hermes-parser 0.5.0 → 0.8.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.
@@ -1,216 +1,453 @@
1
1
  "use strict";
2
2
 
3
- 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); }
4
-
5
3
  Object.defineProperty(exports, "__esModule", {
6
4
  value: true
7
5
  });
8
- exports["default"] = void 0;
6
+ exports.default = void 0;
7
+
8
+ var _HermesASTAdapter = _interopRequireDefault(require("./HermesASTAdapter"));
9
+
10
+ var _getModuleDocblock = require("./getModuleDocblock");
11
+
12
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
13
+
14
+ /**
15
+ * Copyright (c) Meta Platforms, Inc. and affiliates.
16
+ *
17
+ * This source code is licensed under the MIT license found in the
18
+ * LICENSE file in the root directory of this source tree.
19
+ *
20
+ *
21
+ * @format
22
+ */
23
+
24
+ /*
25
+ This class does some very "javascripty" things in the name of
26
+ performance which are ultimately impossible to soundly type.
27
+
28
+ So instead of adding strict types and a large number of suppression
29
+ comments, instead it is left untyped and subclasses are strictly
30
+ typed via a separate flow declaration file.
31
+ */
32
+ class HermesToESTreeAdapter extends _HermesASTAdapter.default {
33
+ constructor(options, code) {
34
+ super(options);
35
+ this.code = void 0;
36
+ this.code = code;
37
+ }
9
38
 
10
- var _HermesASTAdapter2 = _interopRequireDefault(require("./HermesASTAdapter"));
39
+ fixSourceLocation(node) {
40
+ var _this$sourceFilename;
11
41
 
12
- function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { "default": obj }; }
42
+ const loc = node.loc;
13
43
 
14
- function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError("Cannot call a class as a function"); } }
44
+ if (loc == null) {
45
+ return;
46
+ }
15
47
 
16
- 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); } }
48
+ node.loc = {
49
+ source: (_this$sourceFilename = this.sourceFilename) != null ? _this$sourceFilename : null,
50
+ start: loc.start,
51
+ end: loc.end
52
+ };
53
+ node.range = [loc.rangeStart, loc.rangeEnd];
54
+ delete node.start;
55
+ delete node.end;
56
+ }
17
57
 
18
- function _createClass(Constructor, protoProps, staticProps) { if (protoProps) _defineProperties(Constructor.prototype, protoProps); if (staticProps) _defineProperties(Constructor, staticProps); return Constructor; }
58
+ mapNode(node) {
59
+ this.fixSourceLocation(node);
19
60
 
20
- function _inherits(subClass, superClass) { if (typeof superClass !== "function" && superClass !== null) { throw new TypeError("Super expression must either be null or a function"); } subClass.prototype = Object.create(superClass && superClass.prototype, { constructor: { value: subClass, writable: true, configurable: true } }); if (superClass) _setPrototypeOf(subClass, superClass); }
61
+ switch (node.type) {
62
+ case 'Program':
63
+ return this.mapProgram(node);
21
64
 
22
- function _setPrototypeOf(o, p) { _setPrototypeOf = Object.setPrototypeOf || function _setPrototypeOf(o, p) { o.__proto__ = p; return o; }; return _setPrototypeOf(o, p); }
65
+ case 'NullLiteral':
66
+ return this.mapNullLiteral(node);
23
67
 
24
- function _createSuper(Derived) { var hasNativeReflectConstruct = _isNativeReflectConstruct(); return function _createSuperInternal() { var Super = _getPrototypeOf(Derived), result; if (hasNativeReflectConstruct) { var NewTarget = _getPrototypeOf(this).constructor; result = Reflect.construct(Super, arguments, NewTarget); } else { result = Super.apply(this, arguments); } return _possibleConstructorReturn(this, result); }; }
68
+ case 'BooleanLiteral':
69
+ case 'StringLiteral':
70
+ case 'NumericLiteral':
71
+ case 'JSXStringLiteral':
72
+ return this.mapSimpleLiteral(node);
25
73
 
26
- function _possibleConstructorReturn(self, call) { if (call && (_typeof(call) === "object" || typeof call === "function")) { return call; } else if (call !== void 0) { throw new TypeError("Derived constructors may only return object or undefined"); } return _assertThisInitialized(self); }
74
+ case 'BigIntLiteral':
75
+ return this.mapBigIntLiteral(node);
27
76
 
28
- function _assertThisInitialized(self) { if (self === void 0) { throw new ReferenceError("this hasn't been initialised - super() hasn't been called"); } return self; }
77
+ case 'RegExpLiteral':
78
+ return this.mapRegExpLiteral(node);
29
79
 
30
- function _isNativeReflectConstruct() { if (typeof Reflect === "undefined" || !Reflect.construct) return false; if (Reflect.construct.sham) return false; if (typeof Proxy === "function") return true; try { Boolean.prototype.valueOf.call(Reflect.construct(Boolean, [], function () {})); return true; } catch (e) { return false; } }
80
+ case 'Empty':
81
+ return this.mapEmpty(node);
31
82
 
32
- function _getPrototypeOf(o) { _getPrototypeOf = Object.setPrototypeOf ? Object.getPrototypeOf : function _getPrototypeOf(o) { return o.__proto__ || Object.getPrototypeOf(o); }; return _getPrototypeOf(o); }
83
+ case 'TemplateElement':
84
+ return this.mapTemplateElement(node);
33
85
 
34
- 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; }
86
+ case 'BigIntLiteralTypeAnnotation':
87
+ return this.mapBigIntLiteralTypeAnnotation(node);
35
88
 
36
- var HermesToESTreeAdapter = /*#__PURE__*/function (_HermesASTAdapter) {
37
- _inherits(HermesToESTreeAdapter, _HermesASTAdapter);
89
+ case 'GenericTypeAnnotation':
90
+ return this.mapGenericTypeAnnotation(node);
38
91
 
39
- var _super = _createSuper(HermesToESTreeAdapter);
92
+ case 'ImportDeclaration':
93
+ return this.mapImportDeclaration(node);
40
94
 
41
- function HermesToESTreeAdapter(options, code) {
42
- var _this;
95
+ case 'ImportSpecifier':
96
+ return this.mapImportSpecifier(node);
43
97
 
44
- _classCallCheck(this, HermesToESTreeAdapter);
98
+ case 'ExportDefaultDeclaration':
99
+ return this.mapExportDefaultDeclaration(node);
45
100
 
46
- _this = _super.call(this, options);
101
+ case 'ExportNamedDeclaration':
102
+ return this.mapExportNamedDeclaration(node);
47
103
 
48
- _defineProperty(_assertThisInitialized(_this), "code", void 0);
104
+ case 'ExportAllDeclaration':
105
+ return this.mapExportAllDeclaration(node);
49
106
 
50
- _this.code = code;
51
- return _this;
52
- }
107
+ case 'Property':
108
+ return this.mapProperty(node);
53
109
 
54
- _createClass(HermesToESTreeAdapter, [{
55
- key: "fixSourceLocation",
56
- value: function fixSourceLocation(node) {
57
- var _this$sourceFilename;
110
+ case 'FunctionDeclaration':
111
+ case 'FunctionExpression':
112
+ case 'ArrowFunctionExpression':
113
+ return this.mapFunction(node);
58
114
 
59
- var loc = node.loc;
115
+ case 'PrivateName':
116
+ return this.mapPrivateName(node);
60
117
 
61
- if (loc == null) {
62
- return;
63
- }
118
+ case 'ClassProperty':
119
+ case 'ClassPrivateProperty':
120
+ return this.mapClassProperty(node);
64
121
 
65
- node.loc = {
66
- source: (_this$sourceFilename = this.sourceFilename) !== null && _this$sourceFilename !== void 0 ? _this$sourceFilename : null,
67
- start: loc.start,
68
- end: loc.end
69
- };
70
- node.range = [loc.rangeStart, loc.rangeEnd];
122
+ case 'MemberExpression':
123
+ case 'OptionalMemberExpression':
124
+ case 'CallExpression':
125
+ case 'OptionalCallExpression':
126
+ return this.mapChainExpression(node);
127
+
128
+ default:
129
+ return this.mapNodeDefault(node);
71
130
  }
72
- }, {
73
- key: "mapNode",
74
- value: function mapNode(node) {
75
- this.fixSourceLocation(node);
131
+ }
76
132
 
77
- switch (node.type) {
78
- case 'Program':
79
- return this.mapProgram(node);
133
+ mapProgram(node) {
134
+ node = this.mapNodeDefault(node);
135
+ node.sourceType = this.getSourceType();
136
+ node.docblock = (0, _getModuleDocblock.getModuleDocblock)(node);
137
+ return node;
138
+ }
80
139
 
81
- case 'NullLiteral':
82
- return this.mapNullLiteral(node);
140
+ mapSimpleLiteral(node) {
141
+ return {
142
+ type: 'Literal',
143
+ loc: node.loc,
144
+ range: node.range,
145
+ value: node.value,
146
+ raw: this.code.slice(node.range[0], node.range[1]),
147
+ literalType: (() => {
148
+ switch (node.type) {
149
+ case 'NullLiteral':
150
+ return 'null';
151
+
152
+ case 'BooleanLiteral':
153
+ return 'boolean';
154
+
155
+ case 'StringLiteral':
156
+ case 'JSXStringLiteral':
157
+ return 'string';
158
+
159
+ case 'NumericLiteral':
160
+ return 'numeric';
161
+
162
+ case 'BigIntLiteral':
163
+ return 'bigint';
164
+
165
+ case 'RegExpLiteral':
166
+ return 'regexp';
167
+ }
83
168
 
84
- case 'BooleanLiteral':
85
- case 'StringLiteral':
86
- case 'NumericLiteral':
87
- return this.mapSimpleLiteral(node);
169
+ return null;
170
+ })()
171
+ };
172
+ }
88
173
 
89
- case 'RegExpLiteral':
90
- return this.mapRegExpLiteral(node);
174
+ mapBigIntLiteral(node) {
175
+ const newNode = this.mapSimpleLiteral(node);
176
+ const bigint = node.bigint // estree spec is to not have a trailing `n` on this property
177
+ // https://github.com/estree/estree/blob/db962bb417a97effcfe9892f87fbb93c81a68584/es2020.md#bigintliteral
178
+ .replace(/n$/, '') // `BigInt` doesn't accept numeric separator and `bigint` property should not include numeric separator
179
+ .replace(/_/, '');
180
+ return { ...newNode,
181
+ // coerce the string to a bigint value if supported by the environment
182
+ value: typeof BigInt === 'function' ? BigInt(bigint) : null,
183
+ bigint
184
+ };
185
+ }
91
186
 
92
- case 'Empty':
93
- return this.mapEmpty(node);
187
+ mapNullLiteral(node) {
188
+ return { ...this.mapSimpleLiteral(node),
189
+ value: null
190
+ };
191
+ }
94
192
 
95
- case 'TemplateElement':
96
- return this.mapTemplateElement(node);
193
+ mapRegExpLiteral(node) {
194
+ const {
195
+ pattern,
196
+ flags
197
+ } = node; // Create RegExp value if possible. This can fail when the flags are invalid.
97
198
 
98
- case 'GenericTypeAnnotation':
99
- return this.mapGenericTypeAnnotation(node);
199
+ let value;
100
200
 
101
- case 'ImportDeclaration':
102
- return this.mapImportDeclaration(node);
201
+ try {
202
+ value = new RegExp(pattern, flags);
203
+ } catch (e) {
204
+ value = null;
205
+ }
103
206
 
104
- case 'ImportSpecifier':
105
- return this.mapImportSpecifier(node);
207
+ return { ...this.mapSimpleLiteral(node),
208
+ value,
209
+ regex: {
210
+ pattern,
211
+ flags
212
+ }
213
+ };
214
+ }
106
215
 
107
- case 'ExportDefaultDeclaration':
108
- return this.mapExportDefaultDeclaration(node);
216
+ mapBigIntLiteralTypeAnnotation(node) {
217
+ node.value = null;
218
+ return node;
219
+ }
109
220
 
110
- case 'ExportNamedDeclaration':
111
- return this.mapExportNamedDeclaration(node);
221
+ mapTemplateElement(node) {
222
+ return {
223
+ type: 'TemplateElement',
224
+ loc: node.loc,
225
+ range: node.range,
226
+ tail: node.tail,
227
+ value: {
228
+ cooked: node.cooked,
229
+ raw: node.raw
230
+ }
231
+ };
232
+ }
112
233
 
113
- case 'ExportAllDeclaration':
114
- return this.mapExportAllDeclaration(node);
234
+ mapGenericTypeAnnotation(node) {
235
+ // Convert simple `this` generic type to ThisTypeAnnotation
236
+ if (node.typeParameters == null && node.id.type === 'Identifier' && node.id.name === 'this') {
237
+ return {
238
+ type: 'ThisTypeAnnotation',
239
+ loc: node.loc,
240
+ range: node.range
241
+ };
242
+ }
115
243
 
116
- case 'PrivateName':
117
- case 'ClassPrivateProperty':
118
- return this.mapPrivateProperty(node);
244
+ return this.mapNodeDefault(node);
245
+ }
119
246
 
120
- default:
121
- return this.mapNodeDefault(node);
122
- }
123
- }
124
- }, {
125
- key: "mapProgram",
126
- value: function mapProgram(node) {
127
- node = this.mapNodeDefault(node);
128
- node.sourceType = this.getSourceType();
129
- return node;
247
+ mapProperty(nodeUnprocessed) {
248
+ const node = this.mapNodeDefault(nodeUnprocessed);
249
+
250
+ if (node.value.type === 'FunctionExpression') {
251
+ node.value.loc.start = node.key.loc.end;
252
+ node.value.range[0] = node.key.range[1];
130
253
  }
131
- }, {
132
- key: "mapSimpleLiteral",
133
- value: function mapSimpleLiteral(node) {
134
- node.type = 'Literal';
135
- node.raw = this.code.slice(node.range[0], node.range[1]);
136
- return node;
254
+
255
+ return node;
256
+ }
257
+
258
+ mapComment(node) {
259
+ if (node.type === 'CommentBlock') {
260
+ node.type = 'Block';
261
+ } else if (node.type === 'CommentLine') {
262
+ node.type = 'Line';
137
263
  }
138
- }, {
139
- key: "mapNullLiteral",
140
- value: function mapNullLiteral(node) {
141
- node.type = 'Literal';
142
- node.value = null;
143
- node.raw = this.code.slice(node.range[0], node.range[1]);
144
- return node;
264
+
265
+ return node;
266
+ }
267
+
268
+ mapFunction(nodeUnprocessed) {
269
+ const node = this.mapNodeDefault(nodeUnprocessed);
270
+
271
+ switch (node.type) {
272
+ case 'FunctionDeclaration':
273
+ case 'FunctionExpression':
274
+ node.expression = false;
275
+ return node;
276
+
277
+ case 'ArrowFunctionExpression':
278
+ node.expression = node.body.type !== 'BlockStatement';
279
+ return node;
145
280
  }
146
- }, {
147
- key: "mapRegExpLiteral",
148
- value: function mapRegExpLiteral(node) {
149
- var pattern = node.pattern,
150
- flags = node.flags; // Create RegExp value if possible. This can fail when the flags are invalid.
151
-
152
- var value;
153
-
154
- try {
155
- value = new RegExp(pattern, flags);
156
- } catch (e) {
157
- value = null;
281
+
282
+ return node;
283
+ }
284
+
285
+ mapChainExpression(nodeUnprocessed) {
286
+ /*
287
+ NOTE - In the below comments `MemberExpression` and `CallExpression`
288
+ are completely interchangable. For terseness we just reference
289
+ one each time.
290
+ */
291
+
292
+ /*
293
+ Hermes uses the old babel-style AST:
294
+ ```
295
+ (one?.two).three?.four;
296
+ ^^^^^^^^^^^^^^^^^^^^^^ OptionalMemberExpression
297
+ ^^^^^^^^^^^^^^^^ MemberExpression
298
+ ^^^^^^^^ OptionalMemberExpression
299
+ ```
300
+ We need to convert it to the ESTree representation:
301
+ ```
302
+ (one?.two).three?.four;
303
+ ^^^^^^^^^^^^^^^^^^^^^^ ChainExpression
304
+ ^^^^^^^^^^^^^^^^^^^^^^ MemberExpression[optional = true]
305
+ ^^^^^^^^^^^^^^^^ MemberExpression[optional = false]
306
+ ^^^^^^^^ ChainExpression
307
+ ^^^^^^^^ MemberExpression[optional = true]
308
+ ```
309
+ We do this by converting the AST and its children (depth first), and then unwrapping
310
+ the resulting AST as appropriate.
311
+ Put another way:
312
+ 1) traverse to the leaf
313
+ 2) if the current node is an `OptionalMemberExpression`:
314
+ a) if the `.object` is a `ChainExpression`:
315
+ i) unwrap the child (`node.object = child.expression`)
316
+ b) convert this node to a `MemberExpression[optional = true]`
317
+ c) wrap this node (`node = ChainExpression[expression = node]`)
318
+ 3) if the current node is a `MembedExpression`:
319
+ a) convert this node to a `MemberExpression[optional = true]`
320
+ */
321
+ const node = this.mapNodeDefault(nodeUnprocessed);
322
+
323
+ const {
324
+ child,
325
+ childKey,
326
+ isOptional
327
+ } = (() => {
328
+ const isOptional = node.optional === true;
329
+
330
+ if (node.type.endsWith('MemberExpression')) {
331
+ return {
332
+ child: node.object,
333
+ childKey: 'object',
334
+ isOptional
335
+ };
336
+ } else if (node.type.endsWith('CallExpression')) {
337
+ return {
338
+ child: node.callee,
339
+ childKey: 'callee',
340
+ isOptional
341
+ };
342
+ } else {
343
+ return {
344
+ child: node.expression,
345
+ childKey: 'expression',
346
+ isOptional: false
347
+ };
158
348
  }
349
+ })();
350
+
351
+ const isChildUnwrappable = child.type === 'ChainExpression' && // (x?.y).z is semantically different to `x?.y.z`.
352
+ // In the un-parenthesised case `.z` is only executed if and only if `x?.y` returns a non-nullish value.
353
+ // In the parenthesised case, `.z` is **always** executed, regardless of the return of `x?.y`.
354
+ // As such the AST is different between the two cases.
355
+ //
356
+ // In the hermes AST - any member part of a non-short-circuited optional chain is represented with `OptionalMemberExpression`
357
+ // so if we see a `MemberExpression`, then we know we've hit a parenthesis boundary.
358
+ node.type !== 'MemberExpression' && node.type !== 'CallExpression';
359
+
360
+ if (node.type.startsWith('Optional')) {
361
+ node.type = node.type.replace('Optional', '');
362
+ node.optional = isOptional;
363
+ } else {
364
+ node.optional = false;
365
+ }
159
366
 
160
- return {
161
- type: 'Literal',
162
- loc: node.loc,
163
- range: node.range,
164
- value: value,
165
- raw: this.code.slice(node.range[0], node.range[1]),
166
- regex: {
167
- pattern: pattern,
168
- flags: flags
169
- }
170
- };
367
+ if (!isChildUnwrappable && !isOptional) {
368
+ return node;
171
369
  }
172
- }, {
173
- key: "mapTemplateElement",
174
- value: function mapTemplateElement(node) {
175
- return {
176
- type: 'TemplateElement',
177
- loc: node.loc,
178
- range: node.range,
179
- tail: node.tail,
180
- value: {
181
- cooked: node.cooked,
182
- raw: node.raw
183
- }
184
- };
370
+
371
+ if (isChildUnwrappable) {
372
+ const newChild = child.expression;
373
+ node[childKey] = newChild;
185
374
  }
186
- }, {
187
- key: "mapGenericTypeAnnotation",
188
- value: function mapGenericTypeAnnotation(node) {
189
- // Convert simple `this` generic type to ThisTypeAnnotation
190
- if (node.typeParameters === null && node.id.type === 'Identifier' && node.id.name === 'this') {
375
+
376
+ return {
377
+ type: 'ChainExpression',
378
+ expression: node,
379
+ loc: node.loc,
380
+ range: node.range
381
+ };
382
+ }
383
+
384
+ mapClassProperty(nodeUnprocessed) {
385
+ const node = this.mapNodeDefault(nodeUnprocessed);
386
+
387
+ const key = (() => {
388
+ if (node.type === 'ClassPrivateProperty') {
389
+ const key = this.mapNodeDefault(node.key);
191
390
  return {
192
- type: 'ThisTypeAnnotation',
193
- loc: node.loc,
194
- range: node.range
391
+ type: 'PrivateIdentifier',
392
+ name: key.name,
393
+ range: key.range,
394
+ loc: key.loc
195
395
  };
196
396
  }
197
397
 
198
- return this.mapNodeDefault(node);
199
- }
200
- }, {
201
- key: "mapComment",
202
- value: function mapComment(node) {
203
- if (node.type === 'CommentBlock') {
204
- node.type = 'Block';
205
- } else if (node.type === 'CommentLine') {
206
- node.type = 'Line';
398
+ return node.key;
399
+ })();
400
+
401
+ return { ...node,
402
+ computed: node.type === 'ClassPrivateProperty' ? false : node.computed,
403
+ key,
404
+ type: 'PropertyDefinition'
405
+ };
406
+ }
407
+
408
+ mapPrivateName(node) {
409
+ return {
410
+ type: 'PrivateIdentifier',
411
+ name: node.id.name,
412
+ // estree the location refers to the entire string including the hash token
413
+ range: node.range,
414
+ loc: node.loc
415
+ };
416
+ }
417
+
418
+ mapExportNamedDeclaration(nodeUnprocessed) {
419
+ const node = super.mapExportNamedDeclaration(nodeUnprocessed);
420
+ const namespaceSpecifier = node.specifiers.find(spec => spec.type === 'ExportNamespaceSpecifier');
421
+
422
+ if (namespaceSpecifier != null) {
423
+ var _node$exportKind;
424
+
425
+ if (node.specifiers.length !== 1) {
426
+ // this should already a hermes parser error - but let's be absolutely sure we're aligned with the spec
427
+ throw new Error('Cannot use an export all with any other specifiers');
207
428
  }
208
429
 
209
- return node;
430
+ return {
431
+ type: 'ExportAllDeclaration',
432
+ source: node.source,
433
+ exportKind: (_node$exportKind = node.exportKind) != null ? _node$exportKind : 'value',
434
+ exported: namespaceSpecifier.exported,
435
+ range: node.range,
436
+ loc: node.loc
437
+ };
210
438
  }
211
- }]);
212
439
 
213
- return HermesToESTreeAdapter;
214
- }(_HermesASTAdapter2["default"]);
440
+ return node;
441
+ }
442
+
443
+ mapExportAllDeclaration(nodeUnprocessed) {
444
+ var _node$exported;
445
+
446
+ const node = super.mapExportAllDeclaration(nodeUnprocessed);
447
+ node.exported = (_node$exported = node.exported) != null ? _node$exported : null;
448
+ return node;
449
+ }
450
+
451
+ }
215
452
 
216
- exports["default"] = HermesToESTreeAdapter;
453
+ exports.default = HermesToESTreeAdapter;