flow-parser 0.328.0 → 0.330.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.
@@ -13,16 +13,27 @@
13
13
  import type {HermesSourceLocation, HermesNode, HermesToken} from './HermesAST';
14
14
  import type {FlowParserWASM} from './FlowParserWASM';
15
15
  import type {ParserOptions} from './ParserOptions';
16
+ import type {BabelFile} from './babel/BabelAST';
16
17
 
17
18
  import HermesParserDecodeUTF8String from './HermesParserDecodeUTF8String';
18
19
  import NODE_DESERIALIZERS from './FlowParserNodeDeserializers';
19
20
 
20
21
  type FlowComment = {
21
- type: 'Block' | 'Line',
22
+ type: 'Block' | 'Line' | 'CommentBlock' | 'CommentLine',
22
23
  loc: HermesSourceLocation,
23
24
  value: ?string,
25
+ start?: number,
26
+ end?: number,
24
27
  };
25
28
 
29
+ type ExtendedPosition = {
30
+ loc: HermesSourceLocation,
31
+ start: number,
32
+ end: number,
33
+ };
34
+
35
+ const LOCATION_IDENTIFIER_NAME = 1 << 0;
36
+
26
37
  export type FlowParserProgram = {
27
38
  type: 'Program',
28
39
  loc: HermesSourceLocation,
@@ -49,15 +60,15 @@ export default class FlowParserDeserializer {
49
60
  readonly positionBufferSize: number;
50
61
  readonly stringBufferBase: number;
51
62
  readonly locMap: {[number]: HermesSourceLocation};
63
+ readonly extendedPositions: Array<?ExtendedPosition>;
64
+ readonly extendedRanges: WeakMap<HermesSourceLocation, ExtendedPosition>;
52
65
  readonly HEAPU8: FlowParserWASM['HEAPU8'];
53
66
  readonly HEAPU32: FlowParserWASM['HEAPU32'];
54
67
  readonly HEAPF64: FlowParserWASM['HEAPF64'];
55
68
  readonly options: ParserOptions;
69
+ extendedLocationHeaders: boolean;
56
70
 
57
- // Comment types: Flow uses ESTree-standard names
58
- // Matches CommentKind enum in ast.rs: Block = 0, Line = 1
59
71
  readonly commentTypes: ReadonlyArray<FlowComment['type']> = ['Block', 'Line'];
60
-
61
72
  // Matches TokenType enum (same as Hermes for compatibility)
62
73
  readonly tokenTypes: ReadonlyArray<HermesToken['type']> = [
63
74
  'Boolean',
@@ -94,12 +105,15 @@ export default class FlowParserDeserializer {
94
105
  // null pointer (encoded as `(0,)` with no length word).
95
106
  this.stringBufferBase = stringBufferBase;
96
107
  this.locMap = {};
108
+ this.extendedPositions = [];
109
+ this.extendedRanges = new WeakMap();
97
110
 
98
111
  this.HEAPU8 = wasmParser.HEAPU8;
99
112
  this.HEAPU32 = wasmParser.HEAPU32;
100
113
  this.HEAPF64 = wasmParser.HEAPF64;
101
114
 
102
115
  this.options = options;
116
+ this.extendedLocationHeaders = false;
103
117
  }
104
118
 
105
119
  /**
@@ -110,33 +124,35 @@ export default class FlowParserDeserializer {
110
124
  return num;
111
125
  }
112
126
 
113
- deserialize(): FlowParserProgram {
127
+ deserialize(): FlowParserProgram | BabelFile {
128
+ if (this.HEAPU32[this.programBufferIdx] === 0) {
129
+ return this.deserializeESTreeProgram();
130
+ }
131
+ this.extendedLocationHeaders = true;
132
+ this.prepareExtendedPositions();
133
+ const root = this.deserializeNode();
134
+ if (root == null) {
135
+ throw new Error('Expected serialized parser root');
136
+ }
137
+ // $FlowExpectedError[incompatible-type] The root node kind defines the public schema.
138
+ return root;
139
+ }
140
+
141
+ deserializeESTreeProgram(): FlowParserProgram {
114
142
  const program: FlowParserProgram = {
115
143
  type: 'Program',
116
144
  loc: this.addEmptyLoc(),
117
145
  body: this.deserializeNodeList(),
118
- comments: this.deserializeComments(),
146
+ comments: this.deserializeESTreeComments(),
119
147
  };
120
-
121
- // Interpreter directive (OCaml `program` estree_translator.ml:118-123).
122
- // The serializer writes a Node slot here: an `InterpreterDirective` node
123
- // when `#!shebang` is present, otherwise null. Always attach the slot so
124
- // the public Program shape carries `interpreter: InterpreterDirective | null`
125
- // — matches upstream hermes-parser, which exposes the slot uniformly.
126
148
  program.interpreter = this.deserializeNode();
127
-
128
149
  if (this.options.tokens === true) {
129
150
  program.tokens = this.deserializeTokens();
130
151
  } else {
131
- // Tokens slot is always written by the serializer; consume the count
132
- // even when callers didn't ask for tokens.
133
152
  this.deserializeTokens();
134
153
  }
135
-
136
154
  program.errors = this.deserializeErrors();
137
-
138
155
  this.fillLocs();
139
-
140
156
  return program;
141
157
  }
142
158
 
@@ -219,9 +235,19 @@ export default class FlowParserDeserializer {
219
235
  if (nodeType === 0) {
220
236
  return null;
221
237
  }
222
-
223
- const nodeDeserializer = NODE_DESERIALIZERS[nodeType - 1].bind(this);
224
- return nodeDeserializer();
238
+ const deserializeNode = NODE_DESERIALIZERS[nodeType - 1];
239
+ if (deserializeNode == null) {
240
+ throw new Error(
241
+ `Unknown serialized node kind ${nodeType - 1} at program word ${
242
+ this.programBufferIdx - 1
243
+ }`,
244
+ );
245
+ }
246
+ const node = deserializeNode.call(this);
247
+ if (this.extendedLocationHeaders) {
248
+ this.addExtendedRange(node);
249
+ }
250
+ return node;
225
251
  }
226
252
 
227
253
  /**
@@ -235,10 +261,18 @@ export default class FlowParserDeserializer {
235
261
  for (let i = 0; i < size; i++) {
236
262
  nodeList.push(this.deserializeNode());
237
263
  }
238
-
239
264
  return nodeList;
240
265
  }
241
266
 
267
+ deserializeEnumRuntime(): unknown {
268
+ const getRuntime =
269
+ this.options.transformOptions?.TransformEnumSyntax?.getRuntime;
270
+ if (typeof getRuntime !== 'function') {
271
+ throw new Error('Expected TransformEnumSyntax.getRuntime callback');
272
+ }
273
+ return getRuntime();
274
+ }
275
+
242
276
  /**
243
277
  * Comments are serialized as a node list, where each comment is serialized
244
278
  * as a 4-byte integer denoting comment type, followed by a 4-byte value
@@ -249,19 +283,39 @@ export default class FlowParserDeserializer {
249
283
  const comments = [];
250
284
 
251
285
  for (let i = 0; i < size; i++) {
252
- const commentType = this.commentTypes[this.next()];
286
+ const commentType = this.deserializeString();
287
+ if (commentType == null) {
288
+ throw new Error('Expected serialized comment type');
289
+ }
253
290
  const loc = this.addEmptyLoc();
254
- const value = this.deserializeString();
255
- comments.push({
291
+ const comment: FlowComment = {
292
+ // $FlowExpectedError[incompatible-type] Rust emits the closed comment type set.
256
293
  type: commentType,
257
294
  loc,
258
- value,
259
- });
295
+ value: this.deserializeString(),
296
+ };
297
+ this.addExtendedRange(comment);
298
+ comments.push(comment);
260
299
  }
261
300
 
262
301
  return comments;
263
302
  }
264
303
 
304
+ deserializeESTreeComments(): Array<FlowComment> {
305
+ const size = this.next();
306
+ const comments = [];
307
+ for (let i = 0; i < size; i++) {
308
+ const commentType = this.commentTypes[this.next()];
309
+ const comment: FlowComment = {
310
+ type: commentType,
311
+ loc: this.addEmptyLoc(),
312
+ value: this.deserializeString(),
313
+ };
314
+ comments.push(comment);
315
+ }
316
+ return comments;
317
+ }
318
+
265
319
  deserializeTokens(): Array<HermesToken> {
266
320
  const size = this.next();
267
321
  const tokens = [];
@@ -270,11 +324,12 @@ export default class FlowParserDeserializer {
270
324
  const tokenType = this.tokenTypes[this.next()];
271
325
  const loc = this.addEmptyLoc();
272
326
  const value = this.deserializeString();
273
- tokens.push({
327
+ const token: HermesToken = {
274
328
  type: tokenType,
275
329
  loc,
276
330
  value,
277
- });
331
+ };
332
+ tokens.push(token);
278
333
  }
279
334
 
280
335
  return tokens;
@@ -286,11 +341,70 @@ export default class FlowParserDeserializer {
286
341
  * objects that are filled after the AST has been deserialized.
287
342
  */
288
343
  addEmptyLoc(): HermesSourceLocation {
344
+ const locId = this.next();
345
+ if (this.extendedLocationHeaders) {
346
+ const flags = this.next();
347
+ const position = this.extendedPositions[locId];
348
+ if (position == null) {
349
+ throw new Error(`Missing serialized extended location ${locId}`);
350
+ }
351
+ const loc = position.loc;
352
+ if (flags & LOCATION_IDENTIFIER_NAME) {
353
+ const identifierName = this.deserializeString();
354
+ if (identifierName != null) {
355
+ // $FlowExpectedError[prop-missing] The extended wire location schema carries this field.
356
+ loc.identifierName = identifierName;
357
+ }
358
+ }
359
+ this.extendedRanges.set(loc, position);
360
+ return loc;
361
+ }
289
362
  const loc: HermesSourceLocation = {};
290
- this.locMap[this.next()] = loc;
363
+ this.locMap[locId] = loc;
291
364
  return loc;
292
365
  }
293
366
 
367
+ prepareExtendedPositions(): void {
368
+ let index = this.positionBufferIdx;
369
+ for (let i = 0; i < this.positionBufferSize; i++) {
370
+ const locId = this.HEAPU32[index++];
371
+ const kind = this.HEAPU32[index++];
372
+ const line = this.HEAPU32[index++];
373
+ const column = this.HEAPU32[index++];
374
+ const offset = this.HEAPU32[index++];
375
+ const position: ExtendedPosition = this.extendedPositions[locId] ?? {
376
+ loc: {} as HermesSourceLocation,
377
+ start: 0,
378
+ end: 0,
379
+ };
380
+ if (kind === 0) {
381
+ position.loc.start = {line, column};
382
+ position.start = offset;
383
+ } else {
384
+ position.loc.end = {line, column};
385
+ position.end = offset;
386
+ }
387
+ this.extendedPositions[locId] = position;
388
+ }
389
+ }
390
+
391
+ addExtendedRange(owner: {
392
+ readonly loc: HermesSourceLocation,
393
+ start?: number,
394
+ end?: number,
395
+ ...
396
+ }): void {
397
+ if (owner.loc == null) {
398
+ return;
399
+ }
400
+ const position = this.extendedRanges.get(owner.loc);
401
+ if (position == null) {
402
+ return;
403
+ }
404
+ owner.start = position.start;
405
+ owner.end = position.end;
406
+ }
407
+
294
408
  /**
295
409
  * Positions are serialized as a loc ID which denotes which loc it is
296
410
  * associated with, followed by kind which denotes whether it is a start
@@ -305,6 +419,9 @@ export default class FlowParserDeserializer {
305
419
  const offset = this.HEAPU32[this.positionBufferIdx++];
306
420
 
307
421
  const loc = this.locMap[locId];
422
+ if (loc == null) {
423
+ throw new Error(`Missing serialized location ${locId}`);
424
+ }
308
425
  if (kind === 0) {
309
426
  loc.start = {
310
427
  line,