From cf374a546a36ff3057aa94d5faddf2ace6c8b932 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joaqu=C3=ADn=20S=C3=A1nchez?= Date: Sat, 28 Sep 2024 01:46:50 +0200 Subject: [PATCH] fix(addon): wrong vue directives transform filter (#380) --- src/addons/vue-directives.ts | 16 +++- src/presets/vue.ts | 3 + test/vue-directives.test.ts | 179 +++++++++++++++++++++++++++++++++++ 3 files changed, 195 insertions(+), 3 deletions(-) diff --git a/src/addons/vue-directives.ts b/src/addons/vue-directives.ts index 95b64d1f..c63a017f 100644 --- a/src/addons/vue-directives.ts +++ b/src/addons/vue-directives.ts @@ -15,14 +15,24 @@ export function vueDirectivesAddon( options: AddonVueDirectivesOptions = {}, ): Addon { function isDirective(importEntry: Import) { - return importEntry.meta?.vueDirective === true - || (options.isDirective?.(normalizePath(process.cwd(), importEntry.from), importEntry) ?? false) + let isDirective = importEntry.meta?.vueDirective === true + if (isDirective) { + return true + } + + isDirective = options.isDirective?.(normalizePath(process.cwd(), importEntry.from), importEntry) ?? false + if (isDirective) { + importEntry.meta ??= {} + importEntry.meta.vueDirective = true + } + + return isDirective } const self = { name: VUE_DIRECTIVES_NAME, async transform(s, id) { - if (!s.original.includes('_ctx.') || !s.original.match(contextRE)) + if (!s.original.match(contextRE)) return s const matches = Array diff --git a/src/presets/vue.ts b/src/presets/vue.ts index cd58469c..f43e7089 100644 --- a/src/presets/vue.ts +++ b/src/presets/vue.ts @@ -65,12 +65,15 @@ export const CommonCompositionAPI: InlinePreset['imports'] = [ 'Component', 'ComponentPublicInstance', 'ComputedRef', + 'DirectiveBinding', 'ExtractDefaultPropTypes', 'ExtractPropTypes', 'ExtractPublicPropTypes', 'InjectionKey', 'PropType', 'Ref', + 'MaybeRef', + 'MaybeRefOrGetter', 'VNode', 'WritableComputedRef', ].map(name => ({ name, type: true })), diff --git a/test/vue-directives.test.ts b/test/vue-directives.test.ts index 44866734..f31f93e9 100644 --- a/test/vue-directives.test.ts +++ b/test/vue-directives.test.ts @@ -68,6 +68,17 @@ const allDirectives = compileTemplate({ }, }) +const onlySingleDirective = compileTemplate({ + id: 'template.vue', + filename: 'template.vue', + source: ` +
+ `, + compilerOptions: { + hoistStatic: false, + }, +}) + function replaceRoot(code: string) { return code.replaceAll(process.cwd().replace(/\\/g, '/'), '') } @@ -609,4 +620,172 @@ describe('vue-directives', () => { `) }) }) + + describe('only single directive', async () => { + const ctx = createUnimport({ + presets: resolvePresets([{ + from: 'directives/awesome-directive.ts', + imports: [{ + name: 'AwesomeDirective', + meta: { + vueDirective: true, + }, + }], + }]), + addons: { + vueDirectives: true, + }, + }) + + await ctx.init() + + it('inject', async () => { + expect(replaceRoot(onlySingleDirective.code)).toMatchInlineSnapshot(` + "import { resolveDirective as _resolveDirective, withDirectives as _withDirectives, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" + + export function render(_ctx, _cache) { + const _directive_awesome_directive = _resolveDirective("awesome-directive") + + return _withDirectives((_openBlock(), _createElementBlock("div", null, null, 512 /* NEED_PATCH */)), [ + [_directive_awesome_directive] + ]) + }" + `) + expect(replaceRoot((await ctx.injectImports(onlySingleDirective.code, 'a.vue')).code.toString())).toMatchInlineSnapshot(` + "import { AwesomeDirective as _directive_awesome_directive } from '/directives/awesome-directive.ts';import { withDirectives as _withDirectives, openBlock as _openBlock, createElementBlock as _createElementBlock } from "vue" + + export function render(_ctx, _cache) { + return _withDirectives((_openBlock(), _createElementBlock("div", null, null, 512 /* NEED_PATCH */)), [ + [_directive_awesome_directive] + ]) + }" + `) + }) + + it('dts', async () => { + expect(replaceRoot(await ctx.generateTypeDeclarations())).toMatchInlineSnapshot(` + "export {} + declare global { + const AwesomeDirective: typeof import('/directives/awesome-directive')['AwesomeDirective'] + } + // for vue directives auto import + declare module 'vue' { + interface ComponentCustomProperties { + vAwesomeDirective: typeof import('/directives/awesome-directive')['AwesomeDirective'] + } + interface GlobalDirectives { + vAwesomeDirective: typeof import('/directives/awesome-directive')['AwesomeDirective'] + } + }" + `) + }) + }) + + describe('directives from scan with meta.vueDirective set to true', async () => { + const cwd = `${process.cwd().replace(/\\/g, '/')}/playground` + const directives = `${cwd}/directives/` + const ctx = createUnimport({ + dirsScanOptions: { cwd }, + dirs: ['./directives/**'], + addons: { + // DON'T REMOVE: for coverage + addons: [{ declaration: dts => dts }], + // DON'T REMOVE: for coverage + vueTemplate: true, + vueDirectives: { + isDirective(normalizeImportFrom) { + return normalizeImportFrom.includes('/directives/') + }, + }, + }, + }) + + await ctx.init() + + it('meta.vueDirective set to true', async () => { + await ctx.injectImports(allDirectives.code, 'a.vue') + const imports = await ctx.getImports() + .then(imports => imports.filter(i => i.from.startsWith(directives)).map((i) => { + i.from = replaceRoot(i.from) + return i + })) + imports.map(i => expect(i.meta?.vueDirective).toBeTruthy()) + expect(imports).toMatchInlineSnapshot(` + [ + { + "as": "awesomeDirective", + "from": "/playground/directives/awesome-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "default", + }, + { + "as": "AwesomeDirective", + "from": "/playground/directives/awesome-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "AwesomeDirective", + }, + { + "as": "customDirective", + "from": "/playground/directives/custom-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "default", + }, + { + "as": "CustomDirective", + "from": "/playground/directives/custom-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "CustomDirective", + }, + { + "as": "mixedDirective", + "from": "/playground/directives/mixed-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "default", + }, + { + "as": "NamedMixedDirective", + "from": "/playground/directives/mixed-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "NamedMixedDirective", + }, + { + "as": "NamedDirective", + "from": "/playground/directives/named-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "NamedDirective", + }, + { + "as": "vRippleDirective", + "from": "/playground/directives/ripple-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "vRippleDirective", + }, + { + "as": "vFocusDirective", + "from": "/playground/directives/v-focus-directive.ts", + "meta": { + "vueDirective": true, + }, + "name": "default", + }, + ] + `) + }) + }) })