193fb6ee3Sopenharmony_ciimport { readFileSync, createReadStream, readdirSync } from 'node:fs';
293fb6ee3Sopenharmony_ciimport Benchmark from 'benchmark';
393fb6ee3Sopenharmony_ciimport { loadTreeConstructionTestData } from 'parse5-test-utils/dist/generate-parsing-tests.js';
493fb6ee3Sopenharmony_ciimport { loadSAXParserTestData } from 'parse5-test-utils/dist/load-sax-parser-test-data.js';
593fb6ee3Sopenharmony_ciimport { treeAdapters, WritableStreamStub, finished } from 'parse5-test-utils/dist/common.js';
693fb6ee3Sopenharmony_ciimport * as parse5 from '../../packages/parse5/dist/index.js';
793fb6ee3Sopenharmony_ciimport { ParserStream as parse5Stream } from '../../packages/parse5-parser-stream/dist/index.js';
893fb6ee3Sopenharmony_ciimport * as parse5Upstream from 'parse5';
993fb6ee3Sopenharmony_ci
1093fb6ee3Sopenharmony_ciconst hugePagePath = new URL('../../test/data/huge-page/huge-page.html', import.meta.url);
1193fb6ee3Sopenharmony_ciconst treeConstructionPath = new URL('../../test/data/html5lib-tests/tree-construction', import.meta.url);
1293fb6ee3Sopenharmony_ciconst saxPath = new URL('../../test/data/sax/', import.meta.url);
1393fb6ee3Sopenharmony_ci
1493fb6ee3Sopenharmony_ci//HACK: https://github.com/bestiejs/benchmark.js/issues/51
1593fb6ee3Sopenharmony_ci/* global workingCopy, WorkingCopyParserStream, upstreamParser, hugePage, microTests, runMicro, runPages, files */
1693fb6ee3Sopenharmony_ciglobal.workingCopy = parse5;
1793fb6ee3Sopenharmony_ciglobal.WorkingCopyParserStream = parse5Stream;
1893fb6ee3Sopenharmony_ciglobal.upstreamParser = parse5Upstream;
1993fb6ee3Sopenharmony_ci
2093fb6ee3Sopenharmony_ci// Huge page data
2193fb6ee3Sopenharmony_ciglobal.hugePage = readFileSync(hugePagePath).toString();
2293fb6ee3Sopenharmony_ci
2393fb6ee3Sopenharmony_ci// Micro data
2493fb6ee3Sopenharmony_ciglobal.microTests = loadTreeConstructionTestData(treeConstructionPath, treeAdapters.default)
2593fb6ee3Sopenharmony_ci    .filter(
2693fb6ee3Sopenharmony_ci        (test) =>
2793fb6ee3Sopenharmony_ci            //NOTE: this test caused a stack overflow in parse5 v1.x
2893fb6ee3Sopenharmony_ci            test.input !== '<button><p><button>'
2993fb6ee3Sopenharmony_ci    )
3093fb6ee3Sopenharmony_ci    .map((test) => ({
3193fb6ee3Sopenharmony_ci        html: test.input,
3293fb6ee3Sopenharmony_ci        fragmentContext: test.fragmentContext,
3393fb6ee3Sopenharmony_ci    }));
3493fb6ee3Sopenharmony_ci
3593fb6ee3Sopenharmony_ciglobal.runMicro = function (parser) {
3693fb6ee3Sopenharmony_ci    for (const test of microTests) {
3793fb6ee3Sopenharmony_ci        if (test.fragmentContext) {
3893fb6ee3Sopenharmony_ci            parser.parseFragment(test.fragmentContext, test.html);
3993fb6ee3Sopenharmony_ci        } else {
4093fb6ee3Sopenharmony_ci            parser.parse(test.html);
4193fb6ee3Sopenharmony_ci        }
4293fb6ee3Sopenharmony_ci    }
4393fb6ee3Sopenharmony_ci};
4493fb6ee3Sopenharmony_ci
4593fb6ee3Sopenharmony_ci// Pages data
4693fb6ee3Sopenharmony_ciconst pages = loadSAXParserTestData().map((test) => test.src);
4793fb6ee3Sopenharmony_ci
4893fb6ee3Sopenharmony_ciglobal.runPages = function (parser) {
4993fb6ee3Sopenharmony_ci    for (const page of pages) {
5093fb6ee3Sopenharmony_ci        parser.parse(page);
5193fb6ee3Sopenharmony_ci    }
5293fb6ee3Sopenharmony_ci};
5393fb6ee3Sopenharmony_ci
5493fb6ee3Sopenharmony_ci// Stream data
5593fb6ee3Sopenharmony_ciglobal.files = readdirSync(saxPath).map((dirName) => new URL(`${dirName}/src.html`, saxPath).pathname);
5693fb6ee3Sopenharmony_ci
5793fb6ee3Sopenharmony_ci// Utils
5893fb6ee3Sopenharmony_cifunction getHz(suite, testName) {
5993fb6ee3Sopenharmony_ci    for (let i = 0; i < suite.length; i++) {
6093fb6ee3Sopenharmony_ci        if (suite[i].name === testName) {
6193fb6ee3Sopenharmony_ci            return suite[i].hz;
6293fb6ee3Sopenharmony_ci        }
6393fb6ee3Sopenharmony_ci    }
6493fb6ee3Sopenharmony_ci}
6593fb6ee3Sopenharmony_ci
6693fb6ee3Sopenharmony_cifunction runBench({ name, workingCopyFn, upstreamFn, defer = false }) {
6793fb6ee3Sopenharmony_ci    const suite = new Benchmark.Suite(name);
6893fb6ee3Sopenharmony_ci
6993fb6ee3Sopenharmony_ci    suite
7093fb6ee3Sopenharmony_ci        .add('Working copy', workingCopyFn, { defer })
7193fb6ee3Sopenharmony_ci        .add('Upstream', upstreamFn, { defer })
7293fb6ee3Sopenharmony_ci        .on('start', () => console.log(name))
7393fb6ee3Sopenharmony_ci        .on('cycle', (event) => console.log(String(event.target)))
7493fb6ee3Sopenharmony_ci        .on('complete', () => {
7593fb6ee3Sopenharmony_ci            const workingCopyHz = getHz(suite, 'Working copy');
7693fb6ee3Sopenharmony_ci            const upstreamHz = getHz(suite, 'Upstream');
7793fb6ee3Sopenharmony_ci
7893fb6ee3Sopenharmony_ci            if (workingCopyHz > upstreamHz) {
7993fb6ee3Sopenharmony_ci                console.log(`Working copy is ${(workingCopyHz / upstreamHz).toFixed(2)}x faster.\n`);
8093fb6ee3Sopenharmony_ci            } else {
8193fb6ee3Sopenharmony_ci                console.log(`Working copy is ${(upstreamHz / workingCopyHz).toFixed(2)}x slower.\n`);
8293fb6ee3Sopenharmony_ci            }
8393fb6ee3Sopenharmony_ci        })
8493fb6ee3Sopenharmony_ci        .run();
8593fb6ee3Sopenharmony_ci}
8693fb6ee3Sopenharmony_ci
8793fb6ee3Sopenharmony_ci// Benchmarks
8893fb6ee3Sopenharmony_cirunBench({
8993fb6ee3Sopenharmony_ci    name: 'parse5 regression benchmark - MICRO',
9093fb6ee3Sopenharmony_ci    workingCopyFn: () => runMicro(workingCopy),
9193fb6ee3Sopenharmony_ci    upstreamFn: () => runMicro(upstreamParser),
9293fb6ee3Sopenharmony_ci});
9393fb6ee3Sopenharmony_ci
9493fb6ee3Sopenharmony_cirunBench({
9593fb6ee3Sopenharmony_ci    name: 'parse5 regression benchmark - HUGE',
9693fb6ee3Sopenharmony_ci    workingCopyFn: () => workingCopy.parse(hugePage),
9793fb6ee3Sopenharmony_ci    upstreamFn: () => upstreamParser.parse(hugePage),
9893fb6ee3Sopenharmony_ci});
9993fb6ee3Sopenharmony_ci
10093fb6ee3Sopenharmony_cirunBench({
10193fb6ee3Sopenharmony_ci    name: 'parse5 regression benchmark - PAGES',
10293fb6ee3Sopenharmony_ci    workingCopyFn: () => runPages(workingCopy),
10393fb6ee3Sopenharmony_ci    upstreamFn: () => runPages(upstreamParser),
10493fb6ee3Sopenharmony_ci});
10593fb6ee3Sopenharmony_ci
10693fb6ee3Sopenharmony_cirunBench({
10793fb6ee3Sopenharmony_ci    name: 'parse5 regression benchmark - STREAM',
10893fb6ee3Sopenharmony_ci    defer: true,
10993fb6ee3Sopenharmony_ci    workingCopyFn: async (deferred) => {
11093fb6ee3Sopenharmony_ci        const parsePromises = files.map((fileName) => {
11193fb6ee3Sopenharmony_ci            const stream = createReadStream(fileName, 'utf8');
11293fb6ee3Sopenharmony_ci            const parserStream = new WorkingCopyParserStream();
11393fb6ee3Sopenharmony_ci
11493fb6ee3Sopenharmony_ci            stream.pipe(parserStream);
11593fb6ee3Sopenharmony_ci            return finished(parserStream);
11693fb6ee3Sopenharmony_ci        });
11793fb6ee3Sopenharmony_ci
11893fb6ee3Sopenharmony_ci        await Promise.all(parsePromises);
11993fb6ee3Sopenharmony_ci        deferred.resolve();
12093fb6ee3Sopenharmony_ci    },
12193fb6ee3Sopenharmony_ci    upstreamFn: async (deferred) => {
12293fb6ee3Sopenharmony_ci        const parsePromises = files.map(async (fileName) => {
12393fb6ee3Sopenharmony_ci            const stream = createReadStream(fileName, 'utf8');
12493fb6ee3Sopenharmony_ci            const writable = new WritableStreamStub();
12593fb6ee3Sopenharmony_ci
12693fb6ee3Sopenharmony_ci            stream.pipe(writable);
12793fb6ee3Sopenharmony_ci
12893fb6ee3Sopenharmony_ci            await finished(writable);
12993fb6ee3Sopenharmony_ci
13093fb6ee3Sopenharmony_ci            upstreamParser.parse(writable.writtenData);
13193fb6ee3Sopenharmony_ci        });
13293fb6ee3Sopenharmony_ci
13393fb6ee3Sopenharmony_ci        await Promise.all(parsePromises);
13493fb6ee3Sopenharmony_ci        deferred.resolve();
13593fb6ee3Sopenharmony_ci    },
13693fb6ee3Sopenharmony_ci});
137