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