Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
35 changed files
with
625 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
--- | ||
'unplugin-vue-macros': minor | ||
'@vue-macros/export-expose': patch | ||
'@vue-macros/volar': minor | ||
--- | ||
|
||
- Disable `exportExpose` and `exportProps` by default. | ||
- Introduce `exportExpose`. | ||
- Add `include` option for Volar plugins (`exportExpose` and `exportProps`). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
# @vue-macros/export-expose [![npm](https://img.shields.io/npm/v/@vue-macros/export-expose.svg)](https://npmjs.com/package/@vue-macros/export-expose) | ||
|
||
Please refer to [README.md](https://github.com/sxzz/vue-macros#readme) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,102 @@ | ||
{ | ||
"name": "@vue-macros/export-expose", | ||
"version": "0.0.0", | ||
"packageManager": "[email protected]", | ||
"description": "export-expose feature from Vue Macros.", | ||
"keywords": [ | ||
"vue-macros", | ||
"macros", | ||
"vue", | ||
"sfc", | ||
"setup", | ||
"script-setup", | ||
"export-expose", | ||
"unplugin" | ||
], | ||
"license": "MIT", | ||
"homepage": "https://github.com/sxzz/vue-macros#readme", | ||
"bugs": { | ||
"url": "https://github.com/sxzz/vue-macros/issues" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+https://github.com/sxzz/vue-macros.git", | ||
"directory": "packages/export-expose" | ||
}, | ||
"author": "三咲智子 <[email protected]>", | ||
"files": [ | ||
"dist", | ||
"*.d.ts" | ||
], | ||
"main": "dist/index.js", | ||
"module": "dist/index.mjs", | ||
"types": "dist/index.d.ts", | ||
"exports": { | ||
".": { | ||
"dev": "./src/index.ts", | ||
"types": "./dist/index.d.ts", | ||
"require": "./dist/index.js", | ||
"import": "./dist/index.mjs" | ||
}, | ||
"./api": { | ||
"dev": "./src/api.ts", | ||
"types": "./dist/api.d.ts", | ||
"require": "./dist/api.js", | ||
"import": "./dist/api.mjs" | ||
}, | ||
"./esbuild": { | ||
"dev": "./src/esbuild.ts", | ||
"types": "./dist/esbuild.d.ts", | ||
"require": "./dist/esbuild.js", | ||
"import": "./dist/esbuild.mjs" | ||
}, | ||
"./rollup": { | ||
"dev": "./src/rollup.ts", | ||
"types": "./dist/rollup.d.ts", | ||
"require": "./dist/rollup.js", | ||
"import": "./dist/rollup.mjs" | ||
}, | ||
"./vite": { | ||
"dev": "./src/vite.ts", | ||
"types": "./dist/vite.d.ts", | ||
"require": "./dist/vite.js", | ||
"import": "./dist/vite.mjs" | ||
}, | ||
"./webpack": { | ||
"dev": "./src/webpack.ts", | ||
"types": "./dist/webpack.d.ts", | ||
"require": "./dist/webpack.js", | ||
"import": "./dist/webpack.mjs" | ||
}, | ||
"./*": [ | ||
"./*", | ||
"./*.d.ts" | ||
] | ||
}, | ||
"typesVersions": { | ||
"<=4.9": { | ||
"*": [ | ||
"./dist/*", | ||
"./*" | ||
] | ||
} | ||
}, | ||
"scripts": { | ||
"build": "tsup && tsx ../../scripts/postbuild.mts", | ||
"dev": "DEV=true tsup" | ||
}, | ||
"peerDependencies": { | ||
"vue": "^2.7.0 || ^3.2.25" | ||
}, | ||
"dependencies": { | ||
"@vue-macros/common": "workspace:~", | ||
"@vue/compiler-sfc": "^3.3.4", | ||
"unplugin": "^1.3.1" | ||
}, | ||
"devDependencies": { | ||
"vue": "^3.3.4" | ||
}, | ||
"engines": { | ||
"node": ">=16.14.0" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export * from './core' |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,119 @@ | ||
import { | ||
HELPER_PREFIX, | ||
MagicString, | ||
getTransformResult, | ||
parseSFC, | ||
} from '@vue-macros/common' | ||
import { extractIdentifiers } from '@vue/compiler-sfc' | ||
|
||
const MACROS_VAR_PREFIX = `${HELPER_PREFIX}expose_` | ||
|
||
export function transformExportExpose(code: string, id: string) { | ||
const { scriptSetup, getSetupAst } = parseSFC(code, id) | ||
if (!scriptSetup) return | ||
|
||
const s = new MagicString(code) | ||
const nodes = getSetupAst()!.body | ||
const offset = scriptSetup.loc.start.offset | ||
|
||
const exposed: Record<string, string> = {} | ||
|
||
let i = 0 | ||
for (const stmt of nodes) { | ||
const start = offset + stmt.start! | ||
const end = start + 6 /* 'export'.length */ | ||
|
||
if (stmt.type === 'ExportNamedDeclaration' && stmt.exportKind === 'value') { | ||
if (stmt.declaration) { | ||
if ( | ||
stmt.declaration.type === 'VariableDeclaration' && | ||
!stmt.declaration.declare | ||
) { | ||
for (const decl of stmt.declaration.declarations) { | ||
for (const id of extractIdentifiers(decl.id)) { | ||
exposed[id.name] = id.name | ||
} | ||
} | ||
} else if ( | ||
(stmt.declaration.type === 'FunctionDeclaration' || | ||
stmt.declaration.type === 'ClassDeclaration' || | ||
stmt.declaration.type === 'TSEnumDeclaration') && | ||
!stmt.declaration.declare | ||
) { | ||
exposed[stmt.declaration.id!.name] = stmt.declaration.id!.name | ||
} | ||
|
||
s.remove(start, end) | ||
} else { | ||
for (const specifier of stmt.specifiers) { | ||
let exported: string, local: string | ||
if (specifier.type === 'ExportSpecifier') { | ||
if (specifier.exportKind === 'type') continue | ||
|
||
exported = | ||
specifier.exported.type === 'Identifier' | ||
? specifier.exported.name | ||
: specifier.exported.value | ||
|
||
if (stmt.source) { | ||
// rename variable | ||
local = MACROS_VAR_PREFIX + String(i++) | ||
if (specifier.local.name === exported) { | ||
s.overwriteNode( | ||
specifier.local, | ||
`${specifier.local.name} as ${local}`, | ||
{ offset } | ||
) | ||
} else { | ||
s.overwriteNode(specifier.exported, local, { offset }) | ||
} | ||
} else { | ||
local = specifier.local.name | ||
} | ||
} else if (specifier.type === 'ExportNamespaceSpecifier') { | ||
local = MACROS_VAR_PREFIX + String(i++) | ||
exported = specifier.exported.name | ||
|
||
s.overwriteNode(specifier.exported, local, { offset }) | ||
} else continue | ||
|
||
exposed[exported] = local | ||
} | ||
|
||
if (stmt.source) { | ||
s.overwrite(start, end, 'import') | ||
} else { | ||
s.removeNode(stmt, { offset }) | ||
} | ||
} | ||
} else if ( | ||
stmt.type === 'ExportAllDeclaration' && | ||
stmt.exportKind === 'value' | ||
) { | ||
throw new Error( | ||
'export from another module is not supported. Please import and export separately.' | ||
) | ||
} else if (stmt.type === 'ExportDefaultDeclaration') { | ||
throw new Error( | ||
'export default is not supported. Please use named export.' | ||
) | ||
} | ||
} | ||
|
||
if (Object.keys(exposed).length === 0) return | ||
|
||
let codegen = '' | ||
for (const [exported, local] of Object.entries(exposed)) { | ||
codegen += `\n ` | ||
if (exported === local) { | ||
codegen += `${exported},` | ||
} else { | ||
codegen += `${exported}: ${local},` | ||
} | ||
} | ||
codegen = `defineExpose({${codegen}\n})` | ||
|
||
s.prependLeft(scriptSetup.loc.end.offset, `${codegen}\n`) | ||
|
||
return getTransformResult(s, id) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import unplugin from '.' | ||
|
||
export default unplugin.esbuild |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
import { createUnplugin } from 'unplugin' | ||
import { | ||
type BaseOptions, | ||
type MarkRequired, | ||
REGEX_SETUP_SFC, | ||
REGEX_VUE_SFC, | ||
REGEX_VUE_SUB, | ||
createFilter, | ||
detectVueVersion, | ||
} from '@vue-macros/common' | ||
import { transformExportExpose } from './core' | ||
|
||
export { transformExportExpose as transformDefineProps } from './core' | ||
|
||
export type Options = BaseOptions | ||
export type OptionsResolved = MarkRequired<Options, 'include' | 'version'> | ||
|
||
function resolveOption(options: Options): OptionsResolved { | ||
const version = options.version || detectVueVersion() | ||
return { | ||
include: [REGEX_VUE_SFC, REGEX_SETUP_SFC, REGEX_VUE_SUB], | ||
...options, | ||
version, | ||
} | ||
} | ||
|
||
const name = 'unplugin-vue-export-expose' | ||
|
||
export default createUnplugin<Options | undefined, false>( | ||
(userOptions = {}) => { | ||
const options = resolveOption(userOptions) | ||
const filter = createFilter(options) | ||
|
||
return { | ||
name, | ||
enforce: 'pre', | ||
|
||
transformInclude(id) { | ||
return filter(id) | ||
}, | ||
|
||
transform(code, id) { | ||
return transformExportExpose(code, id) | ||
}, | ||
} | ||
} | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import unplugin from '.' | ||
|
||
export default unplugin.rollup |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import unplugin from '.' | ||
|
||
export default unplugin.vite |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
import unplugin from '.' | ||
|
||
export default unplugin.webpack |
69 changes: 69 additions & 0 deletions
69
packages/export-expose/tests/__snapshots__/fixtures.test.ts.snap
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html | ||
|
||
exports[`fixtures > ./fixtures/basic.vue 1`] = ` | ||
"<script setup lang=\\"ts\\"> | ||
const foo: string = 'foo', | ||
bar = 10 | ||
let baz: string | undefined | ||
var qux = fn() | ||
const { a, b, c } = { a: 1, b: 2, c: 3 } | ||
function fn() {} | ||
class A {} | ||
defineExpose({ | ||
foo, | ||
bar, | ||
baz, | ||
qux, | ||
a, | ||
b, | ||
c, | ||
fn, | ||
A, | ||
foo1: foo, | ||
}) | ||
</script> | ||
" | ||
`; | ||
exports[`fixtures > ./fixtures/error/export-all.vue 1`] = `"export from another module is not supported. Please import and export separately."`; | ||
exports[`fixtures > ./fixtures/error/export-default.vue 1`] = `"export default is not supported. Please use named export."`; | ||
exports[`fixtures > ./fixtures/export-from-other.vue 1`] = ` | ||
"<script setup lang=\\"ts\\"> | ||
import { foo as __MACROS_expose_0, type Foo, foo as __MACROS_expose_1 } from './types' | ||
defineExpose({ | ||
foo: __MACROS_expose_0, | ||
bar: __MACROS_expose_1, | ||
}) | ||
</script> | ||
" | ||
`; | ||
exports[`fixtures > ./fixtures/namespace-export.vue 1`] = ` | ||
"<script setup lang=\\"ts\\"> | ||
import * as __MACROS_expose_0 from './types' | ||
defineExpose({ | ||
foo: __MACROS_expose_0, | ||
}) | ||
</script> | ||
" | ||
`; | ||
exports[`fixtures > ./fixtures/rename.vue 1`] = ` | ||
"<script setup lang=\\"ts\\"> | ||
const foo = 1, | ||
bar = 1 | ||
import { foo as __MACROS_expose_0 } from './types' | ||
import * as __MACROS_expose_1 from './types' | ||
defineExpose({ | ||
foo: __MACROS_expose_0, | ||
bar: __MACROS_expose_1, | ||
}) | ||
</script> | ||
" | ||
`; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,13 @@ | ||
import { testFixtures } from '@vue-macros/test-utils' | ||
import { describe } from 'vitest' | ||
import { transformExportExpose } from '../src/core' | ||
|
||
describe('fixtures', async () => { | ||
await testFixtures( | ||
import.meta.glob('./fixtures/**/*.vue', { | ||
eager: true, | ||
as: 'raw', | ||
}), | ||
(args, id, code) => transformExportExpose(code, id)?.code | ||
) | ||
}) |
Oops, something went wrong.