hermes-parser 0.15.1 → 0.16.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,623 @@
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
+
11
+ /**
12
+ * This transform strips Flow types that are not supported past Babel 7.
13
+ *
14
+ * It is expected that all transforms create valid ESTree AST output. If
15
+ * the transform requires outputting Babel specific AST nodes then it
16
+ * should live in `ConvertESTreeToBabel.js`
17
+ */
18
+ 'use strict';
19
+
20
+ Object.defineProperty(exports, "__esModule", {
21
+ value: true
22
+ });
23
+ exports.transformProgram = transformProgram;
24
+
25
+ var _SimpleTransform = require("../transform/SimpleTransform");
26
+
27
+ var _astNodeMutationHelpers = require("../transform/astNodeMutationHelpers");
28
+
29
+ var _SimpleTraverser = require("../traverse/SimpleTraverser");
30
+
31
+ const nodeWith = _SimpleTransform.SimpleTransform.nodeWith; // Rely on the mapper to fix up parent relationships.
32
+
33
+ const EMPTY_PARENT = null;
34
+
35
+ function createSyntaxError(node, err) {
36
+ const syntaxError = new SyntaxError(err); // $FlowExpectedError[prop-missing]
37
+
38
+ syntaxError.loc = {
39
+ line: node.loc.start.line,
40
+ column: node.loc.start.column
41
+ };
42
+ return syntaxError;
43
+ }
44
+
45
+ function createDefaultPosition() {
46
+ return {
47
+ line: 1,
48
+ column: 0
49
+ };
50
+ }
51
+
52
+ function mapDeclareComponent(node) {
53
+ return {
54
+ type: 'DeclareVariable',
55
+ id: nodeWith(node.id, {
56
+ typeAnnotation: {
57
+ type: 'TypeAnnotation',
58
+ typeAnnotation: {
59
+ type: 'AnyTypeAnnotation',
60
+ loc: node.loc,
61
+ range: node.range,
62
+ parent: EMPTY_PARENT
63
+ },
64
+ loc: node.loc,
65
+ range: node.range,
66
+ parent: EMPTY_PARENT
67
+ }
68
+ }),
69
+ kind: 'const',
70
+ loc: node.loc,
71
+ range: node.range,
72
+ parent: node.parent
73
+ };
74
+ }
75
+
76
+ function getComponentParameterName(paramName) {
77
+ switch (paramName.type) {
78
+ case 'Identifier':
79
+ return paramName.name;
80
+
81
+ case 'Literal':
82
+ return paramName.value;
83
+
84
+ default:
85
+ throw createSyntaxError(paramName, `Unknown Component parameter name type of "${paramName.type}"`);
86
+ }
87
+ }
88
+
89
+ function createPropsTypeAnnotation(loc, range) {
90
+ // Create empty loc for type annotation nodes
91
+ const createParamsTypeLoc = () => ({
92
+ loc: {
93
+ start: (loc == null ? void 0 : loc.start) != null ? loc.start : createDefaultPosition(),
94
+ end: (loc == null ? void 0 : loc.end) != null ? loc.end : createDefaultPosition()
95
+ },
96
+ range: range != null ? range : [0, 0],
97
+ parent: EMPTY_PARENT
98
+ });
99
+
100
+ return {
101
+ type: 'TypeAnnotation',
102
+ typeAnnotation: {
103
+ type: 'GenericTypeAnnotation',
104
+ id: {
105
+ type: 'Identifier',
106
+ name: '$ReadOnly',
107
+ optional: false,
108
+ typeAnnotation: null,
109
+ ...createParamsTypeLoc()
110
+ },
111
+ typeParameters: {
112
+ type: 'TypeParameterInstantiation',
113
+ params: [{
114
+ type: 'ObjectTypeAnnotation',
115
+ callProperties: [],
116
+ properties: [],
117
+ indexers: [],
118
+ internalSlots: [],
119
+ exact: false,
120
+ inexact: true,
121
+ ...createParamsTypeLoc()
122
+ }],
123
+ ...createParamsTypeLoc()
124
+ },
125
+ ...createParamsTypeLoc()
126
+ },
127
+ ...createParamsTypeLoc()
128
+ };
129
+ }
130
+
131
+ function mapComponentParameters(params) {
132
+ if (params.length === 0) {
133
+ return {
134
+ props: null,
135
+ ref: null
136
+ };
137
+ } // Optimize `component Foo(...props: Props) {}` to `function Foo(props: Props) {}
138
+
139
+
140
+ if (params.length === 1 && params[0].type === 'RestElement' && (params[0].argument.type === 'Identifier' || params[0].argument.type === 'ObjectPattern')) {
141
+ var _restElementArgument$, _restElementArgument$2;
142
+
143
+ const restElementArgument = params[0].argument;
144
+ return {
145
+ props: nodeWith(restElementArgument, {
146
+ typeAnnotation: createPropsTypeAnnotation((_restElementArgument$ = restElementArgument.typeAnnotation) == null ? void 0 : _restElementArgument$.loc, (_restElementArgument$2 = restElementArgument.typeAnnotation) == null ? void 0 : _restElementArgument$2.range)
147
+ }),
148
+ ref: null
149
+ };
150
+ } // Filter out any ref param and capture it's details.
151
+
152
+
153
+ let refParam = null;
154
+ const paramsWithoutRef = params.filter(param => {
155
+ if (param.type === 'ComponentParameter' && getComponentParameterName(param.name) === 'ref') {
156
+ refParam = param;
157
+ return false;
158
+ }
159
+
160
+ return true;
161
+ });
162
+ const propsProperties = paramsWithoutRef.map(mapComponentParameter);
163
+ let props = null;
164
+
165
+ if (propsProperties.length === 0) {
166
+ if (refParam == null) {
167
+ throw new Error('TransformReactScriptForBabel: Invalid state, ref should always be set at this point if props are empty');
168
+ }
169
+
170
+ const emptyParamsLoc = {
171
+ start: refParam.loc.start,
172
+ end: refParam.loc.start
173
+ };
174
+ const emptyParamsRange = [refParam.range[0], refParam.range[0]]; // no properties provided (must have had a single ref)
175
+
176
+ props = {
177
+ type: 'Identifier',
178
+ name: '_$$empty_props_placeholder$$',
179
+ optional: false,
180
+ typeAnnotation: createPropsTypeAnnotation(emptyParamsLoc, emptyParamsRange),
181
+ loc: emptyParamsLoc,
182
+ range: emptyParamsRange,
183
+ parent: EMPTY_PARENT
184
+ };
185
+ } else {
186
+ const lastPropsProperty = propsProperties[propsProperties.length - 1];
187
+ props = {
188
+ type: 'ObjectPattern',
189
+ properties: propsProperties,
190
+ typeAnnotation: createPropsTypeAnnotation({
191
+ start: lastPropsProperty.loc.end,
192
+ end: lastPropsProperty.loc.end
193
+ }, [lastPropsProperty.range[1], lastPropsProperty.range[1]]),
194
+ loc: {
195
+ start: propsProperties[0].loc.start,
196
+ end: lastPropsProperty.loc.end
197
+ },
198
+ range: [propsProperties[0].range[0], lastPropsProperty.range[1]],
199
+ parent: EMPTY_PARENT
200
+ };
201
+ }
202
+
203
+ let ref = null;
204
+
205
+ if (refParam != null) {
206
+ const refType = refParam.local;
207
+ ref = {
208
+ type: 'Identifier',
209
+ name: 'ref',
210
+ optional: false,
211
+ typeAnnotation: refType.type === 'AssignmentPattern' ? refType.left.typeAnnotation : refType.typeAnnotation,
212
+ loc: refParam.loc,
213
+ range: refParam.range,
214
+ parent: EMPTY_PARENT
215
+ };
216
+ }
217
+
218
+ return {
219
+ props,
220
+ ref
221
+ };
222
+ }
223
+
224
+ function mapComponentParameter(param) {
225
+ switch (param.type) {
226
+ case 'RestElement':
227
+ {
228
+ const a = nodeWith(param, {
229
+ typeAnnotation: null,
230
+ argument: nodeWith(param.argument, {
231
+ typeAnnotation: null
232
+ })
233
+ });
234
+ return a;
235
+ }
236
+
237
+ case 'ComponentParameter':
238
+ {
239
+ if (getComponentParameterName(param.name) === 'ref') {
240
+ throw createSyntaxError(param, 'Component parameters named "ref" are currently not supported');
241
+ }
242
+
243
+ let value;
244
+
245
+ if (param.local.type === 'AssignmentPattern') {
246
+ value = nodeWith(param.local, {
247
+ left: nodeWith(param.local.left, {
248
+ typeAnnotation: null,
249
+ optional: false
250
+ })
251
+ });
252
+ } else {
253
+ value = nodeWith(param.local, {
254
+ typeAnnotation: null,
255
+ optional: false
256
+ });
257
+ } // Shorthand params
258
+
259
+
260
+ if (param.name.type === 'Identifier' && param.shorthand && (value.type === 'Identifier' || value.type === 'AssignmentPattern')) {
261
+ return {
262
+ type: 'Property',
263
+ key: param.name,
264
+ kind: 'init',
265
+ value,
266
+ method: false,
267
+ shorthand: true,
268
+ computed: false,
269
+ loc: param.loc,
270
+ range: param.range,
271
+ parent: EMPTY_PARENT
272
+ };
273
+ } // Complex params
274
+
275
+
276
+ return {
277
+ type: 'Property',
278
+ key: param.name,
279
+ kind: 'init',
280
+ value,
281
+ method: false,
282
+ shorthand: false,
283
+ computed: false,
284
+ loc: param.loc,
285
+ range: param.range,
286
+ parent: EMPTY_PARENT
287
+ };
288
+ }
289
+
290
+ default:
291
+ {
292
+ throw createSyntaxError(param, `Unknown Component parameter type of "${param.type}"`);
293
+ }
294
+ }
295
+ }
296
+
297
+ function createForwardRefWrapper(originalComponent) {
298
+ const internalCompId = {
299
+ type: 'Identifier',
300
+ name: `${originalComponent.id.name}_withRef`,
301
+ optional: false,
302
+ typeAnnotation: null,
303
+ loc: originalComponent.id.loc,
304
+ range: originalComponent.id.range,
305
+ parent: EMPTY_PARENT
306
+ };
307
+ return {
308
+ forwardRefStatement: {
309
+ type: 'VariableDeclaration',
310
+ kind: 'const',
311
+ declarations: [{
312
+ type: 'VariableDeclarator',
313
+ id: (0, _astNodeMutationHelpers.shallowCloneNode)(originalComponent.id),
314
+ init: {
315
+ type: 'CallExpression',
316
+ callee: {
317
+ type: 'MemberExpression',
318
+ object: {
319
+ type: 'Identifier',
320
+ name: 'React',
321
+ optional: false,
322
+ typeAnnotation: null,
323
+ loc: originalComponent.loc,
324
+ range: originalComponent.range,
325
+ parent: EMPTY_PARENT
326
+ },
327
+ property: {
328
+ type: 'Identifier',
329
+ name: 'forwardRef',
330
+ optional: false,
331
+ typeAnnotation: null,
332
+ loc: originalComponent.loc,
333
+ range: originalComponent.range,
334
+ parent: EMPTY_PARENT
335
+ },
336
+ computed: false,
337
+ optional: false,
338
+ loc: originalComponent.loc,
339
+ range: originalComponent.range,
340
+ parent: EMPTY_PARENT
341
+ },
342
+ arguments: [(0, _astNodeMutationHelpers.shallowCloneNode)(internalCompId)],
343
+ typeArguments: null,
344
+ optional: false,
345
+ loc: originalComponent.loc,
346
+ range: originalComponent.range,
347
+ parent: EMPTY_PARENT
348
+ },
349
+ loc: originalComponent.loc,
350
+ range: originalComponent.range,
351
+ parent: EMPTY_PARENT
352
+ }],
353
+ loc: originalComponent.loc,
354
+ range: originalComponent.range,
355
+ parent: originalComponent.parent
356
+ },
357
+ internalCompId: internalCompId,
358
+ forwardRefCompId: originalComponent.id
359
+ };
360
+ }
361
+
362
+ function mapComponentDeclaration(node) {
363
+ let rendersType = node.rendersType;
364
+
365
+ if (rendersType == null) {
366
+ // Create empty loc for return type annotation nodes
367
+ const createRendersTypeLoc = () => ({
368
+ loc: {
369
+ start: node.body.loc.end,
370
+ end: node.body.loc.end
371
+ },
372
+ range: [node.body.range[1], node.body.range[1]],
373
+ parent: EMPTY_PARENT
374
+ });
375
+
376
+ rendersType = {
377
+ type: 'TypeAnnotation',
378
+ typeAnnotation: {
379
+ type: 'GenericTypeAnnotation',
380
+ id: {
381
+ type: 'QualifiedTypeIdentifier',
382
+ qualification: {
383
+ type: 'Identifier',
384
+ name: 'React',
385
+ optional: false,
386
+ typeAnnotation: null,
387
+ ...createRendersTypeLoc()
388
+ },
389
+ id: {
390
+ type: 'Identifier',
391
+ name: 'Node',
392
+ optional: false,
393
+ typeAnnotation: null,
394
+ ...createRendersTypeLoc()
395
+ },
396
+ ...createRendersTypeLoc()
397
+ },
398
+ typeParameters: null,
399
+ ...createRendersTypeLoc()
400
+ },
401
+ ...createRendersTypeLoc()
402
+ };
403
+ }
404
+
405
+ const {
406
+ props,
407
+ ref
408
+ } = mapComponentParameters(node.params);
409
+ let forwardRefDetails = null;
410
+
411
+ if (ref != null) {
412
+ forwardRefDetails = createForwardRefWrapper(node);
413
+ }
414
+
415
+ const comp = {
416
+ type: 'FunctionDeclaration',
417
+ id: forwardRefDetails != null ? (0, _astNodeMutationHelpers.shallowCloneNode)(forwardRefDetails.internalCompId) : (0, _astNodeMutationHelpers.shallowCloneNode)(node.id),
418
+ __componentDeclaration: true,
419
+ typeParameters: node.typeParameters,
420
+ params: props == null ? [] : ref == null ? [props] : [props, ref],
421
+ returnType: rendersType,
422
+ body: node.body,
423
+ async: false,
424
+ generator: false,
425
+ predicate: null,
426
+ loc: node.loc,
427
+ range: node.range,
428
+ parent: node.parent
429
+ };
430
+ return {
431
+ comp,
432
+ forwardRefDetails
433
+ };
434
+ }
435
+ /**
436
+ * Scan a list of statements and return the position of the
437
+ * first statement that contains a reference to a given component
438
+ * or null of no references were found.
439
+ */
440
+
441
+
442
+ function scanForFirstComponentReference(compName, bodyList) {
443
+ for (let i = 0; i < bodyList.length; i++) {
444
+ const bodyNode = bodyList[i];
445
+ let referencePos = null;
446
+
447
+ _SimpleTraverser.SimpleTraverser.traverse(bodyNode, {
448
+ enter(node) {
449
+ switch (node.type) {
450
+ case 'Identifier':
451
+ {
452
+ if (node.name === compName) {
453
+ // We found a reference, record it and stop.
454
+ referencePos = i;
455
+ throw _SimpleTraverser.SimpleTraverser.Break;
456
+ }
457
+ }
458
+ }
459
+ },
460
+
461
+ leave(_node) {}
462
+
463
+ });
464
+
465
+ if (referencePos != null) {
466
+ return referencePos;
467
+ }
468
+ }
469
+
470
+ return null;
471
+ }
472
+
473
+ function mapComponentDeclarationIntoList(node, newBody, insertExport) {
474
+ const {
475
+ comp,
476
+ forwardRefDetails
477
+ } = mapComponentDeclaration(node);
478
+
479
+ if (forwardRefDetails != null) {
480
+ // Scan for references to our component.
481
+ const referencePos = scanForFirstComponentReference(forwardRefDetails.forwardRefCompId.name, newBody); // If a reference is found insert the forwardRef statement before it (to simulate function hoisting).
482
+
483
+ if (referencePos != null) {
484
+ newBody.splice(referencePos, 0, forwardRefDetails.forwardRefStatement);
485
+ } else {
486
+ newBody.push(forwardRefDetails.forwardRefStatement);
487
+ }
488
+
489
+ newBody.push(comp);
490
+
491
+ if (insertExport != null) {
492
+ newBody.push(insertExport(forwardRefDetails.forwardRefCompId));
493
+ }
494
+
495
+ return;
496
+ }
497
+
498
+ newBody.push(insertExport != null ? insertExport(comp) : comp);
499
+ }
500
+
501
+ function mapStatementList(stmts) {
502
+ const newBody = [];
503
+
504
+ for (const node of stmts) {
505
+ switch (node.type) {
506
+ case 'ComponentDeclaration':
507
+ {
508
+ mapComponentDeclarationIntoList(node, newBody);
509
+ break;
510
+ }
511
+
512
+ case 'ExportNamedDeclaration':
513
+ {
514
+ var _node$declaration;
515
+
516
+ if (((_node$declaration = node.declaration) == null ? void 0 : _node$declaration.type) === 'ComponentDeclaration') {
517
+ mapComponentDeclarationIntoList(node.declaration, newBody, componentOrRef => {
518
+ switch (componentOrRef.type) {
519
+ case 'FunctionDeclaration':
520
+ {
521
+ // No ref, so we can export the component directly.
522
+ return nodeWith(node, {
523
+ declaration: componentOrRef
524
+ });
525
+ }
526
+
527
+ case 'Identifier':
528
+ {
529
+ // If a ref is inserted, we should just export that id.
530
+ return {
531
+ type: 'ExportNamedDeclaration',
532
+ declaration: null,
533
+ specifiers: [{
534
+ type: 'ExportSpecifier',
535
+ exported: (0, _astNodeMutationHelpers.shallowCloneNode)(componentOrRef),
536
+ local: (0, _astNodeMutationHelpers.shallowCloneNode)(componentOrRef),
537
+ loc: node.loc,
538
+ range: node.range,
539
+ parent: EMPTY_PARENT
540
+ }],
541
+ exportKind: 'value',
542
+ source: null,
543
+ loc: node.loc,
544
+ range: node.range,
545
+ parent: node.parent
546
+ };
547
+ }
548
+ }
549
+ });
550
+ break;
551
+ }
552
+
553
+ newBody.push(node);
554
+ break;
555
+ }
556
+
557
+ case 'ExportDefaultDeclaration':
558
+ {
559
+ var _node$declaration2;
560
+
561
+ if (((_node$declaration2 = node.declaration) == null ? void 0 : _node$declaration2.type) === 'ComponentDeclaration') {
562
+ mapComponentDeclarationIntoList(node.declaration, newBody, componentOrRef => nodeWith(node, {
563
+ declaration: componentOrRef
564
+ }));
565
+ break;
566
+ }
567
+
568
+ newBody.push(node);
569
+ break;
570
+ }
571
+
572
+ default:
573
+ {
574
+ newBody.push(node);
575
+ }
576
+ }
577
+ }
578
+
579
+ return newBody;
580
+ }
581
+
582
+ function transformProgram(program, _options) {
583
+ return _SimpleTransform.SimpleTransform.transformProgram(program, {
584
+ transform(node) {
585
+ switch (node.type) {
586
+ case 'DeclareComponent':
587
+ {
588
+ return mapDeclareComponent(node);
589
+ }
590
+
591
+ case 'Program':
592
+ case 'BlockStatement':
593
+ {
594
+ return nodeWith(node, {
595
+ body: mapStatementList(node.body)
596
+ });
597
+ }
598
+
599
+ case 'SwitchCase':
600
+ {
601
+ return nodeWith(node, {
602
+ /* $FlowExpectedError[incompatible-call] We know `mapStatementList` will
603
+ not return `ModuleDeclaration` nodes if it is not passed any */
604
+ consequent: mapStatementList(node.consequent)
605
+ });
606
+ }
607
+
608
+ case 'ComponentDeclaration':
609
+ {
610
+ var _node$parent;
611
+
612
+ throw createSyntaxError(node, `Components must be defined at the top level of a module or within a ` + `BlockStatement, instead got parent of "${(_node$parent = node.parent) == null ? void 0 : _node$parent.type}".`);
613
+ }
614
+
615
+ default:
616
+ {
617
+ return node;
618
+ }
619
+ }
620
+ }
621
+
622
+ });
623
+ }