1import { mustCall } from '../common/index.mjs'; 2import { ok, deepStrictEqual, strictEqual } from 'assert'; 3 4import importer from '../fixtures/es-modules/pkgimports/importer.js'; 5import { requireFixture } from '../fixtures/pkgexports.mjs'; 6 7const { requireImport, importImport } = importer; 8 9[requireImport, importImport].forEach((loadFixture) => { 10 const isRequire = loadFixture === requireImport; 11 12 const internalImports = new Map([ 13 // Base case 14 ['#test', { default: 'test' }], 15 // import / require conditions 16 ['#branch', { default: isRequire ? 'requirebranch' : 'importbranch' }], 17 // Subpath imports 18 ['#subpath/x.js', { default: 'xsubpath' }], 19 // External imports 20 ['#external', { default: 'asdf' }], 21 // External subpath imports 22 ['#external/subpath/asdf.js', { default: 'asdf' }], 23 // Trailing pattern imports 24 ['#subpath/asdf.asdf', { default: 'test' }], 25 // Leading slash 26 ['#subpath//asdf.asdf', { default: 'test' }], 27 // Double slash 28 ['#subpath/as//df.asdf', { default: 'test' }], 29 ]); 30 31 for (const [validSpecifier, expected] of internalImports) { 32 if (validSpecifier === null) continue; 33 34 loadFixture(validSpecifier) 35 .then(mustCall((actual) => { 36 deepStrictEqual({ ...actual }, expected); 37 })); 38 } 39 40 const invalidImportTargets = new Set([ 41 // Target steps below the package base 42 ['#belowbase', '#belowbase'], 43 // Target is a URL 44 ['#url', '#url'], 45 ]); 46 47 for (const [specifier, subpath] of invalidImportTargets) { 48 loadFixture(specifier).catch(mustCall((err) => { 49 strictEqual(err.code, 'ERR_INVALID_PACKAGE_TARGET'); 50 assertStartsWith(err.message, 'Invalid "imports"'); 51 assertIncludes(err.message, subpath); 52 assertNotIncludes(err.message, 'targets must start with'); 53 })); 54 } 55 56 const invalidImportSpecifiers = new Map([ 57 // Backtracking below the package base 58 ['#subpath/sub/../../../belowbase', 'request is not a valid match in pattern'], 59 // Percent-encoded slash errors 60 ['#external/subpath/x%2Fy', 'must not include encoded "/" or "\\"'], 61 ['#external/subpath/x%5Cy', 'must not include encoded "/" or "\\"'], 62 // Target must have a name 63 ['#', '#'], 64 // Initial slash target must have a leading name 65 ['#/initialslash', '#/initialslash'], 66 // Percent-encoded target paths 67 ['#encodedslash', 'must not include encoded "/" or "\\"'], 68 ['#encodedbackslash', 'must not include encoded "/" or "\\"'], 69 ]); 70 71 for (const [specifier, expected] of invalidImportSpecifiers) { 72 loadFixture(specifier).catch(mustCall((err) => { 73 strictEqual(err.code, 'ERR_INVALID_MODULE_SPECIFIER'); 74 assertStartsWith(err.message, 'Invalid module'); 75 assertIncludes(err.message, expected); 76 })); 77 } 78 79 const undefinedImports = new Set([ 80 // EOL subpaths 81 '#external/invalidsubpath/x', 82 // Missing import 83 '#missing', 84 // Explicit null import 85 '#null', 86 '#subpath/null', 87 // No condition match import 88 '#nullcondition', 89 // Null subpath shadowing 90 '#subpath/nullshadow/x', 91 // Null pattern 92 '#subpath/internal/test', 93 '#subpath/internal//test', 94 ]); 95 96 for (const specifier of undefinedImports) { 97 loadFixture(specifier).catch(mustCall((err) => { 98 strictEqual(err.code, 'ERR_PACKAGE_IMPORT_NOT_DEFINED'); 99 assertStartsWith(err.message, 'Package import '); 100 assertIncludes(err.message, specifier); 101 })); 102 } 103 104 // Handle not found for the defined imports target not existing 105 const nonDefinedImports = new Set([ 106 '#notfound', 107 '#subpath//null', 108 '#subpath/////null', 109 '#subpath//internal/test', 110 '#subpath//internal//test', 111 '#subpath/////internal/////test', 112 ]); 113 for (const specifier of nonDefinedImports) { 114 loadFixture(specifier).catch(mustCall((err) => { 115 strictEqual(err.code, 116 isRequire ? 'MODULE_NOT_FOUND' : 'ERR_MODULE_NOT_FOUND'); 117 })); 118 } 119}); 120 121// CJS resolver must still support #package packages in node_modules 122requireFixture('#cjs').then(mustCall((actual) => { 123 strictEqual(actual.default, 'cjs backcompat'); 124})); 125 126function assertStartsWith(actual, expected) { 127 const start = actual.toString().substr(0, expected.length); 128 strictEqual(start, expected); 129} 130 131function assertIncludes(actual, expected) { 132 ok(actual.toString().indexOf(expected) !== -1, 133 `${JSON.stringify(actual)} includes ${JSON.stringify(expected)}`); 134} 135 136function assertNotIncludes(actual, expected) { 137 ok(actual.toString().indexOf(expected) === -1, 138 `${JSON.stringify(actual)} doesn't include ${JSON.stringify(expected)}`); 139} 140