From 5b2bd1df78e8ff524c3a184adaa284681aba6574 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=B8=89=E5=92=B2=E6=99=BA=E5=AD=90=20Kevin=20Deng?= Date: Fri, 8 Dec 2023 15:22:27 +0800 Subject: [PATCH] feat(compiler-sfc): support import attributes and `using` syntax (#8786) --- .../__snapshots__/compileScript.spec.ts.snap | 28 +++++++++++++++ .../__tests__/compileScript.spec.ts | 34 +++++++++++++++++++ packages/compiler-sfc/__tests__/utils.ts | 5 ++- packages/compiler-sfc/src/rewriteDefault.ts | 3 +- packages/compiler-sfc/src/script/context.ts | 15 ++++++-- 5 files changed, 81 insertions(+), 4 deletions(-) diff --git a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap index b2c6904fbac..01267cd42c7 100644 --- a/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap +++ b/packages/compiler-sfc/__tests__/__snapshots__/compileScript.spec.ts.snap @@ -1483,3 +1483,31 @@ _sfc_.setup = __setup__ : __injectCSSVars__ " `; + +exports[`SFC genDefaultAs > parser plugins > import attributes (user override for deprecated syntax) 1`] = ` +"import { foo } from './foo.js' assert { type: 'foobar' } + +export default { + setup(__props, { expose: __expose }) { + __expose(); + + +return { get foo() { return foo } } +} + +}" +`; + +exports[`SFC genDefaultAs > parser plugins > import attributes 1`] = ` +"import { foo } from './foo.js' with { type: 'foobar' } + +export default { + setup(__props, { expose: __expose }) { + __expose(); + + +return { get foo() { return foo } } +} + +}" +`; diff --git a/packages/compiler-sfc/__tests__/compileScript.spec.ts b/packages/compiler-sfc/__tests__/compileScript.spec.ts index 6eef8d51e63..96338b022f3 100644 --- a/packages/compiler-sfc/__tests__/compileScript.spec.ts +++ b/packages/compiler-sfc/__tests__/compileScript.spec.ts @@ -1600,4 +1600,38 @@ describe('SFC genDefaultAs', () => { foo: BindingTypes.SETUP_REF }) }) + + describe('parser plugins', () => { + test('import attributes', () => { + const { content } = compile(` + + `) + assertCode(content) + + expect(() => + compile(` + `) + ).toThrow() + }) + + test('import attributes (user override for deprecated syntax)', () => { + const { content } = compile( + ` + + `, + { + babelParserPlugins: [ + ['importAttributes', { deprecatedAssertSyntax: true }] + ] + } + ) + assertCode(content) + }) + }) }) diff --git a/packages/compiler-sfc/__tests__/utils.ts b/packages/compiler-sfc/__tests__/utils.ts index 13e12d765a2..5fcc6f0b7f8 100644 --- a/packages/compiler-sfc/__tests__/utils.ts +++ b/packages/compiler-sfc/__tests__/utils.ts @@ -28,7 +28,10 @@ export function assertCode(code: string) { try { babelParse(code, { sourceType: 'module', - plugins: ['typescript'] + plugins: [ + 'typescript', + ['importAttributes', { deprecatedAssertSyntax: true }] + ] }) } catch (e: any) { console.log(code) diff --git a/packages/compiler-sfc/src/rewriteDefault.ts b/packages/compiler-sfc/src/rewriteDefault.ts index 277eedce011..cb1826b4a83 100644 --- a/packages/compiler-sfc/src/rewriteDefault.ts +++ b/packages/compiler-sfc/src/rewriteDefault.ts @@ -2,6 +2,7 @@ import { parse } from '@babel/parser' import MagicString from 'magic-string' import type { ParserPlugin } from '@babel/parser' import type { Identifier, Statement } from '@babel/types' +import { resolveParserPlugins } from './script/context' export function rewriteDefault( input: string, @@ -10,7 +11,7 @@ export function rewriteDefault( ): string { const ast = parse(input, { sourceType: 'module', - plugins: parserPlugins + plugins: resolveParserPlugins('js', parserPlugins) }).program.body const s = new MagicString(input) diff --git a/packages/compiler-sfc/src/script/context.ts b/packages/compiler-sfc/src/script/context.ts index b05b8d910ee..900cf109260 100644 --- a/packages/compiler-sfc/src/script/context.ts +++ b/packages/compiler-sfc/src/script/context.ts @@ -1,6 +1,6 @@ import { CallExpression, Node, ObjectPattern, Program } from '@babel/types' import { SFCDescriptor } from '../parse' -import { generateCodeFrame } from '@vue/shared' +import { generateCodeFrame, isArray } from '@vue/shared' import { parse as babelParse, ParserPlugin } from '@babel/parser' import { ImportBinding, SFCScriptCompileOptions } from '../compileScript' import { PropsDestructureBindings } from './defineProps' @@ -155,6 +155,17 @@ export function resolveParserPlugins( dts = false ) { const plugins: ParserPlugin[] = [] + if ( + !userPlugins || + !userPlugins.some( + p => + p === 'importAssertions' || + p === 'importAttributes' || + (isArray(p) && p[0] === 'importAttributes') + ) + ) { + plugins.push('importAttributes') + } if (lang === 'jsx' || lang === 'tsx') { plugins.push('jsx') } else if (userPlugins) { @@ -163,7 +174,7 @@ export function resolveParserPlugins( userPlugins = userPlugins.filter(p => p !== 'jsx') } if (lang === 'ts' || lang === 'tsx') { - plugins.push(['typescript', { dts }]) + plugins.push(['typescript', { dts }], 'explicitResourceManagement') if (!userPlugins || !userPlugins.includes('decorators')) { plugins.push('decorators-legacy') }