diff --git a/packages/compartment-mapper/src/node-modules.js b/packages/compartment-mapper/src/node-modules.js index ef1f183d00..7a9f7c27c1 100644 --- a/packages/compartment-mapper/src/node-modules.js +++ b/packages/compartment-mapper/src/node-modules.js @@ -547,6 +547,11 @@ const gatherDependency = async ( ); }; +/** + * The name used by a root entry compartment that has no `name` in its package descriptor. + */ +export const ANONYMOUS_COMPARTMENT = ''; + /** * graphPackages returns a graph whose keys are nominally URLs, one per * package, with values that are label: (an informative Compartment name, built @@ -621,6 +626,15 @@ const graphPackages = async ( }; } + /** + * If the entry package descriptor has no `name`, we need to put _something_ + * in there to pass compartment map validation (go find + * `assertCompartmentMap()`). + */ + if (!packageDescriptor.name) { + packageDescriptor.name = ANONYMOUS_COMPARTMENT; + } + const graph = create(null); await graphPackage( packageDescriptor.name, diff --git a/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/incognito/index.js b/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/incognito/index.js new file mode 100644 index 0000000000..32802f71ae --- /dev/null +++ b/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/incognito/index.js @@ -0,0 +1 @@ +export default 'doctor emilio lizardo'; diff --git a/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/incognito/package.json b/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/incognito/package.json new file mode 100644 index 0000000000..aead43de36 --- /dev/null +++ b/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/incognito/package.json @@ -0,0 +1,3 @@ +{ + "type": "module" +} \ No newline at end of file diff --git a/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/package.json b/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/package.json new file mode 100644 index 0000000000..7d092e9795 --- /dev/null +++ b/packages/compartment-mapper/test/fixtures-anonymous/node_modules/unnamed/package.json @@ -0,0 +1,11 @@ +{ + "name": "unnamed", + "version": "1.0.0", + "exports": { + "./incognito": "./incognito/index.js" + }, + "type": "commonjs", + "scripts": { + "preinstall": "echo DO NOT INSTALL TEST FIXTURES; exit -1" + } +} diff --git a/packages/compartment-mapper/test/node-modules.test.js b/packages/compartment-mapper/test/node-modules.test.js new file mode 100644 index 0000000000..4af66b28f2 --- /dev/null +++ b/packages/compartment-mapper/test/node-modules.test.js @@ -0,0 +1,58 @@ +import 'ses'; +import fs from 'node:fs'; +import url from 'node:url'; +import test from 'ava'; +import { mapNodeModules } from '../src/node-modules.js'; +import { makeReadPowers } from '../src/node-powers.js'; +import { ANONYMOUS_COMPARTMENT } from '../src/node-modules.js'; + +const { keys, entries, values } = Object; + +test('mapNodeModules() should fulfill with a denormalized CompartmentMapDescriptor', async t => { + t.plan(4); + + const readPowers = makeReadPowers({ fs, url }); + const moduleLocation = `${new URL( + 'fixtures-0/node_modules/bundle/main.js', + import.meta.url, + )}`; + + const { compartments, entry } = await mapNodeModules( + readPowers, + moduleLocation, + ); + + t.deepEqual( + values(compartments) + .map(({ name }) => name) + .sort(), + ['bundle', 'bundle-dep'], + ); + + t.true(keys(compartments).every(name => name.startsWith('file://'))); + + t.is(compartments[entry.compartment].name, 'bundle'); + + t.deepEqual(keys(compartments[entry.compartment].modules).sort(), [ + '.', + 'bundle', + 'bundle-dep', + ]); +}); + +test(`mapNodeModules() should assign a package name when the entry point's package descriptor lacks a "name" field`, async t => { + t.plan(1); + + const readPowers = makeReadPowers({ fs, url }); + const moduleLocation = `${new URL( + 'fixtures-anonymous/node_modules/unnamed/incognito/index.js', + import.meta.url, + )}`; + + const { compartments } = await mapNodeModules(readPowers, moduleLocation); + + t.deepEqual( + values(compartments).map(({ name }) => name), + [ANONYMOUS_COMPARTMENT], + ); +});