@volar/language-server
Advanced tools
Comparing version 2.4.0 to 2.4.1
@@ -34,2 +34,5 @@ import * as vscode from 'vscode-languageserver/browser'; | ||
has(uri: URI): boolean; | ||
onDidChange: (cb: vscode.NotificationHandler<vscode.WorkspaceFoldersChangeEvent>) => { | ||
dispose(): void; | ||
}; | ||
}; | ||
@@ -51,2 +54,3 @@ fileWatcher: { | ||
}; | ||
env: import("./index").LanguageServerEnvironment; | ||
connection: vscode.Connection; | ||
@@ -53,0 +57,0 @@ onInitialize(callback: (serverCapabilities: vscode.ServerCapabilities<import("./index").ExperimentalFeatures>) => void): void; |
@@ -37,3 +37,9 @@ "use strict"; | ||
function createServer(connection) { | ||
const server = (0, server_1.createServerBase)(connection); | ||
const server = (0, server_1.createServerBase)(connection, { | ||
timer: { | ||
setImmediate: (callback, ...args) => { | ||
setTimeout(callback, 0, ...args); | ||
}, | ||
}, | ||
}); | ||
server.fileSystem.install('http', http_2.provider); | ||
@@ -40,0 +46,0 @@ server.fileSystem.install('https', http_2.provider); |
@@ -690,3 +690,3 @@ "use strict"; | ||
return new Promise(resolve => { | ||
setTimeout(async () => { | ||
server.env.timer.setImmediate(async () => { | ||
if (token.isCancellationRequested) { | ||
@@ -703,3 +703,3 @@ resolve(undefined); | ||
resolve(result); | ||
}, 0); | ||
}); | ||
}); | ||
@@ -706,0 +706,0 @@ } |
@@ -0,1 +1,2 @@ | ||
import * as vscode from 'vscode-languageserver'; | ||
import { URI } from 'vscode-uri'; | ||
@@ -6,2 +7,5 @@ import { LanguageServerState } from '../types'; | ||
has(uri: URI): boolean; | ||
onDidChange: (cb: vscode.NotificationHandler<vscode.WorkspaceFoldersChangeEvent>) => { | ||
dispose(): void; | ||
}; | ||
}; |
@@ -8,2 +8,3 @@ "use strict"; | ||
const folders = (0, language_service_1.createUriMap)(); | ||
const didChangeCallbacks = new Set(); | ||
server.onInitialize(serverCapabilities => { | ||
@@ -32,9 +33,16 @@ const { initializeParams } = server; | ||
server.connection.workspace.onDidChangeWorkspaceFolders(e => { | ||
for (const folder of e.added) { | ||
folders.set(vscode_uri_1.URI.parse(folder.uri), true); | ||
e.added = e.added.filter(folder => !folders.has(vscode_uri_1.URI.parse(folder.uri))); | ||
e.removed = e.removed.filter(folder => folders.has(vscode_uri_1.URI.parse(folder.uri))); | ||
if (e.added.length || e.removed.length) { | ||
for (const folder of e.added) { | ||
folders.set(vscode_uri_1.URI.parse(folder.uri), true); | ||
} | ||
for (const folder of e.removed) { | ||
folders.delete(vscode_uri_1.URI.parse(folder.uri)); | ||
} | ||
server.project.reload(); | ||
for (const cb of didChangeCallbacks) { | ||
cb(e); | ||
} | ||
} | ||
for (const folder of e.removed) { | ||
folders.delete(vscode_uri_1.URI.parse(folder.uri)); | ||
} | ||
server.project.reload(); | ||
}); | ||
@@ -50,4 +58,13 @@ } | ||
}, | ||
onDidChange, | ||
}; | ||
function onDidChange(cb) { | ||
didChangeCallbacks.add(cb); | ||
return { | ||
dispose() { | ||
didChangeCallbacks.delete(cb); | ||
}, | ||
}; | ||
} | ||
} | ||
//# sourceMappingURL=workspaceFolders.js.map |
@@ -91,5 +91,5 @@ "use strict"; | ||
} | ||
await prepareClosestootParsedCommandLine(); | ||
await prepareClosestootCommandLine(); | ||
return await findDirectIncludeTsconfig() ?? await findIndirectReferenceTsconfig(); | ||
async function prepareClosestootParsedCommandLine() { | ||
async function prepareClosestootCommandLine() { | ||
let matches = []; | ||
@@ -103,3 +103,3 @@ for (const rootTsConfig of rootTsConfigs) { | ||
if (matches.length) { | ||
await getParsedCommandLine(matches[0]); | ||
await getCommandLine(matches[0]); | ||
} | ||
@@ -118,4 +118,4 @@ } | ||
const map = (0, language_service_1.createUriMap)(); | ||
const parsedCommandLine = await getParsedCommandLine(tsconfig); | ||
for (const fileName of parsedCommandLine?.fileNames ?? []) { | ||
const commandLine = await getCommandLine(tsconfig); | ||
for (const fileName of commandLine?.fileNames ?? []) { | ||
const uri = uriConverter.asUri(fileName); | ||
@@ -133,3 +133,3 @@ map.set(uri, true); | ||
if (project) { | ||
let chains = await getReferencesChains(project.getParsedCommandLine(), rootTsConfig, []); | ||
let chains = await getReferencesChains(project.getCommandLine(), rootTsConfig, []); | ||
// This is to be consistent with tsserver behavior | ||
@@ -152,6 +152,6 @@ chains = chains.reverse(); | ||
} | ||
async function getReferencesChains(parsedCommandLine, tsConfig, before) { | ||
if (parsedCommandLine.projectReferences?.length) { | ||
async function getReferencesChains(commandLine, tsConfig, before) { | ||
if (commandLine.projectReferences?.length) { | ||
const newChains = []; | ||
for (const projectReference of parsedCommandLine.projectReferences) { | ||
for (const projectReference of commandLine.projectReferences) { | ||
let tsConfigPath = projectReference.path.replace(/\\/g, '/'); | ||
@@ -174,5 +174,5 @@ // fix https://github.com/johnsoncodehk/volar/issues/712 | ||
else { | ||
const referenceParsedCommandLine = await getParsedCommandLine(tsConfigPath); | ||
if (referenceParsedCommandLine) { | ||
for (const chain of await getReferencesChains(referenceParsedCommandLine, tsConfigPath, [...before, tsConfig])) { | ||
const referenceCommandLine = await getCommandLine(tsConfigPath); | ||
if (referenceCommandLine) { | ||
for (const chain of await getReferencesChains(referenceCommandLine, tsConfigPath, [...before, tsConfig])) { | ||
newChains.push(chain); | ||
@@ -189,5 +189,5 @@ } | ||
} | ||
async function getParsedCommandLine(tsConfig) { | ||
async function getCommandLine(tsConfig) { | ||
const project = await getOrCreateConfiguredProject(server, tsConfig); | ||
return project?.getParsedCommandLine(); | ||
return project?.getCommandLine(); | ||
} | ||
@@ -194,0 +194,0 @@ } |
@@ -8,3 +8,3 @@ import { Language, LanguagePlugin, LanguageService, LanguageServiceEnvironment, ProjectContext, ProviderResult } from '@volar/language-service'; | ||
tryAddFile(fileName: string): void; | ||
getParsedCommandLine(): ts.ParsedCommandLine; | ||
getCommandLine(): ts.ParsedCommandLine; | ||
languageService: LanguageService; | ||
@@ -11,0 +11,0 @@ dispose(): void; |
@@ -6,2 +6,3 @@ "use strict"; | ||
const typescript_1 = require("@volar/typescript"); | ||
const utilities_1 = require("@volar/typescript/lib/typescript/utilities"); | ||
const path = require("path-browserify"); | ||
@@ -12,3 +13,3 @@ const vscode = require("vscode-languageserver"); | ||
async function createTypeScriptLS(ts, tsLocalized, tsconfig, server, serviceEnv, workspaceFolder, uriConverter, create) { | ||
let parsedCommandLine; | ||
let commandLine; | ||
let projectVersion = 0; | ||
@@ -23,10 +24,10 @@ const getCurrentDirectory = () => uriConverter.asFileName(workspaceFolder); | ||
getScriptFileNames() { | ||
return rootFiles; | ||
return commandLine.fileNames; | ||
}, | ||
getCompilationSettings() { | ||
return parsedCommandLine.options; | ||
return commandLine.options; | ||
}, | ||
getLocalizedDiagnosticMessages: tsLocalized ? () => tsLocalized : undefined, | ||
getProjectReferences() { | ||
return parsedCommandLine.projectReferences; | ||
return commandLine.projectReferences; | ||
}, | ||
@@ -41,7 +42,39 @@ }; | ||
}); | ||
const docOpenWatcher = server.documents.onDidOpen(({ document }) => updateFsCacheFromSyncedDocument(document)); | ||
const docSaveWatcher = server.documents.onDidSave(({ document }) => updateFsCacheFromSyncedDocument(document)); | ||
const docChangeWatcher = server.documents.onDidChangeContent(() => projectVersion++); | ||
const fileWatch = serviceEnv.onDidChangeWatchedFiles?.(params => onWorkspaceFilesChanged(params.changes)); | ||
let rootFiles = await getRootFiles(languagePlugins); | ||
const unsavedRootFileUris = (0, language_service_1.createUriMap)(); | ||
const disposables = [ | ||
server.documents.onDidOpen(({ document }) => updateFsCacheFromSyncedDocument(document)), | ||
server.documents.onDidSave(({ document }) => updateFsCacheFromSyncedDocument(document)), | ||
server.documents.onDidChangeContent(() => projectVersion++), | ||
serviceEnv.onDidChangeWatchedFiles?.(async ({ changes }) => { | ||
const createdOrDeleted = changes.some(change => change.type !== vscode.FileChangeType.Changed); | ||
if (createdOrDeleted) { | ||
await updateCommandLine(); | ||
} | ||
projectVersion++; | ||
}), | ||
server.documents.onDidOpen(async ({ document }) => { | ||
const uri = vscode_uri_1.URI.parse(document.uri); | ||
const isWorkspaceFile = workspaceFolder.scheme === uri.scheme; | ||
if (!isWorkspaceFile) { | ||
return; | ||
} | ||
const stat = await serviceEnv.fs?.stat(uri); | ||
const isUnsaved = stat?.type !== 1; | ||
if (isUnsaved) { | ||
const lastProjectVersion = projectVersion; | ||
await updateCommandLine(); | ||
if (lastProjectVersion !== projectVersion) { | ||
unsavedRootFileUris.set(uri, true); | ||
} | ||
} | ||
}), | ||
server.documents.onDidClose(async ({ document }) => { | ||
const uri = vscode_uri_1.URI.parse(document.uri); | ||
if (unsavedRootFileUris.has(uri)) { | ||
unsavedRootFileUris.delete(uri); | ||
await updateCommandLine(); | ||
} | ||
}), | ||
].filter(d => !!d); | ||
await updateCommandLine(); | ||
const language = (0, language_service_1.createLanguage)([ | ||
@@ -93,4 +126,4 @@ { getLanguageId: uri => server.documents.get(uri)?.languageId }, | ||
tryAddFile(fileName) { | ||
if (!rootFiles.includes(fileName)) { | ||
rootFiles.push(fileName); | ||
if (!commandLine.fileNames.includes(fileName)) { | ||
commandLine.fileNames.push(fileName); | ||
projectVersion++; | ||
@@ -102,8 +135,6 @@ } | ||
languageService?.dispose(); | ||
fileWatch?.dispose(); | ||
docOpenWatcher.dispose(); | ||
docSaveWatcher.dispose(); | ||
docChangeWatcher.dispose(); | ||
disposables.forEach(({ dispose }) => dispose()); | ||
disposables.length = 0; | ||
}, | ||
getParsedCommandLine: () => parsedCommandLine, | ||
getCommandLine: () => commandLine, | ||
}; | ||
@@ -118,48 +149,91 @@ function updateFsCacheFromSyncedDocument(document) { | ||
} | ||
async function getRootFiles(languagePlugins) { | ||
parsedCommandLine = await createParsedCommandLine(ts, sys, uriConverter.asFileName(workspaceFolder), tsconfig, languagePlugins.map(plugin => plugin.typescript?.extraFileExtensions ?? []).flat()); | ||
return parsedCommandLine.fileNames; | ||
} | ||
async function onWorkspaceFilesChanged(changes) { | ||
const createsAndDeletes = changes.filter(change => change.type !== vscode.FileChangeType.Changed); | ||
if (createsAndDeletes.length) { | ||
rootFiles = await getRootFiles(languagePlugins); | ||
async function updateCommandLine() { | ||
const oldFileNames = new Set(commandLine?.fileNames ?? []); | ||
commandLine = await parseConfig(ts, sys, uriConverter.asFileName(workspaceFolder), tsconfig, languagePlugins.map(plugin => plugin.typescript?.extraFileExtensions ?? []).flat()); | ||
const newFileNames = new Set(commandLine.fileNames); | ||
if (oldFileNames.size !== newFileNames.size || [...oldFileNames].some(fileName => !newFileNames.has(fileName))) { | ||
projectVersion++; | ||
} | ||
projectVersion++; | ||
} | ||
} | ||
async function createParsedCommandLine(ts, sys, workspacePath, tsconfig, extraFileExtensions) { | ||
let content = { | ||
errors: [], | ||
fileNames: [], | ||
options: {}, | ||
}; | ||
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), {}, tsconfig, undefined, extraFileExtensions); | ||
async function parseConfig(ts, sys, workspacePath, tsconfig, extraFileExtensions) { | ||
let commandLine = { | ||
errors: [], | ||
fileNames: [], | ||
options: {}, | ||
}; | ||
let sysVersion; | ||
let newSysVersion = await sys.sync(); | ||
while (sysVersion !== newSysVersion) { | ||
sysVersion = newSysVersion; | ||
try { | ||
commandLine = await parseConfigWorker(ts, sys, workspacePath, tsconfig, extraFileExtensions); | ||
} | ||
else { | ||
content = ts.parseJsonConfigFileContent({ files: [] }, sys, workspacePath, tsconfig, workspacePath + '/jsconfig.json', undefined, extraFileExtensions); | ||
catch { | ||
// will be failed if web fs host first result not ready | ||
} | ||
// 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, '/')); | ||
newSysVersion = await sys.sync(); | ||
} | ||
catch { | ||
// will be failed if web fs host first result not ready | ||
return commandLine; | ||
} | ||
function parseConfigWorker(ts, _host, workspacePath, tsconfig, extraFileExtensions) { | ||
let content = { | ||
errors: [], | ||
fileNames: [], | ||
options: {}, | ||
}; | ||
const maybeUnsavedFileNames = server.documents.all() | ||
.map(document => vscode_uri_1.URI.parse(document.uri)) | ||
.filter(uri => uri.scheme === workspaceFolder.scheme) | ||
.map(uri => uriConverter.asFileName(uri)); | ||
const host = { | ||
..._host, | ||
readDirectory(rootDir, extensions, excludes, includes, depth) { | ||
const fsFiles = _host.readDirectory(rootDir, extensions, excludes, includes, depth); | ||
const unsavedFiles = (0, utilities_1.matchFiles)(rootDir, extensions, excludes, includes, sys.useCaseSensitiveFileNames, getCurrentDirectory(), depth, dirPath => { | ||
dirPath = dirPath.replace(/\\/g, '/'); | ||
const files = []; | ||
const dirs = []; | ||
for (const fileName of maybeUnsavedFileNames) { | ||
const match = sys.useCaseSensitiveFileNames | ||
? fileName.startsWith(dirPath + '/') | ||
: fileName.toLowerCase().startsWith(dirPath.toLowerCase() + '/'); | ||
if (match) { | ||
const name = fileName.slice(dirPath.length + 1); | ||
if (name.includes('/')) { | ||
const dir = name.split('/')[0]; | ||
if (!dirs.includes(dir)) { | ||
dirs.push(dir); | ||
} | ||
} | ||
else { | ||
files.push(name); | ||
} | ||
} | ||
} | ||
return { | ||
files, | ||
directories: dirs, | ||
}; | ||
}, path => path); | ||
if (!unsavedFiles.length) { | ||
return fsFiles; | ||
} | ||
return [...new Set([...fsFiles, ...unsavedFiles])]; | ||
}, | ||
}; | ||
if (typeof tsconfig === 'string') { | ||
const config = ts.readJsonConfigFile(tsconfig, host.readFile); | ||
content = ts.parseJsonSourceFileConfigFileContent(config, host, path.dirname(tsconfig), {}, tsconfig, undefined, extraFileExtensions); | ||
} | ||
newSysVersion = await sys.sync(); | ||
} | ||
if (content) { | ||
else { | ||
content = ts.parseJsonConfigFileContent({ files: [] }, host, workspacePath, tsconfig, workspacePath + '/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, '/')); | ||
return content; | ||
} | ||
return content; | ||
} | ||
//# sourceMappingURL=typescriptProjectLs.js.map |
import { LanguageServicePlugin } from '@volar/language-service'; | ||
import * as vscode from 'vscode-languageserver'; | ||
import type { ExperimentalFeatures, LanguageServerProject } from './types.js'; | ||
export declare function createServerBase(connection: vscode.Connection): { | ||
import type { ExperimentalFeatures, LanguageServerEnvironment, LanguageServerProject } from './types.js'; | ||
export declare function createServerBase(connection: vscode.Connection, env: LanguageServerEnvironment): { | ||
initializeParams: vscode.InitializeParams; | ||
@@ -29,2 +29,5 @@ project: LanguageServerProject; | ||
has(uri: import("vscode-uri").URI): boolean; | ||
onDidChange: (cb: vscode.NotificationHandler<vscode.WorkspaceFoldersChangeEvent>) => { | ||
dispose(): void; | ||
}; | ||
}; | ||
@@ -46,2 +49,3 @@ fileWatcher: { | ||
}; | ||
env: LanguageServerEnvironment; | ||
connection: vscode.Connection; | ||
@@ -48,0 +52,0 @@ onInitialize(callback: (serverCapabilities: vscode.ServerCapabilities<ExperimentalFeatures>) => void): void; |
@@ -11,6 +11,7 @@ "use strict"; | ||
const workspaceFolders_js_1 = require("./features/workspaceFolders.js"); | ||
function createServerBase(connection) { | ||
function createServerBase(connection, env) { | ||
const onInitializeCallbacks = []; | ||
const onInitializedCallbacks = []; | ||
const state = { | ||
env, | ||
connection, | ||
@@ -17,0 +18,0 @@ initializeParams: undefined, |
@@ -5,2 +5,7 @@ import type { InitializeParams, LanguageService, LanguageServicePlugin, ProviderResult, ServerCapabilities } from '@volar/language-service'; | ||
import { createServerBase } from './server'; | ||
export interface LanguageServerEnvironment { | ||
timer: { | ||
setImmediate: (callback: (...args: any[]) => void, ...args: any[]) => void; | ||
}; | ||
} | ||
export interface LanguageServerProject { | ||
@@ -13,2 +18,3 @@ setup(server: LanguageServer): void; | ||
export interface LanguageServerState { | ||
env: LanguageServerEnvironment; | ||
connection: Connection; | ||
@@ -15,0 +21,0 @@ initializeParams: InitializeParams; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
; | ||
//# sourceMappingURL=types.js.map |
@@ -33,2 +33,5 @@ import * as vscode from 'vscode-languageserver/node'; | ||
has(uri: import("vscode-uri").URI): boolean; | ||
onDidChange: (cb: vscode.NotificationHandler<vscode.WorkspaceFoldersChangeEvent>) => { | ||
dispose(): void; | ||
}; | ||
}; | ||
@@ -50,2 +53,3 @@ fileWatcher: { | ||
}; | ||
env: import("./index").LanguageServerEnvironment; | ||
connection: vscode.Connection; | ||
@@ -52,0 +56,0 @@ onInitialize(callback: (serverCapabilities: vscode.ServerCapabilities<import("./index").ExperimentalFeatures>) => void): void; |
@@ -33,3 +33,7 @@ "use strict"; | ||
function createServer(connection) { | ||
const server = (0, server_1.createServerBase)(connection); | ||
const server = (0, server_1.createServerBase)(connection, { | ||
timer: { | ||
setImmediate: setImmediate, | ||
}, | ||
}); | ||
server.fileSystem.install('file', node_1.provider); | ||
@@ -36,0 +40,0 @@ server.fileSystem.install('http', http_1.provider); |
{ | ||
"name": "@volar/language-server", | ||
"version": "2.4.0", | ||
"version": "2.4.1", | ||
"license": "MIT", | ||
@@ -15,5 +15,5 @@ "files": [ | ||
"dependencies": { | ||
"@volar/language-core": "2.4.0", | ||
"@volar/language-service": "2.4.0", | ||
"@volar/typescript": "2.4.0", | ||
"@volar/language-core": "2.4.1", | ||
"@volar/language-service": "2.4.1", | ||
"@volar/typescript": "2.4.1", | ||
"path-browserify": "^1.0.1", | ||
@@ -29,3 +29,3 @@ "request-light": "^0.7.0", | ||
}, | ||
"gitHead": "7e98885cfe284451e655cf1c3954786b51aea2f8" | ||
"gitHead": "b920b6c4a3e4b2d8f46c676ea414e94c437cb5b7" | ||
} |
142877
2943
+ Added@volar/language-core@2.4.1(transitive)
+ Added@volar/language-service@2.4.1(transitive)
+ Added@volar/source-map@2.4.1(transitive)
+ Added@volar/typescript@2.4.1(transitive)
- Removed@volar/language-core@2.4.0(transitive)
- Removed@volar/language-service@2.4.0(transitive)
- Removed@volar/source-map@2.4.0(transitive)
- Removed@volar/typescript@2.4.0(transitive)
Updated@volar/language-core@2.4.1
Updated@volar/typescript@2.4.1