Skip to content

Commit 34847f0

Browse files
committed
Making language service host changes optional
1 parent c71c5a8 commit 34847f0

File tree

1 file changed

+86
-74
lines changed

1 file changed

+86
-74
lines changed

src/services/services.ts

Lines changed: 86 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -1158,9 +1158,13 @@ namespace ts {
11581158
error?(s: string): void;
11591159
useCaseSensitiveFileNames?(): boolean;
11601160

1161-
readDirectory(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
1162-
readFile(path: string, encoding?: string): string;
1163-
fileExists(path: string): boolean;
1161+
/*
1162+
* LS host can optionally implement these methods to support getImportModuleCompletionsAtPosition.
1163+
* Without these methods, only completions for ambient modules will be provided.
1164+
*/
1165+
readDirectory?(path: string, extensions?: string[], exclude?: string[], include?: string[]): string[];
1166+
readFile?(path: string, encoding?: string): string;
1167+
fileExists?(path: string): boolean;
11641168

11651169
/*
11661170
* LS host can optionally implement this method if it wants to be completely in charge of module name resolution.
@@ -3155,7 +3159,8 @@ namespace ts {
31553159
writeFile: (fileName, data, writeByteOrderMark) => { },
31563160
getCurrentDirectory: () => currentDirectory,
31573161
fileExists: (fileName): boolean => {
3158-
return host.fileExists(fileName);
3162+
// stub missing host functionality
3163+
return hostCache.getOrCreateEntry(fileName) !== undefined;
31593164
},
31603165
readFile: (fileName): string => {
31613166
// stub missing host functionality
@@ -4598,23 +4603,25 @@ namespace ts {
45984603
const ignoreCase = !(host.useCaseSensitiveFileNames && host.useCaseSensitiveFileNames());
45994604

46004605
if (directoryProbablyExists(baseDirectory, host)) {
4601-
// Enumerate the available files
4602-
const files = host.readDirectory(baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]);
4603-
for (let filePath of files) {
4604-
filePath = normalizePath(filePath);
4605-
if (exclude && comparePaths(filePath, exclude, scriptPath, ignoreCase) === Comparison.EqualTo) {
4606-
continue;
4607-
}
4606+
if (host.readDirectory) {
4607+
// Enumerate the available files if possible
4608+
const files = host.readDirectory(baseDirectory, extensions, /*exclude*/undefined, /*include*/["./*"]);
4609+
for (let filePath of files) {
4610+
filePath = normalizePath(filePath);
4611+
if (exclude && comparePaths(filePath, exclude, scriptPath, ignoreCase) === Comparison.EqualTo) {
4612+
continue;
4613+
}
46084614

4609-
const fileName = includeExtensions ? getBaseFileName(filePath) : removeFileExtension(getBaseFileName(filePath));
4610-
const duplicate = !includeExtensions && forEach(result, entry => entry.name === fileName);
4615+
const fileName = includeExtensions ? getBaseFileName(filePath) : removeFileExtension(getBaseFileName(filePath));
4616+
const duplicate = !includeExtensions && forEach(result, entry => entry.name === fileName);
46114617

4612-
if (!duplicate) {
4613-
result.push({
4614-
name: fileName,
4615-
kind: ScriptElementKind.scriptElement,
4616-
sortText: fileName
4617-
});
4618+
if (!duplicate) {
4619+
result.push({
4620+
name: fileName,
4621+
kind: ScriptElementKind.scriptElement,
4622+
sortText: fileName
4623+
});
4624+
}
46184625
}
46194626
}
46204627

@@ -4691,44 +4698,46 @@ namespace ts {
46914698
}
46924699

46934700
function getModulesForPathsPattern(fragment: string, baseUrl: string, pattern: string, fileExtensions: string[]): string[] {
4694-
const parsed = hasZeroOrOneAsteriskCharacter(pattern) ? tryParsePattern(pattern) : undefined;
4695-
if (parsed) {
4696-
// The prefix has two effective parts: the directory path and the base component after the filepath that is not a
4697-
// full directory component. For example: directory/path/of/prefix/base*
4698-
const normalizedPrefix = normalizeAndPreserveTrailingSlash(parsed.prefix);
4699-
const normalizedPrefixDirectory = getDirectoryPath(normalizedPrefix);
4700-
const normalizedPrefixBase = getBaseFileName(normalizedPrefix);
4701-
4702-
const fragmentHasPath = fragment.indexOf(directorySeparator) !== -1;
4703-
4704-
// Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call
4705-
const expandedPrefixDirectory = fragmentHasPath ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + getDirectoryPath(fragment)) : normalizedPrefixDirectory;
4706-
4707-
const normalizedSuffix = normalizePath(parsed.suffix);
4708-
const baseDirectory = combinePaths(baseUrl, expandedPrefixDirectory);
4709-
const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase;
4710-
4711-
// If we have a suffix, then we need to read the directory all the way down. We could create a glob
4712-
// that encodes the suffix, but we would have to escape the character "?" which readDirectory
4713-
// doesn't support. For now, this is safer but slower
4714-
const includeGlob = normalizedSuffix ? "**/*" : "./*";
4715-
4716-
const matches = host.readDirectory(baseDirectory, fileExtensions, undefined, [includeGlob]);
4717-
const result: string[] = [];
4718-
4719-
// Trim away prefix and suffix
4720-
for (const match of matches) {
4721-
const normalizedMatch = normalizePath(match);
4722-
if (!endsWith(normalizedMatch, normalizedSuffix) || !startsWith(normalizedMatch, completePrefix)) {
4723-
continue;
4724-
}
4701+
if (host.readDirectory) {
4702+
const parsed = hasZeroOrOneAsteriskCharacter(pattern) ? tryParsePattern(pattern) : undefined;
4703+
if (parsed) {
4704+
// The prefix has two effective parts: the directory path and the base component after the filepath that is not a
4705+
// full directory component. For example: directory/path/of/prefix/base*
4706+
const normalizedPrefix = normalizeAndPreserveTrailingSlash(parsed.prefix);
4707+
const normalizedPrefixDirectory = getDirectoryPath(normalizedPrefix);
4708+
const normalizedPrefixBase = getBaseFileName(normalizedPrefix);
4709+
4710+
const fragmentHasPath = fragment.indexOf(directorySeparator) !== -1;
4711+
4712+
// Try and expand the prefix to include any path from the fragment so that we can limit the readDirectory call
4713+
const expandedPrefixDirectory = fragmentHasPath ? combinePaths(normalizedPrefixDirectory, normalizedPrefixBase + getDirectoryPath(fragment)) : normalizedPrefixDirectory;
4714+
4715+
const normalizedSuffix = normalizePath(parsed.suffix);
4716+
const baseDirectory = combinePaths(baseUrl, expandedPrefixDirectory);
4717+
const completePrefix = fragmentHasPath ? baseDirectory : ensureTrailingDirectorySeparator(baseDirectory) + normalizedPrefixBase;
4718+
4719+
// If we have a suffix, then we need to read the directory all the way down. We could create a glob
4720+
// that encodes the suffix, but we would have to escape the character "?" which readDirectory
4721+
// doesn't support. For now, this is safer but slower
4722+
const includeGlob = normalizedSuffix ? "**/*" : "./*";
4723+
4724+
const matches = host.readDirectory(baseDirectory, fileExtensions, undefined, [includeGlob]);
4725+
const result: string[] = [];
4726+
4727+
// Trim away prefix and suffix
4728+
for (const match of matches) {
4729+
const normalizedMatch = normalizePath(match);
4730+
if (!endsWith(normalizedMatch, normalizedSuffix) || !startsWith(normalizedMatch, completePrefix)) {
4731+
continue;
4732+
}
47254733

4726-
const start = completePrefix.length;
4727-
const length = normalizedMatch.length - start - normalizedSuffix.length;
4734+
const start = completePrefix.length;
4735+
const length = normalizedMatch.length - start - normalizedSuffix.length;
47284736

4729-
result.push(removeFileExtension(normalizedMatch.substr(start, length)));
4737+
result.push(removeFileExtension(normalizedMatch.substr(start, length)));
4738+
}
4739+
return result;
47304740
}
4731-
return result;
47324741
}
47334742

47344743
return undefined;
@@ -4762,7 +4771,7 @@ namespace ts {
47624771
if (!isNestedModule) {
47634772
nonRelativeModules.push(visibleModule.moduleName);
47644773
}
4765-
else if (startsWith(visibleModule.moduleName, moduleNameFragment)) {
4774+
else if (host.readDirectory && startsWith(visibleModule.moduleName, moduleNameFragment)) {
47664775
const nestedFiles = host.readDirectory(visibleModule.moduleDir, supportedTypeScriptExtensions, /*exclude*/undefined, /*include*/["./*"]);
47674776

47684777
for (let f of nestedFiles) {
@@ -4891,28 +4900,31 @@ namespace ts {
48914900

48924901
function enumerateNodeModulesVisibleToScript(host: LanguageServiceHost, scriptPath: string) {
48934902
const result: VisibleModuleInfo[] = [];
4894-
for (const packageJson of findPackageJsons(scriptPath)) {
4895-
const package = tryReadingPackageJson(packageJson);
4896-
if (!package) {
4897-
return;
4898-
}
48994903

4900-
const nodeModulesDir = combinePaths(getDirectoryPath(packageJson), "node_modules");
4901-
const foundModuleNames: string[] = [];
4904+
if (host.readFile && host.fileExists) {
4905+
for (const packageJson of findPackageJsons(scriptPath)) {
4906+
const package = tryReadingPackageJson(packageJson);
4907+
if (!package) {
4908+
return;
4909+
}
49024910

4903-
if (package.dependencies) {
4904-
addPotentialPackageNames(package.dependencies, foundModuleNames);
4905-
}
4906-
if (package.devDependencies) {
4907-
addPotentialPackageNames(package.devDependencies, foundModuleNames);
4908-
}
4911+
const nodeModulesDir = combinePaths(getDirectoryPath(packageJson), "node_modules");
4912+
const foundModuleNames: string[] = [];
49094913

4910-
for (const moduleName of foundModuleNames) {
4911-
const moduleDir = combinePaths(nodeModulesDir, moduleName);
4912-
result.push({
4913-
moduleName,
4914-
moduleDir
4915-
});
4914+
if (package.dependencies) {
4915+
addPotentialPackageNames(package.dependencies, foundModuleNames);
4916+
}
4917+
if (package.devDependencies) {
4918+
addPotentialPackageNames(package.devDependencies, foundModuleNames);
4919+
}
4920+
4921+
for (const moduleName of foundModuleNames) {
4922+
const moduleDir = combinePaths(nodeModulesDir, moduleName);
4923+
result.push({
4924+
moduleName,
4925+
moduleDir
4926+
});
4927+
}
49164928
}
49174929
}
49184930

0 commit comments

Comments
 (0)