Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use node's algorithm for calculating the longest matching export/import pattern #49361

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
20 changes: 19 additions & 1 deletion src/compiler/moduleNameResolver.ts
Expand Up @@ -2064,14 +2064,32 @@ namespace ts {
return toSearchResult(/*value*/ undefined);
}

/**
* From https://github.com/nodejs/node/blob/8f39f51cbbd3b2de14b9ee896e26421cc5b20121/lib/internal/modules/esm/resolve.js#L722 -
* "longest" has some nuance as to what "longest" means in the presence of pattern trailers
*/
function comparePatternKeys(a: string, b: string) {
const aPatternIndex = a.indexOf("*");
const bPatternIndex = b.indexOf("*");
const baseLenA = aPatternIndex === -1 ? a.length : aPatternIndex + 1;
const baseLenB = bPatternIndex === -1 ? b.length : bPatternIndex + 1;
if (baseLenA > baseLenB) return -1;
if (baseLenB > baseLenA) return 1;
if (aPatternIndex === -1) return 1;
if (bPatternIndex === -1) return -1;
if (a.length > b.length) return -1;
if (b.length > a.length) return 1;
return 0;
}

function loadModuleFromImportsOrExports(extensions: Extensions, state: ModuleResolutionState, cache: ModuleResolutionCache | undefined, redirectedReference: ResolvedProjectReference | undefined, moduleName: string, lookupTable: object, scope: PackageJsonInfo, isImports: boolean): SearchResult<Resolved> | undefined {
const loadModuleFromTargetImportOrExport = getLoadModuleFromTargetImportOrExport(extensions, state, cache, redirectedReference, moduleName, scope, isImports);

if (!endsWith(moduleName, directorySeparator) && moduleName.indexOf("*") === -1 && hasProperty(lookupTable, moduleName)) {
const target = (lookupTable as {[idx: string]: unknown})[moduleName];
return loadModuleFromTargetImportOrExport(target, /*subpath*/ "", /*pattern*/ false);
}
const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike<unknown>), k => k.indexOf("*") !== -1 || endsWith(k, "/")), (a, b) => a.length - b.length);
const expandingKeys = sort(filter(getOwnKeys(lookupTable as MapLike<unknown>), k => k.indexOf("*") !== -1 || endsWith(k, "/")), comparePatternKeys);
for (const potentialTarget of expandingKeys) {
if (state.features & NodeResolutionFeatures.ExportsPatternTrailers && matchesPatternWithTrailer(potentialTarget, moduleName)) {
const target = (lookupTable as {[idx: string]: unknown})[potentialTarget];
Expand Down
@@ -0,0 +1,123 @@
tests/cases/conformance/node/allowJs/index.cjs(2,23): error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.cjs(3,23): error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.cjs(4,24): error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.js(2,23): error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.js(3,23): error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.js(4,24): error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.mjs(2,23): error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.mjs(3,23): error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/index.mjs(4,24): error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.cts(2,22): error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.cts(3,22): error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.cts(4,23): error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.mts(2,22): error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.mts(3,22): error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.mts(4,23): error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.ts(2,22): error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.ts(3,22): error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.ts(4,23): error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.


==== tests/cases/conformance/node/allowJs/index.js (3 errors) ====
// esm format file
import * as cjsi from "inner/cjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
import * as mjsi from "inner/mjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
import * as typei from "inner/js/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
cjsi;
mjsi;
typei;
==== tests/cases/conformance/node/allowJs/index.mjs (3 errors) ====
// esm format file
import * as cjsi from "inner/cjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
import * as mjsi from "inner/mjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
import * as typei from "inner/js/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
cjsi;
mjsi;
typei;
==== tests/cases/conformance/node/allowJs/index.cjs (3 errors) ====
// cjs format file
import * as cjsi from "inner/cjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
import * as mjsi from "inner/mjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
import * as typei from "inner/js/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
cjsi;
mjsi;
typei;
==== tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.ts (3 errors) ====
// cjs format file
import * as cjs from "inner/cjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
import * as mjs from "inner/mjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
import * as type from "inner/js/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
export { cjs };
export { mjs };
export { type };
==== tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.mts (3 errors) ====
// esm format file
import * as cjs from "inner/cjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
import * as mjs from "inner/mjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
import * as type from "inner/js/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
export { cjs };
export { mjs };
export { type };
==== tests/cases/conformance/node/allowJs/node_modules/inner/exclude/index.d.cts (3 errors) ====
// cjs format file
import * as cjs from "inner/cjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/cjs/exclude/index' or its corresponding type declarations.
import * as mjs from "inner/mjs/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/mjs/exclude/index' or its corresponding type declarations.
import * as type from "inner/js/exclude/index";
~~~~~~~~~~~~~~~~~~~~~~~~
!!! error TS2307: Cannot find module 'inner/js/exclude/index' or its corresponding type declarations.
export { cjs };
export { mjs };
export { type };
==== tests/cases/conformance/node/allowJs/package.json (0 errors) ====
{
"name": "package",
"private": true,
"type": "module"
}
==== tests/cases/conformance/node/allowJs/node_modules/inner/package.json (0 errors) ====
{
"name": "inner",
"private": true,
"exports": {
"./cjs/*": "./*.cjs",
"./cjs/exclude/*": null,
"./mjs/*": "./*.mjs",
"./mjs/exclude/*": null,
"./js/*": "./*.js",
"./js/exclude/*": null
}
}
@@ -0,0 +1,127 @@
//// [tests/cases/conformance/node/allowJs/nodeModulesAllowJsPackagePatternExportsExclude.ts] ////

//// [index.js]
// esm format file
import * as cjsi from "inner/cjs/exclude/index";
import * as mjsi from "inner/mjs/exclude/index";
import * as typei from "inner/js/exclude/index";
cjsi;
mjsi;
typei;
//// [index.mjs]
// esm format file
import * as cjsi from "inner/cjs/exclude/index";
import * as mjsi from "inner/mjs/exclude/index";
import * as typei from "inner/js/exclude/index";
cjsi;
mjsi;
typei;
//// [index.cjs]
// cjs format file
import * as cjsi from "inner/cjs/exclude/index";
import * as mjsi from "inner/mjs/exclude/index";
import * as typei from "inner/js/exclude/index";
cjsi;
mjsi;
typei;
//// [index.d.ts]
// cjs format file
import * as cjs from "inner/cjs/exclude/index";
import * as mjs from "inner/mjs/exclude/index";
import * as type from "inner/js/exclude/index";
export { cjs };
export { mjs };
export { type };
//// [index.d.mts]
// esm format file
import * as cjs from "inner/cjs/exclude/index";
import * as mjs from "inner/mjs/exclude/index";
import * as type from "inner/js/exclude/index";
export { cjs };
export { mjs };
export { type };
//// [index.d.cts]
// cjs format file
import * as cjs from "inner/cjs/exclude/index";
import * as mjs from "inner/mjs/exclude/index";
import * as type from "inner/js/exclude/index";
export { cjs };
export { mjs };
export { type };
//// [package.json]
{
"name": "package",
"private": true,
"type": "module"
}
//// [package.json]
{
"name": "inner",
"private": true,
"exports": {
"./cjs/*": "./*.cjs",
"./cjs/exclude/*": null,
"./mjs/*": "./*.mjs",
"./mjs/exclude/*": null,
"./js/*": "./*.js",
"./js/exclude/*": null
}
}

//// [index.js]
// esm format file
import * as cjsi from "inner/cjs/exclude/index";
import * as mjsi from "inner/mjs/exclude/index";
import * as typei from "inner/js/exclude/index";
cjsi;
mjsi;
typei;
//// [index.mjs]
// esm format file
import * as cjsi from "inner/cjs/exclude/index";
import * as mjsi from "inner/mjs/exclude/index";
import * as typei from "inner/js/exclude/index";
cjsi;
mjsi;
typei;
//// [index.cjs]
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (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 cjsi = __importStar(require("inner/cjs/exclude/index"));
const mjsi = __importStar(require("inner/mjs/exclude/index"));
const typei = __importStar(require("inner/js/exclude/index"));
cjsi;
mjsi;
typei;


//// [index.d.ts]
export {};
//// [index.d.mts]
export {};
//// [index.d.cts]
export {};