hermes-transform 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +8 -0
- package/dist/detachedNode.js +128 -0
- package/dist/detachedNode.js.flow +113 -0
- package/dist/generated/TransformCloneSignatures.js.flow +19 -0
- package/dist/generated/TransformReplaceSignatures.js.flow +943 -0
- package/dist/generated/node-types.js +2071 -0
- package/dist/generated/node-types.js.flow +3149 -0
- package/dist/generated/special-case-node-types.js +178 -0
- package/dist/generated/special-case-node-types.js.flow +248 -0
- package/dist/getVisitorKeys.js +35 -0
- package/dist/getVisitorKeys.js.flow +31 -0
- package/dist/index.js +41 -0
- package/dist/index.js.flow +15 -0
- package/dist/transform/Errors.js +151 -0
- package/dist/transform/Errors.js.flow +17 -0
- package/dist/transform/MutationContext.js +94 -0
- package/dist/transform/MutationContext.js.flow +80 -0
- package/dist/transform/TransformContext.js +136 -0
- package/dist/transform/TransformContext.js.flow +378 -0
- package/dist/transform/comments/comments.js +140 -0
- package/dist/transform/comments/comments.js.flow +145 -0
- package/dist/transform/comments/prettier/README.md +6 -0
- package/dist/transform/comments/prettier/common/util.js +365 -0
- package/dist/transform/comments/prettier/common/util.js.flow +349 -0
- package/dist/transform/comments/prettier/language-js/comments.js +777 -0
- package/dist/transform/comments/prettier/language-js/comments.js.flow +950 -0
- package/dist/transform/comments/prettier/language-js/loc.js +41 -0
- package/dist/transform/comments/prettier/language-js/loc.js.flow +41 -0
- package/dist/transform/comments/prettier/language-js/printer-estree.js +31 -0
- package/dist/transform/comments/prettier/language-js/printer-estree.js.flow +37 -0
- package/dist/transform/comments/prettier/language-js/utils.js +131 -0
- package/dist/transform/comments/prettier/language-js/utils.js.flow +135 -0
- package/dist/transform/comments/prettier/main/comments.js +513 -0
- package/dist/transform/comments/prettier/main/comments.js.flow +436 -0
- package/dist/transform/comments/prettier/utils/get-last.js +15 -0
- package/dist/transform/comments/prettier/utils/get-last.js.flow +14 -0
- package/dist/transform/getTransformedAST.js +159 -0
- package/dist/transform/getTransformedAST.js.flow +128 -0
- package/dist/transform/mutations/AddLeadingComments.js +47 -0
- package/dist/transform/mutations/AddLeadingComments.js.flow +49 -0
- package/dist/transform/mutations/AddTrailingComments.js +47 -0
- package/dist/transform/mutations/AddTrailingComments.js.flow +49 -0
- package/dist/transform/mutations/CloneCommentsTo.js +46 -0
- package/dist/transform/mutations/CloneCommentsTo.js.flow +51 -0
- package/dist/transform/mutations/InsertStatement.js +92 -0
- package/dist/transform/mutations/InsertStatement.js.flow +113 -0
- package/dist/transform/mutations/RemoveComment.js +96 -0
- package/dist/transform/mutations/RemoveComment.js.flow +80 -0
- package/dist/transform/mutations/RemoveStatement.js +61 -0
- package/dist/transform/mutations/RemoveStatement.js.flow +68 -0
- package/dist/transform/mutations/ReplaceNode.js +96 -0
- package/dist/transform/mutations/ReplaceNode.js.flow +113 -0
- package/dist/transform/mutations/ReplaceStatementWithMany.js +81 -0
- package/dist/transform/mutations/ReplaceStatementWithMany.js.flow +102 -0
- package/dist/transform/mutations/utils/arrayUtils.js +41 -0
- package/dist/transform/mutations/utils/arrayUtils.js.flow +35 -0
- package/dist/transform/mutations/utils/getStatementParent.js +147 -0
- package/dist/transform/mutations/utils/getStatementParent.js.flow +143 -0
- package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js +53 -0
- package/dist/transform/mutations/utils/isValidModuleDeclarationParent.js.flow +50 -0
- package/dist/transform/transform.js +69 -0
- package/dist/transform/transform.js.flow +60 -0
- package/dist/traverse/NodeEventGenerator.js +427 -0
- package/dist/traverse/NodeEventGenerator.js.flow +406 -0
- package/dist/traverse/SafeEmitter.js +70 -0
- package/dist/traverse/SafeEmitter.js.flow +46 -0
- package/dist/traverse/SimpleTraverser.js +149 -0
- package/dist/traverse/SimpleTraverser.js.flow +109 -0
- package/dist/traverse/esquery.js +37 -0
- package/dist/traverse/esquery.js.flow +173 -0
- package/dist/traverse/traverse.js +139 -0
- package/dist/traverse/traverse.js.flow +149 -0
- package/package.json +22 -0
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
* @flow strict-local
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
'use strict';
|
|
12
|
+
|
|
13
|
+
import type {Visitor} from '../traverse/traverse';
|
|
14
|
+
import type {TransformContext} from './TransformContext';
|
|
15
|
+
|
|
16
|
+
import * as prettier from 'prettier';
|
|
17
|
+
import {getTransformedAST} from './getTransformedAST';
|
|
18
|
+
import {SimpleTraverser} from '../traverse/SimpleTraverser';
|
|
19
|
+
|
|
20
|
+
export type Visitors = Visitor<TransformContext>;
|
|
21
|
+
|
|
22
|
+
export function transform(
|
|
23
|
+
originalCode: string,
|
|
24
|
+
visitors: Visitor<TransformContext>,
|
|
25
|
+
prettierOptions: {...} = {},
|
|
26
|
+
): string {
|
|
27
|
+
const {ast, astWasMutated, mutatedCode} = getTransformedAST(
|
|
28
|
+
originalCode,
|
|
29
|
+
visitors,
|
|
30
|
+
);
|
|
31
|
+
|
|
32
|
+
if (!astWasMutated) {
|
|
33
|
+
return originalCode;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// prettier fully expects the parent pointers are NOT set and
|
|
37
|
+
// certain cases can crash due to prettier infinite-looping
|
|
38
|
+
// whilst naively traversing the parent property
|
|
39
|
+
// https://github.com/prettier/prettier/issues/11793
|
|
40
|
+
SimpleTraverser.traverse(ast, {
|
|
41
|
+
enter(node) {
|
|
42
|
+
// $FlowExpectedError[cannot-write]
|
|
43
|
+
delete node.parent;
|
|
44
|
+
},
|
|
45
|
+
leave() {},
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
// we need to delete the comments prop or else prettier will do
|
|
49
|
+
// its own attachment pass after the mutation and duplicate the
|
|
50
|
+
// comments on each node, borking the output
|
|
51
|
+
// $FlowExpectedError[cannot-write]
|
|
52
|
+
delete ast.comments;
|
|
53
|
+
|
|
54
|
+
return prettier.format(mutatedCode, {
|
|
55
|
+
...prettierOptions,
|
|
56
|
+
parser() {
|
|
57
|
+
return ast;
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
}
|
|
@@ -0,0 +1,427 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright (c) Facebook, Inc. and its affiliates.
|
|
3
|
+
*
|
|
4
|
+
* This source code is licensed under the MIT license found in the
|
|
5
|
+
* LICENSE file in the root directory of this source tree.
|
|
6
|
+
*
|
|
7
|
+
*
|
|
8
|
+
* @format
|
|
9
|
+
*/
|
|
10
|
+
'use strict';
|
|
11
|
+
|
|
12
|
+
function _typeof(obj) { "@babel/helpers - typeof"; if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
|
|
13
|
+
|
|
14
|
+
Object.defineProperty(exports, "__esModule", {
|
|
15
|
+
value: true
|
|
16
|
+
});
|
|
17
|
+
exports.NodeEventGenerator = void 0;
|
|
18
|
+
|
|
19
|
+
var _hermesEslint = require("hermes-eslint");
|
|
20
|
+
|
|
21
|
+
var esquery = _interopRequireWildcard(require("./esquery"));
|
|
22
|
+
|
|
23
|
+
function _getRequireWildcardCache(nodeInterop) { if (typeof WeakMap !== "function") return null; var cacheBabelInterop = new WeakMap(); var cacheNodeInterop = new WeakMap(); return (_getRequireWildcardCache = function _getRequireWildcardCache(nodeInterop) { return nodeInterop ? cacheNodeInterop : cacheBabelInterop; })(nodeInterop); }
|
|
24
|
+
|
|
25
|
+
function _interopRequireWildcard(obj, nodeInterop) { if (!nodeInterop && obj && obj.__esModule) { return obj; } if (obj === null || _typeof(obj) !== "object" && typeof obj !== "function") { return { "default": obj }; } var cache = _getRequireWildcardCache(nodeInterop); if (cache && cache.has(obj)) { return cache.get(obj); } var newObj = {}; var hasPropertyDescriptor = Object.defineProperty && Object.getOwnPropertyDescriptor; for (var key in obj) { if (key !== "default" && Object.prototype.hasOwnProperty.call(obj, key)) { var desc = hasPropertyDescriptor ? Object.getOwnPropertyDescriptor(obj, key) : null; if (desc && (desc.get || desc.set)) { Object.defineProperty(newObj, key, desc); } else { newObj[key] = obj[key]; } } } newObj["default"] = obj; if (cache) { cache.set(obj, newObj); } return newObj; }
|
|
26
|
+
|
|
27
|
+
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
|
|
28
|
+
|
|
29
|
+
function _defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ("value" in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } }
|
|
30
|
+
|
|
31
|
+
function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
|
|
32
|
+
|
|
33
|
+
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
|
34
|
+
|
|
35
|
+
function _createForOfIteratorHelper(o, allowArrayLike) { var it = typeof Symbol !== "undefined" && o[Symbol.iterator] || o["@@iterator"]; if (!it) { if (Array.isArray(o) || (it = _unsupportedIterableToArray(o)) || allowArrayLike && o && typeof o.length === "number") { if (it) o = it; var i = 0; var F = function F() {}; return { s: F, n: function n() { if (i >= o.length) return { done: true }; return { done: false, value: o[i++] }; }, e: function e(_e) { throw _e; }, f: F }; } throw new TypeError("Invalid attempt to iterate non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); } var normalCompletion = true, didErr = false, err; return { s: function s() { it = it.call(o); }, n: function n() { var step = it.next(); normalCompletion = step.done; return step; }, e: function e(_e2) { didErr = true; err = _e2; }, f: function f() { try { if (!normalCompletion && it["return"] != null) it["return"](); } finally { if (didErr) throw err; } } }; }
|
|
36
|
+
|
|
37
|
+
function _toConsumableArray(arr) { return _arrayWithoutHoles(arr) || _iterableToArray(arr) || _unsupportedIterableToArray(arr) || _nonIterableSpread(); }
|
|
38
|
+
|
|
39
|
+
function _nonIterableSpread() { throw new TypeError("Invalid attempt to spread non-iterable instance.\nIn order to be iterable, non-array objects must have a [Symbol.iterator]() method."); }
|
|
40
|
+
|
|
41
|
+
function _unsupportedIterableToArray(o, minLen) { if (!o) return; if (typeof o === "string") return _arrayLikeToArray(o, minLen); var n = Object.prototype.toString.call(o).slice(8, -1); if (n === "Object" && o.constructor) n = o.constructor.name; if (n === "Map" || n === "Set") return Array.from(o); if (n === "Arguments" || /^(?:Ui|I)nt(?:8|16|32)(?:Clamped)?Array$/.test(n)) return _arrayLikeToArray(o, minLen); }
|
|
42
|
+
|
|
43
|
+
function _iterableToArray(iter) { if (typeof Symbol !== "undefined" && iter[Symbol.iterator] != null || iter["@@iterator"] != null) return Array.from(iter); }
|
|
44
|
+
|
|
45
|
+
function _arrayWithoutHoles(arr) { if (Array.isArray(arr)) return _arrayLikeToArray(arr); }
|
|
46
|
+
|
|
47
|
+
function _arrayLikeToArray(arr, len) { if (len == null || len > arr.length) len = arr.length; for (var i = 0, arr2 = new Array(len); i < len; i++) { arr2[i] = arr[i]; } return arr2; }
|
|
48
|
+
|
|
49
|
+
var ESQUERY_OPTIONS = Object.freeze({
|
|
50
|
+
visitorKeys: _hermesEslint.VisitorKeys,
|
|
51
|
+
fallback: function fallback(node) {
|
|
52
|
+
throw new Error("No visitor keys found for node type \"".concat(node.type, "\"."));
|
|
53
|
+
}
|
|
54
|
+
});
|
|
55
|
+
/**
|
|
56
|
+
* Computes the union of one or more arrays
|
|
57
|
+
* @param arrays One or more arrays to union
|
|
58
|
+
* @returns The union of the input arrays
|
|
59
|
+
*/
|
|
60
|
+
|
|
61
|
+
function union() {
|
|
62
|
+
for (var _len = arguments.length, arrays = new Array(_len), _key = 0; _key < _len; _key++) {
|
|
63
|
+
arrays[_key] = arguments[_key];
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
return _toConsumableArray(new Set(arrays.flat()));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Computes the intersection of one or more arrays
|
|
70
|
+
* @param arrays One or more arrays to intersect
|
|
71
|
+
* @returns The intersection of the input arrays
|
|
72
|
+
*/
|
|
73
|
+
|
|
74
|
+
|
|
75
|
+
function intersection() {
|
|
76
|
+
for (var _len2 = arguments.length, arrays = new Array(_len2), _key2 = 0; _key2 < _len2; _key2++) {
|
|
77
|
+
arrays[_key2] = arguments[_key2];
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
if (arrays.length === 0) {
|
|
81
|
+
return [];
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
var result = _toConsumableArray(new Set(arrays[0]));
|
|
85
|
+
|
|
86
|
+
var _iterator = _createForOfIteratorHelper(arrays.slice(1)),
|
|
87
|
+
_step;
|
|
88
|
+
|
|
89
|
+
try {
|
|
90
|
+
var _loop = function _loop() {
|
|
91
|
+
var array = _step.value;
|
|
92
|
+
result = result.filter(function (x) {
|
|
93
|
+
return array.includes(x);
|
|
94
|
+
});
|
|
95
|
+
};
|
|
96
|
+
|
|
97
|
+
for (_iterator.s(); !(_step = _iterator.n()).done;) {
|
|
98
|
+
_loop();
|
|
99
|
+
}
|
|
100
|
+
} catch (err) {
|
|
101
|
+
_iterator.e(err);
|
|
102
|
+
} finally {
|
|
103
|
+
_iterator.f();
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
return result;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* Gets the possible types of a selector
|
|
110
|
+
* @param parsedSelector An object (from esquery) describing the matching behavior of the selector
|
|
111
|
+
* @returns The node types that could possibly trigger this selector, or `null` if all node types could trigger it
|
|
112
|
+
*/
|
|
113
|
+
|
|
114
|
+
|
|
115
|
+
function getPossibleTypes(parsedSelector) {
|
|
116
|
+
switch (parsedSelector.type) {
|
|
117
|
+
case 'identifier':
|
|
118
|
+
if (!(parsedSelector.value in _hermesEslint.VisitorKeys)) {
|
|
119
|
+
throw new Error("Unexpected selector ".concat(parsedSelector.value));
|
|
120
|
+
} // $FlowExpectedError[incompatible-return]
|
|
121
|
+
|
|
122
|
+
|
|
123
|
+
return [parsedSelector.value];
|
|
124
|
+
|
|
125
|
+
case 'matches':
|
|
126
|
+
{
|
|
127
|
+
var typesForComponents = parsedSelector.selectors.map(getPossibleTypes);
|
|
128
|
+
var typesForComponentsNonNull = typesForComponents.filter(Boolean);
|
|
129
|
+
|
|
130
|
+
if (typesForComponents.length === typesForComponentsNonNull.length) {
|
|
131
|
+
return union.apply(void 0, _toConsumableArray(typesForComponentsNonNull));
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
return null;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
case 'compound':
|
|
138
|
+
{
|
|
139
|
+
var _typesForComponents = parsedSelector.selectors.map(getPossibleTypes).filter(Boolean); // If all of the components could match any type, then the compound could also match any type.
|
|
140
|
+
|
|
141
|
+
|
|
142
|
+
if (!_typesForComponents.length) {
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
/*
|
|
146
|
+
* If at least one of the components could only match a particular type, the compound could only match
|
|
147
|
+
* the intersection of those types.
|
|
148
|
+
*/
|
|
149
|
+
|
|
150
|
+
|
|
151
|
+
return intersection.apply(void 0, _toConsumableArray(_typesForComponents));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
case 'child':
|
|
155
|
+
case 'descendant':
|
|
156
|
+
case 'sibling':
|
|
157
|
+
case 'adjacent':
|
|
158
|
+
return getPossibleTypes(parsedSelector.right);
|
|
159
|
+
|
|
160
|
+
case 'class':
|
|
161
|
+
if (parsedSelector.name === 'function') {
|
|
162
|
+
return ['FunctionDeclaration', 'FunctionExpression', 'ArrowFunctionExpression'];
|
|
163
|
+
}
|
|
164
|
+
|
|
165
|
+
return null;
|
|
166
|
+
|
|
167
|
+
default:
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
/**
|
|
172
|
+
* Counts the number of class, pseudo-class, and attribute queries in this selector
|
|
173
|
+
* @param parsedSelector An object (from esquery) describing the selector's matching behavior
|
|
174
|
+
* @returns The number of class, pseudo-class, and attribute queries in this selector
|
|
175
|
+
*/
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
function countClassAttributes(parsedSelector) {
|
|
179
|
+
switch (parsedSelector.type) {
|
|
180
|
+
case 'child':
|
|
181
|
+
case 'descendant':
|
|
182
|
+
case 'sibling':
|
|
183
|
+
case 'adjacent':
|
|
184
|
+
return countClassAttributes(parsedSelector.left) + countClassAttributes(parsedSelector.right);
|
|
185
|
+
|
|
186
|
+
case 'compound':
|
|
187
|
+
case 'not':
|
|
188
|
+
case 'matches':
|
|
189
|
+
return parsedSelector.selectors.reduce(function (sum, childSelector) {
|
|
190
|
+
return sum + countClassAttributes(childSelector);
|
|
191
|
+
}, 0);
|
|
192
|
+
|
|
193
|
+
case 'attribute':
|
|
194
|
+
case 'field':
|
|
195
|
+
case 'nth-child':
|
|
196
|
+
case 'nth-last-child':
|
|
197
|
+
return 1;
|
|
198
|
+
|
|
199
|
+
default:
|
|
200
|
+
return 0;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
/**
|
|
204
|
+
* Counts the number of identifier queries in this selector
|
|
205
|
+
* @param parsedSelector An object (from esquery) describing the selector's matching behavior
|
|
206
|
+
* @returns The number of identifier queries
|
|
207
|
+
*/
|
|
208
|
+
|
|
209
|
+
|
|
210
|
+
function countIdentifiers(parsedSelector) {
|
|
211
|
+
switch (parsedSelector.type) {
|
|
212
|
+
case 'child':
|
|
213
|
+
case 'descendant':
|
|
214
|
+
case 'sibling':
|
|
215
|
+
case 'adjacent':
|
|
216
|
+
return countIdentifiers(parsedSelector.left) + countIdentifiers(parsedSelector.right);
|
|
217
|
+
|
|
218
|
+
case 'compound':
|
|
219
|
+
case 'not':
|
|
220
|
+
case 'matches':
|
|
221
|
+
return parsedSelector.selectors.reduce(function (sum, childSelector) {
|
|
222
|
+
return sum + countIdentifiers(childSelector);
|
|
223
|
+
}, 0);
|
|
224
|
+
|
|
225
|
+
case 'identifier':
|
|
226
|
+
return 1;
|
|
227
|
+
|
|
228
|
+
default:
|
|
229
|
+
return 0;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
/**
|
|
233
|
+
* Compares the specificity of two selector objects, with CSS-like rules.
|
|
234
|
+
* @param selectorA An AST selector descriptor
|
|
235
|
+
* @param selectorB Another AST selector descriptor
|
|
236
|
+
* @returns
|
|
237
|
+
* a value less than 0 if selectorA is less specific than selectorB
|
|
238
|
+
* a value greater than 0 if selectorA is more specific than selectorB
|
|
239
|
+
* a value less than 0 if selectorA and selectorB have the same specificity, and selectorA <= selectorB alphabetically
|
|
240
|
+
* a value greater than 0 if selectorA and selectorB have the same specificity, and selectorA > selectorB alphabetically
|
|
241
|
+
*/
|
|
242
|
+
|
|
243
|
+
|
|
244
|
+
function compareSpecificity(selectorA, selectorB) {
|
|
245
|
+
return selectorA.attributeCount - selectorB.attributeCount || selectorA.identifierCount - selectorB.identifierCount || (selectorA.rawSelector <= selectorB.rawSelector ? -1 : 1);
|
|
246
|
+
}
|
|
247
|
+
/**
|
|
248
|
+
* Parses a raw selector string, and throws a useful error if parsing fails.
|
|
249
|
+
* @param rawSelector A raw AST selector
|
|
250
|
+
* @returns An object (from esquery) describing the matching behavior of this selector
|
|
251
|
+
* @throws An error if the selector is invalid
|
|
252
|
+
*/
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
function tryParseSelector(rawSelector) {
|
|
256
|
+
try {
|
|
257
|
+
return esquery.parse(rawSelector.replace(/:exit$/, ''));
|
|
258
|
+
} catch (err) {
|
|
259
|
+
if (err.location && err.location.start && typeof err.location.start.offset === 'number') {
|
|
260
|
+
throw new SyntaxError("Syntax error in selector \"".concat(rawSelector, "\" at position ").concat(err.location.start.offset, ": ").concat(err.message));
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
throw err;
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
var selectorCache = new Map();
|
|
268
|
+
/**
|
|
269
|
+
* Parses a raw selector string, and returns the parsed selector along with specificity and type information.
|
|
270
|
+
* @param rawSelector A raw AST selector
|
|
271
|
+
* @returns A selector descriptor
|
|
272
|
+
*/
|
|
273
|
+
|
|
274
|
+
function parseSelector(rawSelector) {
|
|
275
|
+
var cachedSelector = selectorCache.get(rawSelector);
|
|
276
|
+
|
|
277
|
+
if (cachedSelector) {
|
|
278
|
+
return cachedSelector;
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
var parsedSelector = tryParseSelector(rawSelector);
|
|
282
|
+
var result = {
|
|
283
|
+
rawSelector: rawSelector,
|
|
284
|
+
isExit: rawSelector.endsWith(':exit'),
|
|
285
|
+
parsedSelector: parsedSelector,
|
|
286
|
+
listenerTypes: getPossibleTypes(parsedSelector),
|
|
287
|
+
attributeCount: countClassAttributes(parsedSelector),
|
|
288
|
+
identifierCount: countIdentifiers(parsedSelector)
|
|
289
|
+
};
|
|
290
|
+
selectorCache.set(rawSelector, result);
|
|
291
|
+
return result;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The event generator for AST nodes.
|
|
295
|
+
*/
|
|
296
|
+
|
|
297
|
+
|
|
298
|
+
var NodeEventGenerator = /*#__PURE__*/function () {
|
|
299
|
+
/**
|
|
300
|
+
* @param emitter
|
|
301
|
+
* An SafeEmitter which is the destination of events. This emitter must already
|
|
302
|
+
* have registered listeners for all of the events that it needs to listen for.
|
|
303
|
+
* (See lib/linter/safe-emitter.js for more details on `SafeEmitter`.)
|
|
304
|
+
*/
|
|
305
|
+
function NodeEventGenerator(emitter) {
|
|
306
|
+
var _this = this;
|
|
307
|
+
|
|
308
|
+
_classCallCheck(this, NodeEventGenerator);
|
|
309
|
+
|
|
310
|
+
_defineProperty(this, "emitter", void 0);
|
|
311
|
+
|
|
312
|
+
_defineProperty(this, "_currentAncestry", []);
|
|
313
|
+
|
|
314
|
+
_defineProperty(this, "_enterSelectorsByNodeType", new Map());
|
|
315
|
+
|
|
316
|
+
_defineProperty(this, "_exitSelectorsByNodeType", new Map());
|
|
317
|
+
|
|
318
|
+
_defineProperty(this, "_anyTypeEnterSelectors", []);
|
|
319
|
+
|
|
320
|
+
_defineProperty(this, "_anyTypeExitSelectors", []);
|
|
321
|
+
|
|
322
|
+
this.emitter = emitter;
|
|
323
|
+
emitter.eventNames().forEach(function (rawSelector) {
|
|
324
|
+
var selector = parseSelector(rawSelector);
|
|
325
|
+
|
|
326
|
+
if (selector.listenerTypes) {
|
|
327
|
+
var typeMap = selector.isExit ? _this._exitSelectorsByNodeType : _this._enterSelectorsByNodeType;
|
|
328
|
+
selector.listenerTypes.forEach(function (nodeType) {
|
|
329
|
+
var selectors = typeMap.get(nodeType);
|
|
330
|
+
|
|
331
|
+
if (!selectors) {
|
|
332
|
+
typeMap.set(nodeType, [selector]);
|
|
333
|
+
} else {
|
|
334
|
+
selectors.push(selector);
|
|
335
|
+
}
|
|
336
|
+
});
|
|
337
|
+
} else {
|
|
338
|
+
var selectors = selector.isExit ? _this._anyTypeExitSelectors : _this._anyTypeEnterSelectors;
|
|
339
|
+
selectors.push(selector);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
342
|
+
|
|
343
|
+
this._anyTypeEnterSelectors.sort(compareSpecificity);
|
|
344
|
+
|
|
345
|
+
this._anyTypeExitSelectors.sort(compareSpecificity);
|
|
346
|
+
|
|
347
|
+
this._enterSelectorsByNodeType.forEach(function (selectorList) {
|
|
348
|
+
return selectorList.sort(compareSpecificity);
|
|
349
|
+
});
|
|
350
|
+
|
|
351
|
+
this._exitSelectorsByNodeType.forEach(function (selectorList) {
|
|
352
|
+
return selectorList.sort(compareSpecificity);
|
|
353
|
+
});
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Checks a selector against a node, and emits it if it matches
|
|
357
|
+
* @param node The node to check
|
|
358
|
+
* @param selector An AST selector descriptor
|
|
359
|
+
* @private
|
|
360
|
+
*/
|
|
361
|
+
|
|
362
|
+
|
|
363
|
+
_createClass(NodeEventGenerator, [{
|
|
364
|
+
key: "_applySelector",
|
|
365
|
+
value: function _applySelector(node, selector) {
|
|
366
|
+
if (esquery.matches(node, selector.parsedSelector, this._currentAncestry, ESQUERY_OPTIONS)) {
|
|
367
|
+
this.emitter.emit(selector.rawSelector, node);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
/**
|
|
371
|
+
* Applies all appropriate selectors to a node, in specificity order
|
|
372
|
+
* @param node The node to check
|
|
373
|
+
* @param isExit `false` if the node is currently being entered, `true` if it's currently being exited
|
|
374
|
+
* @private
|
|
375
|
+
*/
|
|
376
|
+
|
|
377
|
+
}, {
|
|
378
|
+
key: "_applySelectors",
|
|
379
|
+
value: function _applySelectors(node, isExit) {
|
|
380
|
+
var selectorsByNodeType = (isExit ? this._exitSelectorsByNodeType : this._enterSelectorsByNodeType).get(node.type) || [];
|
|
381
|
+
var anyTypeSelectors = isExit ? this._anyTypeExitSelectors : this._anyTypeEnterSelectors;
|
|
382
|
+
/*
|
|
383
|
+
* selectorsByNodeType and anyTypeSelectors were already sorted by specificity in the constructor.
|
|
384
|
+
* Iterate through each of them, applying selectors in the right order.
|
|
385
|
+
*/
|
|
386
|
+
|
|
387
|
+
var selectorsByTypeIndex = 0;
|
|
388
|
+
var anyTypeSelectorsIndex = 0;
|
|
389
|
+
|
|
390
|
+
while (selectorsByTypeIndex < selectorsByNodeType.length || anyTypeSelectorsIndex < anyTypeSelectors.length) {
|
|
391
|
+
if (selectorsByTypeIndex >= selectorsByNodeType.length || anyTypeSelectorsIndex < anyTypeSelectors.length && compareSpecificity(anyTypeSelectors[anyTypeSelectorsIndex], selectorsByNodeType[selectorsByTypeIndex]) < 0) {
|
|
392
|
+
this._applySelector(node, anyTypeSelectors[anyTypeSelectorsIndex++]);
|
|
393
|
+
} else {
|
|
394
|
+
this._applySelector(node, selectorsByNodeType[selectorsByTypeIndex++]);
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* Emits an event of entering AST node.
|
|
400
|
+
* @param node A node which was entered.
|
|
401
|
+
*/
|
|
402
|
+
|
|
403
|
+
}, {
|
|
404
|
+
key: "enterNode",
|
|
405
|
+
value: function enterNode(node) {
|
|
406
|
+
this._applySelectors(node, false);
|
|
407
|
+
|
|
408
|
+
this._currentAncestry.unshift(node);
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Emits an event of leaving AST node.
|
|
412
|
+
* @param node A node which was left.
|
|
413
|
+
*/
|
|
414
|
+
|
|
415
|
+
}, {
|
|
416
|
+
key: "leaveNode",
|
|
417
|
+
value: function leaveNode(node) {
|
|
418
|
+
this._currentAncestry.shift();
|
|
419
|
+
|
|
420
|
+
this._applySelectors(node, true);
|
|
421
|
+
}
|
|
422
|
+
}]);
|
|
423
|
+
|
|
424
|
+
return NodeEventGenerator;
|
|
425
|
+
}();
|
|
426
|
+
|
|
427
|
+
exports.NodeEventGenerator = NodeEventGenerator;
|