From 6efc2f19c01e884fcf60bae7431382cbceabdd11 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 7 Sep 2021 15:48:35 +0000 Subject: [PATCH 1/7] Support resolving @typescript/x for libs --- src/compiler/program.ts | 29 ++++++++++++++++--- .../compiler/libTypeScriptOverrideSimple.ts | 9 ++++++ .../compiler/libTypeScriptSubfileResolving.ts | 11 +++++++ 3 files changed, 45 insertions(+), 4 deletions(-) create mode 100644 tests/cases/compiler/libTypeScriptOverrideSimple.ts create mode 100644 tests/cases/compiler/libTypeScriptSubfileResolving.ts diff --git a/src/compiler/program.ts b/src/compiler/program.ts index f7c0f00932f6f..e4c1da893d1e5 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -887,6 +887,8 @@ namespace ts { // Key is a file name. Value is the (non-empty, or undefined) list of files that redirect to it. let redirectTargetsMap = createMultiMap(); let usesUriStyleNodeCoreModules = false; + // Used when resolving something like 'dom' for libs + // const libResolveCache = createModuleResolutionCache(currentDirectory, host.getCanonicalFileName, { moduleResolution: ModuleResolutionKind.NodeJs }); /** * map with @@ -995,7 +997,7 @@ namespace ts { } else { forEach(options.lib, (libFileName, index) => { - processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile, index }); + processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ false, { kind: FileIncludeKind.LibFile, index }); }); } } @@ -1737,7 +1739,7 @@ namespace ts { return equalityComparer(file.fileName, getDefaultLibraryFileName()); } else { - return some(options.lib, libFileName => equalityComparer(file.fileName, combinePaths(defaultLibraryPath, libFileName))); + return some(options.lib, libFileName => equalityComparer(file.fileName, pathForLibFile(libFileName))); } } @@ -2406,7 +2408,7 @@ namespace ts { const libName = toFileNameLowerCase(ref.fileName); const libFileName = libMap.get(libName); if (libFileName) { - return getSourceFile(combinePaths(defaultLibraryPath, libFileName)); + return getSourceFile(pathForLibFile(libFileName)); } } @@ -2883,13 +2885,32 @@ namespace ts { } } + function pathForLibFile(libFileName: string): string { + // Support resolving to lib.dom.d.ts -> @typescript/dom, and + // lib.dom.iterable.d.ts -> @typescript/dom/iterable + // lib.es2015.symbol.wellknown.d.ts -> @typescript/es2015/symbol-wellknown + const components = libFileName.split("."); + let path = components[1]; + let i = 2; + while (components[i] && components[i] !== "d") { + path += (i === 2 ? "/" : "-") + components[i]; + i++; + } + // const localOverride = resolveModuleNameFromCache("@typescript/" + path, currentDirectory, libResolveCache); + const localOverride = resolveModuleName("@typescript/" + path, currentDirectory, { moduleResolution: ModuleResolutionKind.NodeJs }, host); + if (localOverride?.resolvedModule) { + return localOverride.resolvedModule.resolvedFileName; + } + return combinePaths(defaultLibraryPath, libFileName); + } + function processLibReferenceDirectives(file: SourceFile) { forEach(file.libReferenceDirectives, (libReference, index) => { const libName = toFileNameLowerCase(libReference.fileName); const libFileName = libMap.get(libName); if (libFileName) { // we ignore any 'no-default-lib' reference set on this file. - processRootFile(combinePaths(defaultLibraryPath, libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, }); + processRootFile(pathForLibFile(libFileName), /*isDefaultLib*/ true, /*ignoreNoDefaultLib*/ true, { kind: FileIncludeKind.LibReferenceDirective, file: file.path, index, }); } else { const unqualifiedLibName = removeSuffix(removePrefix(libName, "lib."), ".d.ts"); diff --git a/tests/cases/compiler/libTypeScriptOverrideSimple.ts b/tests/cases/compiler/libTypeScriptOverrideSimple.ts new file mode 100644 index 0000000000000..4ba67cd0c0181 --- /dev/null +++ b/tests/cases/compiler/libTypeScriptOverrideSimple.ts @@ -0,0 +1,9 @@ +// @Filename: /node_modules/@typescript/dom/index.d.ts +interface ABC { abc: string } +// @Filename: index.ts +/// +const a: ABC = { abc: "Hello" } + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage \ No newline at end of file diff --git a/tests/cases/compiler/libTypeScriptSubfileResolving.ts b/tests/cases/compiler/libTypeScriptSubfileResolving.ts new file mode 100644 index 0000000000000..901d86a236aba --- /dev/null +++ b/tests/cases/compiler/libTypeScriptSubfileResolving.ts @@ -0,0 +1,11 @@ +// @Filename: /node_modules/@typescript/dom/index.d.ts +// NOOP +// @Filename: /node_modules/@typescript/dom/iterable.d.ts +interface DOMIterable { abc: string } +// @Filename: index.ts +/// +const a: DOMIterable = { abc: "Hello" } + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage \ No newline at end of file From 2ec03f3f7163cba6d65a99a19a497e58e620fd56 Mon Sep 17 00:00:00 2001 From: Orta Therox Date: Tue, 7 Sep 2021 15:51:53 +0000 Subject: [PATCH 2/7] Baselines --- .../libTypeScriptOverrideSimple.errors.txt | 14 +++++++++++++ .../reference/libTypeScriptOverrideSimple.js | 18 ++++++++++++++++ .../libTypeScriptOverrideSimple.symbols | 15 +++++++++++++ .../libTypeScriptOverrideSimple.types | 19 +++++++++++++++++ .../libTypeScriptSubfileResolving.errors.txt | 16 ++++++++++++++ .../libTypeScriptSubfileResolving.js | 20 ++++++++++++++++++ .../libTypeScriptSubfileResolving.symbols | 17 +++++++++++++++ .../libTypeScriptSubfileResolving.types | 21 +++++++++++++++++++ 8 files changed, 140 insertions(+) create mode 100644 tests/baselines/reference/libTypeScriptOverrideSimple.errors.txt create mode 100644 tests/baselines/reference/libTypeScriptOverrideSimple.js create mode 100644 tests/baselines/reference/libTypeScriptOverrideSimple.symbols create mode 100644 tests/baselines/reference/libTypeScriptOverrideSimple.types create mode 100644 tests/baselines/reference/libTypeScriptSubfileResolving.errors.txt create mode 100644 tests/baselines/reference/libTypeScriptSubfileResolving.js create mode 100644 tests/baselines/reference/libTypeScriptSubfileResolving.symbols create mode 100644 tests/baselines/reference/libTypeScriptSubfileResolving.types diff --git a/tests/baselines/reference/libTypeScriptOverrideSimple.errors.txt b/tests/baselines/reference/libTypeScriptOverrideSimple.errors.txt new file mode 100644 index 0000000000000..cf5912eb2769d --- /dev/null +++ b/tests/baselines/reference/libTypeScriptOverrideSimple.errors.txt @@ -0,0 +1,14 @@ +tests/cases/compiler/index.ts(6,1): error TS2304: Cannot find name 'window'. + + +==== /node_modules/@typescript/dom/index.d.ts (0 errors) ==== + interface ABC { abc: string } +==== tests/cases/compiler/index.ts (1 errors) ==== + /// + const a: ABC = { abc: "Hello" } + + // This should fail because libdom has been replaced + // by the module above ^ + window.localStorage + ~~~~~~ +!!! error TS2304: Cannot find name 'window'. \ No newline at end of file diff --git a/tests/baselines/reference/libTypeScriptOverrideSimple.js b/tests/baselines/reference/libTypeScriptOverrideSimple.js new file mode 100644 index 0000000000000..ae95b842125f5 --- /dev/null +++ b/tests/baselines/reference/libTypeScriptOverrideSimple.js @@ -0,0 +1,18 @@ +//// [tests/cases/compiler/libTypeScriptOverrideSimple.ts] //// + +//// [index.d.ts] +interface ABC { abc: string } +//// [index.ts] +/// +const a: ABC = { abc: "Hello" } + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage + +//// [index.js] +/// +var a = { abc: "Hello" }; +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage; diff --git a/tests/baselines/reference/libTypeScriptOverrideSimple.symbols b/tests/baselines/reference/libTypeScriptOverrideSimple.symbols new file mode 100644 index 0000000000000..37c7ca70cbe8d --- /dev/null +++ b/tests/baselines/reference/libTypeScriptOverrideSimple.symbols @@ -0,0 +1,15 @@ +=== /node_modules/@typescript/dom/index.d.ts === +interface ABC { abc: string } +>ABC : Symbol(ABC, Decl(index.d.ts, 0, 0)) +>abc : Symbol(ABC.abc, Decl(index.d.ts, 0, 15)) + +=== tests/cases/compiler/index.ts === +/// +const a: ABC = { abc: "Hello" } +>a : Symbol(a, Decl(index.ts, 1, 5)) +>ABC : Symbol(ABC, Decl(index.d.ts, 0, 0)) +>abc : Symbol(abc, Decl(index.ts, 1, 16)) + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage diff --git a/tests/baselines/reference/libTypeScriptOverrideSimple.types b/tests/baselines/reference/libTypeScriptOverrideSimple.types new file mode 100644 index 0000000000000..65a28d7093d1d --- /dev/null +++ b/tests/baselines/reference/libTypeScriptOverrideSimple.types @@ -0,0 +1,19 @@ +=== /node_modules/@typescript/dom/index.d.ts === +interface ABC { abc: string } +>abc : string + +=== tests/cases/compiler/index.ts === +/// +const a: ABC = { abc: "Hello" } +>a : ABC +>{ abc: "Hello" } : { abc: string; } +>abc : string +>"Hello" : "Hello" + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage +>window.localStorage : any +>window : any +>localStorage : any + diff --git a/tests/baselines/reference/libTypeScriptSubfileResolving.errors.txt b/tests/baselines/reference/libTypeScriptSubfileResolving.errors.txt new file mode 100644 index 0000000000000..b2f731e2897da --- /dev/null +++ b/tests/baselines/reference/libTypeScriptSubfileResolving.errors.txt @@ -0,0 +1,16 @@ +tests/cases/compiler/index.ts(6,1): error TS2304: Cannot find name 'window'. + + +==== /node_modules/@typescript/dom/index.d.ts (0 errors) ==== + // NOOP +==== /node_modules/@typescript/dom/iterable.d.ts (0 errors) ==== + interface DOMIterable { abc: string } +==== tests/cases/compiler/index.ts (1 errors) ==== + /// + const a: DOMIterable = { abc: "Hello" } + + // This should fail because libdom has been replaced + // by the module above ^ + window.localStorage + ~~~~~~ +!!! error TS2304: Cannot find name 'window'. \ No newline at end of file diff --git a/tests/baselines/reference/libTypeScriptSubfileResolving.js b/tests/baselines/reference/libTypeScriptSubfileResolving.js new file mode 100644 index 0000000000000..d975c3669c088 --- /dev/null +++ b/tests/baselines/reference/libTypeScriptSubfileResolving.js @@ -0,0 +1,20 @@ +//// [tests/cases/compiler/libTypeScriptSubfileResolving.ts] //// + +//// [index.d.ts] +// NOOP +//// [iterable.d.ts] +interface DOMIterable { abc: string } +//// [index.ts] +/// +const a: DOMIterable = { abc: "Hello" } + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage + +//// [index.js] +/// +var a = { abc: "Hello" }; +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage; diff --git a/tests/baselines/reference/libTypeScriptSubfileResolving.symbols b/tests/baselines/reference/libTypeScriptSubfileResolving.symbols new file mode 100644 index 0000000000000..3bde25ae5b7e2 --- /dev/null +++ b/tests/baselines/reference/libTypeScriptSubfileResolving.symbols @@ -0,0 +1,17 @@ +=== /node_modules/@typescript/dom/index.d.ts === +// NOOP +No type information for this code.=== /node_modules/@typescript/dom/iterable.d.ts === +interface DOMIterable { abc: string } +>DOMIterable : Symbol(DOMIterable, Decl(iterable.d.ts, 0, 0)) +>abc : Symbol(DOMIterable.abc, Decl(iterable.d.ts, 0, 23)) + +=== tests/cases/compiler/index.ts === +/// +const a: DOMIterable = { abc: "Hello" } +>a : Symbol(a, Decl(index.ts, 1, 5)) +>DOMIterable : Symbol(DOMIterable, Decl(iterable.d.ts, 0, 0)) +>abc : Symbol(abc, Decl(index.ts, 1, 24)) + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage diff --git a/tests/baselines/reference/libTypeScriptSubfileResolving.types b/tests/baselines/reference/libTypeScriptSubfileResolving.types new file mode 100644 index 0000000000000..7fe3c02924cbc --- /dev/null +++ b/tests/baselines/reference/libTypeScriptSubfileResolving.types @@ -0,0 +1,21 @@ +=== /node_modules/@typescript/dom/index.d.ts === +// NOOP +No type information for this code.=== /node_modules/@typescript/dom/iterable.d.ts === +interface DOMIterable { abc: string } +>abc : string + +=== tests/cases/compiler/index.ts === +/// +const a: DOMIterable = { abc: "Hello" } +>a : DOMIterable +>{ abc: "Hello" } : { abc: string; } +>abc : string +>"Hello" : "Hello" + +// This should fail because libdom has been replaced +// by the module above ^ +window.localStorage +>window.localStorage : any +>window : any +>localStorage : any + From daa99cef537cafb28de42e72a529e4ed7cb8aa58 Mon Sep 17 00:00:00 2001 From: Orta Date: Tue, 14 Sep 2021 15:46:06 +0100 Subject: [PATCH 3/7] Tightens up the PR --- src/compiler/program.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index e4c1da893d1e5..73d6ddccebced 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -887,8 +887,6 @@ namespace ts { // Key is a file name. Value is the (non-empty, or undefined) list of files that redirect to it. let redirectTargetsMap = createMultiMap(); let usesUriStyleNodeCoreModules = false; - // Used when resolving something like 'dom' for libs - // const libResolveCache = createModuleResolutionCache(currentDirectory, host.getCanonicalFileName, { moduleResolution: ModuleResolutionKind.NodeJs }); /** * map with @@ -1739,7 +1737,7 @@ namespace ts { return equalityComparer(file.fileName, getDefaultLibraryFileName()); } else { - return some(options.lib, libFileName => equalityComparer(file.fileName, pathForLibFile(libFileName))); + return some(options.lib, libFileName => equalityComparer(file.fileName, pathForLibFile(libFileName))); } } @@ -2896,7 +2894,7 @@ namespace ts { path += (i === 2 ? "/" : "-") + components[i]; i++; } - // const localOverride = resolveModuleNameFromCache("@typescript/" + path, currentDirectory, libResolveCache); + const localOverride = resolveModuleName("@typescript/" + path, currentDirectory, { moduleResolution: ModuleResolutionKind.NodeJs }, host); if (localOverride?.resolvedModule) { return localOverride.resolvedModule.resolvedFileName; From e2ca4b5d19bbf88f6d9ab1b7bb248e733572935f Mon Sep 17 00:00:00 2001 From: Orta Date: Tue, 14 Sep 2021 16:59:44 +0100 Subject: [PATCH 4/7] Fix the build --- src/compiler/program.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 73d6ddccebced..e0a5553b4bd47 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2894,8 +2894,8 @@ namespace ts { path += (i === 2 ? "/" : "-") + components[i]; i++; } - - const localOverride = resolveModuleName("@typescript/" + path, currentDirectory, { moduleResolution: ModuleResolutionKind.NodeJs }, host); + // The strange "/fake.file" is to ensure we first resolve in node_modules for the current directory. + const localOverride = resolveModuleName("@typescript/" + path, currentDirectory + "/fake.file", { moduleResolution: ModuleResolutionKind.NodeJs }, host); if (localOverride?.resolvedModule) { return localOverride.resolvedModule.resolvedFileName; } From 99435250db0e36454fc4a6618d7cfbb7f78e9d4a Mon Sep 17 00:00:00 2001 From: Orta Date: Tue, 14 Sep 2021 18:50:58 +0100 Subject: [PATCH 5/7] Add cache --- src/compiler/program.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index e0a5553b4bd47..8c938014c4bda 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2895,7 +2895,7 @@ namespace ts { i++; } // The strange "/fake.file" is to ensure we first resolve in node_modules for the current directory. - const localOverride = resolveModuleName("@typescript/" + path, currentDirectory + "/fake.file", { moduleResolution: ModuleResolutionKind.NodeJs }, host); + const localOverride = resolveModuleName("@typescript/" + path, currentDirectory + "/fake.file", { moduleResolution: ModuleResolutionKind.NodeJs }, host, moduleResolutionCache); if (localOverride?.resolvedModule) { return localOverride.resolvedModule.resolvedFileName; } From 853ac554d26f73e871392830f3b58343952b62b1 Mon Sep 17 00:00:00 2001 From: Orta Date: Wed, 15 Sep 2021 09:29:31 +0100 Subject: [PATCH 6/7] Better naming --- src/compiler/program.ts | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 8c938014c4bda..2987e738e718a 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2894,10 +2894,11 @@ namespace ts { path += (i === 2 ? "/" : "-") + components[i]; i++; } - // The strange "/fake.file" is to ensure we first resolve in node_modules for the current directory. - const localOverride = resolveModuleName("@typescript/" + path, currentDirectory + "/fake.file", { moduleResolution: ModuleResolutionKind.NodeJs }, host, moduleResolutionCache); - if (localOverride?.resolvedModule) { - return localOverride.resolvedModule.resolvedFileName; + + const resolveFrom = combinePaths(currentDirectory, `/__lib_node_modules_lookup_${libFileName}__.ts`); + const localOverrideModuleResult = resolveModuleName("@typescript/" + path, resolveFrom, { moduleResolution: ModuleResolutionKind.NodeJs }, host, moduleResolutionCache); + if (localOverrideModuleResult?.resolvedModule) { + return localOverrideModuleResult.resolvedModule.resolvedFileName; } return combinePaths(defaultLibraryPath, libFileName); } From 77c0e2e28d1ff69a718392add055b59c164d8cd3 Mon Sep 17 00:00:00 2001 From: Orta Date: Wed, 15 Sep 2021 20:25:29 +0100 Subject: [PATCH 7/7] Fixes the lookup path --- src/compiler/program.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/compiler/program.ts b/src/compiler/program.ts index 0a1094b85f695..9dd6db37790a0 100644 --- a/src/compiler/program.ts +++ b/src/compiler/program.ts @@ -2894,8 +2894,7 @@ namespace ts { path += (i === 2 ? "/" : "-") + components[i]; i++; } - - const resolveFrom = combinePaths(currentDirectory, `/__lib_node_modules_lookup_${libFileName}__.ts`); + const resolveFrom = combinePaths(currentDirectory, `__lib_node_modules_lookup_${libFileName}__.ts`); const localOverrideModuleResult = resolveModuleName("@typescript/" + path, resolveFrom, { moduleResolution: ModuleResolutionKind.NodeJs }, host, moduleResolutionCache); if (localOverrideModuleResult?.resolvedModule) { return localOverrideModuleResult.resolvedModule.resolvedFileName;