Skip to content

Commit

Permalink
feat(compartment-mapper): add bundle support for commonjs
Browse files Browse the repository at this point in the history
Co-authored-by: naugtur <naugtur@gmail.com>
Co-authered-by: kumavis <kumavis@users.noreply.github.com>
  • Loading branch information
kumavis and naugtur committed Dec 15, 2022
1 parent feb8599 commit aa5e164
Show file tree
Hide file tree
Showing 8 changed files with 234 additions and 139 deletions.
55 changes: 55 additions & 0 deletions packages/compartment-mapper/src/bundle-cjs.js
@@ -0,0 +1,55 @@
/** quotes strings */
const q = JSON.stringify;

const exportsCellRecord = exportsList =>
''.concat(
...exportsList.map(
exportName => `\
${exportName}: cell(${q(exportName)}),
`,
),
);

// This function is serialized and references variables from its destination scope.
const runtime = function wrapCjsFunctor(num) {
/* eslint-disable no-undef */
return ({ imports = {} }) => {
const cModule = Object.freeze(
Object.defineProperty({}, 'exports', cells[num].default),
);
// TODO: specifier not found handling
const requireImpl = specifier => cells[imports[specifier]].default.get();
functors[num](Object.freeze(requireImpl), cModule.exports, cModule);
Object.keys(cells[num])
.filter(k => k !== 'default' && k !== '*')
.map(k => cells[num][k].set(cModule.exports[k]));
};
/* eslint-enable no-undef */
}.toString();

export default {
runtime,
getBundlerKit({
index,
indexedImports,
record: { cjsFunctor, exports: exportsList = {} },
}) {
const importsMap = JSON.stringify(indexedImports);

return {
getFunctor: () => `\
// === functors[${index}] ===
${cjsFunctor},
`,
getCells: () => `\
{
${exportsCellRecord(exportsList)}\
},
`,
getReexportsWiring: () => '',
getFunctorCall: () => `\
wrapCjsFunctor(${index})({imports: ${importsMap}});
`,
};
},
};
120 changes: 120 additions & 0 deletions packages/compartment-mapper/src/bundle-mjs.js
@@ -0,0 +1,120 @@
/** quotes strings */
const q = JSON.stringify;

const exportsCellRecord = exportMap =>
''.concat(
...Object.keys(exportMap).map(
exportName => `\
${exportName}: cell(${q(exportName)}),
`,
),
);

const importsCellSetter = (exportMap, index) =>
''.concat(
...Object.entries(exportMap).map(
([exportName, [importName]]) => `\
${importName}: cells[${index}].${exportName}.set,
`,
),
);

const adaptReexport = reexportMap => {
if (!reexportMap) {
return {};
}
const ret = Object.fromEntries(
Object.values(reexportMap)
.flat()
.map(([local, exported]) => [exported, [local]]),
);
return ret;
};

export const runtime = `\
function observeImports(map, importName, importIndex) {
for (const [name, observers] of map.get(importName)) {
const cell = cells[importIndex][name];
if (cell === undefined) {
throw new ReferenceError(\`Cannot import name \${name}\`);
}
for (const observer of observers) {
cell.observe(observer);
}
}
}
`;

export default {
runtime,
getBundlerKit({
index,
indexedImports,
record: {
__syncModuleProgram__,
__fixedExportMap__ = {},
__liveExportMap__ = {},
__reexportMap__ = {},
reexports,
},
}) {
return {
getFunctor: () => `\
// === functors[${index}] ===
${__syncModuleProgram__},
`,
getCells: () => `\
{
${exportsCellRecord(__fixedExportMap__)}${exportsCellRecord(
__liveExportMap__,
)}${exportsCellRecord(adaptReexport(__reexportMap__))}\
},
`,
getReexportsWiring: () => {
const mappings = reexports.map(
importSpecifier => `\
Object.defineProperties(cells[${index}], Object.getOwnPropertyDescriptors(cells[${indexedImports[importSpecifier]}]));
`,
);
// Create references for export name as newname
const namedReexportsToProcess = Object.entries(__reexportMap__);
if (namedReexportsToProcess.length > 0) {
mappings.push(`
Object.defineProperties(cells[${index}], {${namedReexportsToProcess.map(
([specifier, renames]) => {
return renames.map(
([localName, exportedName]) =>
`${q(exportedName)}: { value: cells[${
indexedImports[specifier]
}][${q(localName)}] }`,
);
},
)} });
`);
}
return mappings.join('');
},
getFunctorCall: () => `\
functors[${index}]({
imports(entries) {
const map = new Map(entries);
${''.concat(
...Object.entries(indexedImports).map(
([importName, importIndex]) => `\
observeImports(map, ${q(importName)}, ${importIndex});
`,
),
)}\
},
liveVar: {
${importsCellSetter(__liveExportMap__, index)}\
},
onceVar: {
${importsCellSetter(__fixedExportMap__, index)}\
},
importMeta: {},
});
`,
};
},
};

0 comments on commit aa5e164

Please sign in to comment.