From 55fe6fbd8cf38404506d508a51098eb3802fa206 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 4 Jul 2024 21:06:21 +0800 Subject: [PATCH 01/39] chore: update insiders.json --- insiders.json | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/insiders.json b/insiders.json index 6d2ec1f3ac..8f3e1a08ec 100644 --- a/insiders.json +++ b/insiders.json @@ -1,6 +1,14 @@ { - "latest": "2.0.25", + "latest": "2.0.27", "versions": [ + { + "version": "2.0.27", + "date": "2024-07-04", + "downloads": { + "GitHub": "https://github.com/volarjs/insiders/releases/tag/v2.0.27", + "AFDIAN": "https://afdian.net/p/fbd701003a0511ef806352540025c377" + } + }, { "version": "2.0.25", "date": "2024-6-30", From 1d0f6746fa39553f0c281ed892e51fa748a060b0 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 5 Jul 2024 06:08:10 +0800 Subject: [PATCH 02/39] chore: update insiders.json --- insiders.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/insiders.json b/insiders.json index 8f3e1a08ec..7a0a860d7c 100644 --- a/insiders.json +++ b/insiders.json @@ -3,7 +3,7 @@ "versions": [ { "version": "2.0.27", - "date": "2024-07-04", + "date": "2024-7-4", "downloads": { "GitHub": "https://github.com/volarjs/insiders/releases/tag/v2.0.27", "AFDIAN": "https://afdian.net/p/fbd701003a0511ef806352540025c377" @@ -130,4 +130,4 @@ } } ] -} \ No newline at end of file +} From 36cef927bccc3c3331b1077d6c982e921bb24fc5 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 5 Jul 2024 08:04:24 +0800 Subject: [PATCH 03/39] chore: replace type import to triple-slash directives for `@volar/typescript` --- packages/language-core/lib/languageModule.ts | 11 ++++++----- packages/language-service/index.ts | 2 ++ .../lib/plugins/vue-autoinsert-dotvalue.ts | 1 - 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/language-core/lib/languageModule.ts b/packages/language-core/lib/languageModule.ts index f416de2e5e..2586c82465 100644 --- a/packages/language-core/lib/languageModule.ts +++ b/packages/language-core/lib/languageModule.ts @@ -1,14 +1,15 @@ +/// + import { forEachEmbeddedCode, type LanguagePlugin } from '@volar/language-core'; +import * as CompilerDOM from '@vue/compiler-dom'; import type * as ts from 'typescript'; import { getBasePlugins } from './plugins'; -import type { VueCompilerOptions, VueLanguagePlugin } from './types'; -import { VueVirtualCode } from './virtualFile/vueFile'; -import * as CompilerDOM from '@vue/compiler-dom'; -import * as CompilerVue2 from './utils/vue2TemplateCompiler'; import useHtmlFilePlugin from './plugins/file-html'; import useMdFilePlugin from './plugins/file-md'; import useVueFilePlugin from './plugins/file-vue'; -import type * as _ from '@volar/typescript'; +import type { VueCompilerOptions, VueLanguagePlugin } from './types'; +import * as CompilerVue2 from './utils/vue2TemplateCompiler'; +import { VueVirtualCode } from './virtualFile/vueFile'; const normalFileRegistries: { key: string; diff --git a/packages/language-service/index.ts b/packages/language-service/index.ts index 12cd4e264a..f32460d04d 100644 --- a/packages/language-service/index.ts +++ b/packages/language-service/index.ts @@ -1,3 +1,5 @@ +/// + export * from '@volar/language-service'; export * from '@vue/language-core'; export * from './lib/ideFeatures/nameCasing'; diff --git a/packages/language-service/lib/plugins/vue-autoinsert-dotvalue.ts b/packages/language-service/lib/plugins/vue-autoinsert-dotvalue.ts index 69510758e7..6a347c6c68 100644 --- a/packages/language-service/lib/plugins/vue-autoinsert-dotvalue.ts +++ b/packages/language-service/lib/plugins/vue-autoinsert-dotvalue.ts @@ -3,7 +3,6 @@ import { hyphenateAttr } from '@vue/language-core'; import type * as ts from 'typescript'; import type { TextDocument } from 'vscode-languageserver-textdocument'; import { URI } from 'vscode-uri'; -import * as _ from '@volar/typescript'; const asts = new WeakMap(); From f6cf306f889d9fd412015944ecfdfd001d2a9f6a Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Mon, 8 Jul 2024 08:59:47 +0800 Subject: [PATCH 04/39] chore: correct changelog Volar version --- CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1e05ce6689..b587374184 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -18,7 +18,7 @@ ### Other Changes -- Upgraded Volar from `v2.4.0-alpha.2` to `v2.4.0-alpha.14`: +- Upgraded Volar from `v2.4.0-alpha.2` to `v2.4.0-alpha.15`: - Fixed an issue where, when Hybrid Mode is disabled, TS support for Vue files not included in tsconfig may be missing. - Improved the consistency of `vue-tsc` and `tsc` behavior. (#3526) - Fixed the `--clean` flag support for `vue-tsc`. From 519e916354fee59f8d80be63264ce3dc3c222bfc Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Tue, 9 Jul 2024 20:34:46 +0800 Subject: [PATCH 05/39] fix(language-core): getProjectVersion param has no effect --- packages/component-meta/lib/base.ts | 13 ++++----- packages/language-core/lib/languageModule.ts | 27 ++++++++++++++----- packages/language-server/lib/initialize.ts | 15 +++++------ packages/language-server/node.ts | 1 - .../tests/utils/createTester.ts | 17 +++++------- .../language-service/tests/utils/format.ts | 1 - packages/tsc/index.ts | 13 ++++----- packages/tsc/tests/dts.spec.ts | 13 ++++----- packages/typescript-plugin/index.ts | 13 ++++----- 9 files changed, 53 insertions(+), 60 deletions(-) diff --git a/packages/component-meta/lib/base.ts b/packages/component-meta/lib/base.ts index f83a497cce..d2e7302560 100644 --- a/packages/component-meta/lib/base.ts +++ b/packages/component-meta/lib/base.ts @@ -147,14 +147,11 @@ export function baseCreate( const vueLanguagePlugin = vue.createVueLanguagePlugin( ts, id => id, - () => projectHost.getProjectVersion?.() ?? '', - fileName => { - const fileMap = new vue.FileMap(ts.sys.useCaseSensitiveFileNames); - for (const vueFileName of projectHost.getScriptFileNames()) { - fileMap.set(vueFileName, undefined); - } - return fileMap.has(fileName); - }, + vue.createRootFileChecker( + projectHost.getProjectVersion ? () => projectHost.getProjectVersion!() : undefined, + () => projectHost.getScriptFileNames(), + ts.sys.useCaseSensitiveFileNames + ), projectHost.getCompilationSettings(), vueCompilerOptions ); diff --git a/packages/language-core/lib/languageModule.ts b/packages/language-core/lib/languageModule.ts index 2586c82465..8588b67bd3 100644 --- a/packages/language-core/lib/languageModule.ts +++ b/packages/language-core/lib/languageModule.ts @@ -1,6 +1,6 @@ /// -import { forEachEmbeddedCode, type LanguagePlugin } from '@volar/language-core'; +import { FileMap, forEachEmbeddedCode, type LanguagePlugin } from '@volar/language-core'; import * as CompilerDOM from '@vue/compiler-dom'; import type * as ts from 'typescript'; import { getBasePlugins } from './plugins'; @@ -53,10 +53,28 @@ function getFileRegistryKey( return JSON.stringify(values); } +export function createRootFileChecker( + getProjectVersion: (() => string) | undefined, + getRootFileNames: () => string[], + caseSensitive: boolean +) { + const fileNames = new FileMap(caseSensitive); + let projectVersion: string | undefined; + return (fileName: string) => { + if (!getProjectVersion || projectVersion !== getProjectVersion()) { + projectVersion = getProjectVersion?.(); + fileNames.clear(); + for (const rootFileName of getRootFileNames()) { + fileNames.set(rootFileName, undefined); + } + } + return fileNames.has(fileName); + }; +} + export function createVueLanguagePlugin( ts: typeof import('typescript'), asFileName: (scriptId: T) => string, - getProjectVersion: () => string, isRootFile: (fileName: string) => boolean, compilerOptions: ts.CompilerOptions, vueCompilerOptions: VueCompilerOptions @@ -80,8 +98,6 @@ export function createVueLanguagePlugin( const vitePressSfcPlugin = useMdFilePlugin(pluginContext); const petiteVueSfcPlugin = useHtmlFilePlugin(pluginContext); - let canonicalRootFileNamesVersion: string | undefined; - return { getLanguageId(scriptId) { if (vueCompilerOptions.extensions.some(ext => asFileName(scriptId).endsWith(ext))) { @@ -97,9 +113,6 @@ export function createVueLanguagePlugin( createVirtualCode(scriptId, languageId, snapshot) { if (languageId === 'vue' || languageId === 'markdown' || languageId === 'html') { const fileName = asFileName(scriptId); - if (getProjectVersion() !== canonicalRootFileNamesVersion) { - canonicalRootFileNamesVersion = getProjectVersion(); - } if (!pluginContext.globalTypesHolder && isRootFile(fileName)) { pluginContext.globalTypesHolder = fileName; } diff --git a/packages/language-server/lib/initialize.ts b/packages/language-server/lib/initialize.ts index 34def32f86..30dca84741 100644 --- a/packages/language-server/lib/initialize.ts +++ b/packages/language-server/lib/initialize.ts @@ -1,6 +1,6 @@ import type { LanguageServer } from '@volar/language-server'; import { createTypeScriptProject } from '@volar/language-server/node'; -import { createParsedCommandLine, createVueLanguagePlugin, FileMap, resolveVueCompilerOptions, VueCompilerOptions } from '@vue/language-core'; +import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin, resolveVueCompilerOptions, VueCompilerOptions } from '@vue/language-core'; import { Disposable, getFullLanguageServicePlugins, InitializeParams } from '@vue/language-service'; import type * as ts from 'typescript'; @@ -42,14 +42,11 @@ export function initialize( languagePlugins: [createVueLanguagePlugin( ts, s => uriConverter.asFileName(s), - () => projectHost.getProjectVersion?.() ?? '', - fileName => { - const fileMap = new FileMap(sys.useCaseSensitiveFileNames ?? false); - for (const vueFileName of projectHost.getScriptFileNames() ?? []) { - fileMap.set(vueFileName, undefined); - } - return fileMap.has(fileName); - }, + createRootFileChecker( + projectHost.getProjectVersion ? () => projectHost.getProjectVersion!() : undefined, + () => projectHost.getScriptFileNames(), + sys.useCaseSensitiveFileNames + ), compilerOptions, vueCompilerOptions )], diff --git a/packages/language-server/node.ts b/packages/language-server/node.ts index 888926236c..c1c6652f62 100644 --- a/packages/language-server/node.ts +++ b/packages/language-server/node.ts @@ -30,7 +30,6 @@ connection.onInitialize(params => { languagePlugins: [createVueLanguagePlugin( ts, asFileName, - () => '', () => false, commandLine.options, commandLine.vueOptions diff --git a/packages/language-service/tests/utils/createTester.ts b/packages/language-service/tests/utils/createTester.ts index 5fe69e8487..d79c3a5614 100644 --- a/packages/language-service/tests/utils/createTester.ts +++ b/packages/language-service/tests/utils/createTester.ts @@ -1,9 +1,9 @@ -import { FileMap, ProjectContext, createLanguage, createLanguageService, createUriMap } from '@volar/language-service'; +import { ProjectContext, createLanguage, createLanguageService, createUriMap } from '@volar/language-service'; import { TypeScriptProjectHost, createLanguageServiceHost, resolveFileLanguageId } from '@volar/typescript'; import * as path from 'path'; import * as ts from 'typescript'; import { URI } from 'vscode-uri'; -import { createParsedCommandLine, createVueLanguagePlugin, getFullLanguageServicePlugins } from '../..'; +import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin, getFullLanguageServicePlugins } from '../..'; import { createMockServiceEnv, fileNameToUri, uriToFileName } from './mockEnv'; export const rootUri = URI.file(path.resolve(__dirname, '../../../../test-workspace/language-service')); @@ -27,14 +27,11 @@ function createTester(rootUri: URI) { const vueLanguagePlugin = createVueLanguagePlugin( ts, uriToFileName, - () => projectHost.getProjectVersion?.() ?? '', - fileName => { - const fileMap = new FileMap(ts.sys.useCaseSensitiveFileNames); - for (const vueFileName of projectHost.getScriptFileNames()) { - fileMap.set(vueFileName, undefined); - } - return fileMap.has(fileName); - }, + createRootFileChecker( + projectHost.getProjectVersion ? () => projectHost.getProjectVersion!() : undefined, + () => projectHost.getScriptFileNames(), + ts.sys.useCaseSensitiveFileNames + ), parsedCommandLine.options, parsedCommandLine.vueOptions ); diff --git a/packages/language-service/tests/utils/format.ts b/packages/language-service/tests/utils/format.ts index 8b62801b82..1f236f21fa 100644 --- a/packages/language-service/tests/utils/format.ts +++ b/packages/language-service/tests/utils/format.ts @@ -8,7 +8,6 @@ const resolvedVueOptions = resolveVueCompilerOptions({}); const vueLanguagePlugin = createVueLanguagePlugin( ts, () => '', - () => '', () => false, {}, resolvedVueOptions diff --git a/packages/tsc/index.ts b/packages/tsc/index.ts index 96f216d061..0889132792 100644 --- a/packages/tsc/index.ts +++ b/packages/tsc/index.ts @@ -32,14 +32,11 @@ export function run() { const vueLanguagePlugin = vue.createVueLanguagePlugin( ts, id => id, - () => '', - fileName => { - const fileMap = new vue.FileMap(options.host?.useCaseSensitiveFileNames?.() ?? false); - for (const vueFileName of options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/'))) { - fileMap.set(vueFileName, undefined); - } - return fileMap.has(fileName); - }, + vue.createRootFileChecker( + undefined, + () => options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/')), + options.host?.useCaseSensitiveFileNames?.() ?? false + ), options.options, vueOptions ); diff --git a/packages/tsc/tests/dts.spec.ts b/packages/tsc/tests/dts.spec.ts index efb4fb6f30..d0ac81b6fc 100644 --- a/packages/tsc/tests/dts.spec.ts +++ b/packages/tsc/tests/dts.spec.ts @@ -34,14 +34,11 @@ describe('vue-tsc-dts', () => { const vueLanguagePlugin = vue.createVueLanguagePlugin( ts, id => id, - () => '', - fileName => { - const fileMap = new vue.FileMap(options.host?.useCaseSensitiveFileNames?.() ?? false); - for (const vueFileName of options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/'))) { - fileMap.set(vueFileName, undefined); - } - return fileMap.has(fileName); - }, + vue.createRootFileChecker( + undefined, + () => options.rootNames.map(rootName => rootName.replace(windowsPathReg, '/')), + options.host?.useCaseSensitiveFileNames?.() ?? false + ), options.options, vueOptions ); diff --git a/packages/typescript-plugin/index.ts b/packages/typescript-plugin/index.ts index 7269ab7f5e..37abdb3dd1 100644 --- a/packages/typescript-plugin/index.ts +++ b/packages/typescript-plugin/index.ts @@ -11,16 +11,13 @@ const plugin = createLanguageServicePlugin( const languagePlugin = vue.createVueLanguagePlugin( ts, id => id, - () => info.languageServiceHost.getProjectVersion?.() ?? '', info.project.projectKind === ts.server.ProjectKind.Inferred ? () => true - : fileName => { - const fileMap = new vue.FileMap(info.languageServiceHost.useCaseSensitiveFileNames?.() ?? false); - for (const vueFileName of externalFiles.get(info.project) ?? []) { - fileMap.set(vueFileName, undefined); - } - return fileMap.has(fileName); - }, + : vue.createRootFileChecker( + info.languageServiceHost.getProjectVersion ? () => info.languageServiceHost.getProjectVersion!() : undefined, + () => externalFiles.get(info.project) ?? [], + info.languageServiceHost.useCaseSensitiveFileNames?.() ?? false + ), info.languageServiceHost.getCompilationSettings(), vueOptions ); From e753366ff258764f2a54251ac1e2fa3bc026738e Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Tue, 9 Jul 2024 20:45:26 +0800 Subject: [PATCH 06/39] refactor(language-core): add getAllExtensions function --- packages/language-core/lib/languageModule.ts | 37 +++++++++++++------- packages/language-core/lib/utils/ts.ts | 31 +++++++--------- packages/language-server/lib/initialize.ts | 6 ++-- packages/tsc/index.ts | 6 +--- 4 files changed, 41 insertions(+), 39 deletions(-) diff --git a/packages/language-core/lib/languageModule.ts b/packages/language-core/lib/languageModule.ts index 8588b67bd3..8956150565 100644 --- a/packages/language-core/lib/languageModule.ts +++ b/packages/language-core/lib/languageModule.ts @@ -100,13 +100,14 @@ export function createVueLanguagePlugin( return { getLanguageId(scriptId) { - if (vueCompilerOptions.extensions.some(ext => asFileName(scriptId).endsWith(ext))) { + const fileName = asFileName(scriptId); + if (vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext))) { return 'vue'; } - if (vueCompilerOptions.vitePressExtensions.some(ext => asFileName(scriptId).endsWith(ext))) { + if (vueCompilerOptions.vitePressExtensions.some(ext => fileName.endsWith(ext))) { return 'markdown'; } - if (vueCompilerOptions.petiteVueExtensions.some(ext => asFileName(scriptId).endsWith(ext))) { + if (vueCompilerOptions.petiteVueExtensions.some(ext => fileName.endsWith(ext))) { return 'html'; } }, @@ -169,15 +170,12 @@ export function createVueLanguagePlugin( // } // }, typescript: { - extraFileExtensions: [ - ...vueCompilerOptions.extensions, - ...vueCompilerOptions.vitePressExtensions, - ...vueCompilerOptions.petiteVueExtensions, - ].map(ext => ({ - extension: ext.slice(1), - isMixedContent: true, - scriptKind: 7 satisfies ts.ScriptKind.Deferred, - })), + extraFileExtensions: getAllExtensions(vueCompilerOptions) + .map(ext => ({ + extension: ext.slice(1), + isMixedContent: true, + scriptKind: 7 satisfies ts.ScriptKind.Deferred, + })), getServiceScript(root) { for (const code of forEachEmbeddedCode(root)) { if (/script_(js|jsx|ts|tsx)/.test(code.id)) { @@ -204,3 +202,18 @@ export function createVueLanguagePlugin( ); } } + +export function getAllExtensions(options: VueCompilerOptions) { + const result = new Set(); + for (const key in options) { + if (key === 'extensions' || key.endsWith('Extensions')) { + const value = options[key as keyof VueCompilerOptions]; + if (Array.isArray(value) && value.every(v => typeof v === 'string')) { + for (const ext of value) { + result.add(ext); + } + } + } + } + return [...result]; +} diff --git a/packages/language-core/lib/utils/ts.ts b/packages/language-core/lib/utils/ts.ts index cefd77ea9d..08f3280c1f 100644 --- a/packages/language-core/lib/utils/ts.ts +++ b/packages/language-core/lib/utils/ts.ts @@ -1,6 +1,7 @@ import type * as ts from 'typescript'; import * as path from 'path-browserify'; import type { RawVueCompilerOptions, VueCompilerOptions, VueLanguagePlugin } from '../types'; +import { getAllExtensions } from '../languageModule'; export type ParsedCommandLine = ts.ParsedCommandLine & { vueOptions: VueCompilerOptions; @@ -36,15 +37,12 @@ export function createParsedCommandLineByJson( {}, configFileName, undefined, - [ - ...resolvedVueOptions.extensions, - ...resolvedVueOptions.vitePressExtensions, - ...resolvedVueOptions.petiteVueExtensions, - ].map(extension => ({ - extension: extension.slice(1), - isMixedContent: true, - scriptKind: ts.ScriptKind.Deferred, - })) + getAllExtensions(resolvedVueOptions) + .map(extension => ({ + extension: extension.slice(1), + isMixedContent: true, + scriptKind: ts.ScriptKind.Deferred, + })) ); // fix https://github.com/vuejs/language-tools/issues/1786 @@ -87,15 +85,12 @@ export function createParsedCommandLine( {}, tsConfigPath, undefined, - [ - ...resolvedVueOptions.extensions, - ...resolvedVueOptions.vitePressExtensions, - ...resolvedVueOptions.petiteVueExtensions, - ].map(extension => ({ - extension: extension.slice(1), - isMixedContent: true, - scriptKind: ts.ScriptKind.Deferred, - })) + getAllExtensions(resolvedVueOptions) + .map(extension => ({ + extension: extension.slice(1), + isMixedContent: true, + scriptKind: ts.ScriptKind.Deferred, + })) ); // fix https://github.com/vuejs/language-tools/issues/1786 diff --git a/packages/language-server/lib/initialize.ts b/packages/language-server/lib/initialize.ts index 30dca84741..d4f804d339 100644 --- a/packages/language-server/lib/initialize.ts +++ b/packages/language-server/lib/initialize.ts @@ -1,6 +1,6 @@ import type { LanguageServer } from '@volar/language-server'; import { createTypeScriptProject } from '@volar/language-server/node'; -import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin, resolveVueCompilerOptions, VueCompilerOptions } from '@vue/language-core'; +import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin, getAllExtensions, resolveVueCompilerOptions, VueCompilerOptions } from '@vue/language-core'; import { Disposable, getFullLanguageServicePlugins, InitializeParams } from '@vue/language-service'; import type * as ts from 'typescript'; @@ -62,9 +62,7 @@ export function initialize( function updateFileWatcher(vueCompilerOptions: VueCompilerOptions) { const extensions = [ 'js', 'cjs', 'mjs', 'ts', 'cts', 'mts', 'jsx', 'tsx', 'json', - ...vueCompilerOptions.extensions.map(ext => ext.slice(1)), - ...vueCompilerOptions.vitePressExtensions.map(ext => ext.slice(1)), - ...vueCompilerOptions.petiteVueExtensions.map(ext => ext.slice(1)), + ...getAllExtensions(vueCompilerOptions).map(ext => ext.slice(1)), ]; const newExtensions = extensions.filter(ext => !watchingExtensions.has(ext)); if (newExtensions.length) { diff --git a/packages/tsc/index.ts b/packages/tsc/index.ts index 0889132792..5189f0715e 100644 --- a/packages/tsc/index.ts +++ b/packages/tsc/index.ts @@ -16,11 +16,7 @@ export function run() { const vueOptions = typeof configFilePath === 'string' ? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/')).vueOptions : vue.resolveVueCompilerOptions({}); - const allExtensions = [ - ...vueOptions.extensions, - ...vueOptions.vitePressExtensions, - ...vueOptions.petiteVueExtensions, - ]; + const allExtensions = vue.getAllExtensions(vueOptions); if ( runExtensions.length === allExtensions.length && runExtensions.every(ext => allExtensions.includes(ext)) From dc7bffb22fef24b96fcbaad0942ca6099625fdf6 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Tue, 9 Jul 2024 21:18:04 +0800 Subject: [PATCH 07/39] feat(language-core): plugin API 2.1 --- packages/language-core/lib/languageModule.ts | 35 ++++++------------- packages/language-core/lib/plugins.ts | 24 ++++++++----- .../language-core/lib/plugins/file-html.ts | 19 ++++++++-- packages/language-core/lib/plugins/file-md.ts | 19 ++++++++-- .../language-core/lib/plugins/file-vue.ts | 19 ++++++++-- .../lib/plugins/vue-script-js.ts | 2 +- .../lib/plugins/vue-sfc-customblocks.ts | 2 +- .../lib/plugins/vue-sfc-scripts.ts | 2 +- .../lib/plugins/vue-sfc-styles.ts | 2 +- .../lib/plugins/vue-sfc-template.ts | 2 +- .../lib/plugins/vue-template-html.ts | 2 +- .../lib/plugins/vue-template-inline-css.ts | 2 +- .../lib/plugins/vue-template-inline-ts.ts | 2 +- packages/language-core/lib/plugins/vue-tsx.ts | 2 +- packages/language-core/lib/types.ts | 7 ++-- .../lib/virtualFile/computedVueSfc.ts | 4 ++- .../language-core/lib/virtualFile/vueFile.ts | 2 +- packages/language-plugin-pug/index.ts | 2 +- 18 files changed, 93 insertions(+), 56 deletions(-) diff --git a/packages/language-core/lib/languageModule.ts b/packages/language-core/lib/languageModule.ts index 8956150565..2f86d6f558 100644 --- a/packages/language-core/lib/languageModule.ts +++ b/packages/language-core/lib/languageModule.ts @@ -3,10 +3,7 @@ import { FileMap, forEachEmbeddedCode, type LanguagePlugin } from '@volar/language-core'; import * as CompilerDOM from '@vue/compiler-dom'; import type * as ts from 'typescript'; -import { getBasePlugins } from './plugins'; -import useHtmlFilePlugin from './plugins/file-html'; -import useMdFilePlugin from './plugins/file-md'; -import useVueFilePlugin from './plugins/file-vue'; +import { createPlugins } from './plugins'; import type { VueCompilerOptions, VueLanguagePlugin } from './types'; import * as CompilerVue2 from './utils/vue2TemplateCompiler'; import { VueVirtualCode } from './virtualFile/vueFile'; @@ -93,27 +90,21 @@ export function createVueLanguagePlugin( vueCompilerOptions, globalTypesHolder: undefined, }; - const basePlugins = getBasePlugins(pluginContext); - const vueSfcPlugin = useVueFilePlugin(pluginContext); - const vitePressSfcPlugin = useMdFilePlugin(pluginContext); - const petiteVueSfcPlugin = useHtmlFilePlugin(pluginContext); + const plugins = createPlugins(pluginContext); return { getLanguageId(scriptId) { const fileName = asFileName(scriptId); - if (vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext))) { - return 'vue'; - } - if (vueCompilerOptions.vitePressExtensions.some(ext => fileName.endsWith(ext))) { - return 'markdown'; - } - if (vueCompilerOptions.petiteVueExtensions.some(ext => fileName.endsWith(ext))) { - return 'html'; + for (const plugin of plugins) { + const languageId = plugin.getLanguageId?.(fileName); + if (languageId) { + return languageId; + } } }, createVirtualCode(scriptId, languageId, snapshot) { - if (languageId === 'vue' || languageId === 'markdown' || languageId === 'html') { - const fileName = asFileName(scriptId); + const fileName = asFileName(scriptId); + if (plugins.some(plugin => plugin.isValidFile?.(fileName, languageId))) { if (!pluginContext.globalTypesHolder && isRootFile(fileName)) { pluginContext.globalTypesHolder = fileName; } @@ -129,11 +120,7 @@ export function createVueLanguagePlugin( languageId, snapshot, vueCompilerOptions, - languageId === 'html' - ? [petiteVueSfcPlugin, ...basePlugins] - : languageId === 'markdown' - ? [vitePressSfcPlugin, ...basePlugins] - : [vueSfcPlugin, ...basePlugins], + plugins, ts, ); fileRegistry.set(fileName, code); @@ -197,7 +184,7 @@ export function createVueLanguagePlugin( function getFileRegistry(isGlobalTypesHolder: boolean) { return getVueFileRegistry( isGlobalTypesHolder, - getFileRegistryKey(compilerOptions, vueCompilerOptions, basePlugins), + getFileRegistryKey(compilerOptions, vueCompilerOptions, plugins), vueCompilerOptions.plugins ); } diff --git a/packages/language-core/lib/plugins.ts b/packages/language-core/lib/plugins.ts index 205d881ea6..31d8030572 100644 --- a/packages/language-core/lib/plugins.ts +++ b/packages/language-core/lib/plugins.ts @@ -1,19 +1,26 @@ +import useHtmlFilePlugin from './plugins/file-html'; +import useMdFilePlugin from './plugins/file-md'; +import useVueFilePlugin from './plugins/file-vue'; +import vueScriptJsPlugin from './plugins/vue-script-js'; 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 vueScriptJsPlugin from './plugins/vue-script-js'; import vueTemplateHtmlPlugin from './plugins/vue-template-html'; import vueTemplateInlineCssPlugin from './plugins/vue-template-inline-css'; import vueTemplateInlineTsPlugin from './plugins/vue-template-inline-ts'; import vueTsx from './plugins/vue-tsx'; -import { pluginVersion, type VueLanguagePlugin } from './types'; +import { validVersions, VueLanguagePlugin } from './types'; -export * from './plugins/shared' +export * from './plugins/shared'; -export function getBasePlugins(pluginContext: Parameters[0]) { +export function createPlugins(pluginContext: Parameters[0]) { const plugins: VueLanguagePlugin[] = [ + ...pluginContext.vueCompilerOptions.plugins, + useVueFilePlugin, + useMdFilePlugin, + useHtmlFilePlugin, vueScriptJsPlugin, vueTemplateHtmlPlugin, vueTemplateInlineCssPlugin, @@ -23,7 +30,6 @@ export function getBasePlugins(pluginContext: Parameters[0]) vueSfcScriptsFormat, vueSfcTemplate, vueTsx, - ...pluginContext.vueCompilerOptions.plugins, ]; const pluginInstances = plugins @@ -44,10 +50,10 @@ export function getBasePlugins(pluginContext: Parameters[0]) }); return pluginInstances.filter(plugin => { - const valid = plugin.version === pluginVersion; - if (!valid) { - console.warn(`[Vue] Plugin ${JSON.stringify(plugin.name)} API version incompatible, expected "${pluginVersion}" but got "${plugin.version}".`); + if (!validVersions.includes(plugin.version)) { + console.warn(`[Vue] Plugin ${plugin.name} is not compatible with the current Vue language tools version. (version: ${plugin.version}, supported versions: ${JSON.stringify(validVersions)})`); + return false; } - return valid; + return true; }); } diff --git a/packages/language-core/lib/plugins/file-html.ts b/packages/language-core/lib/plugins/file-html.ts index 353cb3d8a8..036d6bf03b 100644 --- a/packages/language-core/lib/plugins/file-html.ts +++ b/packages/language-core/lib/plugins/file-html.ts @@ -4,13 +4,26 @@ import type { VueLanguagePlugin } from '../types'; const sfcBlockReg = /\<(script|style)\b([\s\S]*?)\>([\s\S]*?)\<\/\1\>/g; const langReg = /\blang\s*=\s*(['\"]?)(\S*)\b\1/; -const plugin: VueLanguagePlugin = () => { +const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => { return { - version: 2, + version: 2.1, - parseSFC(fileName, content) { + getLanguageId(fileName) { + if (vueCompilerOptions.petiteVueExtensions.some(ext => fileName.endsWith(ext))) { + return 'html'; + } + }, + + isValidFile(_fileName, languageId) { + return languageId === 'html'; + }, + + parseSFC2(fileName, languageId, content) { + if (languageId !== 'html') { + return; + } let sfc: SFCParseResult = { descriptor: { diff --git a/packages/language-core/lib/plugins/file-md.ts b/packages/language-core/lib/plugins/file-md.ts index fde444fd05..1c3bf353a5 100644 --- a/packages/language-core/lib/plugins/file-md.ts +++ b/packages/language-core/lib/plugins/file-md.ts @@ -13,13 +13,26 @@ const angleBracketReg = /\<\S*\:\S*\>/g; const linkReg = /\[[\s\S]*?\]\([\s\S]*?\)/g; const codeSnippetImportReg = /^\s*<<<\s*.+/gm; -const plugin: VueLanguagePlugin = () => { +const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => { return { - version: 2, + version: 2.1, - parseSFC(_fileName, content) { + getLanguageId(fileName) { + if (vueCompilerOptions.vitePressExtensions.some(ext => fileName.endsWith(ext))) { + return 'markdown'; + } + }, + + isValidFile(_fileName, languageId) { + return languageId === 'markdown'; + }, + + parseSFC2(_fileName, languageId, content) { + if (languageId !== 'markdown') { + return; + } content = content // code block diff --git a/packages/language-core/lib/plugins/file-vue.ts b/packages/language-core/lib/plugins/file-vue.ts index 6c94322ef8..476a44b015 100644 --- a/packages/language-core/lib/plugins/file-vue.ts +++ b/packages/language-core/lib/plugins/file-vue.ts @@ -1,13 +1,26 @@ import type { VueLanguagePlugin } from '../types'; import { parse } from '../utils/parseSfc'; -const plugin: VueLanguagePlugin = _ctx => { +const plugin: VueLanguagePlugin = ({ vueCompilerOptions }) => { return { - version: 2, + version: 2.1, - parseSFC(_fileName, content) { + getLanguageId(fileName) { + if (vueCompilerOptions.extensions.some(ext => fileName.endsWith(ext))) { + return 'vue'; + } + }, + + isValidFile(_fileName, languageId) { + return languageId === 'vue'; + }, + + parseSFC2(_fileName, languageId, content) { + if (languageId !== 'vue') { + return; + } return parse(content); }, diff --git a/packages/language-core/lib/plugins/vue-script-js.ts b/packages/language-core/lib/plugins/vue-script-js.ts index 1e47036f6b..225ebaf5ab 100644 --- a/packages/language-core/lib/plugins/vue-script-js.ts +++ b/packages/language-core/lib/plugins/vue-script-js.ts @@ -4,7 +4,7 @@ const plugin: VueLanguagePlugin = ({ modules }) => { return { - version: 2, + version: 2.1, 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 2fe33eb4b2..be3068d836 100644 --- a/packages/language-core/lib/plugins/vue-sfc-customblocks.ts +++ b/packages/language-core/lib/plugins/vue-sfc-customblocks.ts @@ -5,7 +5,7 @@ const plugin: VueLanguagePlugin = () => { return { - version: 2, + version: 2.1, 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 be30eed318..3939546239 100644 --- a/packages/language-core/lib/plugins/vue-sfc-scripts.ts +++ b/packages/language-core/lib/plugins/vue-sfc-scripts.ts @@ -4,7 +4,7 @@ const plugin: VueLanguagePlugin = () => { return { - version: 2, + version: 2.1, 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 e473f78799..c1f8323e1d 100644 --- a/packages/language-core/lib/plugins/vue-sfc-styles.ts +++ b/packages/language-core/lib/plugins/vue-sfc-styles.ts @@ -5,7 +5,7 @@ const plugin: VueLanguagePlugin = () => { return { - version: 2, + version: 2.1, 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 3350e9b7a5..1dabe5f1d3 100644 --- a/packages/language-core/lib/plugins/vue-sfc-template.ts +++ b/packages/language-core/lib/plugins/vue-sfc-template.ts @@ -5,7 +5,7 @@ const plugin: VueLanguagePlugin = () => { return { - version: 2, + version: 2.1, getEmbeddedCodes(_fileName, sfc) { if (sfc.template) { diff --git a/packages/language-core/lib/plugins/vue-template-html.ts b/packages/language-core/lib/plugins/vue-template-html.ts index f6c324ae9e..9808dcf9d2 100644 --- a/packages/language-core/lib/plugins/vue-template-html.ts +++ b/packages/language-core/lib/plugins/vue-template-html.ts @@ -12,7 +12,7 @@ const plugin: VueLanguagePlugin = ({ modules }) => { return { - version: 2, + version: 2.1, compileSFCTemplate(lang, template, options) { 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 f8d147720b..cd285bf75a 100644 --- a/packages/language-core/lib/plugins/vue-template-inline-css.ts +++ b/packages/language-core/lib/plugins/vue-template-inline-css.ts @@ -13,7 +13,7 @@ const plugin: VueLanguagePlugin = () => { return { - version: 2, + version: 2.1, 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 99e3099c0f..ad38f5e013 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 => { return { - version: 2, + version: 2.1, 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 960117985e..21ff38353a 100644 --- a/packages/language-core/lib/plugins/vue-tsx.ts +++ b/packages/language-core/lib/plugins/vue-tsx.ts @@ -13,7 +13,7 @@ const plugin: VueLanguagePlugin = ctx => { return { - version: 2, + version: 2.1, requiredCompilerOptions: [ 'noPropertyAccessFromIndexSignature', diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index 577c92f0ab..2cedddf45b 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -57,7 +57,7 @@ export interface VueCompilerOptions { experimentalModelPropName: Record | Record[]>>; } -export const pluginVersion = 2; +export const validVersions = [2, 2.1] as const; export type VueLanguagePlugin = (ctx: { modules: { @@ -68,11 +68,14 @@ export type VueLanguagePlugin = (ctx: { vueCompilerOptions: VueCompilerOptions; globalTypesHolder: string | undefined; }) => { - version: typeof pluginVersion; + version: 2.1; name?: string; order?: number; requiredCompilerOptions?: string[]; + getLanguageId?(fileName: string): string | undefined; + isValidFile?(fileName: string, languageId: string): boolean; parseSFC?(fileName: string, content: string): SFCParseResult | undefined; + parseSFC2?(fileName: string, languageId: string, content: string): SFCParseResult | undefined; updateSFC?(oldResult: SFCParseResult, textChange: { start: number, end: number, newText: string; }): SFCParseResult | undefined; resolveTemplateCompilerOptions?(options: CompilerDOM.CompilerOptions): CompilerDOM.CompilerOptions; compileSFCScript?(lang: string, script: string): ts.SourceFile | undefined; diff --git a/packages/language-core/lib/virtualFile/computedVueSfc.ts b/packages/language-core/lib/virtualFile/computedVueSfc.ts index 21e5280ffe..42f6276feb 100644 --- a/packages/language-core/lib/virtualFile/computedVueSfc.ts +++ b/packages/language-core/lib/virtualFile/computedVueSfc.ts @@ -6,6 +6,7 @@ import type { VueLanguagePlugin } from '../types'; export function computedVueSfc( plugins: ReturnType[], fileName: string, + languageId: string, snapshot: () => ts.IScriptSnapshot ) { @@ -36,7 +37,8 @@ export function computedVueSfc( } for (const plugin of plugins) { - const sfc = plugin.parseSFC?.(fileName, snapshot().getText(0, snapshot().getLength())); + const sfc = plugin.parseSFC?.(fileName, snapshot().getText(0, snapshot().getLength())) + ?? plugin.parseSFC2?.(fileName, languageId, snapshot().getText(0, snapshot().getLength())); if (sfc) { if (!sfc.errors.length) { cache = { diff --git a/packages/language-core/lib/virtualFile/vueFile.ts b/packages/language-core/lib/virtualFile/vueFile.ts index c1e6211eb5..b193d72c2e 100644 --- a/packages/language-core/lib/virtualFile/vueFile.ts +++ b/packages/language-core/lib/virtualFile/vueFile.ts @@ -17,7 +17,7 @@ export class VueVirtualCode implements VirtualCode { // computeds - getVueSfc = computedVueSfc(this.plugins, this.fileName, () => this._snapshot()); + getVueSfc = computedVueSfc(this.plugins, this.fileName, this.languageId, () => this._snapshot()); sfc = computedSfc(this.ts, this.plugins, this.fileName, () => this._snapshot(), this.getVueSfc); getMappings = computedMappings(() => this._snapshot(), this.sfc); getEmbeddedCodes = computedFiles(this.plugins, this.fileName, this.sfc); diff --git a/packages/language-plugin-pug/index.ts b/packages/language-plugin-pug/index.ts index 67caa9893f..a8036a4d59 100644 --- a/packages/language-plugin-pug/index.ts +++ b/packages/language-plugin-pug/index.ts @@ -8,7 +8,7 @@ const plugin: VueLanguagePlugin = ({ modules }) => { name: require('./package.json').name, - version: 2, + version: 2.1, compileSFCTemplate(lang, template, options) { From 0cb43aa070dec3cdc8d6cc5c76c31de325d91aba Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Tue, 9 Jul 2024 21:19:22 +0800 Subject: [PATCH 08/39] chore(language-core): languageModule.ts -> languagePlugin.ts --- packages/language-core/index.ts | 2 +- .../language-core/lib/{languageModule.ts => languagePlugin.ts} | 0 packages/language-core/lib/utils/ts.ts | 2 +- 3 files changed, 2 insertions(+), 2 deletions(-) rename packages/language-core/lib/{languageModule.ts => languagePlugin.ts} (100%) diff --git a/packages/language-core/index.ts b/packages/language-core/index.ts index 390a66f6aa..d539d6591c 100644 --- a/packages/language-core/index.ts +++ b/packages/language-core/index.ts @@ -1,5 +1,5 @@ export * from './lib/codegen/template'; -export * from './lib/languageModule'; +export * from './lib/languagePlugin'; export * from './lib/parsers/scriptSetupRanges'; export * from './lib/plugins'; export * from './lib/virtualFile/vueFile'; diff --git a/packages/language-core/lib/languageModule.ts b/packages/language-core/lib/languagePlugin.ts similarity index 100% rename from packages/language-core/lib/languageModule.ts rename to packages/language-core/lib/languagePlugin.ts diff --git a/packages/language-core/lib/utils/ts.ts b/packages/language-core/lib/utils/ts.ts index 08f3280c1f..0d0cf2bbf7 100644 --- a/packages/language-core/lib/utils/ts.ts +++ b/packages/language-core/lib/utils/ts.ts @@ -1,7 +1,7 @@ import type * as ts from 'typescript'; import * as path from 'path-browserify'; import type { RawVueCompilerOptions, VueCompilerOptions, VueLanguagePlugin } from '../types'; -import { getAllExtensions } from '../languageModule'; +import { getAllExtensions } from '../languagePlugin'; export type ParsedCommandLine = ts.ParsedCommandLine & { vueOptions: VueCompilerOptions; From 71ad9c427261f46cdbc232b07f9135a1fd8a15da Mon Sep 17 00:00:00 2001 From: Ray Date: Tue, 9 Jul 2024 22:52:19 +0800 Subject: [PATCH 09/39] fix(vscode): add vue vine to hybrid mode compatible list (#4543) --- extensions/vscode/src/common.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/extensions/vscode/src/common.ts b/extensions/vscode/src/common.ts index a1339d207a..985eefaf31 100644 --- a/extensions/vscode/src/common.ts +++ b/extensions/vscode/src/common.ts @@ -62,6 +62,7 @@ function isExtensionCompatibleWithHybridMode(extension: vscode.Extension) { || extension.id === 'styled-components.vscode-styled-components' || extension.id === 'Divlo.vscode-styled-jsx-languageserver' || extension.id === 'nrwl.angular-console' + || extension.id === 'ShenQingchuan.vue-vine-extension' ) { return true; } From c39f56253295aef3ba0001a47cab6e1dd4244bb0 Mon Sep 17 00:00:00 2001 From: David Matter Date: Tue, 9 Jul 2024 16:54:11 +0200 Subject: [PATCH 10/39] test: global components prop validation (#4542) Co-authored-by: Ray --- test-workspace/tsc/#4503/globalcomp.vue | 9 +++++++++ test-workspace/tsc/#4503/globals.d.ts | 9 +++++++++ test-workspace/tsc/#4503/main.vue | 6 ++++++ test-workspace/tsc/#4503/tsconfig.json | 8 ++++++++ 4 files changed, 32 insertions(+) create mode 100644 test-workspace/tsc/#4503/globalcomp.vue create mode 100644 test-workspace/tsc/#4503/globals.d.ts create mode 100644 test-workspace/tsc/#4503/main.vue create mode 100644 test-workspace/tsc/#4503/tsconfig.json diff --git a/test-workspace/tsc/#4503/globalcomp.vue b/test-workspace/tsc/#4503/globalcomp.vue new file mode 100644 index 0000000000..bd45f2ea96 --- /dev/null +++ b/test-workspace/tsc/#4503/globalcomp.vue @@ -0,0 +1,9 @@ + + + diff --git a/test-workspace/tsc/#4503/globals.d.ts b/test-workspace/tsc/#4503/globals.d.ts new file mode 100644 index 0000000000..5e5942a9a6 --- /dev/null +++ b/test-workspace/tsc/#4503/globals.d.ts @@ -0,0 +1,9 @@ +import type globalcomp from './globalcomp.vue'; + +declare module 'vue' { + export interface GlobalComponents { + globalcomp: typeof globalcomp + } +} + +export { }; diff --git a/test-workspace/tsc/#4503/main.vue b/test-workspace/tsc/#4503/main.vue new file mode 100644 index 0000000000..d3fd5948e9 --- /dev/null +++ b/test-workspace/tsc/#4503/main.vue @@ -0,0 +1,6 @@ + + + diff --git a/test-workspace/tsc/#4503/tsconfig.json b/test-workspace/tsc/#4503/tsconfig.json new file mode 100644 index 0000000000..a4a2260e2a --- /dev/null +++ b/test-workspace/tsc/#4503/tsconfig.json @@ -0,0 +1,8 @@ +{ + "extends": "../../tsconfig.json", + "include": [ "**/*" ], + "compilerOptions": { + "checkJs": true, + "strict": true, + }, +} \ No newline at end of file From 699d2dc84ac2684024410d0b6986034f4024907a Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <32807958+zhiyuanzmj@users.noreply.github.com> Date: Wed, 10 Jul 2024 16:16:07 +0800 Subject: [PATCH 11/39] revert(language-core): vueCompilerOptions.plugins should be the end of plugins (#4573) --- packages/language-core/lib/plugins.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/language-core/lib/plugins.ts b/packages/language-core/lib/plugins.ts index 31d8030572..9515379ca2 100644 --- a/packages/language-core/lib/plugins.ts +++ b/packages/language-core/lib/plugins.ts @@ -17,7 +17,6 @@ export * from './plugins/shared'; export function createPlugins(pluginContext: Parameters[0]) { const plugins: VueLanguagePlugin[] = [ - ...pluginContext.vueCompilerOptions.plugins, useVueFilePlugin, useMdFilePlugin, useHtmlFilePlugin, @@ -30,6 +29,7 @@ export function createPlugins(pluginContext: Parameters[0]) { vueSfcScriptsFormat, vueSfcTemplate, vueTsx, + ...pluginContext.vueCompilerOptions.plugins, ]; const pluginInstances = plugins From ce61a0d189e1ad35e087fa5cdc7ff06dc1eda59b Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Wed, 10 Jul 2024 17:19:20 +0800 Subject: [PATCH 12/39] fix(language-core): preserve backward compatibility --- packages/component-meta/lib/base.ts | 2 +- packages/language-core/lib/languagePlugin.ts | 18 ++++++++++++++++++ packages/language-server/lib/initialize.ts | 4 ++-- packages/language-server/node.ts | 4 ++-- .../tests/utils/createTester.ts | 4 ++-- .../language-service/tests/utils/format.ts | 4 ++-- packages/tsc/index.ts | 2 +- packages/tsc/tests/dts.spec.ts | 2 +- packages/typescript-plugin/index.ts | 2 +- 9 files changed, 30 insertions(+), 12 deletions(-) diff --git a/packages/component-meta/lib/base.ts b/packages/component-meta/lib/base.ts index d2e7302560..2b18d45d16 100644 --- a/packages/component-meta/lib/base.ts +++ b/packages/component-meta/lib/base.ts @@ -144,7 +144,7 @@ export function baseCreate( } }; - const vueLanguagePlugin = vue.createVueLanguagePlugin( + const vueLanguagePlugin = vue.createVueLanguagePlugin2( ts, id => id, vue.createRootFileChecker( diff --git a/packages/language-core/lib/languagePlugin.ts b/packages/language-core/lib/languagePlugin.ts index 2f86d6f558..13d2d9c86f 100644 --- a/packages/language-core/lib/languagePlugin.ts +++ b/packages/language-core/lib/languagePlugin.ts @@ -69,7 +69,25 @@ export function createRootFileChecker( }; } +// TODO: replace `createVueLanguagePlugin` with `createVueLanguagePlugin2` in 2.1 export function createVueLanguagePlugin( + ts: typeof import('typescript'), + asFileName: (scriptId: T) => string, + _getProjectVersion: (() => string) | undefined, + isRootFile: (fileName: string) => boolean, + compilerOptions: ts.CompilerOptions, + vueCompilerOptions: VueCompilerOptions +): LanguagePlugin { + return createVueLanguagePlugin2( + ts, + asFileName, + isRootFile, + compilerOptions, + vueCompilerOptions, + ); +} + +export function createVueLanguagePlugin2( ts: typeof import('typescript'), asFileName: (scriptId: T) => string, isRootFile: (fileName: string) => boolean, diff --git a/packages/language-server/lib/initialize.ts b/packages/language-server/lib/initialize.ts index d4f804d339..042e6d13f5 100644 --- a/packages/language-server/lib/initialize.ts +++ b/packages/language-server/lib/initialize.ts @@ -1,6 +1,6 @@ import type { LanguageServer } from '@volar/language-server'; import { createTypeScriptProject } from '@volar/language-server/node'; -import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin, getAllExtensions, resolveVueCompilerOptions, VueCompilerOptions } from '@vue/language-core'; +import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin2, getAllExtensions, resolveVueCompilerOptions, VueCompilerOptions } from '@vue/language-core'; import { Disposable, getFullLanguageServicePlugins, InitializeParams } from '@vue/language-service'; import type * as ts from 'typescript'; @@ -39,7 +39,7 @@ export function initialize( } updateFileWatcher(vueCompilerOptions); return { - languagePlugins: [createVueLanguagePlugin( + languagePlugins: [createVueLanguagePlugin2( ts, s => uriConverter.asFileName(s), createRootFileChecker( diff --git a/packages/language-server/node.ts b/packages/language-server/node.ts index c1c6652f62..850a5dec91 100644 --- a/packages/language-server/node.ts +++ b/packages/language-server/node.ts @@ -1,5 +1,5 @@ import { createConnection, createServer, loadTsdkByPath } from '@volar/language-server/node'; -import { createParsedCommandLine, createVueLanguagePlugin, resolveVueCompilerOptions } from '@vue/language-core'; +import { createParsedCommandLine, createVueLanguagePlugin2, resolveVueCompilerOptions } from '@vue/language-core'; import { getHybridModeLanguageServicePlugins } from '@vue/language-service'; import * as namedPipeClient from '@vue/typescript-plugin/lib/client'; import { createHybridModeProject } from './lib/hybridModeProject'; @@ -27,7 +27,7 @@ connection.onInitialize(params => { options: ts.getDefaultCompilerOptions(), }; return { - languagePlugins: [createVueLanguagePlugin( + languagePlugins: [createVueLanguagePlugin2( ts, asFileName, () => false, diff --git a/packages/language-service/tests/utils/createTester.ts b/packages/language-service/tests/utils/createTester.ts index d79c3a5614..10f6c7d77d 100644 --- a/packages/language-service/tests/utils/createTester.ts +++ b/packages/language-service/tests/utils/createTester.ts @@ -3,7 +3,7 @@ import { TypeScriptProjectHost, createLanguageServiceHost, resolveFileLanguageId import * as path from 'path'; import * as ts from 'typescript'; import { URI } from 'vscode-uri'; -import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin, getFullLanguageServicePlugins } from '../..'; +import { createParsedCommandLine, createRootFileChecker, createVueLanguagePlugin2, getFullLanguageServicePlugins } from '../..'; import { createMockServiceEnv, fileNameToUri, uriToFileName } from './mockEnv'; export const rootUri = URI.file(path.resolve(__dirname, '../../../../test-workspace/language-service')); @@ -24,7 +24,7 @@ function createTester(rootUri: URI) { getCompilationSettings: () => parsedCommandLine.options, getScriptSnapshot, }; - const vueLanguagePlugin = createVueLanguagePlugin( + const vueLanguagePlugin = createVueLanguagePlugin2( ts, uriToFileName, createRootFileChecker( diff --git a/packages/language-service/tests/utils/format.ts b/packages/language-service/tests/utils/format.ts index 1f236f21fa..05dfb55c58 100644 --- a/packages/language-service/tests/utils/format.ts +++ b/packages/language-service/tests/utils/format.ts @@ -2,10 +2,10 @@ import * as kit from '@volar/kit'; import * as ts from 'typescript'; import { describe, expect, it } from 'vitest'; import type { URI } from 'vscode-uri'; -import { createVueLanguagePlugin, getFullLanguageServicePlugins, resolveVueCompilerOptions } from '../..'; +import { createVueLanguagePlugin2, getFullLanguageServicePlugins, resolveVueCompilerOptions } from '../..'; const resolvedVueOptions = resolveVueCompilerOptions({}); -const vueLanguagePlugin = createVueLanguagePlugin( +const vueLanguagePlugin = createVueLanguagePlugin2( ts, () => '', () => false, diff --git a/packages/tsc/index.ts b/packages/tsc/index.ts index 5189f0715e..48c9ca8408 100644 --- a/packages/tsc/index.ts +++ b/packages/tsc/index.ts @@ -25,7 +25,7 @@ export function run() { options.host!.writeFile = (fileName, contents, ...args) => { return writeFile(fileName, removeEmitGlobalTypes(contents), ...args); }; - const vueLanguagePlugin = vue.createVueLanguagePlugin( + const vueLanguagePlugin = vue.createVueLanguagePlugin2( ts, id => id, vue.createRootFileChecker( diff --git a/packages/tsc/tests/dts.spec.ts b/packages/tsc/tests/dts.spec.ts index d0ac81b6fc..c3a2bc21e1 100644 --- a/packages/tsc/tests/dts.spec.ts +++ b/packages/tsc/tests/dts.spec.ts @@ -31,7 +31,7 @@ describe('vue-tsc-dts', () => { vueOptions = typeof configFilePath === 'string' ? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/')).vueOptions : vue.resolveVueCompilerOptions({ extensions: ['.vue', '.cext'] }); - const vueLanguagePlugin = vue.createVueLanguagePlugin( + const vueLanguagePlugin = vue.createVueLanguagePlugin2( ts, id => id, vue.createRootFileChecker( diff --git a/packages/typescript-plugin/index.ts b/packages/typescript-plugin/index.ts index 37abdb3dd1..9545d8f3c5 100644 --- a/packages/typescript-plugin/index.ts +++ b/packages/typescript-plugin/index.ts @@ -8,7 +8,7 @@ const windowsPathReg = /\\/g; const plugin = createLanguageServicePlugin( (ts, info) => { const vueOptions = getVueCompilerOptions(); - const languagePlugin = vue.createVueLanguagePlugin( + const languagePlugin = vue.createVueLanguagePlugin2( ts, id => id, info.project.projectKind === ts.server.ProjectKind.Inferred From 8a2da750f0bdbc1a56b85b129cf512b157367ee3 Mon Sep 17 00:00:00 2001 From: github-actions <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 10 Jul 2024 09:20:05 +0000 Subject: [PATCH 13/39] ci(lint): auto-fix --- packages/language-core/lib/languagePlugin.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/language-core/lib/languagePlugin.ts b/packages/language-core/lib/languagePlugin.ts index 13d2d9c86f..c744cb7875 100644 --- a/packages/language-core/lib/languagePlugin.ts +++ b/packages/language-core/lib/languagePlugin.ts @@ -83,7 +83,7 @@ export function createVueLanguagePlugin( asFileName, isRootFile, compilerOptions, - vueCompilerOptions, + vueCompilerOptions ); } From 67c2bf0e3dabb88ae84b006109af6901b34d31ce Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 12 Jul 2024 02:54:06 +0800 Subject: [PATCH 14/39] chore(tsc): use throw instead of `console.error` --- packages/tsc/index.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/tsc/index.ts b/packages/tsc/index.ts index 48c9ca8408..c82cbc4ac5 100644 --- a/packages/tsc/index.ts +++ b/packages/tsc/index.ts @@ -51,7 +51,7 @@ export function run() { if (err === extensionsChangedException) { main(); } else { - console.error(err); + throw err; } } } From db870664af92fd160c1e857bdab85513d8d6b6b3 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <32807958+zhiyuanzmj@users.noreply.github.com> Date: Fri, 12 Jul 2024 19:57:29 +0800 Subject: [PATCH 15/39] feat(language-core): improve nested plugins (#4581) --- packages/language-core/lib/languagePlugin.ts | 4 ++-- packages/language-core/lib/plugins.ts | 13 +++++++++--- packages/language-core/lib/types.ts | 20 ++++++++++--------- packages/language-core/lib/utils/ts.ts | 14 +++---------- .../lib/virtualFile/computedFiles.ts | 8 ++++---- .../lib/virtualFile/computedSfc.ts | 6 +++--- .../lib/virtualFile/computedVueSfc.ts | 6 +++--- .../language-core/lib/virtualFile/vueFile.ts | 4 ++-- 8 files changed, 38 insertions(+), 37 deletions(-) diff --git a/packages/language-core/lib/languagePlugin.ts b/packages/language-core/lib/languagePlugin.ts index c744cb7875..d6bb0ff457 100644 --- a/packages/language-core/lib/languagePlugin.ts +++ b/packages/language-core/lib/languagePlugin.ts @@ -4,7 +4,7 @@ import { FileMap, forEachEmbeddedCode, type LanguagePlugin } from '@volar/langua import * as CompilerDOM from '@vue/compiler-dom'; import type * as ts from 'typescript'; import { createPlugins } from './plugins'; -import type { VueCompilerOptions, VueLanguagePlugin } from './types'; +import type { VueCompilerOptions, VueLanguagePlugin, VueLanguagePluginReturn } from './types'; import * as CompilerVue2 from './utils/vue2TemplateCompiler'; import { VueVirtualCode } from './virtualFile/vueFile'; @@ -36,7 +36,7 @@ function getVueFileRegistry(isGlobalTypesHolder: boolean, key: string, plugins: function getFileRegistryKey( compilerOptions: ts.CompilerOptions, vueCompilerOptions: VueCompilerOptions, - plugins: ReturnType[] + plugins: VueLanguagePluginReturn[] ) { const values = [ ...Object.keys(vueCompilerOptions) diff --git a/packages/language-core/lib/plugins.ts b/packages/language-core/lib/plugins.ts index 9515379ca2..e6645ebc60 100644 --- a/packages/language-core/lib/plugins.ts +++ b/packages/language-core/lib/plugins.ts @@ -33,16 +33,23 @@ export function createPlugins(pluginContext: Parameters[0]) { ]; const pluginInstances = plugins - .map(plugin => { + .flatMap(plugin => { try { const instance = plugin(pluginContext); - instance.name ??= (plugin as any).__moduleName; + const moduleName = (plugin as any).__moduleName; + if (Array.isArray(instance)) { + for (let i = 0; i < instance.length; i++) { + instance[i].name ??= `${moduleName} (${i})`; + } + } else { + instance.name ??= moduleName; + } return instance; } catch (err) { console.warn('[Vue] Failed to create plugin', err); } }) - .filter((plugin): plugin is ReturnType => !!plugin) + .filter(plugin => !!plugin) .sort((a, b) => { const aOrder = a.order ?? 0; const bOrder = b.order ?? 0; diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index 2cedddf45b..fa722bcccb 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -59,15 +59,7 @@ export interface VueCompilerOptions { export const validVersions = [2, 2.1] as const; -export type VueLanguagePlugin = (ctx: { - modules: { - typescript: typeof import('typescript'); - '@vue/compiler-dom': typeof import('@vue/compiler-dom'); - }; - compilerOptions: ts.CompilerOptions; - vueCompilerOptions: VueCompilerOptions; - globalTypesHolder: string | undefined; -}) => { +export type VueLanguagePluginReturn = { version: 2.1; name?: string; order?: number; @@ -85,6 +77,16 @@ export type VueLanguagePlugin = (ctx: { resolveEmbeddedCode?(fileName: string, sfc: Sfc, embeddedFile: VueEmbeddedCode): void; }; +export type VueLanguagePlugin = (ctx: { + modules: { + typescript: typeof import('typescript'); + '@vue/compiler-dom': typeof import('@vue/compiler-dom'); + }; + compilerOptions: ts.CompilerOptions; + vueCompilerOptions: VueCompilerOptions; + globalTypesHolder: string | undefined; +}) => VueLanguagePluginReturn | VueLanguagePluginReturn[]; + export interface SfcBlock { name: string; start: number; diff --git a/packages/language-core/lib/utils/ts.ts b/packages/language-core/lib/utils/ts.ts index 0d0cf2bbf7..0c793d3645 100644 --- a/packages/language-core/lib/utils/ts.ts +++ b/packages/language-core/lib/utils/ts.ts @@ -164,19 +164,12 @@ function getPartialVueCompilerOptions( } if (rawOptions.plugins) { const plugins = rawOptions.plugins - .map((pluginPath: string) => { + .map((pluginPath: string) => { try { const resolvedPath = resolvePath(pluginPath); if (resolvedPath) { const plugin = require(resolvedPath); - if (Array.isArray(plugin)) { - for (let i = 0; i < plugin.length; i++) { - plugin[i].__moduleName = `${pluginPath} (${i})`; - } - } - else { - plugin.__moduleName = pluginPath; - } + plugin.__moduleName = pluginPath; return plugin; } else { @@ -187,8 +180,7 @@ function getPartialVueCompilerOptions( console.warn('[Vue] Resolve plugin path failed:', pluginPath, error); } return []; - }) - .flat(Infinity as 1); + }); result.plugins = plugins; } diff --git a/packages/language-core/lib/virtualFile/computedFiles.ts b/packages/language-core/lib/virtualFile/computedFiles.ts index 2a197d53a3..731e5dee20 100644 --- a/packages/language-core/lib/virtualFile/computedFiles.ts +++ b/packages/language-core/lib/virtualFile/computedFiles.ts @@ -2,12 +2,12 @@ import type { VirtualCode } from '@volar/language-core'; import { computed } from 'computeds'; import { toString } from 'muggle-string'; import type * as ts from 'typescript'; -import type { Code, Sfc, SfcBlock, VueLanguagePlugin } from '../types'; +import type { Code, Sfc, SfcBlock, VueLanguagePluginReturn } from '../types'; import { buildMappings } from '../utils/buildMappings'; import { VueEmbeddedCode } from './embeddedFile'; export function computedFiles( - plugins: ReturnType[], + plugins: VueLanguagePluginReturn[], fileName: string, sfc: Sfc ) { @@ -101,8 +101,8 @@ export function computedFiles( } function computedPluginEmbeddedCodes( - plugins: ReturnType[], - plugin: ReturnType, + plugins: VueLanguagePluginReturn[], + plugin: VueLanguagePluginReturn, fileName: string, sfc: Sfc, nameToBlock: () => Record diff --git a/packages/language-core/lib/virtualFile/computedSfc.ts b/packages/language-core/lib/virtualFile/computedSfc.ts index b24c5e39e2..5b0fc75cbc 100644 --- a/packages/language-core/lib/virtualFile/computedSfc.ts +++ b/packages/language-core/lib/virtualFile/computedSfc.ts @@ -2,13 +2,13 @@ import type * as CompilerDOM from '@vue/compiler-dom'; import type { SFCBlock, SFCParseResult } from '@vue/compiler-sfc'; import { computed, computedArray, pauseTracking, resetTracking } from 'computeds'; import type * as ts from 'typescript'; -import type { Sfc, SfcBlock, VueLanguagePlugin } from '../types'; +import type { Sfc, SfcBlock, VueLanguagePluginReturn } from '../types'; import { parseCssClassNames } from '../utils/parseCssClassNames'; import { parseCssVars } from '../utils/parseCssVars'; export function computedSfc( ts: typeof import('typescript'), - plugins: ReturnType[], + plugins: VueLanguagePluginReturn[], fileName: string, snapshot: () => ts.IScriptSnapshot, parsed: () => SFCParseResult | undefined @@ -150,7 +150,7 @@ export function computedSfc( template: string, snapshot: ts.IScriptSnapshot, result: CompilerDOM.CodegenResult, - plugin: ReturnType, + plugin: VueLanguagePluginReturn, } | undefined; return computed(() => { diff --git a/packages/language-core/lib/virtualFile/computedVueSfc.ts b/packages/language-core/lib/virtualFile/computedVueSfc.ts index 42f6276feb..f11f136420 100644 --- a/packages/language-core/lib/virtualFile/computedVueSfc.ts +++ b/packages/language-core/lib/virtualFile/computedVueSfc.ts @@ -1,10 +1,10 @@ import type { SFCParseResult } from '@vue/compiler-sfc'; import { computed } from 'computeds'; import type * as ts from 'typescript'; -import type { VueLanguagePlugin } from '../types'; +import type { VueLanguagePluginReturn } from '../types'; export function computedVueSfc( - plugins: ReturnType[], + plugins: VueLanguagePluginReturn[], fileName: string, languageId: string, snapshot: () => ts.IScriptSnapshot @@ -13,7 +13,7 @@ export function computedVueSfc( let cache: { snapshot: ts.IScriptSnapshot, sfc: SFCParseResult, - plugin: ReturnType, + plugin: VueLanguagePluginReturn, } | undefined; return computed(() => { diff --git a/packages/language-core/lib/virtualFile/vueFile.ts b/packages/language-core/lib/virtualFile/vueFile.ts index b193d72c2e..d3115fac68 100644 --- a/packages/language-core/lib/virtualFile/vueFile.ts +++ b/packages/language-core/lib/virtualFile/vueFile.ts @@ -1,7 +1,7 @@ import type { VirtualCode } from '@volar/language-core'; import { Signal, signal } from 'computeds'; import type * as ts from 'typescript'; -import type { VueCompilerOptions, VueLanguagePlugin } from '../types'; +import type { VueCompilerOptions, VueLanguagePluginReturn } from '../types'; import { computedFiles } from './computedFiles'; import { computedMappings } from './computedMappings'; import { computedSfc } from './computedSfc'; @@ -39,7 +39,7 @@ export class VueVirtualCode implements VirtualCode { public languageId: string, public initSnapshot: ts.IScriptSnapshot, public vueCompilerOptions: VueCompilerOptions, - public plugins: ReturnType[], + public plugins: VueLanguagePluginReturn[], public ts: typeof import('typescript'), ) { this._snapshot = signal(initSnapshot); From 2ce789cf096e47a4acd318ed0f2ef31adf880c0f Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <32807958+zhiyuanzmj@users.noreply.github.com> Date: Sat, 13 Jul 2024 18:03:59 +0800 Subject: [PATCH 16/39] fix(language-core): improve backward compatibility (#4585) --- packages/language-core/lib/types.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/language-core/lib/types.ts b/packages/language-core/lib/types.ts index fa722bcccb..72c14f4915 100644 --- a/packages/language-core/lib/types.ts +++ b/packages/language-core/lib/types.ts @@ -60,7 +60,7 @@ export interface VueCompilerOptions { export const validVersions = [2, 2.1] as const; export type VueLanguagePluginReturn = { - version: 2.1; + version: typeof validVersions[number]; name?: string; order?: number; requiredCompilerOptions?: string[]; From e6c431ce70ff71af5e029bf71a6ee31807688823 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Thu, 18 Jul 2024 17:14:52 +0800 Subject: [PATCH 17/39] fix(language-server): observe named pipe servers within 20 seconds of server startup close #4292 --- .../language-server/lib/hybridModeProject.ts | 37 ++++++++++++++++--- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/packages/language-server/lib/hybridModeProject.ts b/packages/language-server/lib/hybridModeProject.ts index bc504bb0a7..9da028c14e 100644 --- a/packages/language-server/lib/hybridModeProject.ts +++ b/packages/language-server/lib/hybridModeProject.ts @@ -2,7 +2,7 @@ import type { Language, LanguagePlugin, LanguageServer, LanguageServerProject, P import { createLanguageServiceEnvironment } from '@volar/language-server/lib/project/simpleProject'; import { createLanguage } from '@vue/language-core'; import { createLanguageService, createUriMap, LanguageService } from '@vue/language-service'; -import { searchNamedPipeServerForFile } from '@vue/typescript-plugin/lib/utils'; +import { searchNamedPipeServerForFile, readPipeTable } from '@vue/typescript-plugin/lib/utils'; import { URI } from 'vscode-uri'; export function createHybridModeProject( @@ -20,17 +20,18 @@ export function createHybridModeProject( let initialized = false; let simpleLs: Promise | undefined; let server: LanguageServer; + let pipeTableWatcher: NodeJS.Timeout | undefined; const tsconfigProjects = createUriMap>(); - - return { + const project: LanguageServerProject = { setup(_server) { server = _server; }, async getLanguageService(uri) { if (!initialized) { initialized = true; - initialize(server); + initialize(); + trackPipeTableChanges(); } const fileName = asFileName(uri); const projectInfo = (await searchNamedPipeServerForFile(fileName))?.projectInfo; @@ -62,14 +63,20 @@ export function createHybridModeProject( } tsconfigProjects.clear(); simpleLs = undefined; + if (pipeTableWatcher) { + clearInterval(pipeTableWatcher); + pipeTableWatcher = undefined; + } }, }; + return project; + function asFileName(uri: URI) { return uri.fsPath.replace(/\\/g, '/'); } - function initialize(server: LanguageServer) { + function initialize() { server.onDidChangeWatchedFiles(({ changes }) => { for (const change of changes) { const changeUri = URI.parse(change.uri); @@ -82,6 +89,26 @@ export function createHybridModeProject( }); } + function trackPipeTableChanges() { + if (pipeTableWatcher) { + clearInterval(pipeTableWatcher); + pipeTableWatcher = undefined; + } + let table = readPipeTable(); + let remaining = 20; + pipeTableWatcher = setInterval(() => { + const newTable = readPipeTable(); + if (JSON.stringify(table) !== JSON.stringify(newTable)) { + table = newTable; + server.refresh(project); + } + if (remaining-- <= 0) { + clearInterval(pipeTableWatcher); + pipeTableWatcher = undefined; + } + }, 1000); + } + async function createLs(server: LanguageServer, tsconfig: string | undefined) { const { languagePlugins, setup } = await create({ configFileName: tsconfig, From 0ffd1e596faea9554e592af8778ac6a28db99a73 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Fri, 19 Jul 2024 12:48:19 +0800 Subject: [PATCH 18/39] chore: enable `autoAttachChildProcesses` --- .vscode/launch.json | 1 + 1 file changed, 1 insertion(+) diff --git a/.vscode/launch.json b/.vscode/launch.json index 7ef11b5db0..1631ace705 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -6,6 +6,7 @@ "name": "Launch Client", "type": "extensionHost", "request": "launch", + "autoAttachChildProcesses": true, "runtimeExecutable": "${execPath}", "args": [ "--extensionDevelopmentPath=${workspaceRoot}/extensions/vscode", From c0cfa279eddf73055b3601a6b5c16ec992d74723 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sat, 20 Jul 2024 01:14:48 +0800 Subject: [PATCH 19/39] feat(language-service): remove `v-bind` code action (#4601) --- packages/language-service/index.ts | 2 - .../plugins/vue-toggle-v-bind-codeaction.ts | 151 ------------------ 2 files changed, 153 deletions(-) delete mode 100644 packages/language-service/lib/plugins/vue-toggle-v-bind-codeaction.ts diff --git a/packages/language-service/index.ts b/packages/language-service/index.ts index f32460d04d..e837df7c6e 100644 --- a/packages/language-service/index.ts +++ b/packages/language-service/index.ts @@ -24,7 +24,6 @@ import { create as createVueDocumentLinksPlugin } from './lib/plugins/vue-docume import { create as createVueExtractFilePlugin } from './lib/plugins/vue-extract-file'; import { create as createVueSfcPlugin } from './lib/plugins/vue-sfc'; import { create as createVueTemplatePlugin } from './lib/plugins/vue-template'; -import { create as createVueToggleVBindPlugin } from './lib/plugins/vue-toggle-v-bind-codeaction'; import { create as createVueTwoslashQueriesPlugin } from './lib/plugins/vue-twoslash-queries'; import { create as createVueVisualizeHiddenCallbackParamPlugin } from './lib/plugins/vue-visualize-hidden-callback-param'; @@ -200,7 +199,6 @@ function getCommonLanguageServicePlugins( createVueVisualizeHiddenCallbackParamPlugin(), createVueDirectiveCommentsPlugin(), createVueExtractFilePlugin(ts, getTsPluginClient), - createVueToggleVBindPlugin(ts), createEmmetPlugin({ mappedLanguages: { 'vue': 'html', diff --git a/packages/language-service/lib/plugins/vue-toggle-v-bind-codeaction.ts b/packages/language-service/lib/plugins/vue-toggle-v-bind-codeaction.ts deleted file mode 100644 index e21100e593..0000000000 --- a/packages/language-service/lib/plugins/vue-toggle-v-bind-codeaction.ts +++ /dev/null @@ -1,151 +0,0 @@ -import type { LanguageServicePlugin, LanguageServicePluginInstance } from '@volar/language-service'; -import { VueVirtualCode, forEachElementNode, type CompilerDOM } from '@vue/language-core'; -import type * as vscode from 'vscode-languageserver-protocol'; -import { URI } from 'vscode-uri'; - -export function create(ts: typeof import('typescript')): LanguageServicePlugin { - return { - name: 'vue-toggle-v-bind-codeaction', - capabilities: { - codeActionProvider: { - codeActionKinds: ['refactor'], - }, - }, - create(context): LanguageServicePluginInstance { - return { - provideCodeActions(document, range, _context) { - - const startOffset = document.offsetAt(range.start); - const endOffset = document.offsetAt(range.end); - const decoded = context.decodeEmbeddedDocumentUri(URI.parse(document.uri)); - const sourceScript = decoded && context.language.scripts.get(decoded[0]); - const virtualCode = decoded && sourceScript?.generated?.embeddedCodes.get(decoded[1]); - if (!(virtualCode instanceof VueVirtualCode)) { - return; - } - - const { template } = virtualCode.sfc; - if (!template?.ast) { - return; - } - - const templateStartOffset = template.startTagEnd; - const result: vscode.CodeAction[] = []; - - for (const node of forEachElementNode(template.ast)) { - if (startOffset > templateStartOffset + node.loc.end.offset || endOffset < templateStartOffset + node.loc.start.offset) { - return; - } - for (const prop of node.props) { - if ( - startOffset - templateStartOffset >= prop.loc.start.offset - && endOffset - templateStartOffset <= prop.loc.end.offset - ) { - if (prop.type === 7 satisfies CompilerDOM.NodeTypes.DIRECTIVE && prop.exp) { - - const sourceFile = ts.createSourceFile('/a.ts', prop.exp.loc.source, ts.ScriptTarget.Latest, true); - const firstStatement = sourceFile.statements[0]; - - if (sourceFile.statements.length === 1 && ts.isExpressionStatement(firstStatement) && ts.isStringLiteralLike(firstStatement.expression)) { - const stringNode = sourceFile.statements[0]; - const removeTextRanges: [number, number][] = [ - [prop.loc.start.offset, prop.loc.start.offset + 1], - // Work correctly with trivias for cases like - [prop.exp.loc.start.offset, prop.exp.loc.start.offset + stringNode.pos + stringNode.getLeadingTriviaWidth() + 1], - [prop.exp.loc.start.offset + stringNode.end - 1, prop.exp.loc.end.offset], - ]; - result.push({ - title: 'Remove v-bind from attribute', - kind: 'refactor.rewrite.removeVBind', - edit: { - changes: { - [document.uri]: removeTextRanges.map(range => ({ - newText: '', - range: { - start: document.positionAt(templateStartOffset + range[0]), - end: document.positionAt(templateStartOffset + range[1]), - } - })) - }, - }, - }); - } - } - if (prop.type === 6 satisfies CompilerDOM.NodeTypes.ATTRIBUTE) { - - const edits: vscode.TextEdit[] = []; - const addVBindPos = document.positionAt(templateStartOffset + prop.loc.start.offset); - edits.push({ - newText: ':', - range: { - start: addVBindPos, - end: addVBindPos, - }, - }); - - let newPosition: vscode.Position | undefined; - - if (prop.value) { - const valueStart = document.positionAt(templateStartOffset + prop.value.loc.start.offset); - const valueEnd = document.positionAt(templateStartOffset + prop.value.loc.end.offset); - - if (prop.value.loc.end.offset - prop.value.loc.start.offset !== prop.value.content.length) { - valueStart.character++; - valueEnd.character--; - } - - edits.push({ - newText: "'", - range: { - start: valueStart, - end: valueStart, - }, - }); - edits.push({ - newText: "'", - range: { - start: valueEnd, - end: valueEnd, - }, - }); - } - else { - const addValuePos = document.positionAt(templateStartOffset + prop.loc.end.offset); - - newPosition = { - line: addValuePos.line, - character: addValuePos.character + ':'.length + '="'.length, - }; - - edits.push({ - newText: '=""', - range: { - start: addValuePos, - end: addValuePos - }, - }); - } - - result.push({ - title: 'Add v-bind to attribute', - kind: 'refactor.rewrite.addVBind', - edit: { - changes: { [document.uri]: edits }, - }, - command: newPosition ? context?.commands.setSelection.create(newPosition) : undefined, - }); - } - } - } - } - - return result; - }, - - transformCodeAction(item) { - return item; // ignore mapping - }, - }; - }, - }; -} From da39d373ca63a4cf98a68c252403209976c61c58 Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sat, 20 Jul 2024 02:19:03 +0800 Subject: [PATCH 20/39] chore: fix yarn 4 compatibility close #4587 --- packages/language-plugin-pug/package.json | 2 +- packages/language-service/package.json | 16 ++++++++-------- pnpm-lock.yaml | 18 +++++++++--------- 3 files changed, 18 insertions(+), 18 deletions(-) diff --git a/packages/language-plugin-pug/package.json b/packages/language-plugin-pug/package.json index 2ee3cbc34f..931108c04c 100644 --- a/packages/language-plugin-pug/package.json +++ b/packages/language-plugin-pug/package.json @@ -17,6 +17,6 @@ }, "dependencies": { "@volar/source-map": "~2.4.0-alpha.15", - "volar-service-pug": "volar-2.4" + "volar-service-pug": "0.0.59" } } diff --git a/packages/language-service/package.json b/packages/language-service/package.json index d70ac1e240..bb2ed6e3cf 100644 --- a/packages/language-service/package.json +++ b/packages/language-service/package.json @@ -25,14 +25,14 @@ "@vue/typescript-plugin": "2.0.26", "computeds": "^0.0.1", "path-browserify": "^1.0.1", - "volar-service-css": "volar-2.4", - "volar-service-emmet": "volar-2.4", - "volar-service-html": "volar-2.4", - "volar-service-json": "volar-2.4", - "volar-service-pug": "volar-2.4", - "volar-service-pug-beautify": "volar-2.4", - "volar-service-typescript": "volar-2.4", - "volar-service-typescript-twoslash-queries": "volar-2.4", + "volar-service-css": "0.0.59", + "volar-service-emmet": "0.0.59", + "volar-service-html": "0.0.59", + "volar-service-json": "0.0.59", + "volar-service-pug": "0.0.59", + "volar-service-pug-beautify": "0.0.59", + "volar-service-typescript": "0.0.59", + "volar-service-typescript-twoslash-queries": "0.0.59", "vscode-html-languageservice": "^5.2.0", "vscode-languageserver-textdocument": "^1.0.11", "vscode-uri": "^3.0.8" diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index b1923644fe..775b2df64b 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -151,7 +151,7 @@ importers: specifier: ~2.4.0-alpha.15 version: 2.4.0-alpha.15 volar-service-pug: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59 devDependencies: '@types/node': @@ -215,28 +215,28 @@ importers: specifier: ^1.0.1 version: 1.0.1 volar-service-css: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59(@volar/language-service@2.4.0-alpha.15) volar-service-emmet: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59(@volar/language-service@2.4.0-alpha.15) volar-service-html: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59(@volar/language-service@2.4.0-alpha.15) volar-service-json: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59(@volar/language-service@2.4.0-alpha.15) volar-service-pug: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59 volar-service-pug-beautify: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59(@volar/language-service@2.4.0-alpha.15) volar-service-typescript: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59(@volar/language-service@2.4.0-alpha.15) volar-service-typescript-twoslash-queries: - specifier: volar-2.4 + specifier: 0.0.59 version: 0.0.59(@volar/language-service@2.4.0-alpha.15) vscode-html-languageservice: specifier: ^5.2.0 From 7935b36458857ec1b8bf742d1b06ae8b0db8875e Mon Sep 17 00:00:00 2001 From: David Matter Date: Fri, 19 Jul 2024 22:30:33 +0200 Subject: [PATCH 21/39] fix(language-core): infer define model type from options type (#4545) --- .../lib/codegen/script/scriptSetup.ts | 40 ++++++++++--------- test-workspace/tsc/vue2/tsconfig.json | 1 + test-workspace/tsc/vue3/#4512/main.vue | 27 +++++++++++++ test-workspace/tsc/vue3/#4512/test1.vue | 9 +++++ test-workspace/tsc/vue3/#4512/test2.vue | 10 +++++ test-workspace/tsc/vue3/#4512/test3.vue | 16 ++++++++ 6 files changed, 85 insertions(+), 18 deletions(-) create mode 100644 test-workspace/tsc/vue3/#4512/main.vue create mode 100644 test-workspace/tsc/vue3/#4512/test1.vue create mode 100644 test-workspace/tsc/vue3/#4512/test2.vue create mode 100644 test-workspace/tsc/vue3/#4512/test3.vue diff --git a/packages/language-core/lib/codegen/script/scriptSetup.ts b/packages/language-core/lib/codegen/script/scriptSetup.ts index 2a7587d776..1745799089 100644 --- a/packages/language-core/lib/codegen/script/scriptSetup.ts +++ b/packages/language-core/lib/codegen/script/scriptSetup.ts @@ -308,6 +308,8 @@ function* generateComponentProps( if (defineProp.name && defineProp.nameIsString) { // renaming support yield generateSfcBlockSection(scriptSetup, defineProp.name.start, defineProp.name.end, codeFeatures.navigation); + propName = scriptSetup.content.substring(defineProp.name.start, defineProp.name.end); + propName = propName.replace(/['"]+/g, ''); } else if (defineProp.name) { propName = scriptSetup.content.substring(defineProp.name.start, defineProp.name.end); @@ -320,18 +322,7 @@ function* generateComponentProps( yield defineProp.required ? `: ` : `?: `; - if (defineProp.type) { - yield scriptSetup.content.substring(defineProp.type.start, defineProp.type.end); - } - else if (!defineProp.nameIsString) { - yield `NonNullable`; - } - else if (defineProp.defaultValue) { - yield `typeof __VLS_defaults['${propName}']`; - } - else { - yield `any`; - } + yield* generateDefinePropType(scriptSetup, propName, defineProp); yield `,${newLine}`; if (defineProp.modifierType) { @@ -382,12 +373,7 @@ function* generateModelEmits( propName = propName.replace(/['"]+/g, ''); } yield `'update:${propName}': [${propName}:`; - if (defineProp.type) { - yield scriptSetup.content.substring(defineProp.type.start, defineProp.type.end); - } - else { - yield `any`; - } + yield* generateDefinePropType(scriptSetup, propName, defineProp); yield `]${endOfLine}`; } yield `}`; @@ -399,3 +385,21 @@ function* generateModelEmits( } yield endOfLine; } + +function* generateDefinePropType(scriptSetup: NonNullable, propName: string, defineProp: ScriptSetupRanges['defineProp'][number]) { + if (defineProp.type) { + // Infer from defineProp + yield scriptSetup.content.substring(defineProp.type.start, defineProp.type.end); + } + else if ((defineProp.name && defineProp.nameIsString) || !defineProp.nameIsString) { + // Infer from actual prop declaration code + yield `NonNullable`; + } + else if (defineProp.defaultValue) { + // Infer from defineProp({default: T}) + yield `typeof __VLS_defaults['${propName}']`; + } + else { + yield `any`; + } +} diff --git a/test-workspace/tsc/vue2/tsconfig.json b/test-workspace/tsc/vue2/tsconfig.json index ae36414d8e..3363c6cf0b 100644 --- a/test-workspace/tsc/vue2/tsconfig.json +++ b/test-workspace/tsc/vue2/tsconfig.json @@ -19,6 +19,7 @@ "../vue3/#3672", "../vue3/#3782", "../vue3/#4327", + "../vue3/#4512", "../vue3/components", "../vue3/defineEmits", "../vue3/defineModel", diff --git a/test-workspace/tsc/vue3/#4512/main.vue b/test-workspace/tsc/vue3/#4512/main.vue new file mode 100644 index 0000000000..2f2c895d74 --- /dev/null +++ b/test-workspace/tsc/vue3/#4512/main.vue @@ -0,0 +1,27 @@ + + + diff --git a/test-workspace/tsc/vue3/#4512/test1.vue b/test-workspace/tsc/vue3/#4512/test1.vue new file mode 100644 index 0000000000..e3290ecfe7 --- /dev/null +++ b/test-workspace/tsc/vue3/#4512/test1.vue @@ -0,0 +1,9 @@ + + + diff --git a/test-workspace/tsc/vue3/#4512/test2.vue b/test-workspace/tsc/vue3/#4512/test2.vue new file mode 100644 index 0000000000..b1abfb552e --- /dev/null +++ b/test-workspace/tsc/vue3/#4512/test2.vue @@ -0,0 +1,10 @@ + + + diff --git a/test-workspace/tsc/vue3/#4512/test3.vue b/test-workspace/tsc/vue3/#4512/test3.vue new file mode 100644 index 0000000000..31dd91e2a3 --- /dev/null +++ b/test-workspace/tsc/vue3/#4512/test3.vue @@ -0,0 +1,16 @@ + + + From e23ff4d13001ffe78d893bb707d839ead29e0e40 Mon Sep 17 00:00:00 2001 From: _Kerman Date: Sat, 20 Jul 2024 16:14:06 +0800 Subject: [PATCH 22/39] feat(vscode): add empty pattern to codeblock attributes scope (#4590) --- extensions/vscode/syntaxes/markdown-vue.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/extensions/vscode/syntaxes/markdown-vue.json b/extensions/vscode/syntaxes/markdown-vue.json index 198ebdd6ef..c95ea6be7d 100644 --- a/extensions/vscode/syntaxes/markdown-vue.json +++ b/extensions/vscode/syntaxes/markdown-vue.json @@ -20,7 +20,8 @@ "name": "fenced_code.block.language.markdown" }, "5": { - "name": "fenced_code.block.language.attributes.markdown" + "name": "fenced_code.block.language.attributes.markdown", + "patterns": [] } }, "endCaptures": { From 07737817f82ee63d24c198f91b690cd9bcf83d14 Mon Sep 17 00:00:00 2001 From: _Kerman Date: Sat, 20 Jul 2024 17:24:48 +0800 Subject: [PATCH 23/39] fix(language-core): type-checking not working with hyphen in slot name with JS (#4478) --- .../lib/codegen/template/element.ts | 73 ++++++++----------- test-workspace/tsc/vue3/#3819/comp.vue | 7 ++ test-workspace/tsc/vue3/#3819/main.vue | 21 ++++++ 3 files changed, 60 insertions(+), 41 deletions(-) create mode 100644 test-workspace/tsc/vue3/#3819/comp.vue create mode 100644 test-workspace/tsc/vue3/#3819/main.vue diff --git a/packages/language-core/lib/codegen/template/element.ts b/packages/language-core/lib/codegen/template/element.ts index 47291c5e31..6ba918ee6a 100644 --- a/packages/language-core/lib/codegen/template/element.ts +++ b/packages/language-core/lib/codegen/template/element.ts @@ -13,6 +13,7 @@ import type { TemplateCodegenOptions } from './index'; import { generateInterpolation } from './interpolation'; import { generatePropertyAccess } from './propertyAccess'; import { generateTemplateChild } from './templateChild'; +import { generateObjectProperty } from './objectProperty'; const colonReg = /:/g; @@ -419,12 +420,38 @@ function* generateComponentSlot( ctx.hasSlotElements.add(currentComponent); } const slotBlockVars: string[] = []; - let hasProps = false; - if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { + yield `const {`; + if (slotDir?.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && slotDir.arg.content) { + yield* generateObjectProperty( + options, + ctx, + slotDir.arg.loc.source, + slotDir.arg.loc.start.offset, + slotDir.arg.isStatic ? ctx.codeFeatures.withoutHighlight : ctx.codeFeatures.all, + slotDir.arg.loc + ); + yield ': __VLS_thisSlot'; + } + else { + yield `default: `; + yield* wrapWith( + slotDir.loc.start.offset, + slotDir.loc.start.offset + ( + slotDir.loc.source.startsWith('#') + ? '#'.length + : slotDir.loc.source.startsWith('v-slot:') + ? 'v-slot:'.length + : 0 + ), + ctx.codeFeatures.withoutHighlightAndCompletion, + `__VLS_thisSlot` + ); + } + yield `} = ${componentCtxVar}.slots!${endOfLine}`; + if (slotDir?.exp?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION) { const slotAst = createTsAst(options.ts, slotDir, `(${slotDir.exp.content}) => {}`); collectVars(options.ts, slotAst, slotAst, slotBlockVars); - hasProps = true; if (!slotDir.exp.content.includes(':')) { yield `const [`; yield [ @@ -433,7 +460,7 @@ function* generateComponentSlot( slotDir.exp.loc.start.offset, ctx.codeFeatures.all, ]; - yield `] = __VLS_getSlotParams(`; + yield `] = __VLS_getSlotParams(__VLS_thisSlot)${endOfLine}`; } else { yield `const `; @@ -443,45 +470,9 @@ function* generateComponentSlot( slotDir.exp.loc.start.offset, ctx.codeFeatures.all, ]; - yield ` = __VLS_getSlotParam(`; + yield ` = __VLS_getSlotParam(__VLS_thisSlot)${endOfLine}`; } } - yield* wrapWith( - (slotDir.arg ?? slotDir).loc.start.offset, - (slotDir.arg ?? slotDir).loc.end.offset, - ctx.codeFeatures.verification, - `(${componentCtxVar}.slots!)`, - ...( - slotDir?.arg?.type === CompilerDOM.NodeTypes.SIMPLE_EXPRESSION && slotDir.arg.content - ? generatePropertyAccess( - options, - ctx, - slotDir.arg.loc.source, - slotDir.arg.loc.start.offset, - slotDir.arg.isStatic ? ctx.codeFeatures.withoutHighlight : ctx.codeFeatures.all, - slotDir.arg.loc - ) - : [ - `.`, - ...wrapWith( - slotDir.loc.start.offset, - slotDir.loc.start.offset + ( - slotDir.loc.source.startsWith('#') - ? '#'.length - : slotDir.loc.source.startsWith('v-slot:') - ? 'v-slot:'.length - : 0 - ), - ctx.codeFeatures.withoutHighlightAndCompletion, - `default` - ) - ] - ) - ); - if (hasProps) { - yield `)`; - } - yield endOfLine; for (const varName of slotBlockVars) { ctx.addLocalVariable(varName); diff --git a/test-workspace/tsc/vue3/#3819/comp.vue b/test-workspace/tsc/vue3/#3819/comp.vue new file mode 100644 index 0000000000..c7dd588ced --- /dev/null +++ b/test-workspace/tsc/vue3/#3819/comp.vue @@ -0,0 +1,7 @@ + diff --git a/test-workspace/tsc/vue3/#3819/main.vue b/test-workspace/tsc/vue3/#3819/main.vue new file mode 100644 index 0000000000..d222ec399b --- /dev/null +++ b/test-workspace/tsc/vue3/#3819/main.vue @@ -0,0 +1,21 @@ + + + From 0213c010050d1f9cba503e4a3c818fcb189809ff Mon Sep 17 00:00:00 2001 From: Ray Date: Sat, 20 Jul 2024 17:30:20 +0800 Subject: [PATCH 24/39] fix(language-service): filter special tags (#4596) --- .../lib/plugins/vue-template.ts | 36 +++++++++++++------ 1 file changed, 26 insertions(+), 10 deletions(-) diff --git a/packages/language-service/lib/plugins/vue-template.ts b/packages/language-service/lib/plugins/vue-template.ts index beb8bab575..7d67146123 100644 --- a/packages/language-service/lib/plugins/vue-template.ts +++ b/packages/language-service/lib/plugins/vue-template.ts @@ -15,6 +15,8 @@ import { loadModelModifiersData, loadTemplateData } from './data'; let builtInData: html.HTMLDataV1; let modelData: html.HTMLDataV1; +const specialTags = new Set(['slot', 'component', 'template']); + export function create( mode: 'html' | 'pug', ts: typeof import('typescript'), @@ -419,14 +421,8 @@ export function create( if (builtInData.tags) { for (const tag of builtInData.tags) { - if (tag.name === 'slot') { - continue; - } - if (tag.name === 'component') { - continue; - } - if (tag.name === 'template') { - continue; + if (specialTags.has(tag.name)) { + tag.name = createInternalItemId('specialTag', [tag.name]); } if (casing.tag === TagNameCasing.Kebab) { tag.name = hyphenateTag(tag.name); @@ -735,6 +731,26 @@ export function create( for (const item of completionList.items) { + if (specialTags.has(item.label)) { + completionList.items = completionList.items.filter(i => i !== item); + } + + const nameId = readInternalItemId(item.label); + + if (nameId) { + const name = nameId.args[0]; + item.label = name; + if (item.textEdit) { + item.textEdit.newText = name; + }; + if (item.insertText) { + item.insertText = name; + } + if (item.sortText) { + item.sortText = name; + } + } + const itemIdKey = typeof item.documentation === 'string' ? item.documentation : item.documentation?.value; const itemId = itemIdKey ? readInternalItemId(itemIdKey) : undefined; @@ -848,7 +864,7 @@ export function create( } }; -function createInternalItemId(type: 'componentEvent' | 'componentProp', args: string[]) { +function createInternalItemId(type: 'componentEvent' | 'componentProp' | 'specialTag', args: string[]) { return '__VLS_::' + type + '::' + args.join(','); } @@ -856,7 +872,7 @@ function readInternalItemId(key: string) { if (key.startsWith('__VLS_::')) { const strs = key.split('::'); return { - type: strs[1] as 'componentEvent' | 'componentProp', + type: strs[1] as 'componentEvent' | 'componentProp' | 'specialTag', args: strs[2].split(','), }; } From 6cc2bd6f2a7c14784af062ceb1482ed602a7a540 Mon Sep 17 00:00:00 2001 From: zhiyuanzmj <32807958+zhiyuanzmj@users.noreply.github.com> Date: Sat, 20 Jul 2024 19:04:15 +0800 Subject: [PATCH 25/39] fix(language-core): add type check for v-model without argument (#4598) --- .../lib/codegen/template/elementProps.ts | 7 ++++++- test-workspace/tsc/vue2/tsconfig.json | 1 + test-workspace/tsc/vue3/#4540/component.vue | 5 +++++ test-workspace/tsc/vue3/#4540/main.vue | 13 +++++++++++++ 4 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 test-workspace/tsc/vue3/#4540/component.vue create mode 100644 test-workspace/tsc/vue3/#4540/main.vue diff --git a/packages/language-core/lib/codegen/template/elementProps.ts b/packages/language-core/lib/codegen/template/elementProps.ts index dcbd5a9102..7bbb49dbcc 100644 --- a/packages/language-core/lib/codegen/template/elementProps.ts +++ b/packages/language-core/lib/codegen/template/elementProps.ts @@ -132,7 +132,12 @@ export function* generateElementProps( (prop.loc as any).name_2 ?? ((prop.loc as any).name_2 = {}), shouldCamelize ) - : [propName] + : wrapWith( + prop.loc.start.offset, + prop.loc.start.offset + 'v-model'.length, + ctx.codeFeatures.verification, + propName + ) ), `: (`, ...genereatePropExp( diff --git a/test-workspace/tsc/vue2/tsconfig.json b/test-workspace/tsc/vue2/tsconfig.json index 3363c6cf0b..9aaa7ba292 100644 --- a/test-workspace/tsc/vue2/tsconfig.json +++ b/test-workspace/tsc/vue2/tsconfig.json @@ -20,6 +20,7 @@ "../vue3/#3782", "../vue3/#4327", "../vue3/#4512", + "../vue3/#4540", "../vue3/components", "../vue3/defineEmits", "../vue3/defineModel", diff --git a/test-workspace/tsc/vue3/#4540/component.vue b/test-workspace/tsc/vue3/#4540/component.vue new file mode 100644 index 0000000000..ecb17553ea --- /dev/null +++ b/test-workspace/tsc/vue3/#4540/component.vue @@ -0,0 +1,5 @@ + diff --git a/test-workspace/tsc/vue3/#4540/main.vue b/test-workspace/tsc/vue3/#4540/main.vue new file mode 100644 index 0000000000..eb2fbb9d39 --- /dev/null +++ b/test-workspace/tsc/vue3/#4540/main.vue @@ -0,0 +1,13 @@ + + + From 12c7a9f745b60d73c1d60118d4f3abbc4ac0c17d Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sat, 20 Jul 2024 19:58:55 +0800 Subject: [PATCH 26/39] test: correctly reproduce #3819 --- test-workspace/tsc/#3819/component.vue | 8 ++++++++ test-workspace/tsc/{vue3 => }/#3819/main.vue | 6 +++--- test-workspace/tsc/#3819/tsconfig.json | 8 ++++++++ test-workspace/tsc/vue3/#3819/comp.vue | 7 ------- 4 files changed, 19 insertions(+), 10 deletions(-) create mode 100644 test-workspace/tsc/#3819/component.vue rename test-workspace/tsc/{vue3 => }/#3819/main.vue (74%) create mode 100644 test-workspace/tsc/#3819/tsconfig.json delete mode 100644 test-workspace/tsc/vue3/#3819/comp.vue diff --git a/test-workspace/tsc/#3819/component.vue b/test-workspace/tsc/#3819/component.vue new file mode 100644 index 0000000000..3d4d99df8e --- /dev/null +++ b/test-workspace/tsc/#3819/component.vue @@ -0,0 +1,8 @@ + diff --git a/test-workspace/tsc/vue3/#3819/main.vue b/test-workspace/tsc/#3819/main.vue similarity index 74% rename from test-workspace/tsc/vue3/#3819/main.vue rename to test-workspace/tsc/#3819/main.vue index d222ec399b..9ff9781ce2 100644 --- a/test-workspace/tsc/vue3/#3819/main.vue +++ b/test-workspace/tsc/#3819/main.vue @@ -1,19 +1,19 @@