From 2bcd145a913c3802ea92241f2c432b52ae57acae Mon Sep 17 00:00:00 2001 From: Johnson Chu Date: Wed, 13 Dec 2023 07:56:00 +0800 Subject: [PATCH] refactor(tsc): rework based on first-party TS API (#3795) --- extensions/vscode/src/common.ts | 10 +- extensions/vscode/src/nodeClientMain.ts | 7 +- package.json | 2 +- packages/component-meta/src/base.ts | 4 +- packages/language-core/package.json | 2 +- .../language-core/src/generators/script.ts | 4 +- .../language-core/src/generators/template.ts | 12 +- .../language-core/src/parsers/scriptRanges.ts | 20 +- .../src/parsers/scriptSetupRanges.ts | 61 +++--- packages/language-core/src/plugins/vue-tsx.ts | 2 +- packages/language-core/src/utils/transform.ts | 54 ++--- .../src/virtualFile/computedFiles.ts | 6 +- .../src/virtualFile/computedSfc.ts | 4 +- .../src/virtualFile/embeddedFile.ts | 2 +- packages/language-plugin-pug/package.json | 4 +- packages/language-service/package.json | 24 +-- .../src/plugins/vue-codelens-references.ts | 33 --- packages/language-service/tests/reference.ts | 1 + packages/tsc/bin/vue-tsc.js | 58 +---- packages/tsc/src/index.ts | 158 ++------------ packages/tsc/tests/dts.spec.ts | 41 ++-- packages/typescript-plugin/package.json | 2 +- packages/typescript-plugin/src/index.ts | 110 +++------- pnpm-lock.yaml | 201 +++++++++--------- test-workspace/tsc/petite-vue/tsconfig.json | 6 - 25 files changed, 287 insertions(+), 541 deletions(-) delete mode 100644 test-workspace/tsc/petite-vue/tsconfig.json diff --git a/extensions/vscode/src/common.ts b/extensions/vscode/src/common.ts index ada23373dc..632c8f2bc6 100644 --- a/extensions/vscode/src/common.ts +++ b/extensions/vscode/src/common.ts @@ -70,14 +70,6 @@ async function doActivate(context: vscode.ExtensionContext, createLc: CreateLang // doctor.register(context, client); // componentMeta.register(context, client); - const supportedLanguages: Record = { - vue: true, - markdown: true, - javascript: true, - typescript: true, - javascriptreact: true, - typescriptreact: true, - }; const selectors: vscode.DocumentFilter[] = [{ language: 'vue' }]; if (config.server.petiteVue.supportHtmlFile) { @@ -87,7 +79,7 @@ async function doActivate(context: vscode.ExtensionContext, createLc: CreateLang selectors.push({ language: 'markdown' }); } - activateAutoInsertion([client], document => supportedLanguages[document.languageId]); // TODO: implement auto insert .value + activateAutoInsertion(selectors, client); // TODO: implement auto insert .value activateDocumentDropEdit(selectors, client); activateWriteVirtualFiles('volar.action.writeVirtualFiles', client); diff --git a/extensions/vscode/src/nodeClientMain.ts b/extensions/vscode/src/nodeClientMain.ts index 0042d5dd84..1324fb05b1 100644 --- a/extensions/vscode/src/nodeClientMain.ts +++ b/extensions/vscode/src/nodeClientMain.ts @@ -9,8 +9,7 @@ import * as fs from 'fs'; export async function activate(context: vscode.ExtensionContext) { - const languageClients: lsp.LanguageClient[] = []; - + let languageClient: lsp.LanguageClient; let serverPathStatusItem: vscode.StatusBarItem | undefined; await commonActivate(context, ( @@ -110,7 +109,7 @@ export async function activate(context: vscode.ExtensionContext) { ); client.start(); - languageClients.push(client); + languageClient = client; updateProviders(client); @@ -149,7 +148,7 @@ export async function activate(context: vscode.ExtensionContext) { volarLabs: { version: supportLabsVersion, codegenStackSupport: true, - languageClients, + languageClient: languageClient!, languageServerProtocol: serverLib, }, } satisfies ExportsInfoForLabs; diff --git a/package.json b/package.json index c39817dd6e..57ef793d9b 100644 --- a/package.json +++ b/package.json @@ -19,7 +19,7 @@ "devDependencies": { "@lerna-lite/cli": "latest", "@lerna-lite/publish": "latest", - "@volar/language-service": "2.0.0-alpha.3", + "@volar/language-service": "2.0.0-alpha.4", "typescript": "latest", "vite": "latest", "vitest": "latest" diff --git a/packages/component-meta/src/base.ts b/packages/component-meta/src/base.ts index 0722227766..e4524185d6 100644 --- a/packages/component-meta/src/base.ts +++ b/packages/component-meta/src/base.ts @@ -3,7 +3,7 @@ import type * as ts from 'typescript/lib/tsserverlibrary'; import * as path from 'path-browserify'; import { code as typeHelpersCode } from 'vue-component-type-helpers'; import { code as vue2TypeHelpersCode } from 'vue-component-type-helpers/vue2'; -import { createLanguage, decorateLanguageService } from '@volar/typescript'; +import { createLanguage } from '@volar/typescript'; import type { MetaCheckerOptions, @@ -164,8 +164,6 @@ export function baseCreate( const { languageServiceHost } = language.typescript!; const tsLs = ts.createLanguageService(languageServiceHost); - decorateLanguageService(language.files, tsLs, false); - if (checkerOptions.forceUseTs) { const getScriptKind = languageServiceHost.getScriptKind?.bind(languageServiceHost); languageServiceHost.getScriptKind = (fileName) => { diff --git a/packages/language-core/package.json b/packages/language-core/package.json index 0407ad5e70..4c34605f8e 100644 --- a/packages/language-core/package.json +++ b/packages/language-core/package.json @@ -13,7 +13,7 @@ "directory": "packages/language-core" }, "dependencies": { - "@volar/language-core": "2.0.0-alpha.3", + "@volar/language-core": "2.0.0-alpha.4", "@vue/compiler-dom": "^3.3.0", "@vue/shared": "^3.3.0", "computeds": "^0.0.1", diff --git a/packages/language-core/src/generators/script.ts b/packages/language-core/src/generators/script.ts index ed53072f0c..5dafc4b0d4 100644 --- a/packages/language-core/src/generators/script.ts +++ b/packages/language-core/src/generators/script.ts @@ -45,7 +45,7 @@ export function* generate( generic: undefined, genericOffset: 0, attrs: {}, - ast: ts.createSourceFile('', '', ts.ScriptTarget.Latest, false, ts.ScriptKind.TS), + ast: ts.createSourceFile('', '', 99 satisfies ts.ScriptTarget.Latest, false, ts.ScriptKind.TS), }; scriptSetupRanges = { bindings: [], @@ -1013,7 +1013,7 @@ type __VLS_NormalizeEmits = __VLS_Prettify< for (const [segment, offset, onlyError] of eachInterpolationSegment( ts, cssBind.text, - ts.createSourceFile('/a.txt', cssBind.text, ts.ScriptTarget.ESNext), + ts.createSourceFile('/a.txt', cssBind.text, 99 satisfies ts.ScriptTarget.ESNext), emptyLocalVars, cssIds, vueCompilerOptions, diff --git a/packages/language-core/src/generators/template.ts b/packages/language-core/src/generators/template.ts index 973cb321b6..48a91048ef 100644 --- a/packages/language-core/src/generators/template.ts +++ b/packages/language-core/src/generators/template.ts @@ -575,7 +575,7 @@ export function* generate( if (leftExpressionRange && leftExpressionText) { const collectAst = createTsAst(node.parseResult, `const [${leftExpressionText}]`); - collectVars(ts, collectAst, forBlockVars); + collectVars(ts, collectAst, collectAst, forBlockVars); for (const varName of forBlockVars) localVars.set(varName, (localVars.get(varName) ?? 0) + 1); @@ -871,7 +871,7 @@ export function* generate( ); const slotAst = createTsAst(slotDir, `(${slotDir.exp.content}) => {}`); - collectVars(ts, slotAst, slotBlockVars); + collectVars(ts, slotAst, slotAst, slotBlockVars); hasProps = true; if (slotDir.exp.content.indexOf(':') === -1) { yield _ts('const ['); @@ -1093,10 +1093,10 @@ export function* generate( const ast = createTsAst(prop.exp, prop.exp.content); let isCompoundExpression = true; - if (ast.getChildCount() === 2) { // with EOF - ast.forEachChild(child_1 => { + if (ast.statements.length === 1) { + ts.forEachChild(ast, child_1 => { if (ts.isExpressionStatement(child_1)) { - child_1.forEachChild(child_2 => { + ts.forEachChild(child_1, child_2 => { if (ts.isArrowFunction(child_2)) { isCompoundExpression = false; } @@ -1902,7 +1902,7 @@ export function* generate( function createTsAst(astHolder: any, text: string) { if (astHolder.__volar_ast_text !== text) { astHolder.__volar_ast_text = text; - astHolder.__volar_ast = ts.createSourceFile('/a.ts', text, ts.ScriptTarget.ESNext); + astHolder.__volar_ast = ts.createSourceFile('/a.ts', text, 99 satisfies ts.ScriptTarget.ESNext); } return astHolder.__volar_ast as ts.SourceFile; } diff --git a/packages/language-core/src/parsers/scriptRanges.ts b/packages/language-core/src/parsers/scriptRanges.ts index e8331b2d13..1c8ba7a0e8 100644 --- a/packages/language-core/src/parsers/scriptRanges.ts +++ b/packages/language-core/src/parsers/scriptRanges.ts @@ -1,6 +1,6 @@ import type { TextRange } from '../types'; import type * as ts from 'typescript/lib/tsserverlibrary'; -import { getStartEnd, parseBindingRanges } from './scriptSetupRanges'; +import { getNodeText, getStartEnd, parseBindingRanges } from './scriptSetupRanges'; export interface ScriptRanges extends ReturnType { } @@ -17,12 +17,12 @@ export function parseScriptRanges(ts: typeof import('typescript/lib/tsserverlibr const bindings = hasScriptSetup ? parseBindingRanges(ts, ast) : []; - ast.forEachChild(raw => { + ts.forEachChild(ast, raw => { if (ts.isExportAssignment(raw)) { let node: ts.AsExpression | ts.ExportAssignment | ts.ParenthesizedExpression = raw; - while (ts.isAsExpression(node.expression) || ts.isParenthesizedExpression(node.expression)) { // fix https://github.com/vuejs/language-tools/issues/1882 + while (isAsExpression(node.expression) || ts.isParenthesizedExpression(node.expression)) { // fix https://github.com/vuejs/language-tools/issues/1882 node = node.expression; } @@ -39,12 +39,13 @@ export function parseScriptRanges(ts: typeof import('typescript/lib/tsserverlibr if (obj) { let componentsOptionNode: ts.ObjectLiteralExpression | undefined; let nameOptionNode: ts.Expression | undefined; - obj.forEachChild(node => { + ts.forEachChild(obj, node => { if (ts.isPropertyAssignment(node) && ts.isIdentifier(node.name)) { - if (node.name.escapedText === 'components' && ts.isObjectLiteralExpression(node.initializer)) { + const name = getNodeText(ts, node.name, ast); + if (name === 'components' && ts.isObjectLiteralExpression(node.initializer)) { componentsOptionNode = node.initializer; } - if (node.name.escapedText === 'name') { + if (name === 'name') { nameOptionNode = node.initializer; } } @@ -68,6 +69,11 @@ export function parseScriptRanges(ts: typeof import('typescript/lib/tsserverlibr }; function _getStartEnd(node: ts.Node) { - return getStartEnd(node, ast); + return getStartEnd(ts, node, ast); + } + + // isAsExpression is missing in tsc + function isAsExpression(node: ts.Node): node is ts.AsExpression { + return node.kind === ts.SyntaxKind.AsExpression; } } diff --git a/packages/language-core/src/parsers/scriptSetupRanges.ts b/packages/language-core/src/parsers/scriptSetupRanges.ts index a5a1e97228..8aded9fd62 100644 --- a/packages/language-core/src/parsers/scriptSetupRanges.ts +++ b/packages/language-core/src/parsers/scriptSetupRanges.ts @@ -34,8 +34,8 @@ export function parseScriptSetupRanges( define?: ReturnType; } = {}; - const definePropProposalA = vueCompilerOptions.experimentalDefinePropProposal === 'kevinEdition' || ast.getFullText().trimStart().startsWith('// @experimentalDefinePropProposal=kevinEdition'); - const definePropProposalB = vueCompilerOptions.experimentalDefinePropProposal === 'johnsonEdition' || ast.getFullText().trimStart().startsWith('// @experimentalDefinePropProposal=johnsonEdition'); + const definePropProposalA = vueCompilerOptions.experimentalDefinePropProposal === 'kevinEdition' || ast.text.trimStart().startsWith('// @experimentalDefinePropProposal=kevinEdition'); + const definePropProposalB = vueCompilerOptions.experimentalDefinePropProposal === 'johnsonEdition' || ast.text.trimStart().startsWith('// @experimentalDefinePropProposal=johnsonEdition'); const defineProp: { name: TextRange | undefined; nameIsString: boolean; @@ -44,10 +44,10 @@ export function parseScriptSetupRanges( required: boolean; }[] = []; const bindings = parseBindingRanges(ts, ast); - const text = ast.getFullText(); + const text = ast.text; const leadingCommentEndOffset = ts.getLeadingCommentRanges(text, 0)?.reverse()[0].end ?? 0; - ast.forEachChild(node => { + ts.forEachChild(ast, node => { const isTypeExport = (ts.isTypeAliasDeclaration(node) || ts.isInterfaceDeclaration(node)) && node.modifiers?.some(mod => mod.kind === ts.SyntaxKind.ExportKeyword); if ( !foundNonImportExportNode @@ -57,18 +57,18 @@ export function parseScriptSetupRanges( // fix https://github.com/vuejs/language-tools/issues/1223 && !ts.isImportEqualsDeclaration(node) ) { - const commentRanges = ts.getLeadingCommentRanges(text, node.getFullStart()); + const commentRanges = ts.getLeadingCommentRanges(text, node.pos); if (commentRanges?.length) { const commentRange = commentRanges.sort((a, b) => a.pos - b.pos)[0]; importSectionEndOffset = commentRange.pos; } else { - importSectionEndOffset = node.getStart(ast); + importSectionEndOffset = getStartEnd(ts, node, ast).start; } foundNonImportExportNode = true; } }); - ast.forEachChild(child => visitNode(child, [ast])); + ts.forEachChild(ast, child => visitNode(child, [ast])); return { leadingCommentEndOffset, @@ -82,7 +82,7 @@ export function parseScriptSetupRanges( }; function _getStartEnd(node: ts.Node) { - return getStartEnd(node, ast); + return getStartEnd(ts, node, ast); } function parseDefineFunction(node: ts.CallExpression): TextRange & { @@ -102,7 +102,7 @@ export function parseScriptSetupRanges( ts.isCallExpression(node) && ts.isIdentifier(node.expression) ) { - const callText = node.expression.getText(ast); + const callText = getNodeText(ts, node.expression, ast); if (vueCompilerOptions.macros.defineModel.includes(callText)) { let name: TextRange | undefined; let options: ts.Node | undefined; @@ -121,7 +121,7 @@ export function parseScriptSetupRanges( let required = false; if (options && ts.isObjectLiteralExpression(options)) { for (const property of options.properties) { - if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.getText(ast) === 'required' && property.initializer.kind === ts.SyntaxKind.TrueKeyword) { + if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && getNodeText(ts, property.name, ast) === 'required' && property.initializer.kind === ts.SyntaxKind.TrueKeyword) { required = true; break; } @@ -142,7 +142,7 @@ export function parseScriptSetupRanges( const secondArg = node.arguments[1]; if (ts.isObjectLiteralExpression(secondArg)) { for (const property of secondArg.properties) { - if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && property.name.getText(ast) === 'required' && property.initializer.kind === ts.SyntaxKind.TrueKeyword) { + if (ts.isPropertyAssignment(property) && ts.isIdentifier(property.name) && getNodeText(ts, property.name, ast) === 'required' && property.initializer.kind === ts.SyntaxKind.TrueKeyword) { required = true; break; } @@ -181,13 +181,13 @@ export function parseScriptSetupRanges( else if (vueCompilerOptions.macros.defineSlots.includes(callText)) { slots.define = parseDefineFunction(node); if (ts.isVariableDeclaration(parent)) { - slots.name = parent.name.getText(ast); + slots.name = getNodeText(ts, parent.name, ast); } } else if (vueCompilerOptions.macros.defineEmits.includes(callText)) { emits.define = parseDefineFunction(node); if (ts.isVariableDeclaration(parent)) { - emits.name = parent.name.getText(ast); + emits.name = getNodeText(ts, parent.name, ast); } } else if (vueCompilerOptions.macros.defineExpose.includes(callText)) { @@ -199,7 +199,7 @@ export function parseScriptSetupRanges( for (let i = parents.length - 1; i >= 0; i--) { if (ts.isStatement(parents[i])) { const statement = parents[i]; - statement.forEachChild(child => { + ts.forEachChild(statement, child => { const range = _getStartEnd(child); statementRange ??= range; statementRange.end = range.end; @@ -217,7 +217,7 @@ export function parseScriptSetupRanges( }; if (ts.isVariableDeclaration(parent)) { - props.name = parent.name.getText(ast); + props.name = getNodeText(ts, parent.name, ast); } if (node.arguments.length) { props.define.arg = _getStartEnd(node.arguments[0]); @@ -233,11 +233,11 @@ export function parseScriptSetupRanges( props.withDefaults.arg = _getStartEnd(arg); } if (ts.isVariableDeclaration(parent)) { - props.name = parent.name.getText(ast); + props.name = getNodeText(ts, parent.name, ast); } } } - node.forEachChild(child => { + ts.forEachChild(node, child => { parents.push(node); visitNode(child, parents); parents.pop(); @@ -247,7 +247,7 @@ export function parseScriptSetupRanges( export function parseBindingRanges(ts: typeof import('typescript/lib/tsserverlibrary'), sourceFile: ts.SourceFile) { const bindings: TextRange[] = []; - sourceFile.forEachChild(node => { + ts.forEachChild(sourceFile, node => { if (ts.isVariableStatement(node)) { for (const node_2 of node.declarationList.declarations) { const vars = _findBindingVars(node_2.name); @@ -290,7 +290,7 @@ export function parseBindingRanges(ts: typeof import('typescript/lib/tsserverlib }); return bindings; function _getStartEnd(node: ts.Node) { - return getStartEnd(node, sourceFile); + return getStartEnd(ts, node, sourceFile); } function _findBindingVars(left: ts.BindingName) { return findBindingVars(ts, left, sourceFile); @@ -303,7 +303,7 @@ export function findBindingVars(ts: typeof import('typescript/lib/tsserverlibrar return vars; function worker(_node: ts.Node) { if (ts.isIdentifier(_node)) { - vars.push(getStartEnd(_node, sourceFile)); + vars.push(getStartEnd(ts, _node, sourceFile)); } // { ? } = ... // [ ? ] = ... @@ -320,7 +320,7 @@ export function findBindingVars(ts: typeof import('typescript/lib/tsserverlibrar } // { foo } = ... else if (ts.isShorthandPropertyAssignment(_node)) { - vars.push(getStartEnd(_node.name, sourceFile)); + vars.push(getStartEnd(ts, _node.name, sourceFile)); } // { ...? } = ... // [ ...? ] = ... @@ -330,9 +330,22 @@ export function findBindingVars(ts: typeof import('typescript/lib/tsserverlibrar } } -export function getStartEnd(node: ts.Node, sourceFile: ts.SourceFile) { +export function getStartEnd( + ts: typeof import('typescript/lib/tsserverlibrary'), + node: ts.Node, + sourceFile: ts.SourceFile +) { return { - start: node.getStart(sourceFile), - end: node.getEnd(), + start: (ts as any).getTokenPosOfNode(node, sourceFile) as number, + end: node.end, }; } + +export function getNodeText( + ts: typeof import('typescript/lib/tsserverlibrary'), + node: ts.Node, + sourceFile: ts.SourceFile +) { + const { start, end } = getStartEnd(ts, node, sourceFile); + return sourceFile.text.substring(start, end); +} diff --git a/packages/language-core/src/plugins/vue-tsx.ts b/packages/language-core/src/plugins/vue-tsx.ts index 0bc3a4d4e1..b8f7c48b13 100644 --- a/packages/language-core/src/plugins/vue-tsx.ts +++ b/packages/language-core/src/plugins/vue-tsx.ts @@ -64,7 +64,7 @@ const plugin: VueLanguagePlugin = (ctx) => { }); embeddedFile.content = content; embeddedFile.contentStacks = contentStacks; - embeddedFile.linkedNavigationMappings = [...tsx.linkedCodeMappings]; + embeddedFile.linkedCodeMappings = [...tsx.linkedCodeMappings]; } } else if (suffix.match(templateFormatReg)) { diff --git a/packages/language-core/src/utils/transform.ts b/packages/language-core/src/utils/transform.ts index 5bed52f50f..e80adec24e 100644 --- a/packages/language-core/src/utils/transform.ts +++ b/packages/language-core/src/utils/transform.ts @@ -1,6 +1,7 @@ import { isGloballyWhitelisted } from '@vue/shared'; import type * as ts from 'typescript/lib/tsserverlibrary'; import { VueCompilerOptions } from '../types'; +import { getNodeText, getStartEnd } from '../parsers/scriptSetupRanges'; export function* eachInterpolationSegment( ts: typeof import('typescript/lib/tsserverlibrary'), @@ -17,25 +18,26 @@ export function* eachInterpolationSegment( ): Generator<[fragment: string, offset: number | undefined, isJustForErrorMapping?: boolean]> { const varCb = (id: ts.Identifier, isShorthand: boolean) => { + const text = getNodeText(ts, id, ast); if ( - localVars.get(id.text) || + localVars.get(text) || // https://github.com/vuejs/core/blob/245230e135152900189f13a4281302de45fdcfaa/packages/compiler-core/src/transforms/transformExpression.ts#L342-L352 - isGloballyWhitelisted(id.text) || - id.text === 'require' || - id.text.startsWith('__VLS_') + isGloballyWhitelisted(text) || + text === 'require' || + text.startsWith('__VLS_') ) { // localVarOffsets.push(localVar.getStart(ast)); } else { ctxVars.push({ - text: id.text, + text, isShorthand: isShorthand, - offset: id.getStart(ast), + offset: getStartEnd(ts, id, ast).start, }); - identifiers.add(id.text); + identifiers.add(text); } }; - ast.forEachChild(node => walkIdentifiers(ts, node, varCb, localVars)); + ts.forEachChild(ast, node => walkIdentifiers(ts, node, ast, varCb, localVars)); ctxVars = ctxVars.sort((a, b) => a.offset - b.offset); @@ -110,6 +112,7 @@ export function* eachInterpolationSegment( function walkIdentifiers( ts: typeof import('typescript/lib/tsserverlibrary'), node: ts.Node, + ast: ts.SourceFile, cb: (varNode: ts.Identifier, isShorthand: boolean) => void, localVars: Map, blockVars: string[] = [], @@ -123,34 +126,34 @@ function walkIdentifiers( cb(node.name, true); } else if (ts.isPropertyAccessExpression(node)) { - walkIdentifiers(ts, node.expression, cb, localVars, blockVars, false); + walkIdentifiers(ts, node.expression, ast, cb, localVars, blockVars, false); } else if (ts.isVariableDeclaration(node)) { - collectVars(ts, node.name, blockVars); + collectVars(ts, node.name, ast, blockVars); for (const varName of blockVars) { localVars.set(varName, (localVars.get(varName) ?? 0) + 1); } if (node.initializer) - walkIdentifiers(ts, node.initializer, cb, localVars, blockVars, false); + walkIdentifiers(ts, node.initializer, ast, cb, localVars, blockVars, false); } else if (ts.isArrowFunction(node) || ts.isFunctionExpression(node)) { const functionArgs: string[] = []; for (const param of node.parameters) { - collectVars(ts, param.name, functionArgs); + collectVars(ts, param.name, ast, functionArgs); if (param.type) { - walkIdentifiers(ts, param.type, cb, localVars, blockVars, false); + walkIdentifiers(ts, param.type, ast, cb, localVars, blockVars, false); } } for (const varName of functionArgs) localVars.set(varName, (localVars.get(varName) ?? 0) + 1); - walkIdentifiers(ts, node.body, cb, localVars, blockVars, false); + walkIdentifiers(ts, node.body, ast, cb, localVars, blockVars, false); for (const varName of functionArgs) localVars.set(varName, localVars.get(varName)! - 1); @@ -160,31 +163,31 @@ function walkIdentifiers( if (ts.isPropertyAssignment(prop)) { // fix https://github.com/vuejs/language-tools/issues/1176 if (ts.isComputedPropertyName(prop.name)) { - walkIdentifiers(ts, prop.name.expression, cb, localVars, blockVars, false); + walkIdentifiers(ts, prop.name.expression, ast, cb, localVars, blockVars, false); } - walkIdentifiers(ts, prop.initializer, cb, localVars, blockVars, false); + walkIdentifiers(ts, prop.initializer, ast, cb, localVars, blockVars, false); } // fix https://github.com/vuejs/language-tools/issues/1156 else if (ts.isShorthandPropertyAssignment(prop)) { - walkIdentifiers(ts, prop, cb, localVars, blockVars, false); + walkIdentifiers(ts, prop, ast, cb, localVars, blockVars, false); } // fix https://github.com/vuejs/language-tools/issues/1148#issuecomment-1094378126 else if (ts.isSpreadAssignment(prop)) { // TODO: cannot report "Spread types may only be created from object types.ts(2698)" - walkIdentifiers(ts, prop.expression, cb, localVars, blockVars, false); + walkIdentifiers(ts, prop.expression, ast, cb, localVars, blockVars, false); } } } else if (ts.isTypeReferenceNode(node)) { // fix https://github.com/vuejs/language-tools/issues/1422 - node.forEachChild(node => walkIdentifiersInTypeReference(ts, node, cb)); + ts.forEachChild(node, node => walkIdentifiersInTypeReference(ts, node, cb)); } else { const _blockVars = blockVars; if (ts.isBlock(node)) { blockVars = []; } - node.forEachChild(node => walkIdentifiers(ts, node, cb, localVars, blockVars, false)); + ts.forEachChild(node, node => walkIdentifiers(ts, node, ast, cb, localVars, blockVars, false)); if (ts.isBlock(node)) { for (const varName of blockVars) { localVars.set(varName, localVars.get(varName)! - 1); @@ -209,31 +212,32 @@ function walkIdentifiersInTypeReference( cb(node.exprName, false); } else { - node.forEachChild(node => walkIdentifiersInTypeReference(ts, node, cb)); + ts.forEachChild(node, node => walkIdentifiersInTypeReference(ts, node, cb)); } } export function collectVars( ts: typeof import('typescript/lib/tsserverlibrary'), node: ts.Node, + ast: ts.SourceFile, result: string[], ) { if (ts.isIdentifier(node)) { - result.push(node.text); + result.push(getNodeText(ts, node, ast)); } else if (ts.isObjectBindingPattern(node)) { for (const el of node.elements) { - collectVars(ts, el.name, result); + collectVars(ts, el.name, ast, result); } } else if (ts.isArrayBindingPattern(node)) { for (const el of node.elements) { if (ts.isBindingElement(el)) { - collectVars(ts, el.name, result); + collectVars(ts, el.name, ast, result); } } } else { - node.forEachChild(node => collectVars(ts, node, result)); + ts.forEachChild(node, node => collectVars(ts, node, ast, result)); } } diff --git a/packages/language-core/src/virtualFile/computedFiles.ts b/packages/language-core/src/virtualFile/computedFiles.ts index eefad4123d..35e3d606bb 100644 --- a/packages/language-core/src/virtualFile/computedFiles.ts +++ b/packages/language-core/src/virtualFile/computedFiles.ts @@ -51,7 +51,7 @@ export function computedFiles( fileName: file.fileName, languageId: resolveCommonLanguageId(file.fileName), typescript: file.typescript, - linkedNavigationMappings: file.linkedNavigationMappings, + linkedCodeMappings: file.linkedCodeMappings, snapshot, mappings, codegenStacks, @@ -70,7 +70,7 @@ export function computedFiles( fileName: file.fileName, languageId: resolveCommonLanguageId(file.fileName), typescript: file.typescript, - linkedNavigationMappings: file.linkedNavigationMappings, + linkedCodeMappings: file.linkedCodeMappings, snapshot, mappings, codegenStacks, @@ -85,7 +85,7 @@ export function computedFiles( fileName: file.fileName, languageId: resolveCommonLanguageId(file.fileName), typescript: file.typescript, - linkedNavigationMappings: file.linkedNavigationMappings, + linkedCodeMappings: file.linkedCodeMappings, snapshot, mappings, codegenStacks, diff --git a/packages/language-core/src/virtualFile/computedSfc.ts b/packages/language-core/src/virtualFile/computedSfc.ts index af6bb7c0e7..8b107549e4 100644 --- a/packages/language-core/src/virtualFile/computedSfc.ts +++ b/packages/language-core/src/virtualFile/computedSfc.ts @@ -43,7 +43,7 @@ export function computedSfc( const _src = src(); return _src ? untrackedSnapshot().getText(0, base.startTagEnd).lastIndexOf(_src) - base.startTagEnd : -1; }); - const ast = computed(() => ts.createSourceFile(fileName + '.' + base.lang, base.content, ts.ScriptTarget.Latest)); + const ast = computed(() => ts.createSourceFile(fileName + '.' + base.lang, base.content, 99 satisfies ts.ScriptTarget.Latest)); return mergeObject(base, { get src() { return src(); }, get srcOffset() { return srcOffset(); }, @@ -64,7 +64,7 @@ export function computedSfc( const _generic = generic(); return _generic !== undefined ? untrackedSnapshot().getText(0, base.startTagEnd).lastIndexOf(_generic) - base.startTagEnd : -1; }); - const ast = computed(() => ts.createSourceFile(fileName + '.' + base.lang, base.content, ts.ScriptTarget.Latest)); + const ast = computed(() => ts.createSourceFile(fileName + '.' + base.lang, base.content, 99 satisfies ts.ScriptTarget.Latest)); return mergeObject(base, { get generic() { return generic(); }, get genericOffset() { return genericOffset(); }, diff --git a/packages/language-core/src/virtualFile/embeddedFile.ts b/packages/language-core/src/virtualFile/embeddedFile.ts index f5e9fa7b27..31d7d646b3 100644 --- a/packages/language-core/src/virtualFile/embeddedFile.ts +++ b/packages/language-core/src/virtualFile/embeddedFile.ts @@ -5,7 +5,7 @@ export class VueEmbeddedFile { public parentFileName?: string; public typescript: VirtualFile['typescript']; - public linkedNavigationMappings: Mapping[] = []; + public linkedCodeMappings: Mapping[] = []; constructor( public fileName: string, diff --git a/packages/language-plugin-pug/package.json b/packages/language-plugin-pug/package.json index b9589577c2..39f953a3d1 100644 --- a/packages/language-plugin-pug/package.json +++ b/packages/language-plugin-pug/package.json @@ -17,7 +17,7 @@ "@vue/language-core": "1.8.26" }, "dependencies": { - "@volar/source-map": "2.0.0-alpha.3", - "volar-service-pug": "0.0.20" + "@volar/source-map": "2.0.0-alpha.4", + "volar-service-pug": "0.0.21" } } diff --git a/packages/language-service/package.json b/packages/language-service/package.json index e46f40ac98..25ea544f4e 100644 --- a/packages/language-service/package.json +++ b/packages/language-service/package.json @@ -17,29 +17,29 @@ "update-html-data": "node ./scripts/update-html-data.js" }, "dependencies": { - "@volar/language-core": "2.0.0-alpha.3", - "@volar/language-service": "2.0.0-alpha.3", - "@volar/typescript": "2.0.0-alpha.3", + "@volar/language-core": "2.0.0-alpha.4", + "@volar/language-service": "2.0.0-alpha.4", + "@volar/typescript": "2.0.0-alpha.4", "@vue/compiler-dom": "^3.3.0", "@vue/language-core": "1.8.26", "@vue/shared": "^3.3.0", "computeds": "^0.0.1", "path-browserify": "^1.0.1", - "volar-service-css": "0.0.20", - "volar-service-emmet": "0.0.20", - "volar-service-html": "0.0.20", - "volar-service-json": "0.0.20", - "volar-service-pug": "0.0.20", - "volar-service-pug-beautify": "0.0.20", - "volar-service-typescript": "0.0.20", - "volar-service-typescript-twoslash-queries": "0.0.20", + "volar-service-css": "0.0.21", + "volar-service-emmet": "0.0.21", + "volar-service-html": "0.0.21", + "volar-service-json": "0.0.21", + "volar-service-pug": "0.0.21", + "volar-service-pug-beautify": "0.0.21", + "volar-service-typescript": "0.0.21", + "volar-service-typescript-twoslash-queries": "0.0.21", "vscode-html-languageservice": "^5.1.0", "vscode-languageserver-textdocument": "^1.0.11" }, "devDependencies": { "@types/node": "latest", "@types/path-browserify": "latest", - "@volar/kit": "2.0.0-alpha.3", + "@volar/kit": "2.0.0-alpha.4", "vscode-languageserver-protocol": "^3.17.5", "vscode-uri": "^3.0.8" } diff --git a/packages/language-service/src/plugins/vue-codelens-references.ts b/packages/language-service/src/plugins/vue-codelens-references.ts index 403f3352e7..50043aa83d 100644 --- a/packages/language-service/src/plugins/vue-codelens-references.ts +++ b/packages/language-service/src/plugins/vue-codelens-references.ts @@ -31,39 +31,6 @@ export function create(): ServicePlugin { return result; }); }, - - async resolveReferencesCodeLensLocations(document, range, references) { - - const [virtualFile, sourceFile] = context.language.files.getVirtualFile(context.env.uriToFileName(document.uri)); - if (virtualFile && sourceFile?.virtualFile?.[0] instanceof VueFile) { - const vueFile = sourceFile.virtualFile[0]; - const blocks = [ - vueFile.sfc.script, - vueFile.sfc.scriptSetup, - vueFile.sfc.template, - ...vueFile.sfc.styles, - ...vueFile.sfc.customBlocks, - ]; - for (const map of context.documents.getMaps(virtualFile)) { - const sourceOffset = map.map.getSourceOffset(document.offsetAt(range.start)); - if (sourceOffset !== undefined) { - const sourceBlock = blocks.find(block => block && sourceOffset[0] >= block.startTagEnd && sourceOffset[0] <= block.endTagStart); - const sourceDocument = context.documents.get(context.env.fileNameToUri(sourceFile.fileName), sourceFile.languageId, sourceFile.snapshot); - references = references.filter(reference => - reference.uri !== sourceDocument.uri // different file - || sourceBlock !== blocks.find(block => - block - && sourceDocument.offsetAt(reference.range.start) >= block.startTagEnd - && sourceDocument.offsetAt(reference.range.end) <= block.endTagStart - ) // different block - ); - break; - } - } - } - - return references; - }, }; function worker(uri: string, callback: (vueFile: VirtualFile, sourceFile: SourceFile) => T) { diff --git a/packages/language-service/tests/reference.ts b/packages/language-service/tests/reference.ts index 9ebf7c56c4..bcc780a426 100644 --- a/packages/language-service/tests/reference.ts +++ b/packages/language-service/tests/reference.ts @@ -35,6 +35,7 @@ for (const dirName of testDirs) { const locations = await tester.languageService.findReferences( uri, position, + { includeDeclaration: true }, ); expect(locations).toBeDefined(); diff --git a/packages/tsc/bin/vue-tsc.js b/packages/tsc/bin/vue-tsc.js index 2990a71b08..493601fcff 100755 --- a/packages/tsc/bin/vue-tsc.js +++ b/packages/tsc/bin/vue-tsc.js @@ -1,58 +1,2 @@ #!/usr/bin/env node -const semver = require('semver') -const fs = require('fs'); -const tsPkg = require('typescript/package.json'); -const readFileSync = fs.readFileSync; -const tscPath = require.resolve('typescript/lib/tsc'); -const proxyApiPath = require.resolve('../out/index'); - -fs.readFileSync = (...args) => { - if (args[0] === tscPath) { - let tsc = readFileSync(...args); - - // add *.vue files to allow extensions - tryReplace(/supportedTSExtensions = .*(?=;)/, s => s + '.concat([[".vue"]])'); - tryReplace(/supportedJSExtensions = .*(?=;)/, s => s + '.concat([[".vue"]])'); - tryReplace(/allSupportedExtensions = .*(?=;)/, s => s + '.concat([[".vue"]])'); - - // proxy createProgram apis - tryReplace(/function createProgram\(.+\) {/, s => s + ` return require(${JSON.stringify(proxyApiPath)}).createProgram(...arguments);`); - - // patches logic for checking root file extension in build program for incremental builds - if (semver.gt(tsPkg.version, '5.0.0')) { - tryReplace( - `for (const existingRoot of buildInfoVersionMap.roots) {`, - `for (const existingRoot of buildInfoVersionMap.roots - .filter(file => !file.toLowerCase().includes('__vls_')) - .map(file => file.replace(/\.vue\.(j|t)sx?$/i, '.vue')) - ) {` - ); - tryReplace( - `return [toFileId(key), toFileIdListId(state.exportedModulesMap.getValues(key))];`, - `return [toFileId(key), toFileIdListId(new Set(arrayFrom(state.exportedModulesMap.getValues(key)).filter(file => file !== void 0)))];` - ); - } - if (semver.gte(tsPkg.version, '5.0.4')) { - tryReplace( - `return createBuilderProgramUsingProgramBuildInfo(buildInfo, buildInfoPath, host);`, - s => `buildInfo.program.fileNames = buildInfo.program.fileNames - .filter(file => !file.toLowerCase().includes('__vls_')) - .map(file => file.replace(/\.vue\.(j|t)sx?$/i, '.vue'));\n` + s - ); - } - - return tsc; - - function tryReplace(search, replace) { - const before = tsc; - tsc = tsc.replace(search, replace); - const after = tsc; - if (after === before) { - throw 'Search string not found: ' + JSON.stringify(search.toString()); - } - } - } - return readFileSync(...args); -}; - -require(tscPath); +require('../out/index'); diff --git a/packages/tsc/src/index.ts b/packages/tsc/src/index.ts index 6702a298a5..8a6c5c1a64 100644 --- a/packages/tsc/src/index.ts +++ b/packages/tsc/src/index.ts @@ -1,150 +1,16 @@ -import type * as ts from 'typescript/lib/tsserverlibrary'; import * as vue from '@vue/language-core'; -import { createLanguage, decorateLanguageService, getDocumentRegistry, getProgram } from '@volar/typescript'; - -export type _Program = ts.Program & { __vue: ProgramContext; }; - -interface ProgramContext { - projectVersion: number; - options: ts.CreateProgramOptions; - vueCompilerOptions: Partial; - language: vue.Language; - languageService: ts.LanguageService; -} +import { runTsc } from '@volar/typescript/lib/starters/runTsc'; const windowsPathReg = /\\/g; -export function createProgram(options: ts.CreateProgramOptions) { - - assert(options.options.noEmit || options.options.emitDeclarationOnly, 'js emit is not supported'); - assert(options.options.noEmit || !options.options.noEmitOnError, 'noEmitOnError is not supported'); - assert(!options.options.extendedDiagnostics && !options.options.generateTrace, '--extendedDiagnostics / --generateTrace is not supported, please run `Write Virtual Files` in VSCode to write virtual files and use `--extendedDiagnostics` / `--generateTrace` via tsc instead of vue-tsc to debug.'); - assert(options.host, '!options.host'); - - const ts = require('typescript') as typeof import('typescript/lib/tsserverlibrary'); - - let program = options.oldProgram as _Program | undefined; - - if (!program) { - - const ctx: ProgramContext = { - projectVersion: 0, - options, - get vueCompilerOptions() { - return vueCompilerOptions; - }, - get languageService() { - return vueTsLs; - }, - get language() { - return language; - }, - }; - const vueCompilerOptions = getVueCompilerOptions(); - const scripts = new Map(); - const host: vue.TypeScriptProjectHost = { - getCurrentDirectory() { - return ctx.options.host!.getCurrentDirectory().replace(windowsPathReg, '/'); - }, - getCompilationSettings: () => ctx.options.options, - getScriptFileNames: () => { - return ctx.options.rootNames as string[]; - }, - getScriptSnapshot, - getProjectVersion: () => { - return ctx.projectVersion.toString(); - }, - getProjectReferences: () => ctx.options.projectReferences, - getLanguageId: vue.resolveCommonLanguageId, - }; - const language = createLanguage( - ts, - ts.sys, - vue.createLanguages( - ts, - host.getCompilationSettings(), - vueCompilerOptions, - ), - undefined, - host, - ); - const vueTsLs = ts.createLanguageService( - language.typescript!.languageServiceHost, - getDocumentRegistry( - ts, - ts.sys.useCaseSensitiveFileNames, - host.getCurrentDirectory() - ) - ); - - decorateLanguageService(language.files, vueTsLs, false); - - program = getProgram( - ts, - language.files, - vueTsLs, - ts.sys - ) as (ts.Program & { __vue: ProgramContext; }); - program.__vue = ctx; - - function getVueCompilerOptions(): Partial { - const tsConfig = ctx.options.options.configFilePath; - if (typeof tsConfig === 'string') { - return vue.createParsedCommandLine(ts, ts.sys, tsConfig.replace(windowsPathReg, '/')).vueOptions; - } - return {}; - } - function getScriptSnapshot(fileName: string) { - return getScript(fileName)?.scriptSnapshot; - } - function getScript(fileName: string) { - - const script = scripts.get(fileName); - if (script?.projectVersion === ctx.projectVersion) { - return script; - } - - const modifiedTime = ts.sys.getModifiedTime?.(fileName)?.valueOf() ?? 0; - if (script?.modifiedTime === modifiedTime) { - return script; - } - - if (ctx.options.host!.fileExists(fileName)) { - const fileContent = ctx.options.host!.readFile(fileName); - if (fileContent !== undefined) { - const script = { - projectVersion: ctx.projectVersion, - modifiedTime, - scriptSnapshot: ts.ScriptSnapshot.fromString(fileContent), - version: ctx.options.host!.createHash?.(fileContent) ?? fileContent, - }; - scripts.set(fileName, script); - return script; - } - } - } - } - else { - const ctx: ProgramContext = program.__vue; - ctx.options = options; - ctx.projectVersion++; - } - - for (const rootName of options.rootNames) { - // register file watchers - options.host.getSourceFile(rootName, ts.ScriptTarget.ESNext); - } - - return program; -} - -function assert(condition: unknown, message: string): asserts condition { - if (!condition) { - console.error(message); - throw new Error(message); - } -} +runTsc(require.resolve('typescript/lib/tsc'), ['.vue'], (ts, options) => { + const { configFilePath } = options.options; + const vueOptions = typeof configFilePath === 'string' + ? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/')).vueOptions + : {}; + return vue.createLanguages( + ts, + options.options, + vueOptions, + ); +}); diff --git a/packages/tsc/tests/dts.spec.ts b/packages/tsc/tests/dts.spec.ts index 3079066844..cecb6354ae 100644 --- a/packages/tsc/tests/dts.spec.ts +++ b/packages/tsc/tests/dts.spec.ts @@ -2,35 +2,52 @@ import * as path from 'path'; import * as fs from 'fs'; import * as ts from 'typescript'; import { describe, expect, it } from 'vitest'; -import { createProgram } from '../out'; +import { proxyCreateProgram } from '@volar/typescript'; +import * as vue from '@vue/language-core'; const workspace = path.resolve(__dirname, '../../../test-workspace/component-meta'); -const testFiles = readFilesRecursive(workspace); -const ensureTs = (filename: string) => filename.endsWith('.ts') || filename.endsWith('.tsx') ? filename : filename + '.ts'; +const intputFiles = readFilesRecursive(workspace); const normalizePath = (filename: string) => filename.replace(/\\/g, '/'); const normalizeNewline = (text: string) => text.replace(/\r\n/g, '\n'); +const windowsPathReg = /\\/g; describe('vue-tsc-dts', () => { const compilerOptions: ts.CompilerOptions = { rootDir: workspace, declaration: true, emitDeclarationOnly: true, + allowNonTsExtensions: true, }; const host = ts.createCompilerHost(compilerOptions); + const createProgram = proxyCreateProgram(ts, ts.createProgram, ['.vue'], (ts, options) => { + const { configFilePath } = options.options; + const vueOptions = typeof configFilePath === 'string' + ? vue.createParsedCommandLine(ts, ts.sys, configFilePath.replace(windowsPathReg, '/')).vueOptions + : {}; + return vue.createLanguages( + ts, + options.options, + vueOptions, + ); + }); const program = createProgram({ host, - rootNames: testFiles, + rootNames: intputFiles, options: compilerOptions }); - const service = program.__vue.languageService; - for (const file of testFiles) { - const output = service.getEmitOutput(ensureTs(file), true); - for (const outputFile of output.outputFiles) { - it(`Input: ${shortenPath(file)}, Output: ${shortenPath(outputFile.name)}`, () => { - expect(normalizeNewline(outputFile.text)).toMatchSnapshot(); - }); - } + for (const intputFile of intputFiles) { + const sourceFile = program.getSourceFile(intputFile); + program.emit( + sourceFile, + (outputFile, text) => { + it(`Input: ${shortenPath(intputFile)}, Output: ${shortenPath(outputFile)}`, () => { + expect(normalizeNewline(text)).toMatchSnapshot(); + }); + }, + undefined, + true, + ); } }); diff --git a/packages/typescript-plugin/package.json b/packages/typescript-plugin/package.json index 08307ab809..2d316370e3 100644 --- a/packages/typescript-plugin/package.json +++ b/packages/typescript-plugin/package.json @@ -13,7 +13,7 @@ "directory": "packages/typescript-plugin" }, "dependencies": { - "@volar/typescript": "2.0.0-alpha.3", + "@volar/typescript": "2.0.0-alpha.4", "@vue/language-core": "1.8.25" } } diff --git a/packages/typescript-plugin/src/index.ts b/packages/typescript-plugin/src/index.ts index fa9d39590c..cf92e84a60 100644 --- a/packages/typescript-plugin/src/index.ts +++ b/packages/typescript-plugin/src/index.ts @@ -1,91 +1,39 @@ -import { decorateLanguageService, decorateLanguageServiceHost, searchExternalFiles } from '@volar/typescript'; +import { createTSServerPlugin } from '@volar/typescript/lib/starters/createTSServerPlugin'; import * as vue from '@vue/language-core'; +// @ts-expect-error import type * as ts from 'typescript/lib/tsserverlibrary'; -const externalFiles = new WeakMap(); -const projectVueOptions = new WeakMap(); const windowsPathReg = /\\/g; -const init: ts.server.PluginModuleFactory = (modules) => { - const { typescript: ts } = modules; - const pluginModule: ts.server.PluginModule = { - create(info) { - - const getScriptSnapshot = info.languageServiceHost.getScriptSnapshot.bind(info.languageServiceHost); - const vueOptions = vue.resolveVueCompilerOptions(getVueCompilerOptions()); - const files = vue.createFileProvider( - vue.createLanguages( - ts, - info.languageServiceHost.getCompilationSettings(), - vueOptions, - ), - ts.sys.useCaseSensitiveFileNames, - fileName => { - const snapshot = getScriptSnapshot(fileName); - if (snapshot) { - files.updateSourceFile(fileName, vue.resolveCommonLanguageId(fileName), snapshot); - } - else { - files.deleteSourceFile(fileName); - } - } - ); - projectVueOptions.set(info.project, vueOptions); - - decorateLanguageService(files, info.languageService, true); - decorateLanguageServiceHost(files, info.languageServiceHost, ts, vueOptions.extensions); - - const getCompletionsAtPosition = info.languageService.getCompletionsAtPosition; - - info.languageService.getCompletionsAtPosition = (fileName, position, options) => { - const result = getCompletionsAtPosition(fileName, position, options); - if (result) { - result.entries = result.entries.filter(entry => entry.name.indexOf('__VLS_') === -1); - } - return result; - }; - - return info.languageService; +export = createTSServerPlugin((ts, info) => { + const vueOptions = vue.resolveVueCompilerOptions(getVueCompilerOptions()); + const languagePlugins = vue.createLanguages( + ts, + info.languageServiceHost.getCompilationSettings(), + vueOptions, + ); + const getCompletionsAtPosition = info.languageService.getCompletionsAtPosition; + + info.languageService.getCompletionsAtPosition = (fileName, position, options) => { + const result = getCompletionsAtPosition(fileName, position, options); + if (result) { + result.entries = result.entries.filter(entry => entry.name.indexOf('__VLS_') === -1); + } + return result; + }; - function getVueCompilerOptions() { - if (info.project.projectKind === ts.server.ProjectKind.Configured) { - const tsconfig = info.project.getProjectName(); - return vue.createParsedCommandLine(ts, ts.sys, tsconfig.replace(windowsPathReg, '/')).vueOptions; - } - else { - return vue.createParsedCommandLineByJson(ts, ts.sys, info.languageServiceHost.getCurrentDirectory(), {}).vueOptions; - } - } - }, - getExternalFiles(project, updateLevel = 0) { - if ( - updateLevel >= (1 satisfies ts.ProgramUpdateLevel.RootNamesAndUpdate) - || !externalFiles.has(project) - ) { - const oldFiles = externalFiles.get(project); - const newFiles = searchExternalFiles(ts, project, projectVueOptions.get(project)!.extensions); - externalFiles.set(project, newFiles); - if (oldFiles && !arrayItemsEqual(oldFiles, newFiles)) { - project.refreshDiagnostics(); - } - } - return externalFiles.get(project)!; - }, + return { + languagePlugins, + extensions: vueOptions.extensions, }; - return pluginModule; -}; -function arrayItemsEqual(a: string[], b: string[]) { - if (a.length !== b.length) { - return false; - } - const set = new Set(a); - for (const file of b) { - if (!set.has(file)) { - return false; + function getVueCompilerOptions() { + if (info.project.projectKind === ts.server.ProjectKind.Configured) { + const tsconfig = info.project.getProjectName(); + return vue.createParsedCommandLine(ts, ts.sys, tsconfig.replace(windowsPathReg, '/')).vueOptions; + } + else { + return vue.createParsedCommandLineByJson(ts, ts.sys, info.languageServiceHost.getCurrentDirectory(), {}).vueOptions; } } - return true; -} - -export = init; +}); diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index fdbf502bba..d37770d68c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -15,8 +15,8 @@ importers: specifier: latest version: 3.0.0(typescript@5.3.2) '@volar/language-service': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 typescript: specifier: latest version: 5.3.2 @@ -36,8 +36,8 @@ importers: specifier: ^1.82.0 version: 1.84.2 '@volar/vscode': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@vue/language-core': specifier: 1.8.26 version: link:../../packages/language-core @@ -69,8 +69,8 @@ importers: packages/component-meta: dependencies: '@volar/typescript': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@vue/language-core': specifier: 1.8.26 version: link:../language-core @@ -96,8 +96,8 @@ importers: packages/language-core: dependencies: '@volar/language-core': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@vue/compiler-dom': specifier: ^3.3.0 version: 3.3.10 @@ -136,11 +136,11 @@ importers: packages/language-plugin-pug: dependencies: '@volar/source-map': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 volar-service-pug: - specifier: 0.0.20 - version: 0.0.20 + specifier: 0.0.21 + version: 0.0.21 devDependencies: '@types/node': specifier: latest @@ -152,14 +152,14 @@ importers: packages/language-server: dependencies: '@volar/language-core': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@volar/language-server': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@volar/typescript': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@vue/language-core': specifier: 1.8.26 version: link:../language-core @@ -176,14 +176,14 @@ importers: packages/language-service: dependencies: '@volar/language-core': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@volar/language-service': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@volar/typescript': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@vue/compiler-dom': specifier: ^3.3.0 version: 3.3.10 @@ -200,29 +200,29 @@ importers: specifier: ^1.0.1 version: 1.0.1 volar-service-css: - specifier: 0.0.20 - version: 0.0.20(@volar/language-service@2.0.0-alpha.3) + specifier: 0.0.21 + version: 0.0.21(@volar/language-service@2.0.0-alpha.4) volar-service-emmet: - specifier: 0.0.20 - version: 0.0.20(@volar/language-service@2.0.0-alpha.3) + specifier: 0.0.21 + version: 0.0.21(@volar/language-service@2.0.0-alpha.4) volar-service-html: - specifier: 0.0.20 - version: 0.0.20(@volar/language-service@2.0.0-alpha.3) + specifier: 0.0.21 + version: 0.0.21(@volar/language-service@2.0.0-alpha.4) volar-service-json: - specifier: 0.0.20 - version: 0.0.20(@volar/language-service@2.0.0-alpha.3) + specifier: 0.0.21 + version: 0.0.21(@volar/language-service@2.0.0-alpha.4) volar-service-pug: - specifier: 0.0.20 - version: 0.0.20 + specifier: 0.0.21 + version: 0.0.21 volar-service-pug-beautify: - specifier: 0.0.20 - version: 0.0.20(@volar/language-service@2.0.0-alpha.3) + specifier: 0.0.21 + version: 0.0.21(@volar/language-service@2.0.0-alpha.4) volar-service-typescript: - specifier: 0.0.20 - version: 0.0.20(@volar/language-service@2.0.0-alpha.3)(@volar/typescript@2.0.0-alpha.3) + specifier: 0.0.21 + version: 0.0.21(@volar/language-service@2.0.0-alpha.4)(@volar/typescript@2.0.0-alpha.4) volar-service-typescript-twoslash-queries: - specifier: 0.0.20 - version: 0.0.20(@volar/language-service@2.0.0-alpha.3) + specifier: 0.0.21 + version: 0.0.21(@volar/language-service@2.0.0-alpha.4) vscode-html-languageservice: specifier: ^5.1.0 version: 5.1.1 @@ -237,8 +237,8 @@ importers: specifier: latest version: 1.0.2 '@volar/kit': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3(typescript@5.3.3) + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4(typescript@5.3.3) vscode-languageserver-protocol: specifier: ^3.17.5 version: 3.17.5 @@ -249,14 +249,11 @@ importers: packages/tsc: dependencies: '@volar/typescript': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@vue/language-core': specifier: 1.8.26 version: link:../language-core - semver: - specifier: ^7.5.4 - version: 7.5.4 typescript: specifier: '*' version: 5.3.2 @@ -268,8 +265,8 @@ importers: packages/typescript-plugin: dependencies: '@volar/typescript': - specifier: 2.0.0-alpha.3 - version: 2.0.0-alpha.3 + specifier: 2.0.0-alpha.4 + version: 2.0.0-alpha.4 '@vue/language-core': specifier: 1.8.26 version: link:../language-core @@ -1281,31 +1278,31 @@ packages: pretty-format: 29.7.0 dev: true - /@volar/kit@2.0.0-alpha.3(typescript@5.3.3): - resolution: {integrity: sha512-TgVe2oinvD2EB+na24xcJTouvgxSuistT3EqMMs43pB/4K0WQw1Df8kvmBHCn1U4dp32I9/hRWnHFsstsTt7rw==} + /@volar/kit@2.0.0-alpha.4(typescript@5.3.3): + resolution: {integrity: sha512-F2N8KYdEpvP0T1ueN7maP67hsQebWS6ebFhGxF/C6vY3HJ1H6mzaAMmqpDMDs+jiMZ7KS3DvvAOGuIPza4BOog==} peerDependencies: typescript: '*' dependencies: - '@volar/language-service': 2.0.0-alpha.3 - '@volar/typescript': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 + '@volar/typescript': 2.0.0-alpha.4 typesafe-path: 0.2.2 typescript: 5.3.3 vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 dev: true - /@volar/language-core@2.0.0-alpha.3: - resolution: {integrity: sha512-+IFYZ6YaCtLoaoBxa5b6zj6HnNGGKtiXguVyK9LteJWI8QMNit6aeVhvevQAJKSeIMJEzbJBSBDI4fiZvumlSg==} + /@volar/language-core@2.0.0-alpha.4: + resolution: {integrity: sha512-aHceQhK7tdrolnoXjT+DhNkz3mgNsfbgXcTvCRZFFqx9+IFmd8yta1p3Cm8rldb3xL9SxNhfhrL053FaFSqdUA==} dependencies: - '@volar/source-map': 2.0.0-alpha.3 + '@volar/source-map': 2.0.0-alpha.4 - /@volar/language-server@2.0.0-alpha.3: - resolution: {integrity: sha512-8lorXbuk4JXFF5GuYJ3ngb0DMtK4hop6mdsT3x+R/gfaq1/9qqVjUarXcfab25YtzET89TIplszMYRBwjZmZHw==} + /@volar/language-server@2.0.0-alpha.4: + resolution: {integrity: sha512-CuY1m6ZTN/IfCDZvyeAZV5Ecvo7qXRuiB6Px3YuyksHL28XzRFWLyQYad4OX8cSxhUTe1ctPgyNZmotIu74I1Q==} dependencies: - '@volar/language-core': 2.0.0-alpha.3 - '@volar/language-service': 2.0.0-alpha.3 - '@volar/snapshot-document': 2.0.0-alpha.3 - '@volar/typescript': 2.0.0-alpha.3 + '@volar/language-core': 2.0.0-alpha.4 + '@volar/language-service': 2.0.0-alpha.4 + '@volar/snapshot-document': 2.0.0-alpha.4 + '@volar/typescript': 2.0.0-alpha.4 '@vscode/l10n': 0.0.16 path-browserify: 1.0.1 request-light: 0.7.0 @@ -1314,35 +1311,35 @@ packages: vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 - /@volar/language-service@2.0.0-alpha.3: - resolution: {integrity: sha512-rlVj5OF5lFnLYlMdYJWMQ79UP5BYcewy0Yy6Vd/IBuI6z/tkjAsARTbHaXdeHiTDCfLWtZ2HCKNTyqnQ0GjhYA==} + /@volar/language-service@2.0.0-alpha.4: + resolution: {integrity: sha512-up2QIn6C67ieAOQ0wcGB/Wvj4NWxAZ1n0SlnYwFyjfrZNT3khI8CHOmA0uTVcXk0tzbRoqEeJSCKAnf/DO7RdA==} dependencies: - '@volar/language-core': 2.0.0-alpha.3 + '@volar/language-core': 2.0.0-alpha.4 vscode-languageserver-protocol: 3.17.5 vscode-languageserver-textdocument: 1.0.11 vscode-uri: 3.0.8 - /@volar/snapshot-document@2.0.0-alpha.3: - resolution: {integrity: sha512-CLunbI4CxZQb2Ta9dsuCR7HVebvV3HyzeqT+lgxLlf+L0BeyLke1vMPL92TpaIhiv9bPeycwAqpFLSAsUtM8kA==} + /@volar/snapshot-document@2.0.0-alpha.4: + resolution: {integrity: sha512-GnEYslEKiHtLpCG/NRG+oIDr+9oeehvfQsrlJUj4uyCVTrOAPg0GFUYOWrAHJDudDq+XCAAFMgTlSLpzII4IPA==} dependencies: vscode-languageserver-protocol: 3.17.5 vscode-languageserver-textdocument: 1.0.11 - /@volar/source-map@2.0.0-alpha.3: - resolution: {integrity: sha512-Y/1JI1ds2SsWgE2FdbFyqCdFzvd6inX2P//sxvdR3UohChcMY8GXWrVBBdRN3TJaKvRCBR6B9LMHkG/bMy7F+g==} + /@volar/source-map@2.0.0-alpha.4: + resolution: {integrity: sha512-x7pvWgYWlJoXI8HAekVgQyV2jNotuAoeQNwl3EYecXsAcAmVAKOBbXYArGF+66xoFJGTkh1chAyPD0X85SNYDw==} dependencies: muggle-string: 0.4.0 - /@volar/typescript@2.0.0-alpha.3: - resolution: {integrity: sha512-3f6oJvcJed5Ovvip7ge3iSm8MeVSZk+uwQp9+k3JPHz0rpGdgBVMW0/Gn36by65lrxumCDhj6HPUV05oSAPgzQ==} + /@volar/typescript@2.0.0-alpha.4: + resolution: {integrity: sha512-ibqa3zJ3KlpIx6owmr9HjuwZbRaynETGqJOT0Nv0j1s7q1WkMC1RWoiE0OYWVJfEEs7UcIq96FBdq4n2obMD9A==} dependencies: - '@volar/language-core': 2.0.0-alpha.3 + '@volar/language-core': 2.0.0-alpha.4 path-browserify: 1.0.1 - /@volar/vscode@2.0.0-alpha.3: - resolution: {integrity: sha512-7bHWT3nKmb9Nn6rze4+YcZuE85ephJZDbDUK1pm/BGzAFSvVvPaW9ujAiiWerCV4R7wj96xWo6emBzbH+8WUpA==} + /@volar/vscode@2.0.0-alpha.4: + resolution: {integrity: sha512-1zzkyLpaLKU9SjjdMZewipZ07Zbs5wSx2qI/gTyTPg0Pr481lPDslogYQJdx6LkBZxSn5k6SEglDBCvcFMMjZQ==} dependencies: - '@volar/language-server': 2.0.0-alpha.3 + '@volar/language-server': 2.0.0-alpha.4 path-browserify: 1.0.1 vscode-languageclient: 9.0.1 vscode-nls: 5.2.0 @@ -5239,60 +5236,60 @@ packages: - terser dev: true - /volar-service-css@0.0.20(@volar/language-service@2.0.0-alpha.3): - resolution: {integrity: sha512-wRIwc75Og3hS5PARf2cH2GkLH/OZFj+wbfMKIyz4fjDmjKp4OoRUuUpTleENeawEEKUQRdZtboClph1WSBAYgg==} + /volar-service-css@0.0.21(@volar/language-service@2.0.0-alpha.4): + resolution: {integrity: sha512-GSn879I7v+gPqJQntoi0Qdl72w1TYegoa2JFm1GI60YiSpPAoQ745JWFElL6AYX0FL9VqTfa9J6Y9fCUP6ZO6A==} peerDependencies: '@volar/language-service': next peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 vscode-css-languageservice: 6.2.11 vscode-uri: 3.0.8 dev: false - /volar-service-emmet@0.0.20(@volar/language-service@2.0.0-alpha.3): - resolution: {integrity: sha512-Zm6LN8nuOuvT6/+Owa3CazBsUuwCc5YSJH76I4cPqjjg4bBRWrFvSPuFSOlisrrdJLuYYZFc0eN0pZWzb9udtA==} + /volar-service-emmet@0.0.21(@volar/language-service@2.0.0-alpha.4): + resolution: {integrity: sha512-JWmyZxAyAMU92RcGmwdsxixmO0UHD/n1N75Io4rxH0VxnUbrnbMh+20CCB5RTXJQhnwkINbIxFcHfe4caHWgDg==} peerDependencies: '@volar/language-service': next peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 '@vscode/emmet-helper': 2.9.2 - volar-service-html: 0.0.20(@volar/language-service@2.0.0-alpha.3) + volar-service-html: 0.0.21(@volar/language-service@2.0.0-alpha.4) dev: false - /volar-service-html@0.0.20(@volar/language-service@2.0.0-alpha.3): - resolution: {integrity: sha512-gzEtyDGxqw/avAHBSAFbr5lo8Wta7iUXh/B6O3F9A/CDg96lYjPnMzNVTn0ZIDXCPuygpik6hzG8srAjCAR0JA==} + /volar-service-html@0.0.21(@volar/language-service@2.0.0-alpha.4): + resolution: {integrity: sha512-bDZoOOwrF+IJw79qxMMeArrBR/FvxP4Lb15aAP9g3hpTcbvoUMatTuGauzMTsBbz+qt+Ae75zM+1xRmOEWfUqw==} peerDependencies: '@volar/language-service': next peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 vscode-html-languageservice: 5.1.1 vscode-uri: 3.0.8 dev: false - /volar-service-json@0.0.20(@volar/language-service@2.0.0-alpha.3): - resolution: {integrity: sha512-LDo9+Nh/DRewHdlQxOEsEV0CmFPZAhe8FKTJ9nEjg+9h+Z+fFYlL+qLHBiU6inqO157NjxGvTUzDC1MITqHiFw==} + /volar-service-json@0.0.21(@volar/language-service@2.0.0-alpha.4): + resolution: {integrity: sha512-3ee+WKaQuvwJYtMZhOj066boVKJEhwjHLaDBqo/AooCQWLuetr7tA8mBQMr85qMhwRy878+ABI31BmYGnIpALQ==} peerDependencies: '@volar/language-service': next peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 vscode-json-languageservice: 5.3.7 vscode-uri: 3.0.8 dev: false - /volar-service-pug-beautify@0.0.20(@volar/language-service@2.0.0-alpha.3): - resolution: {integrity: sha512-fXEQmHAO6naobEqezOFMT3GkWC+hHih5quXQ4XR4o4lzAXcnQYq0CUlWsI6k5IBMOTzNA16lKtyPeZ4arrMfyQ==} + /volar-service-pug-beautify@0.0.21(@volar/language-service@2.0.0-alpha.4): + resolution: {integrity: sha512-dZ3gi+Y+fTBQhxUcfYIs/d5ooCWUTGw0Iqrs50Qk0HGk5yHCIbvnn4XTsg2CsNXP4U5qL481i/KUKD5VHIxk9Q==} peerDependencies: '@volar/language-service': next peerDependenciesMeta: @@ -5300,33 +5297,33 @@ packages: optional: true dependencies: '@johnsoncodehk/pug-beautify': 0.2.2 - '@volar/language-service': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 dev: false - /volar-service-pug@0.0.20: - resolution: {integrity: sha512-TKasPbPffPn+z57VCdiPYiIJM5TDsdt2lQgBp+ko0rohYg/CqTnLRdow51xG3KeUTBKgVUH+BLm/OqIBwRNzDw==} + /volar-service-pug@0.0.21: + resolution: {integrity: sha512-Y4D1kG2VCRDWcmenHcVFsSrm1qY1qo71xyiT5NQg6rPz2Begg+n6wt/6WXqki3a2fLZHrYAqufX2phGtiif3yg==} dependencies: - '@volar/language-service': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 pug-lexer: 5.0.1 pug-parser: 6.0.0 - volar-service-html: 0.0.20(@volar/language-service@2.0.0-alpha.3) + volar-service-html: 0.0.21(@volar/language-service@2.0.0-alpha.4) vscode-html-languageservice: 5.1.1 vscode-languageserver-textdocument: 1.0.11 dev: false - /volar-service-typescript-twoslash-queries@0.0.20(@volar/language-service@2.0.0-alpha.3): - resolution: {integrity: sha512-cFYhconxEQ3at5/CAyxrjkI1jQkuR8ooAm4Z8gdAhge/qBtC64HkeRcjLRYa7KhpwnVuAfahfQYaa/CUarVV1w==} + /volar-service-typescript-twoslash-queries@0.0.21(@volar/language-service@2.0.0-alpha.4): + resolution: {integrity: sha512-ZrqkbUkDKSv8euHmqVfGgrchpdXMIX0V3+tj1xzd3d5PSMnZI+tqV+dIseAb7XF3eEjO+JInBGnsccwp6t5+Ow==} peerDependencies: '@volar/language-service': next peerDependenciesMeta: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 dev: false - /volar-service-typescript@0.0.20(@volar/language-service@2.0.0-alpha.3)(@volar/typescript@2.0.0-alpha.3): - resolution: {integrity: sha512-7HNalHrkB1BUQI3x/RyQatUFw7QiuqueqFS1TFoUmnfKPL1r7lda6J83397u3GPI14ZfirFhFoafzYoYSVPS8A==} + /volar-service-typescript@0.0.21(@volar/language-service@2.0.0-alpha.4)(@volar/typescript@2.0.0-alpha.4): + resolution: {integrity: sha512-5IGcQxdXPmqCwwZxpy3nWw7hA3/5pRuKsWGJaWI7KsydZB8oqmJmdozX4rr/uLl5kdu5+ceQOmnUghl0IWM0WQ==} peerDependencies: '@volar/language-service': next '@volar/typescript': next @@ -5334,8 +5331,8 @@ packages: '@volar/language-service': optional: true dependencies: - '@volar/language-service': 2.0.0-alpha.3 - '@volar/typescript': 2.0.0-alpha.3 + '@volar/language-service': 2.0.0-alpha.4 + '@volar/typescript': 2.0.0-alpha.4 path-browserify: 1.0.1 semver: 7.5.4 typescript-auto-import-cache: 0.3.0 diff --git a/test-workspace/tsc/petite-vue/tsconfig.json b/test-workspace/tsc/petite-vue/tsconfig.json deleted file mode 100644 index 8042a1b1e8..0000000000 --- a/test-workspace/tsc/petite-vue/tsconfig.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": "../../tsconfig.json", - "include": [ - "**/*", - ], -}