[6a3a178] | 1 | "use strict";
|
---|
| 2 |
|
---|
| 3 | Object.defineProperty(exports, "__esModule", {
|
---|
| 4 | value: true
|
---|
| 5 | });
|
---|
| 6 | exports.get = get;
|
---|
| 7 | exports.minVersion = minVersion;
|
---|
| 8 | exports.getDependencies = getDependencies;
|
---|
| 9 | exports.ensure = ensure;
|
---|
| 10 | exports.default = exports.list = void 0;
|
---|
| 11 |
|
---|
| 12 | var _traverse = require("@babel/traverse");
|
---|
| 13 |
|
---|
| 14 | var _t = require("@babel/types");
|
---|
| 15 |
|
---|
| 16 | var _helpers = require("./helpers");
|
---|
| 17 |
|
---|
| 18 | const {
|
---|
| 19 | assignmentExpression,
|
---|
| 20 | cloneNode,
|
---|
| 21 | expressionStatement,
|
---|
| 22 | file: t_file,
|
---|
| 23 | identifier,
|
---|
| 24 | variableDeclaration,
|
---|
| 25 | variableDeclarator
|
---|
| 26 | } = _t;
|
---|
| 27 |
|
---|
| 28 | function makePath(path) {
|
---|
| 29 | const parts = [];
|
---|
| 30 |
|
---|
| 31 | for (; path.parentPath; path = path.parentPath) {
|
---|
| 32 | parts.push(path.key);
|
---|
| 33 | if (path.inList) parts.push(path.listKey);
|
---|
| 34 | }
|
---|
| 35 |
|
---|
| 36 | return parts.reverse().join(".");
|
---|
| 37 | }
|
---|
| 38 |
|
---|
| 39 | let fileClass = undefined;
|
---|
| 40 |
|
---|
| 41 | function getHelperMetadata(file) {
|
---|
| 42 | const globals = new Set();
|
---|
| 43 | const localBindingNames = new Set();
|
---|
| 44 | const dependencies = new Map();
|
---|
| 45 | let exportName;
|
---|
| 46 | let exportPath;
|
---|
| 47 | const exportBindingAssignments = [];
|
---|
| 48 | const importPaths = [];
|
---|
| 49 | const importBindingsReferences = [];
|
---|
| 50 | const dependencyVisitor = {
|
---|
| 51 | ImportDeclaration(child) {
|
---|
| 52 | const name = child.node.source.value;
|
---|
| 53 |
|
---|
| 54 | if (!_helpers.default[name]) {
|
---|
| 55 | throw child.buildCodeFrameError(`Unknown helper ${name}`);
|
---|
| 56 | }
|
---|
| 57 |
|
---|
| 58 | if (child.get("specifiers").length !== 1 || !child.get("specifiers.0").isImportDefaultSpecifier()) {
|
---|
| 59 | throw child.buildCodeFrameError("Helpers can only import a default value");
|
---|
| 60 | }
|
---|
| 61 |
|
---|
| 62 | const bindingIdentifier = child.node.specifiers[0].local;
|
---|
| 63 | dependencies.set(bindingIdentifier, name);
|
---|
| 64 | importPaths.push(makePath(child));
|
---|
| 65 | },
|
---|
| 66 |
|
---|
| 67 | ExportDefaultDeclaration(child) {
|
---|
| 68 | const decl = child.get("declaration");
|
---|
| 69 |
|
---|
| 70 | if (decl.isFunctionDeclaration()) {
|
---|
| 71 | if (!decl.node.id) {
|
---|
| 72 | throw decl.buildCodeFrameError("Helpers should give names to their exported func declaration");
|
---|
| 73 | }
|
---|
| 74 |
|
---|
| 75 | exportName = decl.node.id.name;
|
---|
| 76 | }
|
---|
| 77 |
|
---|
| 78 | exportPath = makePath(child);
|
---|
| 79 | },
|
---|
| 80 |
|
---|
| 81 | ExportAllDeclaration(child) {
|
---|
| 82 | throw child.buildCodeFrameError("Helpers can only export default");
|
---|
| 83 | },
|
---|
| 84 |
|
---|
| 85 | ExportNamedDeclaration(child) {
|
---|
| 86 | throw child.buildCodeFrameError("Helpers can only export default");
|
---|
| 87 | },
|
---|
| 88 |
|
---|
| 89 | Statement(child) {
|
---|
| 90 | if (child.isModuleDeclaration()) return;
|
---|
| 91 | child.skip();
|
---|
| 92 | }
|
---|
| 93 |
|
---|
| 94 | };
|
---|
| 95 | const referenceVisitor = {
|
---|
| 96 | Program(path) {
|
---|
| 97 | const bindings = path.scope.getAllBindings();
|
---|
| 98 | Object.keys(bindings).forEach(name => {
|
---|
| 99 | if (name === exportName) return;
|
---|
| 100 | if (dependencies.has(bindings[name].identifier)) return;
|
---|
| 101 | localBindingNames.add(name);
|
---|
| 102 | });
|
---|
| 103 | },
|
---|
| 104 |
|
---|
| 105 | ReferencedIdentifier(child) {
|
---|
| 106 | const name = child.node.name;
|
---|
| 107 | const binding = child.scope.getBinding(name);
|
---|
| 108 |
|
---|
| 109 | if (!binding) {
|
---|
| 110 | globals.add(name);
|
---|
| 111 | } else if (dependencies.has(binding.identifier)) {
|
---|
| 112 | importBindingsReferences.push(makePath(child));
|
---|
| 113 | }
|
---|
| 114 | },
|
---|
| 115 |
|
---|
| 116 | AssignmentExpression(child) {
|
---|
| 117 | const left = child.get("left");
|
---|
| 118 | if (!(exportName in left.getBindingIdentifiers())) return;
|
---|
| 119 |
|
---|
| 120 | if (!left.isIdentifier()) {
|
---|
| 121 | throw left.buildCodeFrameError("Only simple assignments to exports are allowed in helpers");
|
---|
| 122 | }
|
---|
| 123 |
|
---|
| 124 | const binding = child.scope.getBinding(exportName);
|
---|
| 125 |
|
---|
| 126 | if (binding != null && binding.scope.path.isProgram()) {
|
---|
| 127 | exportBindingAssignments.push(makePath(child));
|
---|
| 128 | }
|
---|
| 129 | }
|
---|
| 130 |
|
---|
| 131 | };
|
---|
| 132 | (0, _traverse.default)(file.ast, dependencyVisitor, file.scope);
|
---|
| 133 | (0, _traverse.default)(file.ast, referenceVisitor, file.scope);
|
---|
| 134 | if (!exportPath) throw new Error("Helpers must default-export something.");
|
---|
| 135 | exportBindingAssignments.reverse();
|
---|
| 136 | return {
|
---|
| 137 | globals: Array.from(globals),
|
---|
| 138 | localBindingNames: Array.from(localBindingNames),
|
---|
| 139 | dependencies,
|
---|
| 140 | exportBindingAssignments,
|
---|
| 141 | exportPath,
|
---|
| 142 | exportName,
|
---|
| 143 | importBindingsReferences,
|
---|
| 144 | importPaths
|
---|
| 145 | };
|
---|
| 146 | }
|
---|
| 147 |
|
---|
| 148 | function permuteHelperAST(file, metadata, id, localBindings, getDependency) {
|
---|
| 149 | if (localBindings && !id) {
|
---|
| 150 | throw new Error("Unexpected local bindings for module-based helpers.");
|
---|
| 151 | }
|
---|
| 152 |
|
---|
| 153 | if (!id) return;
|
---|
| 154 | const {
|
---|
| 155 | localBindingNames,
|
---|
| 156 | dependencies,
|
---|
| 157 | exportBindingAssignments,
|
---|
| 158 | exportPath,
|
---|
| 159 | exportName,
|
---|
| 160 | importBindingsReferences,
|
---|
| 161 | importPaths
|
---|
| 162 | } = metadata;
|
---|
| 163 | const dependenciesRefs = {};
|
---|
| 164 | dependencies.forEach((name, id) => {
|
---|
| 165 | dependenciesRefs[id.name] = typeof getDependency === "function" && getDependency(name) || id;
|
---|
| 166 | });
|
---|
| 167 | const toRename = {};
|
---|
| 168 | const bindings = new Set(localBindings || []);
|
---|
| 169 | localBindingNames.forEach(name => {
|
---|
| 170 | let newName = name;
|
---|
| 171 |
|
---|
| 172 | while (bindings.has(newName)) newName = "_" + newName;
|
---|
| 173 |
|
---|
| 174 | if (newName !== name) toRename[name] = newName;
|
---|
| 175 | });
|
---|
| 176 |
|
---|
| 177 | if (id.type === "Identifier" && exportName !== id.name) {
|
---|
| 178 | toRename[exportName] = id.name;
|
---|
| 179 | }
|
---|
| 180 |
|
---|
| 181 | const visitor = {
|
---|
| 182 | Program(path) {
|
---|
| 183 | const exp = path.get(exportPath);
|
---|
| 184 | const imps = importPaths.map(p => path.get(p));
|
---|
| 185 | const impsBindingRefs = importBindingsReferences.map(p => path.get(p));
|
---|
| 186 | const decl = exp.get("declaration");
|
---|
| 187 |
|
---|
| 188 | if (id.type === "Identifier") {
|
---|
| 189 | if (decl.isFunctionDeclaration()) {
|
---|
| 190 | exp.replaceWith(decl);
|
---|
| 191 | } else {
|
---|
| 192 | exp.replaceWith(variableDeclaration("var", [variableDeclarator(id, decl.node)]));
|
---|
| 193 | }
|
---|
| 194 | } else if (id.type === "MemberExpression") {
|
---|
| 195 | if (decl.isFunctionDeclaration()) {
|
---|
| 196 | exportBindingAssignments.forEach(assignPath => {
|
---|
| 197 | const assign = path.get(assignPath);
|
---|
| 198 | assign.replaceWith(assignmentExpression("=", id, assign.node));
|
---|
| 199 | });
|
---|
| 200 | exp.replaceWith(decl);
|
---|
| 201 | path.pushContainer("body", expressionStatement(assignmentExpression("=", id, identifier(exportName))));
|
---|
| 202 | } else {
|
---|
| 203 | exp.replaceWith(expressionStatement(assignmentExpression("=", id, decl.node)));
|
---|
| 204 | }
|
---|
| 205 | } else {
|
---|
| 206 | throw new Error("Unexpected helper format.");
|
---|
| 207 | }
|
---|
| 208 |
|
---|
| 209 | Object.keys(toRename).forEach(name => {
|
---|
| 210 | path.scope.rename(name, toRename[name]);
|
---|
| 211 | });
|
---|
| 212 |
|
---|
| 213 | for (const path of imps) path.remove();
|
---|
| 214 |
|
---|
| 215 | for (const path of impsBindingRefs) {
|
---|
| 216 | const node = cloneNode(dependenciesRefs[path.node.name]);
|
---|
| 217 | path.replaceWith(node);
|
---|
| 218 | }
|
---|
| 219 |
|
---|
| 220 | path.stop();
|
---|
| 221 | }
|
---|
| 222 |
|
---|
| 223 | };
|
---|
| 224 | (0, _traverse.default)(file.ast, visitor, file.scope);
|
---|
| 225 | }
|
---|
| 226 |
|
---|
| 227 | const helperData = Object.create(null);
|
---|
| 228 |
|
---|
| 229 | function loadHelper(name) {
|
---|
| 230 | if (!helperData[name]) {
|
---|
| 231 | const helper = _helpers.default[name];
|
---|
| 232 |
|
---|
| 233 | if (!helper) {
|
---|
| 234 | throw Object.assign(new ReferenceError(`Unknown helper ${name}`), {
|
---|
| 235 | code: "BABEL_HELPER_UNKNOWN",
|
---|
| 236 | helper: name
|
---|
| 237 | });
|
---|
| 238 | }
|
---|
| 239 |
|
---|
| 240 | const fn = () => {
|
---|
| 241 | const file = {
|
---|
| 242 | ast: t_file(helper.ast())
|
---|
| 243 | };
|
---|
| 244 |
|
---|
| 245 | if (fileClass) {
|
---|
| 246 | return new fileClass({
|
---|
| 247 | filename: `babel-helper://${name}`
|
---|
| 248 | }, file);
|
---|
| 249 | }
|
---|
| 250 |
|
---|
| 251 | return file;
|
---|
| 252 | };
|
---|
| 253 |
|
---|
| 254 | const metadata = getHelperMetadata(fn());
|
---|
| 255 | helperData[name] = {
|
---|
| 256 | build(getDependency, id, localBindings) {
|
---|
| 257 | const file = fn();
|
---|
| 258 | permuteHelperAST(file, metadata, id, localBindings, getDependency);
|
---|
| 259 | return {
|
---|
| 260 | nodes: file.ast.program.body,
|
---|
| 261 | globals: metadata.globals
|
---|
| 262 | };
|
---|
| 263 | },
|
---|
| 264 |
|
---|
| 265 | minVersion() {
|
---|
| 266 | return helper.minVersion;
|
---|
| 267 | },
|
---|
| 268 |
|
---|
| 269 | dependencies: metadata.dependencies
|
---|
| 270 | };
|
---|
| 271 | }
|
---|
| 272 |
|
---|
| 273 | return helperData[name];
|
---|
| 274 | }
|
---|
| 275 |
|
---|
| 276 | function get(name, getDependency, id, localBindings) {
|
---|
| 277 | return loadHelper(name).build(getDependency, id, localBindings);
|
---|
| 278 | }
|
---|
| 279 |
|
---|
| 280 | function minVersion(name) {
|
---|
| 281 | return loadHelper(name).minVersion();
|
---|
| 282 | }
|
---|
| 283 |
|
---|
| 284 | function getDependencies(name) {
|
---|
| 285 | return Array.from(loadHelper(name).dependencies.values());
|
---|
| 286 | }
|
---|
| 287 |
|
---|
| 288 | function ensure(name, newFileClass) {
|
---|
| 289 | if (!fileClass) {
|
---|
| 290 | fileClass = newFileClass;
|
---|
| 291 | }
|
---|
| 292 |
|
---|
| 293 | loadHelper(name);
|
---|
| 294 | }
|
---|
| 295 |
|
---|
| 296 | const list = Object.keys(_helpers.default).map(name => name.replace(/^_/, "")).filter(name => name !== "__esModule");
|
---|
| 297 | exports.list = list;
|
---|
| 298 | var _default = get;
|
---|
| 299 | exports.default = _default; |
---|