@endo/compartment-mapper
Advanced tools
Comparing version 0.7.1 to 0.7.2
@@ -6,2 +6,26 @@ # Change Log | ||
### [0.7.2](https://github.com/endojs/endo/compare/@endo/compartment-mapper@0.7.1...@endo/compartment-mapper@0.7.2) (2022-04-12) | ||
### Features | ||
* **compartment-mapper:** defer import errors based on parser support declaration ([cf074aa](https://github.com/endojs/endo/commit/cf074aab007a3af16ad7ac25b6dc1bd119d6d1b7)) | ||
* **compartment-mapper:** proper default export implementation for cjs with import and require compatibility ([30cbaa8](https://github.com/endojs/endo/commit/30cbaa8cb79b906742a9f5c1854b22fe506b0575)) | ||
* **compartment-mapper:** support for defineProperty on exports with getters ([4764487](https://github.com/endojs/endo/commit/4764487f149a9af225128cec75d557e35d20bf60)) | ||
### Bug Fixes | ||
* **compartment-mapper:** add support for alternatives in exports defnitions ([#1134](https://github.com/endojs/endo/issues/1134)) ([6663f25](https://github.com/endojs/endo/commit/6663f255de7a514aac0f0081eaa99de880298f73)) | ||
* **compartment-mapper:** Avoid some property override pitfalls ([b4efabe](https://github.com/endojs/endo/commit/b4efabee1d13b13af782ae4442daac4691c721b4)) | ||
* **compartment-mapper:** Fix "module" property in package.json ([68395a2](https://github.com/endojs/endo/commit/68395a2b071856dd0dfdf0a1c7c3d57082d7803e)) | ||
* **compartment-mapper:** handle passing and reading exports reference ([#1142](https://github.com/endojs/endo/issues/1142)) ([3b7584a](https://github.com/endojs/endo/commit/3b7584a9bf6b3ba5b4e3f839c230cd07f022d33e)) | ||
* **compartment-mapper:** propagate parse-cjs changes to parse-pre-cjs, remove async from execute in parse-pre-cjs ([8ac94b8](https://github.com/endojs/endo/commit/8ac94b85a11539155929569a86882a05fc146ad3)) | ||
* **compartment-mapper:** Remove stale note ([85a4eb8](https://github.com/endojs/endo/commit/85a4eb81f65dbe4ba746014fad41ab86d1f70167)) | ||
* **compartment-mapper:** there's more benefit to keeping __esModule flag than not ([#1145](https://github.com/endojs/endo/issues/1145)) ([c769447](https://github.com/endojs/endo/commit/c76944794ebbe9e0ec0c8896e5ae9cce2fb17cb3)) | ||
* **endo:** Ensure conditions include default, import, and endo ([1361abd](https://github.com/endojs/endo/commit/1361abd8c732596d192ecef6a039eda98b4ee563)) | ||
* **ses:** avoid cache corruption when execute() throws ([1d9c17b](https://github.com/endojs/endo/commit/1d9c17b4c4a5ed1450cddd996bd948dd59c80bf6)) | ||
### [0.7.1](https://github.com/endojs/endo/compare/@endo/compartment-mapper@0.7.0...@endo/compartment-mapper@0.7.1) (2022-03-07) | ||
@@ -8,0 +32,0 @@ |
{ | ||
"name": "@endo/compartment-mapper", | ||
"version": "0.7.1", | ||
"version": "0.7.2", | ||
"description": "The compartment mapper assembles Node applications in a sandbox", | ||
@@ -44,9 +44,9 @@ "keywords": [ | ||
"dependencies": { | ||
"@endo/cjs-module-analyzer": "^0.2.21", | ||
"@endo/static-module-record": "^0.7.0", | ||
"@endo/zip": "^0.2.21", | ||
"ses": "^0.15.11" | ||
"@endo/cjs-module-analyzer": "^0.2.22", | ||
"@endo/static-module-record": "^0.7.1", | ||
"@endo/zip": "^0.2.22", | ||
"ses": "^0.15.12" | ||
}, | ||
"devDependencies": { | ||
"@endo/eslint-config": "^0.4.6", | ||
"@endo/eslint-config": "^0.4.7", | ||
"ava": "^3.12.1", | ||
@@ -62,3 +62,3 @@ "babel-eslint": "^10.0.3", | ||
"prettier": "^1.19.1", | ||
"typescript": "~4.5.5" | ||
"typescript": "~4.6.2" | ||
}, | ||
@@ -98,3 +98,3 @@ "files": [ | ||
}, | ||
"gitHead": "9ddd58b4a26755cdba9403b0cb042b2067c69832" | ||
"gitHead": "59e511891ab67f4fa52d67141510974e22362134" | ||
} |
@@ -8,3 +8,3 @@ // @ts-check | ||
/** @typedef {import('./types.js').ModuleDescriptor} ModuleDescriptor */ | ||
/** @typedef {import('./types.js').ParseFn} ParseFn */ | ||
/** @typedef {import('./types.js').ParserImplementation} ParserImplementation */ | ||
/** @typedef {import('./types.js').ReadFn} ReadFn */ | ||
@@ -23,5 +23,5 @@ /** @typedef {import('./types.js').CaptureSourceLocationHook} CaptureSourceLocationHook */ | ||
import { makeImportHookMaker } from './import-hook.js'; | ||
import { parseJson } from './parse-json.js'; | ||
import { parseArchiveCjs } from './parse-archive-cjs.js'; | ||
import { parseArchiveMjs } from './parse-archive-mjs.js'; | ||
import parserJson from './parse-json.js'; | ||
import parserArchiveCjs from './parse-archive-cjs.js'; | ||
import parserArchiveMjs from './parse-archive-mjs.js'; | ||
import { parseLocatedJson } from './json.js'; | ||
@@ -33,7 +33,9 @@ import { unpackReadPowers } from './powers.js'; | ||
/** @type {Record<string, ParseFn>} */ | ||
/** @type {Record<string, ParserImplementation>} */ | ||
const parserForLanguage = { | ||
mjs: parseArchiveMjs, | ||
cjs: parseArchiveCjs, | ||
json: parseJson, | ||
mjs: parserArchiveMjs, | ||
'pre-mjs-json': parserArchiveMjs, | ||
cjs: parserArchiveCjs, | ||
'pre-cjs-json': parserArchiveCjs, | ||
json: parserJson, | ||
}; | ||
@@ -56,3 +58,3 @@ | ||
/** @type {Record<string, string>} */ | ||
const renames = {}; | ||
const renames = Object.create(null); | ||
let n = 0; | ||
@@ -73,3 +75,3 @@ for (const [name, compartment] of entries(compartments)) { | ||
const translateCompartmentMap = (compartments, sources, renames) => { | ||
const result = {}; | ||
const result = Object.create(null); | ||
for (const compartmentName of keys(compartments).sort()) { | ||
@@ -81,3 +83,3 @@ const compartment = compartments[compartmentName]; | ||
/** @type {Record<string, ModuleDescriptor>} */ | ||
const modules = {}; | ||
const modules = Object.create(null); | ||
const compartmentModules = compartment.modules; | ||
@@ -103,3 +105,3 @@ if (compartment.modules) { | ||
const source = compartmentSources[name]; | ||
const { location, parser, exit, sha512 } = source; | ||
const { location, parser, exit, sha512, deferredError } = source; | ||
if (location !== undefined) { | ||
@@ -115,2 +117,6 @@ modules[name] = { | ||
}; | ||
} else if (deferredError !== undefined) { | ||
modules[name] = { | ||
deferredError, | ||
}; | ||
} | ||
@@ -208,2 +214,5 @@ } | ||
const tags = new Set(); | ||
tags.add('endo'); | ||
tags.add('import'); | ||
tags.add('default'); | ||
@@ -229,3 +238,3 @@ const packageDescriptor = parseLocatedJson( | ||
/** @type {Sources} */ | ||
const sources = {}; | ||
const sources = Object.create(null); | ||
@@ -232,0 +241,0 @@ const makeImportHook = makeImportHookMaker( |
@@ -6,3 +6,3 @@ // @ts-check | ||
/** @typedef {import('ses').PrecompiledStaticModuleInterface} PrecompiledStaticModuleInterface */ | ||
/** @typedef {import('./types.js').ParseFn} ParseFn */ | ||
/** @typedef {import('./types.js').ParserImplementation} ParserImplementation */ | ||
/** @typedef {import('./types.js').CompartmentDescriptor} CompartmentDescriptor */ | ||
@@ -21,5 +21,5 @@ /** @typedef {import('./types.js').CompartmentSources} CompartmentSources */ | ||
import { makeImportHookMaker } from './import-hook.js'; | ||
import { parseJson } from './parse-json.js'; | ||
import { parseArchiveCjs } from './parse-archive-cjs.js'; | ||
import { parseArchiveMjs } from './parse-archive-mjs.js'; | ||
import parserJson from './parse-json.js'; | ||
import parserArchiveCjs from './parse-archive-cjs.js'; | ||
import parserArchiveMjs from './parse-archive-mjs.js'; | ||
import { parseLocatedJson } from './json.js'; | ||
@@ -32,7 +32,9 @@ | ||
/** @type {Record<string, ParseFn>} */ | ||
/** @type {Record<string, ParserImplementation>} */ | ||
const parserForLanguage = { | ||
mjs: parseArchiveMjs, | ||
cjs: parseArchiveCjs, | ||
json: parseJson, | ||
mjs: parserArchiveMjs, | ||
'pre-mjs-json': parserArchiveMjs, | ||
cjs: parserArchiveCjs, | ||
'pre-cjs-json': parserArchiveCjs, | ||
json: parserJson, | ||
}; | ||
@@ -77,3 +79,3 @@ | ||
} = /** @type {PrecompiledStaticModuleInterface} */ (record); | ||
const resolvedImports = {}; | ||
const resolvedImports = Object.create(null); | ||
for (const importSpecifier of [...imports, ...reexports]) { | ||
@@ -161,3 +163,3 @@ const resolvedSpecifier = resolve(importSpecifier, moduleSpecifier); | ||
/** @type {Sources} */ | ||
const sources = {}; | ||
const sources = Object.create(null); | ||
@@ -190,3 +192,3 @@ const makeImportHook = makeImportHookMaker( | ||
// index of the corresponding functor. | ||
const modulesByKey = {}; | ||
const modulesByKey = Object.create(null); | ||
for (let index = 0; index < modules.length; index += 1) { | ||
@@ -193,0 +195,0 @@ const module = modules[index]; |
@@ -143,3 +143,10 @@ // @ts-check | ||
const { compartment, module, location, parser, exit } = moduleDescriptor; | ||
const { | ||
compartment, | ||
module, | ||
location, | ||
parser, | ||
exit, | ||
deferredError, | ||
} = moduleDescriptor; | ||
if (compartment !== undefined || module !== undefined) { | ||
@@ -151,2 +158,8 @@ assertCompartmentModule(moduleDescriptor, path, url); | ||
assertExitModule(moduleDescriptor, path, url); | ||
} else if (deferredError !== undefined) { | ||
assert.typeof( | ||
deferredError, | ||
'string', | ||
`${path}.deferredError must be a string contaiing an error message`, | ||
); | ||
} else { | ||
@@ -170,3 +183,3 @@ assert.fail( | ||
allegedModules === modules || !Array.isArray(modules), | ||
`modules must be an object, got ${allegedModules} in ${q(url)}`, | ||
`modules must be an object, got ${q(allegedModules)} in ${q(url)}`, | ||
); | ||
@@ -252,3 +265,3 @@ for (const [key, value] of Object.entries(modules)) { | ||
allegedScopes === scopes && !Array.isArray(scopes), | ||
`${path}.scopes must be an object, got ${allegedScopes} in ${q(url)}`, | ||
`${path}.scopes must be an object, got ${q(allegedScopes)} in ${q(url)}`, | ||
); | ||
@@ -361,3 +374,5 @@ | ||
allegedCompartments === compartments || !Array.isArray(compartments), | ||
`compartments must be an object, got ${allegedCompartments} in ${q(url)}`, | ||
`compartments must be an object, got ${q(allegedCompartments)} in ${q( | ||
url, | ||
)}`, | ||
); | ||
@@ -364,0 +379,0 @@ for (const [key, value] of Object.entries(compartments)) { |
@@ -5,3 +5,3 @@ // @ts-check | ||
/** @typedef {import('ses').ImportHook} ImportHook */ | ||
/** @typedef {import('./types.js').ParseFn} ParseFn */ | ||
/** @typedef {import('./types.js').ParserImplementation} ParserImplementation */ | ||
/** @typedef {import('./types.js').CompartmentDescriptor} CompartmentDescriptor */ | ||
@@ -14,2 +14,3 @@ /** @typedef {import('./types.js').Application} Application */ | ||
/** @typedef {import('./types.js').HashFn} HashFn */ | ||
/** @typedef {import('./types.js').StaticModuleType} StaticModuleType */ | ||
/** @typedef {import('./types.js').ComputeSourceLocationHook} ComputeSourceLocationHook */ | ||
@@ -21,5 +22,5 @@ /** @typedef {import('./types.js').LoadArchiveOptions} LoadArchiveOptions */ | ||
import { link } from './link.js'; | ||
import { parsePreCjs } from './parse-pre-cjs.js'; | ||
import { parseJson } from './parse-json.js'; | ||
import { parsePreMjs } from './parse-pre-mjs.js'; | ||
import parserPreCjs from './parse-pre-cjs.js'; | ||
import parserJson from './parse-json.js'; | ||
import parserPreMjs from './parse-pre-mjs.js'; | ||
import { parseLocatedJson } from './json.js'; | ||
@@ -36,10 +37,33 @@ import { unpackReadPowers } from './powers.js'; | ||
/** @type {Record<string, ParseFn>} */ | ||
const { freeze } = Object; | ||
/** @type {Record<string, ParserImplementation>} */ | ||
const parserForLanguage = { | ||
'pre-cjs-json': parsePreCjs, | ||
'pre-mjs-json': parsePreMjs, | ||
json: parseJson, | ||
'pre-cjs-json': parserPreCjs, | ||
'pre-mjs-json': parserPreMjs, | ||
json: parserJson, | ||
}; | ||
/** | ||
* @param {string} errorMessage - error to throw on execute | ||
* @returns {StaticModuleType} | ||
*/ | ||
const postponeErrorToExecute = errorMessage => { | ||
// Return a place-holder that'd throw an error if executed | ||
// This allows cjs parser to more eagerly find calls to require | ||
// - if parser identified a require call that's a local function, execute will never be called | ||
// - if actual required module is missing, the error will happen anyway - at execution time | ||
const record = freeze({ | ||
imports: [], | ||
exports: [], | ||
execute: () => { | ||
throw Error(errorMessage); | ||
}, | ||
}); | ||
return record; | ||
}; | ||
/** | ||
* @callback ArchiveImportHookMaker | ||
@@ -75,2 +99,5 @@ * @param {string} packageLocation | ||
const module = modules[moduleSpecifier]; | ||
if (module.deferredError !== undefined) { | ||
return postponeErrorToExecute(module.deferredError); | ||
} | ||
if (module.parser === undefined) { | ||
@@ -83,4 +110,3 @@ throw new Error( | ||
} | ||
const parse = parserForLanguage[module.parser]; | ||
if (parse === undefined) { | ||
if (parserForLanguage[module.parser] === undefined) { | ||
throw new Error( | ||
@@ -92,2 +118,3 @@ `Cannot parse ${q(module.parser)} module ${q( | ||
} | ||
const { parse } = parserForLanguage[module.parser]; | ||
const moduleLocation = `${packageLocation}/${module.location}`; | ||
@@ -94,0 +121,0 @@ const moduleBytes = get(moduleLocation); |
@@ -8,2 +8,3 @@ // @ts-check | ||
/** @typedef {import('./types.js').Sources} Sources */ | ||
/** @typedef {import('./types.js').CompartmentSources} CompartmentSources */ | ||
/** @typedef {import('./types.js').CompartmentDescriptor} CompartmentDescriptor */ | ||
@@ -41,2 +42,7 @@ /** @typedef {import('./types.js').ImportHookMaker} ImportHookMaker */ | ||
// this is annoying | ||
function getImportsFromRecord(record) { | ||
return (has(record, 'record') ? record.record.imports : record.imports) || []; | ||
} | ||
/** | ||
@@ -54,16 +60,56 @@ * @param {ReadFn} read | ||
baseLocation, | ||
sources = {}, | ||
compartments = {}, | ||
exitModules = {}, | ||
sources = Object.create(null), | ||
compartments = Object.create(null), | ||
exitModules = Object.create(null), | ||
computeSha512 = undefined, | ||
) => { | ||
// Set of specifiers for modules whose parser is not using heuristics to determine imports | ||
const strictlyRequired = new Set(); | ||
// per-assembly: | ||
/** @type {ImportHookMaker} */ | ||
const makeImportHook = (packageLocation, _packageName, parse) => { | ||
const makeImportHook = ( | ||
packageLocation, | ||
_packageName, | ||
parse, | ||
shouldDeferError, | ||
) => { | ||
// per-compartment: | ||
packageLocation = resolveLocation(packageLocation, baseLocation); | ||
const packageSources = sources[packageLocation] || {}; | ||
const packageSources = sources[packageLocation] || Object.create(null); | ||
sources[packageLocation] = packageSources; | ||
const { modules = {} } = compartments[packageLocation] || {}; | ||
const { modules = Object.create(null) } = | ||
compartments[packageLocation] || {}; | ||
/** | ||
* @param {string} specifier | ||
* @param {Error} error - error to throw on execute | ||
* @returns {StaticModuleType} | ||
*/ | ||
const deferError = (specifier, error) => { | ||
// strictlyRequired is populated with imports declared by modules whose parser is not using heuristics to figure | ||
// out imports. We're guaranteed they're reachable. If the same module is imported and required, it will not | ||
// defer, because importing from esm makes it strictly required. | ||
// Note that ultimately a situation may arise, with exit modules, where the module never reaches importHook but | ||
// its imports do. In that case the notion of strictly required is no longer boolean, it's true,false,noidea. | ||
if (strictlyRequired.has(specifier)) { | ||
throw error; | ||
} | ||
// Return a place-holder that'd throw an error if executed | ||
// This allows cjs parser to more eagerly find calls to require | ||
// - if parser identified a require call that's a local function, execute will never be called | ||
// - if actual required module is missing, the error will happen anyway - at execution time | ||
const record = freeze({ | ||
imports: [], | ||
exports: [], | ||
execute: () => { | ||
throw error; | ||
}, | ||
}); | ||
packageSources[specifier] = { | ||
deferredError: error.message, | ||
}; | ||
return record; | ||
}; | ||
/** @type {ImportHook} */ | ||
@@ -85,6 +131,9 @@ const importHook = async moduleSpecifier => { | ||
} | ||
throw new Error( | ||
`Cannot find external module ${q( | ||
moduleSpecifier, | ||
)} in package ${packageLocation}`, | ||
return deferError( | ||
moduleSpecifier, | ||
new Error( | ||
`Cannot find external module ${q( | ||
moduleSpecifier, | ||
)} in package ${packageLocation}`, | ||
), | ||
); | ||
@@ -168,2 +217,9 @@ } | ||
}; | ||
if (!shouldDeferError(parser)) { | ||
getImportsFromRecord(record).forEach( | ||
strictlyRequired.add, | ||
strictlyRequired, | ||
); | ||
} | ||
return record; | ||
@@ -173,9 +229,12 @@ } | ||
// TODO offer breadcrumbs in the error message, or how to construct breadcrumbs with another tool. | ||
throw new Error( | ||
`Cannot find file for internal module ${q( | ||
moduleSpecifier, | ||
)} (with candidates ${candidates | ||
.map(x => q(x)) | ||
.join(', ')}) in package ${packageLocation}`, | ||
return deferError( | ||
moduleSpecifier, | ||
// TODO offer breadcrumbs in the error message, or how to construct breadcrumbs with another tool. | ||
new Error( | ||
`Cannot find file for internal module ${q( | ||
moduleSpecifier, | ||
)} (with candidates ${candidates | ||
.map(x => q(x)) | ||
.join(', ')}) in package ${packageLocation}`, | ||
), | ||
); | ||
@@ -182,0 +241,0 @@ }; |
@@ -8,3 +8,3 @@ // @ts-check | ||
/** @typedef {import('./types.js').ExecuteOptions} ExecuteOptions */ | ||
/** @typedef {import('./types.js').ParseFn} ParseFn */ | ||
/** @typedef {import('./types.js').ParserImplementation} ParserImplementation */ | ||
/** @typedef {import('./types.js').ReadFn} ReadFn */ | ||
@@ -17,13 +17,13 @@ /** @typedef {import('./types.js').ReadPowers} ReadPowers */ | ||
import { makeImportHookMaker } from './import-hook.js'; | ||
import { parseJson } from './parse-json.js'; | ||
import { parseCjs } from './parse-cjs.js'; | ||
import { parseMjs } from './parse-mjs.js'; | ||
import parserJson from './parse-json.js'; | ||
import parserCjs from './parse-cjs.js'; | ||
import parserMjs from './parse-mjs.js'; | ||
import { parseLocatedJson } from './json.js'; | ||
import { unpackReadPowers } from './powers.js'; | ||
/** @type {Record<string, ParseFn>} */ | ||
/** @type {Record<string, ParserImplementation>} */ | ||
export const parserForLanguage = { | ||
mjs: parseMjs, | ||
cjs: parseCjs, | ||
json: parseJson, | ||
mjs: parserMjs, | ||
cjs: parserCjs, | ||
json: parserJson, | ||
}; | ||
@@ -30,0 +30,0 @@ |
@@ -8,2 +8,3 @@ // @ts-check | ||
const { entries, fromEntries } = Object; | ||
const { isArray } = Array; | ||
@@ -38,2 +39,11 @@ /** | ||
function* interpretExports(name, exports, tags) { | ||
if (isArray(exports)) { | ||
for (const section of exports) { | ||
const results = [...interpretExports(name, section, tags)]; | ||
if (results.length > 0) { | ||
yield* results; | ||
break; | ||
} | ||
} | ||
} | ||
if (typeof exports === 'string') { | ||
@@ -86,16 +96,14 @@ yield [name, relativize(exports)]; | ||
// entries. | ||
if (main !== undefined) { | ||
yield [name, relativize(main)]; | ||
} | ||
if (module !== undefined && tags.has('import')) { | ||
// In this one case, the key "module" has carried a hint that the | ||
// referenced module is an ECMASCript module, and that hint is necessary to | ||
// override whatever type might be inferred from the module specifier | ||
// extension. | ||
// referenced module is an ECMASCript module, and that hint may be | ||
// necessary to override whatever type might be inferred from the module | ||
// specifier extension. | ||
const spec = relativize(module); | ||
types[spec] = 'mjs'; | ||
yield [name, spec]; | ||
} | ||
if (browser !== undefined && tags.has('browser')) { | ||
yield [name, relativize(module)]; | ||
} else if (browser !== undefined && tags.has('browser')) { | ||
yield* interpretBrowserExports(name, browser); | ||
} else if (main !== undefined) { | ||
yield [name, relativize(main)]; | ||
} | ||
@@ -118,10 +126,2 @@ if (exports !== undefined) { | ||
* | ||
* TODO When a package does not supply the `exports` property, this function | ||
* needs to infer that all JavaScript modules in the package are exported. | ||
* Most packages will need this. | ||
* This function can remain synchronous if we pre-populate a file manifest for | ||
* every package. | ||
* That manifest will also prove useful for resolving aliases, like the | ||
* implicit index.js modules within a package. | ||
* | ||
* @param {Object} descriptor - the parsed body of a package.json file. | ||
@@ -128,0 +128,0 @@ * @param {Set<string>} tags - build tags about the target environment |
@@ -6,2 +6,4 @@ // @ts-check | ||
/** @typedef {import('./types.js').ParseFn} ParseFn */ | ||
/** @typedef {import('./types.js').ParserImplementation} ParserImplementation */ | ||
/** @typedef {import('./types.js').ShouldDeferError} ShouldDeferError */ | ||
/** @typedef {import('./types.js').ModuleTransforms} ModuleTransforms */ | ||
@@ -68,3 +70,3 @@ /** @typedef {import('./types.js').Language} Language */ | ||
* from its extension. | ||
* @param {Record<string, ParseFn>} parserForLanguage | ||
* @param {Record<string, ParserImplementation>} parserForLanguage | ||
* @param {ModuleTransforms} transforms | ||
@@ -107,3 +109,3 @@ * @returns {ParseFn} | ||
} | ||
const parse = parserForLanguage[language]; | ||
const { parse } = parserForLanguage[language]; | ||
return parse(bytes, specifier, location, packageLocation); | ||
@@ -117,3 +119,3 @@ }; | ||
* is implied by package.json and should not be inferred from its extension. | ||
* @param {Record<string, ParseFn>} parserForLanguage | ||
* @param {Record<string, ParserImplementation>} parserForLanguage | ||
* @param {ModuleTransforms} transforms | ||
@@ -333,5 +335,5 @@ * @returns {ParseFn} | ||
/** @type {Record<string, Compartment>} */ | ||
const compartments = {}; | ||
const compartments = Object.create(null); | ||
/** @type {Record<string, ResolveHook>} */ | ||
const resolvers = {}; | ||
const resolvers = Object.create(null); | ||
for (const [compartmentName, compartmentDescriptor] of entries( | ||
@@ -343,6 +345,6 @@ compartmentDescriptors, | ||
name, | ||
modules = {}, | ||
parsers: languageForExtension = {}, | ||
types: languageForModuleSpecifier = {}, | ||
scopes = {}, | ||
modules = Object.create(null), | ||
parsers: languageForExtension = Object.create(null), | ||
types: languageForModuleSpecifier = Object.create(null), | ||
scopes = Object.create(null), | ||
} = compartmentDescriptor; | ||
@@ -360,3 +362,14 @@ | ||
); | ||
const importHook = makeImportHook(location, name, parse); | ||
/** @type {ShouldDeferError} */ | ||
const shouldDeferError = language => { | ||
if (language && has(parserForLanguage, language)) { | ||
return parserForLanguage[language].heuristicImports; | ||
} else { | ||
// If language is undefined or there's no parser, the error we could consider deferring is surely related to | ||
// that. Nothing to throw here. | ||
return false; | ||
} | ||
}; | ||
const importHook = makeImportHook(location, name, parse, shouldDeferError); | ||
const moduleMapHook = makeModuleMapHook( | ||
@@ -363,0 +376,0 @@ compartments, |
@@ -168,3 +168,3 @@ // @ts-check | ||
const inferParsers = (descriptor, location) => { | ||
const { type, parsers } = descriptor; | ||
const { type, module, parsers } = descriptor; | ||
if (parsers !== undefined) { | ||
@@ -190,3 +190,3 @@ if (typeof parsers !== 'object') { | ||
} | ||
if (type === 'module') { | ||
if (type === 'module' || module !== undefined) { | ||
return moduleParsers; | ||
@@ -369,2 +369,4 @@ } | ||
tags.add('import'); | ||
tags.add('default'); | ||
tags.add('endo'); | ||
@@ -410,3 +412,3 @@ if (packageDescriptor === undefined) { | ||
/** @type {Record<string, CompartmentDescriptor>} */ | ||
const compartments = {}; | ||
const compartments = Object.create(null); | ||
@@ -427,5 +429,5 @@ // For each package, build a map of all the external modules the package can | ||
/** @type {Record<string, ModuleDescriptor>} */ | ||
const modules = {}; | ||
const modules = Object.create(null); | ||
/** @type {Record<string, ScopeDescriptor>} */ | ||
const scopes = {}; | ||
const scopes = Object.create(null); | ||
/** | ||
@@ -432,0 +434,0 @@ * @param {string} dependencyName |
@@ -28,2 +28,6 @@ // @ts-check | ||
if (!exports.includes('default')) { | ||
exports.push('default'); | ||
} | ||
const pre = textEncoder.encode( | ||
@@ -51,1 +55,7 @@ JSON.stringify({ | ||
}; | ||
/** @type {import('./types.js').ParserImplementation} */ | ||
export default { | ||
parse: parseArchiveCjs, | ||
heuristicImports: true, | ||
}; |
@@ -24,1 +24,7 @@ // @ts-check | ||
}; | ||
/** @type {import('./types.js').ParserImplementation} */ | ||
export default { | ||
parse: parseArchiveMjs, | ||
heuristicImports: false, | ||
}; |
// @ts-check | ||
import { analyzeCommonJS } from '@endo/cjs-module-analyzer'; | ||
import { wrap } from './parse-cjs-shared-export-wrapper.js'; | ||
@@ -23,2 +24,6 @@ const textDecoder = new TextDecoder(); | ||
if (!exports.includes('default')) { | ||
exports.push('default'); | ||
} | ||
/** | ||
@@ -34,41 +39,11 @@ * @param {Object} moduleEnvironmentRecord | ||
const originalExports = new Proxy( | ||
Object.create(compartment.globalThis.Object.prototype), | ||
{ | ||
get(target, prop) { | ||
return moduleEnvironmentRecord[prop] || target[prop]; // this makes things like exports.hasOwnProperty() work. | ||
}, | ||
set(target, prop, value) { | ||
moduleEnvironmentRecord[prop] = value; | ||
return true; | ||
}, | ||
}, | ||
const { require, moduleExports, module, afterExecute } = wrap( | ||
moduleEnvironmentRecord, | ||
compartment, | ||
resolvedImports, | ||
); | ||
let finalExports = originalExports; | ||
const module = freeze({ | ||
get exports() { | ||
return finalExports; | ||
}, | ||
set exports(value) { | ||
finalExports = value; | ||
}, | ||
}); | ||
const require = freeze((/** @type {string} */ importSpecifier) => { | ||
const namespace = compartment.importNow(resolvedImports[importSpecifier]); | ||
if (namespace.default !== undefined) { | ||
if (Object.keys(namespace).length > 1) { | ||
return { ...namespace.default, ...namespace }; // this resembles Node's behavior more closely | ||
} else { | ||
return namespace.default; | ||
} | ||
} | ||
return namespace; | ||
}); | ||
functor( | ||
require, | ||
finalExports, | ||
moduleExports, | ||
module, | ||
@@ -78,5 +53,4 @@ location, // __filename | ||
); | ||
if (finalExports !== originalExports) { | ||
moduleEnvironmentRecord.default = finalExports; | ||
} | ||
afterExecute(); | ||
}; | ||
@@ -90,1 +64,7 @@ | ||
}; | ||
/** @type {import('./types.js').ParserImplementation} */ | ||
export default { | ||
parse: parseCjs, | ||
heuristicImports: true, | ||
}; |
@@ -41,1 +41,7 @@ // @ts-check | ||
}; | ||
/** @type {import('./types.js').ParserImplementation} */ | ||
export default { | ||
parse: parseJson, | ||
heuristicImports: false, | ||
}; |
@@ -22,1 +22,7 @@ // @ts-check | ||
}; | ||
/** @type {import('./types.js').ParserImplementation} */ | ||
export default { | ||
parse: parseMjs, | ||
heuristicImports: false, | ||
}; |
// @ts-check | ||
import { parseLocatedJson } from './json.js'; | ||
import { wrap } from './parse-cjs-shared-export-wrapper.js'; | ||
const { freeze } = Object; | ||
const textDecoder = new TextDecoder(); | ||
@@ -31,26 +30,15 @@ | ||
/** | ||
* @param {Object} moduleExports | ||
* @param {Object} moduleEnvironmentRecord | ||
* @param {Compartment} compartment | ||
* @param {Record<string, string>} resolvedImports | ||
*/ | ||
const execute = async (moduleExports, compartment, resolvedImports) => { | ||
const execute = (moduleEnvironmentRecord, compartment, resolvedImports) => { | ||
const functor = compartment.evaluate(source); | ||
const module = freeze({ | ||
get exports() { | ||
return moduleExports; | ||
}, | ||
set exports(value) { | ||
moduleExports.default = value; | ||
}, | ||
}); | ||
const { require, moduleExports, module, afterExecute } = wrap( | ||
moduleEnvironmentRecord, | ||
compartment, | ||
resolvedImports, | ||
); | ||
const require = freeze((/** @type {string} */ importSpecifier) => { | ||
const namespace = compartment.importNow(resolvedImports[importSpecifier]); | ||
if (namespace.default !== undefined) { | ||
return namespace.default; | ||
} | ||
return namespace; | ||
}); | ||
functor( | ||
@@ -63,2 +51,4 @@ require, | ||
); | ||
afterExecute(); | ||
}; | ||
@@ -77,1 +67,7 @@ | ||
}; | ||
/** @type {import('./types.js').ParserImplementation} */ | ||
export default { | ||
parse: parsePreCjs, | ||
heuristicImports: true, | ||
}; |
@@ -24,1 +24,7 @@ // @ts-check | ||
}; | ||
/** @type {import('./types.js').ParserImplementation} */ | ||
export default { | ||
parse: parsePreMjs, | ||
heuristicImports: false, | ||
}; |
@@ -62,2 +62,3 @@ // @ts-check | ||
* @property {string} [exit] | ||
* @property {string} [deferredError] | ||
*/ | ||
@@ -173,2 +174,8 @@ | ||
/** | ||
* @callback ShouldDeferError | ||
* @param {Language | undefined} language | ||
* @returns {boolean} | ||
*/ | ||
/** | ||
* @callback ImportHookMaker | ||
@@ -178,3 +185,3 @@ * @param {string} packageLocation | ||
* @param {ParseFn} parse | ||
* @param {Record<string, Object>} exitModules | ||
* @param {ShouldDeferError} shouldDeferError | ||
* @returns {ImportHook} | ||
@@ -197,2 +204,11 @@ */ | ||
/** | ||
* ParserImplementation declares if a heuristic is used by parser to detect | ||
* imports - is set to true for cjs, which uses a lexer to find require calls | ||
* | ||
* @typedef {Object} ParserImplementation | ||
* @property {boolean} heuristicImports | ||
* @property {ParseFn} parse | ||
*/ | ||
/** | ||
* @callback ComputeSourceLocationHook | ||
@@ -223,3 +239,3 @@ * @param {string} compartmentName | ||
/** | ||
* @typedef {Record<string, ParseFn>} ParserForLanguage | ||
* @typedef {Record<string, ParserImplementation>} ParserForLanguage | ||
*/ | ||
@@ -263,2 +279,3 @@ | ||
* @typedef {Object} ModuleSource | ||
* @property {string} [deferredError] - module loading error deferred to later stage | ||
* @property {string} [location] - package relative location | ||
@@ -265,0 +282,0 @@ * @property {string} [sourceLocation] - fully qualified location |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Dynamic require
Supply chain riskDynamic require can indicate the package is performing dangerous or unsafe dynamic code execution.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
178754
37
3844
1
Updated@endo/zip@^0.2.22
Updatedses@^0.15.12