diff --git a/packages/language-core/lib/codegen/names.ts b/packages/language-core/lib/codegen/names.ts index 595156570a..7b55a88462 100644 --- a/packages/language-core/lib/codegen/names.ts +++ b/packages/language-core/lib/codegen/names.ts @@ -27,5 +27,6 @@ export const InternalProps = '__VLS_InternalProps'; export const Emit = '__VLS_Emit'; export const Bindings = '__VLS_Bindings'; export const PublicProps = '__VLS_PublicProps'; +export const StyleModules = '__VLS_StyleModules'; export const PROPS_FALLBACK = '__VLS_PROPS_FALLBACK'; diff --git a/packages/language-core/lib/codegen/script/context.ts b/packages/language-core/lib/codegen/script/context.ts index bc68787bd9..d95aa42caf 100644 --- a/packages/language-core/lib/codegen/script/context.ts +++ b/packages/language-core/lib/codegen/script/context.ts @@ -10,14 +10,6 @@ export function createScriptCodegenContext(options: ScriptCodegenOptions) { return { generatedTypes: new Set(), - bindingNames: new Set([ - ...options.scriptRanges?.bindings.map( - ({ range }) => options.script!.content.slice(range.start, range.end), - ) ?? [], - ...options.scriptSetupRanges?.bindings.map( - ({ range }) => options.scriptSetup!.content.slice(range.start, range.end), - ) ?? [], - ]), localTypes, inlayHints, }; diff --git a/packages/language-core/lib/codegen/script/index.ts b/packages/language-core/lib/codegen/script/index.ts index 7cae3c8258..8dd463698f 100644 --- a/packages/language-core/lib/codegen/script/index.ts +++ b/packages/language-core/lib/codegen/script/index.ts @@ -20,17 +20,15 @@ export interface ScriptCodegenOptions { vueCompilerOptions: VueCompilerOptions; script: Sfc['script']; scriptSetup: Sfc['scriptSetup']; - styles: Sfc['styles']; fileName: string; lang: string; scriptRanges: ScriptRanges | undefined; scriptSetupRanges: ScriptSetupRanges | undefined; templateComponents: string[]; templateStartTagOffset: number | undefined; - // TODO: remove this for better increment ality templateCodegen: TemplateCodegenContext & { codes: Code[] } | undefined; - destructuredPropNames: Set; - templateRefNames: Set; + styleCodegen: TemplateCodegenContext & { codes: Code[] } | undefined; + setupBindingNames: Set; } export { generate as generateScript }; diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index f5a1886079..05ffaa74f9 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -191,10 +191,13 @@ export function* generateSetupFunction( yield `(`; }), ); + const type = options.styleCodegen?.generatedTypes.has(names.StyleModules) + ? names.StyleModules + : `{}`; if (arg) { transforms.push( insert(callExp.end, function*() { - yield ` as Omit<__VLS_StyleModules, '$style'>[`; + yield ` as Omit<${type}, '$style'>[`; yield* generateSfcBlockSection(scriptSetup, arg.start, arg.end, codeFeatures.withoutSemantic); yield `])`; }), @@ -206,7 +209,7 @@ export function* generateSetupFunction( else { transforms.push( insert(callExp.end, function*() { - yield ` as __VLS_StyleModules[`; + yield ` as ${type}[`; const token = yield* startBoundary(scriptSetup.name, exp.start, codeFeatures.verification); yield `'$style'`; yield endBoundary(token, exp.end); @@ -282,7 +285,7 @@ export function* generateSetupFunction( (start, end) => generateSfcBlockSection(scriptSetup, start, end, codeFeatures.all, end === scriptSetup.content.length), ); - yield* generateMacros(options, ctx); + yield* generateMacros(options); yield* generateModels(scriptSetup, scriptSetupRanges); yield* generatePublicProps(options, ctx, scriptSetup, scriptSetupRanges); yield* body; @@ -303,15 +306,12 @@ export function* generateSetupFunction( } } -function* generateMacros( - options: ScriptCodegenOptions, - ctx: ScriptCodegenContext, -): Generator { +function* generateMacros(options: ScriptCodegenOptions): Generator { if (options.vueCompilerOptions.target >= 3.3) { yield `// @ts-ignore${newLine}`; yield `declare const { `; for (const macro of Object.keys(options.vueCompilerOptions.macros)) { - if (!ctx.bindingNames.has(macro)) { + if (!options.setupBindingNames.has(macro)) { yield `${macro}, `; } } diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index d4ab660204..0332dd4d5c 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -3,10 +3,6 @@ import * as path from 'path-browserify'; import type { Code } from '../../types'; import { codeFeatures } from '../codeFeatures'; import * as names from '../names'; -import { generateStyleModules } from '../style/modules'; -import { generateStyleScopedClasses } from '../style/scopedClasses'; -import { createTemplateCodegenContext, type TemplateCodegenContext } from '../template/context'; -import { generateInterpolation } from '../template/interpolation'; import { endOfLine, generateSfcBlockSection, newLine } from '../utils'; import { generateSpreadMerge } from '../utils/merge'; import type { ScriptCodegenContext } from './context'; @@ -17,19 +13,14 @@ export function* generateTemplate( ctx: ScriptCodegenContext, ): Generator { yield* generateSelf(options); + yield* generateBindings(options, ctx); yield* generateTemplateCtx(options, ctx); yield* generateTemplateComponents(options); yield* generateTemplateDirectives(options); - const templateCodegenCtx = createTemplateCodegenContext({ - scriptSetupBindingNames: new Set(), - }); - - yield* generateStyleScopedClasses(options); - yield* generateStyleModules(options); - yield* generateCssVars(options, templateCodegenCtx); - yield* generateBindings(options, ctx, templateCodegenCtx); - + if (options.styleCodegen) { + yield* options.styleCodegen.codes; + } if (options.templateCodegen) { yield* options.templateCodegen.codes; } @@ -54,7 +45,7 @@ function* generateSelf({ script, scriptRanges, vueCompilerOptions, fileName }: S } function* generateTemplateCtx( - { vueCompilerOptions, script, scriptRanges, styles, scriptSetupRanges, fileName }: ScriptCodegenOptions, + { vueCompilerOptions, script, scriptRanges, styleCodegen, scriptSetupRanges, fileName }: ScriptCodegenOptions, ctx: ScriptCodegenContext, ): Generator { const exps: Iterable[] = []; @@ -70,8 +61,8 @@ function* generateTemplateCtx( else { exps.push([`{} as import('${vueCompilerOptions.lib}').ComponentPublicInstance`]); } - if (styles.some(style => style.module)) { - exps.push([`{} as __VLS_StyleModules`]); + if (styleCodegen?.generatedTypes.has(names.StyleModules)) { + exps.push([`{} as ${names.StyleModules}`]); } if (scriptSetupRanges?.defineEmits) { @@ -109,7 +100,7 @@ function* generateTemplateCtx( exps.push([`{} as ${names.InternalProps}`]); } - if (scriptSetupRanges && ctx.bindingNames.size) { + if (ctx.generatedTypes.has(names.Bindings)) { exps.push([`{} as ${names.Bindings}`]); } @@ -158,53 +149,31 @@ function* generateTemplateDirectives(options: ScriptCodegenOptions): Generator { - for (const style of options.styles) { - for (const binding of style.bindings) { - yield* generateInterpolation( - options, - ctx, - style, - codeFeatures.all, - binding.text, - binding.offset, - `(`, - `)`, - ); - yield endOfLine; - } - } -} - function* generateBindings( - options: ScriptCodegenOptions, + { templateComponents, templateCodegen, styleCodegen, setupBindingNames }: ScriptCodegenOptions, ctx: ScriptCodegenContext, - templateCodegenCtx: TemplateCodegenContext, ): Generator { - if (!options.scriptSetup || !ctx.bindingNames.size) { + if (!setupBindingNames.size) { return; } + ctx.generatedTypes.add(names.Bindings); - const usageVars = new Set([ - ...options.templateComponents.flatMap(c => [camelize(c), capitalize(camelize(c))]), - ...options.templateCodegen?.accessExternalVariables.keys() ?? [], - ...templateCodegenCtx.accessExternalVariables.keys(), + const usedVars = new Set([ + ...templateComponents.flatMap(c => [camelize(c), capitalize(camelize(c))]), + ...templateCodegen?.accessExternalVariables.keys() ?? [], + ...styleCodegen?.accessExternalVariables.keys() ?? [], ]); yield `type ${names.Bindings} = __VLS_ProxyRefs<{${newLine}`; - for (const varName of ctx.bindingNames) { - if (!usageVars.has(varName)) { + for (const bindingName of setupBindingNames) { + if (!usedVars.has(bindingName)) { continue; } - - const token = Symbol(varName.length); + const token = Symbol(bindingName.length); yield ['', undefined, 0, { __linkedToken: token }]; - yield `${varName}: typeof `; + yield `${bindingName}: typeof `; yield ['', undefined, 0, { __linkedToken: token }]; - yield varName; + yield bindingName; yield endOfLine; } yield `}>${endOfLine}`; diff --git a/packages/language-core/lib/codegen/style/index.ts b/packages/language-core/lib/codegen/style/index.ts new file mode 100644 index 0000000000..1bde041310 --- /dev/null +++ b/packages/language-core/lib/codegen/style/index.ts @@ -0,0 +1,50 @@ +import type { Code, Sfc, VueCompilerOptions } from '../../types'; +import { codeFeatures } from '../codeFeatures'; +import { generateStyleModules } from '../style/modules'; +import { generateStyleScopedClasses } from '../style/scopedClasses'; +import { createTemplateCodegenContext, type TemplateCodegenContext } from '../template/context'; +import { generateInterpolation } from '../template/interpolation'; +import { endOfLine } from '../utils'; + +export interface StyleCodegenOptions { + ts: typeof import('typescript'); + vueCompilerOptions: VueCompilerOptions; + styles: Sfc['styles']; + templateRefNames: Set; + directAccessNames: Set; + setupBindingNames: Set; +} + +export { generate as generateStyle }; + +function* generate(options: StyleCodegenOptions) { + const ctx = createTemplateCodegenContext(options.setupBindingNames); + const endScope = ctx.startScope(); + ctx.declare(...options.directAccessNames); + yield* generateStyleScopedClasses(options); + yield* generateStyleModules(options, ctx); + yield* generateCssVars(options, ctx); + yield* endScope(); + return ctx; +} + +function* generateCssVars( + options: StyleCodegenOptions, + ctx: TemplateCodegenContext, +): Generator { + for (const style of options.styles) { + for (const binding of style.bindings) { + yield* generateInterpolation( + options, + ctx, + style, + codeFeatures.all, + binding.text, + binding.offset, + `(`, + `)`, + ); + yield endOfLine; + } + } +} diff --git a/packages/language-core/lib/codegen/style/modules.ts b/packages/language-core/lib/codegen/style/modules.ts index 356f03addb..e0c5f9a30c 100644 --- a/packages/language-core/lib/codegen/style/modules.ts +++ b/packages/language-core/lib/codegen/style/modules.ts @@ -1,17 +1,22 @@ import type { Code } from '../../types'; import { codeFeatures } from '../codeFeatures'; -import type { ScriptCodegenOptions } from '../script'; +import * as names from '../names'; +import type { TemplateCodegenContext } from '../template/context'; import { endOfLine, newLine } from '../utils'; +import type { StyleCodegenOptions } from '.'; import { generateClassProperty, generateStyleImports } from './common'; export function* generateStyleModules( - { styles, scriptSetupRanges, vueCompilerOptions }: ScriptCodegenOptions, + { styles, vueCompilerOptions }: StyleCodegenOptions, + ctx: TemplateCodegenContext, ): Generator { const styleModules = styles.filter(style => style.module); - if (!styleModules.length && !scriptSetupRanges?.useCssModule.length) { + if (!styleModules.length) { return; } - yield `type __VLS_StyleModules = {${newLine}`; + ctx.generatedTypes.add(names.StyleModules); + + yield `type ${names.StyleModules} = {${newLine}`; for (const style of styleModules) { if (style.module === true) { yield `$style`; diff --git a/packages/language-core/lib/codegen/style/scopedClasses.ts b/packages/language-core/lib/codegen/style/scopedClasses.ts index ef34ea521c..4029b00806 100644 --- a/packages/language-core/lib/codegen/style/scopedClasses.ts +++ b/packages/language-core/lib/codegen/style/scopedClasses.ts @@ -1,11 +1,11 @@ import type { Code } from '../../types'; -import type { ScriptCodegenOptions } from '../script'; import { generateStyleScopedClassReference } from '../template/styleScopedClasses'; import { endOfLine } from '../utils'; +import type { StyleCodegenOptions } from '.'; import { generateClassProperty, generateStyleImports } from './common'; export function* generateStyleScopedClasses( - { vueCompilerOptions, styles }: ScriptCodegenOptions, + { vueCompilerOptions, styles }: StyleCodegenOptions, ): Generator { const { resolveStyleClassNames, resolveStyleImports } = vueCompilerOptions; if (!resolveStyleClassNames) { diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index 15a1ac4fe4..955590efbf 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -4,7 +4,6 @@ import { codeFeatures } from '../codeFeatures'; import type { InlayHintInfo } from '../inlayHints'; import { endOfLine, newLine } from '../utils'; import { endBoundary, startBoundary } from '../utils/boundary'; -import type { TemplateCodegenOptions } from './index'; export type TemplateCodegenContext = ReturnType; @@ -108,14 +107,14 @@ const commentDirectiveRegex = /^