From 279f04b8d81e4e8b77a2893528e7fc8f0c6f2663 Mon Sep 17 00:00:00 2001 From: Teages Date: Tue, 22 Apr 2025 23:18:09 +0800 Subject: [PATCH 1/2] fix: add support for multiple statements in v-on snippets --- package.json | 3 ++- pnpm-lock.yaml | 21 +++++++++-------- src/utils/template.ts | 52 ++++++++++++++++++++++++++++++++++--------- test/template.test.ts | 16 +++++++++++++ 4 files changed, 72 insertions(+), 20 deletions(-) diff --git a/package.json b/package.json index 4bb96d1..232a5b3 100644 --- a/package.json +++ b/package.json @@ -48,7 +48,8 @@ "vue": "^3.5.13" }, "dependencies": { - "@babel/parser": "^7.27.0" + "@babel/parser": "^7.27.0", + "@vue/compiler-core": "^3.5.13" }, "devDependencies": { "@antfu/eslint-config": "4.12.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a784af6..b24f613 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: '@babel/parser': specifier: ^7.27.0 version: 7.27.0 + '@vue/compiler-core': + specifier: ^3.5.13 + version: 3.5.13 devDependencies: '@antfu/eslint-config': specifier: 4.12.0 @@ -56,7 +59,7 @@ importers: version: 15.5.1 mkdist: specifier: 2.3.0 - version: 2.3.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.11(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)) + version: 2.3.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.12(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)) pkg-pr-new: specifier: 0.0.42 version: 0.0.42 @@ -68,7 +71,7 @@ importers: version: 5.8.3 unbuild: specifier: 3.5.0 - version: 3.5.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.11(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)) + version: 3.5.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.12(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)) vitest: specifier: 3.1.2 version: 3.1.2(@types/debug@4.1.12)(@types/node@22.14.1)(sass@1.86.3) @@ -3452,8 +3455,8 @@ packages: peerDependencies: eslint: ^8.57.0 || ^9.0.0 - vue-sfc-transformer@0.1.11: - resolution: {integrity: sha512-nfh8jfBuZKtHv/TRbCfCChQJr28dObEa+SH1IiKWOrRjIZkzPPFyW9wSfY8F5dCN2IV4C1o0n7e59luV4dTlxg==} + vue-sfc-transformer@0.1.12: + resolution: {integrity: sha512-ZIUNw5eJ1KnJGdYSKQf4C4RLQ1DTm2dxAMAYKD+Zhwym9decZ9jF0f9vBqJikubsWZU5EvP+5mRGJ9Ufx2wccw==} engines: {node: '>=18.0.0'} peerDependencies: esbuild: '*' @@ -6200,7 +6203,7 @@ snapshots: mkdirp@1.0.4: {} - mkdist@2.3.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.11(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)): + mkdist@2.3.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.12(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)): dependencies: autoprefixer: 10.4.21(postcss@8.5.3) citty: 0.1.6 @@ -6219,7 +6222,7 @@ snapshots: sass: 1.86.3 typescript: 5.8.3 vue: 3.5.13(typescript@5.8.3) - vue-sfc-transformer: 0.1.11(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)) + vue-sfc-transformer: 0.1.12(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)) vue-tsc: 2.2.8(typescript@5.8.3) mlly@1.7.4: @@ -6952,7 +6955,7 @@ snapshots: ufo@1.5.4: {} - unbuild@3.5.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.11(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)): + unbuild@3.5.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.12(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)): dependencies: '@rollup/plugin-alias': 5.1.1(rollup@4.39.0) '@rollup/plugin-commonjs': 28.0.2(rollup@4.39.0) @@ -6968,7 +6971,7 @@ snapshots: hookable: 5.5.3 jiti: 2.4.2 magic-string: 0.30.17 - mkdist: 2.3.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.11(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)) + mkdist: 2.3.0(sass@1.86.3)(typescript@5.8.3)(vue-sfc-transformer@0.1.12(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)))(vue-tsc@2.2.8(typescript@5.8.3))(vue@3.5.13(typescript@5.8.3)) mlly: 1.7.4 pathe: 2.0.3 pkg-types: 2.1.0 @@ -7145,7 +7148,7 @@ snapshots: transitivePeerDependencies: - supports-color - vue-sfc-transformer@0.1.11(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)): + vue-sfc-transformer@0.1.12(esbuild@0.25.2)(vue@3.5.13(typescript@5.8.3)): dependencies: '@babel/parser': 7.27.0 esbuild: 0.25.2 diff --git a/src/utils/template.ts b/src/utils/template.ts index f3beff0..c70de02 100644 --- a/src/utils/template.ts +++ b/src/utils/template.ts @@ -1,4 +1,5 @@ -import type { AttributeNode, DirectiveNode, ExpressionNode, ForParseResult, ParentNode, RootNode, SourceLocation, TemplateChildNode, TextNode } from '@vue/compiler-dom' +import type { AttributeNode, DirectiveNode, ExpressionNode, ParentNode, RootNode, SourceLocation, TemplateChildNode, TextNode } from '@vue/compiler-dom' +import { isFnExpressionBrowser as isFnExpression, isMemberExpressionBrowser as isMemberExpression } from '@vue/compiler-core' // copy from `@vue/compiler-dom` enum NodeTypes { @@ -37,14 +38,8 @@ enum NodeTypes { JS_RETURN_STATEMENT, } -interface ExpressionTrack { - type: NodeTypes - name?: string - forParseResult?: ForParseResult -} - interface Expression { - track: ExpressionTrack[] + track: VueTemplateNode[] loc: SourceLocation src: string replacement?: string @@ -60,7 +55,7 @@ type VueTemplateNode = function handleNode( node: VueTemplateNode | undefined, addExpression: (...expressions: Expression[]) => void, - track: ExpressionTrack[], + track: VueTemplateNode[], ) { if (!node) { return @@ -264,6 +259,43 @@ const defaultSnippetHandler: SnippetHandler = { standalone: false, } +const multipleStatementsSnippetHandler: SnippetHandler = { + key: (node) => { + const key = `multipleStatements$:${node.src}` + const secondLastTrack = node.track.at(-2) + const lastTrack = node.track.at(-1) + + if ( + lastTrack?.type === NodeTypes.SIMPLE_EXPRESSION + && secondLastTrack?.type === NodeTypes.DIRECTIVE + && secondLastTrack.name === 'on' + ) { + const isMemberExp = isMemberExpression(lastTrack) + const isInlineStatement = !(isMemberExp || isFnExpression(lastTrack)) + + const hasMultipleStatements = node.src.includes(';') + + if ((isInlineStatement || isMemberExp) && hasMultipleStatements) { + return key + } + } + + return null + }, + prepare: (node, id) => `wrapper_${id}(() => {${node.src}});`, + parse: (code) => { + const wrapperRegex = /^(wrapper_\d+)\(\(\) => \{([\s\S]*?)\}\);$/ + + const [_, wrapperName, res] = code.trim().match(wrapperRegex) ?? [] + if (!wrapperName || !res) { + return undefined + } + + return res.trim().replace(/;$/, '') + }, + standalone: false, +} + const destructureSnippetHandler: SnippetHandler = { key: (node) => { const key = `destructure$:${node.src}` @@ -299,7 +331,7 @@ const destructureSnippetHandler: SnippetHandler = { standalone: true, } -const snippetHandlers = [destructureSnippetHandler, defaultSnippetHandler] +const snippetHandlers = [destructureSnippetHandler, multipleStatementsSnippetHandler, defaultSnippetHandler] function getKey(expression: Expression) { for (const handler of snippetHandlers) { const key = handler.key(expression) diff --git a/test/template.test.ts b/test/template.test.ts index 815dbbf..eb7dccf 100644 --- a/test/template.test.ts +++ b/test/template.test.ts @@ -58,6 +58,22 @@ describe('transform typescript template', () => { ping(); }" />" `) + + // https://github.com/nuxt/module-builder/issues/587#issuecomment-2820414064 + expect( + await fixture(`
`), + ).toMatchInlineSnapshot(` + "
" + `) + expect( + await fixture(`
`), + ).toMatchInlineSnapshot(` + "
" + `) }) it('v-slot', async () => { From e119929069795127a4a660f6e834c90d34775d6e Mon Sep 17 00:00:00 2001 From: Teages Date: Tue, 22 Apr 2025 23:40:25 +0800 Subject: [PATCH 2/2] chore(deps): mark `@vue/compiler-core` as peer dependency --- README.md | 4 ++-- package.json | 5 +++-- pnpm-lock.yaml | 6 +++--- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index d9668cb..0446884 100644 --- a/README.md +++ b/README.md @@ -13,10 +13,10 @@ Install package: ```sh # npm -npm install vue-sfc-transformer +npm install vue-sfc-transformer vue @vue/compiler-core esbuild # pnpm -pnpm install vue-sfc-transformer +pnpm install vue-sfc-transformer vue @vue/compiler-core esbuild ``` ```js diff --git a/package.json b/package.json index 232a5b3..c28f179 100644 --- a/package.json +++ b/package.json @@ -44,18 +44,19 @@ "test:types": "tsc --noEmit" }, "peerDependencies": { + "@vue/compiler-core": "^3.5.13", "esbuild": "*", "vue": "^3.5.13" }, "dependencies": { - "@babel/parser": "^7.27.0", - "@vue/compiler-core": "^3.5.13" + "@babel/parser": "^7.27.0" }, "devDependencies": { "@antfu/eslint-config": "4.12.0", "@babel/types": "7.27.0", "@types/node": "22.14.1", "@vitest/coverage-v8": "3.1.2", + "@vue/compiler-core": "3.5.13", "@vue/compiler-dom": "3.5.13", "bumpp": "10.1.0", "changelogithub": "13.13.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b24f613..1a88d68 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,9 +14,6 @@ importers: '@babel/parser': specifier: ^7.27.0 version: 7.27.0 - '@vue/compiler-core': - specifier: ^3.5.13 - version: 3.5.13 devDependencies: '@antfu/eslint-config': specifier: 4.12.0 @@ -30,6 +27,9 @@ importers: '@vitest/coverage-v8': specifier: 3.1.2 version: 3.1.2(vitest@3.1.2(@types/debug@4.1.12)(@types/node@22.14.1)(sass@1.86.3)) + '@vue/compiler-core': + specifier: 3.5.13 + version: 3.5.13 '@vue/compiler-dom': specifier: 3.5.13 version: 3.5.13