"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.get = get; exports.minVersion = minVersion; exports.getDependencies = getDependencies; exports.ensure = ensure; exports.default = exports.list = void 0; var _traverse = _interopRequireDefault(require("@babel/traverse")); var t = _interopRequireWildcard(require("@babel/types")); var _helpers = _interopRequireDefault(require("./helpers")); function _getRequireWildcardCache() { if (typeof WeakMap !== "function") return null; var cache = new WeakMap(); _getRequireWildcardCache = function () { return cache; }; return cache; } function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } if (obj === null || typeof obj !== "object" && typeof obj !== "function") { return { default: obj }; } var cache = _getRequireWildcardCache(); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj.default = obj; if (cache) { cache.set(obj, newObj); } return newObj; } function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } function makePath(path) { const parts = []; for (; path.parentPath; path = path.parentPath) { parts.push(path.key); if (path.inList) parts.push(path.listKey); } return parts.reverse().join("."); } let fileClass = undefined; function getHelperMetadata(file) { const globals = new Set(); const localBindingNames = new Set(); const dependencies = new Map(); let exportName; let exportPath; const exportBindingAssignments = []; const importPaths = []; const importBindingsReferences = []; const dependencyVisitor = { ImportDeclaration(child) { const name = child.node.source.value; if (!_helpers.default[name]) { throw child.buildCodeFrameError(`Unknown helper ${name}`); } if (child.get("specifiers").length !== 1 || !child.get("specifiers.0").isImportDefaultSpecifier()) { throw child.buildCodeFrameError("Helpers can only import a default value"); } const bindingIdentifier = child.node.specifiers[0].local; dependencies.set(bindingIdentifier, name); importPaths.push(makePath(child)); }, ExportDefaultDeclaration(child) { const decl = child.get("declaration"); if (decl.isFunctionDeclaration()) { if (!decl.node.id) { throw decl.buildCodeFrameError("Helpers should give names to their exported func declaration"); } exportName = decl.node.id.name; } exportPath = makePath(child); }, ExportAllDeclaration(child) { throw child.buildCodeFrameError("Helpers can only export default"); }, ExportNamedDeclaration(child) { throw child.buildCodeFrameError("Helpers can only export default"); }, Statement(child) { if (child.isModuleDeclaration()) return; child.skip(); } }; const referenceVisitor = { Program(path) { const bindings = path.scope.getAllBindings(); Object.keys(bindings).forEach(name => { if (name === exportName) return; if (dependencies.has(bindings[name].identifier)) return; localBindingNames.add(name); }); }, ReferencedIdentifier(child) { const name = child.node.name; const binding = child.scope.getBinding(name, true); if (!binding) { globals.add(name); } else if (dependencies.has(binding.identifier)) { importBindingsReferences.push(makePath(child)); } }, AssignmentExpression(child) { const left = child.get("left"); if (!(exportName in left.getBindingIdentifiers())) return; if (!left.isIdentifier()) { throw left.buildCodeFrameError("Only simple assignments to exports are allowed in helpers"); } const binding = child.scope.getBinding(exportName); if (binding && binding.scope.path.isProgram()) { exportBindingAssignments.push(makePath(child)); } } }; (0, _traverse.default)(file.ast, dependencyVisitor, file.scope); (0, _traverse.default)(file.ast, referenceVisitor, file.scope); if (!exportPath) throw new Error("Helpers must default-export something."); exportBindingAssignments.reverse(); return { globals: Array.from(globals), localBindingNames: Array.from(localBindingNames), dependencies, exportBindingAssignments, exportPath, exportName, importBindingsReferences, importPaths }; } function permuteHelperAST(file, metadata, id, localBindings, getDependency) { if (localBindings && !id) { throw new Error("Unexpected local bindings for module-based helpers."); } if (!id) return; const { localBindingNames, dependencies, exportBindingAssignments, exportPath, exportName, importBindingsReferences, importPaths } = metadata; const dependenciesRefs = {}; dependencies.forEach((name, id) => { dependenciesRefs[id.name] = typeof getDependency === "function" && getDependency(name) || id; }); const toRename = {}; const bindings = new Set(localBindings || []); localBindingNames.forEach(name => { let newName = name; while (bindings.has(newName)) newName = "_" + newName; if (newName !== name) toRename[name] = newName; }); if (id.type === "Identifier" && exportName !== id.name) { toRename[exportName] = id.name; } const visitor = { Program(path) { const exp = path.get(exportPath); const imps = importPaths.map(p => path.get(p)); const impsBindingRefs = importBindingsReferences.map(p => path.get(p)); const decl = exp.get("declaration"); if (id.type === "Identifier") { if (decl.isFunctionDeclaration()) { exp.replaceWith(decl); } else { exp.replaceWith(t.variableDeclaration("var", [t.variableDeclarator(id, decl.node)])); } } else if (id.type === "MemberExpression") { if (decl.isFunctionDeclaration()) { exportBindingAssignments.forEach(assignPath => { const assign = path.get(assignPath); assign.replaceWith(t.assignmentExpression("=", id, assign.node)); }); exp.replaceWith(decl); path.pushContainer("body", t.expressionStatement(t.assignmentExpression("=", id, t.identifier(exportName)))); } else { exp.replaceWith(t.expressionStatement(t.assignmentExpression("=", id, decl.node))); } } else { throw new Error("Unexpected helper format."); } Object.keys(toRename).forEach(name => { path.scope.rename(name, toRename[name]); }); for (const path of imps) path.remove(); for (const path of impsBindingRefs) { const node = t.cloneNode(dependenciesRefs[path.node.name]); path.replaceWith(node); } path.stop(); } }; (0, _traverse.default)(file.ast, visitor, file.scope); } const helperData = Object.create(null); function loadHelper(name) { if (!helperData[name]) { const helper = _helpers.default[name]; if (!helper) { throw Object.assign(new ReferenceError(`Unknown helper ${name}`), { code: "BABEL_HELPER_UNKNOWN", helper: name }); } const fn = () => { const file = { ast: t.file(helper.ast()) }; if (fileClass) { return new fileClass({ filename: `babel-helper://${name}` }, file); } return file; }; const metadata = getHelperMetadata(fn()); helperData[name] = { build(getDependency, id, localBindings) { const file = fn(); permuteHelperAST(file, metadata, id, localBindings, getDependency); return { nodes: file.ast.program.body, globals: metadata.globals }; }, minVersion() { return helper.minVersion; }, dependencies: metadata.dependencies }; } return helperData[name]; } function get(name, getDependency, id, localBindings) { return loadHelper(name).build(getDependency, id, localBindings); } function minVersion(name) { return loadHelper(name).minVersion(); } function getDependencies(name) { return Array.from(loadHelper(name).dependencies.values()); } function ensure(name, newFileClass) { if (!fileClass) { fileClass = newFileClass; } loadHelper(name); } const list = Object.keys(_helpers.default).map(name => name.replace(/^_/, "")).filter(name => name !== "__esModule"); exports.list = list; var _default = get; exports.default = _default;