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/generated/deserialize/lazy-types.js +194 -0
- package/generated/deserialize/lazy-visit.js +5457 -0
- package/generated/deserialize/lazy.js +410 -11
- package/index.d.ts +8 -0
- package/index.js +95 -18
- package/package.json +25 -21
- package/raw-transfer/{index.js → common.js} +101 -98
- package/raw-transfer/eager.js +42 -3
- package/raw-transfer/lazy-common.js +4 -1
- package/raw-transfer/lazy.js +95 -21
- package/raw-transfer/node-array.js +127 -92
- package/raw-transfer/supported.js +56 -0
- package/raw-transfer/visitor.js +129 -0
package/raw-transfer/lazy.js
CHANGED
|
@@ -1,14 +1,74 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const { parseSyncRawImpl, parseAsyncRawImpl, returnBufferToCache } = require('./
|
|
3
|
+
const { parseSyncRawImpl, parseAsyncRawImpl, returnBufferToCache } = require('./common.js'),
|
|
4
|
+
{ TOKEN } = require('./lazy-common.js'),
|
|
5
|
+
constructLazyData = require('../generated/deserialize/lazy.js').construct,
|
|
6
|
+
walkProgram = require('../generated/deserialize/lazy-visit.js'),
|
|
7
|
+
{ Visitor, getVisitorsArr } = require('./visitor.js');
|
|
4
8
|
|
|
5
|
-
module.exports = { parseSyncLazy, parseAsyncLazy };
|
|
9
|
+
module.exports = { parseSyncLazy, parseAsyncLazy, Visitor };
|
|
6
10
|
|
|
11
|
+
/**
|
|
12
|
+
* Parse JS/TS source synchronously on current thread.
|
|
13
|
+
*
|
|
14
|
+
* The data in buffer is not deserialized. Is deserialized to JS objects lazily, when accessing the
|
|
15
|
+
* properties of objects.
|
|
16
|
+
*
|
|
17
|
+
* e.g. `program` in returned object is an instance of `Program` class, with getters for `start`, `end`,
|
|
18
|
+
* `body` etc.
|
|
19
|
+
*
|
|
20
|
+
* Returned object contains a `visit` function which can be used to visit the AST with a `Visitor`
|
|
21
|
+
* (`Visitor` class can be obtained by calling `experimentalGetLazyVisitor()`).
|
|
22
|
+
*
|
|
23
|
+
* Returned object contains a `dispose` method. When finished with this AST, it's advisable to call
|
|
24
|
+
* `dispose`, to return the buffer to the cache, so it can be reused.
|
|
25
|
+
* Garbage collector should do this anyway at some point, but on an unpredictable schedule,
|
|
26
|
+
* so it's preferable to call `dispose` manually, to ensure the buffer can be reused immediately.
|
|
27
|
+
*
|
|
28
|
+
* @param {string} filename - Filename
|
|
29
|
+
* @param {string} sourceText - Source text of file
|
|
30
|
+
* @param {Object} options - Parsing options
|
|
31
|
+
* @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`,
|
|
32
|
+
* and `dispose` and `visit` methods
|
|
33
|
+
* @throws {Error} - If raw transfer is not supported on this platform
|
|
34
|
+
*/
|
|
7
35
|
function parseSyncLazy(filename, sourceText, options) {
|
|
36
|
+
let _;
|
|
37
|
+
({ experimentalLazy: _, ...options } = options);
|
|
8
38
|
return parseSyncRawImpl(filename, sourceText, options, construct);
|
|
9
39
|
}
|
|
10
40
|
|
|
41
|
+
/**
|
|
42
|
+
* Parse JS/TS source asynchronously on a separate thread.
|
|
43
|
+
*
|
|
44
|
+
* The data in buffer is not deserialized. Is deserialized to JS objects lazily, when accessing the
|
|
45
|
+
* properties of objects.
|
|
46
|
+
*
|
|
47
|
+
* e.g. `program` in returned object is an instance of `Program` class, with getters for `start`, `end`,
|
|
48
|
+
* `body` etc.
|
|
49
|
+
*
|
|
50
|
+
* Because this function does not deserialize the AST, unlike `parseAsyncRaw`, very little work happens
|
|
51
|
+
* on current thread in this function. Deserialization work only occurs when properties of the objects
|
|
52
|
+
* are accessed.
|
|
53
|
+
*
|
|
54
|
+
* Returned object contains a `visit` function which can be used to visit the AST with a `Visitor`
|
|
55
|
+
* (`Visitor` class can be obtained by calling `experimentalGetLazyVisitor()`).
|
|
56
|
+
*
|
|
57
|
+
* Returned object contains a `dispose` method. When finished with this AST, it's advisable to call
|
|
58
|
+
* `dispose`, to return the buffer to the cache, so it can be reused.
|
|
59
|
+
* Garbage collector should do this anyway at some point, but on an unpredictable schedule,
|
|
60
|
+
* so it's preferable to call `dispose` manually, to ensure the buffer can be reused immediately.
|
|
61
|
+
*
|
|
62
|
+
* @param {string} filename - Filename
|
|
63
|
+
* @param {string} sourceText - Source text of file
|
|
64
|
+
* @param {Object} options - Parsing options
|
|
65
|
+
* @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`,
|
|
66
|
+
* and `dispose` and `visit` methods
|
|
67
|
+
* @throws {Error} - If raw transfer is not supported on this platform
|
|
68
|
+
*/
|
|
11
69
|
function parseAsyncLazy(filename, sourceText, options) {
|
|
70
|
+
let _;
|
|
71
|
+
({ experimentalLazy: _, ...options } = options);
|
|
12
72
|
return parseAsyncRawImpl(filename, sourceText, options, construct);
|
|
13
73
|
}
|
|
14
74
|
|
|
@@ -23,15 +83,18 @@ const bufferRecycleRegistry = typeof FinalizationRegistry === 'undefined'
|
|
|
23
83
|
? null
|
|
24
84
|
: new FinalizationRegistry(returnBufferToCache);
|
|
25
85
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
86
|
+
/**
|
|
87
|
+
* Get an object with getters which lazy deserialize AST and other data from buffer.
|
|
88
|
+
*
|
|
89
|
+
* Object also includes `dispose` and `visit` functions.
|
|
90
|
+
*
|
|
91
|
+
* @param {Uint8Array} buffer - Buffer containing AST in raw form
|
|
92
|
+
* @param {string} sourceText - Source for the file
|
|
93
|
+
* @param {number} sourceByteLen - Length of source text in UTF-8 bytes
|
|
94
|
+
* @returns {Object} - Object with property getters for `program`, `module`, `comments`, and `errors`,
|
|
95
|
+
* and `dispose` and `visit` methods
|
|
96
|
+
*/
|
|
29
97
|
function construct(buffer, sourceText, sourceLen) {
|
|
30
|
-
// Lazy load deserializer, and get `TOKEN` to store in `ast` objects
|
|
31
|
-
if (constructLazyData === null) {
|
|
32
|
-
({ construct: constructLazyData, TOKEN } = require('../generated/deserialize/lazy.js'));
|
|
33
|
-
}
|
|
34
|
-
|
|
35
98
|
// Create AST object
|
|
36
99
|
const sourceIsAscii = sourceText.length === sourceLen;
|
|
37
100
|
const ast = { buffer, sourceText, sourceLen, sourceIsAscii, nodes: new Map(), token: TOKEN };
|
|
@@ -57,21 +120,32 @@ function construct(buffer, sourceText, sourceLen) {
|
|
|
57
120
|
return data.errors;
|
|
58
121
|
},
|
|
59
122
|
dispose: dispose.bind(null, ast),
|
|
123
|
+
visit(visitor) {
|
|
124
|
+
// (2 * 1024 * 1024 * 1024 - 16) >> 2
|
|
125
|
+
const metadataPos32 = 536870908;
|
|
126
|
+
const pos = buffer.uint32[metadataPos32];
|
|
127
|
+
walkProgram(pos, ast, getVisitorsArr(visitor));
|
|
128
|
+
},
|
|
60
129
|
};
|
|
61
130
|
}
|
|
62
131
|
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
132
|
+
/**
|
|
133
|
+
* Dispose of this AST.
|
|
134
|
+
*
|
|
135
|
+
* After calling this method, trying to read any nodes from this AST may cause an error.
|
|
136
|
+
*
|
|
137
|
+
* Buffer is returned to the cache to be reused.
|
|
138
|
+
*
|
|
139
|
+
* The buffer would be returned to the cache anyway, once all nodes of the AST are garbage collected,
|
|
140
|
+
* but calling `dispose` is preferable, as it will happen immediately.
|
|
141
|
+
* Otherwise, garbage collector may take time to collect the `ast` object, and new buffers may be created
|
|
142
|
+
* in the meantime, when we could have reused this one.
|
|
143
|
+
*
|
|
144
|
+
* @param {Object} ast - AST object containing buffer etc
|
|
145
|
+
* @returns {undefined}
|
|
146
|
+
*/
|
|
73
147
|
function dispose(ast) {
|
|
74
|
-
// Return buffer to cache to be reused
|
|
148
|
+
// Return buffer to cache, to be reused
|
|
75
149
|
returnBufferToCache(ast.buffer);
|
|
76
150
|
|
|
77
151
|
// Remove connection between `ast` and the buffer
|
|
@@ -2,22 +2,27 @@
|
|
|
2
2
|
|
|
3
3
|
const { TOKEN, constructorError } = require('./lazy-common.js');
|
|
4
4
|
|
|
5
|
-
//
|
|
6
|
-
// Used by `slice`, `values`, `key` and `elements` methods.
|
|
5
|
+
// Internal symbol to get `NodeArray` from a proxy wrapping a `NodeArray`.
|
|
7
6
|
//
|
|
8
|
-
//
|
|
9
|
-
//
|
|
10
|
-
|
|
7
|
+
// Methods of `NodeArray` are called with `this` being the proxy, rather than the `NodeArray` itself.
|
|
8
|
+
// They can "unwrap" the proxy by getting `this[ARRAY]`, and the `get` proxy trap will return
|
|
9
|
+
// the actual `NodeArray`.
|
|
10
|
+
//
|
|
11
|
+
// This symbol is not exported, and it is not actually defined on `NodeArray`s, so user cannot obtain it
|
|
12
|
+
// via `Object.getOwnPropertySymbols` or `Reflect.ownKeys`. Therefore user code cannot unwrap the proxy.
|
|
13
|
+
const ARRAY = Symbol();
|
|
11
14
|
|
|
12
|
-
//
|
|
13
|
-
let getElement;
|
|
15
|
+
// Functions to get internal properties of a `NodeArray`. Initialized in class static block below.
|
|
16
|
+
let getInternalFromProxy, getLength, getElement;
|
|
14
17
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
/**
|
|
19
|
+
* An array of AST nodes where elements are deserialized lazily upon access.
|
|
20
|
+
*
|
|
21
|
+
* Extends `Array` to make `Array.isArray` return `true` for a `NodeArray`.
|
|
22
|
+
*
|
|
23
|
+
* TODO: Other methods could maybe be more optimal, avoiding going via proxy multiple times
|
|
24
|
+
* e.g. `some`, `indexOf`.
|
|
25
|
+
*/
|
|
21
26
|
class NodeArray extends Array {
|
|
22
27
|
#internal;
|
|
23
28
|
|
|
@@ -39,12 +44,9 @@ class NodeArray extends Array {
|
|
|
39
44
|
constructor(pos, length, stride, construct, ast) {
|
|
40
45
|
if (ast?.token !== TOKEN) constructorError();
|
|
41
46
|
|
|
42
|
-
super(
|
|
43
|
-
this.#internal = { pos, ast, stride, construct };
|
|
44
|
-
|
|
45
|
-
const proxy = new Proxy(this, PROXY_HANDLERS);
|
|
46
|
-
nodeArrays.set(proxy, this);
|
|
47
|
-
return proxy;
|
|
47
|
+
super();
|
|
48
|
+
this.#internal = { pos, length, ast, stride, construct };
|
|
49
|
+
return new Proxy(this, PROXY_HANDLERS);
|
|
48
50
|
}
|
|
49
51
|
|
|
50
52
|
// Allow `arr.filter`, `arr.map` etc.
|
|
@@ -53,66 +55,63 @@ class NodeArray extends Array {
|
|
|
53
55
|
// Override `values` method with a more efficient one that avoids going via proxy for every iteration.
|
|
54
56
|
// TODO: Benchmark to check that this is actually faster.
|
|
55
57
|
values() {
|
|
56
|
-
|
|
57
|
-
const arr = nodeArrays.get(this);
|
|
58
|
-
return new NodeArrayValuesIterator(arr.#internal, arr.length);
|
|
58
|
+
return new NodeArrayValuesIterator(this);
|
|
59
59
|
}
|
|
60
60
|
|
|
61
61
|
// Override `keys` method with a more efficient one that avoids going via proxy for every iteration.
|
|
62
62
|
// TODO: Benchmark to check that this is actually faster.
|
|
63
63
|
keys() {
|
|
64
|
-
|
|
65
|
-
// TODO: `this.length` would work here.
|
|
66
|
-
// Not sure which is more expensive - property lookup via proxy, or `WeakMap` lookup.
|
|
67
|
-
const arr = nodeArrays.get(this);
|
|
68
|
-
return new NodeArrayKeysIterator(arr.length);
|
|
64
|
+
return new NodeArrayKeysIterator(this);
|
|
69
65
|
}
|
|
70
66
|
|
|
71
67
|
// Override `entries` method with a more efficient one that avoids going via proxy for every iteration.
|
|
72
68
|
// TODO: Benchmark to check that this is actually faster.
|
|
73
69
|
entries() {
|
|
74
|
-
|
|
75
|
-
const arr = nodeArrays.get(this);
|
|
76
|
-
return new NodeArrayEntriesIterator(arr.#internal, arr.length);
|
|
70
|
+
return new NodeArrayEntriesIterator(this);
|
|
77
71
|
}
|
|
78
72
|
|
|
79
73
|
// This method is overwritten with reference to `values` method below.
|
|
80
74
|
// Defining dummy method here to prevent the later assignment altering the shape of class prototype.
|
|
81
75
|
[Symbol.iterator]() {}
|
|
82
76
|
|
|
83
|
-
|
|
77
|
+
/**
|
|
78
|
+
* Override `slice` method to return a `NodeArray`.
|
|
79
|
+
*
|
|
80
|
+
* @this {NodeArray}
|
|
81
|
+
* @param {*} start - Start of slice
|
|
82
|
+
* @param {*} end - End of slice
|
|
83
|
+
* @returns {NodeArray} - `NodeArray` containing slice of this one
|
|
84
|
+
*/
|
|
84
85
|
slice(start, end) {
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
if (arr === void 0) throw new Error('`slice` called on a value which is not a `NodeArray`');
|
|
86
|
+
const internal = this[ARRAY].#internal,
|
|
87
|
+
{ length } = internal;
|
|
88
88
|
|
|
89
89
|
start = toInt(start);
|
|
90
90
|
if (start < 0) {
|
|
91
|
-
start =
|
|
91
|
+
start = length + start;
|
|
92
92
|
if (start < 0) start = 0;
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
if (end === void 0) {
|
|
96
|
-
end =
|
|
96
|
+
end = length;
|
|
97
97
|
} else {
|
|
98
98
|
end = toInt(end);
|
|
99
99
|
if (end < 0) {
|
|
100
|
-
end
|
|
100
|
+
end += length;
|
|
101
101
|
if (end < 0) end = 0;
|
|
102
|
-
} else if (end >
|
|
103
|
-
end =
|
|
102
|
+
} else if (end > length) {
|
|
103
|
+
end = length;
|
|
104
104
|
}
|
|
105
105
|
}
|
|
106
106
|
|
|
107
|
-
let
|
|
108
|
-
if (
|
|
107
|
+
let sliceLength = end - start;
|
|
108
|
+
if (sliceLength <= 0 || start >= length) {
|
|
109
109
|
start = 0;
|
|
110
|
-
|
|
110
|
+
sliceLength = 0;
|
|
111
111
|
}
|
|
112
112
|
|
|
113
|
-
const
|
|
114
|
-
|
|
115
|
-
return new NodeArray(internal.pos + start * stride, length, stride, internal.construct, internal.ast);
|
|
113
|
+
const { stride } = internal;
|
|
114
|
+
return new NodeArray(internal.pos + start * stride, sliceLength, stride, internal.construct, internal.ast);
|
|
116
115
|
}
|
|
117
116
|
|
|
118
117
|
// Make `console.log` deserialize all elements.
|
|
@@ -123,16 +122,30 @@ class NodeArray extends Array {
|
|
|
123
122
|
}
|
|
124
123
|
|
|
125
124
|
static {
|
|
125
|
+
/**
|
|
126
|
+
* Get internal properties of `NodeArray`, given a proxy wrapping a `NodeArray`.
|
|
127
|
+
* @param {Proxy} proxy - Proxy wrapping `NodeArray` object
|
|
128
|
+
* @returns {Object} - Internal properties object
|
|
129
|
+
*/
|
|
130
|
+
getInternalFromProxy = proxy => proxy[ARRAY].#internal;
|
|
131
|
+
|
|
132
|
+
/**
|
|
133
|
+
* Get length of `NodeArray`.
|
|
134
|
+
* @param {NodeArray} arr - `NodeArray` object
|
|
135
|
+
* @returns {number} - Array length
|
|
136
|
+
*/
|
|
137
|
+
getLength = arr => arr.#internal.length;
|
|
138
|
+
|
|
126
139
|
/**
|
|
127
140
|
* Get element of `NodeArray` at index `index`.
|
|
128
|
-
* `index` must be in bounds (i.e. `< arr.length`).
|
|
129
141
|
*
|
|
130
142
|
* @param {NodeArray} arr - `NodeArray` object
|
|
131
143
|
* @param {number} index - Index of element to get
|
|
132
|
-
* @returns {
|
|
144
|
+
* @returns {*|undefined} - Element at index `index`, or `undefined` if out of bounds
|
|
133
145
|
*/
|
|
134
146
|
getElement = (arr, index) => {
|
|
135
147
|
const internal = arr.#internal;
|
|
148
|
+
if (index >= internal.length) return void 0;
|
|
136
149
|
return (0, internal.construct)(internal.pos + index * internal.stride, internal.ast);
|
|
137
150
|
};
|
|
138
151
|
}
|
|
@@ -142,20 +155,22 @@ NodeArray.prototype[Symbol.iterator] = NodeArray.prototype.values;
|
|
|
142
155
|
|
|
143
156
|
module.exports = NodeArray;
|
|
144
157
|
|
|
145
|
-
|
|
146
|
-
|
|
158
|
+
/**
|
|
159
|
+
* Iterator over values of a `NodeArray`.
|
|
160
|
+
* Returned by `values` method, and also used as iterator for `for (const node of nodeArray) {}`.
|
|
161
|
+
*/
|
|
147
162
|
class NodeArrayValuesIterator {
|
|
148
163
|
#internal;
|
|
149
164
|
|
|
150
|
-
constructor(
|
|
151
|
-
const
|
|
152
|
-
|
|
165
|
+
constructor(proxy) {
|
|
166
|
+
const internal = getInternalFromProxy(proxy),
|
|
167
|
+
{ pos, stride } = internal;
|
|
153
168
|
|
|
154
169
|
this.#internal = {
|
|
155
170
|
pos,
|
|
156
|
-
endPos: pos + length * stride,
|
|
157
|
-
ast,
|
|
158
|
-
construct:
|
|
171
|
+
endPos: pos + internal.length * stride,
|
|
172
|
+
ast: internal.ast,
|
|
173
|
+
construct: internal.construct,
|
|
159
174
|
stride,
|
|
160
175
|
};
|
|
161
176
|
}
|
|
@@ -173,14 +188,15 @@ class NodeArrayValuesIterator {
|
|
|
173
188
|
}
|
|
174
189
|
}
|
|
175
190
|
|
|
176
|
-
|
|
191
|
+
/**
|
|
192
|
+
* Iterator over keys of a `NodeArray`. Returned by `keys` method.
|
|
193
|
+
*/
|
|
177
194
|
class NodeArrayKeysIterator {
|
|
178
195
|
#internal;
|
|
179
196
|
|
|
180
|
-
constructor(
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
this.#internal = { index: 0, length };
|
|
197
|
+
constructor(proxy) {
|
|
198
|
+
const internal = getInternalFromProxy(proxy);
|
|
199
|
+
this.#internal = { index: 0, length: internal.length };
|
|
184
200
|
}
|
|
185
201
|
|
|
186
202
|
next() {
|
|
@@ -196,21 +212,22 @@ class NodeArrayKeysIterator {
|
|
|
196
212
|
}
|
|
197
213
|
}
|
|
198
214
|
|
|
199
|
-
|
|
215
|
+
/**
|
|
216
|
+
* Iterator over values of a `NodeArray`. Returned by `entries` method.
|
|
217
|
+
*/
|
|
200
218
|
class NodeArrayEntriesIterator {
|
|
201
219
|
#internal;
|
|
202
220
|
|
|
203
|
-
constructor(
|
|
204
|
-
const
|
|
205
|
-
if (ast?.token !== TOKEN) constructorError();
|
|
221
|
+
constructor(proxy) {
|
|
222
|
+
const internal = getInternalFromProxy(proxy);
|
|
206
223
|
|
|
207
224
|
this.#internal = {
|
|
208
225
|
index: 0,
|
|
209
|
-
length,
|
|
210
|
-
pos:
|
|
211
|
-
ast,
|
|
212
|
-
construct:
|
|
213
|
-
stride:
|
|
226
|
+
length: internal.length,
|
|
227
|
+
pos: internal.pos,
|
|
228
|
+
ast: internal.ast,
|
|
229
|
+
construct: internal.construct,
|
|
230
|
+
stride: internal.stride,
|
|
214
231
|
};
|
|
215
232
|
}
|
|
216
233
|
|
|
@@ -241,29 +258,38 @@ const PROXY_HANDLERS = {
|
|
|
241
258
|
// Return `true` for indexes which are in bounds.
|
|
242
259
|
// e.g. `'0' in arr`.
|
|
243
260
|
has(arr, key) {
|
|
244
|
-
|
|
261
|
+
const index = toIndex(key);
|
|
262
|
+
if (index !== null) return index < getLength(arr);
|
|
245
263
|
return Reflect.has(arr, key);
|
|
246
264
|
},
|
|
247
265
|
|
|
248
|
-
// Get
|
|
266
|
+
// Get elements and length.
|
|
249
267
|
get(arr, key) {
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
268
|
+
// Methods of `NodeArray` are called with `this` being the proxy, rather than the `NodeArray` itself.
|
|
269
|
+
// They can "unwrap" the proxy by getting `this[ARRAY]`.
|
|
270
|
+
if (key === ARRAY) return arr;
|
|
271
|
+
if (key === 'length') return getLength(arr);
|
|
272
|
+
const index = toIndex(key);
|
|
273
|
+
if (index !== null) return getElement(arr, index);
|
|
274
|
+
|
|
255
275
|
return Reflect.get(arr, key);
|
|
256
276
|
},
|
|
257
277
|
|
|
258
|
-
// Get descriptors
|
|
278
|
+
// Get descriptors for elements and length.
|
|
259
279
|
getOwnPropertyDescriptor(arr, key) {
|
|
260
|
-
if (
|
|
261
|
-
|
|
262
|
-
|
|
280
|
+
if (key === 'length') {
|
|
281
|
+
// Cannot return `writable: false` unfortunately
|
|
282
|
+
return { value: getLength(arr), writable: true, enumerable: false, configurable: false };
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
const index = toIndex(key);
|
|
286
|
+
if (index !== null) {
|
|
287
|
+
const value = getElement(arr, index);
|
|
288
|
+
if (value === void 0) return void 0;
|
|
263
289
|
// Cannot return `configurable: false` unfortunately
|
|
264
|
-
return { value
|
|
290
|
+
return { value, writable: false, enumerable: true, configurable: true };
|
|
265
291
|
}
|
|
266
|
-
|
|
292
|
+
|
|
267
293
|
return Reflect.getOwnPropertyDescriptor(arr, key);
|
|
268
294
|
},
|
|
269
295
|
|
|
@@ -275,21 +301,22 @@ const PROXY_HANDLERS = {
|
|
|
275
301
|
// * `Object.defineProperty(arr, 'length', {value: 0})`.
|
|
276
302
|
// * Other operations which mutate entries e.g. `arr.push(123)`.
|
|
277
303
|
defineProperty(arr, key, descriptor) {
|
|
278
|
-
if (key === 'length' ||
|
|
304
|
+
if (key === 'length' || toIndex(key) !== null) return false;
|
|
279
305
|
return Reflect.defineProperty(arr, key, descriptor);
|
|
280
306
|
},
|
|
281
307
|
|
|
282
308
|
// Prevent deleting entries.
|
|
283
309
|
deleteProperty(arr, key) {
|
|
284
310
|
// Note: `Reflect.deleteProperty(arr, 'length')` already returns `false`
|
|
285
|
-
if (
|
|
311
|
+
if (toIndex(key) !== null) return false;
|
|
286
312
|
return Reflect.deleteProperty(arr, key);
|
|
287
313
|
},
|
|
288
314
|
|
|
289
315
|
// Get keys, including element indexes.
|
|
290
316
|
ownKeys(arr) {
|
|
291
|
-
const keys = []
|
|
292
|
-
|
|
317
|
+
const keys = [],
|
|
318
|
+
length = getLength(arr);
|
|
319
|
+
for (let i = 0; i < length; i++) {
|
|
293
320
|
keys.push(i + '');
|
|
294
321
|
}
|
|
295
322
|
keys.push(...Reflect.ownKeys(arr));
|
|
@@ -298,16 +325,24 @@ const PROXY_HANDLERS = {
|
|
|
298
325
|
};
|
|
299
326
|
|
|
300
327
|
/**
|
|
301
|
-
*
|
|
328
|
+
* Convert key to array index, if it is a valid array index.
|
|
329
|
+
*
|
|
302
330
|
* Only strings comprising a plain integer are valid indexes.
|
|
303
331
|
* e.g. `"-1"`, `"01"`, `"0xFF"`, `"1e1"`, `"1 "` are not valid indexes.
|
|
332
|
+
* Integers >= 4294967295 are not valid indexes.
|
|
304
333
|
*
|
|
305
|
-
* @param {
|
|
306
|
-
* @returns {
|
|
334
|
+
* @param {string|Symbol} - Key used for property lookup.
|
|
335
|
+
* @returns {number|null} - `key` converted to integer, if it's a valid array index, otherwise `null`.
|
|
307
336
|
*/
|
|
308
|
-
function
|
|
309
|
-
|
|
310
|
-
|
|
337
|
+
function toIndex(key) {
|
|
338
|
+
if (typeof key === 'string') {
|
|
339
|
+
if (key === '0') return 0;
|
|
340
|
+
if (INDEX_REGEX.test(key)) {
|
|
341
|
+
const index = +key;
|
|
342
|
+
if (index < 4294967295) return index;
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
return null;
|
|
311
346
|
}
|
|
312
347
|
|
|
313
348
|
const INDEX_REGEX = /^[1-9]\d*$/;
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const rawTransferSupportedBinding = require('../bindings.js').rawTransferSupported;
|
|
4
|
+
|
|
5
|
+
module.exports = rawTransferSupported;
|
|
6
|
+
|
|
7
|
+
let rawTransferIsSupported = null;
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Returns `true` if `experimentalRawTransfer` is option is supported.
|
|
11
|
+
*
|
|
12
|
+
* Raw transfer is only supported on 64-bit little-endian systems,
|
|
13
|
+
* and NodeJS >= v22.0.0 or Deno >= v2.0.0.
|
|
14
|
+
*
|
|
15
|
+
* Versions of NodeJS prior to v22.0.0 do not support creating an `ArrayBuffer` larger than 4 GiB.
|
|
16
|
+
* Bun (as at v1.2.4) also does not support creating an `ArrayBuffer` larger than 4 GiB.
|
|
17
|
+
* Support on Deno v1 is unknown and it's EOL, so treating Deno before v2.0.0 as unsupported.
|
|
18
|
+
*
|
|
19
|
+
* No easy way to determining pointer width (64 bit or 32 bit) in JS,
|
|
20
|
+
* so call a function on Rust side to find out.
|
|
21
|
+
*
|
|
22
|
+
* @returns {boolean} - `true` if raw transfer is supported on this platform
|
|
23
|
+
*/
|
|
24
|
+
function rawTransferSupported() {
|
|
25
|
+
if (rawTransferIsSupported === null) {
|
|
26
|
+
rawTransferIsSupported = rawTransferRuntimeSupported() && rawTransferSupportedBinding();
|
|
27
|
+
}
|
|
28
|
+
return rawTransferIsSupported;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Checks copied from:
|
|
32
|
+
// https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/src/runtimes.ts
|
|
33
|
+
// MIT license: https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/LICENCE
|
|
34
|
+
function rawTransferRuntimeSupported() {
|
|
35
|
+
let global;
|
|
36
|
+
try {
|
|
37
|
+
global = globalThis;
|
|
38
|
+
} catch (e) {
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const isBun = !!global.Bun || !!global.process?.versions?.bun;
|
|
43
|
+
if (isBun) return false;
|
|
44
|
+
|
|
45
|
+
const isDeno = !!global.Deno;
|
|
46
|
+
if (isDeno) {
|
|
47
|
+
const match = Deno.version?.deno?.match(/^(\d+)\./);
|
|
48
|
+
return !!match && match[1] * 1 >= 2;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
const isNode = global.process?.release?.name === 'node';
|
|
52
|
+
if (!isNode) return false;
|
|
53
|
+
|
|
54
|
+
const match = process.version?.match(/^v(\d+)\./);
|
|
55
|
+
return !!match && match[1] * 1 >= 22;
|
|
56
|
+
}
|