oxc-parser 0.73.2 → 0.75.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/index.d.ts CHANGED
@@ -189,6 +189,14 @@ export interface ParserOptions {
189
189
  * The type of the file is determined from `lang` option, or extension of provided `filename`.
190
190
  */
191
191
  astType?: 'js' | 'ts'
192
+ /**
193
+ * Controls whether the `range` property is included on AST nodes.
194
+ * The `range` property is a `[number, number]` which indicates the start/end offsets
195
+ * of the node in the file contents.
196
+ *
197
+ * @default false
198
+ */
199
+ range?: boolean
192
200
  /**
193
201
  * Emit `ParenthesizedExpression` and `TSParenthesizedType` in AST.
194
202
  *
package/index.js CHANGED
@@ -2,13 +2,9 @@
2
2
 
3
3
  const bindings = require('./bindings.js');
4
4
  const { wrap } = require('./wrap.cjs');
5
- const {
6
- parseSyncRaw,
7
- parseAsyncRaw,
8
- parseSyncLazy,
9
- parseAsyncLazy,
10
- rawTransferSupported,
11
- } = require('./raw-transfer/index.js');
5
+ const rawTransferSupported = require('./raw-transfer/supported.js');
6
+
7
+ const { parseSync: parseSyncBinding, parseAsync: parseAsyncBinding } = bindings;
12
8
 
13
9
  module.exports.ParseResult = bindings.ParseResult;
14
10
  module.exports.ExportExportNameKind = bindings.ExportExportNameKind;
@@ -18,16 +14,97 @@ module.exports.ImportNameKind = bindings.ImportNameKind;
18
14
  module.exports.parseWithoutReturn = bindings.parseWithoutReturn;
19
15
  module.exports.Severity = bindings.Severity;
20
16
 
21
- module.exports.parseAsync = async function parseAsync(filename, sourceText, options) {
22
- if (options?.experimentalRawTransfer) return await parseAsyncRaw(filename, sourceText, options);
23
- if (options?.experimentalLazy) return await parseAsyncLazy(filename, sourceText, options);
24
- return wrap(await bindings.parseAsync(filename, sourceText, options));
25
- };
17
+ module.exports.parseSync = parseSync;
18
+ module.exports.parseAsync = parseAsync;
19
+ module.exports.experimentalGetLazyVisitor = experimentalGetLazyVisitor;
20
+ module.exports.rawTransferSupported = rawTransferSupported;
26
21
 
27
- module.exports.parseSync = function parseSync(filename, sourceText, options) {
28
- if (options?.experimentalRawTransfer) return parseSyncRaw(filename, sourceText, options);
29
- if (options?.experimentalLazy) return parseSyncLazy(filename, sourceText, options);
30
- return wrap(bindings.parseSync(filename, sourceText, options));
31
- };
22
+ // Lazily loaded as needed
23
+ let parseSyncRaw = null,
24
+ parseAsyncRaw,
25
+ parseSyncLazy = null,
26
+ parseAsyncLazy,
27
+ Visitor;
32
28
 
33
- module.exports.rawTransferSupported = rawTransferSupported;
29
+ /**
30
+ * Lazy-load code related to raw transfer.
31
+ * @returns {undefined}
32
+ */
33
+ function loadRawTransfer() {
34
+ if (parseSyncRaw === null) {
35
+ ({ parseSyncRaw, parseAsyncRaw } = require('./raw-transfer/eager.js'));
36
+ }
37
+ }
38
+
39
+ /**
40
+ * Lazy-load code related to raw transfer lazy deserialization.
41
+ * @returns {undefined}
42
+ */
43
+ function loadRawTransferLazy() {
44
+ if (parseSyncLazy === null) {
45
+ ({ parseSyncLazy, parseAsyncLazy, Visitor } = require('./raw-transfer/lazy.js'));
46
+ }
47
+ }
48
+
49
+ /**
50
+ * Parse JS/TS source synchronously on current thread.
51
+ *
52
+ * @param {string} filename - Filename
53
+ * @param {string} sourceText - Source text of file
54
+ * @param {Object|undefined} options - Parsing options
55
+ * @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`
56
+ * @throws {Error} - If `experimentalRawTransfer` or `experimentalLazy` option is enabled,
57
+ * and raw transfer is not supported on this platform
58
+ */
59
+ function parseSync(filename, sourceText, options) {
60
+ if (options?.experimentalRawTransfer) {
61
+ loadRawTransfer();
62
+ return parseSyncRaw(filename, sourceText, options);
63
+ }
64
+ if (options?.experimentalLazy) {
65
+ loadRawTransferLazy();
66
+ return parseSyncLazy(filename, sourceText, options);
67
+ }
68
+ return wrap(parseSyncBinding(filename, sourceText, options));
69
+ }
70
+
71
+ /**
72
+ * Parse JS/TS source asynchronously on a separate thread.
73
+ *
74
+ * Note that not all of the workload can happen on a separate thread.
75
+ * Parsing on Rust side does happen in a separate thread, but deserialization of the AST to JS objects
76
+ * has to happen on current thread. This synchronous deserialization work typically outweighs
77
+ * the asynchronous parsing by a factor of between 3 and 20.
78
+ *
79
+ * i.e. the majority of the workload cannot be parallelized by using this method.
80
+ *
81
+ * Generally `parseSync` is preferable to use as it does not have the overhead of spawning a thread.
82
+ * If you need to parallelize parsing multiple files, it is recommended to use worker threads.
83
+ *
84
+ * @param {string} filename - Filename
85
+ * @param {string} sourceText - Source text of file
86
+ * @param {Object|undefined} options - Parsing options
87
+ * @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`
88
+ * @throws {Error} - If `experimentalRawTransfer` or `experimentalLazy` option is enabled,
89
+ * and raw transfer is not supported on this platform
90
+ */
91
+ async function parseAsync(filename, sourceText, options) {
92
+ if (options?.experimentalRawTransfer) {
93
+ loadRawTransfer();
94
+ return await parseAsyncRaw(filename, sourceText, options);
95
+ }
96
+ if (options?.experimentalLazy) {
97
+ loadRawTransferLazy();
98
+ return await parseAsyncLazy(filename, sourceText, options);
99
+ }
100
+ return wrap(await parseAsyncBinding(filename, sourceText, options));
101
+ }
102
+
103
+ /**
104
+ * Get `Visitor` class to construct visitors with.
105
+ * @returns {function} - `Visitor` class
106
+ */
107
+ function experimentalGetLazyVisitor() {
108
+ loadRawTransferLazy();
109
+ return Visitor;
110
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "oxc-parser",
3
- "version": "0.73.2",
3
+ "version": "0.75.0",
4
4
  "main": "index.js",
5
5
  "browser": "wasm.mjs",
6
6
  "engines": {
@@ -34,28 +34,32 @@
34
34
  "generated/deserialize/js.js",
35
35
  "generated/deserialize/ts.js",
36
36
  "generated/deserialize/lazy.js",
37
- "raw-transfer/index.js",
37
+ "generated/deserialize/lazy-types.js",
38
+ "generated/deserialize/lazy-visit.js",
39
+ "raw-transfer/common.js",
38
40
  "raw-transfer/eager.js",
39
41
  "raw-transfer/lazy.js",
40
42
  "raw-transfer/lazy-common.js",
41
- "raw-transfer/node-array.js"
43
+ "raw-transfer/node-array.js",
44
+ "raw-transfer/supported.js",
45
+ "raw-transfer/visitor.js"
42
46
  ],
43
47
  "publishConfig": {
44
48
  "registry": "https://registry.npmjs.org/",
45
49
  "access": "public"
46
50
  },
47
51
  "dependencies": {
48
- "@oxc-project/types": "^0.73.2"
52
+ "@oxc-project/types": "^0.75.0"
49
53
  },
50
54
  "devDependencies": {
51
55
  "@codspeed/vitest-plugin": "^4.0.0",
52
56
  "@napi-rs/wasm-runtime": "^0.2.7",
53
- "@vitest/browser": "3.2.3",
57
+ "@vitest/browser": "3.2.4",
54
58
  "esbuild": "^0.25.0",
55
59
  "playwright": "^1.51.0",
56
60
  "tinypool": "^1.1.0",
57
61
  "typescript": "5.8.3",
58
- "vitest": "3.2.3"
62
+ "vitest": "3.2.4"
59
63
  },
60
64
  "napi": {
61
65
  "binaryName": "parser",
@@ -85,21 +89,21 @@
85
89
  "dtsHeaderFile": "header.js"
86
90
  },
87
91
  "optionalDependencies": {
88
- "@oxc-parser/binding-win32-x64-msvc": "0.73.2",
89
- "@oxc-parser/binding-win32-arm64-msvc": "0.73.2",
90
- "@oxc-parser/binding-linux-x64-gnu": "0.73.2",
91
- "@oxc-parser/binding-linux-x64-musl": "0.73.2",
92
- "@oxc-parser/binding-freebsd-x64": "0.73.2",
93
- "@oxc-parser/binding-linux-arm64-gnu": "0.73.2",
94
- "@oxc-parser/binding-linux-arm64-musl": "0.73.2",
95
- "@oxc-parser/binding-linux-arm-gnueabihf": "0.73.2",
96
- "@oxc-parser/binding-linux-arm-musleabihf": "0.73.2",
97
- "@oxc-parser/binding-linux-s390x-gnu": "0.73.2",
98
- "@oxc-parser/binding-linux-riscv64-gnu": "0.73.2",
99
- "@oxc-parser/binding-darwin-x64": "0.73.2",
100
- "@oxc-parser/binding-darwin-arm64": "0.73.2",
101
- "@oxc-parser/binding-android-arm64": "0.73.2",
102
- "@oxc-parser/binding-wasm32-wasi": "0.73.2"
92
+ "@oxc-parser/binding-win32-x64-msvc": "0.75.0",
93
+ "@oxc-parser/binding-win32-arm64-msvc": "0.75.0",
94
+ "@oxc-parser/binding-linux-x64-gnu": "0.75.0",
95
+ "@oxc-parser/binding-linux-x64-musl": "0.75.0",
96
+ "@oxc-parser/binding-freebsd-x64": "0.75.0",
97
+ "@oxc-parser/binding-linux-arm64-gnu": "0.75.0",
98
+ "@oxc-parser/binding-linux-arm64-musl": "0.75.0",
99
+ "@oxc-parser/binding-linux-arm-gnueabihf": "0.75.0",
100
+ "@oxc-parser/binding-linux-arm-musleabihf": "0.75.0",
101
+ "@oxc-parser/binding-linux-s390x-gnu": "0.75.0",
102
+ "@oxc-parser/binding-linux-riscv64-gnu": "0.75.0",
103
+ "@oxc-parser/binding-darwin-x64": "0.75.0",
104
+ "@oxc-parser/binding-darwin-arm64": "0.75.0",
105
+ "@oxc-parser/binding-android-arm64": "0.75.0",
106
+ "@oxc-parser/binding-wasm32-wasi": "0.75.0"
103
107
  },
104
108
  "scripts": {
105
109
  "build-dev": "napi build --platform --js bindings.js",
@@ -1,10 +1,14 @@
1
1
  'use strict';
2
2
 
3
3
  const os = require('node:os');
4
- const bindings = require('../bindings.js');
4
+ const rawTransferSupported = require('./supported.js');
5
+ const {
6
+ parseSyncRaw: parseSyncRawBinding,
7
+ parseAsyncRaw: parseAsyncRawBinding,
8
+ getBufferOffset,
9
+ } = require('../bindings.js');
5
10
 
6
11
  module.exports = {
7
- rawTransferSupported,
8
12
  parseSyncRawImpl,
9
13
  parseAsyncRawImpl,
10
14
  prepareRaw,
@@ -12,19 +16,24 @@ module.exports = {
12
16
  returnBufferToCache,
13
17
  };
14
18
 
15
- // Import `eager.js` and `lazy.js` after the exports above, because of circular dependencies
16
- const { parseSyncRaw, parseAsyncRaw } = require('./eager.js');
17
- module.exports.parseSyncRaw = parseSyncRaw;
18
- module.exports.parseAsyncRaw = parseAsyncRaw;
19
-
20
- const { parseSyncLazy, parseAsyncLazy } = require('./lazy.js');
21
- module.exports.parseSyncLazy = parseSyncLazy;
22
- module.exports.parseAsyncLazy = parseAsyncLazy;
23
-
24
- function parseSyncRawImpl(filename, sourceText, options, deserialize) {
25
- const { buffer, sourceByteLen, options: optionsAmended } = prepareRaw(sourceText, options);
26
- bindings.parseSyncRaw(filename, buffer, sourceByteLen, optionsAmended);
27
- return deserialize(buffer, sourceText, sourceByteLen);
19
+ /**
20
+ * Parse JS/TS source synchronously on current thread using raw transfer.
21
+ *
22
+ * Convert the buffer returned by Rust to a JS object with provided `convert` function.
23
+ *
24
+ * This function contains logic shared by both `parseSyncRaw` and `parseSyncLazy`.
25
+ *
26
+ * @param {string} filename - Filename
27
+ * @param {string} sourceText - Source text of file
28
+ * @param {Object|undefined} options - Parsing options
29
+ * @param {function} convert - Function to convert the buffer returned from Rust into a JS object
30
+ * @returns {Object} - The return value of `convert`
31
+ * @throws {Error} - If raw transfer is not supported on this platform
32
+ */
33
+ function parseSyncRawImpl(filename, sourceText, options, convert) {
34
+ const { buffer, sourceByteLen } = prepareRaw(sourceText);
35
+ parseSyncRawBinding(filename, buffer, sourceByteLen, options);
36
+ return convert(buffer, sourceText, sourceByteLen);
28
37
  }
29
38
 
30
39
  // User should not schedule more async tasks than there are available CPUs, as it hurts performance,
@@ -65,7 +74,23 @@ function parseSyncRawImpl(filename, sourceText, options, deserialize) {
65
74
  let availableCores = os.availableParallelism ? os.availableParallelism() : os.cpus().length;
66
75
  const queue = [];
67
76
 
68
- async function parseAsyncRawImpl(filename, sourceText, options, deserialize) {
77
+ /**
78
+ * Parse JS/TS source asynchronously using raw transfer.
79
+ *
80
+ * Convert the buffer returned by Rust to a JS object with provided `convert` function.
81
+ *
82
+ * Queues up parsing operations if more calls than number of CPU cores (see above).
83
+ *
84
+ * This function contains logic shared by both `parseAsyncRaw` and `parseAsyncLazy`.
85
+ *
86
+ * @param {string} filename - Filename
87
+ * @param {string} sourceText - Source text of file
88
+ * @param {Object|undefined} options - Parsing options
89
+ * @param {function} convert - Function to convert the buffer returned from Rust into a JS object
90
+ * @returns {Object} - The return value of `convert`
91
+ * @throws {Error} - If raw transfer is not supported on this platform
92
+ */
93
+ async function parseAsyncRawImpl(filename, sourceText, options, convert) {
69
94
  // Wait for a free CPU core if all CPUs are currently busy.
70
95
  //
71
96
  // Note: `availableCores` is NOT decremented if have to wait in the queue first,
@@ -87,9 +112,9 @@ async function parseAsyncRawImpl(filename, sourceText, options, deserialize) {
87
112
  }
88
113
 
89
114
  // Parse
90
- const { buffer, sourceByteLen, options: optionsAmended } = prepareRaw(sourceText, options);
91
- await bindings.parseAsyncRaw(filename, buffer, sourceByteLen, optionsAmended);
92
- const ret = deserialize(buffer, sourceText, sourceByteLen);
115
+ const { buffer, sourceByteLen } = prepareRaw(sourceText);
116
+ await parseAsyncRawBinding(filename, buffer, sourceByteLen, options);
117
+ const data = convert(buffer, sourceText, sourceByteLen);
93
118
 
94
119
  // Free the CPU core
95
120
  if (queue.length > 0) {
@@ -102,7 +127,7 @@ async function parseAsyncRawImpl(filename, sourceText, options, deserialize) {
102
127
  availableCores++;
103
128
  }
104
129
 
105
- return ret;
130
+ return data;
106
131
  }
107
132
 
108
133
  const ONE_GIB = 1 << 30,
@@ -140,22 +165,29 @@ const ONE_GIB = 1 << 30,
140
165
  // point creating a new buffer, when one already exists.
141
166
  const CLEAR_BUFFERS_TIMEOUT = 10_000; // 10 seconds
142
167
  const buffers = [], oldBuffers = [];
143
-
144
- let encoder = null, clearBuffersTimeout = null;
145
-
146
- // Get a buffer (from cache if possible), copy source text into it, and amend options object
147
- function prepareRaw(sourceText, options) {
168
+ let clearBuffersTimeout = null;
169
+
170
+ const textEncoder = new TextEncoder();
171
+
172
+ /**
173
+ * Get a buffer (from cache if possible), and copy source text into it.
174
+ *
175
+ * @param {string} sourceText - Source text of file
176
+ * @returns {Object} - Object of form `{ buffer, sourceByteLen }`.
177
+ * - `buffer`: `Uint8Array` containing the AST in raw form.
178
+ * - `sourceByteLen`: Length of source text in UTF-8 bytes
179
+ * (which may not be equal to `sourceText.length` if source contains non-ASCII characters).
180
+ * @throws {Error} - If raw transfer is not supported on this platform
181
+ */
182
+ function prepareRaw(sourceText) {
148
183
  if (!rawTransferSupported()) {
149
184
  throw new Error(
150
- '`experimentalRawTransfer` option is not supported on 32-bit or big-endian systems, ' +
151
- 'versions of NodeJS prior to v22.0.0, versions of Deno prior to v2.0.0, and other runtimes',
185
+ '`experimentalRawTransfer` and `experimentalLazy` options are not supported ' +
186
+ 'on 32-bit or big-endian systems, versions of NodeJS prior to v22.0.0, ' +
187
+ 'versions of Deno prior to v2.0.0, or other runtimes',
152
188
  );
153
189
  }
154
190
 
155
- // Delete `experimentalRawTransfer` and `experimentalLazy` options
156
- let _;
157
- ({ experimentalRawTransfer: _, experimentalLazy: _, ...options } = options);
158
-
159
191
  // Cancel timeout for clearing buffers
160
192
  if (clearBuffersTimeout !== null) {
161
193
  clearTimeout(clearBuffersTimeout);
@@ -176,29 +208,36 @@ function prepareRaw(sourceText, options) {
176
208
  // Reuse existing buffer, or create a new one
177
209
  const buffer = buffers.length > 0 ? buffers.pop() : createBuffer();
178
210
 
179
- // Get/create `TextEncoder`
180
- if (encoder === null) encoder = new TextEncoder();
181
-
182
211
  // Write source into start of buffer.
183
212
  // `TextEncoder` cannot write into a `Uint8Array` larger than 1 GiB,
184
213
  // so create a view into buffer of this size to write into.
185
214
  const sourceBuffer = new Uint8Array(buffer.buffer, buffer.byteOffset, ONE_GIB);
186
- const { read, written: sourceByteLen } = encoder.encodeInto(sourceText, sourceBuffer);
215
+ const { read, written: sourceByteLen } = textEncoder.encodeInto(sourceText, sourceBuffer);
187
216
  if (read !== sourceText.length) throw new Error('Failed to write source text into buffer');
188
217
 
189
- return { buffer, sourceByteLen, options };
218
+ return { buffer, sourceByteLen };
190
219
  }
191
220
 
192
- // Get if AST should be parsed as JS or TS.
193
- // Rust side sets a `bool` in this position in buffer which is `true` if TS.
221
+ /**
222
+ * Get if AST should be parsed as JS or TS.
223
+ * Rust side sets a `bool` in this position in buffer which is `true` if TS.
224
+ *
225
+ * @param {Uint8Array} buffer - Buffer containing AST in raw form
226
+ * @returns {boolean} - `true` if AST is JS, `false` if TS
227
+ */
194
228
  function isJsAst(buffer) {
195
229
  // 2147483636 = (2 * 1024 * 1024 * 1024) - 12
196
230
  // i.e. 12 bytes from end of 2 GiB buffer
197
231
  return buffer[2147483636] === 0;
198
232
  }
199
233
 
200
- // Return buffer to cache, to be reused.
201
- // Set a timer to clear buffers.
234
+ /**
235
+ * Return buffer to cache, to be reused.
236
+ * Set a timer to clear buffers.
237
+ *
238
+ * @param {Uint8Array} buffer - Buffer
239
+ * @returns {undefined}
240
+ */
202
241
  function returnBufferToCache(buffer) {
203
242
  buffers.push(buffer);
204
243
 
@@ -207,8 +246,12 @@ function returnBufferToCache(buffer) {
207
246
  clearBuffersTimeout.unref();
208
247
  }
209
248
 
210
- // Downgrade buffers in tier 1 cache (`buffers`) to tier 2 (`oldBuffers`),
211
- // so they can be garbage collected
249
+ /**
250
+ * Downgrade buffers in tier 1 cache (`buffers`) to tier 2 (`oldBuffers`)
251
+ * so they can be garbage collected.
252
+ *
253
+ * @returns {undefined}
254
+ */
212
255
  function clearBuffersCache() {
213
256
  clearBuffersTimeout = null;
214
257
 
@@ -218,66 +261,26 @@ function clearBuffersCache() {
218
261
  buffers.length = 0;
219
262
  }
220
263
 
221
- // Create a `Uint8Array` which is 2 GiB in size, with its start aligned on 4 GiB.
222
- //
223
- // Achieve this by creating a 6 GiB `ArrayBuffer`, getting the offset within it that's aligned to 4 GiB,
224
- // chopping off that number of bytes from the start, and shortening to 2 GiB.
225
- //
226
- // It's always possible to obtain a 2 GiB slice aligned on 4 GiB within a 6 GiB buffer,
227
- // no matter how the 6 GiB buffer is aligned.
228
- //
229
- // Note: On systems with virtual memory, this only consumes 6 GiB of *virtual* memory.
230
- // It does not consume physical memory until data is actually written to the `Uint8Array`.
231
- // Physical memory consumed corresponds to the quantity of data actually written.
264
+ /**
265
+ * Create a `Uint8Array` which is 2 GiB in size, with its start aligned on 4 GiB.
266
+ *
267
+ * Achieve this by creating a 6 GiB `ArrayBuffer`, getting the offset within it that's aligned to 4 GiB,
268
+ * chopping off that number of bytes from the start, and shortening to 2 GiB.
269
+ *
270
+ * It's always possible to obtain a 2 GiB slice aligned on 4 GiB within a 6 GiB buffer,
271
+ * no matter how the 6 GiB buffer is aligned.
272
+ *
273
+ * Note: On systems with virtual memory, this only consumes 6 GiB of *virtual* memory.
274
+ * It does not consume physical memory until data is actually written to the `Uint8Array`.
275
+ * Physical memory consumed corresponds to the quantity of data actually written.
276
+ *
277
+ * @returns {Uint8Array} - Buffer
278
+ */
232
279
  function createBuffer() {
233
280
  const arrayBuffer = new ArrayBuffer(SIX_GIB);
234
- const offset = bindings.getBufferOffset(new Uint8Array(arrayBuffer));
281
+ const offset = getBufferOffset(new Uint8Array(arrayBuffer));
235
282
  const buffer = new Uint8Array(arrayBuffer, offset, TWO_GIB);
236
283
  buffer.uint32 = new Uint32Array(arrayBuffer, offset, TWO_GIB / 4);
237
284
  buffer.float64 = new Float64Array(arrayBuffer, offset, TWO_GIB / 8);
238
285
  return buffer;
239
286
  }
240
-
241
- let rawTransferIsSupported = null;
242
-
243
- // Returns `true` if `experimentalRawTransfer` is option is supported.
244
- //
245
- // Raw transfer is only supported on 64-bit little-endian systems,
246
- // and NodeJS >= v22.0.0 or Deno >= v2.0.0.
247
- //
248
- // Versions of NodeJS prior to v22.0.0 do not support creating an `ArrayBuffer` larger than 4 GiB.
249
- // Bun (as at v1.2.4) also does not support creating an `ArrayBuffer` larger than 4 GiB.
250
- // Support on Deno v1 is unknown and it's EOL, so treating Deno before v2.0.0 as unsupported.
251
- function rawTransferSupported() {
252
- if (rawTransferIsSupported === null) {
253
- rawTransferIsSupported = rawTransferRuntimeSupported() && bindings.rawTransferSupported();
254
- }
255
- return rawTransferIsSupported;
256
- }
257
-
258
- // Checks copied from:
259
- // https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/src/runtimes.ts
260
- // MIT license: https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/LICENCE
261
- function rawTransferRuntimeSupported() {
262
- let global;
263
- try {
264
- global = globalThis;
265
- } catch (e) {
266
- return false;
267
- }
268
-
269
- const isBun = !!global.Bun || !!global.process?.versions?.bun;
270
- if (isBun) return false;
271
-
272
- const isDeno = !!global.Deno;
273
- if (isDeno) {
274
- const match = Deno.version?.deno?.match(/^(\d+)\./);
275
- return !!match && match[1] * 1 >= 2;
276
- }
277
-
278
- const isNode = global.process?.release?.name === 'node';
279
- if (!isNode) return false;
280
-
281
- const match = process.version?.match(/^v(\d+)\./);
282
- return !!match && match[1] * 1 >= 22;
283
- }
@@ -1,20 +1,59 @@
1
1
  'use strict';
2
2
 
3
- const { parseSyncRawImpl, parseAsyncRawImpl, isJsAst, returnBufferToCache } = require('./index.js');
3
+ const { parseSyncRawImpl, parseAsyncRawImpl, isJsAst, returnBufferToCache } = require('./common.js');
4
4
 
5
5
  module.exports = { parseSyncRaw, parseAsyncRaw };
6
6
 
7
+ /**
8
+ * Parse JS/TS source synchronously on current thread, using raw transfer to speed up deserialization.
9
+ *
10
+ * @param {string} filename - Filename
11
+ * @param {string} sourceText - Source text of file
12
+ * @param {Object} options - Parsing options
13
+ * @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`
14
+ * @throws {Error} - If raw transfer is not supported on this platform
15
+ */
7
16
  function parseSyncRaw(filename, sourceText, options) {
17
+ let _;
18
+ ({ experimentalRawTransfer: _, ...options } = options);
8
19
  return parseSyncRawImpl(filename, sourceText, options, deserialize);
9
20
  }
10
21
 
22
+ /**
23
+ * Parse JS/TS source asynchronously, using raw transfer to speed up deserialization.
24
+ *
25
+ * Note that not all of the workload can happen on a separate thread.
26
+ * Parsing on Rust side does happen in a separate thread, but deserialization of the AST to JS objects
27
+ * has to happen on current thread. This synchronous deserialization work typically outweighs
28
+ * the asynchronous parsing by a factor of around 3.
29
+ *
30
+ * i.e. the majority of the workload cannot be parallelized by using this method.
31
+ *
32
+ * Generally `parseSyncRaw` is preferable to use as it does not have the overhead of spawning a thread.
33
+ * If you need to parallelize parsing multiple files, it is recommended to use worker threads.
34
+ *
35
+ * @param {string} filename - Filename
36
+ * @param {string} sourceText - Source text of file
37
+ * @param {Object} options - Parsing options
38
+ * @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`
39
+ * @throws {Error} - If raw transfer is not supported on this platform
40
+ */
11
41
  function parseAsyncRaw(filename, sourceText, options) {
42
+ let _;
43
+ ({ experimentalRawTransfer: _, ...options } = options);
12
44
  return parseAsyncRawImpl(filename, sourceText, options, deserialize);
13
45
  }
14
46
 
15
47
  let deserializeJS = null, deserializeTS = null;
16
48
 
17
- // Deserialize whole AST from buffer eagerly
49
+ /**
50
+ * Deserialize whole AST from buffer.
51
+ *
52
+ * @param {Uint8Array} buffer - Buffer containing AST in raw form
53
+ * @param {string} sourceText - Source for the file
54
+ * @param {number} sourceByteLen - Length of source text in UTF-8 bytes
55
+ * @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`
56
+ */
18
57
  function deserialize(buffer, sourceText, sourceByteLen) {
19
58
  // Lazy load deserializer, and deserialize buffer to JS objects
20
59
  let data;
@@ -38,7 +77,7 @@ function deserialize(buffer, sourceText, sourceByteLen) {
38
77
  returnBufferToCache(buffer);
39
78
 
40
79
  // We cannot lazily deserialize in the getters, because the buffer might be re-used to parse
41
- // another file before the getter is called.
80
+ // another file before the getter is called
42
81
  return {
43
82
  get program() {
44
83
  return data.program;
@@ -4,7 +4,10 @@
4
4
  // Used to prevent user calling class constructors.
5
5
  const TOKEN = {};
6
6
 
7
- // Throw error when restricted class constructor is called by user code.
7
+ /**
8
+ * Throw error when restricted class constructor is called by user code.
9
+ * @throws {Error}
10
+ */
8
11
  function constructorError() {
9
12
  throw new Error('Constructor is for internal use only');
10
13
  }