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 ]); 24 25 for (const [validSpecifier, expected] of internalImports) { 26 if (validSpecifier === null) continue; 27 28 loadFixture(validSpecifier) 29 .then(mustCall((actual) => { 30 deepStrictEqual({ ...actual }, expected); 31 })); 32 } 33 34 const invalidImportTargets = new Set([ 35 // External subpath import without trailing slash 36 ['#external/invalidsubpath/x', '#external/invalidsubpath/'], 37 // Target steps below the package base 38 ['#belowbase', '#belowbase'], 39 // Target is a URL 40 ['#url', '#url'], 41 ]); 42 43 for (const [specifier, subpath] of invalidImportTargets) { 44 loadFixture(specifier).catch(mustCall((err) => { 45 strictEqual(err.code, 'ERR_INVALID_PACKAGE_TARGET'); 46 assertStartsWith(err.message, 'Invalid "imports"'); 47 assertIncludes(err.message, subpath); 48 assertNotIncludes(err.message, 'targets must start with'); 49 })); 50 } 51 52 const invalidImportSpecifiers = new Map([ 53 // Backtracking below the package base 54 ['#subpath/sub/../../../belowbase', 'request is not a valid subpath'], 55 // Percent-encoded slash errors 56 ['#external/subpath/x%2Fy', 'must not include encoded "/"'], 57 // Target must have a name 58 ['#', '#'], 59 // Initial slash target must have a leading name 60 ['#/initialslash', '#/initialslash'], 61 // Percent-encoded target paths 62 ['#percent', 'must not include encoded "/"'], 63 ]); 64 65 for (const [specifier, expected] of invalidImportSpecifiers) { 66 loadFixture(specifier).catch(mustCall((err) => { 67 strictEqual(err.code, 'ERR_INVALID_MODULE_SPECIFIER'); 68 assertStartsWith(err.message, 'Invalid module'); 69 assertIncludes(err.message, expected); 70 })); 71 } 72 73 const undefinedImports = new Set([ 74 // Missing import 75 '#missing', 76 // Explicit null import 77 '#null', 78 // No condition match import 79 '#nullcondition', 80 // Null subpath shadowing 81 '#subpath/nullshadow/x', 82 ]); 83 84 for (const specifier of undefinedImports) { 85 loadFixture(specifier).catch(mustCall((err) => { 86 strictEqual(err.code, 'ERR_PACKAGE_IMPORT_NOT_DEFINED'); 87 assertStartsWith(err.message, 'Package import '); 88 assertIncludes(err.message, specifier); 89 })); 90 } 91 92 // Handle not found for the defined imports target not existing 93 loadFixture('#notfound').catch(mustCall((err) => { 94 strictEqual(err.code, 95 isRequire ? 'MODULE_NOT_FOUND' : 'ERR_MODULE_NOT_FOUND'); 96 })); 97}); 98 99// CJS resolver must still support #package packages in node_modules 100requireFixture('#cjs').then(mustCall((actual) => { 101 strictEqual(actual.default, 'cjs backcompat'); 102})); 103 104function assertStartsWith(actual, expected) { 105 const start = actual.toString().substr(0, expected.length); 106 strictEqual(start, expected); 107} 108 109function assertIncludes(actual, expected) { 110 ok(actual.toString().indexOf(expected) !== -1, 111 `${JSON.stringify(actual)} includes ${JSON.stringify(expected)}`); 112} 113 114function assertNotIncludes(actual, expected) { 115 ok(actual.toString().indexOf(expected) === -1, 116 `${JSON.stringify(actual)} doesn't include ${JSON.stringify(expected)}`); 117} 118