rewrite-live-references.js 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.default = rewriteLiveReferences;
  6. var _core = require("@babel/core");
  7. function isInType(path) {
  8. do {
  9. switch (path.parent.type) {
  10. case "TSTypeAnnotation":
  11. case "TSTypeAliasDeclaration":
  12. case "TSTypeReference":
  13. case "TypeAnnotation":
  14. case "TypeAlias":
  15. return true;
  16. case "ExportSpecifier":
  17. return path.parentPath.parent.exportKind === "type";
  18. default:
  19. if (path.parentPath.isStatement() || path.parentPath.isExpression()) {
  20. return false;
  21. }
  22. }
  23. } while (path = path.parentPath);
  24. }
  25. function rewriteLiveReferences(programPath, metadata, wrapReference) {
  26. const imported = new Map();
  27. const exported = new Map();
  28. const requeueInParent = path => {
  29. programPath.requeue(path);
  30. };
  31. for (const [source, data] of metadata.source) {
  32. for (const [localName, importName] of data.imports) {
  33. imported.set(localName, [source, importName, null]);
  34. }
  35. for (const localName of data.importsNamespace) {
  36. imported.set(localName, [source, null, localName]);
  37. }
  38. }
  39. for (const [local, data] of metadata.local) {
  40. let exportMeta = exported.get(local);
  41. if (!exportMeta) {
  42. exportMeta = [];
  43. exported.set(local, exportMeta);
  44. }
  45. exportMeta.push(...data.names);
  46. }
  47. const rewriteBindingInitVisitorState = {
  48. metadata,
  49. requeueInParent,
  50. scope: programPath.scope,
  51. exported
  52. };
  53. programPath.traverse(rewriteBindingInitVisitor, rewriteBindingInitVisitorState);
  54. const rewriteReferencesVisitorState = {
  55. seen: new WeakSet(),
  56. metadata,
  57. requeueInParent,
  58. scope: programPath.scope,
  59. imported,
  60. exported,
  61. buildImportReference([source, importName, localName], identNode) {
  62. const meta = metadata.source.get(source);
  63. meta.referenced = true;
  64. if (localName) {
  65. if (meta.wrap) {
  66. var _wrapReference;
  67. identNode = (_wrapReference = wrapReference(identNode, meta.wrap)) != null ? _wrapReference : identNode;
  68. }
  69. return identNode;
  70. }
  71. let namespace = _core.types.identifier(meta.name);
  72. if (meta.wrap) {
  73. var _wrapReference2;
  74. namespace = (_wrapReference2 = wrapReference(namespace, meta.wrap)) != null ? _wrapReference2 : namespace;
  75. }
  76. if (importName === "default" && meta.interop === "node-default") {
  77. return namespace;
  78. }
  79. const computed = metadata.stringSpecifiers.has(importName);
  80. return _core.types.memberExpression(namespace, computed ? _core.types.stringLiteral(importName) : _core.types.identifier(importName), computed);
  81. }
  82. };
  83. programPath.traverse(rewriteReferencesVisitor, rewriteReferencesVisitorState);
  84. }
  85. const rewriteBindingInitVisitor = {
  86. Scope(path) {
  87. path.skip();
  88. },
  89. ClassDeclaration(path) {
  90. const {
  91. requeueInParent,
  92. exported,
  93. metadata
  94. } = this;
  95. const {
  96. id
  97. } = path.node;
  98. if (!id) throw new Error("Expected class to have a name");
  99. const localName = id.name;
  100. const exportNames = exported.get(localName) || [];
  101. if (exportNames.length > 0) {
  102. const statement = _core.types.expressionStatement(buildBindingExportAssignmentExpression(metadata, exportNames, _core.types.identifier(localName), path.scope));
  103. statement._blockHoist = path.node._blockHoist;
  104. requeueInParent(path.insertAfter(statement)[0]);
  105. }
  106. },
  107. VariableDeclaration(path) {
  108. const {
  109. requeueInParent,
  110. exported,
  111. metadata
  112. } = this;
  113. const isVar = path.node.kind === "var";
  114. for (const decl of path.get("declarations")) {
  115. const {
  116. id
  117. } = decl.node;
  118. let {
  119. init
  120. } = decl.node;
  121. if (_core.types.isIdentifier(id) && exported.has(id.name) && !_core.types.isArrowFunctionExpression(init) && (!_core.types.isFunctionExpression(init) || init.id) && (!_core.types.isClassExpression(init) || init.id)) {
  122. if (!init) {
  123. if (isVar) {
  124. continue;
  125. } else {
  126. init = path.scope.buildUndefinedNode();
  127. }
  128. }
  129. decl.node.init = buildBindingExportAssignmentExpression(metadata, exported.get(id.name), init, path.scope);
  130. requeueInParent(decl.get("init"));
  131. } else {
  132. for (const localName of Object.keys(decl.getOuterBindingIdentifiers())) {
  133. if (exported.has(localName)) {
  134. const statement = _core.types.expressionStatement(buildBindingExportAssignmentExpression(metadata, exported.get(localName), _core.types.identifier(localName), path.scope));
  135. statement._blockHoist = path.node._blockHoist;
  136. requeueInParent(path.insertAfter(statement)[0]);
  137. }
  138. }
  139. }
  140. }
  141. }
  142. };
  143. const buildBindingExportAssignmentExpression = (metadata, exportNames, localExpr, scope) => {
  144. const exportsObjectName = metadata.exportName;
  145. for (let currentScope = scope; currentScope != null; currentScope = currentScope.parent) {
  146. if (currentScope.hasOwnBinding(exportsObjectName)) {
  147. currentScope.rename(exportsObjectName);
  148. }
  149. }
  150. return (exportNames || []).reduce((expr, exportName) => {
  151. const {
  152. stringSpecifiers
  153. } = metadata;
  154. const computed = stringSpecifiers.has(exportName);
  155. return _core.types.assignmentExpression("=", _core.types.memberExpression(_core.types.identifier(exportsObjectName), computed ? _core.types.stringLiteral(exportName) : _core.types.identifier(exportName), computed), expr);
  156. }, localExpr);
  157. };
  158. const buildImportThrow = localName => {
  159. return _core.template.expression.ast`
  160. (function() {
  161. throw new Error('"' + '${localName}' + '" is read-only.');
  162. })()
  163. `;
  164. };
  165. const rewriteReferencesVisitor = {
  166. ReferencedIdentifier(path) {
  167. const {
  168. seen,
  169. buildImportReference,
  170. scope,
  171. imported,
  172. requeueInParent
  173. } = this;
  174. if (seen.has(path.node)) return;
  175. seen.add(path.node);
  176. const localName = path.node.name;
  177. const importData = imported.get(localName);
  178. if (importData) {
  179. if (isInType(path)) {
  180. throw path.buildCodeFrameError(`Cannot transform the imported binding "${localName}" since it's also used in a type annotation. ` + `Please strip type annotations using @babel/preset-typescript or @babel/preset-flow.`);
  181. }
  182. const localBinding = path.scope.getBinding(localName);
  183. const rootBinding = scope.getBinding(localName);
  184. if (rootBinding !== localBinding) return;
  185. const ref = buildImportReference(importData, path.node);
  186. ref.loc = path.node.loc;
  187. if ((path.parentPath.isCallExpression({
  188. callee: path.node
  189. }) || path.parentPath.isOptionalCallExpression({
  190. callee: path.node
  191. }) || path.parentPath.isTaggedTemplateExpression({
  192. tag: path.node
  193. })) && _core.types.isMemberExpression(ref)) {
  194. path.replaceWith(_core.types.sequenceExpression([_core.types.numericLiteral(0), ref]));
  195. } else if (path.isJSXIdentifier() && _core.types.isMemberExpression(ref)) {
  196. const {
  197. object,
  198. property
  199. } = ref;
  200. path.replaceWith(_core.types.jsxMemberExpression(_core.types.jsxIdentifier(object.name), _core.types.jsxIdentifier(property.name)));
  201. } else {
  202. path.replaceWith(ref);
  203. }
  204. requeueInParent(path);
  205. path.skip();
  206. }
  207. },
  208. UpdateExpression(path) {
  209. const {
  210. scope,
  211. seen,
  212. imported,
  213. exported,
  214. requeueInParent,
  215. buildImportReference
  216. } = this;
  217. if (seen.has(path.node)) return;
  218. seen.add(path.node);
  219. const arg = path.get("argument");
  220. if (arg.isMemberExpression()) return;
  221. const update = path.node;
  222. if (arg.isIdentifier()) {
  223. const localName = arg.node.name;
  224. if (scope.getBinding(localName) !== path.scope.getBinding(localName)) {
  225. return;
  226. }
  227. const exportedNames = exported.get(localName);
  228. const importData = imported.get(localName);
  229. if ((exportedNames == null ? void 0 : exportedNames.length) > 0 || importData) {
  230. if (importData) {
  231. path.replaceWith(_core.types.assignmentExpression(update.operator[0] + "=", buildImportReference(importData, arg.node), buildImportThrow(localName)));
  232. } else if (update.prefix) {
  233. path.replaceWith(buildBindingExportAssignmentExpression(this.metadata, exportedNames, _core.types.cloneNode(update), path.scope));
  234. } else {
  235. const ref = scope.generateDeclaredUidIdentifier(localName);
  236. path.replaceWith(_core.types.sequenceExpression([_core.types.assignmentExpression("=", _core.types.cloneNode(ref), _core.types.cloneNode(update)), buildBindingExportAssignmentExpression(this.metadata, exportedNames, _core.types.identifier(localName), path.scope), _core.types.cloneNode(ref)]));
  237. }
  238. }
  239. }
  240. requeueInParent(path);
  241. path.skip();
  242. },
  243. AssignmentExpression: {
  244. exit(path) {
  245. const {
  246. scope,
  247. seen,
  248. imported,
  249. exported,
  250. requeueInParent,
  251. buildImportReference
  252. } = this;
  253. if (seen.has(path.node)) return;
  254. seen.add(path.node);
  255. const left = path.get("left");
  256. if (left.isMemberExpression()) return;
  257. if (left.isIdentifier()) {
  258. const localName = left.node.name;
  259. if (scope.getBinding(localName) !== path.scope.getBinding(localName)) {
  260. return;
  261. }
  262. const exportedNames = exported.get(localName);
  263. const importData = imported.get(localName);
  264. if ((exportedNames == null ? void 0 : exportedNames.length) > 0 || importData) {
  265. const assignment = path.node;
  266. if (importData) {
  267. assignment.left = buildImportReference(importData, left.node);
  268. assignment.right = _core.types.sequenceExpression([assignment.right, buildImportThrow(localName)]);
  269. }
  270. const {
  271. operator
  272. } = assignment;
  273. let newExpr;
  274. if (operator === "=") {
  275. newExpr = assignment;
  276. } else if (operator === "&&=" || operator === "||=" || operator === "??=") {
  277. newExpr = _core.types.assignmentExpression("=", assignment.left, _core.types.logicalExpression(operator.slice(0, -1), _core.types.cloneNode(assignment.left), assignment.right));
  278. } else {
  279. newExpr = _core.types.assignmentExpression("=", assignment.left, _core.types.binaryExpression(operator.slice(0, -1), _core.types.cloneNode(assignment.left), assignment.right));
  280. }
  281. path.replaceWith(buildBindingExportAssignmentExpression(this.metadata, exportedNames, newExpr, path.scope));
  282. requeueInParent(path);
  283. path.skip();
  284. }
  285. } else {
  286. const ids = left.getOuterBindingIdentifiers();
  287. const programScopeIds = Object.keys(ids).filter(localName => scope.getBinding(localName) === path.scope.getBinding(localName));
  288. const id = programScopeIds.find(localName => imported.has(localName));
  289. if (id) {
  290. path.node.right = _core.types.sequenceExpression([path.node.right, buildImportThrow(id)]);
  291. }
  292. const items = [];
  293. programScopeIds.forEach(localName => {
  294. const exportedNames = exported.get(localName) || [];
  295. if (exportedNames.length > 0) {
  296. items.push(buildBindingExportAssignmentExpression(this.metadata, exportedNames, _core.types.identifier(localName), path.scope));
  297. }
  298. });
  299. if (items.length > 0) {
  300. let node = _core.types.sequenceExpression(items);
  301. if (path.parentPath.isExpressionStatement()) {
  302. node = _core.types.expressionStatement(node);
  303. node._blockHoist = path.parentPath.node._blockHoist;
  304. }
  305. const statement = path.insertAfter(node)[0];
  306. requeueInParent(statement);
  307. }
  308. }
  309. }
  310. },
  311. ForXStatement(path) {
  312. const {
  313. scope,
  314. node
  315. } = path;
  316. const {
  317. left
  318. } = node;
  319. const {
  320. exported,
  321. imported,
  322. scope: programScope
  323. } = this;
  324. if (!_core.types.isVariableDeclaration(left)) {
  325. let didTransformExport = false,
  326. importConstViolationName;
  327. const loopBodyScope = path.get("body").scope;
  328. for (const name of Object.keys(_core.types.getOuterBindingIdentifiers(left))) {
  329. if (programScope.getBinding(name) === scope.getBinding(name)) {
  330. if (exported.has(name)) {
  331. didTransformExport = true;
  332. if (loopBodyScope.hasOwnBinding(name)) {
  333. loopBodyScope.rename(name);
  334. }
  335. }
  336. if (imported.has(name) && !importConstViolationName) {
  337. importConstViolationName = name;
  338. }
  339. }
  340. }
  341. if (!didTransformExport && !importConstViolationName) {
  342. return;
  343. }
  344. path.ensureBlock();
  345. const bodyPath = path.get("body");
  346. const newLoopId = scope.generateUidIdentifierBasedOnNode(left);
  347. path.get("left").replaceWith(_core.types.variableDeclaration("let", [_core.types.variableDeclarator(_core.types.cloneNode(newLoopId))]));
  348. scope.registerDeclaration(path.get("left"));
  349. if (didTransformExport) {
  350. bodyPath.unshiftContainer("body", _core.types.expressionStatement(_core.types.assignmentExpression("=", left, newLoopId)));
  351. }
  352. if (importConstViolationName) {
  353. bodyPath.unshiftContainer("body", _core.types.expressionStatement(buildImportThrow(importConstViolationName)));
  354. }
  355. }
  356. }
  357. };
  358. //# sourceMappingURL=rewrite-live-references.js.map