From a887ef48289eb9f542457dfb9820c16bdc411e6a Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Sat, 9 Apr 2022 18:16:26 +0800 Subject: [PATCH] feat: drop support for typed slots (#1152) * feat: combine multiple TS language services to one * refactor: remove `__VLS_options` logics * refactor: remove `__VLS_slots` logics --- .../vscode-vue-language-features/package.json | 15 +- .../src/features/virtualFiles.ts | 7 +- packages/shared/src/requests.ts | 3 +- packages/typescript-vue-plugin/src/apis.ts | 261 ++++++++---------- packages/typescript-vue-plugin/src/index.ts | 14 +- .../vue-code-gen/src/generators/template.ts | 100 +------ .../src/features/customFeatures.ts | 37 ++- packages/vue-language-server/src/projects.ts | 2 +- .../src/commonPlugins/typescript.ts | 5 +- .../src/documentFeatures/format.ts | 4 +- .../src/documentService.ts | 2 +- .../src/languageFeatures/callHierarchy.ts | 20 +- .../src/languageFeatures/codeActionResolve.ts | 4 +- .../src/languageFeatures/codeActions.ts | 4 - .../src/languageFeatures/complete.ts | 11 +- .../src/languageFeatures/completeResolve.ts | 2 +- .../src/languageFeatures/definition.ts | 29 +- .../src/languageFeatures/executeCommand.ts | 2 +- .../src/languageFeatures/fileRename.ts | 4 +- .../src/languageFeatures/references.ts | 29 +- .../src/languageFeatures/rename.ts | 69 ++--- .../src/languageFeatures/validation.ts | 57 ++-- .../src/languageFeatures/workspaceSymbols.ts | 4 +- .../src/languageService.ts | 78 ++---- .../src/stylesheetExtra.ts | 4 +- packages/vue-language-service/src/types.ts | 4 +- .../src/utils/featureWorkers.ts | 4 +- .../vue-language-service/src/vueDocuments.ts | 35 +-- .../src/vuePlugins/vue.ts | 4 +- .../src/vuePlugins/vueTemplateLanguage.ts | 14 +- .../testCases/renames/emit_from.vue | 3 - .../testCases/renames/emit_to.vue | 8 - .../testCases/tsconfig.json | 1 + .../vue-language-service/tests/index.spec.ts | 1 - .../tests/renames/emit.ts | 51 ---- .../tests/renames/prop.ts | 54 ++-- .../tests/renames/typeProp.ts | 54 ++-- packages/vue-tsc/src/apis.ts | 47 ++-- packages/vue-tsc/src/proxy.ts | 2 +- .../vue-typescript/src/typescriptRuntime.ts | 62 ++--- .../src/use/useSfcCustomBlocks.ts | 1 - .../src/use/useSfcEntryForTemplateLs.ts | 12 +- .../vue-typescript/src/use/useSfcScript.ts | 1 - .../vue-typescript/src/use/useSfcScriptGen.ts | 3 - .../vue-typescript/src/use/useSfcStyles.ts | 1 - .../vue-typescript/src/use/useSfcTemplate.ts | 1 - .../src/use/useSfcTemplateScript.ts | 16 +- .../vue-typescript/src/utils/localTypes.ts | 8 +- packages/vue-typescript/src/vueFile.ts | 22 +- packages/vue-typescript/src/vueFiles.ts | 56 ++-- 50 files changed, 443 insertions(+), 789 deletions(-) delete mode 100644 packages/vue-language-service/testCases/renames/emit_from.vue delete mode 100644 packages/vue-language-service/testCases/renames/emit_to.vue delete mode 100644 packages/vue-language-service/tests/renames/emit.ts diff --git a/extensions/vscode-vue-language-features/package.json b/extensions/vscode-vue-language-features/package.json index 5fe681a16..2d8c4c36e 100644 --- a/extensions/vscode-vue-language-features/package.json +++ b/extensions/vscode-vue-language-features/package.json @@ -447,13 +447,8 @@ "category": "Volar" }, { - "command": "volar.action.writeTemplateLsVirtualFiles", - "title": "Write Template LS Virtual Files", - "category": "Volar (Debug)" - }, - { - "command": "volar.action.writeScriptLsVirtualFiles", - "title": "Write Script LS Virtual Files", + "command": "volar.action.writeVirtualFiles", + "title": "Write Virtual Files", "category": "Volar (Debug)" }, { @@ -539,11 +534,7 @@ "when": "volar.activated" }, { - "command": "volar.action.writeTemplateLsVirtualFiles", - "when": "volar.activated" - }, - { - "command": "volar.action.writeScriptLsVirtualFiles", + "command": "volar.action.writeVirtualFiles", "when": "volar.activated" }, { diff --git a/extensions/vscode-vue-language-features/src/features/virtualFiles.ts b/extensions/vscode-vue-language-features/src/features/virtualFiles.ts index 5b3134318..14636d105 100644 --- a/extensions/vscode-vue-language-features/src/features/virtualFiles.ts +++ b/extensions/vscode-vue-language-features/src/features/virtualFiles.ts @@ -4,10 +4,7 @@ import type { CommonLanguageClient } from 'vscode-languageclient'; export async function activate(context: vscode.ExtensionContext, languageClient: CommonLanguageClient) { await languageClient.onReady(); - context.subscriptions.push(vscode.commands.registerCommand('volar.action.writeTemplateLsVirtualFiles', () => { - languageClient.sendNotification(shared.WriteVirtualFilesNotification.type, { lsType: 'template' }); - })); - context.subscriptions.push(vscode.commands.registerCommand('volar.action.writeScriptLsVirtualFiles', () => { - languageClient.sendNotification(shared.WriteVirtualFilesNotification.type, { lsType: 'script' }); + context.subscriptions.push(vscode.commands.registerCommand('volar.action.writeVirtualFiles', () => { + languageClient.sendNotification(shared.WriteVirtualFilesNotification.type); })); } diff --git a/packages/shared/src/requests.ts b/packages/shared/src/requests.ts index 6874c0a39..f4411142d 100644 --- a/packages/shared/src/requests.ts +++ b/packages/shared/src/requests.ts @@ -91,8 +91,7 @@ export namespace VerifyAllScriptsNotification { } export namespace WriteVirtualFilesNotification { - export type ParamsType = { lsType: 'template' | 'script' }; - export const type = new vscode.NotificationType('volar.action.writeVirtualFiles'); + export const type = new vscode.NotificationType0('volar.action.writeVirtualFiles'); } export namespace DetectDocumentNameCasesRequest { diff --git a/packages/typescript-vue-plugin/src/apis.ts b/packages/typescript-vue-plugin/src/apis.ts index 504017869..0fa161be2 100644 --- a/packages/typescript-vue-plugin/src/apis.ts +++ b/packages/typescript-vue-plugin/src/apis.ts @@ -16,29 +16,28 @@ export function register(context: TypeScriptRuntime) { // apis function getCompletionsAtPosition(fileName: string, position: number, options: ts.GetCompletionsAtPositionOptions | undefined): ReturnType { - const finalResult = context.getTsLs('script').getCompletionsAtPosition(fileName, position, options); + const finalResult = context.getTsLs().getCompletionsAtPosition(fileName, position, options); if (finalResult) { finalResult.entries = finalResult.entries.filter(entry => entry.name.indexOf('__VLS_') === -1); } return finalResult; } function getReferencesAtPosition(fileName: string, position: number): ReturnType { - return findLocations(['script', 'template'], fileName, position, 'references') as ts.ReferenceEntry[]; + return findLocations(fileName, position, 'references') as ts.ReferenceEntry[]; } function getDefinitionAtPosition(fileName: string, position: number): ReturnType { - return findLocations(['script'], fileName, position, 'definition') as ts.DefinitionInfo[]; + return findLocations(fileName, position, 'definition') as ts.DefinitionInfo[]; } function getTypeDefinitionAtPosition(fileName: string, position: number): ReturnType { - return findLocations(['script'], fileName, position, 'typeDefinition') as ts.DefinitionInfo[]; + return findLocations(fileName, position, 'typeDefinition') as ts.DefinitionInfo[]; } function getImplementationAtPosition(fileName: string, position: number): ReturnType { - return findLocations(['script', 'template'], fileName, position, 'implementation') as ts.ImplementationLocation[]; + return findLocations(fileName, position, 'implementation') as ts.ImplementationLocation[]; } function findRenameLocations(fileName: string, position: number, findInStrings: boolean, findInComments: boolean, providePrefixAndSuffixTextForRename?: boolean): ReturnType { - return findLocations(['script', 'template'], fileName, position, 'rename', findInStrings, findInComments, providePrefixAndSuffixTextForRename) as ts.RenameLocation[]; + return findLocations(fileName, position, 'rename', findInStrings, findInComments, providePrefixAndSuffixTextForRename) as ts.RenameLocation[]; } function findLocations( - lsTypes: ('script' | 'template')[], fileName: string, position: number, mode: 'definition' | 'typeDefinition' | 'references' | 'implementation' | 'rename', @@ -47,102 +46,132 @@ export function register(context: TypeScriptRuntime) { providePrefixAndSuffixTextForRename?: boolean ) { - return lsTypes.map(lsType => worker(lsType)).flat(); - - function worker(lsType: 'script' | 'template') { - - const tsLs = context.getTsLs(lsType); - const loopChecker = new Set(); - let symbols: (ts.DefinitionInfo | ts.ReferenceEntry | ts.ImplementationLocation | ts.RenameLocation)[] = []; + const tsLs = context.getTsLs(); + const loopChecker = new Set(); + let symbols: (ts.DefinitionInfo | ts.ReferenceEntry | ts.ImplementationLocation | ts.RenameLocation)[] = []; + + if (tsLs) + withTeleports(fileName, position, tsLs); + + return symbols.map(s => transformDocumentSpanLike(s)).filter(notEmpty); + + function withTeleports(fileName: string, position: number, tsLs: ts.LanguageService) { + if (loopChecker.has(fileName + ':' + position)) + return; + loopChecker.add(fileName + ':' + position); + const _symbols = mode === 'definition' ? tsLs.getDefinitionAtPosition(fileName, position) + : mode === 'typeDefinition' ? tsLs.getTypeDefinitionAtPosition(fileName, position) + : mode === 'references' ? tsLs.getReferencesAtPosition(fileName, position) + : mode === 'implementation' ? tsLs.getImplementationAtPosition(fileName, position) + : mode === 'rename' ? tsLs.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename) + : undefined; + if (!_symbols) return; + symbols = symbols.concat(_symbols); + for (const ref of _symbols) { + loopChecker.add(ref.fileName + ':' + ref.textSpan.start); + const teleport = context.vueFiles.getTeleport(ref.fileName); + + if (!teleport) + continue; + + for (const [teleRange] of teleport.findTeleports( + ref.textSpan.start, + ref.textSpan.start + ref.textSpan.length, + sideData => { + if ((mode === 'definition' || mode === 'typeDefinition' || mode === 'implementation') && !sideData.capabilities.definitions) + return false; + if ((mode === 'references') && !sideData.capabilities.references) + return false; + if ((mode === 'rename') && !sideData.capabilities.rename) + return false; + return true; + }, + )) { + if (loopChecker.has(ref.fileName + ':' + teleRange.start)) + continue; + withTeleports(ref.fileName, teleRange.start, tsLs); + } + } + } + } + function getDefinitionAndBoundSpan(fileName: string, position: number): ReturnType { - if (tsLs) - withTeleports(fileName, position, tsLs); + const tsLs = context.getTsLs(); + const loopChecker = new Set(); + let textSpan: ts.TextSpan | undefined; + let symbols: ts.DefinitionInfo[] = []; - return symbols.map(s => transformDocumentSpanLike(lsType, s)).filter(notEmpty); + if (tsLs) + withTeleports(fileName, position, tsLs); - function withTeleports(fileName: string, position: number, tsLs: ts.LanguageService) { - if (loopChecker.has(fileName + ':' + position)) - return; - loopChecker.add(fileName + ':' + position); - const _symbols = mode === 'definition' ? tsLs.getDefinitionAtPosition(fileName, position) - : mode === 'typeDefinition' ? tsLs.getTypeDefinitionAtPosition(fileName, position) - : mode === 'references' ? tsLs.getReferencesAtPosition(fileName, position) - : mode === 'implementation' ? tsLs.getImplementationAtPosition(fileName, position) - : mode === 'rename' ? tsLs.findRenameLocations(fileName, position, findInStrings, findInComments, providePrefixAndSuffixTextForRename) - : undefined; - if (!_symbols) return; - symbols = symbols.concat(_symbols); - for (const ref of _symbols) { - loopChecker.add(ref.fileName + ':' + ref.textSpan.start); - const teleport = context.vueFiles.getTeleport(lsType, ref.fileName); + if (!textSpan) return; + return { + textSpan: textSpan, + definitions: symbols?.map(s => transformDocumentSpanLike(s)).filter(notEmpty), + }; - if (!teleport) + function withTeleports(fileName: string, position: number, tsLs: ts.LanguageService) { + if (loopChecker.has(fileName + ':' + position)) + return; + loopChecker.add(fileName + ':' + position); + const _symbols = tsLs.getDefinitionAndBoundSpan(fileName, position); + if (!_symbols) return; + if (!textSpan) { + textSpan = _symbols.textSpan; + } + if (!_symbols.definitions) return; + symbols = symbols.concat(_symbols.definitions); + for (const ref of _symbols.definitions) { + + loopChecker.add(ref.fileName + ':' + ref.textSpan.start); + + const teleport = context.vueFiles.getTeleport(ref.fileName); + if (!teleport) + continue; + + for (const [teleRange] of teleport.findTeleports( + ref.textSpan.start, + ref.textSpan.start + ref.textSpan.length, + sideData => !!sideData.capabilities.definitions, + )) { + if (loopChecker.has(ref.fileName + ':' + teleRange.start)) continue; - - for (const [teleRange] of teleport.findTeleports( - ref.textSpan.start, - ref.textSpan.start + ref.textSpan.length, - sideData => { - if ((mode === 'definition' || mode === 'typeDefinition' || mode === 'implementation') && !sideData.capabilities.definitions) - return false; - if ((mode === 'references') && !sideData.capabilities.references) - return false; - if ((mode === 'rename') && !sideData.capabilities.rename) - return false; - return true; - }, - )) { - if (loopChecker.has(ref.fileName + ':' + teleRange.start)) - continue; - withTeleports(ref.fileName, teleRange.start, tsLs); - } + withTeleports(ref.fileName, teleRange.start, tsLs); } } } } - function getDefinitionAndBoundSpan(fileName: string, position: number): ReturnType { - - return worker('script'); - - function worker(lsType: 'script' | 'template') { + function findReferences(fileName: string, position: number): ReturnType { - const tsLs = context.getTsLs(lsType); - const loopChecker = new Set(); - let textSpan: ts.TextSpan | undefined; - let symbols: ts.DefinitionInfo[] = []; + const tsLs = context.getTsLs(); + const loopChecker = new Set(); + let symbols: ts.ReferencedSymbol[] = []; - if (tsLs) - withTeleports(fileName, position, tsLs); + if (tsLs) + withTeleports(fileName, position, tsLs); - if (!textSpan) return; - return { - textSpan: textSpan, - definitions: symbols?.map(s => transformDocumentSpanLike(lsType, s)).filter(notEmpty), - }; + return symbols.map(s => transformReferencedSymbol(s)).filter(notEmpty); - function withTeleports(fileName: string, position: number, tsLs: ts.LanguageService) { - if (loopChecker.has(fileName + ':' + position)) - return; - loopChecker.add(fileName + ':' + position); - const _symbols = tsLs.getDefinitionAndBoundSpan(fileName, position); - if (!_symbols) return; - if (!textSpan) { - textSpan = _symbols.textSpan; - } - if (!_symbols.definitions) return; - symbols = symbols.concat(_symbols.definitions); - for (const ref of _symbols.definitions) { + function withTeleports(fileName: string, position: number, tsLs: ts.LanguageService) { + if (loopChecker.has(fileName + ':' + position)) + return; + loopChecker.add(fileName + ':' + position); + const _symbols = tsLs.findReferences(fileName, position); + if (!_symbols) return; + symbols = symbols.concat(_symbols); + for (const symbol of _symbols) { + for (const ref of symbol.references) { loopChecker.add(ref.fileName + ':' + ref.textSpan.start); - const teleport = context.vueFiles.getTeleport(lsType, ref.fileName); + const teleport = context.vueFiles.getTeleport(ref.fileName); if (!teleport) continue; for (const [teleRange] of teleport.findTeleports( ref.textSpan.start, ref.textSpan.start + ref.textSpan.length, - sideData => !!sideData.capabilities.definitions, + sideData => !!sideData.capabilities.references, )) { if (loopChecker.has(ref.fileName + ':' + teleRange.start)) continue; @@ -152,61 +181,11 @@ export function register(context: TypeScriptRuntime) { } } } - function findReferences(fileName: string, position: number): ReturnType { - - const scriptResult = worker('script'); - const templateResult = worker('template'); - return [ - ...scriptResult, - ...templateResult, - ]; - - function worker(lsType: 'script' | 'template') { - - const tsLs = context.getTsLs(lsType); - const loopChecker = new Set(); - let symbols: ts.ReferencedSymbol[] = []; - - if (tsLs) - withTeleports(fileName, position, tsLs); - - return symbols.map(s => transformReferencedSymbol(lsType, s)).filter(notEmpty); - - function withTeleports(fileName: string, position: number, tsLs: ts.LanguageService) { - if (loopChecker.has(fileName + ':' + position)) - return; - loopChecker.add(fileName + ':' + position); - const _symbols = tsLs.findReferences(fileName, position); - if (!_symbols) return; - symbols = symbols.concat(_symbols); - for (const symbol of _symbols) { - for (const ref of symbol.references) { - - loopChecker.add(ref.fileName + ':' + ref.textSpan.start); - - const teleport = context.vueFiles.getTeleport(lsType, ref.fileName); - if (!teleport) - continue; - - for (const [teleRange] of teleport.findTeleports( - ref.textSpan.start, - ref.textSpan.start + ref.textSpan.length, - sideData => !!sideData.capabilities.references, - )) { - if (loopChecker.has(ref.fileName + ':' + teleRange.start)) - continue; - withTeleports(ref.fileName, teleRange.start, tsLs); - } - } - } - } - } - } // transforms - function transformReferencedSymbol(lsType: 'script' | 'template', symbol: ts.ReferencedSymbol): ts.ReferencedSymbol | undefined { - const definition = transformDocumentSpanLike(lsType, symbol.definition); - const references = symbol.references.map(r => transformDocumentSpanLike(lsType, r)).filter(notEmpty); + function transformReferencedSymbol(symbol: ts.ReferencedSymbol): ts.ReferencedSymbol | undefined { + const definition = transformDocumentSpanLike(symbol.definition); + const references = symbol.references.map(r => transformDocumentSpanLike(r)).filter(notEmpty); if (definition) { return { definition, @@ -224,12 +203,12 @@ export function register(context: TypeScriptRuntime) { }; } } - function transformDocumentSpanLike(lsType: 'script' | 'template', documentSpan: T): T | undefined { - const textSpan = transformSpan(lsType, documentSpan.fileName, documentSpan.textSpan); + function transformDocumentSpanLike(documentSpan: T): T | undefined { + const textSpan = transformSpan(documentSpan.fileName, documentSpan.textSpan); if (!textSpan) return; - const contextSpan = transformSpan(lsType, documentSpan.fileName, documentSpan.contextSpan); - const originalTextSpan = transformSpan(lsType, documentSpan.originalFileName, documentSpan.originalTextSpan); - const originalContextSpan = transformSpan(lsType, documentSpan.originalFileName, documentSpan.originalContextSpan); + const contextSpan = transformSpan(documentSpan.fileName, documentSpan.contextSpan); + const originalTextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalTextSpan); + const originalContextSpan = transformSpan(documentSpan.originalFileName, documentSpan.originalContextSpan); return { ...documentSpan, fileName: textSpan.fileName, @@ -240,10 +219,10 @@ export function register(context: TypeScriptRuntime) { originalContextSpan: originalContextSpan?.textSpan, }; } - function transformSpan(lsType: 'script' | 'template', fileName: string | undefined, textSpan: ts.TextSpan | undefined) { + function transformSpan(fileName: string | undefined, textSpan: ts.TextSpan | undefined) { if (!fileName) return; if (!textSpan) return; - for (const vueLoc of context.vueFiles.fromEmbeddedLocation(lsType, fileName, textSpan.start, textSpan.start + textSpan.length)) { + for (const vueLoc of context.vueFiles.fromEmbeddedLocation(fileName, textSpan.start, textSpan.start + textSpan.length)) { return { fileName: vueLoc.fileName, textSpan: { diff --git a/packages/typescript-vue-plugin/src/index.ts b/packages/typescript-vue-plugin/src/index.ts index d541e1ab7..6ede17f04 100644 --- a/packages/typescript-vue-plugin/src/index.ts +++ b/packages/typescript-vue-plugin/src/index.ts @@ -34,14 +34,14 @@ const init: ts.server.PluginModuleFactory = (modules) => { }); const _tsPluginApis = apis.register(tsRuntime); const tsPluginProxy: Partial = { - getSemanticDiagnostics: apiHook(tsRuntime.getTsLs('script').getSemanticDiagnostics, false), - getEncodedSemanticClassifications: apiHook(tsRuntime.getTsLs('script').getEncodedSemanticClassifications, false), + getSemanticDiagnostics: apiHook(tsRuntime.getTsLs().getSemanticDiagnostics, false), + getEncodedSemanticClassifications: apiHook(tsRuntime.getTsLs().getEncodedSemanticClassifications, false), getCompletionsAtPosition: apiHook(_tsPluginApis.getCompletionsAtPosition, false), - getCompletionEntryDetails: apiHook(tsRuntime.getTsLs('script').getCompletionEntryDetails, false), // not sure - getCompletionEntrySymbol: apiHook(tsRuntime.getTsLs('script').getCompletionEntrySymbol, false), // not sure - getQuickInfoAtPosition: apiHook(tsRuntime.getTsLs('script').getQuickInfoAtPosition, false), - getSignatureHelpItems: apiHook(tsRuntime.getTsLs('script').getSignatureHelpItems, false), - getRenameInfo: apiHook(tsRuntime.getTsLs('script').getRenameInfo, false), + getCompletionEntryDetails: apiHook(tsRuntime.getTsLs().getCompletionEntryDetails, false), // not sure + getCompletionEntrySymbol: apiHook(tsRuntime.getTsLs().getCompletionEntrySymbol, false), // not sure + getQuickInfoAtPosition: apiHook(tsRuntime.getTsLs().getQuickInfoAtPosition, false), + getSignatureHelpItems: apiHook(tsRuntime.getTsLs().getSignatureHelpItems, false), + getRenameInfo: apiHook(tsRuntime.getTsLs().getRenameInfo, false), findRenameLocations: apiHook(_tsPluginApis.findRenameLocations, true), getDefinitionAtPosition: apiHook(_tsPluginApis.getDefinitionAtPosition, false), diff --git a/packages/vue-code-gen/src/generators/template.ts b/packages/vue-code-gen/src/generators/template.ts index 501b48b9b..30dc4d077 100644 --- a/packages/vue-code-gen/src/generators/template.ts +++ b/packages/vue-code-gen/src/generators/template.ts @@ -18,7 +18,7 @@ const capabilitiesSet = { slotName: { basic: true, diagnostic: true, references: true, definitions: true, completion: true, }, slotNameExport: { basic: true, diagnostic: true, references: true, definitions: true, referencesCodeLens: true }, refAttr: { references: true, definitions: true, rename: true, }, -} +}; const formatBrackets = { empty: ['', ''] as [string, string], round: ['(', ')'] as [string, string], @@ -100,7 +100,6 @@ export function generate( const isNamespacedTag = tagName.indexOf('.') >= 0; const var_correctTagName = `__VLS_${elementIndex++}`; - const var_wrapComponent = `__VLS_${elementIndex++}`; const var_rawComponent = `__VLS_${elementIndex++}`; const var_slotsComponent = `__VLS_${elementIndex++}`; const var_baseProps = `__VLS_${elementIndex++}`; @@ -131,23 +130,12 @@ export function generate( } else { tsCodeGen.addText(`declare const ${var_correctTagName}: __VLS_types.GetComponentName;\n`); - tsCodeGen.addText(`declare const ${var_wrapComponent}: __VLS_types.GetProperty;\n`); tsCodeGen.addText(`declare const ${var_rawComponent}: __VLS_types.GetProperty;\n`); } tsCodeGen.addText(`declare const ${var_slotsComponent}: __VLS_types.SlotsComponent;\n`); tsCodeGen.addText(`declare const ${var_baseProps}: __VLS_types.ExtractComponentProps;\n`); tsCodeGen.addText(`declare const ${var_emit}: __VLS_types.ExtractEmit2;\n`); - - if (isNamespacedTag) { - tsCodeGen.addText(`declare const ${var_slots}: - __VLS_types.TemplateSlots - & __VLS_types.DefaultSlots;\n`); - } - else { - tsCodeGen.addText(`declare const ${var_slots}: - __VLS_types.TemplateSlots - & __VLS_types.DefaultSlots;\n`); - } + tsCodeGen.addText(`declare const ${var_slots}: __VLS_types.DefaultSlots;\n`); for (const eventName in tag.events) { @@ -223,8 +211,6 @@ export function generate( } } - writeOptionReferences(); - /* Completion */ tsCodeGen.addText('/* Completion: Emits */\n'); for (const name of componentNames) { @@ -245,88 +231,6 @@ export function generate( events: var_events, offsets: tag.offsets.map(offset => htmlToTemplate(offset, offset)?.start).filter(notEmpty), }; - - function writeOptionReferences() { - // fix find references not work if prop has default value - // fix emits references not work - for (const propName in tag.props) { - - const prop = tag.props[propName]; - const propNames = new Set(); - propNames.add(propName); - propNames.add(camelize(propName)); - - for (const name of propNames.values()) { - // __VLS_options.props - tsCodeGen.addText(`// @ts-ignore\n`); - tsCodeGen.addText(`${var_wrapComponent}.__VLS_options.props`); - writePropertyAccess2( - name, - prop.offsets.map(offset => ({ start: offset, end: offset + prop.argName.length })), - { - vueTag: 'template', - capabilities: { - ...capabilitiesSet.attrReference, - rename: propName === prop.argName, - }, - normalizeNewName: camelize, - applyNewName: keepHyphenateName, - }, - ); - tsCodeGen.addText(`;\n`); - } - } - for (const eventName in tag.events) { - - const event = tag.events[eventName]; - const eventNames = new Set(); - const propNames = new Set(); - eventNames.add(eventName); - eventNames.add(camelize(eventName)); - propNames.add(camelize('on-' + eventName)); - - for (const name of eventNames.values()) { - // __VLS_options.emits - tsCodeGen.addText(`// @ts-ignore\n`); - tsCodeGen.addText(`${var_wrapComponent}.__VLS_options.emits`); - writePropertyAccess2( - name, - event.offsets.map(offset => ({ start: offset, end: offset + eventName.length })), - { - vueTag: 'template', - capabilities: capabilitiesSet.attrReference, - normalizeNewName: camelize, - applyNewName: keepHyphenateName, - }, - ); - tsCodeGen.addText(`;\n`); - } - for (const name of propNames.values()) { - // __VLS_options.props - tsCodeGen.addText(`// @ts-ignore\n`); - tsCodeGen.addText(`${var_wrapComponent}.__VLS_options.props`); - writePropertyAccess2( - name, - event.offsets.map(offset => ({ start: offset, end: offset + eventName.length })), - { - vueTag: 'template', - capabilities: capabilitiesSet.attrReference, - normalizeNewName(newName) { - return camelize('on-' + newName); - }, - applyNewName(oldName, newName) { - const hName = hyphenate(newName); - if (hyphenate(newName).startsWith('on-')) { - return camelize(hName.slice('on-'.length)); - } - return newName; - }, - }, - ); - tsCodeGen.addText(`;\n`); - } - } - } } for (const childNode of templateAst.children) { diff --git a/packages/vue-language-server/src/features/customFeatures.ts b/packages/vue-language-server/src/features/customFeatures.ts index 0a86b2090..6addff427 100644 --- a/packages/vue-language-server/src/features/customFeatures.ts +++ b/packages/vue-language-server/src/features/customFeatures.ts @@ -20,7 +20,7 @@ export function register( const projects = getProjects(); return (await projects?.getProject(handler.uri))?.tsconfig; }); - connection.onNotification(shared.WriteVirtualFilesNotification.type, async ({ lsType }) => { + connection.onNotification(shared.WriteVirtualFilesNotification.type, async () => { const projects = getProjects(); if (!projects) return; @@ -29,7 +29,7 @@ export function register( for (const project of [...workspace.projects.values(), workspace.getInferredProjectDontCreate()].filter(shared.notEmpty)) { const ls = await (await project).getLanguageServiceDontCreate(); if (!ls) continue; - const localTypes = ls.__internal__.tsRuntime.getLocalTypesFiles(lsType); + const localTypes = ls.__internal__.tsRuntime.getLocalTypesFiles(); for (const fileName of localTypes.fileNames) { connection.workspace.applyEdit({ edit: { @@ -46,19 +46,26 @@ export function register( const context = await ls.__internal__.getContext(); for (const vueDocument of context.vueDocuments.getAll()) { for (const sourceMap of vueDocument.getSourceMaps()) { - if (sourceMap.embeddedFile.lsType === lsType) { - connection.workspace.applyEdit({ - edit: { - documentChanges: [ - vscode.CreateFile.create(sourceMap.mappedDocument.uri), - vscode.TextDocumentEdit.create( - vscode.OptionalVersionedTextDocumentIdentifier.create(sourceMap.mappedDocument.uri, null), - [{ range: vscode.Range.create(0, 0, 0, 0), newText: sourceMap.mappedDocument.getText() }], - ), - ] - } - }); - } + + const isTsFile = sourceMap.embeddedFile.fileName.endsWith('.js') || + sourceMap.embeddedFile.fileName.endsWith('.ts') || + sourceMap.embeddedFile.fileName.endsWith('.jsx') || + sourceMap.embeddedFile.fileName.endsWith('.tsx') + + if (!isTsFile) + continue; + + connection.workspace.applyEdit({ + edit: { + documentChanges: [ + vscode.CreateFile.create(sourceMap.mappedDocument.uri), + vscode.TextDocumentEdit.create( + vscode.OptionalVersionedTextDocumentIdentifier.create(sourceMap.mappedDocument.uri, null), + [{ range: vscode.Range.create(0, 0, 0, 0), newText: sourceMap.mappedDocument.getText() }], + ), + ] + } + }); } } } diff --git a/packages/vue-language-server/src/projects.ts b/packages/vue-language-server/src/projects.ts index ec793c112..66c9bfb24 100644 --- a/packages/vue-language-server/src/projects.ts +++ b/packages/vue-language-server/src/projects.ts @@ -352,7 +352,7 @@ function createWorkspace( return findTsconfig(async tsconfig => { const project = await projects.fsPathGet(tsconfig); const ls = await project?.getLanguageServiceDontCreate(); - const validDoc = ls?.__internal__.context.getTsLs('script').__internal__.getValidTextDocument(uri); + const validDoc = ls?.__internal__.context.getTsLs().__internal__.getValidTextDocument(uri); return !!validDoc; }); } diff --git a/packages/vue-language-service/src/commonPlugins/typescript.ts b/packages/vue-language-service/src/commonPlugins/typescript.ts index ae31c5d1e..601bc7dd5 100644 --- a/packages/vue-language-service/src/commonPlugins/typescript.ts +++ b/packages/vue-language-service/src/commonPlugins/typescript.ts @@ -29,7 +29,7 @@ const directiveCommentTriggerCharacters = ['@']; export default function (options: { tsVersion: string, getTsLs: () => ts2.LanguageService, - baseCompletionOptions?: ts.GetCompletionsAtPositionOptions, + getBaseCompletionOptions?: (uri: string) => ts.GetCompletionsAtPositionOptions, }): EmbeddedLanguageServicePlugin { const basicTriggerCharacters = getBasicTriggerCharacters(options.tsVersion); @@ -58,8 +58,9 @@ export default function (options: { if (!context || context.triggerKind !== vscode.CompletionTriggerKind.TriggerCharacter || (context.triggerCharacter && basicTriggerCharacters.includes(context.triggerCharacter))) { + const baseCompletionOptions = options.getBaseCompletionOptions?.(document.uri) ?? []; const completeOptions: ts.GetCompletionsAtPositionOptions = { - ...options.baseCompletionOptions, + ...baseCompletionOptions, triggerCharacter: context?.triggerCharacter as ts.CompletionsTriggerCharacter, triggerKind: context?.triggerKind, }; diff --git a/packages/vue-language-service/src/documentFeatures/format.ts b/packages/vue-language-service/src/documentFeatures/format.ts index 11f8eacfe..4db7b7485 100644 --- a/packages/vue-language-service/src/documentFeatures/format.ts +++ b/packages/vue-language-service/src/documentFeatures/format.ts @@ -32,7 +32,6 @@ export function register(context: DocumentServiceRuntimeContext) { let edits: vscode.TextEdit[] = []; let toPatchIndent: { - lsType: string, sourceMapEmbeddedDocumentUri: string, } | undefined; @@ -45,7 +44,6 @@ export function register(context: DocumentServiceRuntimeContext) { if (embedded.inheritParentIndent) toPatchIndent = { - lsType: sourceMap.embeddedFile.lsType, sourceMapEmbeddedDocumentUri: sourceMap.mappedDocument.uri, }; @@ -75,7 +73,7 @@ export function register(context: DocumentServiceRuntimeContext) { tryUpdateVueDocument(); - const sourceMap = vueDocument.getSourceMaps().find(sourceMap => sourceMap.embeddedFile.lsType === toPatchIndent?.lsType && sourceMap.mappedDocument.uri === toPatchIndent.sourceMapEmbeddedDocumentUri); + const sourceMap = vueDocument.getSourceMaps().find(sourceMap => sourceMap.mappedDocument.uri === toPatchIndent?.sourceMapEmbeddedDocumentUri); if (sourceMap) { diff --git a/packages/vue-language-service/src/documentService.ts b/packages/vue-language-service/src/documentService.ts index eed3a7170..1e0e8a1c5 100644 --- a/packages/vue-language-service/src/documentService.ts +++ b/packages/vue-language-service/src/documentService.ts @@ -47,7 +47,7 @@ export function getDocumentService( // language support plugins const vuePlugin = useVuePlugin({ getVueDocument, - scriptTsLs: undefined, + tsLs: undefined, }); const htmlPlugin = useHtmlPlugin({ fileSystemProvider, diff --git a/packages/vue-language-service/src/languageFeatures/callHierarchy.ts b/packages/vue-language-service/src/languageFeatures/callHierarchy.ts index 8115dbdee..0914e793a 100644 --- a/packages/vue-language-service/src/languageFeatures/callHierarchy.ts +++ b/packages/vue-language-service/src/languageFeatures/callHierarchy.ts @@ -10,7 +10,6 @@ export interface PluginCallHierarchyData { originalItem: vscode.CallHierarchyItem, pluginId: number, sourceMap: { - lsType: 'script' | 'template' | 'nonTs', embeddedDocumentUri: string } | undefined, } @@ -45,7 +44,6 @@ export function register(context: LanguageServiceRuntimeContext) { originalItem: item, pluginId: plugin.id, sourceMap: sourceMap ? { - lsType: sourceMap.embeddedFile.lsType, embeddedDocumentUri: sourceMap.mappedDocument.uri, } : undefined, }; @@ -57,7 +55,7 @@ export function register(context: LanguageServiceRuntimeContext) { }); }, (data, sourceMap) => !sourceMap ? data : data - .map(item => transformCallHierarchyItem(sourceMap.embeddedFile.lsType, item, [])?.[0]) + .map(item => transformCallHierarchyItem(item, [])?.[0]) .filter(shared.notEmpty), arr => dedupe.withLocations(arr.flat()), ); @@ -82,7 +80,7 @@ export function register(context: LanguageServiceRuntimeContext) { if (data.sourceMap) { - const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.lsType, data.sourceMap.embeddedDocumentUri); + const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.embeddedDocumentUri); if (sourceMap) { @@ -90,7 +88,7 @@ export function register(context: LanguageServiceRuntimeContext) { for (const _call of _calls) { - const calls = transformCallHierarchyItem(sourceMap.embeddedFile.lsType, _call.from, _call.fromRanges); + const calls = transformCallHierarchyItem(_call.from, _call.fromRanges); if (!calls) continue; @@ -108,7 +106,7 @@ export function register(context: LanguageServiceRuntimeContext) { for (const _call of _calls) { - const calls = transformCallHierarchyItem('script', _call.from, _call.fromRanges); + const calls = transformCallHierarchyItem(_call.from, _call.fromRanges); if (!calls) continue; @@ -143,7 +141,7 @@ export function register(context: LanguageServiceRuntimeContext) { if (data.sourceMap) { - const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.lsType, data.sourceMap.embeddedDocumentUri); + const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.embeddedDocumentUri); if (sourceMap) { @@ -151,7 +149,7 @@ export function register(context: LanguageServiceRuntimeContext) { for (const call of _calls) { - const calls = transformCallHierarchyItem(sourceMap.embeddedFile.lsType, call.to, call.fromRanges); + const calls = transformCallHierarchyItem(call.to, call.fromRanges); if (!calls) continue; @@ -169,7 +167,7 @@ export function register(context: LanguageServiceRuntimeContext) { for (const call of _calls) { - const calls = transformCallHierarchyItem('script', call.to, call.fromRanges); + const calls = transformCallHierarchyItem(call.to, call.fromRanges); if (!calls) continue; @@ -186,9 +184,9 @@ export function register(context: LanguageServiceRuntimeContext) { }, }; - function transformCallHierarchyItem(lsType: 'script' | 'template' | 'nonTs', tsItem: vscode.CallHierarchyItem, tsRanges: vscode.Range[]): [vscode.CallHierarchyItem, vscode.Range[]] | undefined { + function transformCallHierarchyItem(tsItem: vscode.CallHierarchyItem, tsRanges: vscode.Range[]): [vscode.CallHierarchyItem, vscode.Range[]] | undefined { - const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(lsType, tsItem.uri); + const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(tsItem.uri); if (!sourceMap) return [tsItem, tsRanges]; // not virtual file diff --git a/packages/vue-language-service/src/languageFeatures/codeActionResolve.ts b/packages/vue-language-service/src/languageFeatures/codeActionResolve.ts index 84e4946d5..52f7dd4c6 100644 --- a/packages/vue-language-service/src/languageFeatures/codeActionResolve.ts +++ b/packages/vue-language-service/src/languageFeatures/codeActionResolve.ts @@ -22,7 +22,7 @@ export function register(context: LanguageServiceRuntimeContext) { if (data.sourceMap) { - const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.lsType, data.sourceMap.embeddedDocumentUri); + const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.embeddedDocumentUri); if (sourceMap) { @@ -31,8 +31,6 @@ export function register(context: LanguageServiceRuntimeContext) { if (resolvedItem.edit) { const edit = embeddedEditToSourceEdit( - sourceMap.embeddedFile.lsType, - false, resolvedItem.edit, context.vueDocuments, ); diff --git a/packages/vue-language-service/src/languageFeatures/codeActions.ts b/packages/vue-language-service/src/languageFeatures/codeActions.ts index 84d14f17d..beac00efc 100644 --- a/packages/vue-language-service/src/languageFeatures/codeActions.ts +++ b/packages/vue-language-service/src/languageFeatures/codeActions.ts @@ -11,7 +11,6 @@ export interface PluginCodeActionData { originalItem: vscode.CodeAction, pluginId: number, sourceMap: { - lsType: 'script' | 'template' | 'nonTs', embeddedDocumentUri: string } | undefined, } @@ -84,7 +83,6 @@ export function register(context: LanguageServiceRuntimeContext) { originalItem: _codeAction, pluginId: plugin.id, sourceMap: sourceMap ? { - lsType: sourceMap.embeddedFile.lsType, embeddedDocumentUri: sourceMap.mappedDocument.uri, } : undefined, }; @@ -102,8 +100,6 @@ export function register(context: LanguageServiceRuntimeContext) { if (_codeAction.edit) { const edit = embeddedEditToSourceEdit( - sourceMap.embeddedFile.lsType, - false, _codeAction.edit, context.vueDocuments, ); diff --git a/packages/vue-language-service/src/languageFeatures/complete.ts b/packages/vue-language-service/src/languageFeatures/complete.ts index 4efe80816..1cbd15eaf 100644 --- a/packages/vue-language-service/src/languageFeatures/complete.ts +++ b/packages/vue-language-service/src/languageFeatures/complete.ts @@ -9,7 +9,6 @@ export interface PluginCompletionData { originalItem: vscode.CompletionItem, pluginId: number, sourceMap: { - lsType: 'script' | 'template' | 'nonTs', embeddedDocumentUri: string } | undefined, } @@ -20,7 +19,6 @@ export function register(context: LanguageServiceRuntimeContext) { uri: string, data: { sourceMap: { - lsType: 'script' | 'template' | 'nonTs', embeddedDocumentUri: string } | undefined, plugin: LanguageServicePlugin, @@ -47,7 +45,7 @@ export function register(context: LanguageServiceRuntimeContext) { if (cacheData.sourceMap) { - const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(cacheData.sourceMap.lsType, cacheData.sourceMap.embeddedDocumentUri); + const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(cacheData.sourceMap.embeddedDocumentUri); if (!sourceMap) continue; @@ -72,7 +70,6 @@ export function register(context: LanguageServiceRuntimeContext) { originalItem: item, pluginId: cacheData.plugin.id, sourceMap: { - lsType: sourceMap.embeddedFile.lsType, embeddedDocumentUri: sourceMap.mappedDocument.uri, }, }; @@ -134,7 +131,7 @@ export function register(context: LanguageServiceRuntimeContext) { await visitEmbedded(vueDocument, embeddeds, async sourceMap => { - const plugins = context.getPlugins(sourceMap.embeddedFile.lsType).sort(sortPlugins); + const plugins = context.getPlugins().sort(sortPlugins); for (const [embeddedRange] of sourceMap.getMappedRanges(position, position, data => !!data.capabilities.completion)) { @@ -166,7 +163,6 @@ export function register(context: LanguageServiceRuntimeContext) { originalItem: item, pluginId: plugin.id, sourceMap: { - lsType: sourceMap.embeddedFile.lsType, embeddedDocumentUri: sourceMap.mappedDocument.uri, } }; @@ -182,7 +178,6 @@ export function register(context: LanguageServiceRuntimeContext) { cache!.data.push({ sourceMap: { - lsType: sourceMap.embeddedFile.lsType, embeddedDocumentUri: sourceMap.mappedDocument.uri, }, plugin, @@ -197,7 +192,7 @@ export function register(context: LanguageServiceRuntimeContext) { if (document) { - const plugins = context.getPlugins('script').sort(sortPlugins); + const plugins = context.getPlugins().sort(sortPlugins); for (const plugin of plugins) { diff --git a/packages/vue-language-service/src/languageFeatures/completeResolve.ts b/packages/vue-language-service/src/languageFeatures/completeResolve.ts index f330fa923..ee44f7891 100644 --- a/packages/vue-language-service/src/languageFeatures/completeResolve.ts +++ b/packages/vue-language-service/src/languageFeatures/completeResolve.ts @@ -23,7 +23,7 @@ export function register(context: LanguageServiceRuntimeContext) { if (data.sourceMap) { - const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.lsType, data.sourceMap.embeddedDocumentUri); + const sourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(data.sourceMap.embeddedDocumentUri); if (sourceMap) { diff --git a/packages/vue-language-service/src/languageFeatures/definition.ts b/packages/vue-language-service/src/languageFeatures/definition.ts index c13e5eba6..57a8d65f0 100644 --- a/packages/vue-language-service/src/languageFeatures/definition.ts +++ b/packages/vue-language-service/src/languageFeatures/definition.ts @@ -53,27 +53,24 @@ export function register( let foundTeleport = false; - if (sourceMap?.embeddedFile.lsType !== 'nonTs') { + recursiveChecker.add({ uri: definition.targetUri, range: { start: definition.targetRange.start, end: definition.targetRange.start } }); - recursiveChecker.add({ uri: definition.targetUri, range: { start: definition.targetRange.start, end: definition.targetRange.start } }); + const teleport = context.vueDocuments.teleportfromEmbeddedDocumentUri(definition.targetUri); - const teleport = context.vueDocuments.teleportfromEmbeddedDocumentUri(sourceMap?.embeddedFile.lsType ?? 'script', definition.targetUri); + if (teleport) { - if (teleport) { + for (const [teleRange] of teleport.findTeleports( + definition.targetSelectionRange.start, + definition.targetSelectionRange.end, + isValidTeleportSideData, + )) { - for (const [teleRange] of teleport.findTeleports( - definition.targetSelectionRange.start, - definition.targetSelectionRange.end, - isValidTeleportSideData, - )) { + if (recursiveChecker.has({ uri: teleport.document.uri, range: { start: teleRange.start, end: teleRange.start } })) + continue; - if (recursiveChecker.has({ uri: teleport.document.uri, range: { start: teleRange.start, end: teleRange.start } })) - continue; + foundTeleport = true; - foundTeleport = true; - - await withTeleports(teleport.document, teleRange.start, originDefinition ?? definition); - } + await withTeleports(teleport.document, teleRange.start, originDefinition ?? definition); } } @@ -103,7 +100,7 @@ export function register( link.originSelectionRange = originSelectionRange; } - const targetSourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(sourceMap?.embeddedFile.lsType ?? 'script', link.targetUri); + const targetSourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(link.targetUri); if (targetSourceMap) { diff --git a/packages/vue-language-service/src/languageFeatures/executeCommand.ts b/packages/vue-language-service/src/languageFeatures/executeCommand.ts index eee615a3b..a7862ece4 100644 --- a/packages/vue-language-service/src/languageFeatures/executeCommand.ts +++ b/packages/vue-language-service/src/languageFeatures/executeCommand.ts @@ -26,7 +26,7 @@ export function register(context: LanguageServiceRuntimeContext) { } else { - for (const plugin of context.getPlugins('script')) { + for (const plugin of context.getPlugins()) { await plugin.doExecuteCommand?.(originalCommand.command, originalCommand.arguments as any, executeCommandContext); } diff --git a/packages/vue-language-service/src/languageFeatures/fileRename.ts b/packages/vue-language-service/src/languageFeatures/fileRename.ts index 47cd05103..1ec19d3d6 100644 --- a/packages/vue-language-service/src/languageFeatures/fileRename.ts +++ b/packages/vue-language-service/src/languageFeatures/fileRename.ts @@ -13,7 +13,7 @@ export function register(context: LanguageServiceRuntimeContext) { newUri += '.ts'; } - const plugins = context.getPlugins('script'); + const plugins = context.getPlugins(); for (const plugin of plugins) { @@ -24,8 +24,6 @@ export function register(context: LanguageServiceRuntimeContext) { if (workspaceEdit) { return embeddedEditToSourceEdit( - 'script', - false, workspaceEdit, context.vueDocuments, ) diff --git a/packages/vue-language-service/src/languageFeatures/references.ts b/packages/vue-language-service/src/languageFeatures/references.ts index 4672c3d04..af422d63c 100644 --- a/packages/vue-language-service/src/languageFeatures/references.ts +++ b/packages/vue-language-service/src/languageFeatures/references.ts @@ -47,27 +47,24 @@ export function register(context: LanguageServiceRuntimeContext) { let foundTeleport = false; - if (sourceMap?.embeddedFile.lsType !== 'nonTs') { + recursiveChecker.add({ uri: reference.uri, range: { start: reference.range.start, end: reference.range.start } }); - recursiveChecker.add({ uri: reference.uri, range: { start: reference.range.start, end: reference.range.start } }); + const teleport = context.vueDocuments.teleportfromEmbeddedDocumentUri(reference.uri); - const teleport = context.vueDocuments.teleportfromEmbeddedDocumentUri(sourceMap?.embeddedFile.lsType ?? 'script', reference.uri); + if (teleport) { - if (teleport) { + for (const [teleRange] of teleport.findTeleports( + reference.range.start, + reference.range.end, + sideData => !!sideData.capabilities.references, + )) { - for (const [teleRange] of teleport.findTeleports( - reference.range.start, - reference.range.end, - sideData => !!sideData.capabilities.references, - )) { + if (recursiveChecker.has({ uri: teleport.document.uri, range: { start: teleRange.start, end: teleRange.start } })) + continue; - if (recursiveChecker.has({ uri: teleport.document.uri, range: { start: teleRange.start, end: teleRange.start } })) - continue; + foundTeleport = true; - foundTeleport = true; - - await withTeleports(teleport.document, teleRange.start); - } + await withTeleports(teleport.document, teleRange.start); } } @@ -79,7 +76,7 @@ export function register(context: LanguageServiceRuntimeContext) { }, (data, sourceMap) => data.map(reference => { - const referenceSourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(sourceMap?.embeddedFile.lsType ?? 'script', reference.uri); + const referenceSourceMap = context.vueDocuments.sourceMapFromEmbeddedDocumentUri(reference.uri); if (referenceSourceMap) { diff --git a/packages/vue-language-service/src/languageFeatures/rename.ts b/packages/vue-language-service/src/languageFeatures/rename.ts index b11e223a6..030e6ea42 100644 --- a/packages/vue-language-service/src/languageFeatures/rename.ts +++ b/packages/vue-language-service/src/languageFeatures/rename.ts @@ -65,31 +65,28 @@ export function register(context: LanguageServiceRuntimeContext) { let foundTeleport = false; - if (sourceMap?.embeddedFile.lsType !== 'nonTs') { + recursiveChecker.add({ uri: editUri, range: { start: textEdit.range.start, end: textEdit.range.start } }); - recursiveChecker.add({ uri: editUri, range: { start: textEdit.range.start, end: textEdit.range.start } }); + const teleport = context.vueDocuments.teleportfromEmbeddedDocumentUri(editUri); - const teleport = context.vueDocuments.teleportfromEmbeddedDocumentUri(sourceMap?.embeddedFile.lsType ?? 'script', editUri); + if (teleport) { - if (teleport) { + for (const [teleRange, sideData] of teleport.findTeleports( + textEdit.range.start, + textEdit.range.end, + sideData => !!sideData.capabilities.references, + )) { - for (const [teleRange, sideData] of teleport.findTeleports( - textEdit.range.start, - textEdit.range.end, - sideData => !!sideData.capabilities.references, - )) { + if (recursiveChecker.has({ uri: teleport.document.uri, range: { start: teleRange.start, end: teleRange.start } })) + continue; - if (recursiveChecker.has({ uri: teleport.document.uri, range: { start: teleRange.start, end: teleRange.start } })) - continue; + foundTeleport = true; - foundTeleport = true; + const newName_2 = sideData.transformNewName + ? sideData.transformNewName(newName) + : newName; - const newName_2 = sideData.transformNewName - ? sideData.transformNewName(newName) - : newName; - - await withTeleports(teleport.document, teleRange.start, newName_2); - } + await withTeleports(teleport.document, teleRange.start, newName_2); } } @@ -128,13 +125,7 @@ export function register(context: LanguageServiceRuntimeContext) { } }, (data, sourceMap) => { - - const vueDocument = context.vueDocuments.get(uri); - const renameFromScriptContent = !vueDocument || !vueDocument.getSourceMaps().some(sourceMap => sourceMap.embeddedFile.lsType === 'template' && sourceMap.getMappedRange(position)); - return embeddedEditToSourceEdit( - sourceMap?.embeddedFile.lsType ?? 'script', - sourceMap?.embeddedFile.lsType === 'template' && renameFromScriptContent, data, context.vueDocuments, ); @@ -201,8 +192,6 @@ export function mergeWorkspaceEdits(original: vscode.WorkspaceEdit, ...others: v * -> No: Access all results */ export function embeddedEditToSourceEdit( - lsType: 'script' | 'template' | 'nonTs', - ignoreScriptLsResult: boolean, tsResult: vscode.WorkspaceEdit, vueDocuments: VueDocuments, ) { @@ -216,27 +205,19 @@ export function embeddedEditToSourceEdit( vueResult.changeAnnotations = {}; const tsAnno = tsResult.changeAnnotations[tsUri]; - const uri = vueDocuments.sourceMapFromEmbeddedDocumentUri(lsType, tsUri)?.sourceDocument.uri ?? tsUri; + const uri = vueDocuments.sourceMapFromEmbeddedDocumentUri(tsUri)?.sourceDocument.uri ?? tsUri; vueResult.changeAnnotations[uri] = tsAnno; } for (const tsUri in tsResult.changes) { const tsEdits = tsResult.changes[tsUri]; for (const tsEdit of tsEdits) { for (const vueLoc of vueDocuments.fromEmbeddedLocation( - lsType, tsUri, tsEdit.range.start, tsEdit.range.end, data => typeof data.capabilities.rename === 'object' ? data.capabilities.rename.out : !!data.capabilities.rename, // fix https://github.com/johnsoncodehk/volar/issues/1091 )) { - if (ignoreScriptLsResult) { - const isTemplateResult = vueLoc.sourceMap && (vueLoc.data.vueTag === 'template' || vueLoc.data.vueTag === 'style'); - if (!isTemplateResult) { - continue; - } - } - let newText_2 = tsEdit.newText; if (vueLoc.sourceMap && vueLoc.data.applyNewName) { @@ -267,7 +248,7 @@ export function embeddedEditToSourceEdit( } let vueDocEdit: typeof tsDocEdit | undefined; if (vscode.TextDocumentEdit.is(tsDocEdit)) { - const sourceMap = vueDocuments.sourceMapFromEmbeddedDocumentUri(lsType, tsDocEdit.textDocument.uri); + const sourceMap = vueDocuments.sourceMapFromEmbeddedDocumentUri(tsDocEdit.textDocument.uri); if (sourceMap) { vueDocEdit = vscode.TextDocumentEdit.create( { uri: sourceMap.sourceDocument.uri, version: sourceMap.sourceDocument.version }, @@ -280,10 +261,6 @@ export function embeddedEditToSourceEdit( data => typeof data.capabilities.rename === 'object' ? data.capabilities.rename.out : !!data.capabilities.rename, // fix https://github.com/johnsoncodehk/volar/issues/1091 )) { - if (ignoreScriptLsResult && !(data.vueTag === 'template' || data.vueTag === 'style')) { - continue; - } - vueDocEdit.edits.push({ annotationId: vscode.AnnotatedTextEdit.is(tsEdit.range) ? tsEdit.range.annotationId : undefined, newText: tsEdit.newText, @@ -295,19 +272,19 @@ export function embeddedEditToSourceEdit( vueDocEdit = undefined; } } - else if (!ignoreScriptLsResult) { + else { vueDocEdit = tsDocEdit; } } - else if (vscode.CreateFile.is(tsDocEdit) && !ignoreScriptLsResult) { + else if (vscode.CreateFile.is(tsDocEdit)) { vueDocEdit = tsDocEdit; // TODO: remove .ts? } - else if (vscode.RenameFile.is(tsDocEdit) && !ignoreScriptLsResult) { - const oldUri = vueDocuments.sourceMapFromEmbeddedDocumentUri(lsType, tsDocEdit.oldUri)?.sourceDocument.uri ?? tsDocEdit.oldUri; + else if (vscode.RenameFile.is(tsDocEdit)) { + const oldUri = vueDocuments.sourceMapFromEmbeddedDocumentUri(tsDocEdit.oldUri)?.sourceDocument.uri ?? tsDocEdit.oldUri; vueDocEdit = vscode.RenameFile.create(oldUri, tsDocEdit.newUri /* TODO: remove .ts? */, tsDocEdit.options, tsDocEdit.annotationId); } - else if (vscode.DeleteFile.is(tsDocEdit) && !ignoreScriptLsResult) { - const uri = vueDocuments.sourceMapFromEmbeddedDocumentUri(lsType, tsDocEdit.uri)?.sourceDocument.uri ?? tsDocEdit.uri; + else if (vscode.DeleteFile.is(tsDocEdit)) { + const uri = vueDocuments.sourceMapFromEmbeddedDocumentUri(tsDocEdit.uri)?.sourceDocument.uri ?? tsDocEdit.uri; vueDocEdit = vscode.DeleteFile.create(uri, tsDocEdit.options, tsDocEdit.annotationId); } if (vueDocEdit) { diff --git a/packages/vue-language-service/src/languageFeatures/validation.ts b/packages/vue-language-service/src/languageFeatures/validation.ts index e353c888f..a701d6199 100644 --- a/packages/vue-language-service/src/languageFeatures/validation.ts +++ b/packages/vue-language-service/src/languageFeatures/validation.ts @@ -51,7 +51,7 @@ export function register(context: LanguageServiceRuntimeContext, updateTemplateS let errorsDirty = false; // avoid cache error range jitter - await worker('nonTs', { + await worker(false, { declaration: true, semantic: true, suggestion: true, @@ -67,20 +67,26 @@ export function register(context: LanguageServiceRuntimeContext, updateTemplateS const isScriptChanged = lastUpdated.script || lastUpdated.scriptSetup; if (isScriptChanged) { - await scriptWorker(); + await worker(true, { syntactic: true }, templateTsCache_syntactic, errors => cache.templateTs_syntactic = errors ?? []); + await worker(true, { suggestion: true }, templateTsCache_suggestion, errors => cache.templateTs_suggestion = errors ?? []); doResponse(); - await templateWorker(); + if (!await isCancel?.()) + updateTemplateScripts(); + await worker(true, { semantic: true }, templateTsCache_semantic, errors => cache.templateTs_semantic = errors ?? []); } else { - await templateWorker(); + await worker(true, { syntactic: true }, scriptTsCache_syntactic, errors => cache.scriptTs_syntactic = errors ?? []); + await worker(true, { suggestion: true }, scriptTsCache_suggestion, errors => cache.scriptTs_suggestion = errors ?? []); doResponse(); - await scriptWorker(); + await worker(true, { semantic: true }, scriptTsCache_semantic, errors => cache.scriptTs_semantic = errors ?? []); } + } else { - await scriptWorker(); + await worker(true, { syntactic: true }, scriptTsCache_syntactic, errors => cache.scriptTs_syntactic = errors ?? []); + await worker(true, { suggestion: true }, scriptTsCache_suggestion, errors => cache.scriptTs_suggestion = errors ?? []); doResponse(); - await templateWorker(); + await worker(true, { semantic: true }, scriptTsCache_semantic, errors => cache.scriptTs_semantic = errors ?? []); } return getErrors(); @@ -92,23 +98,6 @@ export function register(context: LanguageServiceRuntimeContext, updateTemplateS } } - async function templateWorker() { - - await worker('template', { syntactic: true }, templateTsCache_syntactic, errors => cache.templateTs_syntactic = errors ?? []); - await worker('template', { suggestion: true }, templateTsCache_suggestion, errors => cache.templateTs_suggestion = errors ?? []); - doResponse(); - if (!await isCancel?.()) - updateTemplateScripts(); - await worker('template', { semantic: true }, templateTsCache_semantic, errors => cache.templateTs_semantic = errors ?? []); - } - - async function scriptWorker() { - await worker('script', { syntactic: true }, scriptTsCache_syntactic, errors => cache.scriptTs_syntactic = errors ?? []); - await worker('script', { suggestion: true }, scriptTsCache_suggestion, errors => cache.scriptTs_suggestion = errors ?? []); - doResponse(); - await worker('script', { semantic: true }, scriptTsCache_semantic, errors => cache.scriptTs_semantic = errors ?? []); - } - function getErrors() { return [ ...cache.nonTs, @@ -122,7 +111,7 @@ export function register(context: LanguageServiceRuntimeContext, updateTemplateS } async function worker( - lsType: 'script' | 'template' | 'nonTs', + isTs: boolean, options: { declaration?: boolean, semantic?: boolean, @@ -137,7 +126,13 @@ export function register(context: LanguageServiceRuntimeContext, updateTemplateS uri, true, function* (arg, sourceMap) { - if (sourceMap.embeddedFile.capabilities.diagnostics && sourceMap.embeddedFile.lsType === lsType) { + + const isTsFile = sourceMap.embeddedFile.fileName.endsWith('.js') || + sourceMap.embeddedFile.fileName.endsWith('.ts') || + sourceMap.embeddedFile.fileName.endsWith('.jsx') || + sourceMap.embeddedFile.fileName.endsWith('.tsx') + + if (sourceMap.embeddedFile.capabilities.diagnostics && isTsFile === isTs) { yield arg; } }, @@ -150,16 +145,11 @@ export function register(context: LanguageServiceRuntimeContext, updateTemplateS if (await isCancel?.()) return; - const _lsType = sourceMap?.embeddedFile.lsType ?? 'script'; - - if (lsType !== _lsType) - return; - const pluginCache = cacheMap.get(plugin.id) ?? cacheMap.set(plugin.id, new Map()).get(plugin.id)!; const cache = pluginCache.get(document.uri); - const tsProjectVersion = _lsType === 'nonTs' ? undefined : context.getTsLs(_lsType)?.__internal__.host.getProjectVersion?.(); + const tsProjectVersion = isTs ? undefined : context.getTsLs()?.__internal__.host.getProjectVersion?.(); - if (_lsType === 'nonTs') { + if (!isTs) { if (cache && cache.documentVersion === document.version) { return cache.errors; } @@ -225,7 +215,6 @@ export function register(context: LanguageServiceRuntimeContext, updateTemplateS for (const info of _error.relatedInformation) { for (const sourceLoc of context.vueDocuments.fromEmbeddedLocation( - sourceMap?.embeddedFile.lsType ?? 'script', info.location.uri, info.location.range.start, info.location.range.end, diff --git a/packages/vue-language-service/src/languageFeatures/workspaceSymbols.ts b/packages/vue-language-service/src/languageFeatures/workspaceSymbols.ts index 2994873a8..285599c22 100644 --- a/packages/vue-language-service/src/languageFeatures/workspaceSymbols.ts +++ b/packages/vue-language-service/src/languageFeatures/workspaceSymbols.ts @@ -6,7 +6,7 @@ export function register(context: LanguageServiceRuntimeContext) { return async (query: string) => { - const plugins = context.getPlugins('script'); + const plugins = context.getPlugins(); const symbolsList: vscode.SymbolInformation[][] = []; for (const plugin of plugins) { @@ -20,7 +20,7 @@ export function register(context: LanguageServiceRuntimeContext) { continue; const symbols = transformSymbolInformations(embeddedSymbols, loc => { - for (const vueLoc of context.vueDocuments.fromEmbeddedLocation('script', loc.uri, loc.range.start, loc.range.end)) { + for (const vueLoc of context.vueDocuments.fromEmbeddedLocation(loc.uri, loc.range.start, loc.range.end)) { return vscode.Location.create(vueLoc.uri, vueLoc.range); } }); diff --git a/packages/vue-language-service/src/languageService.ts b/packages/vue-language-service/src/languageService.ts index 59e50519c..2697f905b 100644 --- a/packages/vue-language-service/src/languageService.ts +++ b/packages/vue-language-service/src/languageService.ts @@ -110,10 +110,7 @@ export function createLanguageService( const tsSettings = getTsSettings(configurationHost); const documentContext = getDocumentContext(); - const scriptTsLs = ts2.createLanguageService(ts, tsRuntime.getTsLsHost('script'), tsRuntime.getTsLs('script'), tsSettings); - const templateTsLsRaw = tsRuntime.getTsLs('template'); - const templateTsLsHost = tsRuntime.getTsLsHost('template'); - const templateTsLs = templateTsLsHost && templateTsLsRaw ? ts2.createLanguageService(ts, templateTsLsHost, templateTsLsRaw, tsSettings) : undefined; + const tsLs = ts2.createLanguageService(ts, tsRuntime.getTsLsHost(), tsRuntime.getTsLs(), tsSettings); const blockingRequests = new Set>(); const documents = new WeakMap(); const documentVersions = new Map(); @@ -123,7 +120,7 @@ export function createLanguageService( const vuePlugin = defineLanguageServicePlugin( useVuePlugin({ getVueDocument: (document) => vueDocuments.get(document.uri), - scriptTsLs, + tsLs, }), ); const vueTemplateHtmlPlugin = _useVueTemplateLanguagePlugin( @@ -157,28 +154,23 @@ export function createLanguageService( useEmmetPlugin(), ); const scriptTsPlugin = useTsPlugins( - scriptTsLs, + tsLs, false, - { + uri => (uri.indexOf('.__VLS_template') === -1 ? { // includeCompletionsForModuleExports: true, // set in server/src/tsConfigs.ts includeCompletionsWithInsertText: true, // if missing, { 'aaa-bbb': any, ccc: any } type only has result ['ccc'] - }, - ); - const templateTsPlugin = templateTsLs ? useTsPlugins( - templateTsLs, - true, - { + } : { // includeCompletionsForModuleExports: true, // set in server/src/tsConfigs.ts includeCompletionsWithInsertText: true, // if missing, { 'aaa-bbb': any, ccc: any } type only has result ['ccc'] quotePreference: 'single', includeCompletionsForModuleExports: false, includeCompletionsForImportStatements: false, - }, - ) : undefined; + }), + ); const autoDotValuePlugin = defineLanguageServicePlugin( useAutoDotValuePlugin({ ts, - getTsLs: () => scriptTsLs, + getTsLs: () => tsLs, }), ); const referencesCodeLensPlugin = defineLanguageServicePlugin( @@ -210,7 +202,7 @@ export function createLanguageService( doValidation: async (...args) => doValidation_internal(...args), doRename: async (...args) => doRename_internal(...args), findTypeDefinition: async (...args) => findTypeDefinition_internal(...args), - scriptTsLs: scriptTsLs, + scriptTsLs: tsLs, }), ); const tagNameCasingConversionsPlugin = defineLanguageServicePlugin( @@ -237,7 +229,6 @@ export function createLanguageService( refSugarConversionsPlugin, tagNameCasingConversionsPlugin, scriptTsPlugin, - ...(templateTsPlugin ? [templateTsPlugin] : []), ]) { allPlugins.set(plugin.id, plugin); } @@ -245,33 +236,25 @@ export function createLanguageService( const stylesheetExtra = createStylesheetExtra(cssPlugin); const context: LanguageServiceRuntimeContext = { vueDocuments, - getTsLs: lsType => lsType === 'template' ? templateTsLs! : scriptTsLs, + getTsLs: () => tsLs, getTextDocument, - getPlugins: lsType => { - let plugins = [ - ...customPlugins, - vuePlugin, - cssPlugin, - vueTemplateHtmlPlugin, - vueTemplatePugPlugin, - jsonPlugin, - referencesCodeLensPlugin, - htmlPugConversionsPlugin, - scriptSetupConversionsPlugin, - refSugarConversionsPlugin, - tagNameCasingConversionsPlugin, - ]; - if (lsType === 'template' && templateTsPlugin) { - plugins.push(templateTsPlugin); - } - else if (lsType === 'script') { - plugins.push(scriptTsPlugin); - plugins.push(autoDotValuePlugin); - } + getPlugins: () => [ + ...customPlugins, + vuePlugin, + cssPlugin, + vueTemplateHtmlPlugin, + vueTemplatePugPlugin, + jsonPlugin, + referencesCodeLensPlugin, + htmlPugConversionsPlugin, + scriptSetupConversionsPlugin, + refSugarConversionsPlugin, + tagNameCasingConversionsPlugin, + scriptTsPlugin, + autoDotValuePlugin, // put emmet plugin at latest to fix https://github.com/johnsoncodehk/volar/issues/1088 - plugins.push(emmetPlugin); - return plugins; - }, + emmetPlugin, + ], getPluginById: id => allPlugins.get(id), }; const _callHierarchy = callHierarchy.register(context); @@ -413,8 +396,7 @@ export function createLanguageService( } } }, - scriptTsLs: scriptTsLs, - templateTsLs: templateTsLs, + tsLs, isSupportedDocument: (document) => document.languageId === languageId, getNameCases, getScriptContentVersion: tsRuntime.getScriptContentVersion, @@ -426,12 +408,12 @@ export function createLanguageService( }), ); } - function useTsPlugins(tsLs: ts2.LanguageService, isTemplatePlugin: boolean, baseCompletionOptions: ts.GetCompletionsAtPositionOptions) { + function useTsPlugins(tsLs: ts2.LanguageService, isTemplatePlugin: boolean, getBaseCompletionOptions: (uri: string) => ts.GetCompletionsAtPositionOptions) { const _languageSupportPlugin = defineLanguageServicePlugin( useTsPlugin({ tsVersion: ts.version, getTsLs: () => tsLs, - baseCompletionOptions, + getBaseCompletionOptions, }), ); const languageSupportPlugin: LanguageServicePlugin = isTemplatePlugin ? { @@ -468,7 +450,7 @@ export function createLanguageService( } for (const sourceMap of vueDocument.getSourceMaps()) { - if (sourceMap.embeddedFile.lsType === 'template') { + if (sourceMap.embeddedFile.fileName.indexOf('.__VLS_template.') >= 0) { for (const _ of sourceMap.getMappedRanges(pos, pos, data => data.vueTag === 'template' || data.vueTag === 'style' // handle CSS variable injection to fix https://github.com/johnsoncodehk/volar/issues/777 diff --git a/packages/vue-language-service/src/stylesheetExtra.ts b/packages/vue-language-service/src/stylesheetExtra.ts index 486824fde..37997a32a 100644 --- a/packages/vue-language-service/src/stylesheetExtra.ts +++ b/packages/vue-language-service/src/stylesheetExtra.ts @@ -23,9 +23,9 @@ export function createStylesheetExtra(cssPlugin: ReturnType if (!document) { const uri = shared.fsPathToUri(embeddedFile.fileName); - const newVersion = (embeddedDocumentVersions.get(embeddedFile.lsType + ':' + uri.toLowerCase()) ?? 0) + 1; + const newVersion = (embeddedDocumentVersions.get(uri.toLowerCase()) ?? 0) + 1; - embeddedDocumentVersions.set(embeddedFile.lsType + ':' + uri.toLowerCase(), newVersion); + embeddedDocumentVersions.set(uri.toLowerCase(), newVersion); document = TextDocument.create( uri, diff --git a/packages/vue-language-service/src/types.ts b/packages/vue-language-service/src/types.ts index c1604d737..5af143834 100644 --- a/packages/vue-language-service/src/types.ts +++ b/packages/vue-language-service/src/types.ts @@ -17,7 +17,7 @@ export type DocumentServiceRuntimeContext = { export type LanguageServiceRuntimeContext = { vueDocuments: VueDocuments, getTextDocument(uri: string): TextDocument | undefined, - getPlugins(lsType: 'template' | 'script' | 'nonTs'): LanguageServicePlugin[], + getPlugins(): LanguageServicePlugin[], getPluginById(id: number): LanguageServicePlugin | undefined, - getTsLs: (lsType: T) => T extends 'script' ? ts2.LanguageService : (ts2.LanguageService | undefined); + getTsLs(): ts2.LanguageService; } diff --git a/packages/vue-language-service/src/utils/featureWorkers.ts b/packages/vue-language-service/src/utils/featureWorkers.ts index 161f16641..e8f55c61f 100644 --- a/packages/vue-language-service/src/utils/featureWorkers.ts +++ b/packages/vue-language-service/src/utils/featureWorkers.ts @@ -133,7 +133,7 @@ export async function languageFeatureWorker( await visitEmbedded(vueDocument, embeddeds, async sourceMap => { - const plugins = context.getPlugins(sourceMap.embeddedFile.lsType); + const plugins = context.getPlugins(); for (const mappedArg of transformArg(arg, sourceMap)) { @@ -168,7 +168,7 @@ export async function languageFeatureWorker( if (document && (results.length === 0 || !!combineResult)) { - const plugins = context.getPlugins('script'); + const plugins = context.getPlugins(); for (const plugin of plugins) { diff --git a/packages/vue-language-service/src/vueDocuments.ts b/packages/vue-language-service/src/vueDocuments.ts index f530b5949..eae4196f8 100644 --- a/packages/vue-language-service/src/vueDocuments.ts +++ b/packages/vue-language-service/src/vueDocuments.ts @@ -113,30 +113,22 @@ export function parseVueDocuments(vueFiles: VueFiles) { return map; }); const embeddedDocumentsMapLsType = computed(() => { - const maps = { - nonTs: new Map(), - script: new Map(), - template: new Map(), - }; + const map = new Map(); for (const vueDocument of getAll()) { for (const sourceMap of vueDocument.refs.sourceMaps.value) { - maps[sourceMap.embeddedFile.lsType].set(sourceMap.mappedDocument.uri, sourceMap); + map.set(sourceMap.mappedDocument.uri, sourceMap); } } - return maps; + return map; }); const teleportsMapLsType = computed(() => { - const maps = { - nonTs: new Map(), - script: new Map(), - template: new Map(), - }; + const map = new Map(); for (const vueDocument of getAll()) { for (const teleport of vueDocument.refs.teleports.value) { - maps[teleport.embeddedFile.lsType].set(teleport.mappedDocument.uri, teleport); + map.set(teleport.mappedDocument.uri, teleport); } } - return maps; + return map; }); return { @@ -153,14 +145,13 @@ export function parseVueDocuments(vueFiles: VueFiles) { fromEmbeddedDocument: untrack((document: TextDocument) => { return embeddedDocumentsMap.value.get(document); }), - sourceMapFromEmbeddedDocumentUri: untrack((lsType: 'script' | 'template' | 'nonTs', uri: string) => { - return embeddedDocumentsMapLsType.value[lsType].get(uri); + sourceMapFromEmbeddedDocumentUri: untrack((uri: string) => { + return embeddedDocumentsMapLsType.value.get(uri); }), - teleportfromEmbeddedDocumentUri: untrack((lsType: 'script' | 'template' | 'nonTs', uri: string) => { - return teleportsMapLsType.value[lsType].get(uri); + teleportfromEmbeddedDocumentUri: untrack((uri: string) => { + return teleportsMapLsType.value.get(uri); }), fromEmbeddedLocation: untrack(function* ( - lsType: 'script' | 'template' | 'nonTs', uri: string, start: vscode.Position, end?: vscode.Position, @@ -174,7 +165,7 @@ export function parseVueDocuments(vueFiles: VueFiles) { if (end === undefined) end = start; - const sourceMap = embeddedDocumentsMapLsType.value[lsType].get(uri); + const sourceMap = embeddedDocumentsMapLsType.value.get(uri); if (sourceMap) { @@ -215,9 +206,9 @@ export function parseVueDocument(vueFile: VueFile) { const embeddedDocumentsMap = useCacheMap(embeddedFile => { const uri = shared.fsPathToUri(embeddedFile.fileName); - const newVersion = (embeddedDocumentVersions.get(embeddedFile.lsType + ':' + uri.toLowerCase()) ?? 0) + 1; + const newVersion = (embeddedDocumentVersions.get(uri.toLowerCase()) ?? 0) + 1; - embeddedDocumentVersions.set(embeddedFile.lsType + ':' + uri.toLowerCase(), newVersion); + embeddedDocumentVersions.set(uri.toLowerCase(), newVersion); return TextDocument.create( uri, diff --git a/packages/vue-language-service/src/vuePlugins/vue.ts b/packages/vue-language-service/src/vuePlugins/vue.ts index 4c649e7a9..842a84a18 100644 --- a/packages/vue-language-service/src/vuePlugins/vue.ts +++ b/packages/vue-language-service/src/vuePlugins/vue.ts @@ -94,7 +94,7 @@ const dataProvider = html.newHTMLDataProvider('vue', { export default function (options: { getVueDocument(document: TextDocument): VueDocument | undefined, - scriptTsLs: ts2.LanguageService | undefined, + tsLs: ts2.LanguageService | undefined, }): EmbeddedLanguageServicePlugin { const htmlPlugin = useHtmlPlugin({ @@ -129,7 +129,7 @@ export default function (options: { } } - if (options.scriptTsLs && !options.scriptTsLs.__internal__.isValidFile(vueDocument.file.getScriptTsFile().fileName)) { + if (options.tsLs && !options.tsLs.__internal__.isValidFile(vueDocument.file.getScriptTsFile().fileName)) { for (const script of [sfc.script, sfc.scriptSetup]) { if (!script || script.content === '') diff --git a/packages/vue-language-service/src/vuePlugins/vueTemplateLanguage.ts b/packages/vue-language-service/src/vuePlugins/vueTemplateLanguage.ts index eda694a2b..5f345cc4f 100644 --- a/packages/vue-language-service/src/vuePlugins/vueTemplateLanguage.ts +++ b/packages/vue-language-service/src/vuePlugins/vueTemplateLanguage.ts @@ -60,8 +60,7 @@ export default function >(options: { ts: typeof import('typescript/lib/tsserverlibrary'), getSemanticTokenLegend(): vscode.SemanticTokensLegend, getScanner(document: TextDocument): html.Scanner | undefined, - scriptTsLs: ts2.LanguageService, - templateTsLs: ts2.LanguageService | undefined, + tsLs: ts2.LanguageService, templateLanguagePlugin: T, isSupportedDocument: (document: TextDocument) => boolean, getNameCases?: (uri: string) => Promise<{ @@ -411,7 +410,7 @@ export default function >(options: { options.tsSettings.getFormatOptions?.(embeddedScriptDocument) ?? {}, options.tsSettings.getPreferences?.(embeddedScriptDocument) ?? {}, ]); - const tsDetail = options.scriptTsLs.__internal__.raw.getCompletionEntryDetails(shared.uriToFsPath(embeddedScriptDocument.uri), 0, tsImportName, formatOptions, importFile, preferences, undefined); + const tsDetail = options.tsLs.__internal__.raw.getCompletionEntryDetails(shared.uriToFsPath(embeddedScriptDocument.uri), 0, tsImportName, formatOptions, importFile, preferences, undefined); if (tsDetail?.codeActions) { for (const action of tsDetail.codeActions) { for (const change of action.changes) { @@ -756,9 +755,6 @@ export default function >(options: { const result = new Map(); - if (!options.templateTsLs) - return result; - { // watching projectVersion.value; usedTags.value; @@ -791,7 +787,7 @@ export default function >(options: { let offset = file.content.indexOf(searchText); if (offset >= 0) { offset += searchText.length; - bind = options.tsRuntime.getTsLs('template')?.getCompletionsAtPosition(file.fileName, offset, undefined)?.entries ?? []; + bind = options.tsRuntime.getTsLs()?.getCompletionsAtPosition(file.fileName, offset, undefined)?.entries ?? []; } } { @@ -799,12 +795,12 @@ export default function >(options: { let offset = file.content.indexOf(searchText); if (offset >= 0) { offset += searchText.length; - on = options.tsRuntime.getTsLs('template')?.getCompletionsAtPosition(file.fileName, offset, undefined)?.entries ?? []; + on = options.tsRuntime.getTsLs()?.getCompletionsAtPosition(file.fileName, offset, undefined)?.entries ?? []; } } result.set(tag.name, { item: tag.item, bind, on }); } - const globalBind = options.tsRuntime.getTsLs('template')?.getCompletionsAtPosition(entryFile.fileName, entryFile.content.indexOf(SearchTexts.GlobalAttrs), undefined)?.entries ?? []; + const globalBind = options.tsRuntime.getTsLs()?.getCompletionsAtPosition(entryFile.fileName, entryFile.content.indexOf(SearchTexts.GlobalAttrs), undefined)?.entries ?? []; result.set('*', { item: undefined, bind: globalBind, on: [] }); } return result; diff --git a/packages/vue-language-service/testCases/renames/emit_from.vue b/packages/vue-language-service/testCases/renames/emit_from.vue deleted file mode 100644 index 6ad590733..000000000 --- a/packages/vue-language-service/testCases/renames/emit_from.vue +++ /dev/null @@ -1,3 +0,0 @@ - \ No newline at end of file diff --git a/packages/vue-language-service/testCases/renames/emit_to.vue b/packages/vue-language-service/testCases/renames/emit_to.vue deleted file mode 100644 index 25a895d00..000000000 --- a/packages/vue-language-service/testCases/renames/emit_to.vue +++ /dev/null @@ -1,8 +0,0 @@ - - - \ No newline at end of file diff --git a/packages/vue-language-service/testCases/tsconfig.json b/packages/vue-language-service/testCases/tsconfig.json index 61f9d6f82..e101eadf7 100644 --- a/packages/vue-language-service/testCases/tsconfig.json +++ b/packages/vue-language-service/testCases/tsconfig.json @@ -9,5 +9,6 @@ "noUncheckedIndexedAccess": true, "noUnusedLocals": true, "noUnusedParameters": true, + "jsx": "preserve", } } diff --git a/packages/vue-language-service/tests/index.spec.ts b/packages/vue-language-service/tests/index.spec.ts index 4736899cb..67b2d492f 100644 --- a/packages/vue-language-service/tests/index.spec.ts +++ b/packages/vue-language-service/tests/index.spec.ts @@ -1,4 +1,3 @@ -import './renames/emit'; import './renames/prop'; import './renames/typeProp'; import './renames/cssModules'; diff --git a/packages/vue-language-service/tests/renames/emit.ts b/packages/vue-language-service/tests/renames/emit.ts deleted file mode 100644 index ea1ced830..000000000 --- a/packages/vue-language-service/tests/renames/emit.ts +++ /dev/null @@ -1,51 +0,0 @@ -import * as path from 'upath'; -import { Position } from 'vscode-languageserver-protocol'; -import { defineRename } from '../utils/defineRename'; - -const file_from = path.resolve(__dirname, '../../testCases/renames/emit_from.vue'); -const file_to = path.resolve(__dirname, '../../testCases/renames/emit_to.vue'); -const fileResult_from = ` - -`.trim(); -const fileResult_to = ` - - - -`.trim(); - -defineRename({ - fileName: file_from, - position: Position.create(1, 14), - newName: 'barFoo', - length: 6, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); - -defineRename({ - fileName: file_to, - position: Position.create(1, 9), - newName: 'bar-foo', - length: 7, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); - -defineRename({ - fileName: file_to, - position: Position.create(2, 9), - newName: 'barFoo', - length: 6, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); diff --git a/packages/vue-language-service/tests/renames/prop.ts b/packages/vue-language-service/tests/renames/prop.ts index e9ec445e9..cfd583fb9 100644 --- a/packages/vue-language-service/tests/renames/prop.ts +++ b/packages/vue-language-service/tests/renames/prop.ts @@ -22,15 +22,15 @@ import Comp from './prop_from.vue'; `.trim(); -defineRename({ - fileName: file_from, - position: Position.create(0, 13), - newName: 'barFoo', - length: 6, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); +// defineRename({ +// fileName: file_from, +// position: Position.create(0, 13), +// newName: 'barFoo', +// length: 6, +// }, { +// [file_from]: fileResult_from, +// [file_to]: fileResult_to, +// }); defineRename({ fileName: file_from, @@ -42,22 +42,22 @@ defineRename({ [file_to]: fileResult_to, }); -defineRename({ - fileName: file_to, - position: Position.create(1, 9), - newName: 'bar-foo', - length: 7, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); +// defineRename({ +// fileName: file_to, +// position: Position.create(1, 9), +// newName: 'bar-foo', +// length: 7, +// }, { +// [file_from]: fileResult_from, +// [file_to]: fileResult_to, +// }); -defineRename({ - fileName: file_to, - position: Position.create(2, 9), - newName: 'barFoo', - length: 6, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); +// defineRename({ +// fileName: file_to, +// position: Position.create(2, 9), +// newName: 'barFoo', +// length: 6, +// }, { +// [file_from]: fileResult_from, +// [file_to]: fileResult_to, +// }); diff --git a/packages/vue-language-service/tests/renames/typeProp.ts b/packages/vue-language-service/tests/renames/typeProp.ts index 1e0caf9f0..b75e15c49 100644 --- a/packages/vue-language-service/tests/renames/typeProp.ts +++ b/packages/vue-language-service/tests/renames/typeProp.ts @@ -22,15 +22,15 @@ import Comp from './typeProp_from.vue'; `.trim(); -defineRename({ - fileName: file_from, - position: vscode.Position.create(0, 13), - newName: 'barFoo', - length: 6, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); +// defineRename({ +// fileName: file_from, +// position: vscode.Position.create(0, 13), +// newName: 'barFoo', +// length: 6, +// }, { +// [file_from]: fileResult_from, +// [file_to]: fileResult_to, +// }); defineRename({ fileName: file_from, @@ -42,22 +42,22 @@ defineRename({ [file_to]: fileResult_to, }); -defineRename({ - fileName: file_to, - position: vscode.Position.create(1, 9), - newName: 'bar-foo', - length: 7, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); +// defineRename({ +// fileName: file_to, +// position: vscode.Position.create(1, 9), +// newName: 'bar-foo', +// length: 7, +// }, { +// [file_from]: fileResult_from, +// [file_to]: fileResult_to, +// }); -defineRename({ - fileName: file_to, - position: vscode.Position.create(2, 9), - newName: 'barFoo', - length: 6, -}, { - [file_from]: fileResult_from, - [file_to]: fileResult_to, -}); +// defineRename({ +// fileName: file_to, +// position: vscode.Position.create(2, 9), +// newName: 'barFoo', +// length: 6, +// }, { +// [file_from]: fileResult_from, +// [file_to]: fileResult_to, +// }); diff --git a/packages/vue-tsc/src/apis.ts b/packages/vue-tsc/src/apis.ts index 6c5adcb8c..53c0d6517 100644 --- a/packages/vue-tsc/src/apis.ts +++ b/packages/vue-tsc/src/apis.ts @@ -1,8 +1,6 @@ import type * as ts from 'typescript/lib/tsserverlibrary'; import type { TypeScriptRuntime } from '@volar/vue-typescript'; -const lsTypes = ['script', 'template'] as const; - export function register( ts: typeof import('typescript/lib/tsserverlibrary'), context: TypeScriptRuntime, @@ -18,11 +16,7 @@ export function register( }; function getRootFileNames() { - const set = new Set([ - ...getProgram('script')?.getRootFileNames().filter(fileName => context.getTsLsHost('script').fileExists?.(fileName)) ?? [], - ...getProgram('template')?.getRootFileNames().filter(fileName => context.getTsLsHost('template')?.fileExists?.(fileName)) ?? [], - ]); - return [...set.values()]; + return getProgram()?.getRootFileNames().filter(fileName => context.getTsLsHost().fileExists?.(fileName)); } // for vue-tsc --noEmit --watch @@ -46,7 +40,7 @@ export function register( if (sourceFile) { - const mapped = context.vueFiles.fromEmbeddedFileName('script', sourceFile.fileName); + const mapped = context.vueFiles.fromEmbeddedFileName(sourceFile.fileName); if (mapped) { @@ -56,15 +50,20 @@ export function register( for (const embedded of embeddeds) { - if (embedded.file.lsType === 'nonTs' || !embedded.file.capabilities.diagnostics) + const isTsFile = embedded.file.fileName.endsWith('.js') || + embedded.file.fileName.endsWith('.ts') || + embedded.file.fileName.endsWith('.jsx') || + embedded.file.fileName.endsWith('.tsx') + + if (!isTsFile || !embedded.file.capabilities.diagnostics) continue; - const program = getProgram(embedded.file.lsType); + const program = getProgram(); const embeddedSourceFile = program?.getSourceFile(embedded.file.fileName); if (embeddedSourceFile) { - const errors = transformDiagnostics(embedded.file.lsType, program?.[api](embeddedSourceFile, cancellationToken) ?? []); + const errors = transformDiagnostics(program?.[api](embeddedSourceFile, cancellationToken) ?? []); results = results.concat(errors); } } @@ -72,34 +71,30 @@ export function register( return results; } else { - return getProgram('script')?.[api](sourceFile, cancellationToken) ?? []; + return getProgram()?.[api](sourceFile, cancellationToken) ?? []; } } - return lsTypes.map(lsType => transformDiagnostics(lsType, getProgram(lsType)?.[api](sourceFile, cancellationToken) ?? [])).flat(); + return transformDiagnostics(getProgram()?.[api](sourceFile, cancellationToken) ?? []); } function getGlobalDiagnostics(cancellationToken?: ts.CancellationToken): readonly ts.Diagnostic[] { - return lsTypes.map(lsType => transformDiagnostics(lsType, getProgram(lsType)?.getGlobalDiagnostics(cancellationToken) ?? [])).flat(); + return transformDiagnostics(getProgram()?.getGlobalDiagnostics(cancellationToken) ?? []); } function emit(targetSourceFile?: ts.SourceFile, _writeFile?: ts.WriteFileCallback, cancellationToken?: ts.CancellationToken, emitOnlyDtsFiles?: boolean, customTransformers?: ts.CustomTransformers): ts.EmitResult { - const scriptResult = getProgram('script')!.emit(targetSourceFile, (context.vueLsHost.writeFile ?? ts.sys.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers); - const templateResult = getProgram('template')?.emit(targetSourceFile, undefined, cancellationToken, emitOnlyDtsFiles, customTransformers); + const scriptResult = getProgram()!.emit(targetSourceFile, (context.vueLsHost.writeFile ?? ts.sys.writeFile), cancellationToken, emitOnlyDtsFiles, customTransformers); return { emitSkipped: scriptResult.emitSkipped, emittedFiles: scriptResult.emittedFiles, - diagnostics: [ - ...transformDiagnostics('script', scriptResult.diagnostics), - ...transformDiagnostics('template', templateResult?.diagnostics ?? []), - ], + diagnostics: transformDiagnostics(scriptResult.diagnostics), }; } - function getProgram(lsType: 'script' | 'template') { - return context.getTsLs(lsType)?.getProgram(); + function getProgram() { + return context.getTsLs()?.getProgram(); } // transform - function transformDiagnostics(lsType: 'script' | 'template', diagnostics: readonly T[]): T[] { + function transformDiagnostics(diagnostics: readonly T[]): T[] { const result: T[] = []; for (const diagnostic of diagnostics) { if ( @@ -108,7 +103,6 @@ export function register( && diagnostic.length !== undefined ) { for (const tsOrVueLoc of context.vueFiles.fromEmbeddedLocation( - lsType, diagnostic.file.fileName, diagnostic.start, diagnostic.start + diagnostic.length, @@ -118,9 +112,6 @@ export function register( if (!context.vueLsHost.fileExists?.(tsOrVueLoc.fileName)) continue; - if (!tsOrVueLoc.mapped && lsType !== 'script') - continue; - let file = tsOrVueLoc.fileName === diagnostic.file.fileName ? diagnostic.file : undefined; @@ -146,7 +137,7 @@ export function register( }; const relatedInformation = (diagnostic as ts.Diagnostic).relatedInformation; if (relatedInformation) { - (newDiagnostic as ts.Diagnostic).relatedInformation = transformDiagnostics(lsType, relatedInformation); + (newDiagnostic as ts.Diagnostic).relatedInformation = transformDiagnostics(relatedInformation); } result.push(newDiagnostic); } diff --git a/packages/vue-tsc/src/proxy.ts b/packages/vue-tsc/src/proxy.ts index 7a306cf3e..d20482c7d 100644 --- a/packages/vue-tsc/src/proxy.ts +++ b/packages/vue-tsc/src/proxy.ts @@ -60,7 +60,7 @@ export function createProgramProxy( }); tsRuntime.update(true); // must update before getProgram() to update virtual scripts - const tsProgram = tsRuntime.getTsLs('script').getProgram(); + const tsProgram = tsRuntime.getTsLs().getProgram(); if (!tsProgram) throw '!tsProgram'; diff --git a/packages/vue-typescript/src/typescriptRuntime.ts b/packages/vue-typescript/src/typescriptRuntime.ts index 7d2d556ed..56bf81d6e 100644 --- a/packages/vue-typescript/src/typescriptRuntime.ts +++ b/packages/vue-typescript/src/typescriptRuntime.ts @@ -35,8 +35,7 @@ export function createTypeScriptRuntime(options: { let vueProjectVersion: string | undefined; let scriptContentVersion = 0; // only update by `