Skip to content

Commit

Permalink
Use node's algorithm for calculating the longest matching export/impo…
Browse files Browse the repository at this point in the history
…rt pattern (#49361)
  • Loading branch information
weswigham committed Jun 2, 2022
1 parent 2cb8ee2 commit 19b2284
Show file tree
Hide file tree
Showing 19 changed files with 2,847 additions and 1 deletion.
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 {};

0 comments on commit 19b2284

Please sign in to comment.