From eaa881fd5b17bacdedca2df47afef4f9f4999961 Mon Sep 17 00:00:00 2001 From: KazariEX Date: Wed, 19 Nov 2025 16:38:25 +0800 Subject: [PATCH 1/4] fix: strip `expose` from internal component options --- .../lib/codegen/script/scriptSetup.ts | 259 +++++++----------- .../lib/codegen/script/template.ts | 17 +- .../language-core/lib/codegen/utils/index.ts | 24 ++ .../language-core/lib/parsers/scriptRanges.ts | 6 + 4 files changed, 150 insertions(+), 156 deletions(-) diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index d0d2826031..d7603e3a67 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -2,7 +2,14 @@ import { camelize } from '@vue/shared'; import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges'; import type { Code, Sfc, TextRange } from '../../types'; import { codeFeatures } from '../codeFeatures'; -import { endOfLine, generatePartiallyEnding, generateSfcBlockSection, identifierRegex, newLine } from '../utils'; +import { + createBlockGenerator, + endOfLine, + generatePartiallyEnding, + generateSfcBlockSection, + identifierRegex, + newLine, +} from '../utils'; import { generateCamelized } from '../utils/camelized'; import { wrapWith } from '../utils/wrapWith'; import { generateComponent } from './component'; @@ -129,103 +136,103 @@ function* generateSetupFunction( scriptSetupRanges: ScriptSetupRanges, syntax: 'return' | 'export default' | undefined, ): Generator { - let setupCodeModifies: [Code[], number, number][] = []; + const { replace, generate } = createBlockGenerator( + scriptSetup, + Math.max(scriptSetupRanges.importSectionEndOffset, scriptSetupRanges.leadingCommentEndOffset), + scriptSetup.content.length, + codeFeatures.all, + ); + if (scriptSetupRanges.defineProps) { const { name, statement, callExp, typeArg } = scriptSetupRanges.defineProps; - setupCodeModifies.push(...generateDefineWithType( - scriptSetup, - statement, - scriptSetupRanges.withDefaults?.callExp ?? callExp, - typeArg, - name, - `__VLS_props`, - `__VLS_Props`, - )); + for ( + const replacement of generateDefineWithType( + scriptSetup, + statement, + scriptSetupRanges.withDefaults?.callExp ?? callExp, + typeArg, + name, + `__VLS_props`, + `__VLS_Props`, + ) + ) { + replace(...replacement); + } } if (scriptSetupRanges.defineEmits) { const { name, statement, callExp, typeArg } = scriptSetupRanges.defineEmits; - setupCodeModifies.push(...generateDefineWithType( - scriptSetup, - statement, - callExp, - typeArg, - name, - `__VLS_emit`, - `__VLS_Emit`, - )); + for ( + const replacement of generateDefineWithType( + scriptSetup, + statement, + callExp, + typeArg, + name, + `__VLS_emit`, + `__VLS_Emit`, + ) + ) { + replace(...replacement); + } } if (scriptSetupRanges.defineSlots) { const { name, statement, callExp, typeArg } = scriptSetupRanges.defineSlots; - setupCodeModifies.push(...generateDefineWithType( - scriptSetup, - statement, - callExp, - typeArg, - name, - `__VLS_slots`, - `__VLS_Slots`, - )); + for ( + const replacement of generateDefineWithType( + scriptSetup, + statement, + callExp, + typeArg, + name, + `__VLS_slots`, + `__VLS_Slots`, + ) + ) { + replace(...replacement); + } } if (scriptSetupRanges.defineExpose) { const { callExp, arg, typeArg } = scriptSetupRanges.defineExpose; if (typeArg) { - setupCodeModifies.push([ - [ - `let __VLS_exposed!: `, - generateSfcBlockSection(scriptSetup, typeArg.start, typeArg.end, codeFeatures.all), - endOfLine, - ], + replace( callExp.start, callExp.start, - ], [ - [`typeof __VLS_exposed`], + `let __VLS_exposed!: `, + generateSfcBlockSection(scriptSetup, typeArg.start, typeArg.end, codeFeatures.all), + endOfLine, + ); + replace( typeArg.start, typeArg.end, - ]); + `typeof __VLS_exposed`, + ); } else if (arg) { - setupCodeModifies.push([ - [ - `const __VLS_exposed = `, - generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.all), - endOfLine, - ], + replace( callExp.start, callExp.start, - ], [ - [`__VLS_exposed`], - arg.start, - arg.end, - ]); + `const __VLS_exposed = `, + generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.all), + endOfLine, + ); + replace(arg.start, arg.end, `__VLS_exposed`); } else { - setupCodeModifies.push([ - [`const __VLS_exposed = {}${endOfLine}`], - callExp.start, - callExp.start, - ]); + replace(callExp.start, callExp.start, `const __VLS_exposed = {}${endOfLine}`); } } if (options.vueCompilerOptions.inferTemplateDollarAttrs) { for (const { callExp } of scriptSetupRanges.useAttrs) { - setupCodeModifies.push([ - [`(`], - callExp.start, - callExp.start, - ], [ - [` as typeof __VLS_dollars.$attrs)`], - callExp.end, - callExp.end, - ]); + replace(callExp.start, callExp.start, `(`); + replace(callExp.end, callExp.end, ` as typeof __VLS_dollars.$attrs)`); } } for (const { callExp, exp, arg } of scriptSetupRanges.useCssModule) { - setupCodeModifies.push([ - [`(`], - callExp.start, - callExp.start, - ], [ - arg + replace(callExp.start, callExp.start, `(`); + replace( + callExp.end, + callExp.end, + ...arg ? [ ` as Omit<__VLS_StyleModules, '$style'>[`, generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.withoutSemantic), @@ -242,28 +249,15 @@ function* generateSetupFunction( ), `])`, ], - callExp.end, - callExp.end, - ]); + ); if (arg) { - setupCodeModifies.push([ - [`__VLS_placeholder`], - arg.start, - arg.end, - ]); + replace(arg.start, arg.end, `__VLS_placeholder`); } } if (options.vueCompilerOptions.inferTemplateDollarSlots) { for (const { callExp } of scriptSetupRanges.useSlots) { - setupCodeModifies.push([ - [`(`], - callExp.start, - callExp.start, - ], [ - [` as typeof __VLS_dollars.$slots)`], - callExp.end, - callExp.end, - ]); + replace(callExp.start, callExp.start, `(`); + replace(callExp.end, callExp.end, ` as typeof __VLS_dollars.$slots)`); } } const isTs = options.lang !== 'js' && options.lang !== 'jsx'; @@ -276,49 +270,18 @@ function* generateSetupFunction( ] : [`unknown`]; if (isTs) { - setupCodeModifies.push([ - [ - `<`, - ...templateRefType, - `>`, - ], - exp.end, - exp.end, - ]); + replace(exp.end, exp.end, `<`, ...templateRefType, `>`); } else { - setupCodeModifies.push([ - [`(`], - callExp.start, - callExp.start, - ], [ - [ - ` as __VLS_UseTemplateRef<`, - ...templateRefType, - `>)`, - ], - callExp.end, - callExp.end, - ]); + replace(callExp.start, callExp.start, `(`); + replace(callExp.end, callExp.end, ` as __VLS_UseTemplateRef<`, ...templateRefType, `>)`); } if (arg) { - setupCodeModifies.push([ - [`__VLS_placeholder`], - arg.start, - arg.end, - ]); + replace(arg.start, arg.end, `__VLS_placeholder`); } } - setupCodeModifies = setupCodeModifies.sort((a, b) => a[1] - b[1]); - - let nextStart = Math.max(scriptSetupRanges.importSectionEndOffset, scriptSetupRanges.leadingCommentEndOffset); - for (const [codes, start, end] of setupCodeModifies) { - yield generateSfcBlockSection(scriptSetup, nextStart, start, codeFeatures.all); - yield* codes; - nextStart = end; - } - yield generateSfcBlockSection(scriptSetup, nextStart, scriptSetup.content.length, codeFeatures.all); + yield* generate(); yield* generatePartiallyEnding(scriptSetup.name, scriptSetup.content.length, '#3632/scriptSetup.vue'); yield* generateMacros(options, ctx); @@ -375,67 +338,57 @@ function* generateDefineWithType( name: string | undefined, defaultName: string, typeName: string, -): Generator<[Code[], number, number]> { +): Generator<[number, number, ...Code[]]> { if (typeArg) { yield [ - [ - `type ${typeName} = `, - generateSfcBlockSection(scriptSetup, typeArg.start, typeArg.end, codeFeatures.all), - endOfLine, - ], statement.start, statement.start, + `type ${typeName} = `, + generateSfcBlockSection(scriptSetup, typeArg.start, typeArg.end, codeFeatures.all), + endOfLine, ]; - yield [[typeName], typeArg.start, typeArg.end]; + yield [typeArg.start, typeArg.end, typeName]; } if (!name) { if (statement.start === callExp.start && statement.end === callExp.end) { - yield [[`const ${defaultName} = `], callExp.start, callExp.start]; + yield [callExp.start, callExp.start, `const ${defaultName} = `]; } else if (typeArg) { yield [ - [ - `const ${defaultName} = `, - generateSfcBlockSection(scriptSetup, callExp.start, typeArg.start, codeFeatures.all), - ], statement.start, typeArg.start, + `const ${defaultName} = `, + generateSfcBlockSection(scriptSetup, callExp.start, typeArg.start, codeFeatures.all), ]; yield [ - [ - generateSfcBlockSection(scriptSetup, typeArg.end, callExp.end, codeFeatures.all), - endOfLine, - generateSfcBlockSection(scriptSetup, statement.start, callExp.start, codeFeatures.all), - defaultName, - ], typeArg.end, callExp.end, + generateSfcBlockSection(scriptSetup, typeArg.end, callExp.end, codeFeatures.all), + endOfLine, + generateSfcBlockSection(scriptSetup, statement.start, callExp.start, codeFeatures.all), + defaultName, ]; } else { yield [ - [ - `const ${defaultName} = `, - generateSfcBlockSection(scriptSetup, callExp.start, callExp.end, codeFeatures.all), - endOfLine, - generateSfcBlockSection(scriptSetup, statement.start, callExp.start, codeFeatures.all), - defaultName, - ], statement.start, callExp.end, + `const ${defaultName} = `, + generateSfcBlockSection(scriptSetup, callExp.start, callExp.end, codeFeatures.all), + endOfLine, + generateSfcBlockSection(scriptSetup, statement.start, callExp.start, codeFeatures.all), + defaultName, ]; } } else if (!identifierRegex.test(name)) { - yield [[`const ${defaultName} = `], statement.start, callExp.start]; + yield [statement.start, callExp.start, `const ${defaultName} = `]; yield [ - [ - endOfLine, - generateSfcBlockSection(scriptSetup, statement.start, callExp.start, codeFeatures.all), - defaultName, - ], statement.end, statement.end, + endOfLine, + generateSfcBlockSection(scriptSetup, statement.start, callExp.start, codeFeatures.all), + defaultName, ]; } } diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index f0e2f937c7..b1f28722a4 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -7,7 +7,7 @@ import { generateStyleScopedClasses } from '../style/scopedClasses'; import { createTemplateCodegenContext, type TemplateCodegenContext } from '../template/context'; import { generateInterpolation } from '../template/interpolation'; import { generateStyleScopedClassReferences } from '../template/styleScopedClasses'; -import { endOfLine, generateSfcBlockSection, newLine } from '../utils'; +import { createBlockGenerator, endOfLine, generateSfcBlockSection, newLine } from '../utils'; import { generateSpreadMerge } from '../utils/merge'; import type { ScriptCodegenContext } from './context'; import type { ScriptCodegenOptions } from './index'; @@ -27,9 +27,20 @@ export function* generateTemplate( function* generateSelf(options: ScriptCodegenOptions): Generator { if (options.sfc.script && options.scriptRanges?.componentOptions) { + const { args, expose } = options.scriptRanges.componentOptions; + const { replace, generate } = createBlockGenerator( + options.sfc.script, + args.start, + args.end, + codeFeatures.navigation, + ); + + if (expose) { + replace(expose.start, expose.end, `undefined`); + } + yield `const __VLS_self = (await import('${options.vueCompilerOptions.lib}')).defineComponent(`; - const { args } = options.scriptRanges.componentOptions; - yield generateSfcBlockSection(options.sfc.script, args.start, args.end, codeFeatures.all); + yield* generate(); yield `)${endOfLine}`; } else if (options.sfc.script && options.scriptRanges?.exportDefault) { diff --git a/packages/language-core/lib/codegen/utils/index.ts b/packages/language-core/lib/codegen/utils/index.ts index 7b09218b5c..3a47f0d6a5 100644 --- a/packages/language-core/lib/codegen/utils/index.ts +++ b/packages/language-core/lib/codegen/utils/index.ts @@ -35,6 +35,30 @@ export function createTsAst( return ast; } +export function createBlockGenerator( + block: SfcBlock, + start: number, + end: number, + features: VueCodeInformation, +) { + const replacement: [number, number, ...Code[]][] = []; + + return { + replace(...args: typeof replacement[number]) { + replacement.push(args); + }, + *generate() { + let offset = start; + for (const [start, end, ...codes] of replacement.sort((a, b) => a[0] - b[0])) { + yield generateSfcBlockSection(block, offset, start, features); + yield* codes; + offset = end; + } + yield generateSfcBlockSection(block, offset, end, features); + }, + }; +} + export function generateSfcBlockSection( block: SfcBlock, start: number, diff --git a/packages/language-core/lib/parsers/scriptRanges.ts b/packages/language-core/lib/parsers/scriptRanges.ts index 72788c2551..cdd767c198 100644 --- a/packages/language-core/lib/parsers/scriptRanges.ts +++ b/packages/language-core/lib/parsers/scriptRanges.ts @@ -21,6 +21,7 @@ export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.Sourc directives: TextRange | undefined; name: TextRange | undefined; inheritAttrs: string | undefined; + expose: TextRange | undefined; } | undefined; @@ -57,6 +58,7 @@ export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.Sourc let directivesOptionNode: ts.ObjectLiteralExpression | undefined; let nameOptionNode: ts.Expression | undefined; let inheritAttrsOption: string | undefined; + let exposeOptionNode: ts.Expression | undefined; ts.forEachChild(obj, node => { if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name)) { const name = _getNodeText(node.name); @@ -72,6 +74,9 @@ export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.Sourc else if (name === 'inheritAttrs') { inheritAttrsOption = _getNodeText(node.initializer); } + else if (name === 'expose') { + exposeOptionNode = node.initializer; + } } }); componentOptions = { @@ -83,6 +88,7 @@ export function parseScriptRanges(ts: typeof import('typescript'), ast: ts.Sourc directives: directivesOptionNode ? _getStartEnd(directivesOptionNode) : undefined, name: nameOptionNode ? _getStartEnd(nameOptionNode) : undefined, inheritAttrs: inheritAttrsOption, + expose: exposeOptionNode ? _getStartEnd(exposeOptionNode) : undefined, }; } } From 7ae621f37158df33786977667edada3fca2b661b Mon Sep 17 00:00:00 2001 From: KazariEX Date: Wed, 19 Nov 2025 16:38:27 +0800 Subject: [PATCH 2/4] test: add Co-authored-by: serkodev --- .../tsc/passedFixtures/vue3/#5069/main.vue | 42 +++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 test-workspace/tsc/passedFixtures/vue3/#5069/main.vue diff --git a/test-workspace/tsc/passedFixtures/vue3/#5069/main.vue b/test-workspace/tsc/passedFixtures/vue3/#5069/main.vue new file mode 100644 index 0000000000..5877f3d8f3 --- /dev/null +++ b/test-workspace/tsc/passedFixtures/vue3/#5069/main.vue @@ -0,0 +1,42 @@ + + + From 7eb8aa2c786353edc672339a31925daae2a21c32 Mon Sep 17 00:00:00 2001 From: KazariEX Date: Wed, 19 Nov 2025 16:43:06 +0800 Subject: [PATCH 3/4] refactor: rename `createBlockGenerator` to `createSfcBlockGenerator` --- packages/language-core/lib/codegen/script/scriptSetup.ts | 4 ++-- packages/language-core/lib/codegen/script/template.ts | 4 ++-- packages/language-core/lib/codegen/utils/index.ts | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index d7603e3a67..e68ff6e5bb 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -3,7 +3,7 @@ import type { ScriptSetupRanges } from '../../parsers/scriptSetupRanges'; import type { Code, Sfc, TextRange } from '../../types'; import { codeFeatures } from '../codeFeatures'; import { - createBlockGenerator, + createSfcBlockGenerator, endOfLine, generatePartiallyEnding, generateSfcBlockSection, @@ -136,7 +136,7 @@ function* generateSetupFunction( scriptSetupRanges: ScriptSetupRanges, syntax: 'return' | 'export default' | undefined, ): Generator { - const { replace, generate } = createBlockGenerator( + const { replace, generate } = createSfcBlockGenerator( scriptSetup, Math.max(scriptSetupRanges.importSectionEndOffset, scriptSetupRanges.leadingCommentEndOffset), scriptSetup.content.length, diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index b1f28722a4..d6eafef9e0 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -7,7 +7,7 @@ import { generateStyleScopedClasses } from '../style/scopedClasses'; import { createTemplateCodegenContext, type TemplateCodegenContext } from '../template/context'; import { generateInterpolation } from '../template/interpolation'; import { generateStyleScopedClassReferences } from '../template/styleScopedClasses'; -import { createBlockGenerator, endOfLine, generateSfcBlockSection, newLine } from '../utils'; +import { createSfcBlockGenerator, endOfLine, generateSfcBlockSection, newLine } from '../utils'; import { generateSpreadMerge } from '../utils/merge'; import type { ScriptCodegenContext } from './context'; import type { ScriptCodegenOptions } from './index'; @@ -28,7 +28,7 @@ export function* generateTemplate( function* generateSelf(options: ScriptCodegenOptions): Generator { if (options.sfc.script && options.scriptRanges?.componentOptions) { const { args, expose } = options.scriptRanges.componentOptions; - const { replace, generate } = createBlockGenerator( + const { replace, generate } = createSfcBlockGenerator( options.sfc.script, args.start, args.end, diff --git a/packages/language-core/lib/codegen/utils/index.ts b/packages/language-core/lib/codegen/utils/index.ts index 3a47f0d6a5..7c83580495 100644 --- a/packages/language-core/lib/codegen/utils/index.ts +++ b/packages/language-core/lib/codegen/utils/index.ts @@ -35,7 +35,7 @@ export function createTsAst( return ast; } -export function createBlockGenerator( +export function createSfcBlockGenerator( block: SfcBlock, start: number, end: number, From 7fe032819185ef6f834e64d624baa03983e12b04 Mon Sep 17 00:00:00 2001 From: KazariEX Date: Wed, 19 Nov 2025 16:47:25 +0800 Subject: [PATCH 4/4] chore: lint --- packages/language-core/lib/codegen/script/scriptSetup.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index e68ff6e5bb..4f3fbd87cc 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -201,11 +201,7 @@ function* generateSetupFunction( generateSfcBlockSection(scriptSetup, typeArg.start, typeArg.end, codeFeatures.all), endOfLine, ); - replace( - typeArg.start, - typeArg.end, - `typeof __VLS_exposed`, - ); + replace(typeArg.start, typeArg.end, `typeof __VLS_exposed`); } else if (arg) { replace(