Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sync framework 1.7 #3248

Merged
merged 16 commits into from Jun 7, 2023
2 changes: 1 addition & 1 deletion .vscode/launch.json
Expand Up @@ -8,7 +8,7 @@
"request": "launch",
"runtimeExecutable": "${execPath}",
"args": [
"--disable-extensions",
// "--disable-extensions",
"--extensionDevelopmentPath=${workspaceRoot}/packages/vscode-vue"
],
"outFiles": [
Expand Down
10 changes: 5 additions & 5 deletions package.json
Expand Up @@ -22,14 +22,14 @@
},
"devDependencies": {
"@types/node": "latest",
"@volar/language-service": "1.6.9",
"typescript": "latest",
"@volar/language-service": "1.7.2",
"typescript": "~5.0.4",
"vite": "latest",
"vitest": "latest"
"vitest": "latest",
"vscode-languageserver-protocol": "^3.17.3"
},
"optionalDependencies": {
"@lerna-lite/cli": "latest",
"@lerna-lite/publish": "latest",
"opencc": "latest"
"@lerna-lite/publish": "latest"
}
}
3 changes: 2 additions & 1 deletion packages/typescript-vue-plugin/package.json
Expand Up @@ -14,6 +14,7 @@
},
"dependencies": {
"@vue/language-core": "1.7.8",
"@vue/typescript": "1.7.8"
"@vue/typescript": "1.7.8",
"vscode-uri": "^3.0.7"
}
}
60 changes: 47 additions & 13 deletions packages/typescript-vue-plugin/src/index.ts
@@ -1,6 +1,9 @@
import * as vue from '@vue/language-core';
import * as vueTs from '@vue/typescript';
import type * as ts from 'typescript/lib/tsserverlibrary';
import { URI } from 'vscode-uri';
import type { FileType } from '@volar/language-service';
import * as fs from 'fs';

const init: ts.server.PluginModuleFactory = (modules) => {
const { typescript: ts } = modules;
Expand Down Expand Up @@ -35,29 +38,60 @@ const init: ts.server.PluginModuleFactory = (modules) => {
};
}

const vueTsLsHost: vue.LanguageServiceHost = {
getNewLine: () => info.project.getNewLine(),
useCaseSensitiveFileNames: () => info.project.useCaseSensitiveFileNames(),
readFile: path => info.project.readFile(path),
writeFile: (path, content) => info.project.writeFile(path, content),
fileExists: path => info.project.fileExists(path),
directoryExists: path => info.project.directoryExists(path),
getDirectories: path => info.project.getDirectories(path),
readDirectory: (path, extensions, exclude, include, depth) => info.project.readDirectory(path, extensions, exclude, include, depth),
realpath: info.project.realpath ? path => info.project.realpath!(path) : undefined,
const vueTsLsHost: vue.TypeScriptLanguageHost = {
getCompilationSettings: () => info.project.getCompilationSettings(),
getCurrentDirectory: () => info.project.getCurrentDirectory(),
getDefaultLibFileName: () => info.project.getDefaultLibFileName(),
getProjectVersion: () => info.project.getProjectVersion(),
getProjectReferences: () => info.project.getProjectReferences(),
getScriptFileNames: () => [
...info.project.getScriptFileNames(),
...vueFileNames,
],
getScriptVersion: (fileName) => info.project.getScriptVersion(fileName),
getScriptSnapshot: (fileName) => info.project.getScriptSnapshot(fileName),
};
const vueTsLs = vueTs.createLanguageService(vueTsLsHost, parsed.vueOptions, ts);
const uriToFileName = (uri: string) => URI.parse(uri).fsPath.replace(/\\/g, '/');
const fileNameToUri = (fileName: string) => URI.file(fileName).toString();
const vueTsLs = vueTs.createLanguageService(vueTsLsHost, parsed.vueOptions, ts, {
uriToFileName,
fileNameToUri,
rootUri: URI.parse(fileNameToUri(vueTsLsHost.getCurrentDirectory())),
fs: {
stat(uri) {
if (uri.startsWith('file://')) {
const stats = fs.statSync(uriToFileName(uri), { throwIfNoEntry: false });
if (stats) {
return {
type: stats.isFile() ? 1 satisfies FileType.File
: stats.isDirectory() ? 2 satisfies FileType.Directory
: stats.isSymbolicLink() ? 64 satisfies FileType.SymbolicLink
: 0 satisfies FileType.Unknown,
ctime: stats.ctimeMs,
mtime: stats.mtimeMs,
size: stats.size,
};
}
}
},
readFile(uri, encoding) {
if (uri.startsWith('file://')) {
return fs.readFileSync(uriToFileName(uri), { encoding: encoding as 'utf-8' ?? 'utf-8' });
}
},
readDirectory(uri) {
if (uri.startsWith('file://')) {
const dirName = uriToFileName(uri);
const files = fs.existsSync(dirName) ? fs.readdirSync(dirName, { withFileTypes: true }) : [];
return files.map<[string, FileType]>(file => {
return [file.name, file.isFile() ? 1 satisfies FileType.File
: file.isDirectory() ? 2 satisfies FileType.Directory
: file.isSymbolicLink() ? 64 satisfies FileType.SymbolicLink
: 0 satisfies FileType.Unknown];
});
}
return [];
},
},
});

return new Proxy(info.languageService, {
get: (target: any, property: keyof ts.LanguageService) => {
Expand Down
2 changes: 1 addition & 1 deletion packages/vscode-vue/package.json
Expand Up @@ -732,7 +732,7 @@
"devDependencies": {
"@types/semver": "^7.3.13",
"@types/vscode": "1.67.0",
"@volar/vscode": "1.6.9",
"@volar/vscode": "1.7.2",
"@vue/language-server": "1.7.8",
"esbuild": "0.15.18",
"esbuild-plugin-copy": "latest",
Expand Down
2 changes: 1 addition & 1 deletion packages/vscode-vue/src/common.ts
Expand Up @@ -134,7 +134,7 @@ async function doActivate(context: vscode.ExtensionContext, createLc: CreateLang
);

for (const client of clients) {
activateServerSys(context, client, undefined);
activateServerSys(client);
}

async function requestReloadVscode() {
Expand Down
2 changes: 1 addition & 1 deletion packages/vue-component-meta/package.json
Expand Up @@ -13,7 +13,7 @@
"directory": "packages/vue-component-meta"
},
"dependencies": {
"@volar/typescript": "1.6.9",
"@volar/typescript": "1.7.2",
"@vue/language-core": "1.7.8",
"typesafe-path": "^0.2.2",
"vue-component-type-helpers": "1.7.8"
Expand Down
54 changes: 24 additions & 30 deletions packages/vue-component-meta/src/index.ts
Expand Up @@ -25,10 +25,12 @@ export function createComponentMetaCheckerByJsonConfig(
checkerOptions: MetaCheckerOptions = {},
ts: typeof import('typescript/lib/tsserverlibrary') = require('typescript'),
) {
const rootPath = (root as path.OsPath).replace(/\\/g, '/') as path.PosixPath;
return createComponentMetaCheckerWorker(
() => vue.createParsedCommandLineByJson(ts, ts.sys, root, json),
checkerOptions,
path.join((root as path.OsPath).replace(/\\/g, '/') as path.PosixPath, 'jsconfig.json.global.vue' as path.PosixPath),
rootPath,
path.join(rootPath, 'jsconfig.json.global.vue' as path.PosixPath),
ts,
);
}
Expand All @@ -38,17 +40,20 @@ export function createComponentMetaChecker(
checkerOptions: MetaCheckerOptions = {},
ts: typeof import('typescript/lib/tsserverlibrary') = require('typescript'),
) {
const tsconfig = (tsconfigPath as path.OsPath).replace(/\\/g, '/') as path.PosixPath;
return createComponentMetaCheckerWorker(
() => vue.createParsedCommandLine(ts, ts.sys, tsconfigPath),
checkerOptions,
(tsconfigPath as path.OsPath).replace(/\\/g, '/') as path.PosixPath + '.global.vue',
path.dirname(tsconfig),
tsconfig + '.global.vue',
ts,
);
}

function createComponentMetaCheckerWorker(
loadParsedCommandLine: () => vue.ParsedCommandLine,
checkerOptions: MetaCheckerOptions,
rootPath: string,
globalComponentName: string,
ts: typeof import('typescript/lib/tsserverlibrary'),
) {
Expand All @@ -62,16 +67,12 @@ function createComponentMetaCheckerWorker(
let projectVersion = 0;

const scriptSnapshots = new Map<string, ts.IScriptSnapshot>();
const scriptVersions = new Map<string, number>();
const _host: vue.LanguageServiceHost = {
...ts.sys,
getProjectVersion: () => projectVersion.toString(),
getDefaultLibFileName: (options) => ts.getDefaultLibFilePath(options), // should use ts.getDefaultLibFilePath not ts.getDefaultLibFileName
useCaseSensitiveFileNames: () => ts.sys.useCaseSensitiveFileNames,
const _host: vue.TypeScriptLanguageHost = {
getCurrentDirectory: () => rootPath,
getProjectVersion: () => projectVersion,
getCompilationSettings: () => parsedCommandLine.options,
getScriptFileNames: () => fileNames,
getProjectReferences: () => parsedCommandLine.projectReferences,
getScriptVersion: (fileName) => scriptVersions.get(fileName)?.toString() ?? '',
getScriptSnapshot: (fileName) => {
if (!scriptSnapshots.has(fileName)) {
const fileText = ts.sys.readFile(fileName);
Expand All @@ -88,7 +89,6 @@ function createComponentMetaCheckerWorker(
updateFile(fileName: string, text: string) {
fileName = (fileName as path.OsPath).replace(/\\/g, '/') as path.PosixPath;
scriptSnapshots.set(fileName, ts.ScriptSnapshot.fromString(text));
scriptVersions.set(fileName, scriptVersions.has(fileName) ? scriptVersions.get(fileName)! + 1 : 1);
projectVersion++;
},
deleteFile(fileName: string) {
Expand All @@ -103,14 +103,13 @@ function createComponentMetaCheckerWorker(
},
clearCache() {
scriptSnapshots.clear();
scriptVersions.clear();
projectVersion++;
},
};
}

export function baseCreate(
_host: vue.LanguageServiceHost,
_host: vue.TypeScriptLanguageHost,
_vueCompilerOptions: Partial<vue.VueCompilerOptions>,
checkerOptions: MetaCheckerOptions,
globalComponentName: string,
Expand All @@ -119,7 +118,7 @@ export function baseCreate(
const vueCompilerOptions = vue.resolveVueCompilerOptions(_vueCompilerOptions);
const globalComponentSnapshot = ts.ScriptSnapshot.fromString('<script setup lang="ts"></script>');
const metaSnapshots: Record<string, ts.IScriptSnapshot> = {};
const host = new Proxy<Partial<vue.LanguageServiceHost>>({
const host = new Proxy<Partial<vue.TypeScriptLanguageHost>>({
getScriptFileNames: () => {
const names = _host.getScriptFileNames();
return [
Expand Down Expand Up @@ -150,33 +149,28 @@ export function baseCreate(
}
return _host[prop as keyof typeof _host];
},
}) as vue.LanguageServiceHost;
}) as vue.TypeScriptLanguageHost;
const vueLanguages = ts ? vue.createLanguages(
host.getCompilationSettings(),
vueCompilerOptions,
ts,
) : [];
const proxyApis: Partial<ts.LanguageServiceHost> = checkerOptions.forceUseTs ? {
getScriptKind: (fileName) => {
const core = vue.createLanguageContext(host, vueLanguages);
const tsLs = createLanguageService(core, ts, ts.sys);

if (checkerOptions.forceUseTs) {
const getScriptKind = tsLs.__internal__.languageServiceHost.getScriptKind;
tsLs.__internal__.languageServiceHost.getScriptKind = (fileName) => {
if (fileName.endsWith('.vue.js')) {
return ts.ScriptKind.TS;
}
if (fileName.endsWith('.vue.jsx')) {
return ts.ScriptKind.TSX;
}
return host.getScriptKind!(fileName);
},
} : {};
const proxyHost = new Proxy(host, {
get(target, propKey: keyof ts.LanguageServiceHost) {
if (propKey in proxyApis) {
return proxyApis[propKey];
}
return target[propKey];
}
});
const core = vue.createLanguageContext(proxyHost, vueLanguages);
const tsLs = createLanguageService(core, ts);
return getScriptKind!(fileName);
};
}

let globalPropNames: string[] | undefined;

return {
Expand Down Expand Up @@ -626,7 +620,7 @@ function createSchemaResolvers(
const [virtualFile] = core.virtualFiles.getVirtualFile(fileName);
if (virtualFile) {
const maps = core.virtualFiles.getMaps(virtualFile);
for (const [source, map] of maps) {
for (const [source, [_, map]] of maps) {
const start = map.toSourceOffset(declaration.getStart());
const end = map.toSourceOffset(declaration.getEnd());
if (start && end) {
Expand Down
4 changes: 2 additions & 2 deletions packages/vue-language-core/package.json
Expand Up @@ -13,8 +13,8 @@
"directory": "packages/vue-language-core"
},
"dependencies": {
"@volar/language-core": "1.6.9",
"@volar/source-map": "1.6.9",
"@volar/language-core": "1.7.2",
"@volar/source-map": "1.7.2",
"@vue/compiler-dom": "^3.3.0",
"@vue/reactivity": "^3.3.0",
"@vue/shared": "^3.3.0",
Expand Down
2 changes: 1 addition & 1 deletion packages/vue-language-core/src/generators/template.ts
Expand Up @@ -838,7 +838,7 @@ export function generate(
'default',
'template',
[slotDir.loc.start.offset, slotDir.loc.start.offset + (slotDir.loc.source.startsWith('#') ? '#'.length : slotDir.loc.source.startsWith('v-slot:') ? 'v-slot:'.length : 0)],
capabilitiesPresets.slotName,
{ ...capabilitiesPresets.slotName, completion: false },
])
),
['', 'template', (slotDir.arg ?? slotDir).loc.end.offset, capabilitiesPresets.diagnosticOnly],
Expand Down
28 changes: 7 additions & 21 deletions packages/vue-language-core/src/languageModule.ts
Expand Up @@ -12,7 +12,7 @@ export function createLanguage(
_vueCompilerOptions: Partial<VueCompilerOptions> = {},
ts: typeof import('typescript/lib/tsserverlibrary') = require('typescript'),
codegenStack: boolean = false,
): Language {
) {

const vueCompilerOptions = resolveVueCompilerOptions(_vueCompilerOptions);

Expand All @@ -24,8 +24,7 @@ export function createLanguage(
vueCompilerOptions,
codegenStack,
);
const sharedTypesSnapshot = ts.ScriptSnapshot.fromString(sharedTypes.getTypesCode(vueCompilerOptions));
const languageModule: Language = {
const languageModule: Language<VueFile> = {
createVirtualFile(fileName, snapshot, languageId) {
if (
languageId === 'vue'
Expand All @@ -37,35 +36,22 @@ export function createLanguage(
return new VueFile(fileName, snapshot, vueCompilerOptions, vueLanguagePlugin, ts, codegenStack);
}
},
updateVirtualFile(sourceFile: VueFile, snapshot) {
updateVirtualFile(sourceFile, snapshot) {
sourceFile.update(snapshot);
},
resolveHost(host) {
const sharedTypesSnapshot = ts.ScriptSnapshot.fromString(sharedTypes.getTypesCode(vueCompilerOptions));
const sharedTypesFileName = path.join(host.getCurrentDirectory(), sharedTypes.baseName);
return {
...host,
fileExists(fileName) {
const basename = path.basename(fileName);
if (basename === sharedTypes.baseName) {
return true;
}
return host.fileExists(fileName);
},
getScriptFileNames() {
return [
path.join(host.getCurrentDirectory(), sharedTypes.baseName),
sharedTypesFileName,
...host.getScriptFileNames(),
];
},
getScriptVersion(fileName) {
const basename = path.basename(fileName);
if (basename === sharedTypes.baseName) {
return '';
}
return host.getScriptVersion(fileName);
},
getScriptSnapshot(fileName) {
const basename = path.basename(fileName);
if (basename === sharedTypes.baseName) {
if (fileName === sharedTypesFileName) {
return sharedTypesSnapshot;
}
return host.getScriptSnapshot(fileName);
Expand Down
7 changes: 3 additions & 4 deletions packages/vue-language-core/src/utils/ts.ts
Expand Up @@ -13,9 +13,8 @@ export function createParsedCommandLineByJson(
json: any,
): ParsedCommandLine {

const tsConfigPath = path.join(rootDir, 'jsconfig.json');
const proxyHost = proxyParseConfigHostForExtendConfigPaths(parseConfigHost);
ts.parseJsonConfigFileContent(json, proxyHost.host, rootDir, {}, tsConfigPath);
ts.parseJsonConfigFileContent(json, proxyHost.host, rootDir, {}, rootDir + '/jsconfig.json');

let vueOptions: Partial<VueCompilerOptions> = {};

Expand All @@ -31,9 +30,9 @@ export function createParsedCommandLineByJson(
const parsed = ts.parseJsonConfigFileContent(
json,
proxyHost.host,
path.dirname(tsConfigPath),
rootDir,
{},
tsConfigPath,
rootDir + '/jsconfig.json',
undefined,
(vueOptions.extensions ?? ['.vue']).map(extension => ({
extension: extension.slice(1),
Expand Down