UNPKG

3.53 kBJavaScriptView Raw
1"use strict";
2
3// Using Node 4+ features is safe in this module, because it is not depended
4// upon by reify/lib/runtime.
5
6const acorn = require("acorn");
7const dummyParser = new acorn.Parser;
8const utils = Object.assign(exports, require("./runtime/utils.js"));
9
10const codeOfA = "A".charCodeAt(0);
11const codeOfZ = "Z".charCodeAt(0);
12
13function getNamesFromPattern(pattern) {
14 const names = [];
15 const queue = [pattern];
16
17 for (var i = 0; i < queue.length; ++i) {
18 const pattern = queue[i];
19 if (pattern === null) {
20 // The ArrayPattern .elements array can contain null to indicate that
21 // the position is a hole.
22 continue;
23 }
24
25 // Cases are ordered from most to least likely to encounter.
26 switch (pattern.type) {
27 case "Identifier":
28 names.push(pattern.name);
29 break;
30 case "Property":
31 case "ObjectProperty":
32 queue.push(pattern.value);
33 break;
34 case "AssignmentPattern":
35 queue.push(pattern.left);
36 break;
37 case "ObjectPattern":
38 queue.push.apply(queue, pattern.properties);
39 break;
40 case "ArrayPattern":
41 queue.push.apply(queue, pattern.elements);
42 break;
43 case "RestElement":
44 queue.push(pattern.argument);
45 break;
46 }
47 }
48
49 return names;
50}
51
52exports.getNamesFromPattern = getNamesFromPattern;
53
54function isCapitalized(string) {
55 if (typeof string !== "string") {
56 return false;
57 }
58 const code = string.charCodeAt(0);
59 return code >= codeOfA && code <= codeOfZ;
60}
61
62exports.isCapitalized = isCapitalized;
63
64function isNodeLike(value) {
65 // Without a complete list of Node .type names, we have to settle for this
66 // fuzzy matching of object shapes. However, the infeasibility of
67 // maintaining a complete list of type names is one of the reasons we're
68 // using the FastPath/Visitor abstraction in the first place.
69 return utils.isObject(value) &&
70 ! Array.isArray(value) &&
71 isCapitalized(value.type);
72}
73
74exports.isNodeLike = isNodeLike;
75
76function lookahead(parser) {
77 dummyParser.input = parser.input;
78 dummyParser.pos = parser.pos;
79 dummyParser.nextToken();
80 return dummyParser;
81}
82
83exports.lookahead = lookahead;
84
85function toString(value) {
86 if (typeof value === "string") {
87 return value;
88 }
89 return value == null ? "" : String(value);
90}
91
92exports.toString = toString;
93
94// Returns a sorted array of possible indexes within the code string where
95// any identifier in the identifiers array might appear. This information
96// can be used to optimize AST traversal by allowing subtrees to be
97// ignored if they don't contain any possible indexes.
98function findPossibleIndexes(code, identifiers, filter) {
99 const possibleIndexes = [];
100
101 if (identifiers.length === 0) {
102 return possibleIndexes;
103 }
104
105 const pattern = new RegExp(
106 "\\b(?:" + identifiers.join("|") + ")\\b",
107 "g"
108 );
109
110 let match;
111 pattern.lastIndex = 0;
112 while ((match = pattern.exec(code))) {
113 if (typeof filter !== "function" || filter(match)) {
114 possibleIndexes.push(match.index);
115 }
116 }
117
118 return possibleIndexes;
119}
120
121exports.findPossibleIndexes = findPossibleIndexes;
122
123function findLikelyIndexes(code, identifiers) {
124 return findPossibleIndexes(code, identifiers, function (match) {
125 // Make sure the match is not preceded by a `.` character, since that
126 // probably means the identifier is a property access rather than a
127 // variable reference.
128 return match.index < 1 ||
129 code.charAt(match.index - 1) !== ".";
130 });
131}
132
133exports.findLikelyIndexes = findLikelyIndexes;