Skip to content

Commit 0845b46

Browse files
committed
Framework for discover typings extensions
1 parent 5541571 commit 0845b46

File tree

2 files changed

+60
-4
lines changed

2 files changed

+60
-4
lines changed

src/compiler/extensions.ts

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,17 @@
11
namespace ts {
22

3+
export interface BaseProviderStatic {
4+
readonly ["extension-kind"]: ExtensionKind;
5+
}
6+
37
export namespace ExtensionKind {
8+
export const TypeDiscovery: "type-discovery" = "type-discovery";
9+
export type TypeDiscovery = "type-discovery";
410
}
5-
export type ExtensionKind = string;
11+
export type ExtensionKind = ExtensionKind.TypeDiscovery;
612

713
export interface ExtensionCollectionMap {
14+
"type-discovery"?: TypeDiscoveryExtension[];
815
[index: string]: Extension[] | undefined;
916
}
1017

@@ -21,7 +28,12 @@ namespace ts {
2128
length?: number;
2229
}
2330

24-
export type Extension = ExtensionBase;
31+
export interface TypeDiscoveryExtension extends ExtensionBase {
32+
kind: ExtensionKind.TypeDiscovery;
33+
lookup: (searchDir: string, args: any) => string[];
34+
}
35+
36+
export type Extension = TypeDiscoveryExtension;
2537

2638
export interface ExtensionCache {
2739
getCompilerExtensions(): ExtensionCollectionMap;
@@ -89,6 +101,21 @@ namespace ts {
89101
completeProfile(/*enabled*/true, longTask);
90102
}
91103

104+
function verifyType(thing: any, type: string, diagnostics: Diagnostic[], extName: string, extMember: string, extKind: ExtensionKind) {
105+
if (typeof thing !== type) {
106+
diagnostics.push(createCompilerDiagnostic(
107+
Diagnostics.Extension_0_exported_member_1_has_extension_kind_2_but_was_type_3_when_type_4_was_expected,
108+
extName,
109+
extMember,
110+
extKind,
111+
typeof thing,
112+
type
113+
));
114+
return false;
115+
}
116+
return true;
117+
}
118+
92119
export function createExtensionCache(options: CompilerOptions, host: ExtensionHost, resolvedExtensionNames?: Map<string>): ExtensionCache {
93120

94121
const diagnostics: Diagnostic[] = [];
@@ -173,6 +200,12 @@ namespace ts {
173200
kind: annotatedKind as ExtensionKind,
174201
};
175202
switch (ext.kind) {
203+
case ExtensionKind.TypeDiscovery: {
204+
const verified = verifyType(potentialExtension, "function", diagnostics, res.name, key, annotatedKind);
205+
if (!verified) return;
206+
(ext as TypeDiscoveryExtension).lookup = potentialExtension as any;
207+
break;
208+
}
176209
default:
177210
// Include a default case which just puts the extension unchecked onto the base extension
178211
// This can allow language service extensions to query for custom extension kinds

src/services/jsTyping.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
/* @internal */
77
namespace ts.JsTyping {
88

9-
export interface TypingResolutionHost {
9+
export interface TypingResolutionHost extends ExtensionHost {
1010
directoryExists: (path: string) => boolean;
1111
fileExists: (fileName: string) => boolean;
1212
readFile: (path: string, encoding?: string) => string;
@@ -35,6 +35,7 @@ namespace ts.JsTyping {
3535
* @param packageNameToTypingLocation is the map of package names to their cached typing locations
3636
* @param typingOptions are used to customize the typing inference process
3737
* @param compilerOptions are used as a source for typing inference
38+
* @param cache is the optional extension cache to lookup type discovery extensions in - one will be made if it cannot be provided
3839
*/
3940
export function discoverTypings(
4041
host: TypingResolutionHost,
@@ -43,7 +44,8 @@ namespace ts.JsTyping {
4344
safeListPath: Path,
4445
packageNameToTypingLocation: Map<string>,
4546
typingOptions: TypingOptions,
46-
compilerOptions: CompilerOptions):
47+
compilerOptions: CompilerOptions,
48+
cache: ExtensionCache = createExtensionCache(compilerOptions, host)):
4749
{ cachedTypingPaths: string[], newTypingNames: string[], filesToWatch: string[] } {
4850

4951
// A typing name to typing file path mapping
@@ -88,6 +90,8 @@ namespace ts.JsTyping {
8890

8991
const nodeModulesPath = combinePaths(searchDir, "node_modules");
9092
getTypingNamesFromNodeModuleFolder(nodeModulesPath);
93+
94+
getTypingNamesFromExtensions(searchDir, cache);
9195
}
9296
getTypingNamesFromSourceFileNames(fileNames);
9397

@@ -223,5 +227,24 @@ namespace ts.JsTyping {
223227
mergeTypings(typingNames);
224228
}
225229

230+
231+
function getTypingNamesFromExtensions(searchPath: string, cache: ExtensionCache) {
232+
// We don't report issues loading type discovery extensions (if the host cares about them, it should load them in advance and pass in a cache)
233+
const extensions = cache.getCompilerExtensions()["type-discovery"];
234+
for (const extension of extensions) {
235+
let results: string[];
236+
try {
237+
startExtensionProfile(compilerOptions.extendedDiagnostics, extension.name, "lookup");
238+
results = extension.lookup(searchPath, extension.args);
239+
completeExtensionProfile(compilerOptions.extendedDiagnostics, extension.name, "lookup");
240+
}
241+
catch (e) {
242+
// There's presently no way to report errors during discover typings other than a hard failure (which is to be avoided)
243+
}
244+
if (results) {
245+
mergeTypings(results);
246+
}
247+
}
248+
}
226249
}
227250
}

0 commit comments

Comments
 (0)