oxc-parser
Version:
Oxc Parser Node API
151 lines (127 loc) • 5.26 kB
JavaScript
const bindings = require('./bindings.js');
const deserializeJS = require('./deserialize-js.js');
const deserializeTS = require('./deserialize-ts.js');
const { wrap } = require('./wrap.cjs');
module.exports.ParseResult = bindings.ParseResult;
module.exports.ExportExportNameKind = bindings.ExportExportNameKind;
module.exports.ExportImportNameKind = bindings.ExportImportNameKind;
module.exports.ExportLocalNameKind = bindings.ExportLocalNameKind;
module.exports.ImportNameKind = bindings.ImportNameKind;
module.exports.parseWithoutReturn = bindings.parseWithoutReturn;
module.exports.Severity = bindings.Severity;
module.exports.parseAsync = async function parseAsync(...args) {
return wrap(await bindings.parseAsync(...args));
};
module.exports.parseSync = function parseSync(filename, sourceText, options) {
if (options?.experimentalRawTransfer) {
return parseSyncRaw(filename, sourceText, options);
}
return wrap(bindings.parseSync(filename, sourceText, options));
};
let buffer, encoder;
function parseSyncRaw(filename, sourceText, options) {
if (!rawTransferSupported()) {
throw new Error(
'`experimentalRawTransfer` option is not supported on 32-bit or big-endian systems, ' +
'versions of NodeJS prior to v22.0.0, versions of Deno prior to v2.0.0, and other runtimes',
);
}
// Delete `experimentalRawTransfer` option
let experimentalRawTransfer;
({ experimentalRawTransfer, ...options } = options);
// Create buffer and `TextEncoder`
if (!buffer) {
buffer = createBuffer();
encoder = new TextEncoder();
}
// Write source into start of buffer.
// `TextEncoder` cannot write into a `Uint8Array` larger than 1 GiB,
// so create a view into buffer of this size to write into.
const sourceBuffer = new Uint8Array(buffer.buffer, buffer.byteOffset, ONE_GIB);
const { read, written: sourceByteLen } = encoder.encodeInto(sourceText, sourceBuffer);
if (read !== sourceText.length) {
throw new Error('Failed to write source text into buffer');
}
// Parse
bindings.parseSyncRaw(filename, buffer, sourceByteLen, options);
// Deserialize.
// We cannot lazily deserialize in the getters, because the buffer might be re-used to parse
// another file before the getter is called.
// (2 * 1024 * 1024 * 1024 - 12)
const astTypeFlagPos = 2147483636;
let isJsAst = buffer[astTypeFlagPos] === 0;
const data = isJsAst
? deserializeJS(buffer, sourceText, sourceByteLen)
: deserializeTS(buffer, sourceText, sourceByteLen);
return {
get program() {
return data.program;
},
get module() {
return data.module;
},
get comments() {
return data.comments;
},
get errors() {
return data.errors;
},
};
}
const ONE_GIB = 1 << 30,
TWO_GIB = ONE_GIB * 2,
SIX_GIB = ONE_GIB * 6;
// Create a `Uint8Array` which is 2 GiB in size, with its start aligned on 4 GiB.
//
// Achieve this by creating a 6 GiB `ArrayBuffer`, getting the offset within it that's aligned to 4 GiB,
// chopping off that number of bytes from the start, and shortening to 2 GiB.
//
// It's always possible to obtain a 2 GiB slice aligned on 4 GiB within a 6 GiB buffer,
// no matter how the 6 GiB buffer is aligned.
//
// Note: On systems with virtual memory, this only consumes 6 GiB of *virtual* memory.
// It does not consume physical memory until data is actually written to the `Uint8Array`.
// Physical memory consumed corresponds to the quantity of data actually written.
function createBuffer() {
const arrayBuffer = new ArrayBuffer(SIX_GIB);
const offset = bindings.getBufferOffset(new Uint8Array(arrayBuffer));
return new Uint8Array(arrayBuffer, offset, TWO_GIB);
}
let rawTransferIsSupported = null;
// Returns `true` if `experimentalRawTransfer` is option is supported.
//
// Raw transfer is only supported on 64-bit little-endian systems,
// and NodeJS >= v22.0.0 or Deno >= v2.0.0.
//
// Versions of NodeJS prior to v22.0.0 do not support creating an `ArrayBuffer` larger than 4 GiB.
// Bun (as at v1.2.4) also does not support creating an `ArrayBuffer` larger than 4 GiB.
// Support on Deno v1 is unknown and it's EOL, so treating Deno before v2.0.0 as unsupported.
function rawTransferSupported() {
if (rawTransferIsSupported === null) {
rawTransferIsSupported = rawTransferRuntimeSupported() && bindings.rawTransferSupported();
}
return rawTransferIsSupported;
}
module.exports.rawTransferSupported = rawTransferSupported;
// Checks copied from:
// https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/src/runtimes.ts
// MIT license: https://github.com/unjs/std-env/blob/ab15595debec9e9115a9c1d31bc7597a8e71dbfd/LICENCE
function rawTransferRuntimeSupported() {
let global;
try {
global = globalThis;
} catch (e) {
return false;
}
const isBun = !!global.Bun || !!global.process?.versions?.bun;
if (isBun) return false;
const isDeno = !!global.Deno;
if (isDeno) {
const match = Deno.version?.deno?.match(/^(\d+)\./);
return !!match && match[1] * 1 >= 2;
}
const isNode = global.process?.release?.name === 'node';
if (!isNode) return false;
const match = process.version?.match(/^v(\d+)\./);
return !!match && match[1] * 1 >= 22;
}