You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							248 lines
						
					
					
						
							7.5 KiB
						
					
					
				
			
		
		
	
	
							248 lines
						
					
					
						
							7.5 KiB
						
					
					
				"use strict";
 | 
						|
 | 
						|
Object.defineProperty(exports, "__esModule", {
 | 
						|
  value: true
 | 
						|
});
 | 
						|
exports.default = void 0;
 | 
						|
exports.ensure = ensure;
 | 
						|
exports.get = get;
 | 
						|
exports.getDependencies = getDependencies;
 | 
						|
exports.list = void 0;
 | 
						|
exports.minVersion = minVersion;
 | 
						|
var _traverse = require("@babel/traverse");
 | 
						|
var _t = require("@babel/types");
 | 
						|
var _helpers = require("./helpers");
 | 
						|
const {
 | 
						|
  assignmentExpression,
 | 
						|
  cloneNode,
 | 
						|
  expressionStatement,
 | 
						|
  file,
 | 
						|
  identifier
 | 
						|
} = _t;
 | 
						|
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() || !decl.node.id) {
 | 
						|
        throw decl.buildCodeFrameError("Helpers can only export named function declarations");
 | 
						|
      }
 | 
						|
      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.isImportDeclaration() || child.isExportDeclaration()) 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);
 | 
						|
      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 != null && 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 have a default export.");
 | 
						|
 | 
						|
  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 {
 | 
						|
    path
 | 
						|
  } = file;
 | 
						|
 | 
						|
  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") {
 | 
						|
    exp.replaceWith(decl);
 | 
						|
  } else if (id.type === "MemberExpression") {
 | 
						|
    exportBindingAssignments.forEach(assignPath => {
 | 
						|
      const assign = path.get(assignPath);
 | 
						|
      assign.replaceWith(assignmentExpression("=", id, assign.node));
 | 
						|
    });
 | 
						|
    exp.replaceWith(decl);
 | 
						|
    path.pushContainer("body", expressionStatement(assignmentExpression("=", id, identifier(exportName))));
 | 
						|
  } 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 = cloneNode(dependenciesRefs[path.node.name]);
 | 
						|
    path.replaceWith(node);
 | 
						|
  }
 | 
						|
}
 | 
						|
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 = () => {
 | 
						|
      {
 | 
						|
        if (!FileClass) {
 | 
						|
          const fakeFile = {
 | 
						|
            ast: file(helper.ast()),
 | 
						|
            path: null
 | 
						|
          };
 | 
						|
          (0, _traverse.default)(fakeFile.ast, {
 | 
						|
            Program: path => (fakeFile.path = path).stop()
 | 
						|
          });
 | 
						|
          return fakeFile;
 | 
						|
        }
 | 
						|
      }
 | 
						|
      return new FileClass({
 | 
						|
        filename: `babel-helper://${name}`
 | 
						|
      }, {
 | 
						|
        ast: file(helper.ast()),
 | 
						|
        code: "[internal Babel helper code]",
 | 
						|
        inputMap: null
 | 
						|
      });
 | 
						|
    };
 | 
						|
 | 
						|
    let metadata = null;
 | 
						|
    helperData[name] = {
 | 
						|
      minVersion: helper.minVersion,
 | 
						|
      build(getDependency, id, localBindings) {
 | 
						|
        const file = fn();
 | 
						|
        metadata || (metadata = getHelperMetadata(file));
 | 
						|
        permuteHelperAST(file, metadata, id, localBindings, getDependency);
 | 
						|
        return {
 | 
						|
          nodes: file.ast.program.body,
 | 
						|
          globals: metadata.globals
 | 
						|
        };
 | 
						|
      },
 | 
						|
      getDependencies() {
 | 
						|
        metadata || (metadata = getHelperMetadata(fn()));
 | 
						|
        return Array.from(metadata.dependencies.values());
 | 
						|
      }
 | 
						|
    };
 | 
						|
  }
 | 
						|
  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 loadHelper(name).getDependencies();
 | 
						|
}
 | 
						|
function ensure(name, newFileClass) {
 | 
						|
  FileClass || (FileClass = newFileClass);
 | 
						|
  loadHelper(name);
 | 
						|
}
 | 
						|
const list = Object.keys(_helpers.default).map(name => name.replace(/^_/, ""));
 | 
						|
exports.list = list;
 | 
						|
var _default = get;
 | 
						|
exports.default = _default;
 | 
						|
 | 
						|
//# sourceMappingURL=index.js.map
 |