Skip to content

Commit

Permalink
docs(compartment-mapper): Types and docs for makeBundle internals
Browse files Browse the repository at this point in the history
  • Loading branch information
kriskowal committed Jul 19, 2024
1 parent 6e04072 commit 1412380
Show file tree
Hide file tree
Showing 4 changed files with 99 additions and 28 deletions.
13 changes: 10 additions & 3 deletions packages/compartment-mapper/src/bundle-cjs.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
/* Provides CommonJS support for `bundle.js`. */
// @ts-nocheck

/** @import {VirtualModuleSource} from 'ses' */
/** @import {BundlerSupport} from './bundle.js' */

/** @typedef {VirtualModuleSource & {cjsFunctor: string}} CjsModuleSource */

/** quotes strings */
const q = JSON.stringify;

Expand All @@ -15,7 +20,8 @@ const exportsCellRecord = exportsList =>
);

// This function is serialized and references variables from its destination scope.
const runtime = function wrapCjsFunctor(num) {
const runtime = `\
function wrapCjsFunctor(num) {
/* eslint-disable no-undef */
return ({ imports = {} }) => {
const moduleCells = cells[num];
Expand Down Expand Up @@ -50,8 +56,9 @@ const runtime = function wrapCjsFunctor(num) {
moduleCells['*'].set(Object.freeze(starExports));
};
/* eslint-enable no-undef */
}.toString();
}`;

/** @type {BundlerSupport<CjsModuleSource>} */
export default {
runtime,
getBundlerKit({
Expand Down
4 changes: 4 additions & 0 deletions packages/compartment-mapper/src/bundle-mjs.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
/* Provides ESM support for `bundle.js`. */

/** @import {PrecompiledModuleSource} from 'ses' */
/** @import {BundlerSupport} from './bundle.js' */

/** quotes strings */
const q = JSON.stringify;

Expand Down Expand Up @@ -47,6 +50,7 @@ function observeImports(map, importName, importIndex) {
}
`;

/** @type {BundlerSupport<PrecompiledModuleSource>} */
export default {
runtime,
getBundlerKit({
Expand Down
107 changes: 85 additions & 22 deletions packages/compartment-mapper/src/bundle.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// @ts-check
/* eslint no-shadow: 0 */

/** @import {StaticModuleType} from 'ses' */

/** @import {ArchiveOptions} from './types.js' */
/** @import {CompartmentDescriptor} from './types.js' */
/** @import {CompartmentSources} from './types.js' */
Expand All @@ -11,6 +13,56 @@
/** @import {Sources} from './types.js' */
/** @import {WriteFn} from './types.js' */

/**
* @typedef {object} BundlerKit
* @property {() => string} getFunctor Produces a JavaScript string consisting of
* a function expression followed by a comma delimiter that will be evaluated in
* a lexical scope with no free variables except the globals.
* In the generated bundle runtime, the function will receive an environment
* record: a record mapping every name of the corresponding module's internal
* namespace to a "cell" it can use to get, set, or observe the linked
* variable.
* @property {() => string} getCells Produces a JavaScript string consisting of
* a JavaScript object and a trailing comma.
* The string is evaluated in a lexical context with a `cell` maker, the `cells`
* array of every module's internal environment record.
* @property {() => string} getFunctorCall Produces a JavaScript string may
* be a statement that calls this module's functor with the calling convention
* appropriate for its language, injecting whatever cells it needs to link to
* other module namespaces.
* @property {() => string} getReexportsWiring Produces a JavaScript string
* that may include statements that bind the cells reexported by this module.
*/

/**
* @template {unknown} SpecificModuleSource
* @typedef {object} BundleModule
* @property {string} key
* @property {string} compartmentName
* @property {string} moduleSpecifier
* @property {string} parser
* @property {StaticModuleType & SpecificModuleSource} record
* @property {Record<string, string>} resolvedImports
* @property {Record<string, number>} indexedImports
* @property {Uint8Array} bytes
* @property {number} index
* @property {BundlerKit} bundlerKit
*/

/**
* @template {unknown} SpecificModuleSource
* @callback GetBundlerKit
* @param {BundleModule<SpecificModuleSource>} module
* @returns {BundlerKit}
*/

/**
* @template {unknown} SpecificModuleSource
* @typedef {object} BundlerSupport
* @property {string} runtime
* @property {GetBundlerKit<SpecificModuleSource>} getBundlerKit
*/

import { resolve } from './node-module-specifier.js';
import { compartmentMapForNodeModules } from './node-modules.js';
import { search } from './search.js';
Expand Down Expand Up @@ -40,8 +92,11 @@ const sortedModules = (
entryCompartmentName,
entryModuleSpecifier,
) => {
/** @type {BundleModule<unknown>[]} */
const modules = [];
/** @type {Map<string, string>} aliaes */
const aliases = new Map();
/** @type {Set<string>} seen */
const seen = new Set();

/**
Expand All @@ -58,6 +113,8 @@ const sortedModules = (
const source = compartmentSources[compartmentName][moduleSpecifier];
if (source !== undefined) {
const { record, parser, deferredError, bytes } = source;
assert(parser !== undefined);
assert(bytes !== undefined);
if (deferredError) {
throw Error(
`Cannot bundle: encountered deferredError ${deferredError}`,
Expand Down Expand Up @@ -86,6 +143,10 @@ const sortedModules = (
record,
resolvedImports,
bytes,
// @ts-expect-error
index: undefined,
// @ts-expect-error
bundlerKit: null,
});

return key;
Expand Down Expand Up @@ -119,32 +180,37 @@ const sortedModules = (
return { modules, aliases };
};

const implementationPerParser = {
/** @type {Record<string, BundlerSupport<unknown>>} */
const bundlerSupportForLanguage = {
'pre-mjs-json': mjsSupport,
'pre-cjs-json': cjsSupport,
json: jsonSupport,
};

function getRuntime(parser) {
return implementationPerParser[parser]
? implementationPerParser[parser].runtime
: `/*unknown parser:${parser}*/`;
}

function getBundlerKitForModule(module) {
const parser = module.parser;
if (!implementationPerParser[parser]) {
const warning = `/*unknown parser:${parser}*/`;
/** @param {string} language */
const getRuntime = language =>
bundlerSupportForLanguage[language]
? bundlerSupportForLanguage[language].runtime
: `/*unknown language:${language}*/`;

/** @param {BundleModule<unknown>} module */
const getBundlerKitForModule = module => {
const language = module.parser;
assert(language !== undefined);
if (bundlerSupportForLanguage[language] === undefined) {
const warning = `/*unknown language:${language}*/`;
// each item is a function to avoid creating more in-memory copies of the source text etc.
/** @type {BundlerKit} */
return {
getFunctor: () => `(()=>{${warning}})`,
getCells: `{${warning}}`,
getFunctorCall: warning,
getFunctor: () => `(()=>{${warning}}),`,
getCells: () => `{${warning}},`,
getFunctorCall: () => warning,
getReexportsWiring: () => '',
};
}
const { getBundlerKit } = implementationPerParser[parser];
const { getBundlerKit } = bundlerSupportForLanguage[language];
return getBundlerKit(module);
}
};

/**
* @param {ReadFn | ReadPowers | MaybeReadPowers} readPowers
Expand Down Expand Up @@ -269,10 +335,7 @@ export const makeBundle = async (readPowers, moduleLocation, options) => {

const bundle = `\
'use strict';
(() => {
const functors = [
${''.concat(...modules.map(m => m.bundlerKit.getFunctor()))}\
]; // functors end
(functors => {
const cell = (name, value = undefined) => {
const observers = [];
Expand Down Expand Up @@ -300,7 +363,7 @@ ${''.concat(...modules.map(m => m.bundlerKit.getCells()))}\
${''.concat(...modules.map(m => m.bundlerKit.getReexportsWiring()))}\
const namespaces = cells.map(cells => Object.freeze(Object.create(null, {
const namespaces = cells.map(cells => Object.freeze(Object.create(null, {
...cells,
// Make this appear like an ESM module namespace object.
[Symbol.toStringTag]: {
Expand All @@ -320,7 +383,7 @@ ${''.concat(...Array.from(parsersInUse).map(parser => getRuntime(parser)))}
${''.concat(...modules.map(m => m.bundlerKit.getFunctorCall()))}\
return cells[cells.length - 1]['*'].get();
})();
})([${''.concat(...modules.map(m => m.bundlerKit.getFunctor()))}]);
`;

return bundle;
Expand Down
3 changes: 0 additions & 3 deletions packages/compartment-mapper/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,6 @@

export {};

/** @import {FinalStaticModuleType} from 'ses' */
/** @import {ThirdPartyStaticModuleInterface} from 'ses' */
/** @import {ImportHook} from 'ses' */
/** @import {StaticModuleType} from 'ses' */
/** @import {Transform} from 'ses' */

Expand Down

0 comments on commit 1412380

Please sign in to comment.