oxc/napi/parser/test_module_lexer.mjs
Boshen 32303b20fb
New tool: oxc_module_lexer (#2650)
# Oxc Module Lexer

This is not a lexer. The name "lexer" is used for easier recognition.

## [es-module-lexer](https://github.com/guybedford/es-module-lexer)

Outputs the list of exports and locations of import specifiers,
including dynamic import and import meta handling.

Does not have any
[limitations](https://github.com/guybedford/es-module-lexer?tab=readme-ov-file#limitations)
mentioned in `es-module-lexer`.

I'll also work on the following cases to make this feature complete.

- [ ] get imported variables
https://github.com/guybedford/es-module-lexer/issues/163
- [ ] track star exports as imports as well
https://github.com/guybedford/es-module-lexer/issues/76
- [ ] TypeScript specific syntax
- [ ] TypeScript `type` import / export keyword

## [cjs-module-lexer](https://github.com/nodejs/cjs-module-lexer)

- [ ] TODO

## Benchmark

This is 2 times slower than `es-module-lexer`, but will be significantly
faster when TypeScript is processed.

The difference is around 10ms vs 20ms on a large file (700k).
2024-03-09 23:23:55 +08:00

103 lines
2.5 KiB
JavaScript

/*
* Test and bench against `es-module-lexer`
*/
import fs from "fs";
import assert from "assert";
import oxc from "./index.js";
import * as esModuleLexer from "es-module-lexer";
const root = "/Users/boshen/github/es-module-lexer/test/samples";
main();
async function main() {
await esModuleLexer.init;
const files = fs
.readdirSync(root)
.filter((x) => x.endsWith(".js"))
.map((file) => {
const source = fs.readFileSync(`${root}/${file}`);
return {
file,
code: source.toString(),
size: source.byteLength,
};
});
function test(source) {
const [imports, exports, facade, hasModuleSyntax] =
esModuleLexer.parse(source);
const moduleLexer = oxc.moduleLexerSync(source);
assert(moduleLexer.imports.length == imports.length);
assert(moduleLexer.exports.length == exports.length);
assert(moduleLexer.facade == facade);
assert(moduleLexer.hasModuleSyntax == hasModuleSyntax);
}
function testAll(files) {
for (const file of files) {
test(file.code);
}
}
testAll(files);
const n = 25;
bench("es-module-lexer", esModuleLexer.parse);
bench("oxc", oxc.moduleLexerSync);
function bench(name, fn) {
console.log("-----------");
console.log(name);
doRun();
function timeRun(code) {
const start = process.hrtime.bigint();
fn(code);
const end = process.hrtime.bigint();
return Math.round(Number(end - start) / 1e6);
}
function doRun() {
console.log("Cold Run, All Samples");
let totalSize = 0;
{
let total = 0;
files.forEach(({ code, size }) => {
totalSize += size;
total += timeRun(code);
});
console.log(`test/samples/*.js (${Math.round(totalSize / 1e3)} KiB)`);
console.log(`> ${total + "ms"}`);
}
console.log(`\nWarm Runs (average of ${n} runs)`);
files.forEach(({ file, code, size }) => {
console.log(`${file} (${Math.round(size / 1e3)} KiB)`);
let total = 0;
for (let i = 0; i < n; i++) {
total += timeRun(code);
}
console.log(`> ${total / n + "ms"}`);
});
console.log(`\nWarm Runs, All Samples (average of ${n} runs)`);
{
let total = 0;
for (let i = 0; i < n; i++) {
files.forEach(({ code }) => {
total += timeRun(code);
});
}
console.log(`test/samples/*.js (${Math.round(totalSize / 1e3)} KiB)`);
console.log(`> ${total / n + "ms"}`);
}
}
}
}