@ohos-ports/hermes-parser 0.37.0-beta.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.
Files changed (90) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +15 -0
  3. package/dist/HermesAST.js.flow +57 -0
  4. package/dist/HermesASTAdapter.js +192 -0
  5. package/dist/HermesASTAdapter.js.flow +189 -0
  6. package/dist/HermesParser.js +108 -0
  7. package/dist/HermesParser.js.flow +163 -0
  8. package/dist/HermesParserDecodeUTF8String.js +68 -0
  9. package/dist/HermesParserDecodeUTF8String.js.flow +65 -0
  10. package/dist/HermesParserDeserializer.js +242 -0
  11. package/dist/HermesParserDeserializer.js.flow +260 -0
  12. package/dist/HermesParserNodeDeserializers.js +2594 -0
  13. package/dist/HermesParserNodeDeserializers.js.flow +16 -0
  14. package/dist/HermesParserWASM.js +6 -0
  15. package/dist/HermesParserWASM.js.flow +97 -0
  16. package/dist/HermesToESTreeAdapter.js +441 -0
  17. package/dist/HermesToESTreeAdapter.js.flow +423 -0
  18. package/dist/ParserOptions.js +20 -0
  19. package/dist/ParserOptions.js.flow +44 -0
  20. package/dist/babel/TransformESTreeToBabel.js +1197 -0
  21. package/dist/babel/TransformESTreeToBabel.js.flow +1349 -0
  22. package/dist/estree/StripFlowTypes.js +175 -0
  23. package/dist/estree/StripFlowTypes.js.flow +158 -0
  24. package/dist/estree/StripFlowTypesForBabel.js +215 -0
  25. package/dist/estree/StripFlowTypesForBabel.js.flow +216 -0
  26. package/dist/estree/TransformComponentSyntax.js +792 -0
  27. package/dist/estree/TransformComponentSyntax.js.flow +864 -0
  28. package/dist/estree/TransformEnumSyntax.js +106 -0
  29. package/dist/estree/TransformEnumSyntax.js.flow +125 -0
  30. package/dist/estree/TransformMatchSyntax.js +1083 -0
  31. package/dist/estree/TransformMatchSyntax.js.flow +991 -0
  32. package/dist/estree/TransformRecordSyntax.js +296 -0
  33. package/dist/estree/TransformRecordSyntax.js.flow +310 -0
  34. package/dist/generated/ESTreeVisitorKeys.js +233 -0
  35. package/dist/generated/ESTreeVisitorKeys.js.flow +15 -0
  36. package/dist/generated/ParserVisitorKeys.js +842 -0
  37. package/dist/generated/ParserVisitorKeys.js.flow +17 -0
  38. package/dist/getModuleDocblock.js +112 -0
  39. package/dist/getModuleDocblock.js.flow +118 -0
  40. package/dist/index.js +170 -0
  41. package/dist/index.js.flow +131 -0
  42. package/dist/src/HermesASTAdapter.js +192 -0
  43. package/dist/src/HermesParser.js +108 -0
  44. package/dist/src/HermesParserDecodeUTF8String.js +68 -0
  45. package/dist/src/HermesParserDeserializer.js +242 -0
  46. package/dist/src/HermesParserNodeDeserializers.js +2594 -0
  47. package/dist/src/HermesToESTreeAdapter.js +441 -0
  48. package/dist/src/ParserOptions.js +20 -0
  49. package/dist/src/babel/TransformESTreeToBabel.js +1197 -0
  50. package/dist/src/estree/StripFlowTypes.js +175 -0
  51. package/dist/src/estree/StripFlowTypesForBabel.js +215 -0
  52. package/dist/src/estree/TransformComponentSyntax.js +792 -0
  53. package/dist/src/estree/TransformEnumSyntax.js +106 -0
  54. package/dist/src/estree/TransformMatchSyntax.js +1083 -0
  55. package/dist/src/estree/TransformRecordSyntax.js +296 -0
  56. package/dist/src/generated/ESTreeVisitorKeys.js +233 -0
  57. package/dist/src/generated/ParserVisitorKeys.js +842 -0
  58. package/dist/src/getModuleDocblock.js +112 -0
  59. package/dist/src/index.js +170 -0
  60. package/dist/src/transform/SimpleTransform.js +145 -0
  61. package/dist/src/transform/astArrayMutationHelpers.js +62 -0
  62. package/dist/src/transform/astNodeMutationHelpers.js +201 -0
  63. package/dist/src/traverse/SimpleTraverser.js +139 -0
  64. package/dist/src/traverse/getVisitorKeys.js +39 -0
  65. package/dist/src/utils/Builders.js +190 -0
  66. package/dist/src/utils/GenID.js +46 -0
  67. package/dist/src/utils/createSyntaxError.js +25 -0
  68. package/dist/src/utils/isReservedWord.js +62 -0
  69. package/dist/src/utils/mutateESTreeASTForPrettier.js +127 -0
  70. package/dist/transform/SimpleTransform.js +145 -0
  71. package/dist/transform/SimpleTransform.js.flow +168 -0
  72. package/dist/transform/astArrayMutationHelpers.js +62 -0
  73. package/dist/transform/astArrayMutationHelpers.js.flow +71 -0
  74. package/dist/transform/astNodeMutationHelpers.js +201 -0
  75. package/dist/transform/astNodeMutationHelpers.js.flow +252 -0
  76. package/dist/traverse/SimpleTraverser.js +139 -0
  77. package/dist/traverse/SimpleTraverser.js.flow +133 -0
  78. package/dist/traverse/getVisitorKeys.js +39 -0
  79. package/dist/traverse/getVisitorKeys.js.flow +38 -0
  80. package/dist/utils/Builders.js +190 -0
  81. package/dist/utils/Builders.js.flow +218 -0
  82. package/dist/utils/GenID.js +46 -0
  83. package/dist/utils/GenID.js.flow +39 -0
  84. package/dist/utils/createSyntaxError.js +25 -0
  85. package/dist/utils/createSyntaxError.js.flow +24 -0
  86. package/dist/utils/isReservedWord.js +62 -0
  87. package/dist/utils/isReservedWord.js.flow +57 -0
  88. package/dist/utils/mutateESTreeASTForPrettier.js +127 -0
  89. package/dist/utils/mutateESTreeASTForPrettier.js.flow +130 -0
  90. package/package.json +30 -0
@@ -0,0 +1,1083 @@
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
+ * strict
8
+ * @format
9
+ */
10
+ 'use strict';
11
+ /**
12
+ * Transform match expressions and statements.
13
+ */
14
+
15
+ Object.defineProperty(exports, "__esModule", {
16
+ value: true
17
+ });
18
+ exports.transformProgram = transformProgram;
19
+
20
+ var _SimpleTransform = require("../transform/SimpleTransform");
21
+
22
+ var _astNodeMutationHelpers = require("../transform/astNodeMutationHelpers");
23
+
24
+ var _createSyntaxError = require("../utils/createSyntaxError");
25
+
26
+ var _Builders = require("../utils/Builders");
27
+
28
+ var _GenID = _interopRequireDefault(require("../utils/GenID"));
29
+
30
+ function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
31
+
32
+ /**
33
+ * Generated identifiers.
34
+ * `GenID` is initialized in the transform.
35
+ */
36
+ let genID = null;
37
+
38
+ function genIdent() {
39
+ if (genID == null) {
40
+ throw Error('GenID must be initialized at the start of the transform.');
41
+ }
42
+
43
+ return (0, _Builders.ident)(genID.id());
44
+ }
45
+ /**
46
+ * A series of properties.
47
+ * When combined with the match argument (the root expression), provides the
48
+ * location of to be tested against, or location to be extracted to a binding.
49
+ */
50
+
51
+ /**
52
+ * The conditional aspect of a match pattern for a single location.
53
+ */
54
+
55
+ /**
56
+ * A binding introduced by a match pattern.
57
+ */
58
+
59
+
60
+ function objKeyToString(node) {
61
+ switch (node.type) {
62
+ case 'Identifier':
63
+ return node.name;
64
+
65
+ case 'Literal':
66
+ {
67
+ const {
68
+ value
69
+ } = node;
70
+
71
+ if (typeof value === 'number') {
72
+ return String(value);
73
+ } else if (typeof value === 'string') {
74
+ return value;
75
+ } else {
76
+ return node.raw;
77
+ }
78
+ }
79
+ }
80
+ }
81
+
82
+ function convertMemberPattern(pattern) {
83
+ const {
84
+ base,
85
+ property,
86
+ loc,
87
+ range
88
+ } = pattern;
89
+ const object = base.type === 'MatchIdentifierPattern' ? base.id : convertMemberPattern(base);
90
+
91
+ if (property.type === 'Identifier') {
92
+ return {
93
+ type: 'MemberExpression',
94
+ object,
95
+ property,
96
+ computed: false,
97
+ optional: false,
98
+ ...(0, _Builders.etc)({
99
+ loc,
100
+ range
101
+ })
102
+ };
103
+ } else {
104
+ return {
105
+ type: 'MemberExpression',
106
+ object,
107
+ property,
108
+ computed: true,
109
+ optional: false,
110
+ ...(0, _Builders.etc)({
111
+ loc,
112
+ range
113
+ })
114
+ };
115
+ }
116
+ }
117
+
118
+ function checkDuplicateBindingName(seenBindingNames, node, name) {
119
+ if (seenBindingNames.has(name)) {
120
+ throw (0, _createSyntaxError.createSyntaxError)(node, `Duplicate variable name '${name}' in match case pattern.`);
121
+ }
122
+
123
+ seenBindingNames.add(name);
124
+ }
125
+
126
+ function checkBindingKind(node, kind) {
127
+ if (kind === 'var') {
128
+ throw (0, _createSyntaxError.createSyntaxError)(node, `'var' bindings are not allowed. Use 'const' or 'let'.`);
129
+ }
130
+ }
131
+ /**
132
+ * Does an object property's pattern require a `prop-exists` condition added?
133
+ * If the pattern is a literal like `0`, then it's not required, since the `eq`
134
+ * condition implies the prop exists. However, if we could be doing an equality
135
+ * check against `undefined`, then it is required, since that will be true even
136
+ * if the property doesn't exist.
137
+ */
138
+
139
+
140
+ function needsPropExistsCond(pattern) {
141
+ switch (pattern.type) {
142
+ case 'MatchWildcardPattern':
143
+ case 'MatchBindingPattern':
144
+ case 'MatchIdentifierPattern':
145
+ case 'MatchMemberPattern':
146
+ return true;
147
+
148
+ case 'MatchLiteralPattern':
149
+ case 'MatchUnaryPattern':
150
+ case 'MatchObjectPattern':
151
+ case 'MatchInstancePattern':
152
+ case 'MatchArrayPattern':
153
+ return false;
154
+
155
+ case 'MatchAsPattern':
156
+ {
157
+ const {
158
+ pattern: asPattern
159
+ } = pattern;
160
+ return needsPropExistsCond(asPattern);
161
+ }
162
+
163
+ case 'MatchOrPattern':
164
+ {
165
+ const {
166
+ patterns
167
+ } = pattern;
168
+ return patterns.some(needsPropExistsCond);
169
+ }
170
+ }
171
+ }
172
+ /**
173
+ * Analyzes properties of both object patterns and instance patterns.
174
+ */
175
+
176
+
177
+ function analyzeProperties(key, pattern, seenBindingNames, properties, rest) {
178
+ const conditions = [];
179
+ const bindings = [];
180
+ const objKeys = [];
181
+ const seenNames = new Set();
182
+ properties.forEach(prop => {
183
+ const {
184
+ key: objKey,
185
+ pattern: propPattern
186
+ } = prop;
187
+ objKeys.push(objKey);
188
+ const name = objKeyToString(objKey);
189
+
190
+ if (seenNames.has(name)) {
191
+ throw (0, _createSyntaxError.createSyntaxError)(propPattern, `Duplicate property name '${name}' in match object pattern.`);
192
+ }
193
+
194
+ seenNames.add(name);
195
+ const propKey = key.concat(objKey);
196
+
197
+ if (needsPropExistsCond(propPattern)) {
198
+ conditions.push({
199
+ type: 'prop-exists',
200
+ key,
201
+ propName: name
202
+ });
203
+ }
204
+
205
+ const {
206
+ conditions: childConditions,
207
+ bindings: childBindings
208
+ } = analyzePattern(propPattern, propKey, seenBindingNames);
209
+ conditions.push(...childConditions);
210
+ bindings.push(...childBindings);
211
+ });
212
+
213
+ if (rest != null && rest.argument != null) {
214
+ const {
215
+ id,
216
+ kind
217
+ } = rest.argument;
218
+ checkDuplicateBindingName(seenBindingNames, rest.argument, id.name);
219
+ checkBindingKind(pattern, kind);
220
+ bindings.push({
221
+ type: 'object-rest',
222
+ key,
223
+ exclude: objKeys,
224
+ kind,
225
+ id
226
+ });
227
+ }
228
+
229
+ return {
230
+ conditions,
231
+ bindings
232
+ };
233
+ }
234
+
235
+ function constructorExpression(constructor) {
236
+ switch (constructor.type) {
237
+ case 'MatchIdentifierPattern':
238
+ return constructor.id;
239
+
240
+ case 'MatchMemberPattern':
241
+ return convertMemberPattern(constructor);
242
+ }
243
+ }
244
+ /**
245
+ * Analyzes a match pattern, and produced both the conditions and bindings
246
+ * produced by that pattern.
247
+ */
248
+
249
+
250
+ function analyzePattern(pattern, key, seenBindingNames) {
251
+ switch (pattern.type) {
252
+ case 'MatchWildcardPattern':
253
+ {
254
+ return {
255
+ conditions: [],
256
+ bindings: []
257
+ };
258
+ }
259
+
260
+ case 'MatchLiteralPattern':
261
+ {
262
+ const {
263
+ literal
264
+ } = pattern;
265
+ const condition = {
266
+ type: 'eq',
267
+ key,
268
+ arg: literal
269
+ };
270
+ return {
271
+ conditions: [condition],
272
+ bindings: []
273
+ };
274
+ }
275
+
276
+ case 'MatchUnaryPattern':
277
+ {
278
+ const {
279
+ operator,
280
+ argument,
281
+ loc,
282
+ range
283
+ } = pattern;
284
+
285
+ if (argument.value === 0) {
286
+ // We haven't decided whether we will compare these using `===` or `Object.is`
287
+ throw (0, _createSyntaxError.createSyntaxError)(pattern, `'+0' and '-0' are not yet supported in match unary patterns.`);
288
+ }
289
+
290
+ const arg = {
291
+ type: 'UnaryExpression',
292
+ operator,
293
+ argument,
294
+ prefix: true,
295
+ ...(0, _Builders.etc)({
296
+ loc,
297
+ range
298
+ })
299
+ };
300
+ const condition = {
301
+ type: 'eq',
302
+ key,
303
+ arg
304
+ };
305
+ return {
306
+ conditions: [condition],
307
+ bindings: []
308
+ };
309
+ }
310
+
311
+ case 'MatchIdentifierPattern':
312
+ {
313
+ const {
314
+ id
315
+ } = pattern;
316
+ const condition = id.name === 'NaN' ? {
317
+ type: 'is-nan',
318
+ key
319
+ } : {
320
+ type: 'eq',
321
+ key,
322
+ arg: id
323
+ };
324
+ return {
325
+ conditions: [condition],
326
+ bindings: []
327
+ };
328
+ }
329
+
330
+ case 'MatchMemberPattern':
331
+ {
332
+ const arg = convertMemberPattern(pattern);
333
+ const condition = {
334
+ type: 'eq',
335
+ key,
336
+ arg
337
+ };
338
+ return {
339
+ conditions: [condition],
340
+ bindings: []
341
+ };
342
+ }
343
+
344
+ case 'MatchBindingPattern':
345
+ {
346
+ const {
347
+ id,
348
+ kind
349
+ } = pattern;
350
+ checkDuplicateBindingName(seenBindingNames, pattern, id.name);
351
+ checkBindingKind(pattern, kind);
352
+ const binding = {
353
+ type: 'id',
354
+ key,
355
+ kind,
356
+ id
357
+ };
358
+ return {
359
+ conditions: [],
360
+ bindings: [binding]
361
+ };
362
+ }
363
+
364
+ case 'MatchAsPattern':
365
+ {
366
+ const {
367
+ pattern: asPattern,
368
+ target
369
+ } = pattern;
370
+
371
+ if (asPattern.type === 'MatchBindingPattern') {
372
+ throw (0, _createSyntaxError.createSyntaxError)(pattern, `Match 'as' patterns are not allowed directly on binding patterns.`);
373
+ }
374
+
375
+ const {
376
+ conditions,
377
+ bindings
378
+ } = analyzePattern(asPattern, key, seenBindingNames);
379
+ const constKind = 'const';
380
+ const [id, kind] = target.type === 'MatchBindingPattern' ? [target.id, target.kind] : [target, constKind];
381
+ checkDuplicateBindingName(seenBindingNames, pattern, id.name);
382
+ checkBindingKind(pattern, kind);
383
+ const binding = {
384
+ type: 'id',
385
+ key,
386
+ kind,
387
+ id
388
+ };
389
+ return {
390
+ conditions,
391
+ bindings: bindings.concat(binding)
392
+ };
393
+ }
394
+
395
+ case 'MatchArrayPattern':
396
+ {
397
+ const {
398
+ elements,
399
+ rest
400
+ } = pattern;
401
+ const lengthOp = rest == null ? 'eq' : 'gte';
402
+ const conditions = [{
403
+ type: 'array',
404
+ key,
405
+ length: elements.length,
406
+ lengthOp
407
+ }];
408
+ const bindings = [];
409
+ elements.forEach((element, i) => {
410
+ const elementKey = key.concat((0, _Builders.numberLiteral)(i));
411
+ const {
412
+ conditions: childConditions,
413
+ bindings: childBindings
414
+ } = analyzePattern(element, elementKey, seenBindingNames);
415
+ conditions.push(...childConditions);
416
+ bindings.push(...childBindings);
417
+ });
418
+
419
+ if (rest != null && rest.argument != null) {
420
+ const {
421
+ id,
422
+ kind
423
+ } = rest.argument;
424
+ checkDuplicateBindingName(seenBindingNames, rest.argument, id.name);
425
+ checkBindingKind(pattern, kind);
426
+ bindings.push({
427
+ type: 'array-rest',
428
+ key,
429
+ exclude: elements.length,
430
+ kind,
431
+ id
432
+ });
433
+ }
434
+
435
+ return {
436
+ conditions,
437
+ bindings
438
+ };
439
+ }
440
+
441
+ case 'MatchObjectPattern':
442
+ {
443
+ const {
444
+ properties,
445
+ rest
446
+ } = pattern;
447
+ const {
448
+ conditions: propertyConditions,
449
+ bindings
450
+ } = analyzeProperties(key, pattern, seenBindingNames, properties, rest);
451
+ const conditions = [{
452
+ type: 'object',
453
+ key
454
+ }, ...propertyConditions];
455
+ return {
456
+ conditions,
457
+ bindings
458
+ };
459
+ }
460
+
461
+ case 'MatchInstancePattern':
462
+ {
463
+ const {
464
+ targetConstructor,
465
+ properties: {
466
+ properties,
467
+ rest
468
+ }
469
+ } = pattern;
470
+ const {
471
+ conditions: propertyConditions,
472
+ bindings
473
+ } = analyzeProperties(key, pattern, seenBindingNames, properties, rest);
474
+ const conditions = [{
475
+ type: 'instanceof',
476
+ key,
477
+ constructor: constructorExpression(targetConstructor)
478
+ }, ...propertyConditions];
479
+ return {
480
+ conditions,
481
+ bindings
482
+ };
483
+ }
484
+
485
+ case 'MatchOrPattern':
486
+ {
487
+ const {
488
+ patterns
489
+ } = pattern;
490
+ let hasWildcard = false;
491
+ const orConditions = patterns.map(subpattern => {
492
+ const {
493
+ conditions,
494
+ bindings
495
+ } = analyzePattern(subpattern, key, seenBindingNames);
496
+
497
+ if (bindings.length > 0) {
498
+ // We will implement this in the future.
499
+ throw (0, _createSyntaxError.createSyntaxError)(pattern, `Bindings in match 'or' patterns are not yet supported.`);
500
+ }
501
+
502
+ if (conditions.length === 0) {
503
+ hasWildcard = true;
504
+ }
505
+
506
+ return conditions;
507
+ });
508
+
509
+ if (hasWildcard) {
510
+ return {
511
+ conditions: [],
512
+ bindings: []
513
+ };
514
+ }
515
+
516
+ return {
517
+ conditions: [{
518
+ type: 'or',
519
+ orConditions
520
+ }],
521
+ bindings: []
522
+ };
523
+ }
524
+ }
525
+ }
526
+
527
+ function expressionOfKey(root, key) {
528
+ return key.reduce((acc, prop) => prop.type === 'Identifier' ? {
529
+ type: 'MemberExpression',
530
+ object: acc,
531
+ property: (0, _astNodeMutationHelpers.shallowCloneNode)(prop),
532
+ computed: false,
533
+ optional: false,
534
+ ...(0, _Builders.etc)()
535
+ } : {
536
+ type: 'MemberExpression',
537
+ object: acc,
538
+ property: (0, _astNodeMutationHelpers.shallowCloneNode)(prop),
539
+ computed: true,
540
+ optional: false,
541
+ ...(0, _Builders.etc)()
542
+ }, (0, _astNodeMutationHelpers.deepCloneNode)(root));
543
+ }
544
+
545
+ function testsOfCondition(root, condition) {
546
+ switch (condition.type) {
547
+ case 'eq':
548
+ {
549
+ // <x> === <arg>
550
+ const {
551
+ key,
552
+ arg
553
+ } = condition;
554
+ return [{
555
+ type: 'BinaryExpression',
556
+ left: expressionOfKey(root, key),
557
+ right: arg,
558
+ operator: '===',
559
+ ...(0, _Builders.etc)()
560
+ }];
561
+ }
562
+
563
+ case 'is-nan':
564
+ {
565
+ // Number.isNaN(<x>)
566
+ const {
567
+ key
568
+ } = condition;
569
+ const callee = {
570
+ type: 'MemberExpression',
571
+ object: (0, _Builders.ident)('Number'),
572
+ property: (0, _Builders.ident)('isNaN'),
573
+ computed: false,
574
+ optional: false,
575
+ ...(0, _Builders.etc)()
576
+ };
577
+ return [(0, _Builders.callExpression)(callee, [expressionOfKey(root, key)])];
578
+ }
579
+
580
+ case 'array':
581
+ {
582
+ // Array.isArray(<x>) && <x>.length === <length>
583
+ const {
584
+ key,
585
+ length,
586
+ lengthOp
587
+ } = condition;
588
+ const operator = lengthOp === 'eq' ? '===' : '>=';
589
+ const isArray = (0, _Builders.callExpression)({
590
+ type: 'MemberExpression',
591
+ object: (0, _Builders.ident)('Array'),
592
+ property: (0, _Builders.ident)('isArray'),
593
+ computed: false,
594
+ optional: false,
595
+ ...(0, _Builders.etc)()
596
+ }, [expressionOfKey(root, key)]);
597
+ const lengthCheck = {
598
+ type: 'BinaryExpression',
599
+ left: {
600
+ type: 'MemberExpression',
601
+ object: expressionOfKey(root, key),
602
+ property: (0, _Builders.ident)('length'),
603
+ computed: false,
604
+ optional: false,
605
+ ...(0, _Builders.etc)()
606
+ },
607
+ right: (0, _Builders.numberLiteral)(length),
608
+ operator,
609
+ ...(0, _Builders.etc)()
610
+ };
611
+ return [isArray, lengthCheck];
612
+ }
613
+
614
+ case 'object':
615
+ {
616
+ // (typeof <x> === 'object' && <x> !== null) || typeof <x> === 'function'
617
+ const {
618
+ key
619
+ } = condition;
620
+ const typeofObject = (0, _Builders.typeofExpression)(expressionOfKey(root, key), 'object');
621
+ const typeofFunction = (0, _Builders.typeofExpression)(expressionOfKey(root, key), 'function');
622
+ const notNull = {
623
+ type: 'BinaryExpression',
624
+ left: expressionOfKey(root, key),
625
+ right: (0, _Builders.nullLiteral)(),
626
+ operator: '!==',
627
+ ...(0, _Builders.etc)()
628
+ };
629
+ return [(0, _Builders.disjunction)([(0, _Builders.conjunction)([typeofObject, notNull]), typeofFunction])];
630
+ }
631
+
632
+ case 'instanceof':
633
+ {
634
+ const {
635
+ key,
636
+ constructor
637
+ } = condition;
638
+ return [{
639
+ type: 'BinaryExpression',
640
+ left: expressionOfKey(root, key),
641
+ right: constructor,
642
+ operator: 'instanceof',
643
+ ...(0, _Builders.etc)()
644
+ }];
645
+ }
646
+
647
+ case 'prop-exists':
648
+ {
649
+ // <propName> in <x>
650
+ const {
651
+ key,
652
+ propName
653
+ } = condition;
654
+ const inObject = {
655
+ type: 'BinaryExpression',
656
+ left: (0, _Builders.stringLiteral)(propName),
657
+ right: expressionOfKey(root, key),
658
+ operator: 'in',
659
+ ...(0, _Builders.etc)()
660
+ };
661
+ return [inObject];
662
+ }
663
+
664
+ case 'or':
665
+ {
666
+ // <a> || <b> || ...
667
+ const {
668
+ orConditions
669
+ } = condition;
670
+ const tests = orConditions.map(conditions => (0, _Builders.conjunction)(testsOfConditions(root, conditions)));
671
+ return [(0, _Builders.disjunction)(tests)];
672
+ }
673
+ }
674
+ }
675
+
676
+ function testsOfConditions(root, conditions) {
677
+ return conditions.flatMap(condition => testsOfCondition(root, condition));
678
+ }
679
+
680
+ function statementsOfBindings(root, bindings) {
681
+ return bindings.map(binding => {
682
+ switch (binding.type) {
683
+ case 'id':
684
+ {
685
+ // const <id> = <x>;
686
+ const {
687
+ key,
688
+ kind,
689
+ id
690
+ } = binding;
691
+ return (0, _Builders.variableDeclaration)(kind, id, expressionOfKey(root, key));
692
+ }
693
+
694
+ case 'array-rest':
695
+ {
696
+ // const <id> = <x>.slice(<exclude>);
697
+ const {
698
+ key,
699
+ kind,
700
+ id,
701
+ exclude
702
+ } = binding;
703
+ const init = (0, _Builders.callExpression)({
704
+ type: 'MemberExpression',
705
+ object: expressionOfKey(root, key),
706
+ property: (0, _Builders.ident)('slice'),
707
+ computed: false,
708
+ optional: false,
709
+ ...(0, _Builders.etc)()
710
+ }, [(0, _Builders.numberLiteral)(exclude)]);
711
+ return (0, _Builders.variableDeclaration)(kind, id, init);
712
+ }
713
+
714
+ case 'object-rest':
715
+ {
716
+ // const {a: _, b: _, ...<id>} = <x>;
717
+ const {
718
+ key,
719
+ kind,
720
+ id,
721
+ exclude
722
+ } = binding;
723
+ const destructuring = {
724
+ type: 'ObjectPattern',
725
+ properties: exclude.map(prop => prop.type === 'Identifier' ? {
726
+ type: 'Property',
727
+ key: (0, _astNodeMutationHelpers.shallowCloneNode)(prop),
728
+ value: genIdent(),
729
+ kind: 'init',
730
+ computed: false,
731
+ method: false,
732
+ shorthand: false,
733
+ ...(0, _Builders.etc)(),
734
+ parent: _Builders.EMPTY_PARENT
735
+ } : {
736
+ type: 'Property',
737
+ key: (0, _astNodeMutationHelpers.shallowCloneNode)(prop),
738
+ value: genIdent(),
739
+ kind: 'init',
740
+ computed: true,
741
+ method: false,
742
+ shorthand: false,
743
+ ...(0, _Builders.etc)(),
744
+ parent: _Builders.EMPTY_PARENT
745
+ }).concat({
746
+ type: 'RestElement',
747
+ argument: id,
748
+ ...(0, _Builders.etc)()
749
+ }),
750
+ typeAnnotation: null,
751
+ ...(0, _Builders.etc)()
752
+ };
753
+ return (0, _Builders.variableDeclaration)(kind, destructuring, expressionOfKey(root, key));
754
+ }
755
+ }
756
+ });
757
+ }
758
+ /**
759
+ * For throwing an error if no cases are matched.
760
+ */
761
+
762
+
763
+ const fallthroughErrorMsgText = `Match: No case succesfully matched. Make exhaustive or add a wildcard case using '_'.`;
764
+
765
+ function fallthroughErrorMsg(value) {
766
+ return {
767
+ type: 'BinaryExpression',
768
+ operator: '+',
769
+ left: (0, _Builders.stringLiteral)(`${fallthroughErrorMsgText} Argument: `),
770
+ right: value,
771
+ ...(0, _Builders.etc)()
772
+ };
773
+ }
774
+
775
+ function fallthroughError(value) {
776
+ return (0, _Builders.throwStatement)(fallthroughErrorMsg(value));
777
+ }
778
+ /**
779
+ * If the argument has no side-effects (ignoring getters). Either an identifier
780
+ * or member expression with identifier root and non-computed/literal properties.
781
+ */
782
+
783
+
784
+ function calculateSimpleArgument(node) {
785
+ switch (node.type) {
786
+ case 'Identifier':
787
+ case 'Super':
788
+ return true;
789
+
790
+ case 'MemberExpression':
791
+ {
792
+ const {
793
+ object,
794
+ property,
795
+ computed
796
+ } = node;
797
+
798
+ if (computed && property.type !== 'Literal') {
799
+ return false;
800
+ }
801
+
802
+ return calculateSimpleArgument(object);
803
+ }
804
+
805
+ default:
806
+ return false;
807
+ }
808
+ }
809
+ /**
810
+ * Analyze the match cases and return information we will use to build the result.
811
+ */
812
+
813
+
814
+ function analyzeCases(cases) {
815
+ let hasBindings = false;
816
+ let hasWildcard = false;
817
+ const analyses = [];
818
+
819
+ for (let i = 0; i < cases.length; i++) {
820
+ const {
821
+ pattern,
822
+ guard,
823
+ body
824
+ } = cases[i];
825
+ const {
826
+ conditions,
827
+ bindings
828
+ } = analyzePattern(pattern, [], new Set());
829
+ hasBindings = hasBindings || bindings.length > 0;
830
+ analyses.push({
831
+ conditions,
832
+ bindings,
833
+ guard,
834
+ body
835
+ }); // This case catches everything, no reason to continue.
836
+
837
+ if (conditions.length === 0 && guard == null) {
838
+ hasWildcard = true;
839
+ break;
840
+ }
841
+ }
842
+
843
+ return {
844
+ hasBindings,
845
+ hasWildcard,
846
+ analyses
847
+ };
848
+ }
849
+ /**
850
+ * Match expression transform entry point.
851
+ */
852
+
853
+
854
+ function mapMatchExpression(node) {
855
+ const {
856
+ argument,
857
+ cases
858
+ } = node;
859
+ const {
860
+ hasBindings,
861
+ hasWildcard,
862
+ analyses
863
+ } = analyzeCases(cases);
864
+ const isSimpleArgument = !hasBindings && calculateSimpleArgument(argument);
865
+ const genRoot = !isSimpleArgument ? genIdent() : null;
866
+ const root = genRoot == null ? argument : genRoot; // No bindings and a simple argument means we can use nested conditional
867
+ // expressions.
868
+
869
+ if (isSimpleArgument) {
870
+ const wildcardAnalaysis = hasWildcard ? analyses.pop() : null;
871
+ const lastBody = wildcardAnalaysis != null ? wildcardAnalaysis.body : (0, _Builders.iife)([fallthroughError((0, _astNodeMutationHelpers.shallowCloneNode)(root))]);
872
+ return analyses.reverse().reduce((acc, analysis) => {
873
+ const {
874
+ conditions,
875
+ guard,
876
+ body
877
+ } = analysis;
878
+ const tests = testsOfConditions(root, conditions);
879
+
880
+ if (guard != null) {
881
+ tests.push(guard);
882
+ } // <tests> ? <body> : <acc>
883
+
884
+
885
+ return {
886
+ type: 'ConditionalExpression',
887
+ test: (0, _Builders.conjunction)(tests),
888
+ consequent: body,
889
+ alternate: acc,
890
+ ...(0, _Builders.etc)()
891
+ };
892
+ }, lastBody);
893
+ } // There are bindings, so we produce an immediately invoked arrow expression.
894
+ // If the original argument is simple, no need for a new variable.
895
+
896
+
897
+ const statements = analyses.map(({
898
+ conditions,
899
+ bindings,
900
+ guard,
901
+ body
902
+ }) => {
903
+ const returnNode = {
904
+ type: 'ReturnStatement',
905
+ argument: body,
906
+ ...(0, _Builders.etc)()
907
+ }; // If we have a guard, then we use a nested if statement
908
+ // `if (<guard>) return <body>`
909
+
910
+ const bodyNode = guard == null ? returnNode : {
911
+ type: 'IfStatement',
912
+ test: guard,
913
+ consequent: returnNode,
914
+ ...(0, _Builders.etc)()
915
+ };
916
+ const bindingNodes = statementsOfBindings(root, bindings);
917
+ const caseBody = bindingNodes.concat(bodyNode);
918
+
919
+ if (conditions.length > 0) {
920
+ const tests = testsOfConditions(root, conditions);
921
+ return {
922
+ type: 'IfStatement',
923
+ test: (0, _Builders.conjunction)(tests),
924
+ consequent: {
925
+ type: 'BlockStatement',
926
+ body: caseBody,
927
+ ...(0, _Builders.etc)()
928
+ },
929
+ ...(0, _Builders.etc)()
930
+ };
931
+ } else {
932
+ // No conditions, so no if statement
933
+ if (bindingNodes.length > 0) {
934
+ // Bindings require a block to introduce a new scope
935
+ return {
936
+ type: 'BlockStatement',
937
+ body: caseBody,
938
+ ...(0, _Builders.etc)()
939
+ };
940
+ } else {
941
+ return bodyNode;
942
+ }
943
+ }
944
+ });
945
+
946
+ if (!hasWildcard) {
947
+ statements.push(fallthroughError((0, _astNodeMutationHelpers.shallowCloneNode)(root)));
948
+ }
949
+
950
+ const [params, args] = genRoot == null ? [[], []] : [[genRoot], [argument]]; // `((<params>) => { ... })(<args>)`, or
951
+ // `(() => { ... })()` if is simple argument.
952
+
953
+ return (0, _Builders.iife)(statements, params, args);
954
+ }
955
+ /**
956
+ * Match statement transform entry point.
957
+ */
958
+
959
+
960
+ function mapMatchStatement(node) {
961
+ const {
962
+ argument,
963
+ cases
964
+ } = node;
965
+ const {
966
+ hasBindings,
967
+ hasWildcard,
968
+ analyses
969
+ } = analyzeCases(cases);
970
+ const topLabel = genIdent();
971
+ const isSimpleArgument = !hasBindings && calculateSimpleArgument(argument);
972
+ const genRoot = !isSimpleArgument ? genIdent() : null;
973
+ const root = genRoot == null ? argument : genRoot;
974
+ const statements = [];
975
+
976
+ if (genRoot != null) {
977
+ statements.push((0, _Builders.variableDeclaration)('const', genRoot, argument));
978
+ }
979
+
980
+ analyses.forEach(({
981
+ conditions,
982
+ bindings,
983
+ guard,
984
+ body
985
+ }) => {
986
+ const breakNode = {
987
+ type: 'BreakStatement',
988
+ label: (0, _astNodeMutationHelpers.shallowCloneNode)(topLabel),
989
+ ...(0, _Builders.etc)()
990
+ };
991
+ const bodyStatements = body.body.concat(breakNode); // If we have a guard, then we use a nested if statement
992
+ // `if (<guard>) return <body>`
993
+
994
+ const guardedBodyStatements = guard == null ? bodyStatements : [{
995
+ type: 'IfStatement',
996
+ test: guard,
997
+ consequent: {
998
+ type: 'BlockStatement',
999
+ body: bodyStatements,
1000
+ ...(0, _Builders.etc)()
1001
+ },
1002
+ ...(0, _Builders.etc)()
1003
+ }];
1004
+ const bindingNodes = statementsOfBindings(root, bindings);
1005
+ const caseBody = bindingNodes.concat(guardedBodyStatements);
1006
+
1007
+ if (conditions.length > 0) {
1008
+ const tests = testsOfConditions(root, conditions);
1009
+ statements.push({
1010
+ type: 'IfStatement',
1011
+ test: (0, _Builders.conjunction)(tests),
1012
+ consequent: {
1013
+ type: 'BlockStatement',
1014
+ body: caseBody,
1015
+ ...(0, _Builders.etc)()
1016
+ },
1017
+ ...(0, _Builders.etc)()
1018
+ });
1019
+ } else {
1020
+ // No conditions, so no if statement
1021
+ statements.push({
1022
+ type: 'BlockStatement',
1023
+ body: caseBody,
1024
+ ...(0, _Builders.etc)()
1025
+ });
1026
+ }
1027
+ });
1028
+
1029
+ if (!hasWildcard) {
1030
+ statements.push(fallthroughError((0, _astNodeMutationHelpers.shallowCloneNode)(root)));
1031
+ }
1032
+
1033
+ return {
1034
+ type: 'LabeledStatement',
1035
+ label: topLabel,
1036
+ body: {
1037
+ type: 'BlockStatement',
1038
+ body: statements,
1039
+ ...(0, _Builders.etc)()
1040
+ },
1041
+ ...(0, _Builders.etc)()
1042
+ };
1043
+ }
1044
+
1045
+ function transformProgram(program, _options) {
1046
+ // Initialize so each file transformed starts freshly incrementing the
1047
+ // variable name counter, and has its own usage tracking.
1048
+ genID = new _GenID.default('m');
1049
+ return _SimpleTransform.SimpleTransform.transformProgram(program, {
1050
+ transform(node) {
1051
+ switch (node.type) {
1052
+ case 'MatchExpression':
1053
+ {
1054
+ return mapMatchExpression(node);
1055
+ }
1056
+
1057
+ case 'MatchStatement':
1058
+ {
1059
+ return mapMatchStatement(node);
1060
+ }
1061
+
1062
+ case 'Identifier':
1063
+ {
1064
+ // A rudimentary check to avoid some collisions with our generated
1065
+ // variable names. Ideally, we would have access a scope analyzer
1066
+ // inside the transform instead.
1067
+ if (genID == null) {
1068
+ throw Error('GenID must be initialized at the start of the transform.');
1069
+ }
1070
+
1071
+ genID.addUsage(node.name);
1072
+ return node;
1073
+ }
1074
+
1075
+ default:
1076
+ {
1077
+ return node;
1078
+ }
1079
+ }
1080
+ }
1081
+
1082
+ });
1083
+ }