From 749465d77a008d3a47b70e9c2b4ec366ce0fa13c Mon Sep 17 00:00:00 2001 From: Wesley Wigham Date: Mon, 4 Oct 2021 13:34:46 -0700 Subject: [PATCH] Properly support scoped package self name lookups --- src/compiler/moduleNameResolver.ts | 8 ++- ...geSelfNameScoped(module=node12).errors.txt | 24 +++++++ ...odePackageSelfNameScoped(module=node12).js | 63 +++++++++++++++++++ ...ckageSelfNameScoped(module=node12).symbols | 24 +++++++ ...PackageSelfNameScoped(module=node12).types | 24 +++++++ ...SelfNameScoped(module=nodenext).errors.txt | 24 +++++++ ...ePackageSelfNameScoped(module=nodenext).js | 63 +++++++++++++++++++ ...ageSelfNameScoped(module=nodenext).symbols | 24 +++++++ ...ckageSelfNameScoped(module=nodenext).types | 24 +++++++ .../node/nodePackageSelfNameScoped.ts | 21 +++++++ 10 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=node12).errors.txt create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=node12).js create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=node12).symbols create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=node12).types create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).errors.txt create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).js create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).symbols create mode 100644 tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).types create mode 100644 tests/cases/conformance/node/nodePackageSelfNameScoped.ts diff --git a/src/compiler/moduleNameResolver.ts b/src/compiler/moduleNameResolver.ts index 75991144d9b1a..bc606ffebe354 100644 --- a/src/compiler/moduleNameResolver.ts +++ b/src/compiler/moduleNameResolver.ts @@ -1724,11 +1724,15 @@ namespace ts { if (!scope || !scope.packageJsonContent.exports) { return undefined; } + if (typeof scope.packageJsonContent.name !== "string") { + return undefined; + } const parts = getPathComponents(moduleName); // unrooted paths should have `""` as their 0th entry - if (scope.packageJsonContent.name !== parts[1]) { + const nameParts = getPathComponents(scope.packageJsonContent.name); + if (!every(nameParts, (p, i) => parts[i] === p)) { return undefined; } - const trailingParts = parts.slice(2); + const trailingParts = parts.slice(nameParts.length); return loadModuleFromExports(scope, extensions, !length(trailingParts) ? "." : `.${directorySeparator}${trailingParts.join(directorySeparator)}`, state, cache, redirectedReference); } diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).errors.txt b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).errors.txt new file mode 100644 index 0000000000000..b2a9f313de779 --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).errors.txt @@ -0,0 +1,24 @@ +tests/cases/conformance/node/index.cts(2,23): error TS1471: Module '@scope/package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. + + +==== tests/cases/conformance/node/index.ts (0 errors) ==== + // esm format file + import * as self from "@scope/package"; + self; +==== tests/cases/conformance/node/index.mts (0 errors) ==== + // esm format file + import * as self from "@scope/package"; + self; +==== tests/cases/conformance/node/index.cts (1 errors) ==== + // cjs format file + import * as self from "@scope/package"; + ~~~~~~~~~~~~~~~~ +!!! error TS1471: Module '@scope/package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. + self; +==== tests/cases/conformance/node/package.json (0 errors) ==== + { + "name": "@scope/package", + "private": true, + "type": "module", + "exports": "./index.js" + } \ No newline at end of file diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).js b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).js new file mode 100644 index 0000000000000..c812b758e9bba --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).js @@ -0,0 +1,63 @@ +//// [tests/cases/conformance/node/nodePackageSelfNameScoped.ts] //// + +//// [index.ts] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.mts] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.cts] +// cjs format file +import * as self from "@scope/package"; +self; +//// [package.json] +{ + "name": "@scope/package", + "private": true, + "type": "module", + "exports": "./index.js" +} + +//// [index.js] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.mjs] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.cjs] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// cjs format file +const self = __importStar(require("@scope/package")); +self; + + +//// [index.d.ts] +export {}; +//// [index.d.mts] +export {}; +//// [index.d.cts] +export {}; diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).symbols b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).symbols new file mode 100644 index 0000000000000..e54b0cb667ac3 --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/node/index.ts === +// esm format file +import * as self from "@scope/package"; +>self : Symbol(self, Decl(index.ts, 1, 6)) + +self; +>self : Symbol(self, Decl(index.ts, 1, 6)) + +=== tests/cases/conformance/node/index.mts === +// esm format file +import * as self from "@scope/package"; +>self : Symbol(self, Decl(index.mts, 1, 6)) + +self; +>self : Symbol(self, Decl(index.mts, 1, 6)) + +=== tests/cases/conformance/node/index.cts === +// cjs format file +import * as self from "@scope/package"; +>self : Symbol(self, Decl(index.cts, 1, 6)) + +self; +>self : Symbol(self, Decl(index.cts, 1, 6)) + diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).types b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).types new file mode 100644 index 0000000000000..3e5c141f63f4f --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=node12).types @@ -0,0 +1,24 @@ +=== tests/cases/conformance/node/index.ts === +// esm format file +import * as self from "@scope/package"; +>self : typeof self + +self; +>self : typeof self + +=== tests/cases/conformance/node/index.mts === +// esm format file +import * as self from "@scope/package"; +>self : typeof self + +self; +>self : typeof self + +=== tests/cases/conformance/node/index.cts === +// cjs format file +import * as self from "@scope/package"; +>self : typeof self + +self; +>self : typeof self + diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).errors.txt b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).errors.txt new file mode 100644 index 0000000000000..b2a9f313de779 --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).errors.txt @@ -0,0 +1,24 @@ +tests/cases/conformance/node/index.cts(2,23): error TS1471: Module '@scope/package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. + + +==== tests/cases/conformance/node/index.ts (0 errors) ==== + // esm format file + import * as self from "@scope/package"; + self; +==== tests/cases/conformance/node/index.mts (0 errors) ==== + // esm format file + import * as self from "@scope/package"; + self; +==== tests/cases/conformance/node/index.cts (1 errors) ==== + // cjs format file + import * as self from "@scope/package"; + ~~~~~~~~~~~~~~~~ +!!! error TS1471: Module '@scope/package' cannot be imported using this construct. The specifier only resolves to an ES module, which cannot be imported synchronously. Use dynamic import instead. + self; +==== tests/cases/conformance/node/package.json (0 errors) ==== + { + "name": "@scope/package", + "private": true, + "type": "module", + "exports": "./index.js" + } \ No newline at end of file diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).js b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).js new file mode 100644 index 0000000000000..c812b758e9bba --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).js @@ -0,0 +1,63 @@ +//// [tests/cases/conformance/node/nodePackageSelfNameScoped.ts] //// + +//// [index.ts] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.mts] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.cts] +// cjs format file +import * as self from "@scope/package"; +self; +//// [package.json] +{ + "name": "@scope/package", + "private": true, + "type": "module", + "exports": "./index.js" +} + +//// [index.js] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.mjs] +// esm format file +import * as self from "@scope/package"; +self; +//// [index.cjs] +"use strict"; +var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } }); +}) : (function(o, m, k, k2) { + if (k2 === undefined) k2 = k; + o[k2] = m[k]; +})); +var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { + Object.defineProperty(o, "default", { enumerable: true, value: v }); +}) : function(o, v) { + o["default"] = v; +}); +var __importStar = (this && this.__importStar) || function (mod) { + if (mod && mod.__esModule) return mod; + var result = {}; + if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); + __setModuleDefault(result, mod); + return result; +}; +Object.defineProperty(exports, "__esModule", { value: true }); +// cjs format file +const self = __importStar(require("@scope/package")); +self; + + +//// [index.d.ts] +export {}; +//// [index.d.mts] +export {}; +//// [index.d.cts] +export {}; diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).symbols b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).symbols new file mode 100644 index 0000000000000..e54b0cb667ac3 --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).symbols @@ -0,0 +1,24 @@ +=== tests/cases/conformance/node/index.ts === +// esm format file +import * as self from "@scope/package"; +>self : Symbol(self, Decl(index.ts, 1, 6)) + +self; +>self : Symbol(self, Decl(index.ts, 1, 6)) + +=== tests/cases/conformance/node/index.mts === +// esm format file +import * as self from "@scope/package"; +>self : Symbol(self, Decl(index.mts, 1, 6)) + +self; +>self : Symbol(self, Decl(index.mts, 1, 6)) + +=== tests/cases/conformance/node/index.cts === +// cjs format file +import * as self from "@scope/package"; +>self : Symbol(self, Decl(index.cts, 1, 6)) + +self; +>self : Symbol(self, Decl(index.cts, 1, 6)) + diff --git a/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).types b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).types new file mode 100644 index 0000000000000..3e5c141f63f4f --- /dev/null +++ b/tests/baselines/reference/nodePackageSelfNameScoped(module=nodenext).types @@ -0,0 +1,24 @@ +=== tests/cases/conformance/node/index.ts === +// esm format file +import * as self from "@scope/package"; +>self : typeof self + +self; +>self : typeof self + +=== tests/cases/conformance/node/index.mts === +// esm format file +import * as self from "@scope/package"; +>self : typeof self + +self; +>self : typeof self + +=== tests/cases/conformance/node/index.cts === +// cjs format file +import * as self from "@scope/package"; +>self : typeof self + +self; +>self : typeof self + diff --git a/tests/cases/conformance/node/nodePackageSelfNameScoped.ts b/tests/cases/conformance/node/nodePackageSelfNameScoped.ts new file mode 100644 index 0000000000000..f4ef1e3798c7a --- /dev/null +++ b/tests/cases/conformance/node/nodePackageSelfNameScoped.ts @@ -0,0 +1,21 @@ +// @module: node12,nodenext +// @declaration: true +// @filename: index.ts +// esm format file +import * as self from "@scope/package"; +self; +// @filename: index.mts +// esm format file +import * as self from "@scope/package"; +self; +// @filename: index.cts +// cjs format file +import * as self from "@scope/package"; +self; +// @filename: package.json +{ + "name": "@scope/package", + "private": true, + "type": "module", + "exports": "./index.js" +} \ No newline at end of file