From 9dcd34ee93bf7fac5d1fa59b17e5bdb667c73a6d Mon Sep 17 00:00:00 2001 From: ZHAO Jinxiang Date: Mon, 29 Nov 2021 00:49:31 +0800 Subject: [PATCH] fix: directive parser (#76) --- package.json | 7 +-- pnpm-lock.yaml | 60 ++++++++++++++++++++--- src/core/parseSFC.ts | 48 +++++++++++++++--- test/__snapshots__/transform.test.ts.snap | 44 ++++++++++++++--- test/fixtures/ComponentsDirectives.vue | 26 ++++++++-- 5 files changed, 157 insertions(+), 28 deletions(-) diff --git a/package.json b/package.json index ba3c2f3..87a4559 100644 --- a/package.json +++ b/package.json @@ -50,8 +50,9 @@ "@babel/traverse": "^7.16.3", "@babel/types": "^7.16.0", "@rollup/pluginutils": "^4.1.1", - "@vue/ref-transform": "^3.2.21", - "@vue/shared": "^3.2.21", + "@vue/compiler-core": "^3.2.23", + "@vue/ref-transform": "^3.2.23", + "@vue/shared": "^3.2.23", "defu": "^5.0.0", "htmlparser2": "5.0.1", "magic-string": "^0.25.7", @@ -63,7 +64,7 @@ "@types/jest": "^27.0.2", "@types/node": "^16.11.7", "@vue/composition-api": "^1.4.0", - "@vue/runtime-dom": "^3.2.21", + "@vue/runtime-dom": "^3.2.23", "bumpp": "^7.1.1", "eslint": "^8.2.0", "eslint-plugin-jest": "^25.2.4", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index a55315b..d8802a8 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,10 +15,11 @@ importers: '@rollup/pluginutils': ^4.1.1 '@types/jest': ^27.0.2 '@types/node': ^16.11.7 + '@vue/compiler-core': ^3.2.23 '@vue/composition-api': ^1.4.0 - '@vue/ref-transform': ^3.2.21 - '@vue/runtime-dom': ^3.2.21 - '@vue/shared': ^3.2.21 + '@vue/ref-transform': ^3.2.23 + '@vue/runtime-dom': ^3.2.23 + '@vue/shared': ^3.2.23 bumpp: ^7.1.1 defu: ^5.0.0 eslint: ^8.2.0 @@ -44,8 +45,9 @@ importers: '@babel/traverse': 7.16.3 '@babel/types': 7.16.0 '@rollup/pluginutils': 4.1.1 - '@vue/ref-transform': 3.2.21 - '@vue/shared': 3.2.21 + '@vue/compiler-core': 3.2.23 + '@vue/ref-transform': 3.2.23 + '@vue/shared': 3.2.23 defu: 5.0.0 htmlparser2: 5.0.1 magic-string: 0.25.7 @@ -56,7 +58,7 @@ importers: '@types/jest': 27.0.2 '@types/node': 16.11.7 '@vue/composition-api': 1.4.0 - '@vue/runtime-dom': 3.2.21 + '@vue/runtime-dom': 3.2.23 bumpp: 7.1.1 eslint: 8.2.0 eslint-plugin-jest: 25.2.4_17df0fa4ec9ba9d0cf30cc54515c24df @@ -3193,6 +3195,16 @@ packages: '@vue/shared': 3.2.21 estree-walker: 2.0.2 source-map: 0.6.1 + dev: true + + /@vue/compiler-core/3.2.23: + resolution: {integrity: sha512-4ZhiI/orx+7EJ1B+0zjgvXMV2uRN+XBfG06UN2sJfND9rH5gtEQT3QmO4erum1o6Irl7y754W8/KSaDJh4EUQg==} + dependencies: + '@babel/parser': 7.16.3 + '@vue/shared': 3.2.23 + estree-walker: 2.0.2 + source-map: 0.6.1 + dev: false /@vue/compiler-dom/3.2.21: resolution: {integrity: sha512-gsJD3DpYZSYquiA7UIPsMDSlAooYWDvHPq9VRsqzJEk2PZtFvLvHPb4aaMD8Ufd62xzYn32cnnkzsEOJhyGilA==} @@ -3249,6 +3261,12 @@ packages: '@vue/shared': 3.2.21 dev: true + /@vue/reactivity/3.2.23: + resolution: {integrity: sha512-8RGVr/5Kpgb/EkCjgHXqttgA5IMc6n0lIXFY4TVbMkzdXrvaIhzBd7Te44oIDsTSYVKZLpfHd6/wEnuDqE8vFw==} + dependencies: + '@vue/shared': 3.2.23 + dev: true + /@vue/ref-transform/3.2.21: resolution: {integrity: sha512-uiEWWBsrGeun9O7dQExYWzXO3rHm/YdtFNXDVqCSoPypzOVxWxdiL+8hHeWzxMB58fVuV2sT80aUtIVyaBVZgQ==} dependencies: @@ -3257,6 +3275,17 @@ packages: '@vue/shared': 3.2.21 estree-walker: 2.0.2 magic-string: 0.25.7 + dev: true + + /@vue/ref-transform/3.2.23: + resolution: {integrity: sha512-gW0GD2PSAs/th7mC7tPB/UwpIQxclbApVtsDtscDmOJXb2+cdu60ny+SuHNgfrlUT/JqWKQHq7jFKO4woxLNaA==} + dependencies: + '@babel/parser': 7.16.3 + '@vue/compiler-core': 3.2.23 + '@vue/shared': 3.2.23 + estree-walker: 2.0.2 + magic-string: 0.25.7 + dev: false /@vue/runtime-core/3.2.21: resolution: {integrity: sha512-7oOxKaU0D2IunOAMOOHZgJVrHg63xwng8BZx3fbgmakqEIMwHhQcp+5GV1sOg/sWW7R4UhaRDIUCukO2GRVK2Q==} @@ -3265,6 +3294,13 @@ packages: '@vue/shared': 3.2.21 dev: true + /@vue/runtime-core/3.2.23: + resolution: {integrity: sha512-wSI5lmY2kCGLf89iiygqxVh6/5bsawz78Me9n1x4U2bHnN0yf3PWyuhN0WgIE8VfEaF7e75E333uboNEIFjgkg==} + dependencies: + '@vue/reactivity': 3.2.23 + '@vue/shared': 3.2.23 + dev: true + /@vue/runtime-dom/3.2.21: resolution: {integrity: sha512-apBdriD6QsI4ywbllY8kjr9/0scGuStDuvLbJULPQkFPtHzntd51bP5PQTQVAEIc9kwnTozmj6x6ZdX/cwo7xA==} dependencies: @@ -3273,8 +3309,20 @@ packages: csstype: 2.6.18 dev: true + /@vue/runtime-dom/3.2.23: + resolution: {integrity: sha512-z6lp0888NkLmxD9j2sGoll8Kb7J743s8s6w7GbiyUc4WZwm0KJ35B4qTFDMoIU0G7CatS6Z+yRTpPHc6srtByg==} + dependencies: + '@vue/runtime-core': 3.2.23 + '@vue/shared': 3.2.23 + csstype: 2.6.18 + dev: true + /@vue/shared/3.2.21: resolution: {integrity: sha512-5EQmIPK6gw4UVYUbM959B0uPsJ58+xoMESCZs3N89XyvJ9e+fX4pqEPrOGV8OroIk3SbEvJcC+eYc8BH9JQrHA==} + dev: true + + /@vue/shared/3.2.23: + resolution: {integrity: sha512-U+/Jefa0QfXUF2qVy9Dqlrb6HKJSr9/wJcM66wXmWcTOoqg7hOWzF4qruDle51pyF4x3wMn6TSH54UdjKjCKMA==} /@vue/web-component-wrapper/1.3.0: resolution: {integrity: sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==} diff --git a/src/core/parseSFC.ts b/src/core/parseSFC.ts index ed539ce..ba6460c 100644 --- a/src/core/parseSFC.ts +++ b/src/core/parseSFC.ts @@ -1,5 +1,6 @@ import { Parser as HTMLParser, ParserOptions as HTMLParserOptions } from 'htmlparser2' import type { ParserOptions } from '@babel/parser' +import { NodeTypes, baseCompile } from '@vue/compiler-core' import { camelize, isHTMLTag, isSVGTag, isVoidTag } from '@vue/shared' import { ParsedSFC, ScriptSetupTransformOptions, ScriptTagMeta } from '../types' import { getIdentifierUsages } from './identifiers' @@ -31,6 +32,32 @@ const BUILD_IN_DIRECTIVES = new Set([ // 'ref', ]) +const parseDirective = (attr: string) => { + try { + const elementNode = baseCompile(``).ast.children[0] + if (elementNode?.type !== NodeTypes.ELEMENT) return undefined + + const directiveNode = elementNode.props[0] + if (directiveNode?.type !== NodeTypes.DIRECTIVE) return undefined + + const { arg, modifiers, name } = directiveNode + const argExpression + = arg?.type !== NodeTypes.SIMPLE_EXPRESSION + ? undefined + : arg.isStatic + ? JSON.stringify(arg.content) + : arg.content + return { + argExpression, + modifiers, + name, + } + } + catch (error) { + return undefined + } +} + export function parseSFC(code: string, id?: string, options?: ScriptSetupTransformOptions): ParsedSFC { /** foo-bar -> FooBar */ const components = new Set() @@ -78,25 +105,30 @@ export function parseSFC(code: string, id?: string, options?: ScriptSetupTransfo function handleTemplateContent(name: string, attributes: Record) { if (!isHTMLTag(name) && !isSVGTag(name) && !isVoidTag(name)) - components.add(pascalize((name))) + components.add(pascalize(name)) Object.entries(attributes).forEach(([key, value]) => { - if (!value) + // ref + if (key === 'ref') { + identifiers.add(value) return - if (key.startsWith('v-') || key.startsWith('@') || key.startsWith(':')) { + } + + if (value !== '' && (key.startsWith('v-') || key.startsWith('@') || key.startsWith(':'))) { if (key === 'v-for') // we strip out delectations for v-for before `in` or `of` expressions.add(`(${value.replace(/^.*\s(?:in|of)\s/, '')})`) else expressions.add(`(${value})`) } + if (key.startsWith('v-')) { - const directiveName = key.slice('v-'.length).split(':')[0].split('.')[0] - if (!BUILD_IN_DIRECTIVES.has(directiveName)) - directives.add(camelize(directiveName)) + const parsedDirective = parseDirective(key) + if (parsedDirective && !BUILD_IN_DIRECTIVES.has(parsedDirective.name)) + directives.add(camelize(parsedDirective.name)) + if (parsedDirective?.argExpression) + expressions.add(parsedDirective.argExpression) } - if (key === 'ref') - identifiers.add(value) }) } diff --git a/test/__snapshots__/transform.test.ts.snap b/test/__snapshots__/transform.test.ts.snap index 51e57a0..ba9fee6 100644 --- a/test/__snapshots__/transform.test.ts.snap +++ b/test/__snapshots__/transform.test.ts.snap @@ -183,7 +183,18 @@ export default __sfc_main; exports[`transform fixtures test/fixtures/ComponentsDirectives.vue 1`] = ` " @@ -191,17 +202,30 @@ exports[`transform fixtures test/fixtures/ComponentsDirectives.vue 1`] = ` diff --git a/test/fixtures/ComponentsDirectives.vue b/test/fixtures/ComponentsDirectives.vue index 5aa9c97..30c78ad 100644 --- a/test/fixtures/ComponentsDirectives.vue +++ b/test/fixtures/ComponentsDirectives.vue @@ -1,6 +1,17 @@ @@ -8,9 +19,16 @@