Nicolò Ribaudo 6ef7b51a11 Implement assumptions defined in the babel/rfcs#5 RFC
- `mutableTemplateObject` and `ignoreToPrimitiveHint` (#12408)
- `setClassMethods` (#12407)
- `setComputedProperties` (#12490)
- `ignoreFunctionLength` (#12491)
- `noDocumentAll` (#12481)
- `iterableIsArray` and `arrayLikeIsIterable` (#12489)
- `pureGetters` (#12504)
- `skipForOfIteratorClosing` (#12496)
- `objectRestNoSymbols`, `setSpreadProperties` and `pureGetters` (#12505)
- `noNewArrows` (#12613, #12793)
- `setPublicClassFields` and `privateFieldsAsProperties` (#12497)
- `constantReexports` and `enumerableModuleMeta` (#12618)
- `constantSuper`, `superIsCallableConstructor` and `noClassCalls` (#12726)

Co-authored-by: Justin Ridgewell <justin@ridgewell.name>
Co-authored-by: Huáng Jùnliàng <JLHwung@users.noreply.github.com>
2021-02-21 17:09:45 +01:00

176 lines
4.9 KiB
JavaScript

import { declare } from "@babel/helper-plugin-utils";
import {
isModule,
rewriteModuleStatementsAndPrepareHeader,
hasExports,
isSideEffectImport,
buildNamespaceInitStatements,
ensureStatementsHoisted,
wrapInterop,
getModuleName,
} from "@babel/helper-module-transforms";
import { template, types as t } from "@babel/core";
import { getImportSource } from "babel-plugin-dynamic-import-node/utils";
const buildWrapper = template(`
define(MODULE_NAME, AMD_ARGUMENTS, function(IMPORT_NAMES) {
})
`);
const buildAnonymousWrapper = template(`
define(["require"], function(REQUIRE) {
})
`);
function injectWrapper(path, wrapper) {
const { body, directives } = path.node;
path.node.directives = [];
path.node.body = [];
const amdWrapper = path.pushContainer("body", wrapper)[0];
const amdFactory = amdWrapper
.get("expression.arguments")
.filter(arg => arg.isFunctionExpression())[0]
.get("body");
amdFactory.pushContainer("directives", directives);
amdFactory.pushContainer("body", body);
}
export default declare((api, options) => {
api.assertVersion(7);
const { allowTopLevelThis, strict, strictMode, noInterop } = options;
const constantReexports =
api.assumption("constantReexports") ?? options.loose;
const enumerableModuleMeta =
api.assumption("enumerableModuleMeta") ?? options.loose;
return {
name: "transform-modules-amd",
pre() {
this.file.set("@babel/plugin-transform-modules-*", "amd");
},
visitor: {
CallExpression(path, state) {
if (!this.file.has("@babel/plugin-proposal-dynamic-import")) return;
if (!path.get("callee").isImport()) return;
let { requireId, resolveId, rejectId } = state;
if (!requireId) {
requireId = path.scope.generateUidIdentifier("require");
state.requireId = requireId;
}
if (!resolveId || !rejectId) {
resolveId = path.scope.generateUidIdentifier("resolve");
rejectId = path.scope.generateUidIdentifier("reject");
state.resolveId = resolveId;
state.rejectId = rejectId;
}
let result = t.identifier("imported");
if (!noInterop) result = wrapInterop(path, result, "namespace");
path.replaceWith(
template.expression.ast`
new Promise((${resolveId}, ${rejectId}) =>
${requireId}(
[${getImportSource(t, path.node)}],
imported => ${t.cloneNode(resolveId)}(${result}),
${t.cloneNode(rejectId)}
)
)`,
);
},
Program: {
exit(path, { requireId }) {
if (!isModule(path)) {
if (requireId) {
injectWrapper(
path,
buildAnonymousWrapper({ REQUIRE: t.cloneNode(requireId) }),
);
}
return;
}
const amdArgs = [];
const importNames = [];
if (requireId) {
amdArgs.push(t.stringLiteral("require"));
importNames.push(t.cloneNode(requireId));
}
let moduleName = getModuleName(this.file.opts, options);
if (moduleName) moduleName = t.stringLiteral(moduleName);
const { meta, headers } = rewriteModuleStatementsAndPrepareHeader(
path,
{
enumerableModuleMeta,
constantReexports,
strict,
strictMode,
allowTopLevelThis,
noInterop,
},
);
if (hasExports(meta)) {
amdArgs.push(t.stringLiteral("exports"));
importNames.push(t.identifier(meta.exportName));
}
for (const [source, metadata] of meta.source) {
amdArgs.push(t.stringLiteral(source));
importNames.push(t.identifier(metadata.name));
if (!isSideEffectImport(metadata)) {
const interop = wrapInterop(
path,
t.identifier(metadata.name),
metadata.interop,
);
if (interop) {
const header = t.expressionStatement(
t.assignmentExpression(
"=",
t.identifier(metadata.name),
interop,
),
);
header.loc = metadata.loc;
headers.push(header);
}
}
headers.push(
...buildNamespaceInitStatements(
meta,
metadata,
constantReexports,
),
);
}
ensureStatementsHoisted(headers);
path.unshiftContainer("body", headers);
injectWrapper(
path,
buildWrapper({
MODULE_NAME: moduleName,
AMD_ARGUMENTS: t.arrayExpression(amdArgs),
IMPORT_NAMES: importNames,
}),
);
},
},
},
};
});