index.js 7.9 KB

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