202 lines
8.8 KiB
Plaintext
202 lines
8.8 KiB
Plaintext
|
"use strict";
|
||
|
Object.defineProperty(exports, "__esModule", { value: true });
|
||
|
exports.createProject = void 0;
|
||
|
const language_service_1 = require("@volar/language-service");
|
||
|
const path = require("path-browserify");
|
||
|
const vscode = require("vscode-languageserver");
|
||
|
const serverConfig_1 = require("./utils/serverConfig");
|
||
|
const uriMap_1 = require("./utils/uriMap");
|
||
|
const typescript_1 = require("@volar/typescript");
|
||
|
const globalSnapshots = new WeakMap();
|
||
|
async function createProject(context) {
|
||
|
let projectVersion = 0;
|
||
|
let token = context.server.runtimeEnv.getCancellationToken();
|
||
|
let languageService;
|
||
|
const tsToken = {
|
||
|
isCancellationRequested() {
|
||
|
return token.isCancellationRequested;
|
||
|
},
|
||
|
throwIfCancellationRequested() { },
|
||
|
};
|
||
|
const { uriToFileName, fileNameToUri, fs } = context.server.runtimeEnv;
|
||
|
const env = {
|
||
|
uriToFileName,
|
||
|
fileNameToUri,
|
||
|
fs,
|
||
|
console: context.server.runtimeEnv.console,
|
||
|
locale: context.workspaces.initParams.locale,
|
||
|
workspaceUri: context.project.workspaceUri,
|
||
|
rootUri: context.project.rootUri,
|
||
|
clientCapabilities: context.workspaces.initParams.capabilities,
|
||
|
getConfiguration: context.server.configurationHost?.getConfiguration,
|
||
|
onDidChangeConfiguration: context.server.configurationHost?.onDidChangeConfiguration,
|
||
|
onDidChangeWatchedFiles: context.server.onDidChangeWatchedFiles,
|
||
|
};
|
||
|
if (!globalSnapshots.has(fs)) {
|
||
|
globalSnapshots.set(fs, (0, uriMap_1.createUriMap)(fileNameToUri));
|
||
|
}
|
||
|
const askedFiles = (0, uriMap_1.createUriMap)(fileNameToUri);
|
||
|
const languageHost = {
|
||
|
workspacePath: uriToFileName(context.project.workspaceUri.toString()),
|
||
|
rootPath: uriToFileName(context.project.rootUri.toString()),
|
||
|
getProjectVersion: () => projectVersion.toString(),
|
||
|
getScriptFileNames: () => parsedCommandLine.fileNames,
|
||
|
getScriptSnapshot: (fileName) => {
|
||
|
askedFiles.pathSet(fileName, true);
|
||
|
const doc = context.workspaces.documents.data.pathGet(fileName);
|
||
|
if (doc) {
|
||
|
return doc.getSnapshot();
|
||
|
}
|
||
|
const fsSnapshot = globalSnapshots.get(fs).pathGet(fileName);
|
||
|
if (fsSnapshot) {
|
||
|
return fsSnapshot;
|
||
|
}
|
||
|
},
|
||
|
getLanguageId: (fileName) => context.workspaces.documents.data.pathGet(fileName)?.languageId,
|
||
|
getCancellationToken: () => tsToken,
|
||
|
getCompilationSettings: () => parsedCommandLine.options,
|
||
|
getLocalizedDiagnosticMessages: context.workspaces.tsLocalized ? () => context.workspaces.tsLocalized : undefined,
|
||
|
getProjectReferences: () => parsedCommandLine.projectReferences,
|
||
|
};
|
||
|
const docChangeWatcher = context.workspaces.documents.onDidChangeContent(() => {
|
||
|
projectVersion++;
|
||
|
token = context.server.runtimeEnv.getCancellationToken();
|
||
|
});
|
||
|
const fileWatch = env.onDidChangeWatchedFiles?.(params => {
|
||
|
onWorkspaceFilesChanged(params.changes);
|
||
|
});
|
||
|
let existingOptions;
|
||
|
for (const plugin of context.workspaces.plugins) {
|
||
|
if (plugin.resolveExistingOptions) {
|
||
|
existingOptions = plugin.resolveExistingOptions(existingOptions);
|
||
|
}
|
||
|
}
|
||
|
let parsedCommandLine = await createParsedCommandLine(context.workspaces.ts, env, uriToFileName(context.project.rootUri.toString()), context.project.tsConfig, context.workspaces.plugins, existingOptions);
|
||
|
let config = (context.project.workspaceUri.scheme === 'file' ? (0, serverConfig_1.loadConfig)(context.server.runtimeEnv.console, context.server.runtimeEnv.uriToFileName(context.project.workspaceUri.toString()), context.workspaces.initOptions.configFilePath) : {}) ?? {};
|
||
|
for (const plugin of context.workspaces.plugins) {
|
||
|
if (plugin.resolveConfig) {
|
||
|
config = await plugin.resolveConfig(config, {
|
||
|
...context,
|
||
|
env,
|
||
|
host: languageHost,
|
||
|
});
|
||
|
}
|
||
|
}
|
||
|
await syncRootScriptSnapshots();
|
||
|
return {
|
||
|
context,
|
||
|
tsConfig: context.project.tsConfig,
|
||
|
languageHost,
|
||
|
getLanguageService,
|
||
|
getLanguageServiceDontCreate: () => languageService,
|
||
|
getParsedCommandLine: () => parsedCommandLine,
|
||
|
tryAddFile: (fileName) => {
|
||
|
if (!parsedCommandLine.fileNames.includes(fileName)) {
|
||
|
parsedCommandLine.fileNames.push(fileName);
|
||
|
projectVersion++;
|
||
|
token = context.server.runtimeEnv.getCancellationToken();
|
||
|
}
|
||
|
},
|
||
|
askedFiles,
|
||
|
dispose,
|
||
|
};
|
||
|
function getLanguageService() {
|
||
|
if (!languageService) {
|
||
|
languageService = (0, language_service_1.createLanguageService)({ typescript: context.workspaces.ts }, env, config, languageHost);
|
||
|
}
|
||
|
return languageService;
|
||
|
}
|
||
|
async function syncRootScriptSnapshots() {
|
||
|
const promises = [];
|
||
|
let dirty = false;
|
||
|
for (const fileName of parsedCommandLine.fileNames) {
|
||
|
const uri = fileNameToUri(fileName);
|
||
|
if (!globalSnapshots.get(fs).uriGet(uri)) {
|
||
|
dirty = true;
|
||
|
promises.push(updateRootScriptSnapshot(uri));
|
||
|
}
|
||
|
}
|
||
|
await Promise.all(promises);
|
||
|
return dirty;
|
||
|
}
|
||
|
async function updateRootScriptSnapshot(uri) {
|
||
|
const text = await context.server.runtimeEnv.fs.readFile(uri);
|
||
|
globalSnapshots.get(fs).uriSet(uri, text !== undefined ? {
|
||
|
getText: (start, end) => text.substring(start, end),
|
||
|
getLength: () => text.length,
|
||
|
getChangeRange: () => undefined,
|
||
|
} : undefined);
|
||
|
}
|
||
|
async function onWorkspaceFilesChanged(changes) {
|
||
|
const oldProjectVersion = projectVersion;
|
||
|
const creates = changes.filter(change => change.type === vscode.FileChangeType.Created);
|
||
|
if (creates.length) {
|
||
|
parsedCommandLine = await createParsedCommandLine(context.workspaces.ts, env, uriToFileName(context.project.rootUri.toString()), context.project.tsConfig, context.workspaces.plugins, existingOptions);
|
||
|
if (await syncRootScriptSnapshots()) {
|
||
|
projectVersion++;
|
||
|
}
|
||
|
}
|
||
|
await Promise.all(changes.map(async (change) => {
|
||
|
if (askedFiles.uriGet(change.uri) && globalSnapshots.get(fs).uriGet(change.uri)) {
|
||
|
if (change.type === vscode.FileChangeType.Changed) {
|
||
|
await updateRootScriptSnapshot(change.uri);
|
||
|
}
|
||
|
else if (change.type === vscode.FileChangeType.Deleted) {
|
||
|
globalSnapshots.get(fs).uriSet(change.uri, undefined);
|
||
|
}
|
||
|
projectVersion++;
|
||
|
}
|
||
|
}));
|
||
|
if (oldProjectVersion !== projectVersion) {
|
||
|
token = context.server.runtimeEnv.getCancellationToken();
|
||
|
}
|
||
|
}
|
||
|
function dispose() {
|
||
|
languageService?.dispose();
|
||
|
fileWatch?.dispose();
|
||
|
docChangeWatcher.dispose();
|
||
|
}
|
||
|
}
|
||
|
exports.createProject = createProject;
|
||
|
async function createParsedCommandLine(ts, env, rootPath, tsConfig, plugins, existingOptions) {
|
||
|
const extraFileExtensions = plugins.map(plugin => plugin.extraFileExtensions ?? []).flat();
|
||
|
if (ts) {
|
||
|
const sys = (0, typescript_1.createSys)(ts, {
|
||
|
...env,
|
||
|
onDidChangeWatchedFiles: undefined,
|
||
|
});
|
||
|
let content;
|
||
|
let sysVersion;
|
||
|
let newSysVersion = await sys.sync();
|
||
|
while (sysVersion !== newSysVersion) {
|
||
|
sysVersion = newSysVersion;
|
||
|
try {
|
||
|
if (typeof tsConfig === 'string') {
|
||
|
const config = ts.readJsonConfigFile(tsConfig, sys.readFile);
|
||
|
content = ts.parseJsonSourceFileConfigFileContent(config, sys, path.dirname(tsConfig), existingOptions, tsConfig, undefined, extraFileExtensions);
|
||
|
}
|
||
|
else {
|
||
|
content = ts.parseJsonConfigFileContent({ files: [] }, sys, rootPath, { ...tsConfig, ...existingOptions }, rootPath + '/jsconfig.json', undefined, extraFileExtensions);
|
||
|
}
|
||
|
// fix https://github.com/johnsoncodehk/volar/issues/1786
|
||
|
// https://github.com/microsoft/TypeScript/issues/30457
|
||
|
// patching ts server broke with outDir + rootDir + composite/incremental
|
||
|
content.options.outDir = undefined;
|
||
|
content.fileNames = content.fileNames.map(fileName => fileName.replace(/\\/g, '/'));
|
||
|
}
|
||
|
catch {
|
||
|
// will be failed if web fs host first result not ready
|
||
|
}
|
||
|
newSysVersion = await sys.sync();
|
||
|
}
|
||
|
if (content) {
|
||
|
return content;
|
||
|
}
|
||
|
}
|
||
|
return {
|
||
|
errors: [],
|
||
|
fileNames: [],
|
||
|
options: {},
|
||
|
};
|
||
|
}
|
||
|
//# sourceMappingURL=project.js.map
|