From 3f7aa665051c006e05406ad5c199640f8040376f Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Tue, 23 Jul 2024 11:51:46 -0700 Subject: [PATCH 1/2] refactor(compartment-mapper): Alias conditions to tags --- packages/compartment-mapper/NEWS.md | 2 + packages/compartment-mapper/README.md | 41 +++++--------- .../compartment-mapper/src/archive-lite.js | 2 +- packages/compartment-mapper/src/archive.js | 16 +++--- packages/compartment-mapper/src/bundle.js | 7 ++- .../compartment-mapper/src/capture-lite.js | 2 +- .../compartment-mapper/src/compartment-map.js | 24 +++++--- packages/compartment-mapper/src/import.js | 4 +- .../compartment-mapper/src/infer-exports.js | 34 ++++++------ .../compartment-mapper/src/node-modules.js | 55 +++++++++++-------- packages/compartment-mapper/src/types.js | 9 ++- .../test/infer-exports.test.js | 4 +- packages/compartment-mapper/test/main.test.js | 2 +- .../compartment-mapper/test/policy.test.js | 4 +- packages/compartment-mapper/test/scaffold.js | 23 ++++---- 15 files changed, 119 insertions(+), 110 deletions(-) diff --git a/packages/compartment-mapper/NEWS.md b/packages/compartment-mapper/NEWS.md index d98df7d920..d710cf475d 100644 --- a/packages/compartment-mapper/NEWS.md +++ b/packages/compartment-mapper/NEWS.md @@ -22,6 +22,8 @@ User-visible changes to the compartment mapper: The new `import-lite.js` does not entrain `node-modules.js` and composes with potential alternative package discovery, storage, and locks. - Adds JSON module support to `makeBundle`. +- Aliases and deprecates `tags` in favor of `conditions` to align with Node.js + terminology. # 0.9.0 (2023-08-07) diff --git a/packages/compartment-mapper/README.md b/packages/compartment-mapper/README.md index 5d2a88d24d..68ed240a52 100644 --- a/packages/compartment-mapper/README.md +++ b/packages/compartment-mapper/README.md @@ -164,27 +164,15 @@ in a parent directory, under `node_modules`. The `main`, `browser`, and `exports` properties determine the modules each package exports to other compartments. -The `exports` property describes [package entry points] and can be influenced -by build _tags_. -Currently, the only tag supported by the compartment mapper is `import`, which -indicates that the module map should use ESM modules over CommonJS modules or -other variants. - -> TODO -> -> A future version may reveal other tags like `browser` to prepare an -> application for use in a web client. -> For this case, the compartment mapper would prepare a JSON manifest like an -> `importmap` (if not precisely an `importmap`). -> The "compartment map" would be consistent except when the dependency graph -> changes so updates could be automated with a `postinstall` script. -> Preparing a web application for production would follow a process similar to -> creating an archive, but with the `browser` build tag. - -The `browser` and `require` tags are well-known but not yet supported. -The `browser` tag will apply for compartment maps generated for use on the web. -The `require` tag is a fallback for environments that do not support ESM and -will never apply. +The `exports` property describes [package entry points][] and can be influenced +by build _conditions_. +Currently, the only conditions supported by the compartment mapper are +`import`, `browser`, and `endo`. +The `imports` condition indicates that the module map should use ESM modules +over CommonJS modules or other variants, and `endo`. +The `browser` condition also draws in the `browser` property from +`package.json` instead of `main`. +The `endo` condition only indicates that this tool is in use. If no `exports` apply to the root of the compartment namespace (`"."`), the `main` property serves as a default. @@ -284,7 +272,7 @@ Node.js platform. > For browser applications, the compartment mapper would use the translator > modules in two modes. > During development, the compartment mapper would be able to load the -> translator in the client, with the `browser` tag. +> translator in the client, with the `browser` condition. > The compartment mapper would also be able to run the translator in a separate > non-browser compartment during bundling, so the translator can be excluded > from the production application and archived applications. @@ -392,18 +380,19 @@ The compartment map shape: // CompartmentMap describes how to prepare compartments // to run an application. type CompartmentMap = { - tags: Tags, + conditions: Conditions, entry: Entry, compartments: Record, realms: Record, // TODO }; -// Tags are the build tags for the compartment. +// Conditions influence which modules are selected +// to represent the implementation of various modules. // These may include terms like "browser", meaning // each compartment uses the implementation of each // module suitable for use in a browser environment. -type Tags = Array; -type Tag = string; +type Conditions = Array; +type Condition = string; // Entry is a reference to the module that is the module to initially import. type Entry = CompartmentModule; diff --git a/packages/compartment-mapper/src/archive-lite.js b/packages/compartment-mapper/src/archive-lite.js index f48f62e0c3..d7a70f19bd 100644 --- a/packages/compartment-mapper/src/archive-lite.js +++ b/packages/compartment-mapper/src/archive-lite.js @@ -281,7 +281,7 @@ export const makeArchiveCompartmentMap = (compartmentMap, sources) => { const archiveSources = renameSources(sources, compartmentRenames); const archiveCompartmentMap = { - tags: [], + conditions: [], entry: { compartment: archiveEntryCompartmentName, module: entryModuleSpecifier, diff --git a/packages/compartment-mapper/src/archive.js b/packages/compartment-mapper/src/archive.js index 9eab2f1d3a..f3d209fac1 100644 --- a/packages/compartment-mapper/src/archive.js +++ b/packages/compartment-mapper/src/archive.js @@ -72,11 +72,11 @@ export const makeAndHashArchive = async ( * @returns {Promise} */ export const makeArchive = async (powers, moduleLocation, options = {}) => { - const { dev, tags, commonDependencies, policy } = options; + const { dev, tags, conditions = tags, commonDependencies, policy } = options; const compartmentMap = await mapNodeModules(powers, moduleLocation, { dev, - tags, + conditions, commonDependencies, policy, }); @@ -95,11 +95,11 @@ export const makeArchive = async (powers, moduleLocation, options = {}) => { * @returns {Promise} */ export const mapLocation = async (powers, moduleLocation, options = {}) => { - const { dev, tags, commonDependencies, policy } = options; + const { dev, tags, conditions = tags, commonDependencies, policy } = options; const compartmentMap = await mapNodeModules(powers, moduleLocation, { dev, - tags, + conditions, commonDependencies, policy, }); @@ -114,11 +114,11 @@ export const mapLocation = async (powers, moduleLocation, options = {}) => { * @returns {Promise} */ export const hashLocation = async (powers, moduleLocation, options = {}) => { - const { dev, tags, commonDependencies, policy } = options; + const { dev, tags, conditions = tags, commonDependencies, policy } = options; const compartmentMap = await mapNodeModules(powers, moduleLocation, { dev, - tags, + conditions, commonDependencies, policy, }); @@ -140,10 +140,10 @@ export const writeArchive = async ( moduleLocation, options = {}, ) => { - const { dev, tags, commonDependencies, policy } = options; + const { dev, tags, conditions = tags, commonDependencies, policy } = options; const compartmentMap = await mapNodeModules(readPowers, moduleLocation, { dev, - tags, + conditions, commonDependencies, policy, }); diff --git a/packages/compartment-mapper/src/bundle.js b/packages/compartment-mapper/src/bundle.js index bbee7f3360..c7bcd78d01 100644 --- a/packages/compartment-mapper/src/bundle.js +++ b/packages/compartment-mapper/src/bundle.js @@ -224,14 +224,15 @@ export const makeBundle = async (readPowers, moduleLocation, options) => { const { moduleTransforms, dev, - tags: tagsOption, + tags, + conditions: conditionsOption = tags, searchSuffixes, commonDependencies, sourceMapHook = undefined, parserForLanguage: parserForLanguageOption = {}, languageForExtension: languageForExtensionOption = {}, } = options || {}; - const tags = new Set(tagsOption); + const conditions = new Set(conditionsOption); const parserForLanguage = Object.freeze( Object.assign( @@ -258,7 +259,7 @@ export const makeBundle = async (readPowers, moduleLocation, options) => { const compartmentMap = await compartmentMapForNodeModules( read, packageLocation, - tags, + conditions, packageDescriptor, moduleSpecifier, { dev, commonDependencies }, diff --git a/packages/compartment-mapper/src/capture-lite.js b/packages/compartment-mapper/src/capture-lite.js index 0ba4efbc6e..f584218e1c 100644 --- a/packages/compartment-mapper/src/capture-lite.js +++ b/packages/compartment-mapper/src/capture-lite.js @@ -227,7 +227,7 @@ const captureCompartmentMap = (compartmentMap, sources) => { const captureSources = renameSources(sources, compartmentRenames); const captureCompartmentMap = { - tags: [], + conditions: [], entry: { compartment: captureEntryCompartmentName, module: entryModuleSpecifier, diff --git a/packages/compartment-mapper/src/compartment-map.js b/packages/compartment-mapper/src/compartment-map.js index 8b23459fe1..ef5fd024b5 100644 --- a/packages/compartment-mapper/src/compartment-map.js +++ b/packages/compartment-mapper/src/compartment-map.js @@ -85,20 +85,20 @@ const assertEmptyObject = (object, message) => { }; /** - * @param {unknown} tags + * @param {unknown} conditions * @param {string} url */ -const assertTags = (tags, url) => { - if (tags === undefined) return; +const assertConditions = (conditions, url) => { + if (conditions === undefined) return; assert( - Array.isArray(tags), - `tags must be an array, got ${tags} in ${q(url)}`, + Array.isArray(conditions), + `conditions must be an array, got ${conditions} in ${q(url)}`, ); - for (const [index, value] of enumerate(tags)) { + for (const [index, value] of enumerate(conditions)) { assert.typeof( value, 'string', - `tags[${index}] must be a string, got ${value} in ${q(url)}`, + `conditions[${index}] must be a string, got ${value} in ${q(url)}`, ); } }; @@ -480,14 +480,20 @@ export const assertCompartmentMap = ( url, )}`, ); - const { tags, entry, compartments, ...extra } = Object(compartmentMap); + const { + tags, + conditions = tags, + entry, + compartments, + ...extra + } = Object(compartmentMap); assertEmptyObject( extra, `Compartment map must not have extra properties, got ${q( Object.keys(extra), )} in ${q(url)}`, ); - assertTags(tags, url); + assertConditions(conditions, url); assertEntry(entry, url); assertCompartments(compartments, url); }; diff --git a/packages/compartment-mapper/src/import.js b/packages/compartment-mapper/src/import.js index 578a1f7265..151b4c3985 100644 --- a/packages/compartment-mapper/src/import.js +++ b/packages/compartment-mapper/src/import.js @@ -48,10 +48,10 @@ export const loadLocation = async ( moduleLocation, options = {}, ) => { - const { dev, tags, commonDependencies, policy } = options; + const { dev, tags, conditions = tags, commonDependencies, policy } = options; const compartmentMap = await mapNodeModules(readPowers, moduleLocation, { dev, - tags, + conditions, commonDependencies, policy, }); diff --git a/packages/compartment-mapper/src/infer-exports.js b/packages/compartment-mapper/src/infer-exports.js index 436a14577b..f0be444a9f 100644 --- a/packages/compartment-mapper/src/infer-exports.js +++ b/packages/compartment-mapper/src/infer-exports.js @@ -57,15 +57,15 @@ function* interpretBrowserField(name, browser, main = 'index.js') { /** * @param {string} name - the name of the referrer package. * @param {object} exports - the `exports` field from a package.json. - * @param {Set} tags - build tags about the target environment + * @param {Set} conditions - build conditions about the target environment * for selecting relevant exports, e.g., "browser" or "node". * @yields {[string, string]} * @returns {Generator<[string, string]>} */ -function* interpretExports(name, exports, tags) { +function* interpretExports(name, exports, conditions) { if (isArray(exports)) { for (const section of exports) { - const results = [...interpretExports(name, section, tags)]; + const results = [...interpretExports(name, section, conditions)]; if (results.length > 0) { yield* results; break; @@ -84,12 +84,12 @@ function* interpretExports(name, exports, tags) { for (const [key, value] of entries(exports)) { if (key.startsWith('./') || key === '.') { if (name === '.') { - yield* interpretExports(key, value, tags); + yield* interpretExports(key, value, conditions); } else { - yield* interpretExports(join(name, key), value, tags); + yield* interpretExports(join(name, key), value, conditions); } - } else if (tags.has(key)) { - yield* interpretExports(name, value, tags); + } else if (conditions.has(key)) { + yield* interpretExports(name, value, conditions); // Take only the first matching tag. break; } @@ -110,7 +110,7 @@ function* interpretExports(name, exports, tags) { * @param {string} packageDescriptor.main * @param {string} [packageDescriptor.module] * @param {object} [packageDescriptor.exports] - * @param {Set} tags - build tags about the target environment + * @param {Set} conditions - build conditions about the target environment * for selecting relevant exports, e.g., "browser" or "node". * @param {LanguageForExtension} types - an object to populate * with any recognized module's type, if implied by a tag. @@ -118,12 +118,12 @@ function* interpretExports(name, exports, tags) { */ export const inferExportsEntries = function* inferExportsEntries( { main, module, exports }, - tags, + conditions, types, ) { // From lowest to highest precedence, such that later entries override former // entries. - if (module !== undefined && tags.has('import')) { + if (module !== undefined && conditions.has('import')) { // In this one case, the key "module" has carried a hint that the // referenced module is an ECMASCript module, and that hint may be // necessary to override whatever type might be inferred from the module @@ -135,7 +135,7 @@ export const inferExportsEntries = function* inferExportsEntries( yield ['.', relativize(main)]; } if (exports !== undefined) { - yield* interpretExports('.', exports, tags); + yield* interpretExports('.', exports, conditions); } // TODO Otherwise, glob 'files' for all '.js', '.cjs', and '.mjs' entry // modules, taking care to exclude node_modules. @@ -151,20 +151,20 @@ export const inferExportsEntries = function* inferExportsEntries( * package's module map, like `./index.js`. * * @param {object} descriptor - the parsed body of a package.json file. - * @param {Set} tags - build tags about the target environment + * @param {Set} conditions - build conditions about the target environment * for selecting relevant exports, e.g., "browser" or "node". * @param {LanguageForExtension} types - an object to populate * with any recognized module's type, if implied by a tag. * @returns {Record} */ -export const inferExports = (descriptor, tags, types) => - fromEntries(inferExportsEntries(descriptor, tags, types)); +export const inferExports = (descriptor, conditions, types) => + fromEntries(inferExportsEntries(descriptor, conditions, types)); export const inferExportsAndAliases = ( descriptor, externalAliases, internalAliases, - tags, + conditions, types, ) => { const { name, type, main, module, exports, browser } = descriptor; @@ -172,7 +172,7 @@ export const inferExportsAndAliases = ( // collect externalAliases from exports and main/module assign( externalAliases, - fromEntries(inferExportsEntries(descriptor, tags, types)), + fromEntries(inferExportsEntries(descriptor, conditions, types)), ); // expose default module as package root @@ -188,7 +188,7 @@ export const inferExportsAndAliases = ( } // if present, allow "browser" field to populate moduleMap - if (tags.has('browser') && browser !== undefined) { + if (conditions.has('browser') && browser !== undefined) { for (const [specifier, target] of interpretBrowserField( name, browser, diff --git a/packages/compartment-mapper/src/node-modules.js b/packages/compartment-mapper/src/node-modules.js index c4290b2d60..f57d1a2f02 100644 --- a/packages/compartment-mapper/src/node-modules.js +++ b/packages/compartment-mapper/src/node-modules.js @@ -276,7 +276,7 @@ const inferParsers = ( * @param {object} packageDetails * @param {string} packageDetails.packageLocation * @param {object} packageDetails.packageDescriptor - * @param {Set} tags + * @param {Set} conditions * @param {boolean} dev * @param {CommonDependencyDescriptors} commonDependencyDescriptors * @param {Map>} preferredPackageLogicalPathMap @@ -289,7 +289,7 @@ const graphPackage = async ( canonical, graph, { packageLocation, packageDescriptor }, - tags, + conditions, dev, commonDependencyDescriptors, preferredPackageLogicalPathMap = new Map(), @@ -359,7 +359,7 @@ const graphPackage = async ( dependencyLocations, packageLocation, name, - tags, + conditions, preferredPackageLogicalPathMap, childLogicalPath, optional, @@ -388,7 +388,7 @@ const graphPackage = async ( packageDescriptor, externalAliases, internalAliases, - tags, + conditions, types, ); @@ -453,7 +453,7 @@ const graphPackage = async ( * @param {Record} dependencyLocations * @param {string} packageLocation - location of the package of interest. * @param {string} name - name of the package of interest. - * @param {Set} tags + * @param {Set} conditions * @param {Map>} preferredPackageLogicalPathMap * @param {Array} [childLogicalPath] * @param {boolean} [optional] - whether the dependency is optional @@ -466,7 +466,7 @@ const gatherDependency = async ( dependencyLocations, packageLocation, name, - tags, + conditions, preferredPackageLogicalPathMap, childLogicalPath = [], optional = false, @@ -501,7 +501,7 @@ const gatherDependency = async ( canonical, graph, dependency, - tags, + conditions, false, commonDependencyDescriptors, preferredPackageLogicalPathMap, @@ -521,7 +521,7 @@ const gatherDependency = async ( * @param {MaybeReadFn} maybeRead * @param {CanonicalFn} canonical * @param {string} packageLocation - location of the main package. - * @param {Set} tags + * @param {Set} conditions * @param {object} mainPackageDescriptor - the parsed contents of the main * package.json, which was already read when searching for the package.json. * @param {boolean} dev - whether to use devDependencies from this package (and @@ -532,7 +532,7 @@ const graphPackages = async ( maybeRead, canonical, packageLocation, - tags, + conditions, mainPackageDescriptor, dev, commonDependencies = {}, @@ -551,10 +551,10 @@ const graphPackages = async ( const packageDescriptor = await readDescriptor(packageLocation); - tags = new Set(tags || []); - tags.add('import'); - tags.add('default'); - tags.add('endo'); + conditions = new Set(conditions || []); + conditions.add('import'); + conditions.add('default'); + conditions.add('endo'); if (packageDescriptor === undefined) { throw Error( @@ -589,7 +589,7 @@ const graphPackages = async ( packageLocation, packageDescriptor, }, - tags, + conditions, dev, commonDependencyDescriptors, ); @@ -603,7 +603,7 @@ const graphPackages = async ( * @param {string} entryPackageLocation * @param {string} entryModuleSpecifier * @param {Graph} graph - * @param {Set} tags - build tags about the target environment + * @param {Set} conditions - build conditions about the target environment * for selecting relevant exports, e.g., "browser" or "node". * @param {import('./types.js').Policy} [policy] * @returns {CompartmentMapDescriptor} @@ -612,7 +612,7 @@ const translateGraph = ( entryPackageLocation, entryModuleSpecifier, graph, - tags, + conditions, policy, ) => { /** @type {Record} */ @@ -728,7 +728,7 @@ const translateGraph = ( } return { - tags: [...tags], + conditions: [...conditions], entry: { compartment: entryPackageLocation, module: entryModuleSpecifier, @@ -740,7 +740,7 @@ const translateGraph = ( /** * @param {ReadFn | ReadPowers | MaybeReadPowers} readPowers * @param {string} packageLocation - * @param {Set} tags + * @param {Set} conditions * @param {object} packageDescriptor * @param {string} moduleSpecifier * @param {object} [options] @@ -752,7 +752,7 @@ const translateGraph = ( export const compartmentMapForNodeModules = async ( readPowers, packageLocation, - tags, + conditions, packageDescriptor, moduleSpecifier, options = {}, @@ -763,7 +763,7 @@ export const compartmentMapForNodeModules = async ( maybeRead, canonical, packageLocation, - tags, + conditions, packageDescriptor, dev, commonDependencies, @@ -789,7 +789,7 @@ export const compartmentMapForNodeModules = async ( packageLocation, moduleSpecifier, graph, - tags, + conditions, policy, ); @@ -800,7 +800,8 @@ export const compartmentMapForNodeModules = async ( * @param {ReadFn | ReadPowers | MaybeReadPowers} readPowers * @param {string} moduleLocation * @param {object} [options] - * @param {Set} [options.tags] + * @param {Set} [options.tags] deprecated in favor of `conditions` + * @param {Set} [options.conditions] * @param {boolean} [options.dev] * @param {object} [options.commonDependencies] * @param {object} [options.policy] @@ -811,7 +812,13 @@ export const mapNodeModules = async ( moduleLocation, options = {}, ) => { - const { tags = new Set(), dev = false, commonDependencies, policy } = options; + const { + tags = new Set(), + conditions = tags, + dev = false, + commonDependencies, + policy, + } = options; const { maybeRead } = unpackReadPowers(readPowers); @@ -830,7 +837,7 @@ export const mapNodeModules = async ( return compartmentMapForNodeModules( readPowers, packageLocation, - tags, + conditions, packageDescriptor, moduleSpecifier, { dev, commonDependencies, policy }, diff --git a/packages/compartment-mapper/src/types.js b/packages/compartment-mapper/src/types.js index c10fd28f2d..800c663df0 100644 --- a/packages/compartment-mapper/src/types.js +++ b/packages/compartment-mapper/src/types.js @@ -17,7 +17,8 @@ export {}; * Compartments, each corresponding to Node.js style packaged modules. * * @typedef {object} CompartmentMapDescriptor - * @property {Array} tags + * @property {Array} [tags] is deprecated in favor of `conditions` + * @property {Array} conditions * @property {EntryDescriptor} entry * @property {Record} compartments */ @@ -424,7 +425,8 @@ export {}; * @property {Record} [modules] * @property {boolean} [dev] * @property {SomePolicy} [policy] - * @property {Set} [tags] + * @property {Set} [tags] deprecated in favor of `conditions` + * @property {Set} [conditions] * @property {CaptureSourceLocationHook} [captureSourceLocation] * @property {ExitModuleImportHook} [importHook] * @property {Array} [searchSuffixes] @@ -627,7 +629,8 @@ export {}; * @property {Record} [modules] * @property {boolean} [dev] * @property {SomePolicy} [policy] - * @property {Set} [tags] + * @property {Set} [tags] deprecated in favor of `conditions` + * @property {Set} [conditions] * @property {ExitModuleImportHook} [importHook] * @property {Array} [searchSuffixes] * @property {Record} [commonDependencies] diff --git a/packages/compartment-mapper/test/infer-exports.test.js b/packages/compartment-mapper/test/infer-exports.test.js index 9793a4e026..ee8189cc45 100644 --- a/packages/compartment-mapper/test/infer-exports.test.js +++ b/packages/compartment-mapper/test/infer-exports.test.js @@ -2,11 +2,11 @@ import test from 'ava'; import { inferExports } from '../src/infer-exports.js'; function scaffold(cases) { - const tags = new Set(['node', 'import', 'default']); + const conditions = new Set(['node', 'import', 'default']); cases.forEach(pkg => { test(`infer-exports for ${pkg.name}`, t => { const types = {}; - const exports = inferExports(pkg, tags, types); + const exports = inferExports(pkg, conditions, types); t.snapshot({ types, exports }); }); }); diff --git a/packages/compartment-mapper/test/main.test.js b/packages/compartment-mapper/test/main.test.js index ab1806d887..28a5e81797 100644 --- a/packages/compartment-mapper/test/main.test.js +++ b/packages/compartment-mapper/test/main.test.js @@ -207,7 +207,7 @@ scaffold( }); }, 1, - { tags: new Set(['browser']) }, + { conditions: new Set(['browser']) }, ); scaffold( diff --git a/packages/compartment-mapper/test/policy.test.js b/packages/compartment-mapper/test/policy.test.js index 72f1e87572..547fcd0c93 100644 --- a/packages/compartment-mapper/test/policy.test.js +++ b/packages/compartment-mapper/test/policy.test.js @@ -200,7 +200,7 @@ scaffold( }, }, // 'eve' defines a browser override for 'dan' pointing to 'hackity' - tags: new Set(['browser']), + conditions: new Set(['browser']), }, ); @@ -222,7 +222,7 @@ scaffold( addGlobals: globals, policy, // This turns alice malicious - attempting to redirect alice.js to an outside module - tags: new Set(['browser']), + conditions: new Set(['browser']), }, ); diff --git a/packages/compartment-mapper/test/scaffold.js b/packages/compartment-mapper/test/scaffold.js index 7876649d46..bf1303283f 100644 --- a/packages/compartment-mapper/test/scaffold.js +++ b/packages/compartment-mapper/test/scaffold.js @@ -87,6 +87,7 @@ export function scaffold( policy, knownFailure = false, tags = undefined, + conditions = tags, searchSuffixes = undefined, commonDependencies = undefined, additionalOptions = {}, @@ -130,7 +131,7 @@ export function scaffold( const application = await loadLocation(readPowers, fixture, { dev: true, policy, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -154,7 +155,7 @@ export function scaffold( modules, Compartment, dev: true, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -172,7 +173,7 @@ export function scaffold( modules, dev: true, policy, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -209,7 +210,7 @@ export function scaffold( modules, dev: true, policy, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -254,7 +255,7 @@ export function scaffold( modules: { builtin: true }, dev: true, policy, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -307,7 +308,7 @@ export function scaffold( policy, modules, dev: true, - tags, + conditions, searchSuffixes, commonDependencies, sourceMapHook, @@ -344,7 +345,7 @@ export function scaffold( modules, Compartment, dev: true, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -353,7 +354,7 @@ export function scaffold( const archiveBytes = await makeArchive(readPowers, fixture, { modules, dev: true, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -366,7 +367,7 @@ export function scaffold( { modules, dev: true, - tags, + conditions, computeSha512, expectedSha512, ...additionalOptions, @@ -384,7 +385,7 @@ export function scaffold( modules, Compartment, dev: true, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, @@ -393,7 +394,7 @@ export function scaffold( const archive = await makeArchive(readPowers, fixture, { modules, dev: true, - tags, + conditions, searchSuffixes, commonDependencies, ...additionalOptions, From 7e516a08f6fa2bf92d22687d5cd52581cd4222cb Mon Sep 17 00:00:00 2001 From: Kris Kowal Date: Tue, 23 Jul 2024 11:54:14 -0700 Subject: [PATCH 2/2] refactor(bundle-source): Rename tags to conditions --- packages/bundle-source/NEWS.md | 4 +- packages/bundle-source/cache.js | 44 ++++++++++--------- packages/bundle-source/src/main.js | 12 ++--- packages/bundle-source/src/script.js | 4 +- packages/bundle-source/src/types.js | 2 +- packages/bundle-source/src/zip-base64.js | 6 +-- .../bundle-source/test/tags-command.test.js | 6 +-- 7 files changed, 40 insertions(+), 38 deletions(-) diff --git a/packages/bundle-source/NEWS.md b/packages/bundle-source/NEWS.md index a110edc50f..f86e77ebef 100644 --- a/packages/bundle-source/NEWS.md +++ b/packages/bundle-source/NEWS.md @@ -11,8 +11,8 @@ - Adds a `-f,--format` command flag to specify other module formats. - Adds a new `endoScript` module format. - Adds a no-cache, bundle-to-stdout mode. -- Adds a `-t,--tag` command flag to specify export/import conditions like - `"browser"`. +- Adds a `-C,--condition` command flag to specify export/import conditions like + `"development"` or `"browser"`. # v3.2.1 (2024-03-20) diff --git a/packages/bundle-source/cache.js b/packages/bundle-source/cache.js index 6506dbfc7d..74220fa760 100644 --- a/packages/bundle-source/cache.js +++ b/packages/bundle-source/cache.js @@ -20,7 +20,7 @@ const { Fail, quote: q } = assert; * @property {number} bundleSize * @property {boolean} noTransforms * @property {ModuleFormat} format - * @property {string[]} tags + * @property {string[]} conditions * @property {{ relative: string, absolute: string }} moduleSource * @property {Array<{ relativePath: string, mtime: string, size: number }>} contents */ @@ -53,6 +53,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { * @param {object} [options] * @param {boolean} [options.noTransforms] * @param {string[]} [options.tags] + * @param {string[]} [options.conditions] * @param {ModuleFormat} [options.format] */ const add = async (rootPath, targetName, log = defaultLog, options = {}) => { @@ -61,10 +62,10 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { const { noTransforms = false, format = 'endoZipBase64', - tags = [], + conditions = [], } = options; - tags.sort(); + conditions.sort(); const statsByPath = new Map(); @@ -93,7 +94,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { const bundle = await bundleSource( rootPath, - { ...bundleOptions, noTransforms, format }, + { ...bundleOptions, noTransforms, format, conditions }, { ...readPowers, read: loggedRead, @@ -123,7 +124,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { ), noTransforms, format, - tags, + conditions, }; await metaWr.atomicWriteText(JSON.stringify(meta, null, 2)); @@ -154,6 +155,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { * @param {boolean} [options.noTransforms] * @param {ModuleFormat} [options.format] * @param {string[]} [options.tags] + * @param {string[]} [options.conditions] * @returns {Promise} */ const validate = async ( @@ -167,9 +169,9 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { const { noTransforms: expectedNoTransforms, format: expectedFormat, - tags: expectedTags = [], + conditions: expectedConditions = [], } = options; - expectedTags.sort(); + expectedConditions.sort(); if (!meta) { const metaJson = await loadMetaText(targetName, log); if (metaJson) { @@ -194,15 +196,15 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { moduleSource: { absolute: moduleSource }, format = 'endoZipBase64', noTransforms = false, - tags = [], + conditions = [], } = meta; - tags.sort(); + conditions.sort(); assert.equal(bundleFileName, toBundleName(targetName)); assert.equal(format, expectedFormat); assert.equal(noTransforms, expectedNoTransforms); - assert.equal(tags.length, expectedTags.length); - tags.forEach((tag, index) => { - assert.equal(tag, expectedTags[index]); + assert.equal(conditions.length, expectedConditions.length); + conditions.forEach((tag, index) => { + assert.equal(tag, expectedConditions[index]); }); if (rootOpt) { moduleSource === cwd.neighbor(rootOpt).absolute() || @@ -250,7 +252,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { * @param {object} [options] * @param {boolean} [options.noTransforms] * @param {ModuleFormat} [options.format] - * @param {string[]} [options.tags] + * @param {string[]} [options.conditions] * @returns {Promise} */ const validateOrAdd = async ( @@ -269,7 +271,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { meta = await validate(targetName, rootPath, log, meta, { format: options.format, noTransforms: options.noTransforms, - tags: options.tags, + conditions: options.conditions, }); const { bundleTime, @@ -277,7 +279,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { contents, noTransforms, format = 'endoZipBase64', - tags = [], + conditions = [], } = meta; log( `${wr}`, @@ -291,8 +293,8 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { noTransforms ? 'w/o transforms' : 'with transforms', 'with format', format, - 'and tags', - JSON.stringify(tags), + 'and conditions', + JSON.stringify(conditions), ); } catch (invalid) { meta = undefined; @@ -309,7 +311,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { contents, noTransforms, format = 'endoZipBase64', - tags = [], + conditions = [], } = meta; log( `${wr}`, @@ -322,8 +324,8 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { noTransforms ? 'w/o transforms' : 'with transforms', 'with format', format, - 'and tags', - JSON.stringify(tags), + 'and conditions', + JSON.stringify(conditions), ); } @@ -338,7 +340,7 @@ export const makeBundleCache = (wr, cwd, readPowers, opts) => { * @param {object} [options] * @param {boolean} [options.noTransforms] * @param {ModuleFormat} [options.format] - * @param {string[]} [options.tags] + * @param {string[]} [options.conditions] */ const load = async ( rootPath, diff --git a/packages/bundle-source/src/main.js b/packages/bundle-source/src/main.js index 4f31983c19..11bdd02c0e 100644 --- a/packages/bundle-source/src/main.js +++ b/packages/bundle-source/src/main.js @@ -11,7 +11,7 @@ const USAGE = `\ bundle-source [-Tft] bundle-source [-Tft] --cache-js|--cache-json ( )* -f,--format endoZipBase64*|nestedEvaluate|getExport - -t,--tag (browser, node, &c) + -C,--condition (browser, node, development, &c) -T,--no-transforms`; const options = /** @type {const} */ ({ @@ -33,9 +33,9 @@ const options = /** @type {const} */ ({ short: 'f', multiple: false, }, - tag: { + condition: { type: 'string', - short: 't', + short: 'C', multiple: true, }, // deprecated @@ -58,7 +58,7 @@ export const main = async (args, { loadModule, pid, log }) => { const { values: { format: moduleFormat = 'endoZipBase64', - tag: tags = [], + condition: conditions = [], 'no-transforms': noTransforms, 'cache-json': cacheJson, 'cache-js': cacheJs, @@ -94,7 +94,7 @@ export const main = async (args, { loadModule, pid, log }) => { const bundle = await bundleSource(entryPath, { noTransforms, format, - tags, + conditions, }); process.stdout.write(JSON.stringify(bundle)); process.stdout.write('\n'); @@ -125,7 +125,7 @@ export const main = async (args, { loadModule, pid, log }) => { await cache.validateOrAdd(bundleRoot, bundleName, undefined, { noTransforms, format, - tags, + conditions, }); } }; diff --git a/packages/bundle-source/src/script.js b/packages/bundle-source/src/script.js index 2e430927b9..3e08e8347b 100644 --- a/packages/bundle-source/src/script.js +++ b/packages/bundle-source/src/script.js @@ -37,7 +37,7 @@ export async function bundleScript( dev = false, cacheSourceMaps = false, noTransforms = false, - tags = [], + conditions = [], commonDependencies, } = options; const powers = { ...readPowers, ...grantedPowers }; @@ -70,7 +70,7 @@ export async function bundleScript( const source = await makeBundle(powers, entry, { dev, - tags, + conditions, commonDependencies, parserForLanguage, moduleTransforms, diff --git a/packages/bundle-source/src/types.js b/packages/bundle-source/src/types.js index 836f1b4326..087e0adab7 100644 --- a/packages/bundle-source/src/types.js +++ b/packages/bundle-source/src/types.js @@ -70,7 +70,7 @@ export {}; * @property {boolean} [noTransforms] - when true, generates a bundle with the * original sources instead of SES-shim specific ESM and CJS. This may become * default in a future major version. - * @property {string[]} [tags] - conditions for package.json conditional + * @property {string[]} [conditions] - conditions for package.json conditional * exports and imports. */ diff --git a/packages/bundle-source/src/zip-base64.js b/packages/bundle-source/src/zip-base64.js index e7bd1e29d8..dbf7cb0089 100644 --- a/packages/bundle-source/src/zip-base64.js +++ b/packages/bundle-source/src/zip-base64.js @@ -22,7 +22,7 @@ const readPowers = makeReadPowers({ fs, url, crypto }); * @param {boolean} [options.dev] * @param {boolean} [options.cacheSourceMaps] * @param {boolean} [options.noTransforms] - * @param {string[]} [options.tags] + * @param {string[]} [options.condditions] * @param {Record} [options.commonDependencies] * @param {object} [grantedPowers] * @param {(bytes: string | Uint8Array) => string} [grantedPowers.computeSha512] @@ -40,7 +40,7 @@ export async function bundleZipBase64( dev = false, cacheSourceMaps = false, noTransforms = false, - tags = [], + conditions = [], commonDependencies, } = options; const powers = { ...readPowers, ...grantedPowers }; @@ -73,7 +73,7 @@ export async function bundleZipBase64( const compartmentMap = await mapNodeModules(powers, entry, { dev, - tags, + conditions, commonDependencies, }); diff --git a/packages/bundle-source/test/tags-command.test.js b/packages/bundle-source/test/tags-command.test.js index ead4ccd88b..c0a4065ff8 100644 --- a/packages/bundle-source/test/tags-command.test.js +++ b/packages/bundle-source/test/tags-command.test.js @@ -40,11 +40,11 @@ const bundleSource = async (...args) => { return JSON.parse(bundleText); }; -test('bundle-source with --format and --tag', async t => { +test('bundle-source with --format and --condition', async t => { const compartment = new Compartment(); { const bundle = await bundleSource( - '--tag', + '--condition', 'b', '--format', 'endoScript', @@ -55,7 +55,7 @@ test('bundle-source with --format and --tag', async t => { } { const bundle = await bundleSource( - '--tag', + '--condition', 'a', '--format', 'endoScript',