Convert AMD to use new shared implementation.
This commit is contained in:
@@ -1,143 +1,111 @@
|
||||
import { basename, extname } from "path";
|
||||
import template from "babel-template";
|
||||
import transformCommonjs from "babel-plugin-transform-es2015-modules-commonjs";
|
||||
import {
|
||||
rewriteModuleStatementsAndPrepareHeader,
|
||||
hasExports,
|
||||
getSourceMetadataArray,
|
||||
buildNamespaceInitStatements,
|
||||
ensureStatementsHoisted,
|
||||
wrapInterop,
|
||||
} from "babel-helper-modules";
|
||||
|
||||
const buildDefine = template(`
|
||||
define(MODULE_NAME, [SOURCES], FACTORY);
|
||||
`);
|
||||
|
||||
const buildFactory = template(`
|
||||
(function (PARAMS) {
|
||||
BODY;
|
||||
const buildWrapper = template(`
|
||||
define(MODULE_NAME, AMD_ARGUMENTS, function(IMPORT_NAMES) {
|
||||
})
|
||||
`);
|
||||
|
||||
export default function({ types: t }) {
|
||||
function isValidRequireCall(path) {
|
||||
if (!path.isCallExpression()) return false;
|
||||
if (!path.get("callee").isIdentifier({ name: "require" })) return false;
|
||||
if (path.scope.getBinding("require")) return false;
|
||||
|
||||
const args = path.get("arguments");
|
||||
if (args.length !== 1) return false;
|
||||
|
||||
const arg = args[0];
|
||||
if (!arg.isStringLiteral()) return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
function buildParamsAndSource(sourcesFound) {
|
||||
const params = [];
|
||||
const sources = [];
|
||||
|
||||
let hasSeenNonBareRequire = false;
|
||||
for (let i = sourcesFound.length - 1; i > -1; i--) {
|
||||
const source = sourcesFound[i];
|
||||
|
||||
sources.unshift(source[1]);
|
||||
|
||||
// bare import at end, no need for param
|
||||
if (!hasSeenNonBareRequire && source[2] === true) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hasSeenNonBareRequire = true;
|
||||
params.unshift(source[0]);
|
||||
}
|
||||
|
||||
return [params, sources];
|
||||
}
|
||||
|
||||
const amdVisitor = {
|
||||
ReferencedIdentifier({ node, scope }) {
|
||||
if (node.name === "exports" && !scope.getBinding("exports")) {
|
||||
this.hasExports = true;
|
||||
}
|
||||
|
||||
if (node.name === "module" && !scope.getBinding("module")) {
|
||||
this.hasModule = true;
|
||||
}
|
||||
},
|
||||
|
||||
CallExpression(path) {
|
||||
if (!isValidRequireCall(path)) return;
|
||||
const source = path.node.arguments[0];
|
||||
const ref = path.scope.generateUidIdentifier(
|
||||
basename(source.value, extname(source.value)),
|
||||
);
|
||||
this.sources.push([ref, source, true]);
|
||||
path.remove();
|
||||
},
|
||||
|
||||
VariableDeclarator(path) {
|
||||
const id = path.get("id");
|
||||
if (!id.isIdentifier()) return;
|
||||
|
||||
const init = path.get("init");
|
||||
if (!isValidRequireCall(init)) return;
|
||||
|
||||
const source = init.node.arguments[0];
|
||||
this.sourceNames[source.value] = true;
|
||||
|
||||
this.sources.push([id.node, source]);
|
||||
|
||||
path.remove();
|
||||
},
|
||||
};
|
||||
|
||||
return {
|
||||
inherits: transformCommonjs,
|
||||
|
||||
pre() {
|
||||
// source strings
|
||||
this.sources = [];
|
||||
this.sourceNames = Object.create(null);
|
||||
|
||||
this.hasExports = false;
|
||||
this.hasModule = false;
|
||||
},
|
||||
|
||||
visitor: {
|
||||
Program: {
|
||||
exit(path) {
|
||||
if (this.ran) return;
|
||||
this.ran = true;
|
||||
|
||||
path.traverse(amdVisitor, this);
|
||||
|
||||
const [params, sources] = buildParamsAndSource(this.sources);
|
||||
exit(path, state) {
|
||||
const {
|
||||
loose,
|
||||
allowTopLevelThis,
|
||||
strict,
|
||||
strictMode,
|
||||
noInterop,
|
||||
} = state.opts;
|
||||
|
||||
let moduleName = this.getModuleName();
|
||||
if (moduleName) moduleName = t.stringLiteral(moduleName);
|
||||
|
||||
if (this.hasExports) {
|
||||
sources.unshift(t.stringLiteral("exports"));
|
||||
params.unshift(t.identifier("exports"));
|
||||
}
|
||||
|
||||
if (this.hasModule) {
|
||||
sources.unshift(t.stringLiteral("module"));
|
||||
params.unshift(t.identifier("module"));
|
||||
}
|
||||
|
||||
const { node } = path;
|
||||
const factory = buildFactory({
|
||||
PARAMS: params,
|
||||
BODY: node.body,
|
||||
const {
|
||||
meta,
|
||||
headers,
|
||||
} = rewriteModuleStatementsAndPrepareHeader(path, {
|
||||
loose,
|
||||
strict,
|
||||
strictMode,
|
||||
allowTopLevelThis,
|
||||
noInterop,
|
||||
});
|
||||
factory.expression.body.directives = node.directives;
|
||||
node.directives = [];
|
||||
|
||||
node.body = [];
|
||||
const amdArgs = [];
|
||||
const commonjsArgs = [];
|
||||
const importNames = [];
|
||||
|
||||
path.pushContainer("body", [
|
||||
buildDefine({
|
||||
if (hasExports(meta)) {
|
||||
amdArgs.push(t.stringLiteral("exports"));
|
||||
commonjsArgs.push(t.identifier("exports"));
|
||||
|
||||
importNames.push(t.identifier(meta.exportName));
|
||||
}
|
||||
|
||||
getSourceMetadataArray(
|
||||
meta,
|
||||
).forEach(([source, metadata, , inSideEffectBlock]) => {
|
||||
amdArgs.push(t.stringLiteral(source));
|
||||
commonjsArgs.push(
|
||||
t.callExpression(t.identifier("require"), [
|
||||
t.stringLiteral(source),
|
||||
]),
|
||||
);
|
||||
|
||||
if (!inSideEffectBlock) {
|
||||
importNames.push(t.identifier(metadata.name));
|
||||
|
||||
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));
|
||||
});
|
||||
|
||||
ensureStatementsHoisted(headers);
|
||||
path.unshiftContainer("body", headers);
|
||||
|
||||
const { body, directives } = path.node;
|
||||
path.node.directives = [];
|
||||
path.node.body = [];
|
||||
const amdWrapper = path.pushContainer("body", [
|
||||
buildWrapper({
|
||||
MODULE_NAME: moduleName,
|
||||
SOURCES: sources,
|
||||
FACTORY: factory,
|
||||
|
||||
AMD_ARGUMENTS: t.arrayExpression(amdArgs),
|
||||
COMMONJS_ARGUMENTS: commonjsArgs,
|
||||
IMPORT_NAMES: importNames,
|
||||
}),
|
||||
]);
|
||||
])[0];
|
||||
const amdFactory = amdWrapper
|
||||
.get("expression.arguments")
|
||||
.filter(arg => arg.isFunctionExpression())[0]
|
||||
.get("body");
|
||||
amdFactory.pushContainer("directives", directives);
|
||||
amdFactory.pushContainer("body", body);
|
||||
},
|
||||
},
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user