From 7ee6772c195185b5dc02d442e810ef6bec732811 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Wed, 23 Jul 2025 13:12:26 +0800 Subject: [PATCH 1/6] refactor(language-service): simplify vue-template plugin --- .../language-server/tests/completions.spec.ts | 4 +- .../lib/plugins/vue-template.ts | 195 ++++++++++-------- 2 files changed, 108 insertions(+), 91 deletions(-) diff --git a/packages/language-server/tests/completions.spec.ts b/packages/language-server/tests/completions.spec.ts index 542428c8d6..05344f67e1 100644 --- a/packages/language-server/tests/completions.spec.ts +++ b/packages/language-server/tests/completions.spec.ts @@ -177,7 +177,9 @@ test('HTML tags and built-in components', async () => { "dialog", "script", "noscript", + "template", "canvas", + "slot", "data", "hgroup", "menu", @@ -190,8 +192,6 @@ test('HTML tags and built-in components', async () => { "Teleport", "Suspense", "component", - "slot", - "template", "BaseTransition", "Fixture", ] diff --git a/packages/language-service/lib/plugins/vue-template.ts b/packages/language-service/lib/plugins/vue-template.ts index 8aba12f980..55d413f828 100644 --- a/packages/language-service/lib/plugins/vue-template.ts +++ b/packages/language-service/lib/plugins/vue-template.ts @@ -19,8 +19,7 @@ import { loadModelModifiersData, loadTemplateData } from './data'; type InternalItemId = | 'componentEvent' - | 'componentProp' - | 'specialTag'; + | 'componentProp'; const specialTags = new Set([ 'slot', @@ -174,24 +173,20 @@ export function create( return; } - // #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver - baseServiceInstance.provideCompletionItems?.(document, position, completionContext, token); - - let sync = (await provideHtmlData(sourceScript.id, root)).sync; - let currentVersion: number | undefined; - let completionList: CompletionList | null | undefined; - - while (currentVersion !== (currentVersion = await sync?.())) { - completionList = await baseServiceInstance.provideCompletionItems?.( - document, - position, - completionContext, - token, - ); - } + const completionList = await runWithVueData( + sourceScript.id, + root, + () => + baseServiceInstance.provideCompletionItems!( + document, + position, + completionContext, + token, + ), + ); if (completionList) { - transformCompletionList(completionList, document); + postProcessCompletionList(completionList, document); return completionList; } }, @@ -209,30 +204,37 @@ export function create( }, }; + async function runWithVueData(sourceDocumentUri: URI, vueCode: VueVirtualCode, fn: () => T) { + // #4298: Precompute HTMLDocument before provideHtmlData to avoid parseHTMLDocument requesting component names from tsserver + await fn(); + + const { sync } = await provideHtmlData(sourceDocumentUri, vueCode); + let lastVersion = await sync(); + let result = await fn(); + while (lastVersion !== (lastVersion = await sync())) { + result = await fn(); + } + return result; + } + async function provideHtmlData(sourceDocumentUri: URI, vueCode: VueVirtualCode) { await (initializing ??= initialize()); const casing = await checkCasing(context, sourceDocumentUri); - if (builtInData.tags) { - for (const tag of builtInData.tags) { - if (isItemKey(tag.name)) { - continue; - } - - if (specialTags.has(tag.name)) { - tag.name = generateItemKey('specialTag', tag.name, ''); - } - else if (casing.tag === TagNameCasing.Kebab) { - tag.name = hyphenateTag(tag.name); - } - else { - tag.name = camelize(capitalize(tag.name)); - } + for (const tag of builtInData.tags ?? []) { + if (specialTags.has(tag.name)) { + continue; + } + if (casing.tag === TagNameCasing.Kebab) { + tag.name = hyphenateTag(tag.name); + } + else { + tag.name = camelize(capitalize(tag.name)); } } - const promises: Promise[] = []; + const tasks: Promise[] = []; const tagInfos = new Map true, provideTags: () => { if (!components) { - promises.push((async () => { + components = []; + tasks.push((async () => { components = (await tsPluginClient?.getComponentNames(vueCode.fileName) ?? []) .filter(name => name !== 'Transition' @@ -264,7 +267,6 @@ export function create( lastCompletionComponentNames = new Set(components); version++; })()); - return []; } const scriptSetupRanges = tsCodegen.get(vueCode.sfc)?.getScriptSetupRanges(); const names = new Set(); @@ -299,10 +301,16 @@ export function create( return tags; }, provideAttributes: tag => { - const tagInfo = tagInfos.get(tag); - + let tagInfo = tagInfos.get(tag); if (!tagInfo) { - promises.push((async () => { + tagInfo = { + attrs: [], + propInfos: [], + events: [], + directives: [], + }; + tagInfos.set(tag, tagInfo); + tasks.push((async () => { const attrs = await tsPluginClient?.getElementAttrs(vueCode.fileName, tag) ?? []; const propInfos = await tsPluginClient?.getComponentProps(vueCode.fileName, tag) ?? []; const events = await tsPluginClient?.getComponentEvents(vueCode.fileName, tag) ?? []; @@ -315,7 +323,6 @@ export function create( }); version++; })()); - return []; } const { attrs, propInfos, events, directives } = tagInfo; @@ -458,63 +465,26 @@ export function create( return { async sync() { - await Promise.all(promises); + await Promise.all(tasks); return version; }, }; } - function transformCompletionList(completionList: CompletionList, document: TextDocument) { - addDirectiveModifiers(); + function postProcessCompletionList(completionList: CompletionList, document: TextDocument) { + addDirectiveModifiers(completionList, document); - function addDirectiveModifiers() { - const replacement = getReplacement(completionList, document); - if (!replacement?.text.includes('.')) { - return; - } + const tagMap = new Map(); - const [text, ...modifiers] = replacement.text.split('.'); - const isVOn = text.startsWith('v-on:') || text.startsWith('@') && text.length > 1; - const isVBind = text.startsWith('v-bind:') || text.startsWith(':') && text.length > 1; - const isVModel = text.startsWith('v-model:') || text === 'v-model'; - const currentModifiers = isVOn - ? vOnModifiers - : isVBind - ? vBindModifiers - : isVModel - ? vModelModifiers - : undefined; - - if (!currentModifiers) { - return; + completionList.items = completionList.items.filter(item => { + const key = item.kind + '_' + item.label; + if (!tagMap.has(key)) { + tagMap.set(key, item); + return true; } - - for (const modifier in currentModifiers) { - if (modifiers.includes(modifier)) { - continue; - } - - const description = currentModifiers[modifier]; - const insertText = text + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier; - const newItem: html.CompletionItem = { - label: modifier, - filterText: insertText, - documentation: { - kind: 'markdown', - value: description, - }, - textEdit: { - range: replacement.textEdit.range, - newText: insertText, - }, - kind: 20 satisfies typeof CompletionItemKind.EnumMember, - }; - - completionList.items.push(newItem); - } - } - - completionList.items = completionList.items.filter(item => !specialTags.has(parseLabel(item.label).name)); + tagMap.get(key)!.documentation = item.documentation; + return false; + }); const htmlDocumentations = new Map(); @@ -693,6 +663,53 @@ export function create( updateExtraCustomData([]); } + function addDirectiveModifiers(completionList: CompletionList, document: TextDocument) { + const replacement = getReplacement(completionList, document); + if (!replacement?.text.includes('.')) { + return; + } + + const [text, ...modifiers] = replacement.text.split('.'); + const isVOn = text.startsWith('v-on:') || text.startsWith('@') && text.length > 1; + const isVBind = text.startsWith('v-bind:') || text.startsWith(':') && text.length > 1; + const isVModel = text.startsWith('v-model:') || text === 'v-model'; + const currentModifiers = isVOn + ? vOnModifiers + : isVBind + ? vBindModifiers + : isVModel + ? vModelModifiers + : undefined; + + if (!currentModifiers) { + return; + } + + for (const modifier in currentModifiers) { + if (modifiers.includes(modifier)) { + continue; + } + + const description = currentModifiers[modifier]; + const insertText = text + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier; + const newItem: html.CompletionItem = { + label: modifier, + filterText: insertText, + documentation: { + kind: 'markdown', + value: description, + }, + textEdit: { + range: replacement.textEdit.range, + newText: insertText, + }, + kind: 20 satisfies typeof CompletionItemKind.EnumMember, + }; + + completionList.items.push(newItem); + } + } + async function initialize() { customData = await getHtmlCustomData(); } From 7e5188a0beb8be3f5e288c60c37eb9ae3f74a968 Mon Sep 17 00:00:00 2001 From: KazariEX Date: Wed, 23 Jul 2025 13:20:53 +0800 Subject: [PATCH 2/6] feat(language-service): check casing when dropping component into template --- .../language-service/lib/plugins/vue-document-drop.ts | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/language-service/lib/plugins/vue-document-drop.ts b/packages/language-service/lib/plugins/vue-document-drop.ts index 1f8b3fc27a..caf2c3abfe 100644 --- a/packages/language-service/lib/plugins/vue-document-drop.ts +++ b/packages/language-service/lib/plugins/vue-document-drop.ts @@ -9,7 +9,7 @@ import { camelize, capitalize, hyphenate } from '@vue/shared'; import { posix as path } from 'path-browserify'; import { getUserPreferences } from 'volar-service-typescript/lib/configs/getUserPreferences'; import { URI } from 'vscode-uri'; -import { TagNameCasing } from '../nameCasing'; +import { checkCasing, TagNameCasing } from '../nameCasing'; import { createAddComponentToOptionEdit, getLastImportNode } from '../plugins/vue-extract-file'; export function create( @@ -25,7 +25,6 @@ export function create( }, create(context) { const tsPluginClient = getTsPluginClient?.(context); - let casing = TagNameCasing.Pascal as TagNameCasing; // TODO return { async provideDocumentDropEdits(document, _position, dataTransfer) { @@ -61,9 +60,9 @@ export function create( return; } - let baseName = importUri.slice(importUri.lastIndexOf('/') + 1); - baseName = baseName.slice(0, baseName.lastIndexOf('.')); - const newName = capitalize(camelize(baseName)); + const casing = await checkCasing(context, decoded![0]); + const baseName = path.basename(importUri); + const newName = capitalize(camelize(baseName.slice(0, baseName.lastIndexOf('.')))); const additionalEdit: WorkspaceEdit = {}; const code = [...forEachEmbeddedCode(root)].find(code => @@ -134,7 +133,7 @@ export function create( } return { - insertText: `<${casing === TagNameCasing.Kebab ? hyphenate(newName) : newName}$0 />`, + insertText: `<${casing.tag === TagNameCasing.Kebab ? hyphenate(newName) : newName}$0 />`, insertTextFormat: 2 satisfies typeof InsertTextFormat.Snippet, additionalEdit, }; From 7cde30a61e7097e130d3440a2d464ee0aabed15d Mon Sep 17 00:00:00 2001 From: KazariEX Date: Wed, 23 Jul 2025 14:00:20 +0800 Subject: [PATCH 3/6] feat(language-core): introduce `compileSFCStyle` to provide style related infomation --- .../lib/codegen/script/template.ts | 6 +- packages/language-core/lib/plugins.ts | 2 + .../lib/plugins/vue-sfc-styles.ts | 8 +-- .../lib/plugins/vue-style-css.ts | 68 +++++++++++++++++++ packages/language-core/lib/types.ts | 7 +- .../lib/utils/parseCssClassNames.ts | 15 ---- .../lib/utils/parseCssImports.ts | 16 ----- .../language-core/lib/utils/parseCssVars.ts | 23 ------- .../lib/virtualFile/computedSfc.ts | 23 ++++--- 9 files changed, 97 insertions(+), 71 deletions(-) create mode 100644 packages/language-core/lib/plugins/vue-style-css.ts delete mode 100644 packages/language-core/lib/utils/parseCssClassNames.ts delete mode 100644 packages/language-core/lib/utils/parseCssImports.ts delete mode 100644 packages/language-core/lib/utils/parseCssVars.ts diff --git a/packages/language-core/lib/codegen/script/template.ts b/packages/language-core/lib/codegen/script/template.ts index 7e443b7ffa..a4d26a2887 100644 --- a/packages/language-core/lib/codegen/script/template.ts +++ b/packages/language-core/lib/codegen/script/template.ts @@ -123,14 +123,14 @@ function* generateCssVars(options: ScriptCodegenOptions, ctx: TemplateCodegenCon } yield `// CSS variable injection ${newLine}`; for (const style of options.sfc.styles) { - for (const cssBind of style.cssVars) { + for (const binding of style.bindings) { yield* generateInterpolation( options, ctx, style.name, codeFeatures.all, - cssBind.text, - cssBind.offset, + binding.text, + binding.offset, ); yield endOfLine; } diff --git a/packages/language-core/lib/plugins.ts b/packages/language-core/lib/plugins.ts index 354ba6db01..1e32bbed9f 100644 --- a/packages/language-core/lib/plugins.ts +++ b/packages/language-core/lib/plugins.ts @@ -7,6 +7,7 @@ import vueSfcCustomBlocks from './plugins/vue-sfc-customblocks'; import vueSfcScriptsFormat from './plugins/vue-sfc-scripts'; import vueSfcStyles from './plugins/vue-sfc-styles'; import vueSfcTemplate from './plugins/vue-sfc-template'; +import vueStyleCss from './plugins/vue-style-css'; import vueTemplateHtmlPlugin from './plugins/vue-template-html'; import vueTemplateInlineCssPlugin from './plugins/vue-template-inline-css'; import vueTemplateInlineTsPlugin from './plugins/vue-template-inline-ts'; @@ -22,6 +23,7 @@ export function createPlugins(pluginContext: Parameters[0]) { useHtmlFilePlugin, vueRootTagsPlugin, vueScriptJsPlugin, + vueStyleCss, vueTemplateHtmlPlugin, vueTemplateInlineCssPlugin, vueTemplateInlineTsPlugin, diff --git a/packages/language-core/lib/plugins/vue-sfc-styles.ts b/packages/language-core/lib/plugins/vue-sfc-styles.ts index c04b9fbccf..7128940aea 100644 --- a/packages/language-core/lib/plugins/vue-sfc-styles.ts +++ b/packages/language-core/lib/plugins/vue-sfc-styles.ts @@ -17,7 +17,7 @@ const plugin: VueLanguagePlugin = () => { id: 'style_' + i, lang: style.lang, }); - if (style.cssVars.length) { + if (style.bindings.length) { result.push({ id: 'style_' + i + '_inline_ts', lang: 'ts', @@ -34,13 +34,13 @@ const plugin: VueLanguagePlugin = () => { const style = sfc.styles[index]; if (embeddedFile.id.endsWith('_inline_ts')) { embeddedFile.parentCodeId = 'style_' + index; - for (const cssVar of style.cssVars) { + for (const binding of style.bindings) { embeddedFile.content.push( '(', [ - cssVar.text, + binding.text, style.name, - cssVar.offset, + binding.offset, allCodeFeatures, ], ');\n', diff --git a/packages/language-core/lib/plugins/vue-style-css.ts b/packages/language-core/lib/plugins/vue-style-css.ts new file mode 100644 index 0000000000..f685ed8f91 --- /dev/null +++ b/packages/language-core/lib/plugins/vue-style-css.ts @@ -0,0 +1,68 @@ +import type { VueLanguagePlugin } from '../types'; + +const plugin: VueLanguagePlugin = () => { + return { + version: 2.1, + + compileSFCStyle(_lang, style) { + return { + imports: [...parseCssImports(style)], + bindings: [...parseCssBindings(style)], + classNames: [...parseCssClassNames(style)], + }; + }, + }; +}; + +export default plugin; + +const cssImportReg = /(?<=@import\s+url\()(["']?).*?\1(?=\))|(?<=@import\b\s*)(["']).*?\2/g; +const cssBindingReg = /\bv-bind\(\s*(?:'([^']+)'|"([^"]+)"|([a-z_]\w*))\s*\)/gi; +const cssClassNameReg = /(?=(\.[a-z_][-\w]*)[\s.,+~>:#)[{])/gi; +const commentReg = /(?<=\/\*)[\s\S]*?(?=\*\/)|(?<=\/\/)[\s\S]*?(?=\n)/g; +const fragmentReg = /(?<={)[^{]*(?=(? t); + if (matchText) { + const offset = match.index + css.slice(match.index).indexOf(matchText); + yield { offset, text: matchText }; + } + } +} + +function* parseCssClassNames(css: string) { + css = fillBlank(css, commentReg, fragmentReg); + const matches = css.matchAll(cssClassNameReg); + for (const match of matches) { + const matchText = match[1]; + if (matchText) { + yield { offset: match.index, text: matchText }; + } + } +} + +function fillBlank(css: string, ...regs: RegExp[]) { + for (const reg of regs) { + css = css.replace(reg, match => ' '.repeat(match.length)); + } + return css; +} diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index 7bffaac10a..7288c6dbd7 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -97,6 +97,11 @@ export type VueLanguagePluginReturn = { template: string, options: CompilerDOM.CompilerOptions, ): CompilerDOM.CodegenResult | undefined; + compileSFCStyle?(lang: string, style: string): { + imports?: Sfc['styles'][number]['imports']; + bindings?: Sfc['styles'][number]['bindings']; + classNames?: Sfc['styles'][number]['classNames']; + } | undefined; updateSFCTemplate?( oldResult: CompilerDOM.CodegenResult, textChange: { start: number; end: number; newText: string }, @@ -162,7 +167,7 @@ export interface Sfc { text: string; offset: number; }[]; - cssVars: { + bindings: { text: string; offset: number; }[]; diff --git a/packages/language-core/lib/utils/parseCssClassNames.ts b/packages/language-core/lib/utils/parseCssClassNames.ts deleted file mode 100644 index b786c8393c..0000000000 --- a/packages/language-core/lib/utils/parseCssClassNames.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { commentReg, fillBlank } from './parseCssVars'; - -const cssClassNameReg = /(?=(\.[a-z_][-\w]*)[\s.,+~>:#)[{])/gi; -const fragmentReg = /(?<={)[^{]*(?=(? t); - if (matchText) { - const offset = match.index + css.slice(match.index).indexOf(matchText); - yield { offset, text: matchText }; - } - } -} - -export function fillBlank(css: string, ...regs: RegExp[]) { - for (const reg of regs) { - css = css.replace(reg, match => ' '.repeat(match.length)); - } - return css; -} diff --git a/packages/language-core/lib/virtualFile/computedSfc.ts b/packages/language-core/lib/virtualFile/computedSfc.ts index caad57d2c6..142ce99a2e 100644 --- a/packages/language-core/lib/virtualFile/computedSfc.ts +++ b/packages/language-core/lib/virtualFile/computedSfc.ts @@ -3,9 +3,6 @@ import type { SFCBlock, SFCParseResult } from '@vue/compiler-sfc'; import { computed, setCurrentSub } from 'alien-signals'; import type * as ts from 'typescript'; import type { Sfc, SfcBlock, SfcBlockAttr, VueLanguagePluginReturn } from '../types'; -import { parseCssClassNames } from '../utils/parseCssClassNames'; -import { parseCssImports } from '../utils/parseCssImports'; -import { parseCssVars } from '../utils/parseCssVars'; import { computedArray, computedItems } from '../utils/signals'; export const templateInlineTsAsts = new WeakMap>(); @@ -133,16 +130,24 @@ export function computedSfc( const getSrc = computedAttrValue('__src', base, getBlock); const getModule = computedAttrValue('__module', base, getBlock); const getScoped = computed(() => !!getBlock().scoped); + const getIr = computed(() => { + for (const plugin of plugins) { + const ast = plugin.compileSFCStyle?.(base.lang, base.content); + if (ast) { + return ast; + } + } + }); const getImports = computedItems( - () => [...parseCssImports(base.content)], + () => getIr()?.imports ?? [], (oldItem, newItem) => oldItem.text === newItem.text && oldItem.offset === newItem.offset, ); - const getCssVars = computedItems( - () => [...parseCssVars(base.content)], + const getBindings = computedItems( + () => getIr()?.bindings ?? [], (oldItem, newItem) => oldItem.text === newItem.text && oldItem.offset === newItem.offset, ); const getClassNames = computedItems( - () => [...parseCssClassNames(base.content)], + () => getIr()?.classNames ?? [], (oldItem, newItem) => oldItem.text === newItem.text && oldItem.offset === newItem.offset, ); return () => @@ -159,8 +164,8 @@ export function computedSfc( get imports() { return getImports(); }, - get cssVars() { - return getCssVars(); + get bindings() { + return getBindings(); }, get classNames() { return getClassNames(); From 88f5ff739b6ed44929b56d699a1212324b48ae92 Mon Sep 17 00:00:00 2001 From: KazariEX Date: Sun, 27 Jul 2025 00:30:57 +0800 Subject: [PATCH 4/6] chore: undo irrelevant changes --- .../language-server/tests/completions.spec.ts | 4 +- .../lib/plugins/vue-template.ts | 47 ------------------- 2 files changed, 2 insertions(+), 49 deletions(-) diff --git a/packages/language-server/tests/completions.spec.ts b/packages/language-server/tests/completions.spec.ts index 05344f67e1..542428c8d6 100644 --- a/packages/language-server/tests/completions.spec.ts +++ b/packages/language-server/tests/completions.spec.ts @@ -177,9 +177,7 @@ test('HTML tags and built-in components', async () => { "dialog", "script", "noscript", - "template", "canvas", - "slot", "data", "hgroup", "menu", @@ -192,6 +190,8 @@ test('HTML tags and built-in components', async () => { "Teleport", "Suspense", "component", + "slot", + "template", "BaseTransition", "Fixture", ] diff --git a/packages/language-service/lib/plugins/vue-template.ts b/packages/language-service/lib/plugins/vue-template.ts index e6b6644ab4..42a73b4243 100644 --- a/packages/language-service/lib/plugins/vue-template.ts +++ b/packages/language-service/lib/plugins/vue-template.ts @@ -688,53 +688,6 @@ export function create( } } - function addDirectiveModifiers(completionList: CompletionList, document: TextDocument) { - const replacement = getReplacement(completionList, document); - if (!replacement?.text.includes('.')) { - return; - } - - const [text, ...modifiers] = replacement.text.split('.'); - const isVOn = text.startsWith('v-on:') || text.startsWith('@') && text.length > 1; - const isVBind = text.startsWith('v-bind:') || text.startsWith(':') && text.length > 1; - const isVModel = text.startsWith('v-model:') || text === 'v-model'; - const currentModifiers = isVOn - ? vOnModifiers - : isVBind - ? vBindModifiers - : isVModel - ? vModelModifiers - : undefined; - - if (!currentModifiers) { - return; - } - - for (const modifier in currentModifiers) { - if (modifiers.includes(modifier)) { - continue; - } - - const description = currentModifiers[modifier]; - const insertText = text + modifiers.slice(0, -1).map(m => '.' + m).join('') + '.' + modifier; - const newItem: html.CompletionItem = { - label: modifier, - filterText: insertText, - documentation: { - kind: 'markdown', - value: description, - }, - textEdit: { - range: replacement.textEdit.range, - newText: insertText, - }, - kind: 20 satisfies typeof CompletionItemKind.EnumMember, - }; - - completionList.items.push(newItem); - } - } - async function initialize() { customData = await getHtmlCustomData(); } From ac5d8aadcd5e21ee168edc89fb5a40eb15f811d9 Mon Sep 17 00:00:00 2001 From: KazariEX Date: Fri, 1 Aug 2025 23:25:48 +0800 Subject: [PATCH 5/6] refactor: make all properties required --- packages/language-core/lib/types.ts | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index 7288c6dbd7..e8a5e07a3b 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -97,11 +97,9 @@ export type VueLanguagePluginReturn = { template: string, options: CompilerDOM.CompilerOptions, ): CompilerDOM.CodegenResult | undefined; - compileSFCStyle?(lang: string, style: string): { - imports?: Sfc['styles'][number]['imports']; - bindings?: Sfc['styles'][number]['bindings']; - classNames?: Sfc['styles'][number]['classNames']; - } | undefined; + compileSFCStyle?(lang: string, style: string): + | Pick + | undefined; updateSFCTemplate?( oldResult: CompilerDOM.CodegenResult, textChange: { start: number; end: number; newText: string }, From 7ca7a63042cb15602d8d5754f527c9cbdd1e7a69 Mon Sep 17 00:00:00 2001 From: KazariEX Date: Fri, 1 Aug 2025 23:27:03 +0800 Subject: [PATCH 6/6] feat: update plugin version --- packages/language-core/lib/plugins/file-html.ts | 2 +- packages/language-core/lib/plugins/file-md.ts | 2 +- packages/language-core/lib/plugins/file-vue.ts | 2 +- packages/language-core/lib/plugins/vue-root-tags.ts | 2 +- packages/language-core/lib/plugins/vue-script-js.ts | 2 +- packages/language-core/lib/plugins/vue-sfc-customblocks.ts | 2 +- packages/language-core/lib/plugins/vue-sfc-scripts.ts | 2 +- packages/language-core/lib/plugins/vue-sfc-styles.ts | 2 +- packages/language-core/lib/plugins/vue-sfc-template.ts | 2 +- packages/language-core/lib/plugins/vue-style-css.ts | 2 +- packages/language-core/lib/plugins/vue-template-html.ts | 2 +- packages/language-core/lib/plugins/vue-template-inline-css.ts | 2 +- packages/language-core/lib/plugins/vue-template-inline-ts.ts | 2 +- packages/language-core/lib/plugins/vue-tsx.ts | 2 +- packages/language-core/lib/types.ts | 2 +- packages/language-plugin-pug/index.ts | 2 +- 16 files changed, 16 insertions(+), 16 deletions(-) diff --git a/packages/language-core/lib/plugins/file-html.ts b/packages/language-core/lib/plugins/file-html.ts index b3b5ad2f30..73bafda5e0 100644 --- a/packages/language-core/lib/plugins/file-html.ts +++ b/packages/language-core/lib/plugins/file-html.ts @@ -6,7 +6,7 @@ const langReg = /\blang\s*=\s*(['"]?)(\S*)\b\1/; const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => { return { - version: 2.1, + version: 2.2, getLanguageId(fileName) { if (vueCompilerOptions.petiteVueExtensions.some(ext => fileName.endsWith(ext))) { diff --git a/packages/language-core/lib/plugins/file-md.ts b/packages/language-core/lib/plugins/file-md.ts index 66896864e8..1fb53acf71 100644 --- a/packages/language-core/lib/plugins/file-md.ts +++ b/packages/language-core/lib/plugins/file-md.ts @@ -17,7 +17,7 @@ const codeSnippetImportReg = /^\s*<<<\s*.+/gm; const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => { return { - version: 2.1, + version: 2.2, getLanguageId(fileName) { if (vueCompilerOptions.vitePressExtensions.some(ext => fileName.endsWith(ext))) { diff --git a/packages/language-core/lib/plugins/file-vue.ts b/packages/language-core/lib/plugins/file-vue.ts index 892ab1b5f8..a36b627ac5 100644 --- a/packages/language-core/lib/plugins/file-vue.ts +++ b/packages/language-core/lib/plugins/file-vue.ts @@ -3,7 +3,7 @@ import { parse } from '../utils/parseSfc'; const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => { return { - version: 2.1, + version: 2.2, getLanguageId(fileName) { if (vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext))) { diff --git a/packages/language-core/lib/plugins/vue-root-tags.ts b/packages/language-core/lib/plugins/vue-root-tags.ts index cee5cedd2e..2e6d7f06b2 100644 --- a/packages/language-core/lib/plugins/vue-root-tags.ts +++ b/packages/language-core/lib/plugins/vue-root-tags.ts @@ -4,7 +4,7 @@ import { allCodeFeatures } from './shared'; const plugin: VueLanguagePlugin = () => { return { - version: 2.1, + version: 2.2, getEmbeddedCodes() { return [{ diff --git a/packages/language-core/lib/plugins/vue-script-js.ts b/packages/language-core/lib/plugins/vue-script-js.ts index debdfbd6f0..ebcb669772 100644 --- a/packages/language-core/lib/plugins/vue-script-js.ts +++ b/packages/language-core/lib/plugins/vue-script-js.ts @@ -3,7 +3,7 @@ import type { VueLanguagePlugin } from '../types'; const plugin: VueLanguagePlugin = ({ modules }) => { return { - version: 2.1, + version: 2.2, compileSFCScript(lang, script) { if (lang === 'js' || lang === 'ts' || lang === 'jsx' || lang === 'tsx') { diff --git a/packages/language-core/lib/plugins/vue-sfc-customblocks.ts b/packages/language-core/lib/plugins/vue-sfc-customblocks.ts index 91172a7119..4c8ae49d9d 100644 --- a/packages/language-core/lib/plugins/vue-sfc-customblocks.ts +++ b/packages/language-core/lib/plugins/vue-sfc-customblocks.ts @@ -3,7 +3,7 @@ import { allCodeFeatures } from './shared'; const plugin: VueLanguagePlugin = () => { return { - version: 2.1, + version: 2.2, getEmbeddedCodes(_fileName, sfc) { return sfc.customBlocks.map((customBlock, i) => ({ diff --git a/packages/language-core/lib/plugins/vue-sfc-scripts.ts b/packages/language-core/lib/plugins/vue-sfc-scripts.ts index e7596ff4ff..033f2fddfd 100644 --- a/packages/language-core/lib/plugins/vue-sfc-scripts.ts +++ b/packages/language-core/lib/plugins/vue-sfc-scripts.ts @@ -2,7 +2,7 @@ import type { VueLanguagePlugin } from '../types'; const plugin: VueLanguagePlugin = () => { return { - version: 2.1, + version: 2.2, getEmbeddedCodes(_fileName, sfc) { const names: { diff --git a/packages/language-core/lib/plugins/vue-sfc-styles.ts b/packages/language-core/lib/plugins/vue-sfc-styles.ts index 7128940aea..a3141a821d 100644 --- a/packages/language-core/lib/plugins/vue-sfc-styles.ts +++ b/packages/language-core/lib/plugins/vue-sfc-styles.ts @@ -3,7 +3,7 @@ import { allCodeFeatures } from './shared'; const plugin: VueLanguagePlugin = () => { return { - version: 2.1, + version: 2.2, getEmbeddedCodes(_fileName, sfc) { const result: { diff --git a/packages/language-core/lib/plugins/vue-sfc-template.ts b/packages/language-core/lib/plugins/vue-sfc-template.ts index c627eab975..eb4c9bcd8f 100644 --- a/packages/language-core/lib/plugins/vue-sfc-template.ts +++ b/packages/language-core/lib/plugins/vue-sfc-template.ts @@ -3,7 +3,7 @@ import { allCodeFeatures } from './shared'; const plugin: VueLanguagePlugin = () => { return { - version: 2.1, + version: 2.2, getEmbeddedCodes(_fileName, sfc) { if (sfc.template?.lang === 'html') { diff --git a/packages/language-core/lib/plugins/vue-style-css.ts b/packages/language-core/lib/plugins/vue-style-css.ts index f685ed8f91..49ede9f7f4 100644 --- a/packages/language-core/lib/plugins/vue-style-css.ts +++ b/packages/language-core/lib/plugins/vue-style-css.ts @@ -2,7 +2,7 @@ import type { VueLanguagePlugin } from '../types'; const plugin: VueLanguagePlugin = () => { return { - version: 2.1, + version: 2.2, compileSFCStyle(_lang, style) { return { diff --git a/packages/language-core/lib/plugins/vue-template-html.ts b/packages/language-core/lib/plugins/vue-template-html.ts index 9aa469e096..c907008937 100644 --- a/packages/language-core/lib/plugins/vue-template-html.ts +++ b/packages/language-core/lib/plugins/vue-template-html.ts @@ -17,7 +17,7 @@ const shouldAddSuffix = /(?<=<[^>/]+)$/; const plugin: VueLanguagePlugin = ({ modules }) => { return { - version: 2.1, + version: 2.2, compileSFCTemplate(lang, template, options) { if (lang === 'html' || lang === 'md') { diff --git a/packages/language-core/lib/plugins/vue-template-inline-css.ts b/packages/language-core/lib/plugins/vue-template-inline-css.ts index 6f13cfe05f..ff80abe077 100644 --- a/packages/language-core/lib/plugins/vue-template-inline-css.ts +++ b/packages/language-core/lib/plugins/vue-template-inline-css.ts @@ -11,7 +11,7 @@ const codeFeatures = { const plugin: VueLanguagePlugin = () => { return { - version: 2.1, + version: 2.2, getEmbeddedCodes(_fileName, sfc) { if (!sfc.template?.ast) { diff --git a/packages/language-core/lib/plugins/vue-template-inline-ts.ts b/packages/language-core/lib/plugins/vue-template-inline-ts.ts index 4ae42ca048..a0fc1d2b65 100644 --- a/packages/language-core/lib/plugins/vue-template-inline-ts.ts +++ b/packages/language-core/lib/plugins/vue-template-inline-ts.ts @@ -27,7 +27,7 @@ const plugin: VueLanguagePlugin = ctx => { const parseds = new WeakMap>(); return { - version: 2.1, + version: 2.2, getEmbeddedCodes(_fileName, sfc) { if (!sfc.template?.ast) { diff --git a/packages/language-core/lib/plugins/vue-tsx.ts b/packages/language-core/lib/plugins/vue-tsx.ts index 8f8315ebc1..6d94ad7ac8 100644 --- a/packages/language-core/lib/plugins/vue-tsx.ts +++ b/packages/language-core/lib/plugins/vue-tsx.ts @@ -16,7 +16,7 @@ const validLangs = new Set(['js', 'jsx', 'ts', 'tsx']); const plugin: VueLanguagePlugin = ctx => { return { - version: 2.1, + version: 2.2, requiredCompilerOptions: [ 'noPropertyAccessFromIndexSignature', diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index e8a5e07a3b..50cdcad51a 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -75,7 +75,7 @@ export interface VueCompilerOptions { >; } -export const validVersions = [2, 2.1] as const; +export const validVersions = [2, 2.1, 2.2] as const; export type VueLanguagePluginReturn = { version: typeof validVersions[number]; diff --git a/packages/language-plugin-pug/index.ts b/packages/language-plugin-pug/index.ts index 891efb4f6e..847495cabd 100644 --- a/packages/language-plugin-pug/index.ts +++ b/packages/language-plugin-pug/index.ts @@ -9,7 +9,7 @@ const plugin: VueLanguagePlugin = ({ modules }) => { return { name: require('./package.json').name, - version: 2.1, + version: 2.2, getEmbeddedCodes(_fileName, sfc) { if (sfc.template?.lang === 'pug') {