flow-parser 0.328.0 → 0.329.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.
package/README.md CHANGED
@@ -28,3 +28,44 @@ The Flow parser exposes a single `parse(code, [options])` function, where `code`
28
28
  - `TransformEnumSyntax`
29
29
  - `enable`: `boolean` - Whether to enable the transform. By default, `false`.
30
30
  - `getRuntime` (optional): `() => Expression` - The expression which should be a reference to the Flow Enums runtime. By default, is `require('flow-enums-runtime')`.
31
+
32
+ ## Babel plugin
33
+
34
+ Flow parser plugin for [Babel](https://babeljs.io/). This plugin switches Babel to use `flow-parser` instead of the `@babel/parser`. The Flow parser uses Rust compiled to WASM for full Flow syntax support.
35
+
36
+ ### Install
37
+
38
+ Using npm:
39
+
40
+ ```sh
41
+ npm install --save-dev flow-parser
42
+ ```
43
+
44
+ or using yarn:
45
+
46
+ ```sh
47
+ yarn add flow-parser --dev
48
+ ```
49
+
50
+ ### Usage
51
+
52
+ The plugin can be enabled via:
53
+
54
+ ```
55
+ // babel.config.json
56
+ {
57
+ "plugins": ["flow-parser/babel-plugin"]
58
+ }
59
+ ```
60
+
61
+ If parser options need to be provide you can do so via the `parserOpts` config:
62
+
63
+ ```
64
+ // babel.config.json
65
+ {
66
+ "plugins": ["flow-parser/babel-plugin"],
67
+ "parserOpts": {
68
+ "allowReturnOutsideFunction": true
69
+ }
70
+ }
71
+ ```
@@ -12,6 +12,12 @@ function _interopRequireDefault(e) {
12
12
  default: e
13
13
  };
14
14
  }
15
+ function asWireNode(value) {
16
+ if (value == null || typeof value !== 'object') {
17
+ return null;
18
+ }
19
+ return value;
20
+ }
15
21
  let FlowParserWASM;
16
22
  let flowParse;
17
23
  let flowParseResult_free;
@@ -22,6 +28,7 @@ let flowParseResult_getProgramBuffer;
22
28
  let flowParseResult_getPositionBuffer;
23
29
  let flowParseResult_getPositionBufferSize;
24
30
  let flowParseResult_getStringBuffer;
31
+ const BABEL_LOWERING_ERROR_PREFIX = '$FlowBabelLoweringError$';
25
32
  function initFlowParserWASM() {
26
33
  if (FlowParserWASM != null) {
27
34
  return;
@@ -31,7 +38,7 @@ function initFlowParserWASM() {
31
38
  throw toThrow;
32
39
  }
33
40
  });
34
- flowParse = FlowParserWASM.cwrap('hermesParse', 'number', ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);
41
+ flowParse = FlowParserWASM.cwrap('hermesParse', 'number', ['number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number', 'number']);
35
42
  flowParseResult_free = FlowParserWASM.cwrap('hermesParseResult_free', 'void', ['number']);
36
43
  flowParseResult_getError = FlowParserWASM.cwrap('hermesParseResult_getError', 'string', ['number']);
37
44
  flowParseResult_getErrorLine = FlowParserWASM.cwrap('hermesParseResult_getErrorLine', 'number', ['number']);
@@ -58,6 +65,7 @@ function parse(source, options) {
58
65
  let filenameLen = 0;
59
66
  let parseResult = 0;
60
67
  try {
68
+ var _options$transformOpt, _options$transformOpt2, _options$transformOpt3, _options$transformOpt4;
61
69
  sourceAddr = FlowParserWASM._malloc(sourceBuffer.length + 1);
62
70
  if (!sourceAddr) {
63
71
  throw new Error('Parser out of memory');
@@ -73,7 +81,28 @@ function parse(source, options) {
73
81
  copyToHeap(sourceBuffer, sourceAddr);
74
82
  const enableTypes = options.enableTypes === false ? 0 : 1;
75
83
  const sourceTypeCode = options.sourceType === 'script' ? 1 : options.sourceType === 'module' ? 2 : 0;
76
- parseResult = flowParse(sourceAddr, sourceBuffer.length + 1, filenameAddr, filenameLen, flag(options.enableExperimentalComponentSyntax), flag(options.enableExperimentalFlowMatchSyntax), flag(options.enableExperimentalDecorators), flag(options.tokens), flag(options.allowReturnOutsideFunction), flag(options.assertOperator), flag(options.enableEnums), flag(options.enableRecords), enableTypes, sourceTypeCode, flag(options.enableTypesPragmaDetection), 0);
84
+ parseResult = flowParse(sourceAddr, sourceBuffer.length + 1, filenameAddr, filenameLen, flag(options.enableExperimentalComponentSyntax), flag(options.enableExperimentalFlowMatchSyntax), flag(options.enableExperimentalDecorators), flag(options.tokens), flag(options.allowReturnOutsideFunction), flag(options.assertOperator), flag(options.enableEnums), flag(options.enableRecords), enableTypes, sourceTypeCode, flag(options.enableTypesPragmaDetection), 0, flag(options.babel), flag((_options$transformOpt = options.transformOptions) == null ? void 0 : (_options$transformOpt2 = _options$transformOpt.TransformEnumSyntax) == null ? void 0 : _options$transformOpt2.enable), flag(((_options$transformOpt3 = options.transformOptions) == null ? void 0 : (_options$transformOpt4 = _options$transformOpt3.TransformEnumSyntax) == null ? void 0 : _options$transformOpt4.getRuntime) != null), options.reactRuntimeTarget === '19' ? 19 : 18, options.throwOnParseErrors === false ? 0 : 1);
85
+ if (options.babel === true) {
86
+ const error = flowParseResult_getError(parseResult);
87
+ const line = flowParseResult_getErrorLine(parseResult);
88
+ const column = flowParseResult_getErrorColumn(parseResult);
89
+ if (error != null && error.startsWith(BABEL_LOWERING_ERROR_PREFIX)) {
90
+ const syntaxError = new SyntaxError(error.slice(BABEL_LOWERING_ERROR_PREFIX.length));
91
+ syntaxError.loc = {
92
+ line,
93
+ column
94
+ };
95
+ throw syntaxError;
96
+ }
97
+ if (error != null && error.length > 0 && options.throwOnParseErrors !== false) {
98
+ const syntaxError = new SyntaxError(`${error} (${line}:${column})`);
99
+ syntaxError.loc = {
100
+ line,
101
+ column
102
+ };
103
+ throw syntaxError;
104
+ }
105
+ }
77
106
  const programBuffer = flowParseResult_getProgramBuffer(parseResult);
78
107
  if (!programBuffer) {
79
108
  const err = flowParseResult_getError(parseResult);
@@ -84,19 +113,25 @@ function parse(source, options) {
84
113
  };
85
114
  throw syntaxError;
86
115
  }
87
- const deserializer = new _FlowParserDeserializer.default(programBuffer, flowParseResult_getPositionBuffer(parseResult), flowParseResult_getPositionBufferSize(parseResult), flowParseResult_getStringBuffer(parseResult), FlowParserWASM, options);
88
- const ast = deserializer.deserialize();
89
- if (ast.type !== 'Program') {
90
- throw new Error(`Expected Program, got ${ast.type}`);
116
+ const deserialized = new _FlowParserDeserializer.default(programBuffer, flowParseResult_getPositionBuffer(parseResult), flowParseResult_getPositionBufferSize(parseResult), flowParseResult_getStringBuffer(parseResult), FlowParserWASM, options).deserialize();
117
+ if (options.babel === true) {
118
+ if (deserialized.type !== 'File') {
119
+ throw new Error(`Expected File, got ${deserialized.type}`);
120
+ }
121
+ return deserialized;
122
+ }
123
+ if (deserialized.type !== 'Program') {
124
+ throw new Error(`Expected Program, got ${deserialized.type}`);
91
125
  }
126
+ const ast = deserialized;
92
127
  const sourceFilename = typeof options.sourceFilename === 'string' ? options.sourceFilename : null;
93
128
  const visitedNodes = new WeakSet();
94
129
  const locRanges = new WeakMap();
95
130
  function fixLocs(node) {
96
- if (node == null || typeof node !== 'object') {
131
+ const wireNode = asWireNode(node);
132
+ if (wireNode == null) {
97
133
  return;
98
134
  }
99
- const wireNode = node;
100
135
  if (visitedNodes.has(wireNode)) {
101
136
  return;
102
137
  }
@@ -168,8 +203,7 @@ function parse(source, options) {
168
203
  }
169
204
  }
170
205
  function asProgram(ast) {
171
- const program = ast;
172
- return program;
206
+ return ast;
173
207
  }
174
208
  function detectSourceType(program) {
175
209
  if (!Array.isArray(program.body)) {
@@ -14,6 +14,7 @@ import type {Program} from 'flow-estree';
14
14
  import type {ParserOptions} from './ParserOptions';
15
15
  import type {FlowParserProgram} from './FlowParserDeserializer';
16
16
  import type {FlowParserWASM as FlowParserWASMType} from './FlowParserWASM';
17
+ import type {BabelFile} from './babel/BabelAST';
17
18
 
18
19
  import FlowParserDeserializer from './FlowParserDeserializer';
19
20
  import FlowParserWASMModule from './FlowParserWASM';
@@ -36,6 +37,11 @@ type FlowParse = (
36
37
  number,
37
38
  number,
38
39
  number,
40
+ number,
41
+ number,
42
+ number,
43
+ number,
44
+ number,
39
45
  ) => number;
40
46
 
41
47
  type WireSourceLocation = {
@@ -53,6 +59,15 @@ type WireNode = {
53
59
  [string]: unknown,
54
60
  };
55
61
 
62
+ function asWireNode(value: unknown): ?WireNode {
63
+ if (value == null || typeof value !== 'object') {
64
+ return null;
65
+ }
66
+ // $FlowExpectedError[incompatible-type] Dynamic binary-schema envelope.
67
+ // $FlowExpectedError[incompatible-variance] Dynamic binary-schema envelope.
68
+ return value;
69
+ }
70
+
56
71
  let FlowParserWASM: FlowParserWASMType;
57
72
  let flowParse: FlowParse;
58
73
  let flowParseResult_free: number => void;
@@ -64,6 +79,8 @@ let flowParseResult_getPositionBuffer: number => number;
64
79
  let flowParseResult_getPositionBufferSize: number => number;
65
80
  let flowParseResult_getStringBuffer: number => number;
66
81
 
82
+ const BABEL_LOWERING_ERROR_PREFIX = '$FlowBabelLoweringError$';
83
+
67
84
  /**
68
85
  * Init the WASM wrapper code generated by `emscripten` for the
69
86
  * Flow Rust parser WASM binary.
@@ -113,6 +130,11 @@ function initFlowParserWASM(): void {
113
130
  'number',
114
131
  'number',
115
132
  'number',
133
+ 'number',
134
+ 'number',
135
+ 'number',
136
+ 'number',
137
+ 'number',
116
138
  ]);
117
139
 
118
140
  flowParseResult_free = FlowParserWASM.cwrap(
@@ -178,7 +200,7 @@ function flag(v: unknown): 0 | 1 {
178
200
  return v === true ? 1 : 0;
179
201
  }
180
202
 
181
- function parse(source: string, options: ParserOptions): Program {
203
+ function parse(source: string, options: ParserOptions): Program | BabelFile {
182
204
  initFlowParserWASM();
183
205
 
184
206
  const sourceBuffer = Buffer.from(source, 'utf8');
@@ -265,8 +287,37 @@ function parse(source: string, options: ParserOptions): Program {
265
287
  // `enableTypes` directly.
266
288
  flag(options.enableTypesPragmaDetection),
267
289
  0,
290
+ flag(options.babel),
291
+ flag(options.transformOptions?.TransformEnumSyntax?.enable),
292
+ flag(options.transformOptions?.TransformEnumSyntax?.getRuntime != null),
293
+ options.reactRuntimeTarget === '19' ? 19 : 18,
294
+ options.throwOnParseErrors === false ? 0 : 1,
268
295
  );
269
296
 
297
+ if (options.babel === true) {
298
+ const error = flowParseResult_getError(parseResult);
299
+ const line = flowParseResult_getErrorLine(parseResult);
300
+ const column = flowParseResult_getErrorColumn(parseResult);
301
+ if (error?.startsWith(BABEL_LOWERING_ERROR_PREFIX)) {
302
+ const syntaxError = new SyntaxError(
303
+ error.slice(BABEL_LOWERING_ERROR_PREFIX.length),
304
+ );
305
+ // $FlowExpectedError[prop-missing] SyntaxError loc is a parser extension.
306
+ syntaxError.loc = {line, column};
307
+ throw syntaxError;
308
+ }
309
+ if (
310
+ error != null &&
311
+ error.length > 0 &&
312
+ options.throwOnParseErrors !== false
313
+ ) {
314
+ const syntaxError = new SyntaxError(`${error} (${line}:${column})`);
315
+ // $FlowExpectedError[prop-missing] SyntaxError loc is a parser extension.
316
+ syntaxError.loc = {line, column};
317
+ throw syntaxError;
318
+ }
319
+ }
320
+
270
321
  // The Rust parser always returns a (possibly partial) AST plus an
271
322
  // error list, mirroring the OCaml behaviour. Errors are surfaced as
272
323
  // `program.errors` by the deserializer; only fall back to throwing if
@@ -283,18 +334,24 @@ function parse(source: string, options: ParserOptions): Program {
283
334
  throw syntaxError;
284
335
  }
285
336
 
286
- const deserializer = new FlowParserDeserializer(
337
+ const deserialized = new FlowParserDeserializer(
287
338
  programBuffer,
288
339
  flowParseResult_getPositionBuffer(parseResult),
289
340
  flowParseResult_getPositionBufferSize(parseResult),
290
341
  flowParseResult_getStringBuffer(parseResult),
291
342
  FlowParserWASM,
292
343
  options,
293
- );
294
- const ast = deserializer.deserialize();
295
- if (ast.type !== 'Program') {
296
- throw new Error(`Expected Program, got ${ast.type}`);
344
+ ).deserialize();
345
+ if (options.babel === true) {
346
+ if (deserialized.type !== 'File') {
347
+ throw new Error(`Expected File, got ${deserialized.type}`);
348
+ }
349
+ return deserialized;
350
+ }
351
+ if (deserialized.type !== 'Program') {
352
+ throw new Error(`Expected Program, got ${deserialized.type}`);
297
353
  }
354
+ const ast = deserialized;
298
355
 
299
356
  // Wire→ESTree loc/range normalization. The wire format carries
300
357
  // `rangeStart` / `rangeEnd` on the loc object; ESTree consumers expect a
@@ -318,12 +375,10 @@ function parse(source: string, options: ParserOptions): Program {
318
375
  const locRanges: WeakMap<WireSourceLocation, [number, number]> =
319
376
  new WeakMap();
320
377
  function fixLocs(node: unknown): void {
321
- if (node == null || typeof node !== 'object') {
378
+ const wireNode = asWireNode(node);
379
+ if (wireNode == null) {
322
380
  return;
323
381
  }
324
- // $FlowFixMe[incompatible-variance] Dynamic ESTree serializer object.
325
- // $FlowFixMe[incompatible-type] Dynamic ESTree serializer object.
326
- const wireNode: WireNode = node;
327
382
  if (visitedNodes.has(wireNode)) {
328
383
  return;
329
384
  }
@@ -423,8 +478,8 @@ function asProgram(ast: FlowParserProgram): Program {
423
478
  // FlowParserProgram is the deserialized wire shape. `fixLocs` above mutates
424
479
  // that shape into the public ESTree Program shape, including loc/range
425
480
  // fields that Flow cannot prove from the serializer protocol.
426
- const program: $FlowFixMe = ast;
427
- return program;
481
+ // $FlowExpectedError[incompatible-type] Normalized binary-schema boundary.
482
+ return ast;
428
483
  }
429
484
 
430
485
  function detectSourceType(program: FlowParserProgram): 'script' | 'module' {
@@ -11,6 +11,7 @@ function _interopRequireDefault(e) {
11
11
  default: e
12
12
  };
13
13
  }
14
+ const LOCATION_IDENTIFIER_NAME = 1 << 0;
14
15
  class FlowParserDeserializer {
15
16
  constructor(programBuffer, positionBuffer, positionBufferSize, stringBufferBase, wasmParser, options) {
16
17
  this.programBufferIdx = void 0;
@@ -18,10 +19,13 @@ class FlowParserDeserializer {
18
19
  this.positionBufferSize = void 0;
19
20
  this.stringBufferBase = void 0;
20
21
  this.locMap = void 0;
22
+ this.extendedPositions = void 0;
23
+ this.extendedRanges = void 0;
21
24
  this.HEAPU8 = void 0;
22
25
  this.HEAPU32 = void 0;
23
26
  this.HEAPF64 = void 0;
24
27
  this.options = void 0;
28
+ this.extendedLocationHeaders = void 0;
25
29
  this.commentTypes = ['Block', 'Line'];
26
30
  this.tokenTypes = ['Boolean', 'Identifier', 'Keyword', 'Null', 'Numeric', 'BigInt', 'Punctuator', 'String', 'RegularExpression', 'Template', 'JSXText'];
27
31
  this.programBufferIdx = programBuffer / 4;
@@ -29,21 +33,36 @@ class FlowParserDeserializer {
29
33
  this.positionBufferSize = positionBufferSize;
30
34
  this.stringBufferBase = stringBufferBase;
31
35
  this.locMap = {};
36
+ this.extendedPositions = [];
37
+ this.extendedRanges = new WeakMap();
32
38
  this.HEAPU8 = wasmParser.HEAPU8;
33
39
  this.HEAPU32 = wasmParser.HEAPU32;
34
40
  this.HEAPF64 = wasmParser.HEAPF64;
35
41
  this.options = options;
42
+ this.extendedLocationHeaders = false;
36
43
  }
37
44
  next() {
38
45
  const num = this.HEAPU32[this.programBufferIdx++];
39
46
  return num;
40
47
  }
41
48
  deserialize() {
49
+ if (this.HEAPU32[this.programBufferIdx] === 0) {
50
+ return this.deserializeESTreeProgram();
51
+ }
52
+ this.extendedLocationHeaders = true;
53
+ this.prepareExtendedPositions();
54
+ const root = this.deserializeNode();
55
+ if (root == null) {
56
+ throw new Error('Expected serialized parser root');
57
+ }
58
+ return root;
59
+ }
60
+ deserializeESTreeProgram() {
42
61
  const program = {
43
62
  type: 'Program',
44
63
  loc: this.addEmptyLoc(),
45
64
  body: this.deserializeNodeList(),
46
- comments: this.deserializeComments()
65
+ comments: this.deserializeESTreeComments()
47
66
  };
48
67
  program.interpreter = this.deserializeNode();
49
68
  if (this.options.tokens === true) {
@@ -98,8 +117,15 @@ class FlowParserDeserializer {
98
117
  if (nodeType === 0) {
99
118
  return null;
100
119
  }
101
- const nodeDeserializer = _FlowParserNodeDeserializers.default[nodeType - 1].bind(this);
102
- return nodeDeserializer();
120
+ const deserializeNode = _FlowParserNodeDeserializers.default[nodeType - 1];
121
+ if (deserializeNode == null) {
122
+ throw new Error(`Unknown serialized node kind ${nodeType - 1} at program word ${this.programBufferIdx - 1}`);
123
+ }
124
+ const node = deserializeNode.call(this);
125
+ if (this.extendedLocationHeaders) {
126
+ this.addExtendedRange(node);
127
+ }
128
+ return node;
103
129
  }
104
130
  deserializeNodeList() {
105
131
  const size = this.next();
@@ -109,18 +135,44 @@ class FlowParserDeserializer {
109
135
  }
110
136
  return nodeList;
111
137
  }
138
+ deserializeEnumRuntime() {
139
+ var _this$options$transfo, _this$options$transfo2;
140
+ const getRuntime = (_this$options$transfo = this.options.transformOptions) == null ? void 0 : (_this$options$transfo2 = _this$options$transfo.TransformEnumSyntax) == null ? void 0 : _this$options$transfo2.getRuntime;
141
+ if (typeof getRuntime !== 'function') {
142
+ throw new Error('Expected TransformEnumSyntax.getRuntime callback');
143
+ }
144
+ return getRuntime();
145
+ }
112
146
  deserializeComments() {
113
147
  const size = this.next();
114
148
  const comments = [];
115
149
  for (let i = 0; i < size; i++) {
116
- const commentType = this.commentTypes[this.next()];
150
+ const commentType = this.deserializeString();
151
+ if (commentType == null) {
152
+ throw new Error('Expected serialized comment type');
153
+ }
117
154
  const loc = this.addEmptyLoc();
118
- const value = this.deserializeString();
119
- comments.push({
155
+ const comment = {
120
156
  type: commentType,
121
157
  loc,
122
- value
123
- });
158
+ value: this.deserializeString()
159
+ };
160
+ this.addExtendedRange(comment);
161
+ comments.push(comment);
162
+ }
163
+ return comments;
164
+ }
165
+ deserializeESTreeComments() {
166
+ const size = this.next();
167
+ const comments = [];
168
+ for (let i = 0; i < size; i++) {
169
+ const commentType = this.commentTypes[this.next()];
170
+ const comment = {
171
+ type: commentType,
172
+ loc: this.addEmptyLoc(),
173
+ value: this.deserializeString()
174
+ };
175
+ comments.push(comment);
124
176
  }
125
177
  return comments;
126
178
  }
@@ -131,19 +183,78 @@ class FlowParserDeserializer {
131
183
  const tokenType = this.tokenTypes[this.next()];
132
184
  const loc = this.addEmptyLoc();
133
185
  const value = this.deserializeString();
134
- tokens.push({
186
+ const token = {
135
187
  type: tokenType,
136
188
  loc,
137
189
  value
138
- });
190
+ };
191
+ tokens.push(token);
139
192
  }
140
193
  return tokens;
141
194
  }
142
195
  addEmptyLoc() {
196
+ const locId = this.next();
197
+ if (this.extendedLocationHeaders) {
198
+ const flags = this.next();
199
+ const position = this.extendedPositions[locId];
200
+ if (position == null) {
201
+ throw new Error(`Missing serialized extended location ${locId}`);
202
+ }
203
+ const loc = position.loc;
204
+ if (flags & LOCATION_IDENTIFIER_NAME) {
205
+ const identifierName = this.deserializeString();
206
+ if (identifierName != null) {
207
+ loc.identifierName = identifierName;
208
+ }
209
+ }
210
+ this.extendedRanges.set(loc, position);
211
+ return loc;
212
+ }
143
213
  const loc = {};
144
- this.locMap[this.next()] = loc;
214
+ this.locMap[locId] = loc;
145
215
  return loc;
146
216
  }
217
+ prepareExtendedPositions() {
218
+ let index = this.positionBufferIdx;
219
+ for (let i = 0; i < this.positionBufferSize; i++) {
220
+ var _this$extendedPositio;
221
+ const locId = this.HEAPU32[index++];
222
+ const kind = this.HEAPU32[index++];
223
+ const line = this.HEAPU32[index++];
224
+ const column = this.HEAPU32[index++];
225
+ const offset = this.HEAPU32[index++];
226
+ const position = (_this$extendedPositio = this.extendedPositions[locId]) != null ? _this$extendedPositio : {
227
+ loc: {},
228
+ start: 0,
229
+ end: 0
230
+ };
231
+ if (kind === 0) {
232
+ position.loc.start = {
233
+ line,
234
+ column
235
+ };
236
+ position.start = offset;
237
+ } else {
238
+ position.loc.end = {
239
+ line,
240
+ column
241
+ };
242
+ position.end = offset;
243
+ }
244
+ this.extendedPositions[locId] = position;
245
+ }
246
+ }
247
+ addExtendedRange(owner) {
248
+ if (owner.loc == null) {
249
+ return;
250
+ }
251
+ const position = this.extendedRanges.get(owner.loc);
252
+ if (position == null) {
253
+ return;
254
+ }
255
+ owner.start = position.start;
256
+ owner.end = position.end;
257
+ }
147
258
  fillLocs() {
148
259
  for (let i = 0; i < this.positionBufferSize; i++) {
149
260
  const locId = this.HEAPU32[this.positionBufferIdx++];
@@ -152,6 +263,9 @@ class FlowParserDeserializer {
152
263
  const column = this.HEAPU32[this.positionBufferIdx++];
153
264
  const offset = this.HEAPU32[this.positionBufferIdx++];
154
265
  const loc = this.locMap[locId];
266
+ if (loc == null) {
267
+ throw new Error(`Missing serialized location ${locId}`);
268
+ }
155
269
  if (kind === 0) {
156
270
  loc.start = {
157
271
  line,