From 1fe9c882cdd0bbf1ee4d91623c9ddbadc97a5897 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 4 Aug 2024 16:25:47 +0800 Subject: [PATCH 1/9] feat: document links for classname within `:class` --- .../lib/codegen/template/element.ts | 124 +++++++++++++++--- 1 file changed, 108 insertions(+), 16 deletions(-) diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index e7e7e5e450..4b5c1da47f 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -1,4 +1,5 @@ import * as CompilerDOM from '@vue/compiler-dom'; +import type * as ts from 'typescript'; import { camelize, capitalize } from '@vue/shared'; import type { Code, VueCodeInformation } from '../../types'; import { hyphenateTag } from '../../utils/shared'; @@ -365,7 +366,7 @@ function* generateVScope( yield* generateElementDirectives(options, ctx, node); yield* generateReferencesForElements(options, ctx, node); // - yield* generateReferencesForScopedCssClasses(ctx, node); + yield* generateReferencesForScopedCssClasses(options, ctx, node); if (inScope) { yield `}${newLine}`; @@ -541,6 +542,7 @@ function* generateReferencesForElements( } function* generateReferencesForScopedCssClasses( + options: TemplateCodegenOptions, ctx: TemplateCodegenContext, node: CompilerDOM.ElementNode ): Generator { @@ -552,28 +554,17 @@ function* generateReferencesForScopedCssClasses( ) { let startOffset = prop.value.loc.start.offset; let content = prop.value.loc.source; + let isWrapped = false; if ( (content.startsWith(`'`) && content.endsWith(`'`)) || (content.startsWith(`"`) && content.endsWith(`"`)) ) { - startOffset++; + isWrapped = true; content = content.slice(1, -1); } if (content) { - let currentClassName = ''; - for (const char of (content + ' ')) { - if (char.trim() === '') { - if (currentClassName !== '') { - ctx.scopedClasses.push({ className: currentClassName, offset: startOffset }); - startOffset += currentClassName.length; - currentClassName = ''; - } - startOffset += char.length; - } - else { - currentClassName += char; - } - } + const classes = collectClasses(content, startOffset, isWrapped); + ctx.scopedClasses.push(...classes); } else { ctx.emptyClassOffsets.push(startOffset); @@ -593,6 +584,83 @@ function* generateReferencesForScopedCssClasses( ctx.codeFeatures.navigationAndCompletion, ]; yield `)${endOfLine}`; + + const leading = "const temp = "; + const startOffset = prop.exp.loc.start.offset - leading.length; + const content = leading + prop.exp.content; + + const { ts } = options; + const ast = ts.createSourceFile('', content, 99 satisfies typeof ts.ScriptTarget.Latest); + const literals: ts.StringLiteralLike[] = []; + + ts.forEachChild(ast, node => { + if (!ts.isVariableStatement(node)) { + return; + } + + const initializer = node.declarationList.declarations[0].initializer!; + + if (ts.isStringLiteralLike(initializer)) { + literals.push(initializer); + } + + if (ts.isArrayLiteralExpression(initializer)) { + walkArrayLiteral(initializer); + } + + if (ts.isObjectLiteralExpression(initializer)) { + walkObjectLiteral(initializer); + } + }); + + for (const literal of literals) { + const classes = collectClasses( + literal.text, + literal.end - literal.text.length - 2 + startOffset, + true + ); + ctx.scopedClasses.push(...classes); + } + + function walkArrayLiteral(node: ts.ArrayLiteralExpression) { + const { elements } = node; + for (const element of elements) { + if (ts.isStringLiteralLike(element)) { + literals.push(element); + } + else if (ts.isObjectLiteralExpression(element)) { + walkObjectLiteral(element); + } + } + } + + function walkObjectLiteral(node: ts.ObjectLiteralExpression) { + const { properties } = node; + for (const property of properties) { + if (ts.isPropertyAssignment(property)) { + const { name } = property; + if (ts.isIdentifier(name)) { + walkStringLiteral(name); + } + else if (ts.isComputedPropertyName(name)) { + const { expression } = name; + if (ts.isStringLiteralLike(expression)) { + literals.push(expression); + } + } + } + else if (ts.isShorthandPropertyAssignment(property)) { + walkStringLiteral(property.name); + } + } + } + + function walkStringLiteral(node: ts.Identifier) { + ctx.scopedClasses.push({ + className: node.text, + offset: node.end - node.text.length + startOffset + }); + } } } } @@ -604,3 +672,27 @@ function camelizeComponentName(newName: string) { function getTagRenameApply(oldName: string) { return oldName === hyphenateTag(oldName) ? hyphenateTag : undefined; } + +function collectClasses(content: string, startOffset = 0, isWrapped = false) { + const classes: { className: string, offset: number; }[] = []; + + let currentClassName = ''; + let offset = isWrapped ? 1 : 0; + for (const char of (content + ' ')) { + if (char.trim() === '') { + if (currentClassName !== '') { + classes.push({ + className: currentClassName, + offset: offset + startOffset + }); + offset += currentClassName.length; + currentClassName = ''; + } + offset += char.length; + } + else { + currentClassName += char; + } + } + return classes; +} \ No newline at end of file From 0bda8d0df3d97e2926e2c27a73b64237a3456350 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 4 Aug 2024 17:37:14 +0800 Subject: [PATCH 2/9] refactor: build template expression --- .../lib/codegen/template/element.ts | 32 +++++++++---------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index 4b5c1da47f..12c143f489 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -585,31 +585,31 @@ function* generateReferencesForScopedCssClasses( ]; yield `)${endOfLine}`; - const leading = "const temp = "; - const startOffset = prop.exp.loc.start.offset - leading.length; - const content = leading + prop.exp.content; + const content = '`${' + prop.exp.content + '}`'; + const startOffset = prop.exp.loc.start.offset - 3; const { ts } = options; const ast = ts.createSourceFile('', content, 99 satisfies typeof ts.ScriptTarget.Latest); const literals: ts.StringLiteralLike[] = []; ts.forEachChild(ast, node => { - if (!ts.isVariableStatement(node)) { - return; - } + if ( + !ts.isExpressionStatement(node) || + !ts.isTemplateExpression(node.expression) + ) return; - const initializer = node.declarationList.declarations[0].initializer!; + const expression = node.expression.templateSpans[0].expression; - if (ts.isStringLiteralLike(initializer)) { - literals.push(initializer); + if (ts.isStringLiteralLike(expression)) { + literals.push(expression); } - if (ts.isArrayLiteralExpression(initializer)) { - walkArrayLiteral(initializer); + if (ts.isArrayLiteralExpression(expression)) { + walkArrayLiteral(expression); } - if (ts.isObjectLiteralExpression(initializer)) { - walkObjectLiteral(initializer); + if (ts.isObjectLiteralExpression(expression)) { + walkObjectLiteral(expression); } }); @@ -640,7 +640,7 @@ function* generateReferencesForScopedCssClasses( if (ts.isPropertyAssignment(property)) { const { name } = property; if (ts.isIdentifier(name)) { - walkStringLiteral(name); + walkIdentifier(name); } else if (ts.isComputedPropertyName(name)) { const { expression } = name; @@ -650,12 +650,12 @@ function* generateReferencesForScopedCssClasses( } } else if (ts.isShorthandPropertyAssignment(property)) { - walkStringLiteral(property.name); + walkIdentifier(property.name); } } } - function walkStringLiteral(node: ts.Identifier) { + function walkIdentifier(node: ts.Identifier) { ctx.scopedClasses.push({ className: node.text, offset: node.end - node.text.length + startOffset From b1b5f2d9e791cfd85e4d989449d5eff3edbbcc65 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 4 Aug 2024 20:30:17 +0800 Subject: [PATCH 3/9] refactor: drop redundant parameter --- .../language-core/lib/codegen/template/element.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index 12c143f489..33a3de6970 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -559,11 +559,11 @@ function* generateReferencesForScopedCssClasses( (content.startsWith(`'`) && content.endsWith(`'`)) || (content.startsWith(`"`) && content.endsWith(`"`)) ) { - isWrapped = true; content = content.slice(1, -1); + isWrapped = true; } if (content) { - const classes = collectClasses(content, startOffset, isWrapped); + const classes = collectClasses(content, startOffset + (isWrapped ? 1 : 0)); ctx.scopedClasses.push(...classes); } else { @@ -616,8 +616,7 @@ function* generateReferencesForScopedCssClasses( for (const literal of literals) { const classes = collectClasses( literal.text, - literal.end - literal.text.length - 2 + startOffset, - true + literal.end - literal.text.length - 1 + startOffset ); ctx.scopedClasses.push(...classes); } @@ -673,11 +672,11 @@ function getTagRenameApply(oldName: string) { return oldName === hyphenateTag(oldName) ? hyphenateTag : undefined; } -function collectClasses(content: string, startOffset = 0, isWrapped = false) { +function collectClasses(content: string, startOffset = 0) { const classes: { className: string, offset: number; }[] = []; let currentClassName = ''; - let offset = isWrapped ? 1 : 0; + let offset = 0; for (const char of (content + ' ')) { if (char.trim() === '') { if (currentClassName !== '') { From 0f65e0665476f45dc79cbc766b05a32c5941d1ee Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Sun, 11 Aug 2024 01:16:34 +0800 Subject: [PATCH 4/9] fix: ployfill for missing function in tsc --- packages/language-core/lib/codegen/template/element.ts | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index 33a3de6970..6819c61fdf 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -595,7 +595,7 @@ function* generateReferencesForScopedCssClasses( ts.forEachChild(ast, node => { if ( !ts.isExpressionStatement(node) || - !ts.isTemplateExpression(node.expression) + !isTemplateExpression(node.expression) ) return; const expression = node.expression.templateSpans[0].expression; @@ -694,4 +694,9 @@ function collectClasses(content: string, startOffset = 0) { } } return classes; +} + +// isTemplateExpression is missing in tsc +function isTemplateExpression(node: ts.Node): node is ts.TemplateExpression { + return node.kind === 228 satisfies ts.SyntaxKind.TemplateExpression; } \ No newline at end of file From 1f3053c6af38935f6ebabc26a6ae9901d4a6bc96 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 13 Aug 2024 03:24:10 +0800 Subject: [PATCH 5/9] feat: treat duplicate class declarations as references --- .../lib/codegen/script/template.ts | 12 +++ .../lib/codegen/template/context.ts | 6 +- .../lib/codegen/template/element.ts | 8 +- .../lib/codegen/template/index.ts | 42 +--------- .../codegen/template/styleScopedClasses.ts | 80 +++++++++++++++++++ 5 files changed, 106 insertions(+), 42 deletions(-) create mode 100644 packages/language-core/lib/codegen/template/styleScopedClasses.ts diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index 8d0dbc85a3..9fd6e6b1e0 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -7,6 +7,7 @@ import { forEachInterpolationSegment } from '../template/interpolation'; import type { ScriptCodegenContext } from './context'; import { codeFeatures, type ScriptCodegenOptions } from './index'; import { generateInternalComponent } from './internalComponent'; +import { generateStyleScopedClasses } from '../template/styleScopedClasses'; export function* generateTemplate( options: ScriptCodegenOptions, @@ -124,6 +125,7 @@ function* generateTemplateContext( yield `let __VLS_components!: typeof __VLS_localComponents & __VLS_GlobalComponents & typeof __VLS_ctx${endOfLine}`; // for html completion, TS references... /* Style Scoped */ + const firstClasses = new Set(); yield `/* Style Scoped */${newLine}`; yield `type __VLS_StyleScopedClasses = {}`; for (let i = 0; i < options.sfc.styles.length; i++) { @@ -131,6 +133,15 @@ function* generateTemplateContext( const option = options.vueCompilerOptions.experimentalResolveStyleCssClasses; if (option === 'always' || (option === 'scoped' && style.scoped)) { for (const className of style.classNames) { + if (firstClasses.has(className.text)) { + templateCodegenCtx.scopedClasses.push({ + source: 'style_' + i, + className: className.text.slice(1), + offset: className.offset + 1 + }); + continue; + } + firstClasses.add(className.text); yield* generateCssClassProperty( i, className.text, @@ -143,6 +154,7 @@ function* generateTemplateContext( } yield endOfLine; yield `let __VLS_styleScopedClasses!: __VLS_StyleScopedClasses | keyof __VLS_StyleScopedClasses | (keyof __VLS_StyleScopedClasses)[]${endOfLine}`; + yield* generateStyleScopedClasses(templateCodegenCtx); yield* generateCssVars(options, templateCodegenCtx); if (options.templateCodegen) { diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index 54c7d3d259..8334820481 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -108,7 +108,11 @@ export function createTemplateCodegenContext(scriptSetupBindingNames: TemplateCo const hasSlotElements = new Set();; const blockConditions: string[] = []; const usedComponentCtxVars = new Set(); - const scopedClasses: { className: string, offset: number; }[] = []; + const scopedClasses: { + source: string; + className: string; + offset: number; + }[] = []; const emptyClassOffsets: number[] = []; return { diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index 6819c61fdf..325ab1d162 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -656,6 +656,7 @@ function* generateReferencesForScopedCssClasses( function walkIdentifier(node: ts.Identifier) { ctx.scopedClasses.push({ + source: 'template', className: node.text, offset: node.end - node.text.length + startOffset }); @@ -673,7 +674,11 @@ function getTagRenameApply(oldName: string) { } function collectClasses(content: string, startOffset = 0) { - const classes: { className: string, offset: number; }[] = []; + const classes: { + source: string; + className: string; + offset: number; + }[] = []; let currentClassName = ''; let offset = 0; @@ -681,6 +686,7 @@ function collectClasses(content: string, startOffset = 0) { if (char.trim() === '') { if (currentClassName !== '') { classes.push({ + source: 'template', className: currentClassName, offset: offset + startOffset }); diff --git a/packages/language-core/lib/codegen/template/index.ts b/packages/language-core/lib/codegen/template/index.ts index 1dc04b2076..c0a0e8334b 100644 --- a/packages/language-core/lib/codegen/template/index.ts +++ b/packages/language-core/lib/codegen/template/index.ts @@ -6,6 +6,7 @@ import { TemplateCodegenContext, createTemplateCodegenContext } from './context' import { getCanonicalComponentName, getPossibleOriginalComponentNames } from './element'; import { generateObjectProperty } from './objectProperty'; import { generateTemplateChild, getVForNode } from './templateChild'; +import { generateStyleScopedClasses } from './styleScopedClasses'; export interface TemplateCodegenOptions { ts: typeof ts; @@ -35,7 +36,7 @@ export function* generateTemplate(options: TemplateCodegenOptions): Generator { - yield `if (typeof __VLS_styleScopedClasses === 'object' && !Array.isArray(__VLS_styleScopedClasses)) {${newLine}`; - for (const offset of ctx.emptyClassOffsets) { - yield `__VLS_styleScopedClasses['`; - yield [ - '', - 'template', - offset, - ctx.codeFeatures.additionalCompletion, - ]; - yield `']${endOfLine}`; - } - for (const { className, offset } of ctx.scopedClasses) { - yield `__VLS_styleScopedClasses[`; - yield [ - '', - 'template', - offset, - ctx.codeFeatures.navigationWithoutRename, - ]; - yield `'`; - yield [ - className, - 'template', - offset, - ctx.codeFeatures.navigationAndAdditionalCompletion, - ]; - yield `'`; - yield [ - '', - 'template', - offset + className.length, - ctx.codeFeatures.navigationWithoutRename, - ]; - yield `]${endOfLine}`; - } - yield `}${newLine}`; - } - function* generatePreResolveComponents(): Generator { yield `let __VLS_resolvedLocalAndGlobalComponents!: {}`; if (options.template.ast) { diff --git a/packages/language-core/lib/codegen/template/styleScopedClasses.ts b/packages/language-core/lib/codegen/template/styleScopedClasses.ts new file mode 100644 index 0000000000..d16b73a4ff --- /dev/null +++ b/packages/language-core/lib/codegen/template/styleScopedClasses.ts @@ -0,0 +1,80 @@ +import type { Code } from '../../types'; +import type { TemplateCodegenContext } from './context'; +import { endOfLine, newLine } from '../common'; + +export function* generateStyleScopedClasses( + ctx: TemplateCodegenContext +): Generator { + yield `if (typeof __VLS_styleScopedClasses === 'object' && !Array.isArray(__VLS_styleScopedClasses)) {${newLine}`; + for (const offset of ctx.emptyClassOffsets) { + yield `__VLS_styleScopedClasses['`; + yield [ + '', + 'template', + offset, + ctx.codeFeatures.additionalCompletion, + ]; + yield `']${endOfLine}`; + } + for (const { source, className, offset } of ctx.scopedClasses) { + yield `__VLS_styleScopedClasses[`; + yield [ + '', + source, + offset, + ctx.codeFeatures.navigationWithoutRename, + ]; + yield `'`; + + // fix https://github.com/vuejs/language-tools/issues/4537 + yield* escapeString(source, className, offset, ['\\', '\'']); + yield `'`; + yield [ + '', + source, + offset + className.length, + ctx.codeFeatures.navigationWithoutRename, + ]; + yield `]${endOfLine}`; + } + yield `}${newLine}`; + + function* escapeString(source: string, className: string, offset: number, escapeTargets: string[]): Generator { + let count = 0; + + const currentEscapeTargets = [...escapeTargets]; + const firstEscapeTarget = currentEscapeTargets.shift()!; + const splitted = className.split(firstEscapeTarget); + + for (let i = 0; i < splitted.length; i++) { + const part = splitted[i]; + const partLength = part.length; + + if (escapeTargets.length > 0) { + yield* escapeString(source, part, offset + count, [...currentEscapeTargets]); + } else { + yield [ + part, + source, + offset + count, + ctx.codeFeatures.navigationAndAdditionalCompletion, + ]; + } + + if (i !== splitted.length - 1) { + yield '\\'; + + yield [ + firstEscapeTarget, + source, + offset + count + partLength, + ctx.codeFeatures.navigationAndAdditionalCompletion, + ]; + + count += partLength + 1; + } else { + count += partLength; + } + } + } +} \ No newline at end of file From d07e282fd6bf2e3b0e29a8acc5d453af6d5a0f21 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 13 Aug 2024 03:46:59 +0800 Subject: [PATCH 6/9] fix: simplify types and remove unnecessary judgments --- packages/language-core/lib/codegen/script/template.ts | 3 +-- packages/language-core/lib/codegen/template/element.ts | 9 --------- .../lib/codegen/template/styleScopedClasses.ts | 3 +-- 3 files changed, 2 insertions(+), 13 deletions(-) diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index 9fd6e6b1e0..62f64276e7 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -127,7 +127,7 @@ function* generateTemplateContext( /* Style Scoped */ const firstClasses = new Set(); yield `/* Style Scoped */${newLine}`; - yield `type __VLS_StyleScopedClasses = {}`; + yield `let __VLS_styleScopedClasses!: {}`; for (let i = 0; i < options.sfc.styles.length; i++) { const style = options.sfc.styles[i]; const option = options.vueCompilerOptions.experimentalResolveStyleCssClasses; @@ -153,7 +153,6 @@ function* generateTemplateContext( } } yield endOfLine; - yield `let __VLS_styleScopedClasses!: __VLS_StyleScopedClasses | keyof __VLS_StyleScopedClasses | (keyof __VLS_StyleScopedClasses)[]${endOfLine}`; yield* generateStyleScopedClasses(templateCodegenCtx); yield* generateCssVars(options, templateCodegenCtx); diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index c88da72c16..d80e72ca90 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -594,15 +594,6 @@ function* generateReferencesForScopedCssClasses( && prop.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && prop.arg.content === 'class' ) { - yield `__VLS_styleScopedClasses = (`; - yield [ - prop.exp.content, - 'template', - prop.exp.loc.start.offset, - ctx.codeFeatures.navigationAndCompletion, - ]; - yield `)${endOfLine}`; - const content = '`${' + prop.exp.content + '}`'; const startOffset = prop.exp.loc.start.offset - 3; diff --git a/packages/language-core/lib/codegen/template/styleScopedClasses.ts b/packages/language-core/lib/codegen/template/styleScopedClasses.ts index d16b73a4ff..1bf5a90e48 100644 --- a/packages/language-core/lib/codegen/template/styleScopedClasses.ts +++ b/packages/language-core/lib/codegen/template/styleScopedClasses.ts @@ -5,7 +5,6 @@ import { endOfLine, newLine } from '../common'; export function* generateStyleScopedClasses( ctx: TemplateCodegenContext ): Generator { - yield `if (typeof __VLS_styleScopedClasses === 'object' && !Array.isArray(__VLS_styleScopedClasses)) {${newLine}`; for (const offset of ctx.emptyClassOffsets) { yield `__VLS_styleScopedClasses['`; yield [ @@ -37,7 +36,7 @@ export function* generateStyleScopedClasses( ]; yield `]${endOfLine}`; } - yield `}${newLine}`; + yield newLine; function* escapeString(source: string, className: string, offset: number, escapeTargets: string[]): Generator { let count = 0; From da70dace4408d4734ab1e46d41862402a82f088b Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 13 Aug 2024 04:02:32 +0800 Subject: [PATCH 7/9] test: modify outdated case --- test-workspace/tsc/#3688/main.vue | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/test-workspace/tsc/#3688/main.vue b/test-workspace/tsc/#3688/main.vue index d894172b00..7fbf85ca0a 100644 --- a/test-workspace/tsc/#3688/main.vue +++ b/test-workspace/tsc/#3688/main.vue @@ -1,8 +1,6 @@ From c712727d3b35cca0ebcdade06ec889eda42ae4c5 Mon Sep 17 00:00:00 2001 From: KazariEX <1364035137@qq.com> Date: Tue, 13 Aug 2024 13:40:32 +0800 Subject: [PATCH 8/9] feat: support rename before dot --- packages/language-core/lib/codegen/script/template.ts | 4 ++-- .../lib/codegen/template/styleScopedClasses.ts | 7 ++++--- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index 62f64276e7..592b0702a9 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -153,7 +153,7 @@ function* generateTemplateContext( } } yield endOfLine; - yield* generateStyleScopedClasses(templateCodegenCtx); + yield* generateStyleScopedClasses(templateCodegenCtx, true); yield* generateCssVars(options, templateCodegenCtx); if (options.templateCodegen) { @@ -183,7 +183,7 @@ function* generateCssClassProperty( '', 'style_' + styleIndex, offset, - codeFeatures.navigationWithoutRename, + codeFeatures.navigation, ]; yield `'`; yield [ diff --git a/packages/language-core/lib/codegen/template/styleScopedClasses.ts b/packages/language-core/lib/codegen/template/styleScopedClasses.ts index 1bf5a90e48..36270a763a 100644 --- a/packages/language-core/lib/codegen/template/styleScopedClasses.ts +++ b/packages/language-core/lib/codegen/template/styleScopedClasses.ts @@ -3,7 +3,8 @@ import type { TemplateCodegenContext } from './context'; import { endOfLine, newLine } from '../common'; export function* generateStyleScopedClasses( - ctx: TemplateCodegenContext + ctx: TemplateCodegenContext, + withDot = false ): Generator { for (const offset of ctx.emptyClassOffsets) { yield `__VLS_styleScopedClasses['`; @@ -20,8 +21,8 @@ export function* generateStyleScopedClasses( yield [ '', source, - offset, - ctx.codeFeatures.navigationWithoutRename, + offset - (withDot ? 1 : 0), + ctx.codeFeatures.navigation, ]; yield `'`; From 4dd2bd530a1479ac3e35af26b3c8160da7500bc7 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Mon, 26 Aug 2024 04:53:35 +0800 Subject: [PATCH 9/9] lint fix --- .../language-core/lib/codegen/template/context.ts | 2 +- .../language-core/lib/codegen/template/element.ts | 4 +++- .../lib/codegen/template/styleScopedClasses.ts | 12 ++++++------ 3 files changed, 10 insertions(+), 8 deletions(-) diff --git a/packages/language-core/lib/codegen/template/context.ts b/packages/language-core/lib/codegen/template/context.ts index 168abccb23..480643d1a8 100644 --- a/packages/language-core/lib/codegen/template/context.ts +++ b/packages/language-core/lib/codegen/template/context.ts @@ -113,7 +113,7 @@ export function createTemplateCodegenContext(scriptSetupBindingNames: TemplateCo source: string; className: string; offset: number; - }[] = []; + }[] = []; const emptyClassOffsets: number[] = []; const inlayHints: InlayHintInfo[] = []; diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index e99ecd4ddb..4bb0f87c87 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -621,7 +621,9 @@ function* generateReferencesForScopedCssClasses( if ( !ts.isExpressionStatement(node) || !isTemplateExpression(node.expression) - ) return; + ) { + return; + } const expression = node.expression.templateSpans[0].expression; diff --git a/packages/language-core/lib/codegen/template/styleScopedClasses.ts b/packages/language-core/lib/codegen/template/styleScopedClasses.ts index 36270a763a..fe1777866b 100644 --- a/packages/language-core/lib/codegen/template/styleScopedClasses.ts +++ b/packages/language-core/lib/codegen/template/styleScopedClasses.ts @@ -41,15 +41,15 @@ export function* generateStyleScopedClasses( function* escapeString(source: string, className: string, offset: number, escapeTargets: string[]): Generator { let count = 0; - + const currentEscapeTargets = [...escapeTargets]; const firstEscapeTarget = currentEscapeTargets.shift()!; const splitted = className.split(firstEscapeTarget); - + for (let i = 0; i < splitted.length; i++) { const part = splitted[i]; const partLength = part.length; - + if (escapeTargets.length > 0) { yield* escapeString(source, part, offset + count, [...currentEscapeTargets]); } else { @@ -60,17 +60,17 @@ export function* generateStyleScopedClasses( ctx.codeFeatures.navigationAndAdditionalCompletion, ]; } - + if (i !== splitted.length - 1) { yield '\\'; - + yield [ firstEscapeTarget, source, offset + count + partLength, ctx.codeFeatures.navigationAndAdditionalCompletion, ]; - + count += partLength + 1; } else { count += partLength;