introspection.js 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", {
  3. value: true
  4. });
  5. exports.matchesPattern = matchesPattern;
  6. exports.has = has;
  7. exports.isStatic = isStatic;
  8. exports.isnt = isnt;
  9. exports.equals = equals;
  10. exports.isNodeType = isNodeType;
  11. exports.canHaveVariableDeclarationOrExpression = canHaveVariableDeclarationOrExpression;
  12. exports.canSwapBetweenExpressionAndStatement = canSwapBetweenExpressionAndStatement;
  13. exports.isCompletionRecord = isCompletionRecord;
  14. exports.isStatementOrBlock = isStatementOrBlock;
  15. exports.referencesImport = referencesImport;
  16. exports.getSource = getSource;
  17. exports.willIMaybeExecuteBefore = willIMaybeExecuteBefore;
  18. exports._guessExecutionStatusRelativeTo = _guessExecutionStatusRelativeTo;
  19. exports._guessExecutionStatusRelativeToDifferentFunctions = _guessExecutionStatusRelativeToDifferentFunctions;
  20. exports.resolve = resolve;
  21. exports._resolve = _resolve;
  22. exports.isConstantExpression = isConstantExpression;
  23. exports.isInStrictMode = isInStrictMode;
  24. exports.is = void 0;
  25. function _includes() {
  26. const data = _interopRequireDefault(require("lodash/includes"));
  27. _includes = function () {
  28. return data;
  29. };
  30. return data;
  31. }
  32. function t() {
  33. const data = _interopRequireWildcard(require("@babel/types"));
  34. t = function () {
  35. return data;
  36. };
  37. return data;
  38. }
  39. 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; } }
  40. function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
  41. function matchesPattern(pattern, allowPartial) {
  42. return t().matchesPattern(this.node, pattern, allowPartial);
  43. }
  44. function has(key) {
  45. const val = this.node && this.node[key];
  46. if (val && Array.isArray(val)) {
  47. return !!val.length;
  48. } else {
  49. return !!val;
  50. }
  51. }
  52. function isStatic() {
  53. return this.scope.isStatic(this.node);
  54. }
  55. const is = has;
  56. exports.is = is;
  57. function isnt(key) {
  58. return !this.has(key);
  59. }
  60. function equals(key, value) {
  61. return this.node[key] === value;
  62. }
  63. function isNodeType(type) {
  64. return t().isType(this.type, type);
  65. }
  66. function canHaveVariableDeclarationOrExpression() {
  67. return (this.key === "init" || this.key === "left") && this.parentPath.isFor();
  68. }
  69. function canSwapBetweenExpressionAndStatement(replacement) {
  70. if (this.key !== "body" || !this.parentPath.isArrowFunctionExpression()) {
  71. return false;
  72. }
  73. if (this.isExpression()) {
  74. return t().isBlockStatement(replacement);
  75. } else if (this.isBlockStatement()) {
  76. return t().isExpression(replacement);
  77. }
  78. return false;
  79. }
  80. function isCompletionRecord(allowInsideFunction) {
  81. let path = this;
  82. let first = true;
  83. do {
  84. const container = path.container;
  85. if (path.isFunction() && !first) {
  86. return !!allowInsideFunction;
  87. }
  88. first = false;
  89. if (Array.isArray(container) && path.key !== container.length - 1) {
  90. return false;
  91. }
  92. } while ((path = path.parentPath) && !path.isProgram());
  93. return true;
  94. }
  95. function isStatementOrBlock() {
  96. if (this.parentPath.isLabeledStatement() || t().isBlockStatement(this.container)) {
  97. return false;
  98. } else {
  99. return (0, _includes().default)(t().STATEMENT_OR_BLOCK_KEYS, this.key);
  100. }
  101. }
  102. function referencesImport(moduleSource, importName) {
  103. if (!this.isReferencedIdentifier()) return false;
  104. const binding = this.scope.getBinding(this.node.name);
  105. if (!binding || binding.kind !== "module") return false;
  106. const path = binding.path;
  107. const parent = path.parentPath;
  108. if (!parent.isImportDeclaration()) return false;
  109. if (parent.node.source.value === moduleSource) {
  110. if (!importName) return true;
  111. } else {
  112. return false;
  113. }
  114. if (path.isImportDefaultSpecifier() && importName === "default") {
  115. return true;
  116. }
  117. if (path.isImportNamespaceSpecifier() && importName === "*") {
  118. return true;
  119. }
  120. if (path.isImportSpecifier() && path.node.imported.name === importName) {
  121. return true;
  122. }
  123. return false;
  124. }
  125. function getSource() {
  126. const node = this.node;
  127. if (node.end) {
  128. const code = this.hub.getCode();
  129. if (code) return code.slice(node.start, node.end);
  130. }
  131. return "";
  132. }
  133. function willIMaybeExecuteBefore(target) {
  134. return this._guessExecutionStatusRelativeTo(target) !== "after";
  135. }
  136. function _guessExecutionStatusRelativeTo(target) {
  137. const targetFuncParent = target.scope.getFunctionParent() || target.scope.getProgramParent();
  138. const selfFuncParent = this.scope.getFunctionParent() || target.scope.getProgramParent();
  139. if (targetFuncParent.node !== selfFuncParent.node) {
  140. const status = this._guessExecutionStatusRelativeToDifferentFunctions(targetFuncParent);
  141. if (status) {
  142. return status;
  143. } else {
  144. target = targetFuncParent.path;
  145. }
  146. }
  147. const targetPaths = target.getAncestry();
  148. if (targetPaths.indexOf(this) >= 0) return "after";
  149. const selfPaths = this.getAncestry();
  150. let commonPath;
  151. let targetIndex;
  152. let selfIndex;
  153. for (selfIndex = 0; selfIndex < selfPaths.length; selfIndex++) {
  154. const selfPath = selfPaths[selfIndex];
  155. targetIndex = targetPaths.indexOf(selfPath);
  156. if (targetIndex >= 0) {
  157. commonPath = selfPath;
  158. break;
  159. }
  160. }
  161. if (!commonPath) {
  162. return "before";
  163. }
  164. const targetRelationship = targetPaths[targetIndex - 1];
  165. const selfRelationship = selfPaths[selfIndex - 1];
  166. if (!targetRelationship || !selfRelationship) {
  167. return "before";
  168. }
  169. if (targetRelationship.listKey && targetRelationship.container === selfRelationship.container) {
  170. return targetRelationship.key > selfRelationship.key ? "before" : "after";
  171. }
  172. const keys = t().VISITOR_KEYS[commonPath.type];
  173. const targetKeyPosition = keys.indexOf(targetRelationship.key);
  174. const selfKeyPosition = keys.indexOf(selfRelationship.key);
  175. return targetKeyPosition > selfKeyPosition ? "before" : "after";
  176. }
  177. function _guessExecutionStatusRelativeToDifferentFunctions(targetFuncParent) {
  178. const targetFuncPath = targetFuncParent.path;
  179. if (!targetFuncPath.isFunctionDeclaration()) return;
  180. const binding = targetFuncPath.scope.getBinding(targetFuncPath.node.id.name);
  181. if (!binding.references) return "before";
  182. const referencePaths = binding.referencePaths;
  183. for (const path of referencePaths) {
  184. if (path.key !== "callee" || !path.parentPath.isCallExpression()) {
  185. return;
  186. }
  187. }
  188. let allStatus;
  189. for (const path of referencePaths) {
  190. const childOfFunction = !!path.find(path => path.node === targetFuncPath.node);
  191. if (childOfFunction) continue;
  192. const status = this._guessExecutionStatusRelativeTo(path);
  193. if (allStatus) {
  194. if (allStatus !== status) return;
  195. } else {
  196. allStatus = status;
  197. }
  198. }
  199. return allStatus;
  200. }
  201. function resolve(dangerous, resolved) {
  202. return this._resolve(dangerous, resolved) || this;
  203. }
  204. function _resolve(dangerous, resolved) {
  205. if (resolved && resolved.indexOf(this) >= 0) return;
  206. resolved = resolved || [];
  207. resolved.push(this);
  208. if (this.isVariableDeclarator()) {
  209. if (this.get("id").isIdentifier()) {
  210. return this.get("init").resolve(dangerous, resolved);
  211. } else {}
  212. } else if (this.isReferencedIdentifier()) {
  213. const binding = this.scope.getBinding(this.node.name);
  214. if (!binding) return;
  215. if (!binding.constant) return;
  216. if (binding.kind === "module") return;
  217. if (binding.path !== this) {
  218. const ret = binding.path.resolve(dangerous, resolved);
  219. if (this.find(parent => parent.node === ret.node)) return;
  220. return ret;
  221. }
  222. } else if (this.isTypeCastExpression()) {
  223. return this.get("expression").resolve(dangerous, resolved);
  224. } else if (dangerous && this.isMemberExpression()) {
  225. const targetKey = this.toComputedKey();
  226. if (!t().isLiteral(targetKey)) return;
  227. const targetName = targetKey.value;
  228. const target = this.get("object").resolve(dangerous, resolved);
  229. if (target.isObjectExpression()) {
  230. const props = target.get("properties");
  231. for (const prop of props) {
  232. if (!prop.isProperty()) continue;
  233. const key = prop.get("key");
  234. let match = prop.isnt("computed") && key.isIdentifier({
  235. name: targetName
  236. });
  237. match = match || key.isLiteral({
  238. value: targetName
  239. });
  240. if (match) return prop.get("value").resolve(dangerous, resolved);
  241. }
  242. } else if (target.isArrayExpression() && !isNaN(+targetName)) {
  243. const elems = target.get("elements");
  244. const elem = elems[targetName];
  245. if (elem) return elem.resolve(dangerous, resolved);
  246. }
  247. }
  248. }
  249. function isConstantExpression() {
  250. if (this.isIdentifier()) {
  251. const binding = this.scope.getBinding(this.node.name);
  252. if (!binding) return false;
  253. return binding.constant;
  254. }
  255. if (this.isLiteral()) {
  256. if (this.isRegExpLiteral()) {
  257. return false;
  258. }
  259. if (this.isTemplateLiteral()) {
  260. return this.get("expressions").every(expression => expression.isConstantExpression());
  261. }
  262. return true;
  263. }
  264. if (this.isUnaryExpression()) {
  265. if (this.get("operator").node !== "void") {
  266. return false;
  267. }
  268. return this.get("argument").isConstantExpression();
  269. }
  270. if (this.isBinaryExpression()) {
  271. return this.get("left").isConstantExpression() && this.get("right").isConstantExpression();
  272. }
  273. return false;
  274. }
  275. function isInStrictMode() {
  276. const start = this.isProgram() ? this : this.parentPath;
  277. const strictParent = start.find(path => {
  278. if (path.isProgram({
  279. sourceType: "module"
  280. })) return true;
  281. if (path.isClass()) return true;
  282. if (!path.isProgram() && !path.isFunction()) return false;
  283. if (path.isArrowFunctionExpression() && !path.get("body").isBlockStatement()) {
  284. return false;
  285. }
  286. let {
  287. node
  288. } = path;
  289. if (path.isFunction()) node = node.body;
  290. for (const directive of node.directives) {
  291. if (directive.value.value === "use strict") {
  292. return true;
  293. }
  294. }
  295. });
  296. return !!strictParent;
  297. }