Skip to content

Commit

Permalink
refactor(tsc): rework based on first-party TS API (#3795)
Browse files Browse the repository at this point in the history
  • Loading branch information
johnsoncodehk committed Dec 21, 2023
1 parent 519f768 commit 2bcd145
Show file tree
Hide file tree
Showing 25 changed files with 287 additions and 541 deletions.
10 changes: 1 addition & 9 deletions extensions/vscode/src/common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,14 +70,6 @@ async function doActivate(context: vscode.ExtensionContext, createLc: CreateLang
// doctor.register(context, client);
// componentMeta.register(context, client);

const supportedLanguages: Record<string, boolean> = {
vue: true,
markdown: true,
javascript: true,
typescript: true,
javascriptreact: true,
typescriptreact: true,
};
const selectors: vscode.DocumentFilter[] = [{ language: 'vue' }];

if (config.server.petiteVue.supportHtmlFile) {
Expand All @@ -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);

Expand Down
7 changes: 3 additions & 4 deletions extensions/vscode/src/nodeClientMain.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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, (
Expand Down Expand Up @@ -110,7 +109,7 @@ export async function activate(context: vscode.ExtensionContext) {
);
client.start();

languageClients.push(client);
languageClient = client;

updateProviders(client);

Expand Down Expand Up @@ -149,7 +148,7 @@ export async function activate(context: vscode.ExtensionContext) {
volarLabs: {
version: supportLabsVersion,
codegenStackSupport: true,
languageClients,
languageClient: languageClient!,
languageServerProtocol: serverLib,
},
} satisfies ExportsInfoForLabs;
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down
4 changes: 1 addition & 3 deletions packages/component-meta/src/base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/language-core/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions packages/language-core/src/generators/script.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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: [],
Expand Down Expand Up @@ -1013,7 +1013,7 @@ type __VLS_NormalizeEmits<T> = __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,
Expand Down
12 changes: 6 additions & 6 deletions packages/language-core/src/generators/template.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 [');
Expand Down Expand Up @@ -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;
}
Expand Down Expand Up @@ -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;
}
Expand Down
20 changes: 13 additions & 7 deletions packages/language-core/src/parsers/scriptRanges.ts
Original file line number Diff line number Diff line change
@@ -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<typeof parseScriptRanges> { }

Expand All @@ -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;
}

Expand All @@ -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;
}
}
Expand All @@ -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;
}
}
61 changes: 37 additions & 24 deletions packages/language-core/src/parsers/scriptSetupRanges.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ export function parseScriptSetupRanges(
define?: ReturnType<typeof parseDefineFunction>;
} = {};

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;
Expand All @@ -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
Expand All @@ -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,
Expand All @@ -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 & {
Expand All @@ -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;
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down Expand Up @@ -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)) {
Expand All @@ -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;
Expand All @@ -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]);
Expand All @@ -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();
Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand All @@ -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));
}
// { ? } = ...
// [ ? ] = ...
Expand All @@ -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));
}
// { ...? } = ...
// [ ...? ] = ...
Expand All @@ -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);
}
Loading

0 comments on commit 2bcd145

Please sign in to comment.