hermes-parser 0.32.1 → 0.33.1

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.
Files changed (36) hide show
  1. package/dist/HermesParser.js +2 -2
  2. package/dist/HermesParser.js.flow +2 -0
  3. package/dist/HermesParserNodeDeserializers.js +109 -5
  4. package/dist/HermesParserWASM.js +1 -1
  5. package/dist/HermesParserWASM.js.flow +11 -1
  6. package/dist/ParserOptions.js +1 -1
  7. package/dist/ParserOptions.js.flow +2 -0
  8. package/dist/babel/TransformESTreeToBabel.js +76 -3
  9. package/dist/babel/TransformESTreeToBabel.js.flow +73 -2
  10. package/dist/estree/StripFlowTypes.js +1 -1
  11. package/dist/estree/StripFlowTypes.js.flow +1 -1
  12. package/dist/estree/TransformMatchSyntax.js +124 -56
  13. package/dist/estree/TransformMatchSyntax.js.flow +124 -46
  14. package/dist/estree/TransformRecordSyntax.js +294 -0
  15. package/dist/estree/TransformRecordSyntax.js.flow +308 -0
  16. package/dist/generated/ESTreeVisitorKeys.js +16 -4
  17. package/dist/generated/ParserVisitorKeys.js +45 -4
  18. package/dist/index.js +8 -1
  19. package/dist/index.js.flow +7 -0
  20. package/dist/src/HermesParser.js +2 -2
  21. package/dist/src/HermesParserNodeDeserializers.js +109 -5
  22. package/dist/src/ParserOptions.js +1 -1
  23. package/dist/src/babel/TransformESTreeToBabel.js +76 -3
  24. package/dist/src/estree/StripFlowTypes.js +1 -1
  25. package/dist/src/estree/TransformMatchSyntax.js +124 -56
  26. package/dist/src/estree/TransformRecordSyntax.js +294 -0
  27. package/dist/src/generated/ESTreeVisitorKeys.js +16 -4
  28. package/dist/src/generated/ParserVisitorKeys.js +45 -4
  29. package/dist/src/index.js +8 -1
  30. package/dist/src/utils/GenID.js +28 -23
  31. package/dist/src/utils/isReservedWord.js +62 -0
  32. package/dist/utils/GenID.js +28 -23
  33. package/dist/utils/GenID.js.flow +23 -22
  34. package/dist/utils/isReservedWord.js +62 -0
  35. package/dist/utils/isReservedWord.js.flow +57 -0
  36. package/package.json +2 -2
@@ -24,8 +24,11 @@ import type {
24
24
  Identifier,
25
25
  Literal,
26
26
  MatchExpression,
27
+ MatchIdentifierPattern,
27
28
  MatchMemberPattern,
29
+ MatchObjectPatternProperty,
28
30
  MatchPattern,
31
+ MatchRestPattern,
29
32
  MatchStatement,
30
33
  MemberExpression,
31
34
  ObjectPattern,
@@ -57,18 +60,18 @@ import {
57
60
  typeofExpression,
58
61
  variableDeclaration,
59
62
  } from '../utils/Builders';
60
- import {createGenID} from '../utils/GenID';
63
+ import GenID from '../utils/GenID';
61
64
 
62
65
  /**
63
66
  * Generated identifiers.
64
67
  * `GenID` is initialized in the transform.
65
68
  */
66
- let GenID: ?ReturnType<typeof createGenID> = null;
69
+ let genID: GenID | null = null;
67
70
  function genIdent(): Identifier {
68
- if (GenID == null) {
71
+ if (genID == null) {
69
72
  throw Error('GenID must be initialized at the start of the transform.');
70
73
  }
71
- return ident(GenID.genID());
74
+ return ident(genID.id());
72
75
  }
73
76
 
74
77
  /**
@@ -86,6 +89,7 @@ type Condition =
86
89
  | {type: 'is-nan', key: Key}
87
90
  | {type: 'array', key: Key, length: number, lengthOp: 'eq' | 'gte'}
88
91
  | {type: 'object', key: Key}
92
+ | {type: 'instanceof', key: Key, constructor: Expression}
89
93
  | {type: 'prop-exists', key: Key, propName: string}
90
94
  | {type: 'or', orConditions: Array<Array<Condition>>};
91
95
 
@@ -194,6 +198,7 @@ function needsPropExistsCond(pattern: MatchPattern): boolean {
194
198
  case 'MatchLiteralPattern':
195
199
  case 'MatchUnaryPattern':
196
200
  case 'MatchObjectPattern':
201
+ case 'MatchInstancePattern':
197
202
  case 'MatchArrayPattern':
198
203
  return false;
199
204
  case 'MatchAsPattern': {
@@ -207,6 +212,74 @@ function needsPropExistsCond(pattern: MatchPattern): boolean {
207
212
  }
208
213
  }
209
214
 
215
+ /**
216
+ * Analyzes properties of both object patterns and instance patterns.
217
+ */
218
+ function analyzeProperties(
219
+ key: Key,
220
+ pattern: MatchPattern,
221
+ seenBindingNames: Set<string>,
222
+ properties: ReadonlyArray<MatchObjectPatternProperty>,
223
+ rest: MatchRestPattern | null,
224
+ ): {
225
+ conditions: Array<Condition>,
226
+ bindings: Array<Binding>,
227
+ } {
228
+ const conditions: Array<Condition> = [];
229
+ const bindings: Array<Binding> = [];
230
+ const objKeys: Array<Identifier | Literal> = [];
231
+ const seenNames = new Set<string>();
232
+
233
+ properties.forEach(prop => {
234
+ const {key: objKey, pattern: propPattern} = prop;
235
+ objKeys.push(objKey);
236
+ const name = objKeyToString(objKey);
237
+ if (seenNames.has(name)) {
238
+ throw createSyntaxError(
239
+ propPattern,
240
+ `Duplicate property name '${name}' in match object pattern.`,
241
+ );
242
+ }
243
+ seenNames.add(name);
244
+ const propKey: Key = key.concat(objKey);
245
+ if (needsPropExistsCond(propPattern)) {
246
+ conditions.push({
247
+ type: 'prop-exists',
248
+ key,
249
+ propName: name,
250
+ });
251
+ }
252
+ const {conditions: childConditions, bindings: childBindings} =
253
+ analyzePattern(propPattern, propKey, seenBindingNames);
254
+ conditions.push(...childConditions);
255
+ bindings.push(...childBindings);
256
+ });
257
+ if (rest != null && rest.argument != null) {
258
+ const {id, kind} = rest.argument;
259
+ checkDuplicateBindingName(seenBindingNames, rest.argument, id.name);
260
+ checkBindingKind(pattern, kind);
261
+ bindings.push({
262
+ type: 'object-rest',
263
+ key,
264
+ exclude: objKeys,
265
+ kind,
266
+ id,
267
+ });
268
+ }
269
+ return {conditions, bindings};
270
+ }
271
+
272
+ function constructorExpression(
273
+ constructor: MatchIdentifierPattern | MatchMemberPattern,
274
+ ): Expression {
275
+ switch (constructor.type) {
276
+ case 'MatchIdentifierPattern':
277
+ return constructor.id;
278
+ case 'MatchMemberPattern':
279
+ return convertMemberPattern(constructor);
280
+ }
281
+ }
282
+
210
283
  /**
211
284
  * Analyzes a match pattern, and produced both the conditions and bindings
212
285
  * produced by that pattern.
@@ -317,46 +390,39 @@ function analyzePattern(
317
390
  }
318
391
  case 'MatchObjectPattern': {
319
392
  const {properties, rest} = pattern;
320
- const conditions: Array<Condition> = [{type: 'object', key}];
321
- const bindings: Array<Binding> = [];
322
- const objKeys: Array<Identifier | Literal> = [];
323
- const seenNames = new Set<string>();
324
- properties.forEach(prop => {
325
- const {key: objKey, pattern: propPattern} = prop;
326
- objKeys.push(objKey);
327
- const name = objKeyToString(objKey);
328
- if (seenNames.has(name)) {
329
- throw createSyntaxError(
330
- propPattern,
331
- `Duplicate property name '${name}' in match object pattern.`,
332
- );
333
- }
334
- seenNames.add(name);
335
- const propKey: Key = key.concat(objKey);
336
- if (needsPropExistsCond(propPattern)) {
337
- conditions.push({
338
- type: 'prop-exists',
339
- key,
340
- propName: name,
341
- });
342
- }
343
- const {conditions: childConditions, bindings: childBindings} =
344
- analyzePattern(propPattern, propKey, seenBindingNames);
345
- conditions.push(...childConditions);
346
- bindings.push(...childBindings);
347
- });
348
- if (rest != null && rest.argument != null) {
349
- const {id, kind} = rest.argument;
350
- checkDuplicateBindingName(seenBindingNames, rest.argument, id.name);
351
- checkBindingKind(pattern, kind);
352
- bindings.push({
353
- type: 'object-rest',
393
+ const {conditions: propertyConditions, bindings} = analyzeProperties(
394
+ key,
395
+ pattern,
396
+ seenBindingNames,
397
+ properties,
398
+ rest,
399
+ );
400
+ const conditions: Array<Condition> = [
401
+ {type: 'object', key},
402
+ ...propertyConditions,
403
+ ];
404
+ return {conditions, bindings};
405
+ }
406
+ case 'MatchInstancePattern': {
407
+ const {
408
+ targetConstructor,
409
+ properties: {properties, rest},
410
+ } = pattern;
411
+ const {conditions: propertyConditions, bindings} = analyzeProperties(
412
+ key,
413
+ pattern,
414
+ seenBindingNames,
415
+ properties,
416
+ rest,
417
+ );
418
+ const conditions: Array<Condition> = [
419
+ {
420
+ type: 'instanceof',
354
421
  key,
355
- exclude: objKeys,
356
- kind,
357
- id,
358
- });
359
- }
422
+ constructor: constructorExpression(targetConstructor),
423
+ },
424
+ ...propertyConditions,
425
+ ];
360
426
  return {conditions, bindings};
361
427
  }
362
428
  case 'MatchOrPattern': {
@@ -499,6 +565,18 @@ function testsOfCondition(
499
565
  disjunction([conjunction([typeofObject, notNull]), typeofFunction]),
500
566
  ];
501
567
  }
568
+ case 'instanceof': {
569
+ const {key, constructor} = condition;
570
+ return [
571
+ {
572
+ type: 'BinaryExpression',
573
+ left: expressionOfKey(root, key),
574
+ right: constructor,
575
+ operator: 'instanceof',
576
+ ...etc(),
577
+ },
578
+ ];
579
+ }
502
580
  case 'prop-exists': {
503
581
  // <propName> in <x>
504
582
  const {key, propName} = condition;
@@ -881,7 +959,7 @@ export function transformProgram(
881
959
  ): Program {
882
960
  // Initialize so each file transformed starts freshly incrementing the
883
961
  // variable name counter, and has its own usage tracking.
884
- GenID = createGenID('m');
962
+ genID = new GenID('m');
885
963
  return SimpleTransform.transformProgram(program, {
886
964
  transform(node: ESNode) {
887
965
  switch (node.type) {
@@ -895,12 +973,12 @@ export function transformProgram(
895
973
  // A rudimentary check to avoid some collisions with our generated
896
974
  // variable names. Ideally, we would have access a scope analyzer
897
975
  // inside the transform instead.
898
- if (GenID == null) {
976
+ if (genID == null) {
899
977
  throw Error(
900
978
  'GenID must be initialized at the start of the transform.',
901
979
  );
902
980
  }
903
- GenID.addUsage(node.name);
981
+ genID.addUsage(node.name);
904
982
  return node;
905
983
  }
906
984
  default: {
@@ -0,0 +1,294 @@
1
+ /**
2
+ * Copyright (c) Meta Platforms, Inc. and 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
+ * Transform record declarations.
13
+ */
14
+
15
+ Object.defineProperty(exports, "__esModule", {
16
+ value: true
17
+ });
18
+ exports.transformProgram = transformProgram;
19
+
20
+ var _hermesEstree = require("hermes-estree");
21
+
22
+ var _SimpleTransform = require("../transform/SimpleTransform");
23
+
24
+ var _astNodeMutationHelpers = require("../transform/astNodeMutationHelpers");
25
+
26
+ var _Builders = require("../utils/Builders");
27
+
28
+ var _isReservedWord = _interopRequireDefault(require("../utils/isReservedWord"));
29
+
30
+ var _GenID = _interopRequireDefault(require("../utils/GenID"));
31
+
32
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
33
+
34
+ function nameOfKey(key) {
35
+ switch (key.type) {
36
+ case 'Identifier':
37
+ return key.name;
38
+
39
+ case 'Literal':
40
+ if ((0, _hermesEstree.isBigIntLiteral)(key)) {
41
+ return key.bigint;
42
+ }
43
+
44
+ return String(key.value);
45
+ }
46
+ }
47
+
48
+ function mapRecordDeclaration(genID, node) {
49
+ const ownProperties = [];
50
+ const staticProperties = [];
51
+ const methods = [];
52
+ const staticMethods = [];
53
+
54
+ for (const element of node.body.elements) {
55
+ switch (element.type) {
56
+ case 'RecordDeclarationProperty':
57
+ ownProperties.push(element);
58
+ break;
59
+
60
+ case 'RecordDeclarationStaticProperty':
61
+ staticProperties.push(element);
62
+ break;
63
+
64
+ case 'MethodDefinition':
65
+ if (element.static) {
66
+ staticMethods.push(element);
67
+ } else {
68
+ methods.push(element);
69
+ }
70
+
71
+ break;
72
+ }
73
+ }
74
+
75
+ const reservedPropNames = new Map(); // Create constructor parameter as an object pattern with all properties
76
+
77
+ const constructorParam = {
78
+ type: 'ObjectPattern',
79
+ properties: ownProperties.map(prop => {
80
+ const {
81
+ key,
82
+ defaultValue
83
+ } = prop;
84
+ const keyName = nameOfKey(key);
85
+
86
+ const getValue = bindingIdent => defaultValue != null ? {
87
+ type: 'AssignmentPattern',
88
+ left: bindingIdent,
89
+ right: (0, _astNodeMutationHelpers.deepCloneNode)(defaultValue),
90
+ ...(0, _Builders.etc)()
91
+ } : bindingIdent;
92
+
93
+ switch (key.type) {
94
+ case 'Identifier':
95
+ {
96
+ const needsNewBinding = (0, _isReservedWord.default)(keyName);
97
+ const bindingName = needsNewBinding ? genID.id() : keyName;
98
+ const bindingIdent = (0, _Builders.ident)(bindingName);
99
+
100
+ if (needsNewBinding) {
101
+ reservedPropNames.set(keyName, bindingName);
102
+ }
103
+
104
+ if (needsNewBinding) {
105
+ return {
106
+ type: 'Property',
107
+ kind: 'init',
108
+ key: (0, _astNodeMutationHelpers.shallowCloneNode)(key),
109
+ value: getValue(bindingIdent),
110
+ shorthand: false,
111
+ method: false,
112
+ computed: false,
113
+ ...(0, _Builders.etc)(),
114
+ parent: _Builders.EMPTY_PARENT
115
+ };
116
+ } else {
117
+ return {
118
+ type: 'Property',
119
+ kind: 'init',
120
+ key: (0, _astNodeMutationHelpers.shallowCloneNode)(key),
121
+ value: getValue(bindingIdent),
122
+ shorthand: true,
123
+ method: false,
124
+ computed: false,
125
+ ...(0, _Builders.etc)(),
126
+ parent: _Builders.EMPTY_PARENT
127
+ };
128
+ }
129
+ }
130
+
131
+ case 'Literal':
132
+ {
133
+ const bindingName = genID.id();
134
+ const bindingIdent = (0, _Builders.ident)(bindingName);
135
+ reservedPropNames.set(keyName, bindingName);
136
+ return {
137
+ type: 'Property',
138
+ kind: 'init',
139
+ key: (0, _astNodeMutationHelpers.shallowCloneNode)(key),
140
+ value: getValue(bindingIdent),
141
+ shorthand: false,
142
+ method: false,
143
+ computed: false,
144
+ ...(0, _Builders.etc)(),
145
+ parent: _Builders.EMPTY_PARENT
146
+ };
147
+ }
148
+ }
149
+ }),
150
+ typeAnnotation: null,
151
+ ...(0, _Builders.etc)()
152
+ }; // Create the constructor method
153
+
154
+ const constructor = {
155
+ type: 'MethodDefinition',
156
+ key: (0, _Builders.ident)('constructor'),
157
+ kind: 'constructor',
158
+ computed: false,
159
+ static: false,
160
+ value: {
161
+ type: 'FunctionExpression',
162
+ id: null,
163
+ params: [constructorParam],
164
+ body: {
165
+ type: 'BlockStatement',
166
+ body: ownProperties.map(({
167
+ key
168
+ }) => {
169
+ var _reservedPropNames$ge;
170
+
171
+ const keyName = nameOfKey(key);
172
+ const bindingIdent = (0, _Builders.ident)((_reservedPropNames$ge = reservedPropNames.get(keyName)) != null ? _reservedPropNames$ge : keyName);
173
+ const object = {
174
+ type: 'ThisExpression',
175
+ ...(0, _Builders.etc)()
176
+ };
177
+ const memberExpression = key.type === 'Identifier' ? {
178
+ type: 'MemberExpression',
179
+ object,
180
+ property: (0, _astNodeMutationHelpers.shallowCloneNode)(key),
181
+ computed: false,
182
+ optional: false,
183
+ ...(0, _Builders.etc)()
184
+ } : {
185
+ type: 'MemberExpression',
186
+ object,
187
+ property: (0, _astNodeMutationHelpers.shallowCloneNode)(key),
188
+ computed: true,
189
+ optional: false,
190
+ ...(0, _Builders.etc)()
191
+ };
192
+ return {
193
+ type: 'ExpressionStatement',
194
+ expression: {
195
+ type: 'AssignmentExpression',
196
+ operator: '=',
197
+ left: memberExpression,
198
+ right: bindingIdent,
199
+ ...(0, _Builders.etc)()
200
+ },
201
+ directive: null,
202
+ ...(0, _Builders.etc)()
203
+ };
204
+ }),
205
+ ...(0, _Builders.etc)()
206
+ },
207
+ generator: false,
208
+ async: false,
209
+ predicate: null,
210
+ returnType: null,
211
+ typeParameters: null,
212
+ ...(0, _Builders.etc)()
213
+ },
214
+ ...(0, _Builders.etc)(),
215
+ parent: _Builders.EMPTY_PARENT
216
+ };
217
+ const classStaticProperties = staticProperties.map(prop => ({
218
+ type: 'PropertyDefinition',
219
+ key: (0, _astNodeMutationHelpers.shallowCloneNode)(prop.key),
220
+ value: (0, _astNodeMutationHelpers.deepCloneNode)(prop.value),
221
+ static: true,
222
+ typeAnnotation: null,
223
+ variance: null,
224
+ computed: false,
225
+ declare: false,
226
+ optional: false,
227
+ ...(0, _Builders.etc)(),
228
+ parent: _Builders.EMPTY_PARENT
229
+ }));
230
+ const classBodyElements = [constructor, ...methods, ...classStaticProperties, ...staticMethods];
231
+ return {
232
+ type: 'ClassDeclaration',
233
+ id: (0, _astNodeMutationHelpers.shallowCloneNode)(node.id),
234
+ body: {
235
+ type: 'ClassBody',
236
+ body: classBodyElements,
237
+ ...(0, _Builders.etc)(),
238
+ parent: _Builders.EMPTY_PARENT
239
+ },
240
+ superClass: null,
241
+ typeParameters: null,
242
+ superTypeArguments: null,
243
+ implements: [],
244
+ decorators: [],
245
+ ...(0, _Builders.etc)()
246
+ };
247
+ }
248
+
249
+ function mapRecordExpression(node) {
250
+ const obj = {
251
+ type: 'ObjectExpression',
252
+ properties: node.properties.properties,
253
+ ...(0, _Builders.etc)()
254
+ };
255
+ return {
256
+ type: 'NewExpression',
257
+ callee: node.recordConstructor,
258
+ arguments: [obj],
259
+ typeArguments: null,
260
+ ...(0, _Builders.etc)()
261
+ };
262
+ }
263
+
264
+ function transformProgram(program, _options) {
265
+ const genID = new _GenID.default('r');
266
+ return _SimpleTransform.SimpleTransform.transformProgram(program, {
267
+ transform(node) {
268
+ switch (node.type) {
269
+ case 'RecordDeclaration':
270
+ {
271
+ return mapRecordDeclaration(genID, node);
272
+ }
273
+
274
+ case 'RecordExpression':
275
+ {
276
+ return mapRecordExpression(node);
277
+ }
278
+
279
+ case 'Identifier':
280
+ {
281
+ // A rudimentary check to avoid some collisions with our generated
282
+ // variable names. Ideally, we would have access a scope analyzer
283
+ // inside the transform instead.
284
+ genID.addUsage(node.name);
285
+ return node;
286
+ }
287
+
288
+ default:
289
+ return node;
290
+ }
291
+ }
292
+
293
+ });
294
+ }