globals.js 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. "use strict";
  2. var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
  3. if (k2 === undefined) k2 = k;
  4. Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
  5. }) : (function(o, m, k, k2) {
  6. if (k2 === undefined) k2 = k;
  7. o[k2] = m[k];
  8. }));
  9. var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
  10. Object.defineProperty(o, "default", { enumerable: true, value: v });
  11. }) : function(o, v) {
  12. o["default"] = v;
  13. });
  14. var __importStar = (this && this.__importStar) || function (mod) {
  15. if (mod && mod.__esModule) return mod;
  16. var result = {};
  17. if (mod != null) for (var k in mod) if (Object.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
  18. __setModuleDefault(result, mod);
  19. return result;
  20. };
  21. var __importDefault = (this && this.__importDefault) || function (mod) {
  22. return (mod && mod.__esModule) ? mod : { "default": mod };
  23. };
  24. Object.defineProperty(exports, "__esModule", { value: true });
  25. const assert_never_1 = __importDefault(require("assert-never"));
  26. const babel_walk_1 = require("babel-walk");
  27. const t = __importStar(require("@babel/types"));
  28. const reference_1 = __importDefault(require("./reference"));
  29. const isScope = (node) => t.isFunctionParent(node) || t.isProgram(node);
  30. const isBlockScope = (node) => t.isBlockStatement(node) || isScope(node);
  31. const declaresArguments = (node) => t.isFunction(node) && !t.isArrowFunctionExpression(node);
  32. const declaresThis = declaresArguments;
  33. const LOCALS_SYMBOL = Symbol('locals');
  34. const getLocals = (node) => node[LOCALS_SYMBOL];
  35. const declareLocals = (node) => (node[LOCALS_SYMBOL] = node[LOCALS_SYMBOL] || new Set());
  36. const setLocal = (node, name) => declareLocals(node).add(name);
  37. // First pass
  38. function declareFunction(node) {
  39. for (const param of node.params) {
  40. declarePattern(param, node);
  41. }
  42. const id = node.id;
  43. if (id) {
  44. setLocal(node, id.name);
  45. }
  46. }
  47. function declarePattern(node, parent) {
  48. switch (node.type) {
  49. case 'Identifier':
  50. setLocal(parent, node.name);
  51. break;
  52. case 'ObjectPattern':
  53. for (const prop of node.properties) {
  54. switch (prop.type) {
  55. case 'RestElement':
  56. declarePattern(prop.argument, parent);
  57. break;
  58. case 'ObjectProperty':
  59. declarePattern(prop.value, parent);
  60. break;
  61. default:
  62. assert_never_1.default(prop);
  63. break;
  64. }
  65. }
  66. break;
  67. case 'ArrayPattern':
  68. for (const element of node.elements) {
  69. if (element)
  70. declarePattern(element, parent);
  71. }
  72. break;
  73. case 'RestElement':
  74. declarePattern(node.argument, parent);
  75. break;
  76. case 'AssignmentPattern':
  77. declarePattern(node.left, parent);
  78. break;
  79. // istanbul ignore next
  80. default:
  81. throw new Error('Unrecognized pattern type: ' + node.type);
  82. }
  83. }
  84. function declareModuleSpecifier(node, _state, parents) {
  85. for (let i = parents.length - 2; i >= 0; i--) {
  86. if (isScope(parents[i])) {
  87. setLocal(parents[i], node.local.name);
  88. return;
  89. }
  90. }
  91. }
  92. const firstPass = babel_walk_1.ancestor({
  93. VariableDeclaration(node, _state, parents) {
  94. for (let i = parents.length - 2; i >= 0; i--) {
  95. if (node.kind === 'var'
  96. ? t.isFunctionParent(parents[i])
  97. : isBlockScope(parents[i])) {
  98. for (const declaration of node.declarations) {
  99. declarePattern(declaration.id, parents[i]);
  100. }
  101. return;
  102. }
  103. }
  104. },
  105. FunctionDeclaration(node, _state, parents) {
  106. if (node.id) {
  107. for (let i = parents.length - 2; i >= 0; i--) {
  108. if (isScope(parents[i])) {
  109. setLocal(parents[i], node.id.name);
  110. return;
  111. }
  112. }
  113. }
  114. },
  115. Function: declareFunction,
  116. ClassDeclaration(node, _state, parents) {
  117. for (let i = parents.length - 2; i >= 0; i--) {
  118. if (isScope(parents[i])) {
  119. setLocal(parents[i], node.id.name);
  120. return;
  121. }
  122. }
  123. },
  124. TryStatement(node) {
  125. if (node.handler === null)
  126. return;
  127. if (node.handler.param === null)
  128. return;
  129. declarePattern(node.handler.param, node.handler);
  130. },
  131. ImportDefaultSpecifier: declareModuleSpecifier,
  132. ImportSpecifier: declareModuleSpecifier,
  133. ImportNamespaceSpecifier: declareModuleSpecifier,
  134. });
  135. // Second pass
  136. const secondPass = babel_walk_1.ancestor({
  137. Identifier(node, state, parents) {
  138. var _a;
  139. const name = node.name;
  140. if (name === 'undefined')
  141. return;
  142. const lastParent = parents[parents.length - 2];
  143. if (lastParent) {
  144. if (!reference_1.default(node, lastParent))
  145. return;
  146. for (const parent of parents) {
  147. if (name === 'arguments' && declaresArguments(parent)) {
  148. return;
  149. }
  150. if ((_a = getLocals(parent)) === null || _a === void 0 ? void 0 : _a.has(name)) {
  151. return;
  152. }
  153. }
  154. }
  155. state.globals.push(node);
  156. },
  157. ThisExpression(node, state, parents) {
  158. for (const parent of parents) {
  159. if (declaresThis(parent)) {
  160. return;
  161. }
  162. }
  163. state.globals.push(node);
  164. },
  165. });
  166. function findGlobals(ast) {
  167. const globals = [];
  168. // istanbul ignore if
  169. if (!t.isNode(ast)) {
  170. throw new TypeError('Source must be a Babylon AST');
  171. }
  172. firstPass(ast, undefined);
  173. secondPass(ast, { globals });
  174. const groupedGlobals = new Map();
  175. for (const node of globals) {
  176. const name = node.type === 'ThisExpression' ? 'this' : node.name;
  177. const existing = groupedGlobals.get(name);
  178. if (existing) {
  179. existing.push(node);
  180. }
  181. else {
  182. groupedGlobals.set(name, [node]);
  183. }
  184. }
  185. return [...groupedGlobals]
  186. .map(([name, nodes]) => ({ name, nodes }))
  187. .sort((a, b) => (a.name < b.name ? -1 : 1));
  188. }
  189. exports.default = findGlobals;
  190. //# sourceMappingURL=globals.js.map