oxc-parser 0.72.3 → 0.73.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/generated/deserialize/js.js +4 -146
- package/generated/deserialize/lazy.js +13853 -0
- package/generated/deserialize/ts.js +4 -146
- package/index.js +11 -288
- package/package.json +26 -21
- package/raw-transfer/eager.js +56 -0
- package/raw-transfer/index.js +283 -0
- package/raw-transfer/lazy.js +87 -0
|
@@ -13,8 +13,8 @@ const textDecoder = new TextDecoder('utf-8', { ignoreBOM: true }),
|
|
|
13
13
|
|
|
14
14
|
function deserialize(buffer, sourceTextInput, sourceLenInput) {
|
|
15
15
|
uint8 = buffer;
|
|
16
|
-
uint32 =
|
|
17
|
-
float64 =
|
|
16
|
+
uint32 = buffer.uint32;
|
|
17
|
+
float64 = buffer.float64;
|
|
18
18
|
|
|
19
19
|
sourceText = sourceTextInput;
|
|
20
20
|
sourceLen = sourceLenInput;
|
|
@@ -1223,14 +1223,13 @@ function deserializeStringLiteral(pos) {
|
|
|
1223
1223
|
}
|
|
1224
1224
|
|
|
1225
1225
|
function deserializeBigIntLiteral(pos) {
|
|
1226
|
-
const
|
|
1227
|
-
bigint = raw.slice(0, -1).replace(/_/g, '');
|
|
1226
|
+
const bigint = deserializeStr(pos + 8);
|
|
1228
1227
|
return {
|
|
1229
1228
|
type: 'Literal',
|
|
1230
1229
|
start: deserializeU32(pos),
|
|
1231
1230
|
end: deserializeU32(pos + 4),
|
|
1232
1231
|
value: BigInt(bigint),
|
|
1233
|
-
raw,
|
|
1232
|
+
raw: deserializeOptionStr(pos + 24),
|
|
1234
1233
|
bigint,
|
|
1235
1234
|
};
|
|
1236
1235
|
}
|
|
@@ -4236,11 +4235,6 @@ function deserializeVecStatement(pos) {
|
|
|
4236
4235
|
return arr;
|
|
4237
4236
|
}
|
|
4238
4237
|
|
|
4239
|
-
function deserializeOptionScopeId(pos) {
|
|
4240
|
-
if (uint32[pos >> 2] === 0) return null;
|
|
4241
|
-
return deserializeScopeId(pos);
|
|
4242
|
-
}
|
|
4243
|
-
|
|
4244
4238
|
function deserializeBoxBooleanLiteral(pos) {
|
|
4245
4239
|
return deserializeBooleanLiteral(uint32[pos >> 2]);
|
|
4246
4240
|
}
|
|
@@ -4401,16 +4395,6 @@ function deserializeBoxV8IntrinsicExpression(pos) {
|
|
|
4401
4395
|
return deserializeV8IntrinsicExpression(uint32[pos >> 2]);
|
|
4402
4396
|
}
|
|
4403
4397
|
|
|
4404
|
-
function deserializeOptionReferenceId(pos) {
|
|
4405
|
-
if (uint32[pos >> 2] === 0) return null;
|
|
4406
|
-
return deserializeReferenceId(pos);
|
|
4407
|
-
}
|
|
4408
|
-
|
|
4409
|
-
function deserializeOptionSymbolId(pos) {
|
|
4410
|
-
if (uint32[pos >> 2] === 0) return null;
|
|
4411
|
-
return deserializeSymbolId(pos);
|
|
4412
|
-
}
|
|
4413
|
-
|
|
4414
4398
|
function deserializeVecArrayExpressionElement(pos) {
|
|
4415
4399
|
const arr = [],
|
|
4416
4400
|
pos32 = pos >> 2,
|
|
@@ -5016,15 +5000,6 @@ function deserializeF64(pos) {
|
|
|
5016
5000
|
return float64[pos >> 3];
|
|
5017
5001
|
}
|
|
5018
5002
|
|
|
5019
|
-
function deserializeBoxPattern(pos) {
|
|
5020
|
-
return deserializePattern(uint32[pos >> 2]);
|
|
5021
|
-
}
|
|
5022
|
-
|
|
5023
|
-
function deserializeOptionBoxPattern(pos) {
|
|
5024
|
-
if (uint32[pos >> 2] === 0 && uint32[(pos + 4) >> 2] === 0) return null;
|
|
5025
|
-
return deserializeBoxPattern(pos);
|
|
5026
|
-
}
|
|
5027
|
-
|
|
5028
5003
|
function deserializeU8(pos) {
|
|
5029
5004
|
return uint8[pos];
|
|
5030
5005
|
}
|
|
@@ -5413,74 +5388,6 @@ function deserializeOptionNameSpan(pos) {
|
|
|
5413
5388
|
return deserializeNameSpan(pos);
|
|
5414
5389
|
}
|
|
5415
5390
|
|
|
5416
|
-
function deserializeVecAlternative(pos) {
|
|
5417
|
-
const arr = [],
|
|
5418
|
-
pos32 = pos >> 2,
|
|
5419
|
-
len = uint32[pos32 + 2];
|
|
5420
|
-
pos = uint32[pos32];
|
|
5421
|
-
for (let i = 0; i < len; i++) {
|
|
5422
|
-
arr.push(deserializeAlternative(pos));
|
|
5423
|
-
pos += 32;
|
|
5424
|
-
}
|
|
5425
|
-
return arr;
|
|
5426
|
-
}
|
|
5427
|
-
|
|
5428
|
-
function deserializeVecTerm(pos) {
|
|
5429
|
-
const arr = [],
|
|
5430
|
-
pos32 = pos >> 2,
|
|
5431
|
-
len = uint32[pos32 + 2];
|
|
5432
|
-
pos = uint32[pos32];
|
|
5433
|
-
for (let i = 0; i < len; i++) {
|
|
5434
|
-
arr.push(deserializeTerm(pos));
|
|
5435
|
-
pos += 16;
|
|
5436
|
-
}
|
|
5437
|
-
return arr;
|
|
5438
|
-
}
|
|
5439
|
-
|
|
5440
|
-
function deserializeBoxBoundaryAssertion(pos) {
|
|
5441
|
-
return deserializeBoundaryAssertion(uint32[pos >> 2]);
|
|
5442
|
-
}
|
|
5443
|
-
|
|
5444
|
-
function deserializeBoxLookAroundAssertion(pos) {
|
|
5445
|
-
return deserializeLookAroundAssertion(uint32[pos >> 2]);
|
|
5446
|
-
}
|
|
5447
|
-
|
|
5448
|
-
function deserializeBoxQuantifier(pos) {
|
|
5449
|
-
return deserializeQuantifier(uint32[pos >> 2]);
|
|
5450
|
-
}
|
|
5451
|
-
|
|
5452
|
-
function deserializeBoxCharacter(pos) {
|
|
5453
|
-
return deserializeCharacter(uint32[pos >> 2]);
|
|
5454
|
-
}
|
|
5455
|
-
|
|
5456
|
-
function deserializeBoxCharacterClassEscape(pos) {
|
|
5457
|
-
return deserializeCharacterClassEscape(uint32[pos >> 2]);
|
|
5458
|
-
}
|
|
5459
|
-
|
|
5460
|
-
function deserializeBoxUnicodePropertyEscape(pos) {
|
|
5461
|
-
return deserializeUnicodePropertyEscape(uint32[pos >> 2]);
|
|
5462
|
-
}
|
|
5463
|
-
|
|
5464
|
-
function deserializeBoxCharacterClass(pos) {
|
|
5465
|
-
return deserializeCharacterClass(uint32[pos >> 2]);
|
|
5466
|
-
}
|
|
5467
|
-
|
|
5468
|
-
function deserializeBoxCapturingGroup(pos) {
|
|
5469
|
-
return deserializeCapturingGroup(uint32[pos >> 2]);
|
|
5470
|
-
}
|
|
5471
|
-
|
|
5472
|
-
function deserializeBoxIgnoreGroup(pos) {
|
|
5473
|
-
return deserializeIgnoreGroup(uint32[pos >> 2]);
|
|
5474
|
-
}
|
|
5475
|
-
|
|
5476
|
-
function deserializeBoxIndexedReference(pos) {
|
|
5477
|
-
return deserializeIndexedReference(uint32[pos >> 2]);
|
|
5478
|
-
}
|
|
5479
|
-
|
|
5480
|
-
function deserializeBoxNamedReference(pos) {
|
|
5481
|
-
return deserializeNamedReference(uint32[pos >> 2]);
|
|
5482
|
-
}
|
|
5483
|
-
|
|
5484
5391
|
function deserializeU64(pos) {
|
|
5485
5392
|
const pos32 = pos >> 2;
|
|
5486
5393
|
return uint32[pos32] + uint32[pos32 + 1] * 4294967296;
|
|
@@ -5491,55 +5398,6 @@ function deserializeOptionU64(pos) {
|
|
|
5491
5398
|
return deserializeU64(pos + 8);
|
|
5492
5399
|
}
|
|
5493
5400
|
|
|
5494
|
-
function deserializeVecCharacterClassContents(pos) {
|
|
5495
|
-
const arr = [],
|
|
5496
|
-
pos32 = pos >> 2,
|
|
5497
|
-
len = uint32[pos32 + 2];
|
|
5498
|
-
pos = uint32[pos32];
|
|
5499
|
-
for (let i = 0; i < len; i++) {
|
|
5500
|
-
arr.push(deserializeCharacterClassContents(pos));
|
|
5501
|
-
pos += 16;
|
|
5502
|
-
}
|
|
5503
|
-
return arr;
|
|
5504
|
-
}
|
|
5505
|
-
|
|
5506
|
-
function deserializeBoxCharacterClassRange(pos) {
|
|
5507
|
-
return deserializeCharacterClassRange(uint32[pos >> 2]);
|
|
5508
|
-
}
|
|
5509
|
-
|
|
5510
|
-
function deserializeBoxClassStringDisjunction(pos) {
|
|
5511
|
-
return deserializeClassStringDisjunction(uint32[pos >> 2]);
|
|
5512
|
-
}
|
|
5513
|
-
|
|
5514
|
-
function deserializeVecClassString(pos) {
|
|
5515
|
-
const arr = [],
|
|
5516
|
-
pos32 = pos >> 2,
|
|
5517
|
-
len = uint32[pos32 + 2];
|
|
5518
|
-
pos = uint32[pos32];
|
|
5519
|
-
for (let i = 0; i < len; i++) {
|
|
5520
|
-
arr.push(deserializeClassString(pos));
|
|
5521
|
-
pos += 40;
|
|
5522
|
-
}
|
|
5523
|
-
return arr;
|
|
5524
|
-
}
|
|
5525
|
-
|
|
5526
|
-
function deserializeVecCharacter(pos) {
|
|
5527
|
-
const arr = [],
|
|
5528
|
-
pos32 = pos >> 2,
|
|
5529
|
-
len = uint32[pos32 + 2];
|
|
5530
|
-
pos = uint32[pos32];
|
|
5531
|
-
for (let i = 0; i < len; i++) {
|
|
5532
|
-
arr.push(deserializeCharacter(pos));
|
|
5533
|
-
pos += 16;
|
|
5534
|
-
}
|
|
5535
|
-
return arr;
|
|
5536
|
-
}
|
|
5537
|
-
|
|
5538
|
-
function deserializeOptionModifiers(pos) {
|
|
5539
|
-
if (uint8[pos] === 0) return null;
|
|
5540
|
-
return deserializeModifiers(pos + 8);
|
|
5541
|
-
}
|
|
5542
|
-
|
|
5543
5401
|
function deserializeVecError(pos) {
|
|
5544
5402
|
const arr = [],
|
|
5545
5403
|
pos32 = pos >> 2,
|
package/index.js
CHANGED
|
@@ -1,6 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
2
3
|
const bindings = require('./bindings.js');
|
|
3
4
|
const { wrap } = require('./wrap.cjs');
|
|
5
|
+
const {
|
|
6
|
+
parseSyncRaw,
|
|
7
|
+
parseAsyncRaw,
|
|
8
|
+
parseSyncLazy,
|
|
9
|
+
parseAsyncLazy,
|
|
10
|
+
rawTransferSupported,
|
|
11
|
+
} = require('./raw-transfer/index.js');
|
|
4
12
|
|
|
5
13
|
module.exports.ParseResult = bindings.ParseResult;
|
|
6
14
|
module.exports.ExportExportNameKind = bindings.ExportExportNameKind;
|
|
@@ -12,299 +20,14 @@ module.exports.Severity = bindings.Severity;
|
|
|
12
20
|
|
|
13
21
|
module.exports.parseAsync = async function parseAsync(filename, sourceText, options) {
|
|
14
22
|
if (options?.experimentalRawTransfer) return await parseAsyncRaw(filename, sourceText, options);
|
|
23
|
+
if (options?.experimentalLazy) return await parseAsyncLazy(filename, sourceText, options);
|
|
15
24
|
return wrap(await bindings.parseAsync(filename, sourceText, options));
|
|
16
25
|
};
|
|
17
26
|
|
|
18
27
|
module.exports.parseSync = function parseSync(filename, sourceText, options) {
|
|
19
28
|
if (options?.experimentalRawTransfer) return parseSyncRaw(filename, sourceText, options);
|
|
29
|
+
if (options?.experimentalLazy) return parseSyncLazy(filename, sourceText, options);
|
|
20
30
|
return wrap(bindings.parseSync(filename, sourceText, options));
|
|
21
31
|
};
|
|
22
32
|
|
|
23
|
-
function parseSyncRaw(filename, sourceText, options) {
|
|
24
|
-
const { buffer, sourceByteLen, options: optionsAmended } = prepareRaw(sourceText, options);
|
|
25
|
-
bindings.parseSyncRaw(filename, buffer, sourceByteLen, optionsAmended);
|
|
26
|
-
return deserialize(buffer, sourceText, sourceByteLen);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
// User should not schedule more async tasks than there are available CPUs, as it hurts performance,
|
|
30
|
-
// but it's a common mistake in async JS code to do exactly that.
|
|
31
|
-
//
|
|
32
|
-
// That anti-pattern looks like this when applied to Oxc:
|
|
33
|
-
//
|
|
34
|
-
// ```js
|
|
35
|
-
// const asts = await Promise.all(
|
|
36
|
-
// files.map(
|
|
37
|
-
// async (filename) => {
|
|
38
|
-
// const sourceText = await fs.readFile(filename, 'utf8');
|
|
39
|
-
// const ast = await oxc.parseAsync(filename, sourceText);
|
|
40
|
-
// return ast;
|
|
41
|
-
// }
|
|
42
|
-
// )
|
|
43
|
-
// );
|
|
44
|
-
// ```
|
|
45
|
-
//
|
|
46
|
-
// In most cases, that'd just result in a bit of degraded performance, and higher memory use because
|
|
47
|
-
// of loading sources into memory prematurely.
|
|
48
|
-
//
|
|
49
|
-
// However, raw transfer uses a 6 GiB buffer for each parsing operation.
|
|
50
|
-
// Most of the memory pages in those buffers are never touched, so this does not consume a huge amount
|
|
51
|
-
// of physical memory, but it does still consume virtual memory.
|
|
52
|
-
//
|
|
53
|
-
// If we allowed creating a large number of 6 GiB buffers simultaneously, it would quickly consume
|
|
54
|
-
// virtual memory space and risk memory exhaustion. The code above would exhaust all of bottom half
|
|
55
|
-
// (heap) of 48-bit virtual memory space if `files.length >= 21_845`. This is not a number which
|
|
56
|
-
// is unrealistic in real world code.
|
|
57
|
-
//
|
|
58
|
-
// To guard against this possibility, we implement a simple queue.
|
|
59
|
-
// No more than `os.availableParallelism()` files can be parsed simultaneously, and any further calls to
|
|
60
|
-
// `parseAsyncRaw` will be put in a queue, to execute once other tasks complete.
|
|
61
|
-
let availableCores = availableParallelism();
|
|
62
|
-
const queue = [];
|
|
63
|
-
|
|
64
|
-
async function parseAsyncRaw(filename, sourceText, options) {
|
|
65
|
-
// Wait for a free CPU core if all CPUs are currently busy.
|
|
66
|
-
//
|
|
67
|
-
// Note: `availableCores` is NOT decremented if have to wait in the queue first,
|
|
68
|
-
// and NOT incremented when parsing completes and it runs next task in the queue.
|
|
69
|
-
//
|
|
70
|
-
// This is to avoid a race condition if `parseAsyncRaw` is called during the microtick in between
|
|
71
|
-
// `resolve` being called below, and the promise resolving here. In that case the new task could
|
|
72
|
-
// start running, and then the promise resolves, and the queued task also starts running.
|
|
73
|
-
// We'd then have `availableParallelism() + 1` tasks running simultaneously. Potentially, this could
|
|
74
|
-
// happen repeatedly, with the number of tasks running simultaneously ever-increasing.
|
|
75
|
-
if (availableCores === 0) {
|
|
76
|
-
// All CPU cores are busy. Put this task in queue and wait for capacity to become available.
|
|
77
|
-
await new Promise((resolve, _) => {
|
|
78
|
-
queue.push(resolve);
|
|
79
|
-
});
|
|
80
|
-
} else {
|
|
81
|
-
// A CPU core is available. Mark core as busy, and run parsing now.
|
|
82
|
-
availableCores--;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
// Parse
|
|
86
|
-
const { buffer, sourceByteLen, options: optionsAmended } = prepareRaw(sourceText, options);
|
|
87
|
-
await bindings.parseAsyncRaw(filename, buffer, sourceByteLen, optionsAmended);
|
|
88
|
-
const ret = deserialize(buffer, sourceText, sourceByteLen);
|
|
89
|
-
|
|
90
|
-
// Free the CPU core
|
|
91
|
-
if (queue.length > 0) {
|
|
92
|
-
// Some further tasks waiting in queue. Run the next one.
|
|
93
|
-
// Do not increment `availableCores` (see above).
|
|
94
|
-
const resolve = queue.shift();
|
|
95
|
-
resolve();
|
|
96
|
-
} else {
|
|
97
|
-
// No tasks waiting in queue. This CPU is now free.
|
|
98
|
-
availableCores++;
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
return ret;
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
const ONE_GIB = 1 << 30,
|
|
105
|
-
TWO_GIB = ONE_GIB * 2,
|
|
106
|
-
SIX_GIB = ONE_GIB * 6;
|
|
107
|
-
|
|
108
|
-
// We keep a cache of buffers for raw transfer, so we can reuse them as much as possible.
|
|
109
|
-
//
|
|
110
|
-
// When processing multiple files, it's ideal if can reuse an existing buffer, as it's more likely to
|
|
111
|
-
// be warm in CPU cache, it avoids allocations, and it saves work for the garbage collector.
|
|
112
|
-
//
|
|
113
|
-
// However, we also don't want to keep a load of large buffers around indefinitely using up memory,
|
|
114
|
-
// if they're not going to be used again.
|
|
115
|
-
//
|
|
116
|
-
// We have no knowledge of what pattern over time user may process files in (could be lots in quick
|
|
117
|
-
// succession, or more occasionally in a long-running process). So we try to use flexible caching
|
|
118
|
-
// strategy which is adaptable to many usage patterns.
|
|
119
|
-
//
|
|
120
|
-
// We use a 2-tier cache.
|
|
121
|
-
// Tier 1 uses strong references, tier 2 uses weak references.
|
|
122
|
-
//
|
|
123
|
-
// When parsing is complete and the buffer is no longer in use, push it to `buffers` (tier 1 cache).
|
|
124
|
-
// Set a timer to clear the cache when no activity for 10 seconds.
|
|
125
|
-
//
|
|
126
|
-
// When the timer expires, move all the buffers from tier 1 cache into `oldBuffers` (tier 2).
|
|
127
|
-
// They are stored there as `WeakRef`s, so the garbage collector is free to reclaim them.
|
|
128
|
-
//
|
|
129
|
-
// On the next call to `parseSync` or `parseAsync`, promote any buffers in tier 2 cache which were not
|
|
130
|
-
// already garbage collected back into tier 1 cache. This is on assumption that parsing one file
|
|
131
|
-
// indicates parsing as a whole is an ongoing process, and there will likely be further calls to
|
|
132
|
-
// `parseSync` / `parseAsync` in future.
|
|
133
|
-
//
|
|
134
|
-
// The weak tier 2 cache is because V8 does not necessarily free memory as soon as it's able to be
|
|
135
|
-
// freed. We don't want to block it from freeing memory, but if it's not done that yet, there's no
|
|
136
|
-
// point creating a new buffer, when one already exists.
|
|
137
|
-
const CLEAR_BUFFERS_TIMEOUT = 10_000; // 10 seconds
|
|
138
|
-
const buffers = [], oldBuffers = [];
|
|
139
|
-
|
|
140
|
-
let encoder = null, deserializeJS = null, deserializeTS = null, clearBuffersTimeout = null;
|
|
141
|
-
|
|
142
|
-
// Get a buffer (from cache if possible), copy source text into it, and amend options object
|
|
143
|
-
function prepareRaw(sourceText, options) {
|
|
144
|
-
if (!rawTransferSupported()) {
|
|
145
|
-
throw new Error(
|
|
146
|
-
'`experimentalRawTransfer` option is not supported on 32-bit or big-endian systems, ' +
|
|
147
|
-
'versions of NodeJS prior to v22.0.0, versions of Deno prior to v2.0.0, and other runtimes',
|
|
148
|
-
);
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
// Delete `experimentalRawTransfer` option
|
|
152
|
-
let _;
|
|
153
|
-
({ experimentalRawTransfer: _, ...options } = options);
|
|
154
|
-
|
|
155
|
-
// Cancel timeout for clearing buffers
|
|
156
|
-
if (clearBuffersTimeout !== null) {
|
|
157
|
-
clearTimeout(clearBuffersTimeout);
|
|
158
|
-
clearBuffersTimeout = null;
|
|
159
|
-
}
|
|
160
|
-
|
|
161
|
-
// Revive any discarded buffers which have not yet been garbage collected
|
|
162
|
-
if (oldBuffers.length > 0) {
|
|
163
|
-
const revivedBuffers = [];
|
|
164
|
-
for (let oldBuffer of oldBuffers) {
|
|
165
|
-
oldBuffer = oldBuffer.deref();
|
|
166
|
-
if (oldBuffer !== undefined) revivedBuffers.push(oldBuffer);
|
|
167
|
-
}
|
|
168
|
-
oldBuffers.length = 0;
|
|
169
|
-
if (revivedBuffers.length > 0) buffers.unshift(...revivedBuffers);
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// Reuse existing buffer, or create a new one
|
|
173
|
-
const buffer = buffers.length > 0 ? buffers.pop() : createBuffer();
|
|
174
|
-
|
|
175
|
-
// Get/create `TextEncoder`
|
|
176
|
-
if (encoder === null) encoder = new TextEncoder();
|
|
177
|
-
|
|
178
|
-
// Write source into start of buffer.
|
|
179
|
-
// `TextEncoder` cannot write into a `Uint8Array` larger than 1 GiB,
|
|
180
|
-
// so create a view into buffer of this size to write into.
|
|
181
|
-
const sourceBuffer = new Uint8Array(buffer.buffer, buffer.byteOffset, ONE_GIB);
|
|
182
|
-
const { read, written: sourceByteLen } = encoder.encodeInto(sourceText, sourceBuffer);
|
|
183
|
-
if (read !== sourceText.length) throw new Error('Failed to write source text into buffer');
|
|
184
|
-
|
|
185
|
-
return { buffer, sourceByteLen, options };
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
// Deserialize AST from buffer
|
|
189
|
-
function deserialize(buffer, sourceText, sourceByteLen) {
|
|
190
|
-
// 2147483636 = (2 * 1024 * 1024 * 1024) - 12
|
|
191
|
-
// i.e. 12 bytes from end of 2 GiB buffer
|
|
192
|
-
const isJsAst = buffer[2147483636] === 0;
|
|
193
|
-
|
|
194
|
-
// Lazy load deserializer, and deserialize buffer to JS objects
|
|
195
|
-
let data;
|
|
196
|
-
if (isJsAst) {
|
|
197
|
-
if (deserializeJS === null) deserializeJS = require('./generated/deserialize/js.js');
|
|
198
|
-
data = deserializeJS(buffer, sourceText, sourceByteLen);
|
|
199
|
-
|
|
200
|
-
// Add a line comment for hashbang
|
|
201
|
-
const { hashbang } = data.program;
|
|
202
|
-
if (hashbang !== null) {
|
|
203
|
-
data.comments.unshift({ type: 'Line', value: hashbang.value, start: hashbang.start, end: hashbang.end });
|
|
204
|
-
}
|
|
205
|
-
} else {
|
|
206
|
-
if (deserializeTS === null) deserializeTS = require('./generated/deserialize/ts.js');
|
|
207
|
-
data = deserializeTS(buffer, sourceText, sourceByteLen);
|
|
208
|
-
// Note: Do not add line comment for hashbang, to match `@typescript-eslint/parser`.
|
|
209
|
-
// See https://github.com/oxc-project/oxc/blob/ea784f5f082e4c53c98afde9bf983afd0b95e44e/napi/parser/src/lib.rs#L106-L130
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
// Return buffer to cache, to be reused
|
|
213
|
-
buffers.push(buffer);
|
|
214
|
-
|
|
215
|
-
// Set timer to clear buffers
|
|
216
|
-
if (clearBuffersTimeout !== null) clearTimeout(clearBuffersTimeout);
|
|
217
|
-
clearBuffersTimeout = setTimeout(clearBuffersCache, CLEAR_BUFFERS_TIMEOUT);
|
|
218
|
-
clearBuffersTimeout.unref();
|
|
219
|
-
|
|
220
|
-
// We cannot lazily deserialize in the getters, because the buffer might be re-used to parse
|
|
221
|
-
// another file before the getter is called.
|
|
222
|
-
return {
|
|
223
|
-
get program() {
|
|
224
|
-
return data.program;
|
|
225
|
-
},
|
|
226
|
-
get module() {
|
|
227
|
-
return data.module;
|
|
228
|
-
},
|
|
229
|
-
get comments() {
|
|
230
|
-
return data.comments;
|
|
231
|
-
},
|
|
232
|
-
get errors() {
|
|
233
|
-
return data.errors;
|
|
234
|
-
},
|
|
235
|
-
};
|
|
236
|
-
}
|
|
237
|
-
|
|
238
|
-
// Downgrade buffers in tier 1 cache (`buffers`) to tier 2 (`oldBuffers`),
|
|
239
|
-
// so they can be garbage collected
|
|
240
|
-
function clearBuffersCache() {
|
|
241
|
-
clearBuffersTimeout = null;
|
|
242
|
-
|
|
243
|
-
for (const buffer of buffers) {
|
|
244
|
-
oldBuffers.push(new WeakRef(buffer));
|
|
245
|
-
}
|
|
246
|
-
buffers.length = 0;
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
// Create a `Uint8Array` which is 2 GiB in size, with its start aligned on 4 GiB.
|
|
250
|
-
//
|
|
251
|
-
// Achieve this by creating a 6 GiB `ArrayBuffer`, getting the offset within it that's aligned to 4 GiB,
|
|
252
|
-
// chopping off that number of bytes from the start, and shortening to 2 GiB.
|
|
253
|
-
//
|
|
254
|
-
// It's always possible to obtain a 2 GiB slice aligned on 4 GiB within a 6 GiB buffer,
|
|
255
|
-
// no matter how the 6 GiB buffer is aligned.
|
|
256
|
-
//
|
|
257
|
-
// Note: On systems with virtual memory, this only consumes 6 GiB of *virtual* memory.
|
|
258
|
-
// It does not consume physical memory until data is actually written to the `Uint8Array`.
|
|
259
|
-
// Physical memory consumed corresponds to the quantity of data actually written.
|
|
260
|
-
function createBuffer() {
|
|
261
|
-
const arrayBuffer = new ArrayBuffer(SIX_GIB);
|
|
262
|
-
const offset = bindings.getBufferOffset(new Uint8Array(arrayBuffer));
|
|
263
|
-
return new Uint8Array(arrayBuffer, offset, TWO_GIB);
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
let rawTransferIsSupported = null;
|
|
267
|
-
|
|
268
|
-
// Returns `true` if `experimentalRawTransfer` is option is supported.
|
|
269
|
-
//
|
|
270
|
-
// Raw transfer is only supported on 64-bit little-endian systems,
|
|
271
|
-
// and NodeJS >= v22.0.0 or Deno >= v2.0.0.
|
|
272
|
-
//
|
|
273
|
-
// Versions of NodeJS prior to v22.0.0 do not support creating an `ArrayBuffer` larger than 4 GiB.
|
|
274
|
-
// Bun (as at v1.2.4) also does not support creating an `ArrayBuffer` larger than 4 GiB.
|
|
275
|
-
// Support on Deno v1 is unknown and it's EOL, so treating Deno before v2.0.0 as unsupported.
|
|
276
|
-
function rawTransferSupported() {
|
|
277
|
-
if (rawTransferIsSupported === null) {
|
|
278
|
-
rawTransferIsSupported = rawTransferRuntimeSupported() && bindings.rawTransferSupported();
|
|
279
|
-
}
|
|
280
|
-
return rawTransferIsSupported;
|
|
281
|
-
}
|
|
282
|
-
|
|
283
33
|
module.exports.rawTransferSupported = rawTransferSupported;
|
|
284
|
-
|
|
285
|
-
// Checks copied from:
|
|
286
|
-
// https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/src/runtimes.ts
|
|
287
|
-
// MIT license: https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/LICENCE
|
|
288
|
-
function rawTransferRuntimeSupported() {
|
|
289
|
-
let global;
|
|
290
|
-
try {
|
|
291
|
-
global = globalThis;
|
|
292
|
-
} catch (e) {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
const isBun = !!global.Bun || !!global.process?.versions?.bun;
|
|
297
|
-
if (isBun) return false;
|
|
298
|
-
|
|
299
|
-
const isDeno = !!global.Deno;
|
|
300
|
-
if (isDeno) {
|
|
301
|
-
const match = Deno.version?.deno?.match(/^(\d+)\./);
|
|
302
|
-
return !!match && match[1] * 1 >= 2;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
const isNode = global.process?.release?.name === 'node';
|
|
306
|
-
if (!isNode) return false;
|
|
307
|
-
|
|
308
|
-
const match = process.version?.match(/^v(\d+)\./);
|
|
309
|
-
return !!match && match[1] * 1 >= 22;
|
|
310
|
-
}
|
package/package.json
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "oxc-parser",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.73.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"browser": "wasm.mjs",
|
|
6
6
|
"engines": {
|
|
7
|
-
"node": ">=
|
|
7
|
+
"node": ">=20.0.0"
|
|
8
8
|
},
|
|
9
9
|
"description": "Oxc Parser Node API",
|
|
10
10
|
"keywords": [
|
|
@@ -32,23 +32,28 @@
|
|
|
32
32
|
"bindings.js",
|
|
33
33
|
"webcontainer-fallback.js",
|
|
34
34
|
"generated/deserialize/js.js",
|
|
35
|
-
"generated/deserialize/ts.js"
|
|
35
|
+
"generated/deserialize/ts.js",
|
|
36
|
+
"generated/deserialize/lazy.js",
|
|
37
|
+
"raw-transfer/index.js",
|
|
38
|
+
"raw-transfer/eager.js",
|
|
39
|
+
"raw-transfer/lazy.js"
|
|
36
40
|
],
|
|
37
41
|
"publishConfig": {
|
|
38
42
|
"registry": "https://registry.npmjs.org/",
|
|
39
43
|
"access": "public"
|
|
40
44
|
},
|
|
41
45
|
"dependencies": {
|
|
42
|
-
"@oxc-project/types": "^0.
|
|
46
|
+
"@oxc-project/types": "^0.73.0"
|
|
43
47
|
},
|
|
44
48
|
"devDependencies": {
|
|
45
49
|
"@codspeed/vitest-plugin": "^4.0.0",
|
|
46
50
|
"@napi-rs/wasm-runtime": "^0.2.7",
|
|
47
|
-
"@vitest/browser": "3.
|
|
51
|
+
"@vitest/browser": "3.2.2",
|
|
48
52
|
"esbuild": "^0.25.0",
|
|
49
53
|
"playwright": "^1.51.0",
|
|
50
|
-
"
|
|
51
|
-
"typescript": "5.8.3"
|
|
54
|
+
"tinypool": "^1.1.0",
|
|
55
|
+
"typescript": "5.8.3",
|
|
56
|
+
"vitest": "3.2.2"
|
|
52
57
|
},
|
|
53
58
|
"napi": {
|
|
54
59
|
"binaryName": "parser",
|
|
@@ -77,20 +82,20 @@
|
|
|
77
82
|
"dtsHeaderFile": "header.js"
|
|
78
83
|
},
|
|
79
84
|
"optionalDependencies": {
|
|
80
|
-
"@oxc-parser/binding-win32-x64-msvc": "0.
|
|
81
|
-
"@oxc-parser/binding-win32-arm64-msvc": "0.
|
|
82
|
-
"@oxc-parser/binding-linux-x64-gnu": "0.
|
|
83
|
-
"@oxc-parser/binding-linux-x64-musl": "0.
|
|
84
|
-
"@oxc-parser/binding-freebsd-x64": "0.
|
|
85
|
-
"@oxc-parser/binding-linux-arm64-gnu": "0.
|
|
86
|
-
"@oxc-parser/binding-linux-arm64-musl": "0.
|
|
87
|
-
"@oxc-parser/binding-linux-arm-gnueabihf": "0.
|
|
88
|
-
"@oxc-parser/binding-linux-arm-musleabihf": "0.
|
|
89
|
-
"@oxc-parser/binding-linux-s390x-gnu": "0.
|
|
90
|
-
"@oxc-parser/binding-linux-riscv64-gnu": "0.
|
|
91
|
-
"@oxc-parser/binding-darwin-x64": "0.
|
|
92
|
-
"@oxc-parser/binding-darwin-arm64": "0.
|
|
93
|
-
"@oxc-parser/binding-wasm32-wasi": "0.
|
|
85
|
+
"@oxc-parser/binding-win32-x64-msvc": "0.73.0",
|
|
86
|
+
"@oxc-parser/binding-win32-arm64-msvc": "0.73.0",
|
|
87
|
+
"@oxc-parser/binding-linux-x64-gnu": "0.73.0",
|
|
88
|
+
"@oxc-parser/binding-linux-x64-musl": "0.73.0",
|
|
89
|
+
"@oxc-parser/binding-freebsd-x64": "0.73.0",
|
|
90
|
+
"@oxc-parser/binding-linux-arm64-gnu": "0.73.0",
|
|
91
|
+
"@oxc-parser/binding-linux-arm64-musl": "0.73.0",
|
|
92
|
+
"@oxc-parser/binding-linux-arm-gnueabihf": "0.73.0",
|
|
93
|
+
"@oxc-parser/binding-linux-arm-musleabihf": "0.73.0",
|
|
94
|
+
"@oxc-parser/binding-linux-s390x-gnu": "0.73.0",
|
|
95
|
+
"@oxc-parser/binding-linux-riscv64-gnu": "0.73.0",
|
|
96
|
+
"@oxc-parser/binding-darwin-x64": "0.73.0",
|
|
97
|
+
"@oxc-parser/binding-darwin-arm64": "0.73.0",
|
|
98
|
+
"@oxc-parser/binding-wasm32-wasi": "0.73.0"
|
|
94
99
|
},
|
|
95
100
|
"scripts": {
|
|
96
101
|
"build-dev": "napi build --platform --js bindings.js",
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const { parseSyncRawImpl, parseAsyncRawImpl, isJsAst, returnBufferToCache } = require('./index.js');
|
|
4
|
+
|
|
5
|
+
module.exports = { parseSyncRaw, parseAsyncRaw };
|
|
6
|
+
|
|
7
|
+
function parseSyncRaw(filename, sourceText, options) {
|
|
8
|
+
return parseSyncRawImpl(filename, sourceText, options, deserialize);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
function parseAsyncRaw(filename, sourceText, options) {
|
|
12
|
+
return parseAsyncRawImpl(filename, sourceText, options, deserialize);
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
let deserializeJS = null, deserializeTS = null;
|
|
16
|
+
|
|
17
|
+
// Deserialize whole AST from buffer eagerly
|
|
18
|
+
function deserialize(buffer, sourceText, sourceByteLen) {
|
|
19
|
+
// Lazy load deserializer, and deserialize buffer to JS objects
|
|
20
|
+
let data;
|
|
21
|
+
if (isJsAst(buffer)) {
|
|
22
|
+
if (deserializeJS === null) deserializeJS = require('../generated/deserialize/js.js');
|
|
23
|
+
data = deserializeJS(buffer, sourceText, sourceByteLen);
|
|
24
|
+
|
|
25
|
+
// Add a line comment for hashbang
|
|
26
|
+
const { hashbang } = data.program;
|
|
27
|
+
if (hashbang !== null) {
|
|
28
|
+
data.comments.unshift({ type: 'Line', value: hashbang.value, start: hashbang.start, end: hashbang.end });
|
|
29
|
+
}
|
|
30
|
+
} else {
|
|
31
|
+
if (deserializeTS === null) deserializeTS = require('../generated/deserialize/ts.js');
|
|
32
|
+
data = deserializeTS(buffer, sourceText, sourceByteLen);
|
|
33
|
+
// Note: Do not add line comment for hashbang, to match `@typescript-eslint/parser`.
|
|
34
|
+
// See https://github.com/oxc-project/oxc/blob/ea784f5f082e4c53c98afde9bf983afd0b95e44e/napi/parser/src/lib.rs#L106-L130
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Return buffer to cache, to be reused
|
|
38
|
+
returnBufferToCache(buffer);
|
|
39
|
+
|
|
40
|
+
// We cannot lazily deserialize in the getters, because the buffer might be re-used to parse
|
|
41
|
+
// another file before the getter is called.
|
|
42
|
+
return {
|
|
43
|
+
get program() {
|
|
44
|
+
return data.program;
|
|
45
|
+
},
|
|
46
|
+
get module() {
|
|
47
|
+
return data.module;
|
|
48
|
+
},
|
|
49
|
+
get comments() {
|
|
50
|
+
return data.comments;
|
|
51
|
+
},
|
|
52
|
+
get errors() {
|
|
53
|
+
return data.errors;
|
|
54
|
+
},
|
|
55
|
+
};
|
|
56
|
+
}
|