fix(static-module-record): make exported unassigned functions fixed
MODIFY
packages/static-module-record/src/babelPlugin.js
packages/static-module-record/src/babelPlugin.js
@@ -61,6 +61,22 @@ function makeModulePlugins(options) {
allowedHiddens.add(id);
};
+ const markExported = (name, force = undefined) => {
+ if (force === 'fixed' || (!force && topLevelIsOnce[name])) {
+ topLevelExported[name].forEach(
+ importTo => (fixedExportMap[importTo] = [name]),
+ );
+ return hOnceId;
+ }
+
+ if (force === 'live' || (!force && !topLevelIsOnce[name])) {
+ topLevelExported[name].forEach(
+ importTo => (liveExportMap[importTo] = [name, true]),
+ );
+ return hLiveId;
+ }
+ };
+
const rewriteVars = (vids, isConst, needsHoisting) =>
vids.reduce((prior, id) => {
const { name } = id;
@@ -76,9 +92,7 @@ function makeModulePlugins(options) {
),
),
);
- for (const importTo of topLevelExported[name]) {
- liveExportMap[importTo] = [name, true];
- }
+ markExported(name, 'live');
} else {
// Make this variable mutable with: let name = $c_name;
soften(id);
@@ -87,24 +101,27 @@ function makeModulePlugins(options) {
t.variableDeclarator(t.identifier(name), id),
]),
);
+ markExported(name, 'live');
}
} else if (topLevelExported[name]) {
if (needsHoisting) {
// Hoist the declaration and soften.
- soften(id);
if (needsHoisting === 'function') {
- options.hoistedDecls.push([name, id.name]);
+ if (!topLevelIsOnce[name]) {
+ soften(id);
+ }
+ options.hoistedDecls.push([name, topLevelIsOnce[name], id.name]);
+ markExported(name);
} else {
// Rewrite to be just name = value.
+ soften(id);
options.hoistedDecls.push([name]);
prior.push(
t.expressionStatement(
t.assignmentExpression('=', t.identifier(name), id),
),
);
- }
- for (const importTo of topLevelExported[name]) {
- liveExportMap[importTo] = [name, true];
+ markExported(name, 'live');
}
} else {
// Just add $h_once.name(name);
@@ -113,9 +130,7 @@ function makeModulePlugins(options) {
t.callExpression(t.memberExpression(hOnceId, id), [id]),
),
);
- for (const importTo of topLevelExported[name]) {
- fixedExportMap[importTo] = [name];
- }
+ markExported(name, 'fixed');
}
}
return prior;
@@ -270,6 +285,7 @@ function makeModulePlugins(options) {
id,
);
let expr = path.node.declaration;
+ const decl = path.node.declaration;
if (expr.type === 'ClassDeclaration') {
expr = t.classExpression(expr.id, expr.superClass, expr.body);
} else if (expr.type === 'FunctionDeclaration') {
@@ -281,7 +297,17 @@ function makeModulePlugins(options) {
expr.async,
);
}
- // const {default: $c_default} = {default: (XXX)}; $h_once.default($c_default);
+
+ if (decl.id) {
+ // Just keep the same declaration and mark it as the default.
+ path.replaceWithMultiple([
+ decl,
+ t.expressionStatement(t.callExpression(callee, [decl.id])),
+ ]);
+ return;
+ }
+
+ // const {default: $c_default} = {default: expr.id}; $h_once.default($c_default);
path.replaceWithMultiple([
t.variableDeclaration('const', [
t.variableDeclarator(
@@ -305,19 +331,11 @@ function makeModulePlugins(options) {
}
if (doTransform) {
if (topLevelExported[name]) {
- const callee = t.memberExpression(
- hiddenIdentifier(h.HIDDEN_LIVE),
- path.node.id,
- );
- path.replaceWith(
- t.blockStatement([
+ const callee = t.memberExpression(markExported(name), path.node.id);
+ path.replaceWithMultiple([
path.node,
t.expressionStatement(t.callExpression(callee, [path.node.id])),
- ]),
- );
- for (const importTo of topLevelExported[name]) {
- liveExportMap[importTo] = [name, true];
- }
+ ]);
}
}
},
@@ -330,13 +348,12 @@ function makeModulePlugins(options) {
const { name } = path.node.id;
if (doAnalyze) {
topLevelIsOnce[name] = path.scope.getBinding(name).constant;
+ // console.error('have function', name, 'is', topLevelIsOnce[name]);
}
if (doTransform) {
if (topLevelExported[name]) {
rewriteDeclaration(path);
- for (const importTo of topLevelExported[name]) {
- liveExportMap[importTo] = [name, true];
- }
+ markExported(name);
}
}
},

MODIFY
packages/static-module-record/src/transform-analyze.js
packages/static-module-record/src/transform-analyze.js
@@ -123,15 +123,16 @@ const makeCreateStaticRecord = transformSource =>
)
.join(',')}]));`;
preamble += sourceOptions.hoistedDecls
- .map(([vname, cvname]) => {
+ .map(([vname, isOnce, cvname]) => {
let src = '';
if (cvname) {
- // It's a function, so set its name property.
+ // It's a function assigned to, so set its name property.
src = `Object.defineProperty(${cvname}, 'name', {value: ${js(
vname,
)}});`;
}
- src += `${h.HIDDEN_LIVE}.${vname}(${cvname || ''});`;
+ const hDeclId = isOnce ? h.HIDDEN_ONCE : h.HIDDEN_LIVE;
+ src += `${hDeclId}.${vname}(${cvname || ''});`;
return src;
})
.join('');

MODIFY
packages/static-module-record/test/test-static-module-record.js
packages/static-module-record/test/test-static-module-record.js
@@ -622,7 +622,7 @@ test('export all', t => {
// TODO cross product let, class, maybe var:
-test.failing('export function should be fixed when not assigned', t => {
+test('export function should be fixed when not assigned', t => {
const { __fixedExportMap__, __liveExportMap__ } = new StaticModuleRecord(`
export function work() {}
`);

fix(static-module-record): make exported unassigned functions fixed