From 837e4a5410e202733c3cbb121c87d4a7b40866aa Mon Sep 17 00:00:00 2001 From: ZHAO Jinxiang Date: Sun, 28 Nov 2021 19:57:30 +0800 Subject: [PATCH] feat: add directive support (#75) --- src/core/parseSFC.ts | 36 ++++++++++++++- src/core/transformScriptSetup.ts | 55 +++++++++++++++++++---- src/core/utils.ts | 5 +++ src/types.ts | 3 ++ test/__snapshots__/transform.test.ts.snap | 37 +++++++++++++++ test/fixtures/ComponentsDirectives.vue | 16 +++++++ 6 files changed, 141 insertions(+), 11 deletions(-) create mode 100644 src/core/utils.ts create mode 100644 test/fixtures/ComponentsDirectives.vue diff --git a/src/core/parseSFC.ts b/src/core/parseSFC.ts index 4f0e8d2..ed539ce 100644 --- a/src/core/parseSFC.ts +++ b/src/core/parseSFC.ts @@ -1,15 +1,41 @@ import { Parser as HTMLParser, ParserOptions as HTMLParserOptions } from 'htmlparser2' import type { ParserOptions } from '@babel/parser' -import { camelize, capitalize, isHTMLTag, isSVGTag, isVoidTag } from '@vue/shared' +import { camelize, isHTMLTag, isSVGTag, isVoidTag } from '@vue/shared' import { ParsedSFC, ScriptSetupTransformOptions, ScriptTagMeta } from '../types' import { getIdentifierUsages } from './identifiers' import { parse } from './babel' +import { pascalize } from './utils' const multilineCommentsRE = /\/\*\s(.|[\r\n])*?\*\//gm const singlelineCommentsRE = /\/\/\s.*/g +const BUILD_IN_DIRECTIVES = new Set([ + 'if', + 'else', + 'else-if', + 'for', + 'once', + 'model', + 'on', + 'bind', + 'slot', + 'slot-scope', + 'key', + 'ref', + 'text', + 'html', + 'show', + 'pre', + 'cloak', + // 'el', + // 'ref', +]) + export function parseSFC(code: string, id?: string, options?: ScriptSetupTransformOptions): ParsedSFC { + /** foo-bar -> FooBar */ const components = new Set() + /** v-foo-bar -> fooBar */ + const directives = new Set() const expressions = new Set() const identifiers = new Set() @@ -52,7 +78,7 @@ export function parseSFC(code: string, id?: string, options?: ScriptSetupTransfo function handleTemplateContent(name: string, attributes: Record) { if (!isHTMLTag(name) && !isSVGTag(name) && !isVoidTag(name)) - components.add(capitalize(camelize(name))) + components.add(pascalize((name))) Object.entries(attributes).forEach(([key, value]) => { if (!value) @@ -64,6 +90,11 @@ export function parseSFC(code: string, id?: string, options?: ScriptSetupTransfo 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)) + } if (key === 'ref') identifiers.add(value) }) @@ -183,6 +214,7 @@ export function parseSFC(code: string, id?: string, options?: ScriptSetupTransfo id, template: { components, + directives, identifiers, }, scriptSetup, diff --git a/src/core/transformScriptSetup.ts b/src/core/transformScriptSetup.ts index 8f4833a..b9da054 100644 --- a/src/core/transformScriptSetup.ts +++ b/src/core/transformScriptSetup.ts @@ -1,4 +1,4 @@ -import { camelize, capitalize } from '@vue/shared' +import { capitalize } from '@vue/shared' import type { Node, ObjectExpression, Statement } from '@babel/types' import generate from '@babel/generator' import { partition } from '@antfu/utils' @@ -6,6 +6,7 @@ import { ParsedSFC, ScriptSetupTransformOptions } from '../types' import { applyMacros } from './macros' import { getIdentifierDeclarations } from './identifiers' import { t } from './babel' +import { isNotNil, pascalize } from './utils' function isAsyncImport(node: any) { if (node.type === 'VariableDeclaration') { @@ -35,22 +36,29 @@ export function transformScriptSetup(sfc: ParsedSFC, options?: ScriptSetupTransf const declarations = new Set() getIdentifierDeclarations(hoisted, declarations) getIdentifierDeclarations(setupBody, declarations) + const declarationArray = Array.from(declarations).filter(isNotNil) // filter out identifiers that are used in `