V8 Coverage Report
Files covered Lines Remaining
. / test.mjs
100.00 %
4215 / 4215

0 / 4215
    1.      1/*jslint beta, node*/
    2.      1import jslint from "./jslint.mjs";
    3.      1import jslintCjs from "./jslint_wrapper_cjs.cjs";
    4.      1import moduleChildProcess from "child_process";
    5.      1import moduleFs from "fs";
    6.      1import modulePath from "path";
    7.      1import moduleVm from "vm";
    8.      1
    9.      1let {
   10.      1    assertErrorThrownAsync,
   11.      1    assertJsonEqual,
   12.      1    assertOrThrow,
   13.      1    debugInline,
   14.      1    fsWriteFileWithParents,
   15.      1    globExclude,
   16.      1    jstestDescribe,
   17.      1    jstestIt,
   18.      1    moduleFsInit,
   19.      1    noop,
   20.      1    v8CoverageListMerge,
   21.      1    v8CoverageReportCreate
   22.      1} = jslint;
   23.      1let sourceJslintMjs;
   24.      1let testCoverageMergeData;
   25.      1
   26.     15function assertMatch(text, rgx) {
   27.     15
   28.     15// Assert <text> matches regexp <rgx>, showing <text> on failure.
   29.     15
   30.     15    assertOrThrow(rgx.test(text), text);
   31.     15}
   32.      1
   33.     23function childRun(env, source, stdin) {
   34.     23
   35.     23// Run <source> in a child node with jslint imported, fed <stdin>, and resolve
   36.     23// its exit-code, stderr and stdout. Clear the parent's test filter, then apply
   37.     23// <env>.
   38.     23
   39.     23    return new Promise(function (resolve) {
   40.     23        moduleChildProcess.execFile(process.execPath, [
   41.     23            "--input-type=module",
   42.     23            "--eval",
   43.     23            "import jslint from \"./jslint.mjs\";\n" + source
   44.     23        ], {
   45.     23            env: {
   46.     23                ...process.env,
   47.     23                npm_config_mode_test_filter: "",
   48.     23                ...env
   49.     23            },
   50.     23
   51.     23// Kill a hung child, so a broken runner fails this suite instead of hanging it.
   52.     23// A killed child resolves exit-code null, never a passing 0.
   53.     23
   54.     23            timeout: 10000
   55.     23        }, function (err, stdout, stderr) {
   56.     23            resolve([(
   57.     23                err
   58.     20                ? err.code
   59.      3                : 0
   60.     23            ), stderr, stdout]);
   61.     23        }).stdin.end(stdin);
   62.     23    });
   63.     23}
   64.      1
   65.      1await (async function init() {
   66.      1
   67.      1// Coverage-hack - Ugly-hack to get test-coverage for all initialization-states.
   68.      1
   69.      1    moduleFsInit();
   70.      1    moduleFsInit();
   71.      1
   72.      1// A runner that ended every async test before it ran would also pass the tests
   73.      1// that check it, so check one async failure here, outside any jstestIt.
   74.      1
   75.      1    await childRun({}, String(`
   76.      1jslint.jstestDescribe("aa", function () {
   77.      1    jslint.jstestIt("bb", async function () {
   78.      1        await null;
   79.      1        throw new Error("bb late");
   80.      1    });
   81.      1});
   82.      1    `)).then(function ([exitCode, stderr]) {
   83.      1
   84.      1// Reported as a failed test, not merely a crash, which also exits 1.
   85.      1
   86.      1        assertOrThrow(
   87.      1            exitCode === 1 && (
   88.      1                / 1\. test it - bb\nError: bb late\n/
   89.      1            ).test(stderr),
   90.      1            "jstest passed an async test that failed\n" + stderr
   91.      1        );
   92.      1    });
   93.      1
   94.      1// Cleanup directory .tmp
   95.      1
   96.      1    await moduleFs.promises.rm(".tmp", {
   97.      1        recursive: true
   98.      1    }).catch(noop);
   99.      1
  100.      1// init sourceJslintMjs
  101.      1
  102.      1    sourceJslintMjs = await moduleFs.promises.readFile("jslint.mjs", "utf8");
  103.      1
  104.      1// init testCoverageMergeData
  105.      1
  106.      1    testCoverageMergeData = JSON.parse(
  107.      1        await moduleFs.promises.readFile(
  108.      1            "test_coverage_merge_data.json",
  109.      1            "utf8"
  110.      1        )
  111.      1    );
  112.      1}());
  113.      1
  114.     16function processExit0(exitCode) {
  115.     16    assertOrThrow(exitCode === 0, exitCode);
  116.     16}
  117.      1
  118.     14function processExit1(exitCode) {
  119.     14    assertOrThrow(exitCode === 1, exitCode);
  120.     14}
  121.      1
  122.      1jstestDescribe((
  123.      1    "test assertXxx handling-behavior"
  124.      1), function () {
  125.      1    jstestIt((
  126.      1        "test assertXxx-error handling-behavior"
  127.      1    ), async function () {
  128.      1        // Keep <debugInline> imported, for debugging tests.
  129.      1        noop(debugInline);
  130.      1        // test assertErrorThrownAsync error handling-behavior
  131.      1        await assertErrorThrownAsync(function () {
  132.      1            return assertErrorThrownAsync(noop);
  133.      1        });
  134.      1        // test assertJsonEqual error handling-behavior
  135.      1        await assertErrorThrownAsync(function () {
  136.      1            assertJsonEqual(1, 2);
  137.      1        });
  138.      1        await assertErrorThrownAsync(function () {
  139.      1            assertJsonEqual(1, 2, "undefined");
  140.      1        });
  141.      1        await assertErrorThrownAsync(function () {
  142.      1            assertJsonEqual(1, 2, {});
  143.      1        });
  144.      1        // test assertOrThrow error handling-behavior
  145.      1        await assertErrorThrownAsync(function () {
  146.      1            assertOrThrow(undefined, "undefined");
  147.      1        });
  148.      1        await assertErrorThrownAsync(function () {
  149.      1            assertOrThrow(undefined, new Error());
  150.      1        });
  151.      1    });
  152.      1});
  153.      1
  154.      1jstestDescribe((
  155.      1    "test fsXxx handling-behavior"
  156.      1), function () {
  157.      1    jstestIt((
  158.      1        "test fsWriteFileWithParents handling-behavior"
  159.      1    ), async function () {
  160.      1        await Promise.all([
  161.      1            1, 2, 3, 4
  162.      4        ].map(async function () {
  163.      4            await fsWriteFileWithParents(
  164.      4                ".tmp/fsWriteFileWithParents/aa/bb/cc",
  165.      4                "aa"
  166.      4            );
  167.      4        }));
  168.      1        assertJsonEqual(
  169.      1            await moduleFs.promises.readFile(
  170.      1                ".tmp/fsWriteFileWithParents/aa/bb/cc",
  171.      1                "utf8"
  172.      1            ),
  173.      1            "aa"
  174.      1        );
  175.      1    });
  176.      1});
  177.      1
  178.      1jstestDescribe((
  179.      1    "test globXxx handling-behavior"
  180.      1), function () {
  181.      1    jstestIt((
  182.      1        "test globAssertNotWeird-error handling-behavior"
  183.      1    ), async function () {
  184.      1        await Promise.all([
  185.      1            "\n",
  186.      1            "\r",
  187.      1            "\u0000"
  188.      3        ].map(async function (char) {
  189.      3            await assertErrorThrownAsync(function () {
  190.      3                return globExclude({
  191.      3                    pathnameList: [
  192.      3                        "aa",
  193.      3                        `cc/${char}/dd`,
  194.      3                        "bb"
  195.      3                    ]
  196.      3                });
  197.      3            }, (
  198.      3                "Weird character " +
  199.      3                JSON.stringify(char).replace((/\\/g), "\\\\") +
  200.      3                " found in "
  201.      3            ));
  202.      3        }));
  203.      1    });
  204.      1    jstestIt((
  205.      1        "test globExclude handling-behavior"
  206.      1    ), function () {
  207.      1        let pathnameList = [
  208.      1            ".dockerignore",
  209.      1            ".eslintrc.js",
  210.      1            ".gitignore",
  211.      1            ".npmignore",
  212.      1            ".travis.yml",
  213.      1            "/node_modules/aa/bb/cc.js",
  214.      1            "/node_modules/aa/bb/dd.js",
  215.      1            "CHANGELOG.md",
  216.      1            "CONTRIBUTING.md",
  217.      1            "Dockerfile",
  218.      1            "LICENSE",
  219.      1            "Makefile",
  220.      1            "README.md",
  221.      1            "appveyor.yml",
  222.      1            "benchmark/insert-transaction.sql",
  223.      1            "benchmark/insert.js",
  224.      1            "binding.gyp",
  225.      1            "cloudformation/ci.template.js",
  226.      1            "deps/common-sqlite.gypi",
  227.      1            "deps/extract.py",
  228.      1            "deps/sqlite-autoconf-3340000.tar.gz",
  229.      1            "deps/sqlite3.gyp",
  230.      1            "examples/simple-chaining.js",
  231.      1            "lib/index.js",
  232.      1            "lib/sqlite3-binding.js",
  233.      1            "lib/sqlite3.js",
  234.      1            "lib/trace.js",
  235.      1            "node_modules/aa/bb/cc.js",
  236.      1            "node_modules/aa/bb/dd.js",
  237.      1            "package.json",
  238.      1            "scripts/build-appveyor.bat",
  239.      1            "scripts/build-local.bat",
  240.      1            "scripts/build_against_electron.sh",
  241.      1            "scripts/build_against_node.sh",
  242.      1            "scripts/build_against_node_webkit.sh",
  243.      1            "scripts/build_for_node_webkit.cmd",
  244.      1            "scripts/install_node.sh",
  245.      1            "scripts/validate_tag.sh",
  246.      1            "sqlite3.js",
  247.      1            "src/async.h",
  248.      1            "src/backup.cc",
  249.      1            "src/backup.h",
  250.      1            "src/database.cc",
  251.      1            "src/database.h",
  252.      1            "src/gcc-preinclude.h",
  253.      1            "src/macros.h",
  254.      1            "src/node_sqlite3.cc",
  255.      1            "src/statement.cc",
  256.      1            "src/statement.h",
  257.      1            "src/threading.h",
  258.      1            "test/affected.test.js",
  259.      1            "test/backup.test.js",
  260.      1            "test/blob.test.js",
  261.      1            "test/cache.test.js",
  262.      1            "test/constants.test.js",
  263.      1            "test/database_fail.test.js",
  264.      1            "test/each.test.js",
  265.      1            "test/exec.test.js",
  266.      1            "test/extension.test.js",
  267.      1            "test/fts-content.test.js",
  268.      1            "test/interrupt.test.js",
  269.      1            "test/issue-108.test.js",
  270.      1            "test/json.test.js",
  271.      1            "test/map.test.js",
  272.      1            "test/named_columns.test.js",
  273.      1            "test/named_params.test.js",
  274.      1            "test/null_error.test.js",
  275.      1            "test/nw/.gitignore",
  276.      1            "test/nw/Makefile",
  277.      1            "test/nw/index.html",
  278.      1            "test/nw/package.json",
  279.      1            "test/open_close.test.js",
  280.      1            "test/other_objects.test.js",
  281.      1            "test/parallel_insert.test.js",
  282.      1            "test/prepare.test.js",
  283.      1            "test/profile.test.js",
  284.      1            "test/rerun.test.js",
  285.      1            "test/scheduling.test.js",
  286.      1            "test/serialization.test.js",
  287.      1            "test/support/createdb-electron.js",
  288.      1            "test/support/createdb.js",
  289.      1            "test/support/elmo.png",
  290.      1            "test/support/helper.js",
  291.      1            "test/support/prepare.db",
  292.      1            "test/support/script.sql",
  293.      1            "test/trace.test.js",
  294.      1            "test/unicode.test.js",
  295.      1            "test/upsert.test.js",
  296.      1            "test/verbose.test.js",
  297.      1            "tools/docker/architecture/linux-arm/Dockerfile",
  298.      1            "tools/docker/architecture/linux-arm/run.sh",
  299.      1            "tools/docker/architecture/linux-arm64/Dockerfile",
  300.      1            "tools/docker/architecture/linux-arm64/run.sh"
  301.      1        ];
  302.      1        [
  303.      1            "tes?/",
  304.      1            "tes[-t-]/",
  305.      1            "tes[-t]/",
  306.      1            "tes[0-9A-Z_a-z-]/",
  307.      1            "tes[t-]/",
  308.      1            "test/**/*.js"
  309.      6        ].forEach(function (aa) {
  310.      6            [
  311.      6                "li*/*.js",
  312.      6                "li?/*.js",
  313.      6                "lib/",
  314.      6                "lib/*",
  315.      6                "lib/**/*.js",
  316.      6                "lib/*.js"
  317.     36            ].forEach(function (bb) {
  318.     36                [
  319.     36                    "",
  320.     36                    "**/node_modules/",
  321.     36                    "node_modules/"
  322.    108                ].forEach(function (cc) {
  323.    108                    assertJsonEqual(
  324.    108                        globExclude({
  325.    108                            excludeList: [
  326.    108                                "tes[!0-9A-Z_a-z-]/",
  327.    108                                "tes[^0-9A-Z_a-z-]/",
  328.    108                                "test/suppor*/*elper.js",
  329.    108                                "test/suppor?/?elper.js",
  330.    108                                "test/support/helper.js"
  331.    108                            ].concat(aa, cc),
  332.    108                            includeList: [
  333.    108                                "**/*.cjs",
  334.    108                                "**/*.js",
  335.    108                                "**/*.mjs",
  336.    108                                "lib/sqlite3.js"
  337.    108                            ].concat(bb),
  338.    108                            pathnameList
  339.    108                        }).pathnameList,
  340.    108                        [
  341.    108                            ".eslintrc.js",
  342.    108                            "benchmark/insert.js",
  343.    108                            "cloudformation/ci.template.js",
  344.    108                            "examples/simple-chaining.js",
  345.    108                            "lib/index.js",
  346.    108                            "lib/sqlite3-binding.js",
  347.    108                            "lib/sqlite3.js",
  348.    108                            "lib/trace.js",
  349.    108                            "sqlite3.js"
  350.    108                        ].concat(
  351.    108                            cc === "**/node_modules/"
  352.     36                            ? [
  353.     36                                "node_modules/aa/bb/cc.js",
  354.     36                                "node_modules/aa/bb/dd.js"
  355.     36                            ]
  356.     72                            : cc === "node_modules/"
  357.     72                            ? [
  358.     72                                "/node_modules/aa/bb/cc.js",
  359.     72                                "/node_modules/aa/bb/dd.js"
  360.     72                            ]
  361.     72                            : [
  362.     72                                "/node_modules/aa/bb/cc.js",
  363.     72                                "/node_modules/aa/bb/dd.js",
  364.     72                                "node_modules/aa/bb/cc.js",
  365.     72                                "node_modules/aa/bb/dd.js"
  366.     72                            ]
  367.    108                        ).sort()
  368.    108                    );
  369.    108                });
  370.     36            });
  371.      6        });
  372.      1    });
  373.      1    jstestIt((
  374.      1        "test globToRegexp handling-behavior"
  375.      1    ), function () {
  376.      1        Object.entries({
  377.      1            "*": (
  378.      1                /^[^\/]*?$/gm
  379.      1            ),
  380.      1            "**": (
  381.      1                /^.*?$/gm
  382.      1            ),
  383.      1            "***": (
  384.      1                /^.*?$/gm
  385.      1            ),
  386.      1            "****": (
  387.      1                /^.*?$/gm
  388.      1            ),
  389.      1            "****////****": (
  390.      1                /^.*?$/gm
  391.      1            ),
  392.      1            "***///***": (
  393.      1                /^.*?$/gm
  394.      1            ),
  395.      1            "**/*": (
  396.      1                /^.*?$/gm
  397.      1            ),
  398.      1            "**/node_modules/": (
  399.      1                /^.*?\/node_modules\/.*?$/gm
  400.      1            ),
  401.      1            "**/node_modules/**/*": (
  402.      1                /^.*?\/node_modules\/.*?$/gm
  403.      1            ),
  404.      1            "?": (
  405.      1                /^[^\/]$/gm
  406.      1            ),
  407.      1            "[!0-9A-Za-z-]": (
  408.      1                /^[^0-9A-Za-z\-]$/gm
  409.      1            ),
  410.      1            "[0-9A-Za-z-]": (
  411.      1                /^[0-9A-Za-z\-]$/gm
  412.      1            ),
  413.      1            "[[]] ]][[": (
  414.      1                /^[\[]\] \]\][\[]$/gm
  415.      1            ),
  416.      1            "[]": (
  417.      1                /^$/gm
  418.      1            ),
  419.      1            "[^0-9A-Za-z-]": (
  420.      1                /^[^0-9A-Za-z\-]$/gm
  421.      1            ),
  422.      1            "aa/bb/cc": (
  423.      1                /^aa\/bb\/cc$/gm
  424.      1            ),
  425.      1            "aa/bb/cc/": (
  426.      1                /^aa\/bb\/cc\/.*?$/gm
  427.      1            ),
  428.      1            "li*/*": (
  429.      1                /^li[^\/]*?\/[^\/]*?$/gm
  430.      1            ),
  431.      1            "li?/*": (
  432.      1                /^li[^\/]\/[^\/]*?$/gm
  433.      1            ),
  434.      1            "lib/": (
  435.      1                /^lib\/.*?$/gm
  436.      1            ),
  437.      1            "lib/*": (
  438.      1                /^lib\/[^\/]*?$/gm
  439.      1            ),
  440.      1            "lib/**/*.js": (
  441.      1                /^lib\/.*?\.js$/gm
  442.      1            ),
  443.      1            "lib/*.js": (
  444.      1                /^lib\/[^\/]*?\.js$/gm
  445.      1            ),
  446.      1            "node_modules/": (
  447.      1                /^node_modules\/.*?$/gm
  448.      1            ),
  449.      1            "node_modules/**/*": (
  450.      1                /^node_modules\/.*?$/gm
  451.      1            ),
  452.      1            "tes[!0-9A-Z_a-z-]/**/*": (
  453.      1                /^tes[^0-9A-Z_a-z\-]\/.*?$/gm
  454.      1            ),
  455.      1            "tes[0-9A-Z_a-z-]/**/*": (
  456.      1                /^tes[0-9A-Z_a-z\-]\/.*?$/gm
  457.      1            ),
  458.      1            "tes[^0-9A-Z_a-z-]/**/*": (
  459.      1                /^tes[^0-9A-Z_a-z\-]\/.*?$/gm
  460.      1            ),
  461.      1            "test/**/*": (
  462.      1                /^test\/.*?$/gm
  463.      1            ),
  464.      1            "test/**/*.js": (
  465.      1                /^test\/.*?\.js$/gm
  466.      1            ),
  467.      1            "test/suppor*/*elper.js": (
  468.      1                /^test\/suppor[^\/]*?\/[^\/]*?elper\.js$/gm
  469.      1            ),
  470.      1            "test/suppor?/?elper.js": (
  471.      1                /^test\/suppor[^\/]\/[^\/]elper\.js$/gm
  472.      1            ),
  473.      1            "test/support/helper.js": (
  474.      1                /^test\/support\/helper\.js$/gm
  475.      1            )
  476.     33        }).forEach(function ([
  477.     33            pattern, rgx
  478.     33        ]) {
  479.     33            assertJsonEqual(
  480.     33                globExclude({
  481.     33                    excludeList: [
  482.     33                        pattern
  483.     33                    ]
  484.     33                }).excludeList[0].source,
  485.     33                rgx.source
  486.     33            );
  487.     33            assertJsonEqual(
  488.     33                globExclude({
  489.     33                    includeList: [
  490.     33                        pattern
  491.     33                    ]
  492.     33                }).includeList[0].source,
  493.     33                rgx.source
  494.     33            );
  495.     33        });
  496.      1    });
  497.      1});
  498.      1
  499.      1jstestDescribe((
  500.      1    "test jslint's autofix handling-behavior"
  501.      1), function () {
  502.      1    jstestIt((
  503.      1        "test autofix-api handling-behavior"
  504.      1    ), function () {
  505.      1        let result;
  506.      1        let source;
  507.      1
  508.      1// This function will autofix <source_api> through the API - no fs, no cli -
  509.      1// and assert <autofixed> became <expect_api>. Option node is harmless to
  510.      1// every fixture here, so one option-object serves them all.
  511.      1
  512.     17        function assertAutofix(expect_api, source_api) {
  513.     17            let result_api = jslint.jslint(source_api, {
  514.     17                autofix: true,
  515.     17                node: true
  516.     17            });
  517.     17            assertOrThrow(
  518.     17                result_api.autofixed === expect_api,
  519.     17                JSON.stringify([
  520.     17                    source_api, result_api.autofixed
  521.     17                ])
  522.     17            );
  523.     17            return result_api;
  524.     17        }
  525.      1
  526.      1// Option autofix makes jslint() a PURE fixer. <warnings> and <ok> then
  527.      1// describe <autofixed>, so a repairable source comes back ok.
  528.      1
  529.      1        source = (
  530.      1            "function aa(bb) {\n    return String( bb)+bb;\n}\n" +
  531.      1            "export default Object.freeze(aa);\n"
  532.      1        );
  533.      1        result = assertAutofix((
  534.      1            "function aa(bb) {\n    return String(bb) + bb;\n}\n" +
  535.      1            "export default Object.freeze(aa);\n"
  536.      1        ), source);
  537.      1        assertOrThrow(result.ok, JSON.stringify(result.warnings));
  538.      1
  539.      1// Without the option, <autofixed> is undefined and the warnings are the
  540.      1// source's own.
  541.      1
  542.      1        result = jslint.jslint(source, {});
  543.      1        assertOrThrow(result.autofixed === undefined, result.autofixed);
  544.      1        assertOrThrow(!result.ok, "expected warnings");
  545.      1
  546.      1// A warning autofix cannot fix BLOCKS the first pass, so there is nothing to
  547.      1// write and <autofixed> stays undefined.
  548.      1
  549.      1        result = assertAutofix(undefined, (
  550.      1            "function aa(bb) {\n    let cc = 0;\n    return String( bb);\n}\n"
  551.      1        ));
  552.      1        assertOrThrow(!result.ok, "expected warnings");
  553.      1
  554.      1// Under beta, expected_a_at_end moves a line-leading operator to just after
  555.      1// its left operand - past a template's `// x` line, before a trailing
  556.      1// comment - and an operator alone on its line takes the line with it.
  557.      1
  558.      1        result = jslint.jslint((
  559.      1            "const aa = [\n    `\n// x`\n    + 1 // c\n    +\n    2\n];\n" +
  560.      1            "export default Object.freeze(aa);\n"
  561.      1        ), {
  562.      1            autofix: true,
  563.      1            beta: true
  564.      1        });
  565.      1        assertOrThrow(result.autofixed === (
  566.      1            "const aa = [\n    `\n// x` +\n    1 + // c\n    2\n];\n" +
  567.      1            "export default Object.freeze(aa);\n"
  568.      1        ), result.autofixed);
  569.      1
  570.      1// A tagged template's backtick is NOT an operator to move - moving it would
  571.      1// put the line break inside the template and change its value.
  572.      1
  573.      1        source = (
  574.      1            "function aa() {\n    return String.raw\n    `x${0}`;\n}\n" +
  575.      1            "export default Object.freeze(aa);\n"
  576.      1        );
  577.      1        result = jslint.jslint(source, {
  578.      1            autofix: true,
  579.      1            beta: true
  580.      1        });
  581.      1        assertOrThrow(
  582.      1            result.autofixed === undefined && result.ok,
  583.      1            JSON.stringify([result.autofixed, result.warnings])
  584.      1        );
  585.      1
  586.      1// THE FIXER'S LINE MODEL MUST BE THE LINTER'S (jslint_rgx_crlf). A CRLF file
  587.      1// must come back CRLF - line_list carries NO terminators and the rejoin uses
  588.      1// the file's OWN first one - and a lone \r, which the linter counts as a line
  589.      1// break, must not shift every later fix onto the wrong line. Both were real:
  590.      1// the second deleted spaces from a comment while the warned line stayed
  591.      1// untouched. A MIXED file is NORMALIZED to that first terminator, which is
  592.      1// what the second case pins: the fix lands on the right line, the comment is
  593.      1// untouched, and every \n comes back \r.
  594.      1
  595.      1        assertAutofix((
  596.      1            "function aa(bb) {\r\n    if (bb) {\r\n        return bb;\r\n" +
  597.      1            "    }\r\n    return 0;\r\n}\r\naa();\r\n"
  598.      1        ), (
  599.      1            "function aa(bb) {\r\n    if (bb) { return bb; }\r\n" +
  600.      1            "    return 0;\r\n}\r\naa();\r\n"
  601.      1        ));
  602.      1        assertAutofix((
  603.      1            "function bb(cc) {\r    cc();\r    return String(cc);\r" +
  604.      1            "    // xx              yy\r}\rbb();\r"
  605.      1        ), (
  606.      1            "function bb(cc) {\r    cc();\n    return String( cc);\n" +
  607.      1            "    // xx              yy\n}\nbb();\n"
  608.      1        ));
  609.      1
  610.      1// A WARNING-FREE source is returned UNTOUCHED, never rejoined - otherwise a
  611.      1// clean mixed-terminator file would come back normalized and get written.
  612.      1
  613.      1        result = assertAutofix(undefined, (
  614.      1            "function cc(dd) {\r\n    dd();\r    return 0;\n}\ncc();\n"
  615.      1        ));
  616.      1        assertOrThrow(result.ok, JSON.stringify(result.warnings));
  617.      1
  618.      1// AN EMPTY source is the one input whose rejoin is the EMPTY STRING, which
  619.      1// the call site's <|| state.source> would read as "nothing happened". It is
  620.      1// harmless ONLY because state.source is empty too, so the two agree - but a
  621.      1// non-empty source can never rejoin to "", because a warning implies a token
  622.      1// implies a non-empty line. Whitespace-only sources are blocked instead:
  623.      1// unexpected_trailing_space and use_spaces are not in the fixable set.
  624.      1
  625.      1        [
  626.      1            "", "\n", "\n\n", " ", "    ", "  \n  ", "\t"
  627.      7        ].forEach(function (source_degenerate) {
  628.      7            assertAutofix(undefined, source_degenerate);
  629.      7        });
  630.      1
  631.      1// A STOP in a later pass can only be the fixer's own doing - pass 0 parsed to
  632.      1// the end - so the fix is DISCARDED, never written. test_internal_error throws
  633.      1// AFTER phase 6, so pass 0 fixes, pass 1 stops on it, and <autofixed> must come
  634.      1// back undefined instead of carrying pass 0's text.
  635.      1
  636.      1        result = jslint.jslint("String( 0);\n", {
  637.      1            autofix: true,
  638.      1            test_internal_error: true
  639.      1        });
  640.      1        assertOrThrow(
  641.      1            result.stop && result.autofixed === undefined,
  642.      1            JSON.stringify([result.stop, result.autofixed])
  643.      1        );
  644.      1
  645.      1// And the discard is NAMED in this pass's own warnings, so a fixer defect
  646.      1// cannot pass for an ordinary blocked file. This is also what separates
  647.      1// "guard fired" from "no fix was ever attempted" - both leave <autofixed>
  648.      1// undefined.
  649.      1
  650.      1        assertOrThrow(
  651.      1            result.warnings.some(function ({
  652.      1                message
  653.      1            }) {
  654.      1                return message.startsWith("[autofix discarded");
  655.      1            }),
  656.      3            JSON.stringify(result.warnings.map(function ({
  657.      3                message
  658.      3            }) {
  659.      3                return message;
  660.      3            }))
  661.      1        );
  662.      1
  663.      1// A ONE-LINE source carries NO terminator at all, so jslint_rgx_crlf.exec()
  664.      1// returns null and the rejoin falls back to '\n' - which is also appended,
  665.      1// since the fixed code is missing a trailing one.
  666.      1
  667.      1        result = assertAutofix((
  668.      1            "function aa(bb) {\n    return bb;\n}\naa();\n"
  669.      1        ), "function aa(bb) { return bb; } aa();");
  670.      1        assertOrThrow(result.ok, JSON.stringify(result.warnings));
  671.      1
  672.      1// The appended terminator is the file's own, here '\r\n'.
  673.      1
  674.      1        assertAutofix((
  675.      1            "function aa(bb) {\r\n    return bb;\r\n}\r\naa();\r\n"
  676.      1        ), "function aa(bb) { return bb; }\r\naa();");
  677.      1
  678.      1// A used label warns only its placement, so a mid-line label reaches phase 6,
  679.      1// which splits it onto its own line at column 1.
  680.      1
  681.      1        assertAutofix(
  682.      1            String(`
  683.      1function aa(bb) {
  684.      1    bb();
  685.      1cc:
  686.      1    while (bb) {
  687.      1        if (bb()) {
  688.      1            break cc;
  689.      1        }
  690.      1        bb();
  691.      1    }
  692.      1}
  693.      1aa();
  694.      1            `).trim() + "\n",
  695.      1            String(`
  696.      1function aa(bb) {
  697.      1    bb(); cc: while (bb) {
  698.      1        if (bb()) {
  699.      1            break cc;
  700.      1        }
  701.      1        bb();
  702.      1    }
  703.      1}
  704.      1aa();
  705.      1            `).trim() + "\n"
  706.      1        );
  707.      1
  708.      1// A whitespace-run reaching column 0 is INDENTATION or a line-join, not a gap
  709.      1// between two tokens on one line, so the fix is DECLINED and the warning is
  710.      1// reported against a byte-identical file. Here the run is the whole indent of
  711.      1// a continuation line, which is why the warned column is 9 and not 1.
  712.      1
  713.      1        result = assertAutofix(undefined, (
  714.      1            "function aa(bb) {\n    return aa\n        (bb);\n}\naa();\n"
  715.      1        ));
  716.      1        assertOrThrow(
  717.      1            result.warnings.length === 1 &&
  718.      1            result.warnings[0].code === "unexpected_space_a_b" &&
  719.      1            result.warnings[0].line === 3 &&
  720.      1            result.warnings[0].column === 9,
  721.      1            JSON.stringify(result.warnings)
  722.      1        );
  723.      1
  724.      1// A too_long ALREADY in the source does not block autofix - the fix is made,
  725.      1// and too_long is still reported.
  726.      1
  727.      1        result = assertAutofix(
  728.      1            String(`
  729.      1function aa(bb) {
  730.      1    return bb;
  731.      1}
  732.      1aa("${"a".repeat(80)}");
  733.      1            `).trim() + "\n",
  734.      1            String(`
  735.      1function aa(bb) { return bb; }
  736.      1aa("${"a".repeat(80)}");
  737.      1            `).trim() + "\n"
  738.      1        );
  739.      1        assertOrThrow(
  740.      1            result.warnings.length === 1 &&
  741.      1            result.warnings[0].code === "too_long",
  742.      1            JSON.stringify(result.warnings)
  743.      1        );
  744.      1    });
  745.      1    jstestIt((
  746.      1        "test autofix-cli handling-behavior"
  747.      1    ), async function () {
  748.      1        let source;
  749.      1
  750.      1// This function will autofix <name> in .tmp and assert it became <expect>.
  751.      1// <exit> is processExit1 exactly when a residual warning remains - autofix
  752.      1// exits nonzero like a plain lint, so `jslint_autofix=x.js && deploy` cannot
  753.      1// succeed on a file it failed to repair.
  754.      1
  755.     13        async function autofixFile({
  756.     13            exit = processExit0,
  757.     13            expect,
  758.     13            name,
  759.     13            process_env,
  760.     13            source
  761.     13        }) {
  762.     13            let file = ".tmp/" + name;
  763.     13            await fsWriteFileWithParents(file, source);
  764.     13            await jslint.jslint_cli({
  765.     13                // suppress error
  766.     13                console_error: noop,
  767.     13                mode_cli: true,
  768.     13                process_argv: [
  769.     13                    "node",
  770.     13                    "jslint.mjs",
  771.     13                    "jslint_autofix=" + file
  772.     13                ],
  773.     13                process_env,
  774.     13                process_exit: exit
  775.     13            });
  776.     13            assertOrThrow(
  777.     13                expect === await moduleFs.promises.readFile(file, "utf8"),
  778.     13                file
  779.     13            );
  780.     13        }
  781.      1
  782.      1// Whitespace-only warnings - autofix repairs them and the file lints clean.
  783.      1
  784.      1        await autofixFile({
  785.      1            expect: (
  786.      1                "function aa(bb) {\n    return String(bb) + bb;\n}\n" +
  787.      1                "export default Object.freeze(aa);\n"
  788.      1            ),
  789.      1            name: "autofix.mjs",
  790.      1            source: (
  791.      1                "function aa(bb) {\n    return String( bb)+bb;\n}\n" +
  792.      1                "export default Object.freeze(aa);\n"
  793.      1            )
  794.      1        });
  795.      1
  796.      1// A non-whitespace warning blocks phase-5, so the file is REPORTED and left
  797.      1// BYTE-IDENTICAL.
  798.      1
  799.      1        source = (
  800.      1            "function aa(bb) {\n    let cc = 0;\n" +
  801.      1            "    return String( bb);\n}\n"
  802.      1        );
  803.      1        await autofixFile({
  804.      1            exit: processExit1,
  805.      1            expect: source,
  806.      1            name: "autofix_blocked.mjs",
  807.      1            source
  808.      1        });
  809.      1
  810.      1// Indentation is re-indented to the expected column, cascading across passes.
  811.      1
  812.      1        await autofixFile({
  813.      1            expect: (
  814.      1                "function aa(bb) {\n    if (bb) {\n        return bb;\n" +
  815.      1                "    }\n    return 0;\n}\nexport default Object.freeze(aa);\n"
  816.      1            ),
  817.      1            name: "autofix_indent.mjs",
  818.      1            source: (
  819.      1                "function aa(bb) {\n        if (bb) {\n  return bb;\n" +
  820.      1                "        }\n    return 0;\n}\n" +
  821.      1                "export default Object.freeze(aa);\n"
  822.      1            )
  823.      1        });
  824.      1
  825.      1// A SINGLE-LINE TERNARY WARNS ONLY expected_a_at_b_c, yet what it actually
  826.      1// wants is a line break before ? and before :. Autofix still gets there,
  827.      1// because a column-warning on a MID-LINE token means that token belongs on
  828.      1// its own line - so the break falls out of the column-fix. This is the case
  829.      1// that justifies the mid-line branch; without it the fixer would skip these
  830.      1// and never converge.
  831.      1
  832.      1        await autofixFile({
  833.      1            expect: (
  834.      1                "function aa(bb) {\n    return (\n        bb\n        ? 0\n" +
  835.      1                "        : 1\n    );\n}\nexport default Object.freeze(aa);\n"
  836.      1            ),
  837.      1            name: "autofix_ternary.mjs",
  838.      1            source: (
  839.      1                "function aa(bb) {\n    return (\n        bb ? 0 : 1\n" +
  840.      1                "    );\n}\nexport default Object.freeze(aa);\n"
  841.      1            )
  842.      1        });
  843.      1
  844.      1// An UNPARENTHESISED ternary warns something else entirely, which is not in
  845.      1// fix_list, so the file must come back byte-identical.
  846.      1
  847.      1        source = (
  848.      1            "function aa(bb) {\n    return (bb ? 0 : 1);\n}\n" +
  849.      1            "export default Object.freeze(aa);\n"
  850.      1        );
  851.      1        await autofixFile({
  852.      1            exit: processExit1,
  853.      1            expect: source,
  854.      1            name: "autofix_ternary2.mjs",
  855.      1            source
  856.      1        });
  857.      1
  858.      1// A CLOSED-FORM statement block - opener and body on ONE line - needs BOTH
  859.      1// kinds of fix, in separate passes, because a statement block is always open
  860.      1// form (jslint_phase5_whitage). First a line-break, then column-fixes for the
  861.      1// body and the closer the split leaves misplaced. Assert both kinds appear,
  862.      1// so a regression that drops either one cannot hide behind the end-to-end
  863.      1// test below.
  864.      1
  865.      1        assertOrThrow(
  866.      1            jslint.jslint(
  867.      1                "function aa(bb) {\n    if (bb) { return bb; }\n" +
  868.      1                "    return 0;\n}\nexport default Object.freeze(aa);\n"
  869.      1            ).warnings.some(function ({
  870.      1                code
  871.      1            }) {
  872.      1                return code === "expected_line_break_a_b";
  873.      1            }),
  874.      1            "closed-form block must warn expected_line_break_a_b"
  875.      1        );
  876.      1        assertOrThrow(
  877.      1            jslint.jslint(
  878.      1                "function aa(bb) {\n    if (bb) {\nreturn bb;}\n" +
  879.      1                "    return 0;\n}\nexport default Object.freeze(aa);\n"
  880.      2            ).warnings.filter(function ({
  881.      2                code
  882.      2            }) {
  883.      2                return code === "expected_a_at_b_c";
  884.      2            }).length === 2,
  885.      1            "the split leaves body AND closer needing a column-fix"
  886.      1        );
  887.      1
  888.      1// A one-liner block is split, re-indented and its closer moved, across
  889.      1// passes. The trailing comment must survive, attached to the closer.
  890.      1
  891.      1        await autofixFile({
  892.      1            expect: (
  893.      1                "function aa(bb) {\n    if (bb) {\n        return bb;\n" +
  894.      1                "    } // keep me\n    return 0;\n}\n" +
  895.      1                "export default Object.freeze(aa);\n"
  896.      1            ),
  897.      1            name: "autofix_break.mjs",
  898.      1            source: (
  899.      1                "function aa(bb) {\n    if (bb) { return bb; } // keep me\n" +
  900.      1                "    return 0;\n}\nexport default Object.freeze(aa);\n"
  901.      1            )
  902.      1        });
  903.      1
  904.      1// A *.sh file is not javascript: only its `node --eval` blocks are fixed,
  905.      1// and the surrounding shell must come back byte-identical.
  906.      1
  907.      1        await autofixFile({
  908.      1            expect: (
  909.      1                "shAa() {\n    node --eval '\nconsole.log(\n    0 +\n    0\n" +
  910.      1                ");\n'\n}\n"
  911.      1            ),
  912.      1            name: "autofix_embedded.sh",
  913.      1            process_env: {
  914.      1                JSLINT_BETA: "1"
  915.      1            },
  916.      1            source: (
  917.      1                "shAa() {\n    node --eval '\nconsole.log(\n    0\n  + 0\n" +
  918.      1                ");\n'\n}\n"
  919.      1            )
  920.      1        });
  921.      1
  922.      1// An embedded block with a too_long ALREADY in it is still fixed, and the
  923.      1// residual too_long still exits nonzero.
  924.      1
  925.      1        source = String(`
  926.      1shAa() {
  927.      1    node --eval '
  928.      1console.log("${"a".repeat(80)}");
  929.      1console.log( 0);
  930.      1'
  931.      1}
  932.      1        `).trim() + "\n";
  933.      1        await autofixFile({
  934.      1            exit: processExit1,
  935.      1            expect: source.replace("( 0)", "(0)"),
  936.      1            name: "autofix_embedded_long.sh",
  937.      1            source
  938.      1        });
  939.      1
  940.      1// A too_long that a fix SURFACES keeps the fix and blocks none after it. The
  941.      1// join makes line 3 82 columns, and the closed-form block below still needs
  942.      1// two more passes - its split, then its re-indent.
  943.      1
  944.      1        source = String(`
  945.      1/*jslint beta*/
  946.      1function aa(bb, cc) {
  947.      1    return bb.${"a".repeat(66)}
  948.      1    + cc;
  949.      1}
  950.      1function dd(ee) { return ee; }
  951.      1aa(dd(0), 0);
  952.      1        `).trim() + "\n";
  953.      1        await autofixFile({
  954.      1            exit: processExit1,
  955.      1            expect: source.replace(
  956.      1                "\n    + cc;",
  957.      1                " +\n    cc;"
  958.      1            ).replace(
  959.      1                "{ return ee; }",
  960.      1                "{\n    return ee;\n}"
  961.      1            ),
  962.      1            name: "autofix_long_join.mjs",
  963.      1            source
  964.      1        });
  965.      1
  966.      1// An *.html file is fixed the same way, but through its <script> blocks and
  967.      1// with browser:true - mirroring how jslint_from_file lints them.
  968.      1
  969.      1        await autofixFile({
  970.      1            expect: (
  971.      1                "<body>\n<script>\n/*jslint browser*/\nwindow.console.log(\n" +
  972.      1                "    0\n    + 0\n);\n</script>\n</body>\n"
  973.      1            ),
  974.      1            name: "autofix_embedded.html",
  975.      1            source: (
  976.      1                "<body>\n<script>\n/*jslint browser*/\nwindow.console.log(\n" +
  977.      1                "    0\n  + 0\n);\n</script>\n</body>\n"
  978.      1            )
  979.      1        });
  980.      1
  981.      1// A *.md file is linted with mode_conditional, i.e. only blocks carrying a
  982.      1// /*jslint directive. Autofix inherits that from jslint_from_file, so the
  983.      1// FIRST block below is repaired and the SECOND is left byte-identical.
  984.      1
  985.      1        await autofixFile({
  986.      1            expect: (
  987.      1                "# aa\n\nnode --eval '\n/*jslint node*/\nconsole.log(\n" +
  988.      1                "    0 +\n    0\n);\n'\n\nnode --eval '\nconsole.log(\n" +
  989.      1                "    0\n  + 0\n);\n'\n"
  990.      1            ),
  991.      1            name: "autofix_embedded.md",
  992.      1            process_env: {
  993.      1                JSLINT_BETA: "1"
  994.      1            },
  995.      1            source: (
  996.      1                "# aa\n\nnode --eval '\n/*jslint node*/\nconsole.log(\n" +
  997.      1                "    0\n  + 0\n);\n'\n\nnode --eval '\nconsole.log(\n" +
  998.      1                "    0\n  + 0\n);\n'\n"
  999.      1            )
 1000.      1        });
 1001.      1
 1002.      1// A CRLF or CR container is fixed the same way, and its line terminators
 1003.      1// survive, inside the embedded block too.
 1004.      1
 1005.      1        await autofixFile({
 1006.      1            expect: String(
 1007.      1                "shAa() {\n    node --eval '\nconsole.log(\n    0 +\n    0\n" +
 1008.      1                ");\n'\n}\n"
 1009.      1            ).replace((/\n/g), "\r\n"),
 1010.      1            name: "autofix_embedded_crlf.sh",
 1011.      1            process_env: {
 1012.      1                JSLINT_BETA: "1"
 1013.      1            },
 1014.      1            source: String(
 1015.      1                "shAa() {\n    node --eval '\nconsole.log(\n    0\n  + 0\n" +
 1016.      1                ");\n'\n}\n"
 1017.      1            ).replace((/\n/g), "\r\n")
 1018.      1        });
 1019.      1        await autofixFile({
 1020.      1            expect: String(
 1021.      1                "<body>\n<script>\n/*jslint browser*/\nwindow.console.log(\n" +
 1022.      1                "    0\n    + 0\n);\n</script>\n</body>\n"
 1023.      1            ).replace((/\n/g), "\r"),
 1024.      1            name: "autofix_embedded_cr.html",
 1025.      1            source: String(
 1026.      1                "<body>\n<script>\n/*jslint browser*/\nwindow.console.log(\n" +
 1027.      1                "    0\n  + 0\n);\n</script>\n</body>\n"
 1028.      1            ).replace((/\n/g), "\r")
 1029.      1        });
 1030.      1
 1031.      1// A missing file exits 1 with the error printed, like a plain lint - not an
 1032.      1// unhandled rejection that never reaches process_exit.
 1033.      1
 1034.      1        await jslint.jslint_cli({
 1035.      1            // suppress error
 1036.      1            console_error: noop,
 1037.      1            mode_cli: true,
 1038.      1            process_argv: [
 1039.      1                "node",
 1040.      1                "jslint.mjs",
 1041.      1                "jslint_autofix=.tmp/autofix_missing.mjs"
 1042.      1            ],
 1043.      1            process_exit: processExit1
 1044.      1        });
 1045.      1
 1046.      1// A DIRECTORY rides the same walk as a plain lint of one, and every file whose
 1047.      1// lint returns <autofixed> is written back; a clean file is left alone.
 1048.      1
 1049.      1        await fsWriteFileWithParents(
 1050.      1            ".tmp/autofix_dir/aa.mjs",
 1051.      1            "String( 0);\n"
 1052.      1        );
 1053.      1        await fsWriteFileWithParents(
 1054.      1            ".tmp/autofix_dir/bb.mjs",
 1055.      1            "String(0);\n"
 1056.      1        );
 1057.      1        await jslint.jslint_cli({
 1058.      1            // suppress error
 1059.      1            console_error: noop,
 1060.      1            mode_cli: true,
 1061.      1            process_argv: [
 1062.      1                "node",
 1063.      1                "jslint.mjs",
 1064.      1                "jslint_autofix=.tmp/autofix_dir"
 1065.      1            ],
 1066.      1            process_exit: processExit0
 1067.      1        });
 1068.      1        assertOrThrow(
 1069.      1            (
 1070.      1                await moduleFs.promises.readFile(
 1071.      1                    ".tmp/autofix_dir/aa.mjs",
 1072.      1                    "utf8"
 1073.      1                )
 1074.      1            ) === "String(0);\n",
 1075.      1            ".tmp/autofix_dir/aa.mjs"
 1076.      1        );
 1077.      1        assertOrThrow(
 1078.      1            (
 1079.      1                await moduleFs.promises.readFile(
 1080.      1                    ".tmp/autofix_dir/bb.mjs",
 1081.      1                    "utf8"
 1082.      1                )
 1083.      1            ) === "String(0);\n",
 1084.      1            ".tmp/autofix_dir/bb.mjs"
 1085.      1        );
 1086.      1    });
 1087.      1});
 1088.      1
 1089.      1jstestDescribe((
 1090.      1    "test jslint's cli handling-behavior"
 1091.      1), function () {
 1092.      1    jstestIt((
 1093.      1        "test cli-apidoc handling-behavior"
 1094.      1    ), function () {
 1095.      1        jslint.jslint_cli({
 1096.      1            mode_cli: true,
 1097.      1            process_argv: [
 1098.      1                "node",
 1099.      1                "jslint.mjs",
 1100.      1                "jslint_apidoc=.artifact/apidoc.html",
 1101.      1                JSON.stringify({
 1102.      1                    example_list: [
 1103.      1                        "README.md",
 1104.      1                        "test.mjs",
 1105.      1                        "jslint.mjs"
 1106.      1                    ],
 1107.      1                    github_repo: "https://github.com/jslint-org/jslint",
 1108.      1                    module_list: [
 1109.      1                        {
 1110.      1                            pathname: "./jslint.mjs"
 1111.      1                        }
 1112.      1                    ],
 1113.      1                    package_name: "JSLint",
 1114.      1                    version: jslint.jslint_edition
 1115.      1                })
 1116.      1            ],
 1117.      1            process_exit: processExit0
 1118.      1        });
 1119.      1    });
 1120.      1    jstestIt((
 1121.      1        "test cli-cjs-lint-file handling-behavior"
 1122.      1    ), async function () {
 1123.      1
 1124.      1// Through the cjs wrapper, <jslint_cli> must lint, not resolve 0 unseen: in
 1125.      1// its old new-context sandbox there was no process, so the cli returned early.
 1126.      1
 1127.      1        await fsWriteFileWithParents(
 1128.      1            ".tmp/cli_cjs_lint_file/aa.js",
 1129.      1            "let aa = 1;\n"
 1130.      1        );
 1131.      1        assertJsonEqual(
 1132.      1            await jslintCjs.jslint_cli({
 1133.      1                console_error: noop,
 1134.      1                mode_cli: true,
 1135.      1                process_argv: [
 1136.      1                    "node",
 1137.      1                    "jslint.mjs",
 1138.      1                    ".tmp/cli_cjs_lint_file/aa.js"
 1139.      1                ],
 1140.      1                process_exit: processExit1
 1141.      1            }),
 1142.      1            1
 1143.      1        );
 1144.      1    });
 1145.      1    jstestIt((
 1146.      1        "test cli-embedded-line-offset handling-behavior"
 1147.      1    ), async function () {
 1148.      1
 1149.      1// An embedded block whose opening tag is LINE 1 of its container has no line
 1150.      1// terminator before it, so the offset arithmetic must still yield 1 - a
 1151.      1// precedence slip once made it 0, and every warning in the block reported one
 1152.      1// line too high. <foo> sits on file-line 3 and must be reported there.
 1153.      1
 1154.      1        const stderr_list = [];
 1155.      1        await fsWriteFileWithParents(
 1156.      1            ".tmp/embedded_line1.html",
 1157.      1            "<script>\n/*jslint browser*/\nfoo;\n</script>\n"
 1158.      1        );
 1159.      1        await jslint.jslint_cli({
 1160.      1            console_error: function (msg) {
 1161.      1                stderr_list.push(String(msg));
 1162.      1            },
 1163.      1            mode_cli: true,
 1164.      1            process_argv: [
 1165.      1                "node",
 1166.      1                "jslint.mjs",
 1167.      1                ".tmp/embedded_line1.html"
 1168.      1            ],
 1169.      1            process_exit: processExit1
 1170.      1        });
 1171.      1        assertOrThrow(
 1172.      1            stderr_list.some(function (msg) {
 1173.      1                return msg.includes("line 3, column 1");
 1174.      1            }),
 1175.      1            JSON.stringify(stderr_list)
 1176.      1        );
 1177.      1    });
 1178.      1    jstestIt((
 1179.      1        "test cli-file-error handling-behavior"
 1180.      1    ), function () {
 1181.      1        jslint.jslint_cli({
 1182.      1            // suppress error
 1183.      1            console_error: noop,
 1184.      1            file: "undefined",
 1185.      1            mode_cli: true,
 1186.      1            process_exit: processExit1
 1187.      1        });
 1188.      1    });
 1189.      1    jstestIt((
 1190.      1        "test cli-file-kinds handling-behavior"
 1191.      1    ), async function () {
 1192.      1        await moduleFs.promises.mkdir(
 1193.      1            ".tmp/invalid_file/invalid_file.js",
 1194.      1            {recursive: true}
 1195.      1        );
 1196.      1        [
 1197.      1            ".",                // test dir handling-behavior
 1198.      1            ".tmp/invalid_file",// test invalid-file handling-behavior
 1199.      1            "jslint.mjs",       // test file handling-behavior
 1200.      1            undefined           // test file-undefined handling-behavior
 1201.      4        ].forEach(function (file) {
 1202.      4            jslint.jslint_cli({
 1203.      4                file,
 1204.      4                mode_cli: true,
 1205.      4                process_env: {
 1206.      4                    JSLINT_BETA: "1"
 1207.      4                },
 1208.      4                process_exit: processExit0
 1209.      4            });
 1210.      4        });
 1211.      1    });
 1212.      1    jstestIt((
 1213.      1        "test cli-jslint-wrapper-vim handling-behavior"
 1214.      1    ), function () {
 1215.      1        jslint.jslint_cli({
 1216.      1            // suppress error
 1217.      1            console_error: noop,
 1218.      1            mode_cli: true,
 1219.      1            process_argv: [
 1220.      1                "node",
 1221.      1                "jslint.mjs",
 1222.      1                "jslint_wrapper_vim",
 1223.      1                "syntax-error.js"
 1224.      1            ],
 1225.      1            process_exit: processExit1,
 1226.      1            source: "syntax error"
 1227.      1        });
 1228.      1    });
 1229.      1    jstestIt((
 1230.      1        "test cli-null-case handling-behavior"
 1231.      1    ), function () {
 1232.      1        jslint.jslint_cli({
 1233.      1            mode_noop: true,
 1234.      1            process_exit: processExit0
 1235.      1        });
 1236.      1    });
 1237.      1    jstestIt((
 1238.      1        "test cli-report handling-behavior"
 1239.      1    ), function () {
 1240.      1        jslint.jslint_cli({
 1241.      1            // suppress error
 1242.      1            console_error: noop,
 1243.      1            mode_cli: true,
 1244.      1            process_argv: [
 1245.      1                "node",
 1246.      1                "jslint.mjs",
 1247.      1                "jslint_report=.tmp/jslint_report.html",
 1248.      1                "jslint.mjs"
 1249.      1            ],
 1250.      1            process_exit: processExit0
 1251.      1        });
 1252.      1    });
 1253.      1    jstestIt((
 1254.      1        "test cli-report-embedded handling-behavior"
 1255.      1    ), async function () {
 1256.      1
 1257.      1// A container-file returns no single lint-result, so jslint_report refuses it
 1258.      1// with exit 1 instead of crashing on the missing <warnings>.
 1259.      1
 1260.      1        await fsWriteFileWithParents(".tmp/jslint_report.md", "# aa\n");
 1261.      1        await jslint.jslint_cli({
 1262.      1            // suppress error
 1263.      1            console_error: noop,
 1264.      1            mode_cli: true,
 1265.      1            process_argv: [
 1266.      1                "node",
 1267.      1                "jslint.mjs",
 1268.      1                "jslint_report=.tmp/jslint_report_embedded.html",
 1269.      1                ".tmp/jslint_report.md"
 1270.      1            ],
 1271.      1            process_exit: processExit1
 1272.      1        });
 1273.      1    });
 1274.      1    jstestIt((
 1275.      1        "test cli-report-error handling-behavior"
 1276.      1    ), function () {
 1277.      1        jslint.jslint_cli({
 1278.      1            // suppress error
 1279.      1            console_error: noop,
 1280.      1            mode_cli: true,
 1281.      1            process_argv: [
 1282.      1                "node",
 1283.      1                "jslint.mjs",
 1284.      1                "jslint_report=.tmp/jslint_report.html",
 1285.      1                "syntax-error.js"
 1286.      1            ],
 1287.      1            process_exit: processExit1,
 1288.      1            source: "syntax error"
 1289.      1        });
 1290.      1    });
 1291.      1    jstestIt((
 1292.      1        "test cli-report-json handling-behavior"
 1293.      1    ), function () {
 1294.      1        jslint.jslint_cli({
 1295.      1            // suppress error
 1296.      1            console_error: noop,
 1297.      1            mode_cli: true,
 1298.      1            process_argv: [
 1299.      1                "node",
 1300.      1                "jslint.mjs",
 1301.      1                "jslint_report=.tmp/jslint_report.html",
 1302.      1                "aa.json"
 1303.      1            ],
 1304.      1            process_exit: processExit0,
 1305.      1            source: "[]"
 1306.      1        });
 1307.      1    });
 1308.      1    jstestIt((
 1309.      1        "test cli-report-json-error handling-behavior"
 1310.      1    ), function () {
 1311.      1        jslint.jslint_cli({
 1312.      1            // suppress error
 1313.      1            console_error: noop,
 1314.      1            mode_cli: true,
 1315.      1            process_argv: [
 1316.      1                "node",
 1317.      1                "jslint.mjs",
 1318.      1                "jslint_report=.tmp/jslint_report.html",
 1319.      1                "aa.json"
 1320.      1            ],
 1321.      1            process_exit: processExit1,
 1322.      1            source: "["
 1323.      1        });
 1324.      1    });
 1325.      1    jstestIt((
 1326.      1        "test cli-report-misc handling-behavior"
 1327.      1    ), function () {
 1328.      1        jslint.jslint_cli({
 1329.      1            // suppress error
 1330.      1            console_error: noop,
 1331.      1            mode_cli: true,
 1332.      1            process_argv: [
 1333.      1                "node",
 1334.      1                "jslint.mjs",
 1335.      1                "jslint_report=.tmp/jslint_report.html",
 1336.      1                "aa.js"
 1337.      1            ],
 1338.      1            process_exit: processExit0,
 1339.      1            source: "String();"
 1340.      1        });
 1341.      1        jslint.jslint_cli({
 1342.      1            // suppress error
 1343.      1            console_error: noop,
 1344.      1            mode_cli: true,
 1345.      1            process_argv: [
 1346.      1                "node",
 1347.      1                "jslint.mjs",
 1348.      1                "jslint_report=.tmp/jslint_report.html",
 1349.      1                "aa.js"
 1350.      1            ],
 1351.      1            process_exit: processExit1,
 1352.      1            source: "(aa)=>aa; function aa([aa]){}"
 1353.      1        });
 1354.      1    });
 1355.      1    jstestIt((
 1356.      1        "test cli-syntax-error handling-behavior"
 1357.      1    ), function () {
 1358.      1        jslint.jslint_cli({
 1359.      1            // suppress error
 1360.      1            console_error: noop,
 1361.      1            file: "syntax-error.js",
 1362.      1            mode_cli: true,
 1363.      1            option: {
 1364.      1                trace: true
 1365.      1            },
 1366.      1            process_exit: processExit1,
 1367.      1            source: "syntax error"
 1368.      1        });
 1369.      1    });
 1370.      1    jstestIt((
 1371.      1        "test cli-window-jslint handling-behavior"
 1372.      1    ), function () {
 1373.      1        [
 1374.      1            "&window_jslint=",
 1375.      1            "&window_jslint=12",
 1376.      1            "&window_jslint=1?",
 1377.      1            "&window_jslint=?",
 1378.      1            "?window_jslint=",
 1379.      1            "?window_jslint=12",
 1380.      1            "?window_jslint=1?",
 1381.      1            "?window_jslint=?",
 1382.      1            "window_jslint=1",
 1383.      1            "window_jslint=1&",
 1384.      1            "window_jslint=12",
 1385.      1            "window_jslint=1?"
 1386.     12        ].forEach(function (import_meta_url) {
 1387.     12            jslint.jslint_cli({
 1388.     12                import_meta_url
 1389.     12            });
 1390.     12            assertOrThrow(globalThis.jslint === undefined);
 1391.     12        });
 1392.      1        [
 1393.      1            "&window_jslint=1",
 1394.      1            "&window_jslint=1&",
 1395.      1            "?window_jslint=1",
 1396.      1            "?window_jslint=1&"
 1397.      4        ].forEach(function (import_meta_url) {
 1398.      4            jslint.jslint_cli({
 1399.      4                import_meta_url
 1400.      4            });
 1401.      4            assertOrThrow(globalThis.jslint === jslint);
 1402.      4            delete globalThis.jslint;
 1403.      4        });
 1404.      1    });
 1405.      1});
 1406.      1
 1407.      1jstestDescribe((
 1408.      1    "test jslint's no-warnings handling-behavior"
 1409.      1), function () {
 1410.      1    jstestIt((
 1411.      1        "test jslint's no-warnings handling-behavior"
 1412.      1    ), function () {
 1413.      1        Object.values({
 1414.      1            array: [
 1415.      1                "new Array(0);"
 1416.      1            ],
 1417.      1            async_await: [
 1418.      1                (`
 1419.      1/*jslint fart*/
 1420.      1let aa = 0;
 1421.      1aa = async () => {
 1422.      1    try {
 1423.      1        return await aa();
 1424.      1    } catch (err) {
 1425.      1        await err();
 1426.      1    }
 1427.      1};
 1428.      1await aa();
 1429.      1                `),
 1430.      1                "async function aa() {\n    await aa();\n}\nawait aa();",
 1431.      1
 1432.      1// PR-405 - Bugfix - fix expression after "await" mis-identified as statement.
 1433.      1
 1434.      1                "async function aa() {\n    await aa;\n}\nawait aa();",
 1435.      1                (`
 1436.      1async function aa() {
 1437.      1    try {
 1438.      1        return await aa();
 1439.      1    } catch (err) {
 1440.      1        await err();
 1441.      1    }
 1442.      1}
 1443.      1await aa();
 1444.      1                `)
 1445.      1            ],
 1446.      1
 1447.      1// PR-351 - Add BigInt support.
 1448.      1
 1449.      1            bigint: [
 1450.      1                (`
 1451.      1String(0b0n);
 1452.      1String(0o0n);
 1453.      1String(0x0n);
 1454.      1String(BigInt(0n));
 1455.      1String(typeof String === "bigint");
 1456.      1                `)
 1457.      1            ],
 1458.      1            date: [
 1459.      1                (`
 1460.      1Date.getTime();
 1461.      1String().getTime();
 1462.      1String.aa().getTime();
 1463.      1                `)
 1464.      1            ],
 1465.      1            destructure: [
 1466.      1
 1467.      1// PR-500 - Unify ES2015-destructure-logic.
 1468.      1
 1469.      1                [
 1470.      1                    (`
 1471.      1(function ({expr}) {
 1472.      1    aa(bb, cc, dd, ee, ff, gg);
 1473.      1}());
 1474.      1                    `),
 1475.      1                    (`
 1476.      1(function for_loop() {
 1477.      1    for (const {expr} of for_loop) {
 1478.      1        aa(bb, cc, dd, ee, ff, gg);
 1479.      1    }
 1480.      1}());
 1481.      1                    `),
 1482.      1                    (`
 1483.      1/*jslint fart*/
 1484.      1(({expr}) => {
 1485.      1    aa(bb, cc, dd, ee, ff, gg);
 1486.      1}());
 1487.      1                    `),
 1488.      1                    "const {expr}",
 1489.      1                    "let {expr}",
 1490.      1                    "let [aa, bb, cc, dd, ee, ff, gg] = 0;\n{expr}"
 1491.      6                ].map(function (source) {
 1492.      6                    let expr = String(`
 1493.      6[
 1494.      6    {
 1495.      6        cc,
 1496.      6        dd = 0,
 1497.      6        dd: ee,
 1498.      6        ee: [{bb}],
 1499.      6        ...aa
 1500.      6    },
 1501.      6    [
 1502.      6        gg,
 1503.      6        ...ff
 1504.      6    ]
 1505.      6]
 1506.      6                    `).trim();
 1507.      1                    if ((/function for_loop/).test(source)) {
 1508.      1                        expr = expr.replace((/\n/g), "\n    ");
 1509.      1                    }
 1510.      6                    source = source.trim().replace("{expr}", expr);
 1511.      3                    if (!(/\=>|function/).test(source)) {
 1512.      3                        source = (`
 1513.      3${source} = (function () {
 1514.      3    return;
 1515.      3}());
 1516.      3aa(bb, cc, dd, ee, ff, gg);
 1517.      3                        `);
 1518.      3                    }
 1519.      6                    return source;
 1520.      6                }),
 1521.      1
 1522.      1// PR-459 - Allow destructuring-assignment after function-definition.
 1523.      1
 1524.      1                (`
 1525.      1let aa;
 1526.      1let bb;
 1527.      1function cc() {
 1528.      1    return;
 1529.      1}
 1530.      1[aa, bb] = cc();
 1531.      1aa(bb, cc);
 1532.      1                `),
 1533.      1
 1534.      1// PR-514 - Bugfix - Walk a default in destructuring-assignment, so 'cc' is
 1535.      1// used.
 1536.      1
 1537.      1                (`
 1538.      1let aa;
 1539.      1let cc = 0;
 1540.      1[
 1541.      1    [
 1542.      1        aa = cc
 1543.      1    ]
 1544.      1] = [];
 1545.      1aa();
 1546.      1                `)
 1547.      1            ],
 1548.      1            directive: [
 1549.      1                (`
 1550.      1#!/usr/bin/env node
 1551.      1/*global aa*/
 1552.      1/*jslint browser:false, node*/
 1553.      1/*property bb*/
 1554.      1"use strict";
 1555.      1aa.bb();
 1556.      1                `)
 1557.      1            ],
 1558.      1            ellipsis: [
 1559.      1
 1560.      1// PR-483 - Allow parenthesis after ellipsis inside a function call.
 1561.      1
 1562.      1                (`
 1563.      1String(0, ...(
 1564.      1    String()
 1565.      1    ? 0
 1566.      1    : 1
 1567.      1));
 1568.      1                `),
 1569.      1
 1570.      1// Issue #401 - Add ES2018-syntax for object-literal-spread-operator.
 1571.      1
 1572.      1                (`
 1573.      1let aa;
 1574.      1aa = [
 1575.      1    0,
 1576.      1    ...aa(),
 1577.      1    0,
 1578.      1    ...aa,
 1579.      1    0,
 1580.      1    ...aa.aa,
 1581.      1    0
 1582.      1];
 1583.      1aa = {
 1584.      1    aa: 0,
 1585.      1    ...aa(),
 1586.      1    bb: 0,
 1587.      1    ...aa,
 1588.      1    cc: 0,
 1589.      1    ...aa.aa,
 1590.      1    dd: 0
 1591.      1};
 1592.      1aa();
 1593.      1                `)
 1594.      1            ],
 1595.      1            fart: [
 1596.      1                (`
 1597.      1/*jslint fart*/
 1598.      1let aa = async (bb, [cc, dd], {ee, ff}, ...gg) => {
 1599.      1    await bb(cc, dd, ee, ff, gg);
 1600.      1};
 1601.      1aa();
 1602.      1                `),
 1603.      1                "let aa = () => 0;\naa();"
 1604.      1            ],
 1605.      1            for: [
 1606.      1                (`
 1607.      1async function aa(bb, cc) {
 1608.      1    for (; bb < 0; bb += 1) { //jslint-ignore-line
 1609.      1        bb(cc);
 1610.      1    }
 1611.      1    for (bb = 0; bb < 0; bb += 1) { //jslint-ignore-line
 1612.      1        bb(cc);
 1613.      1    }
 1614.      1    for (cc in bb) { //jslint-ignore-line
 1615.      1        bb(cc);
 1616.      1    }
 1617.      1    for (cc of bb) { //jslint-ignore-line
 1618.      1        cc();
 1619.      1    }
 1620.      1    for (const ii in bb) { //jslint-ignore-line
 1621.      1        bb(cc, ii);
 1622.      1    }
 1623.      1    for (const ii of bb) {
 1624.      1        bb(cc, ii);
 1625.      1    }
 1626.      1    for (let ii = 0; ii < 0; ii += 1) {
 1627.      1        bb(cc, ii);
 1628.      1    }
 1629.      1    for (let ii of bb) {
 1630.      1        bb(cc, ii);
 1631.      1    }
 1632.      1    for await (const ii of bb) {
 1633.      1        bb(cc, ii);
 1634.      1    }
 1635.      1    for await (let ii of bb) {
 1636.      1        bb(cc, ii);
 1637.      1    }
 1638.      1    for (const ii of await (bb())) {
 1639.      1        bb(cc, ii);
 1640.      1    }
 1641.      1}
 1642.      1aa();
 1643.      1                `),
 1644.      1
 1645.      1// PR-514 - Bugfix - Walk the iterable of destructured for..of.
 1646.      1
 1647.      1                (`
 1648.      1function aa(bb) {
 1649.      1    for (const [cc, dd] of bb) {
 1650.      1        cc(dd);
 1651.      1    }
 1652.      1    for (const {ee} of bb) {
 1653.      1        ee();
 1654.      1    }
 1655.      1}
 1656.      1aa();
 1657.      1                `),
 1658.      1
 1659.      1// PR-514 - Bugfix - A ';' in a method-body inside a for-loop-head is not a
 1660.      1// for-loop-semicolon.
 1661.      1
 1662.      1                (`
 1663.      1function aa(bb) {
 1664.      1    for (const cc in { //jslint-ignore-line
 1665.      1        dd() {
 1666.      1            return;
 1667.      1        }
 1668.      1    }) {
 1669.      1        bb(cc);
 1670.      1    }
 1671.      1}
 1672.      1aa();
 1673.      1                `),
 1674.      1
 1675.      1// PR-514 - Bugfix - The '}' of a '${' does not pop the '{' of a function-body
 1676.      1// in a for-loop-head, since '${' is pushed too.
 1677.      1
 1678.      1                (`
 1679.      1function aa(bb) {
 1680.      1    for (const cc of function () {
 1681.      1        return \`\${bb}\`;
 1682.      1    }()) { //jslint-ignore-line
 1683.      1        bb(cc);
 1684.      1    }
 1685.      1}
 1686.      1aa();
 1687.      1                `)
 1688.      1            ],
 1689.      1            import: [
 1690.      1                `let aa = 0;\nimport(aa).then(aa).catch(aa).finally(aa);`,
 1691.      1                `let aa = await import("aa");\naa();`,
 1692.      1                `let aa = await import("aa", {with: {type: "json"}});\naa();`,
 1693.      1                `let {aa, bb} = await import("aa");\naa(bb);`
 1694.      1            ],
 1695.      1            indent_method: [
 1696.      1                (`
 1697.      1String
 1698.      1    .aa
 1699.      1    .aa()
 1700.      1    .aa(0)
 1701.      1    .aa(
 1702.      1        0,
 1703.      1        [0],
 1704.      1        \`${0}\`
 1705.      1    )
 1706.      1    .aa(
 1707.      1        String
 1708.      1            .aa()
 1709.      1            .aa(0)
 1710.      1            .aa(
 1711.      1                0,
 1712.      1                [0],
 1713.      1                \`${0}\`
 1714.      1            )
 1715.      1    )
 1716.      1    .aa(function ({
 1717.      1        aa
 1718.      1    }) {
 1719.      1        return aa;
 1720.      1    });
 1721.      1                `)
 1722.      1            ],
 1723.      1            jslint_disable: [
 1724.      1                "/*jslint-disable*/\n0\n/*jslint-enable*/"
 1725.      1            ],
 1726.      1            jslint_ignore_line: [
 1727.      1                "0 //jslint-ignore-line",
 1728.      1                "new aa //jslint-ignore-line"
 1729.      1            ],
 1730.      1            json: [
 1731.      1                "{\"aa\":[[],-0,null]}"
 1732.      1            ],
 1733.      1            label: [
 1734.      1                (`
 1735.      1function aa() {
 1736.      1bb: do {
 1737.      1        if (true) {
 1738.      1            break bb;
 1739.      1        }
 1740.      1    } while (true);
 1741.      1}
 1742.      1aa();
 1743.      1                `),
 1744.      1                (`
 1745.      1function aa() {
 1746.      1bb: for (const ii of aa) {
 1747.      1        if (ii) {
 1748.      1            break bb;
 1749.      1        }
 1750.      1    }
 1751.      1}
 1752.      1aa();
 1753.      1                `),
 1754.      1                (`
 1755.      1function aa() {
 1756.      1bb: for (let ii = 0; ii < 0; ii += 1) {
 1757.      1        if (ii) {
 1758.      1            break bb;
 1759.      1        }
 1760.      1    }
 1761.      1}
 1762.      1aa();
 1763.      1                `),
 1764.      1                (`
 1765.      1function aa() {
 1766.      1bb: switch (aa) {
 1767.      1    case 0:
 1768.      1        break bb;
 1769.      1    }
 1770.      1}
 1771.      1aa();
 1772.      1                `),
 1773.      1                (`
 1774.      1function aa() {
 1775.      1bb: while (true) {
 1776.      1        if (true) {
 1777.      1            break bb;
 1778.      1        }
 1779.      1    }
 1780.      1}
 1781.      1aa();
 1782.      1                `)
 1783.      1            ],
 1784.      1            literal: [
 1785.      1                "String(\"\".at());",
 1786.      1                "String(\"\\u{000041}\");",
 1787.      1                "String(\"\\u{10FFFF}\");",
 1788.      1                "String(String.raw`\\u{110000}${0}\\u0`);",
 1789.      1                "String([].at());",
 1790.      1                "String(`\\u{000041}`);",
 1791.      1                "String(`\\u{10FFFF}`);"
 1792.      1            ],
 1793.      1            logical_assignment: [
 1794.      1
 1795.      1// PR-514 - Bugfix - '??=' and '||=' assign an unassigned variable.
 1796.      1
 1797.      1                (`
 1798.      1function aa(bb) {
 1799.      1    let cc;
 1800.      1    cc ??= bb;
 1801.      1    return cc;
 1802.      1}
 1803.      1aa();
 1804.      1                `),
 1805.      1                (`
 1806.      1function aa(bb) {
 1807.      1    let cc;
 1808.      1    cc ||= bb;
 1809.      1    return cc;
 1810.      1}
 1811.      1aa();
 1812.      1                `),
 1813.      1                "let aa = 0;\naa &&= 0;",
 1814.      1                "let aa = 0;\naa ??= 0;",
 1815.      1                "let aa = 0;\naa ||= 0;"
 1816.      1            ],
 1817.      1            loop: [
 1818.      1                (`
 1819.      1function aa() {
 1820.      1    do {
 1821.      1        aa();
 1822.      1    } while (aa());
 1823.      1}
 1824.      1aa();
 1825.      1                `),
 1826.      1
 1827.      1// PR-378 - Relax warning "function_in_loop".
 1828.      1
 1829.      1                (`
 1830.      1function aa() {
 1831.      1    while (true) {
 1832.      1        (function () {
 1833.      1            return;
 1834.      1        }());
 1835.      1    }
 1836.      1}
 1837.      1aa();
 1838.      1                `)
 1839.      1            ],
 1840.      1            module: [
 1841.      1                "export default Object.freeze();",
 1842.      1
 1843.      1// PR-439 - Add grammar for "export async function ...".
 1844.      1
 1845.      1                (`
 1846.      1export default Object.freeze(async function () {
 1847.      1    return await 0;
 1848.      1});
 1849.      1                `),
 1850.      1                // `import "aa";`,
 1851.      1                `import * as aa from "aa";\naa();`,
 1852.      1                `import aa from "aa" with {type: "json"};\naa();`,
 1853.      1                `import aa from "aa";\naa();`,
 1854.      1                `import aa, {aa as bb, cc} from "aa";\naa(bb, cc);`,
 1855.      1                `import {} from "aa";`
 1856.      1            ],
 1857.      1            new: [
 1858.      1                "new String`aa`();"
 1859.      1            ],
 1860.      1            number: [
 1861.      1                "String(0.0e0);",
 1862.      1                "String(0b0);",
 1863.      1                "String(0o0);",
 1864.      1                "String(0x0);"
 1865.      1            ],
 1866.      1
 1867.      1// PR-390 - Add numeric-separator support.
 1868.      1
 1869.      1            numeric_separator: [
 1870.      1                "String(0.0_0_0);",
 1871.      1                "String(0b0_1111_1111n);",
 1872.      1                "String(0o0_1237_1237n);",
 1873.      1                "String(0x0_123f_123fn);",
 1874.      1                "String(1_234_234.1_234_234E1_234_234);"
 1875.      1            ],
 1876.      1            optional_chaining: [
 1877.      1                "String().aa?.bb?.cc();",
 1878.      1                "delete String?.[0];",
 1879.      1                "delete String?.aa;"
 1880.      1            ],
 1881.      1            param: [
 1882.      1                "function aa({aa, bb}) {\n    return {aa, bb};\n}\naa();",
 1883.      1                (`
 1884.      1function aa({constructor}) {
 1885.      1    return {constructor};
 1886.      1}
 1887.      1aa();
 1888.      1                `)
 1889.      1            ],
 1890.      1            property: [
 1891.      1                "String[`!`]();"
 1892.      1            ],
 1893.      1            regexp: [
 1894.      1                `RegExp.escape("");`,
 1895.      1                `String(/(?!.)(?:.)(?=.)/);`,
 1896.      1                `String(/(?im-s:.)/);`,
 1897.      1                `String(/./dgimsuy);`,
 1898.      1                `String(/./dgimsvy);`,
 1899.      1                `String(/[\\--\\-]/);`,
 1900.      1                `function aa() {\n    return /./;\n}\naa();`
 1901.      1            ],
 1902.      1            scope: [
 1903.      1                "(function aa(bb = aa) {\n    aa(bb);\n}());",
 1904.      1
 1905.      1// PR-514 - Bugfix - A 'var' named after its named function expression is a new
 1906.      1// writable binding, so assigning it does not warn bad_assignment_a.
 1907.      1
 1908.      1                (`
 1909.      1String(function aa() {
 1910.      1    var aa = 0; //jslint-ignore-line
 1911.      1    aa = 1;
 1912.      1    return aa;
 1913.      1});
 1914.      1                `),
 1915.      1
 1916.      1// PR-514 - A parameter named after its named function expression shadows the
 1917.      1// name, like any parameter shadowing an outer name, so it does not warn.
 1918.      1
 1919.      1                "String(function aa(aa) {\n    return aa;\n});",
 1920.      1
 1921.      1// PR-514 - Bugfix - A 'var' redeclared in a nested block keeps the first one,
 1922.      1// so a use between the two does not warn temporal_dead_zone_a.
 1923.      1
 1924.      1                (`
 1925.      1function aa() {
 1926.      1    var bb = 0;
 1927.      1    bb();
 1928.      1    if (aa) {
 1929.      1        var bb = 1; //jslint-ignore-line
 1930.      1        bb();
 1931.      1    }
 1932.      1}
 1933.      1aa();
 1934.      1                `),
 1935.      1                "function aa(bb = aa) {\n    aa(bb);\n}\naa();",
 1936.      1                (`
 1937.      1function bb(cc) {
 1938.      1    return cc;
 1939.      1}
 1940.      1bb(function aa() {
 1941.      1    return;
 1942.      1});
 1943.      1                `),
 1944.      1                (`
 1945.      1if (String) {
 1946.      1    let aa = 0;
 1947.      1    aa();
 1948.      1} else {
 1949.      1    let aa = 0;
 1950.      1    aa();
 1951.      1}
 1952.      1                `),
 1953.      1                (`
 1954.      1if (String) {
 1955.      1    var aa = 0; //jslint-ignore-line
 1956.      1}
 1957.      1aa();
 1958.      1                `)
 1959.      1            ],
 1960.      1            ternary: [
 1961.      1                (`
 1962.      1String(
 1963.      1    String()
 1964.      1    ? 0
 1965.      1    : 1
 1966.      1);
 1967.      1String(
 1968.      1    String()
 1969.      1    ? \`$\{0}\`
 1970.      1    : \`$\{1}\`
 1971.      1);
 1972.      1
 1973.      1// PR-394 - Bugfix
 1974.      1// Fix jslint falsely believing megastring literals \`0\` and \`1\` are similar.
 1975.      1
 1976.      1String(
 1977.      1    String()
 1978.      1    ? \`0\`
 1979.      1    : \`1\`
 1980.      1);
 1981.      1
 1982.      1// PR-510 - Bugfix - Fix jslint treating tagged templates as equal.
 1983.      1
 1984.      1String(
 1985.      1    String()
 1986.      1    ? String\`$\{0}$\{0}\`
 1987.      1    : String\`$\{0}$\{1}\`
 1988.      1);
 1989.      1                `)
 1990.      1            ],
 1991.      1            try_catch_finally: [
 1992.      1                (`
 1993.      1try {
 1994.      1    String();
 1995.      1} catch (err) {
 1996.      1    err();
 1997.      1} finally {
 1998.      1    String();
 1999.      1}
 2000.      1                `),
 2001.      1                (`
 2002.      1try {
 2003.      1    String();
 2004.      1} catch (err) {
 2005.      1    var aa = err; //jslint-ignore-line
 2006.      1} finally {
 2007.      1    String(aa);
 2008.      1}
 2009.      1                `)
 2010.      1            ],
 2011.      1            use_strict: [
 2012.      1                (`
 2013.      1"use strict";
 2014.      1function aa() {
 2015.      1    "use strict";
 2016.      1    return;
 2017.      1}
 2018.      1aa();
 2019.      1                `)
 2020.      1            ],
 2021.      1            var: [
 2022.      1                "const aa = 0;\naa();\n",
 2023.      1                "let aa = 0;\naa();\n",
 2024.      1                "var aa = 0;\naa();\n"
 2025.      1            ]
 2026.     31        }).forEach(function (codeList) {
 2027.     31            let elemPrv = "";
 2028.     97            codeList.flat().flat().forEach(function (source) {
 2029.     97                let warnings;
 2030.     97                source = source.trim();
 2031.     97                // Assert codeList is sorted.
 2032.     97                assertOrThrow(elemPrv < source, JSON.stringify([
 2033.     97                    elemPrv, source
 2034.     97                ], undefined, 4));
 2035.     97                elemPrv = source;
 2036.     97                [
 2037.     97                    jslint.jslint,
 2038.     97                    jslintCjs.jslint
 2039.    194                ].forEach(function (jslint) {
 2040.    194                    warnings = jslint(source, {
 2041.    194                        beta: true
 2042.    194                    }).warnings;
 2043.    194                    assertOrThrow(
 2044.    194                        warnings.length === 0,
 2045.    194                        `\n\n${source}\n\n${JSON.stringify(
 2046.    194                            warnings,
 2047.    194                            undefined,
 2048.    194                            4
 2049.    194                        )}`
 2050.    194                    );
 2051.    194                });
 2052.     97            });
 2053.     31        });
 2054.      1    });
 2055.      1});
 2056.      1
 2057.      1jstestDescribe((
 2058.      1    "test jslint's option handling-behavior"
 2059.      1), function () {
 2060.      1
 2061.      1// Samples group by option, so each option is one test with a unique name.
 2062.      1
 2063.      1    const sampleDict = Object.groupBy([
 2064.      1        [{bitwise: true}, "String(String | 0);"],
 2065.      1        [{browser: true}, ";\nString(new XMLHttpRequest());"],
 2066.      1        [{convert: true}, "String(\"aa\" + 0);"],
 2067.      1        [{couch: true}, "registerType();"],
 2068.      1        [{devel: true}, "debugger;"],
 2069.      1
 2070.      1// PR-404 - Alias "evil" to jslint-directive "eval" for backwards-compat.
 2071.      1
 2072.      1        [{eval: true, evil: true}, "new Function();\neval();"],
 2073.      1
 2074.      1// PR-514 - Bugfix - A string-key named get aa does not duplicate an accessor.
 2075.      1
 2076.      1        [{getset: true}, String(`
 2077.      1String({
 2078.      1    get aa() {
 2079.      1        return;
 2080.      1    },
 2081.      1    "get aa": 0
 2082.      1});
 2083.      1        `).trim()],
 2084.      1        [{getset: true}, "String({get aa() {\n    return;\n}});"],
 2085.      1        [{getset: true}, "String({set aa(aa) {\n    return aa;\n}});"],
 2086.      1        [{indent2: true}, sourceJslintMjs.replace((/    /g), "  ")],
 2087.      1        [{indent2: true}, "function aa() {\n  return;\n}\naa();"],
 2088.      1        [{long: true}, "/".repeat(100)],
 2089.      1
 2090.      1// PR-404 - Alias "nomen" to jslint-directive "name" for backwards-compat.
 2091.      1
 2092.      1        [{name: true, nomen: true}, "let aa = 0;\naa._();"],
 2093.      1        [{node: true}, "require();"],
 2094.      1        [{single: true}, "String('aa');"],
 2095.      1
 2096.      1// PR-404 - Add new directive "subscript" to play nice with Google Closure.
 2097.      1
 2098.      1        [{subscript: true}, "String[\"aa\"]();"],
 2099.      1        [{test_internal_error: true}, ""],
 2100.      1        [{test_unknown_warning_code: true}, ""],
 2101.      1        [{this: true}, "String(this);"],
 2102.      1        [{trace: true}, ""],
 2103.      1        [{unordered: true}, (`
 2104.      1function aa({bb, aa}) {
 2105.      1    switch (aa) {
 2106.      1    case 1:
 2107.      1        break;
 2108.      1    case 0:
 2109.      1        break;
 2110.      1    default:
 2111.      1        return {bb, aa};
 2112.      1    }
 2113.      1}
 2114.      1aa();
 2115.      1            `)],
 2116.      1        [{unordered: true}, "let {bb, aa} = 0;\naa(bb);"],
 2117.      1        [
 2118.      1            {variable: true},
 2119.      1            (`
 2120.      1function aa() {
 2121.      1    if (aa) {
 2122.      1        let bb = 0;
 2123.      1        return bb;
 2124.      1    }
 2125.      1}
 2126.      1            `)
 2127.      1        ],
 2128.      1        [{variable: true}, "let bb = 0;\nlet aa = 0;\naa(bb);"],
 2129.      1        [{white: true}, "\t"]
 2130.     25    ], function ([
 2131.     25        option_dict
 2132.     25    ]) {
 2133.     25        return JSON.stringify(option_dict);
 2134.     25    });
 2135.      1    let elemPrv = "";
 2136.     20    for (const [key, sampleList] of Object.entries(sampleDict)) {
 2137.     20        jstestIt((
 2138.     20            `test option=${key} handling-behavior`
 2139.     20        ), function () {
 2140.     25            for (const [option_dict, sample] of sampleList) {
 2141.     25                const elemNow = JSON.stringify([option_dict, sample.trim()]);
 2142.     25                const warningsLength = (
 2143.     25                    (
 2144.     25                        option_dict.test_internal_error ||
 2145.     25                        option_dict.test_unknown_warning_code
 2146.     25                    )
 2147.     25                    ? 1
 2148.     25                    : 0
 2149.     25                );
 2150.     25                let source = sample.trim();
 2151.     25                // Assert list is sorted.
 2152.     25                assertOrThrow(
 2153.     25                    elemPrv < elemNow,
 2154.     25                    JSON.stringify(
 2155.     25                        [elemPrv, elemNow],
 2156.     25                        undefined,
 2157.     25                        4
 2158.     25                    )
 2159.     25                );
 2160.     25                elemPrv = elemNow;
 2161.     25                option_dict.beta = true;
 2162.     50                for (const lint of [jslint.jslint, jslintCjs.jslint]) {
 2163.     50                    // test jslint's option handling-behavior
 2164.     50                    let warnings;
 2165.     50                    warnings = lint(
 2166.     50                        source,
 2167.     50                        option_dict
 2168.     50                    ).warnings;
 2169.     50                    assertOrThrow(
 2170.     50                        warnings.length === warningsLength,
 2171.     50                        JSON.stringify([source, warnings], undefined, 4)
 2172.     50                    );
 2173.     50                    // test jslint's directive handling-behavior
 2174.     50                    source = (
 2175.     50                        "/*jslint " +
 2176.     50                        JSON
 2177.     50                            .stringify(option_dict)
 2178.     50                            .slice(1, -1)
 2179.     50                            .replace((/"/g), "") +
 2180.     50                        "*/\n" +
 2181.     50                        source.replace((/^#!/), "//")
 2182.     50                    );
 2183.     50                    warnings = lint(source).warnings;
 2184.     50                    assertOrThrow(
 2185.     50                        warnings.length === warningsLength,
 2186.     50                        JSON.stringify([source, warnings], undefined, 4)
 2187.     50                    );
 2188.     50                }
 2189.     25            }
 2190.     20        });
 2191.     20    }
 2192.      1});
 2193.      1
 2194.      1jstestDescribe((
 2195.      1    "test jslint's report handling-behavior"
 2196.      1), function () {
 2197.      1    jstestIt((
 2198.      1        "test report-autofix handling-behavior"
 2199.      1    ), function () {
 2200.      1        let result;
 2201.      1
 2202.      1// The report's Autofix section SPEAKS ONLY AFTER THE BUTTON - index.html sets
 2203.      1// <autofix> on the button's own lint-result, so a plain JSLint renders an
 2204.      1// empty, default-coloured body. Blocked - a residual warning outside
 2205.      1// jslint_autofix_warning_list - is the ONLY state that goes red, and a fixable
 2206.      1// residual still reads as success.
 2207.      1
 2208.      5        function reportAutofix(source, autofix) {
 2209.      5            let html = jslint.jslint_report({
 2210.      5                ...jslint.jslint(source, {}),
 2211.      5                autofix
 2212.      5            });
 2213.      5            return html.slice(
 2214.      5                html.indexOf("<fieldset\n    class="),
 2215.      5                html.indexOf("<fieldset id=\"JSLINT_REPORT_WARNINGS\"")
 2216.      5            );
 2217.      5        }
 2218.      1
 2219.      5        function reportAutofixExpect(klass, body) {
 2220.      5            return (
 2221.      5                "<fieldset\n    class=\"\n    " + klass + "\n    \"\n" +
 2222.      5                "    id=\"JSLINT_REPORT_AUTOFIX\"\n>\n" +
 2223.      5                "<legend>Report: Autofix</legend>\n" +
 2224.      5                "<div class=\"center\">\n    " + body + "\n</div>\n" +
 2225.      5                "</fieldset>\n"
 2226.      5            );
 2227.      5        }
 2228.      1
 2229.      1// A clean source autofixes to itself, and the click is STILL a success - an
 2230.      1// empty body would read to the clicker as a missing success message.
 2231.      1
 2232.      1        result = reportAutofix((
 2233.      1            "function aa(bb) {\n    return bb;\n}\naa();\n"
 2234.      1        ), true);
 2235.      1        assertOrThrow(
 2236.      1            result === reportAutofixExpect("", "Autofix successful."),
 2237.      1            result
 2238.      1        );
 2239.      1
 2240.      1// A residual warning INSIDE the fixable set is not a blocker, so every
 2241.      1// jslint_autofix_warning_list member must survive the <some> callback.
 2242.      1
 2243.      1        result = reportAutofix((
 2244.      1            "function aa(bb) {\n    return String( bb);\n}\naa();\n"
 2245.      1        ), true);
 2246.      1        assertOrThrow(
 2247.      1            result === reportAutofixExpect("", "Autofix successful."),
 2248.      1            result
 2249.      1        );
 2250.      1
 2251.      1// A residual too_long is not a blocker either - autofix fixes around it.
 2252.      1
 2253.      1        result = reportAutofix(String(`
 2254.      1function aa(bb) {
 2255.      1    return bb;
 2256.      1}
 2257.      1aa("${"a".repeat(80)}");
 2258.      1        `).trim() + "\n", true);
 2259.      1        assertOrThrow(
 2260.      1            result === reportAutofixExpect("", "Autofix successful."),
 2261.      1            result
 2262.      1        );
 2263.      1
 2264.      1// A warning outside the set blocks, and the class is what paints it red.
 2265.      1
 2266.      1        result = reportAutofix("console.log(1);\n", true);
 2267.      1        assertOrThrow(
 2268.      1            result === reportAutofixExpect("blocked", (
 2269.      1                "Autofix blocked. Fix non-whitespace warnings below."
 2270.      1            )),
 2271.      1            result
 2272.      1        );
 2273.      1
 2274.      1// A plain JSLint is ALWAYS empty and default-coloured, even on a source that
 2275.      1// WOULD block - <autofix> is undefined, so <some> never runs.
 2276.      1
 2277.      1        result = reportAutofix("console.log(1);\n", undefined);
 2278.      1        assertOrThrow(result === reportAutofixExpect("", ""), result);
 2279.      1    });
 2280.      1    jstestIt((
 2281.      1        "test report-function-detail handling-behavior"
 2282.      1    ), function () {
 2283.      1        let result;
 2284.      1
 2285.      1// This function will return the function details in the report of <source>,
 2286.      1// each <dl> on its own line.
 2287.      1
 2288.      2        function reportFunction(source) {
 2289.      2            const html = jslint.jslint_report(jslint.jslint(source, {}));
 2290.      2            return html.slice(
 2291.      2                html.indexOf("<div class=\"level level1\">"),
 2292.      2                html.lastIndexOf("</div>\n</fieldset>")
 2293.      2            ).replace((/<dl>/g), "\n<dl>");
 2294.      2        }
 2295.      1
 2296.      1// PR-516 - Bugfix - The report's function details list block-scoped names and
 2297.      1// catch-variables, and mark closure only across a function boundary.
 2298.      1
 2299.      1        result = reportFunction(String(`
 2300.      1let ee = 0;
 2301.      1function aa(gg) {
 2302.      1    let bb = 0;
 2303.      1    let ff = 0;
 2304.      1    if (aa) {
 2305.      1        let cc = 1;
 2306.      1        aa(bb, cc, ee, gg);
 2307.      1    }
 2308.      1    try {
 2309.      1        aa(String);
 2310.      1    } catch (err) {
 2311.      1        aa(function () {
 2312.      1            return err;
 2313.      1        });
 2314.      1    }
 2315.      1    return function () {
 2316.      1        return ff;
 2317.      1    };
 2318.      1}
 2319.      1aa();
 2320.      1        `).trim() + "\n");
 2321.      1        assertOrThrow(result === String(`
 2322.      1<div class="level level1"><address>2: 1</address><dfn>aa(gg)</dfn>
 2323.      1<dl><dt>parameter</dt><dd>gg</dd></dl>
 2324.      1<dl><dt>variable</dt><dd>bb, cc, ff</dd></dl>
 2325.      1<dl><dt>exception</dt><dd>err</dd></dl>
 2326.      1<dl><dt>closure</dt><dd>err, ff</dd></dl>
 2327.      1<dl><dt>global</dt><dd>String, aa, ee</dd></dl></div>
 2328.      1<div class="level level2"><address>12: 12</address><dfn>«aa»()</dfn>
 2329.      1<dl><dt>outer</dt><dd>err</dd></dl></div>
 2330.      1<div class="level level2"><address>16: 12</address><dfn>«anonymous»()</dfn>
 2331.      1<dl><dt>outer</dt><dd>ff</dd></dl></div>
 2332.      1        `).trim() + "\n", result);
 2333.      1
 2334.      1// PR-516 - Bugfix - A named function expression's name is outer only in a
 2335.      1// nested function, and a function lists an outer 'bb' even beside its own
 2336.      1// block-scoped 'bb'.
 2337.      1
 2338.      1        result = reportFunction(String(`
 2339.      1function aa() {
 2340.      1    let bb = 0;
 2341.      1    function cc() {
 2342.      1        if (cc) {
 2343.      1            cc(bb);
 2344.      1        }
 2345.      1        if (cc) {
 2346.      1            let bb = 1;
 2347.      1            cc(bb);
 2348.      1        }
 2349.      1    }
 2350.      1    return function dd() {
 2351.      1        return dd(cc, function () {
 2352.      1            return dd;
 2353.      1        });
 2354.      1    };
 2355.      1}
 2356.      1aa();
 2357.      1        `).trim() + "\n");
 2358.      1        assertOrThrow(result === String(`
 2359.      1<div class="level level1"><address>1: 1</address><dfn>aa()</dfn>
 2360.      1<dl><dt>variable</dt><dd>bb, cc</dd></dl>
 2361.      1<dl><dt>closure</dt><dd>bb, cc</dd></dl></div>
 2362.      1<div class="level level2"><address>3: 5</address><dfn>cc()</dfn>
 2363.      1<dl><dt>variable</dt><dd>bb</dd></dl>
 2364.      1<dl><dt>outer</dt><dd>bb, cc</dd></dl></div>
 2365.      1<div class="level level2"><address>12: 12</address><dfn>dd()</dfn>
 2366.      1<dl><dt>outer</dt><dd>cc</dd></dl></div>
 2367.      1<div class="level level3"><address>13: 23</address><dfn>«cc»()</dfn>
 2368.      1<dl><dt>outer</dt><dd>dd</dd></dl></div>
 2369.      1        `).trim() + "\n", result);
 2370.      1    });
 2371.      1    jstestIt((
 2372.      1        "test report-function-name handling-behavior"
 2373.      1    ), function () {
 2374.      1
 2375.      1// PR-516 - Bugfix - A method or accessor is named after its property, not
 2376.      1// after the identifier before it.
 2377.      1
 2378.      1        assertJsonEqual(jslint.jslint(String(`
 2379.      1/*jslint getset*/
 2380.      1String({
 2381.      1    aa() {
 2382.      1        return;
 2383.      1    },
 2384.      1    get bb() {
 2385.      1        return;
 2386.      1    },
 2387.      1    cc: 0,
 2388.      1    dd() {
 2389.      1        return;
 2390.      1    }
 2391.      1});
 2392.      3        `).trim() + "\n").functions.map(function ({name}) {
 2393.      3            return name;
 2394.      3        }), ["aa", "get bb", "dd"]);
 2395.      1
 2396.      1// PR-516 - Bugfix - A function after a keyword is anonymous, except after
 2397.      1// 'default', the name the spec gives it.
 2398.      1
 2399.      1        assertJsonEqual(jslint.jslint(String(`
 2400.      1String(function () {
 2401.      1    return function () {
 2402.      1        return;
 2403.      1    };
 2404.      1}, typeof function () {
 2405.      1    return;
 2406.      1});
 2407.      1export default function () {
 2408.      1    return;
 2409.      1}
 2410.      4        `).trim() + "\n").functions.map(function ({name}) {
 2411.      4            return name;
 2412.      4        }), ["String", "anonymous", "anonymous", "default"]);
 2413.      1
 2414.      1// PR-516 - Bugfix - A keyword used as a property name still names a function.
 2415.      1
 2416.      1        assertJsonEqual(jslint.jslint(String(`
 2417.      1const aa = {
 2418.      1    delete: function () {
 2419.      1        return;
 2420.      1    }
 2421.      1};
 2422.      1aa.catch = function () {
 2423.      1    return;
 2424.      1};
 2425.      1String(aa?.finally || function () {
 2426.      1    return;
 2427.      1});
 2428.      1String(aa
 2429.      1? null
 2430.      1: function () {
 2431.      1    return;
 2432.      1});
 2433.      4        `).trim() + "\n").functions.map(function ({name}) {
 2434.      4            return name;
 2435.      4        }), ["delete", "catch", "finally", "anonymous"]);
 2436.      1    });
 2437.      1    jstestIt((
 2438.      1        "test report-function-signature handling-behavior"
 2439.      1    ), function () {
 2440.      1        const a38 = "a".repeat(38);
 2441.      1
 2442.      1// PR-516 - Bugfix - A signature keeps default values and drops comments, and a
 2443.      1// multi-line destructure joins with no space inside its brackets. A default
 2444.      1// value longer than 40 characters, or holding a megastring, shows as an
 2445.      1// ellipsis, but a backtick inside a string or regexp does not count.
 2446.      1
 2447.      1        assertJsonEqual(jslint.jslint(String(`
 2448.      1function aa(bb, cc = 1, ...dd) {
 2449.      1    return [bb, cc, dd];
 2450.      1}
 2451.      1function ee({
 2452.      1    ff,
 2453.      1    gg = "" // Comment.
 2454.      1}, hh) {
 2455.      1    return [ff, gg, hh];
 2456.      1}
 2457.      1function ii(jj = function () {
 2458.      1    return "a default value longer than forty characters";
 2459.      1}, kk = [0, 1], ll = \`\${kk}\`) {
 2460.      1    return [jj, kk, ll];
 2461.      1}
 2462.      1function mm(
 2463.      1    nn /* Comment. */,
 2464.      1    oo = [
 2465.      1        1
 2466.      1    ],
 2467.      1    pp = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
 2468.      1    qq = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
 2469.      1    rr = [\`a\`, 1]
 2470.      1) {
 2471.      1    return [nn, oo, pp, qq, rr];
 2472.      1}
 2473.      1function ss(tt = "\`", uu = /\`/) {
 2474.      1    return [tt, uu];
 2475.      1}
 2476.      1function vv(ww = (xx = 1) => "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa") {
 2477.      1    return ww;
 2478.      1}
 2479.      8        `).trim() + "\n").functions.map(function ({signature}) {
 2480.      8            return signature;
 2481.      8        }), [
 2482.      1            "(bb, cc = 1, ...dd)",
 2483.      1            "({ff, gg = \"\"}, hh)",
 2484.      1            "(jj = \u2026, kk = [0, 1], ll = \u2026)",
 2485.      1            "()",
 2486.      1            `(nn, oo = [1], pp = "${a38}", qq = \u2026, rr = \u2026)`,
 2487.      1            "(tt = \"`\", uu = /`/)",
 2488.      1            "(ww = \u2026)",
 2489.      1            "(xx = 1)"
 2490.      1        ]);
 2491.      1
 2492.      1// A parse that stops inside a parameter list leaves the signature '('.
 2493.      1
 2494.      1        assertJsonEqual(jslint.jslint(
 2495.      1            "function aa(bb, 0) {}\n"
 2496.      1        ).functions.map(function ({signature}) {
 2497.      1            return signature;
 2498.      1        }), ["("]);
 2499.      1    });
 2500.      1});
 2501.      1
 2502.      1jstestDescribe((
 2503.      1    "test jslint's warnings handling-behavior"
 2504.      1), function () {
 2505.      1    jstestIt((
 2506.      1        "test binding-power handling-behavior"
 2507.      1    ), function () {
 2508.      1
 2509.      1// PR-514 - Bugfix - Binding-powers follow the spec's grammar, as tabled in
 2510.      1// MDN Operator precedence. Each source returns the expression beside the
 2511.      1// parameters, so none is unused, and lists the warning codes it must raise.
 2512.      1
 2513.      1        for (const [expression, expect] of [
 2514.      1            ["(-aa) ** 2", []],
 2515.      1            ["-aa ** 2", ["wrap_subexpression_a_b"]],
 2516.      1            ["-aa++", ["unexpected_a"]],
 2517.      1            ["[aa] ** 2", []],
 2518.      1            ["aa ** -2", []],
 2519.      1            ["aa ?? (bb || cc)", []],
 2520.      1            ["aa ?? bb && cc", ["wrap_subexpression_a_b"]],
 2521.      1            ["aa ?? bb ?? cc", []],
 2522.      1            ["aa || bb ?? cc", ["wrap_subexpression_a_b"]],
 2523.      1            ["typeof aa ** 2", ["wrap_subexpression_a_b"]]
 2524.     10        ]) {
 2525.     10            const result = jslint.jslint(String(`
 2526.     10function ff(aa, bb, cc) {
 2527.     10    return [aa, bb, cc, ${expression}];
 2528.     10}
 2529.     10ff();
 2530.     10            `).trim() + "\n");
 2531.     10            assertJsonEqual(result.warnings.map(function ({code}) {
 2532.     10                return code;
 2533.     10            }), expect, expression);
 2534.     10        }
 2535.      1
 2536.      1// PR-514 - Bugfix - The operand of 'void' is parsed at rbp 150, like every
 2537.      1// unary operator, so 'void 0 + 0' is '(void 0) + 0'.
 2538.      1
 2539.      1        assertOrThrow(
 2540.      5            jslint.jslint("String(void 0 + 0);\n").tokens.find(function ({
 2541.      5                id
 2542.      5            }) {
 2543.      5                return id === "+";
 2544.      5            }).expression[0].id === "void",
 2545.      1            "void 0 + 0"
 2546.      1        );
 2547.      1
 2548.      1// PR-514 - Bugfix - A relational right side of a for-loop-head 'of' or 'in'
 2549.      1// does not warn on the head's own 'of' or 'in'.
 2550.      1
 2551.      1        for (const [operator, expect] of [
 2552.      1            ["in", ["expected_a_b", "expected_a"]],
 2553.      1            ["of", ["expected_a"]]
 2554.      2        ]) {
 2555.      2            assertJsonEqual(jslint.jslint(String(`
 2556.      2function ff(aa, bb) {
 2557.      2    for (aa ${operator} bb < aa) {
 2558.      2        bb();
 2559.      2    }
 2560.      2}
 2561.      2ff();
 2562.      3            `).trim() + "\n").warnings.map(function ({code}) {
 2563.      3                return code;
 2564.      3            }), expect, operator);
 2565.      2        }
 2566.      1
 2567.      1// PR-514 - A 'for in' suggests 'for...of Object.keys', not 'Object.keys'.
 2568.      1
 2569.      1        assertJsonEqual(jslint.jslint(String(`
 2570.      1function ff(aa) {
 2571.      1    for (const bb in aa) {
 2572.      1        aa(bb);
 2573.      1    }
 2574.      1}
 2575.      1ff();
 2576.      1        `).trim() + "\n").warnings.map(function ({message}) {
 2577.      1            return message;
 2578.      1        }), ["Expected 'for...of Object.keys' and instead saw 'for in'."]);
 2579.      1
 2580.      1// PR-514 - Bugfix - '**=' is one assignment token, '**' takes a space on each
 2581.      1// side like '*', and a line break before a postfix '++' ends the expression.
 2582.      1
 2583.      1        for (const [source, expect] of [
 2584.      1            ["let aa = 2;\naa **= 2;\n", []],
 2585.      1            [
 2586.      1                "let aa = 2;\naa = aa**2;\n",
 2587.      1                ["expected_space_a_b", "expected_space_a_b"]
 2588.      1            ],
 2589.      1            [
 2590.      1                "let aa = 0;\nlet bb = 0;\naa\n++bb;\n",
 2591.      1                [
 2592.      1                    "unexpected_expression_a",
 2593.      1                    "expected_a_after_b",
 2594.      1                    "unexpected_expression_a"
 2595.      1                ]
 2596.      1            ]
 2597.      3        ]) {
 2598.      5            assertJsonEqual(jslint.jslint(source).warnings.map(function ({
 2599.      5                code
 2600.      5            }) {
 2601.      5                return code;
 2602.      5            }), expect, source);
 2603.      3        }
 2604.      1        assertJsonEqual(jslint.jslint("let aa = 2;\naa = aa**2;\n", {
 2605.      1            autofix: true
 2606.      1        }).autofixed, "let aa = 2;\naa = aa ** 2;\n");
 2607.      1    });
 2608.      1    jstestIt((
 2609.      1        "test warning-test-cause handling-behavior"
 2610.      1    ), async function () {
 2611.      1
 2612.      1// This function will validate each fixture in each '// test_cause:' block of
 2613.      1// jslint.mjs. A "(live)" source must run the code below its block, by V8 block
 2614.      1// coverage. A warning must be shown, with the code below its block on the
 2615.      1// stack that option trace records. Then validate the roster of fixtures filed
 2616.      1// up the stack, and that each raise site in jslint.mjs has a fixture.
 2617.      1
 2618.      1        const controlList = [];
 2619.      1        const fixtureLineList = [];
 2620.      1        const fixtureList = [];
 2621.      1        const raiserList = ["stop", "stop_at", "warn", "warn_at"];
 2622.      1        const rgxFixtureLine = (
 2623.      1            /^\/\/ (?!\/\/).*, \d+\](?: \/\/jslint-ignore-line)?$/gm
 2624.      1        );
 2625.      1        const rgxFrame = (
 2626.      1            /^ {4}at (?:(?:Object\.)?([\w.]+).*? \()?.*?jslint\.mjs:(\d+):/gm
 2627.      1        );
 2628.      1        const stackTraceLimit = Error.stackTraceLimit;
 2629.    765        function fixturePush(list, cause, anchor) {
 2630.    765
 2631.    765// This function will push to <list> the fixture <cause>, whose block sits
 2632.    765// directly above the code at offset <anchor> in jslint.mjs.
 2633.    765
 2634.    765            const line = (
 2635.    765                sourceJslintMjs.slice(0, anchor).match(/\n/g).length + 1
 2636.    765            );
 2637.    765            const [source, fn, code, aa, column] = cause;
 2638.    765            const warnings = jslintTrace(source);
 2639.    765
 2640.    765// List each warning with its frames in jslint.mjs, by the stack that option
 2641.    765// trace records, as [name, line] innermost first, and the frames above the
 2642.    765// raisers, whose first is the line that raised it. An anonymous function's
 2643.    765// frame has no name.
 2644.    765
 2645.   1918            const warningsRaised = warnings.map(function (warning) {
 2646.   1918                const frameList = Array.from(
 2647.   1918                    String(warning.stack_trace).matchAll(rgxFrame),
 2648.  20226                    function ([ignore, name, line]) {
 2649.  20226                        return [name, Number(line)];
 2650.  20226                    }
 2651.   1918                );
 2652.   1918                return {
 2653.  20226                    aboveList: frameList.filter(function ([name]) {
 2654.  20226                        return !raiserList.includes(name);
 2655.  20226                    }),
 2656.   1918                    frameList,
 2657.   1918                    warning
 2658.   1918                };
 2659.   1918            });
 2660.    765
 2661.    765// A second warning on one token is dropped, so check the warnings the user
 2662.    765// sees, never the ones raised.
 2663.    765
 2664.   1918            const warningsShown = warningsRaised.filter(function ({warning}) {
 2665.   1918                return (
 2666.    614                    warning.code === code &&
 2667.    614                    String(warning.b || warning.a || "") === aa &&
 2668.    592                    warning.column === column
 2669.   1918                );
 2670.   1918            });
 2671.    765
 2672.    765// The shown warning raised through the code under the block.
 2673.    765
 2674.    584            const warningsVia = warningsShown.filter(function ({frameList}) {
 2675.   1872                return frameList.some(function ([ignore, at]) {
 2676.   1872                    return at === line;
 2677.   1872                });
 2678.    584            });
 2679.    765            list.push({
 2680.    765                anchor,
 2681.    765
 2682.    765// Name the line of the code under the block, so a failure points at it.
 2683.    765
 2684.    765                at: "jslint.mjs:" + line,
 2685.    765                cause: JSON.stringify(cause),
 2686.    765                code,
 2687.    765
 2688.    765// Validate no internal-error. A crash mid-walk still runs every branch before
 2689.    765// it, so a coverage-check alone passes straight through one, and "0``" threw
 2690.    765// in post_b_binary for years with its cause declared and green.
 2691.    765
 2692.   1916                codeless: warnings.some(function (warning) {
 2693.   1916                    return warning.code === undefined;
 2694.   1916                }),
 2695.    765                fn,
 2696.    765
 2697.    765// A fixture has exactly 5 fields. Field 3 "(live)" marks a branch reached with
 2698.    765// no warning of its own, documenting how, so it is not taken for deadcode. Any
 2699.    765// other field 3 must be a warning shown below, so a typo fails there.
 2700.    765
 2701.    764                known: cause.length === 5 && (
 2702.    764                    code !== "(live)" || (aa === "" && column === 0)
 2703.    764                ),
 2704.    765
 2705.    765// Field 2 of a warning names the function that raised it, the first named one
 2706.    765// above the raisers in the stack that option trace records, so a fixture may
 2707.    765// be filed up the stack, above the call that leads down to the raise site.
 2708.    765
 2709.    576                raise: warningsVia[0]?.aboveList[0],
 2710.    616                raiser: warningsVia[0]?.aboveList.find(function ([name]) {
 2711.    616                    return name;
 2712.    616                })?.[0],
 2713.    585                shown: code === "(live)" || warningsShown.length > 0,
 2714.    765
 2715.    765// A "(live)" block must not sit on a raise whose warning shows, since a
 2716.    765// warning fixture checks more.
 2717.    765
 2718.    393                silent: code !== "(live)" || warningsRaised.every(function ({
 2719.    393                    aboveList
 2720.    393                }) {
 2721.    392                    return aboveList[0]?.[1] !== line;
 2722.    393                }),
 2723.    765                source,
 2724.    585                via: code === "(live)" || warningsVia.length > 0
 2725.    765            });
 2726.    765        }
 2727.    765        function jslintTrace(source) {
 2728.    765
 2729.    765// This function will lint <source> with option trace, keeping every frame,
 2730.    765// since a fixture filed up the stack can sit past V8's default of 10. Restore
 2731.    765// the limit even if jslint throws, so no other test inherits it.
 2732.    765
 2733.    765            Error.stackTraceLimit = Infinity;
 2734.    765            try {
 2735.    765                return jslint.jslint(source, {
 2736.    765                    beta: true,
 2737.    765                    trace: true
 2738.    765                }).warnings;
 2739.    765            } finally {
 2740.    765                Error.stackTraceLimit = stackTraceLimit;
 2741.    765            }
 2742.    765        }
 2743.      1
 2744.      1        sourceJslintMjs.replace((
 2745.      1            /(\n\s*?\/\/\s*?test_cause:\s*?)(\S[\S\s]*?\S)(\n\n\s*?) *?\S/g
 2746.    413        ), function (match0, header, causeList, footer, offset) {
 2747.    413            const rgxAnchor = (/(?:\/\/.*\n\s*)*(?:[?:]\s*)?/y);
 2748.    413            let tmp;
 2749.    413            // console.error(match0);
 2750.    413            // Validate header.
 2751.    413            assertOrThrow(header === "\n\n// test_cause:\n", match0);
 2752.    413            // Validate footer.
 2753.    413            assertOrThrow(footer === "\n\n", match0);
 2754.    413            fixtureLineList.push(...match0.match(rgxFixtureLine));
 2755.    413            // Validate causeList.
 2756.    413            causeList = causeList.replace((
 2757.    413                /^\/\/ /gm
 2758.    413            ), "").replace((
 2759.    413                /^\["\n([\S\s]*?)\n"(,.*?)$/gm
 2760.     74            ), function (ignore, source, param) {
 2761.     74                source = "[" + JSON.stringify(source) + param;
 2762.     74                return source;
 2763.     74            }).replace((
 2764.    413                / \/\/jslint-ignore-line$/gm
 2765.    413            ), "");
 2766.    750            tmp = causeList.split("\n").map(function (cause) {
 2767.    750                return (
 2768.    750                    "[" +
 2769.   3750                    JSON.parse(cause).map(function (elem) {
 2770.   3750                        return JSON.stringify(elem);
 2771.   3750                    }).join(", ") +
 2772.    750                    "]"
 2773.    750                );
 2774.    750            }).sort().filter(function (cause, ii, list) {
 2775.    750                return cause !== list[ii - 1];
 2776.    750            }).join("\n");
 2777.    413            assertOrThrow(
 2778.    413                causeList === tmp,
 2779.    413                "\n" + causeList + "\n\n" + tmp
 2780.    413            );
 2781.    413
 2782.    413// Anchor the block to the first code below it, past any comment paragraph and
 2783.    413// a leading '?' or ':' of a ternary branch.
 2784.    413
 2785.    413            rgxAnchor.lastIndex = offset + match0.length - 1;
 2786.    413            rgxAnchor.exec(sourceJslintMjs);
 2787.    750            for (const cause of causeList.split("\n")) {
 2788.    750                fixturePush(
 2789.    750                    fixtureList,
 2790.    750                    JSON.parse(cause),
 2791.    750                    rgxAnchor.lastIndex
 2792.    750                );
 2793.    750            }
 2794.    413            return "";
 2795.    413        });
 2796.      1
 2797.      1// Validate each fixture's last line was parsed in a block, so a misspelled
 2798.      1// header fails, naming the lines it hid, instead of hiding its block. The
 2799.      1// count catches a line that two blocks share. Commented-out code keeps its
 2800.      1// blocks as '// // test_cause:', unchecked.
 2801.      1
 2802.      1        assertJsonEqual(sourceJslintMjs.match(rgxFixtureLine).filter(
 2803.    750            function (line) {
 2804.    750                return !fixtureLineList.includes(line);
 2805.    750            }
 2806.      1        ), []);
 2807.      1        assertJsonEqual(
 2808.      1            sourceJslintMjs.match(rgxFixtureLine).length,
 2809.      1            fixtureLineList.length
 2810.      1        );
 2811.      1
 2812.      1// Negative controls: each bad fixture, filed in the block of a good one, must
 2813.      1// fail exactly the named check, so a weakened checker turns this test red.
 2814.      1
 2815.      1        for (const [good, bad, expect] of [
 2816.      1            [
 2817.      1                [
 2818.      1                    "/*jslint test_internal_error*/\nif(0%0){}",
 2819.      1                    "condition",
 2820.      1                    "(live)",
 2821.      1                    "",
 2822.      1                    0
 2823.      1                ],
 2824.      1                ["codeless", "silent"]
 2825.      1            ], [
 2826.      1                ["if(0%0){}", "condition", "unexpectd_a", "%", 5],
 2827.      1                ["inFn", "shown", "via"]
 2828.      1            ], [
 2829.      1                ["if(0%0){}", "condition", "(live)", "", 0],
 2830.      1                ["silent"]
 2831.      1            ], [
 2832.      1                ["if(0%0){}", "condition", "(live)", "aa", 0],
 2833.      1                ["known", "silent"]
 2834.      1            ], [
 2835.      1                ["if(0%0){}", "condition", "(live)", "", 5],
 2836.      1                ["known", "silent"]
 2837.      1            ], [
 2838.      1                ["if(0%0){}", "condition", "unexpected_a", "%", 5, "extra"],
 2839.      1                ["known"]
 2840.      1            ], [
 2841.      1                ["if(0%0){}", "condition", "unexpected_a", "%", 6],
 2842.      1                ["inFn", "shown", "via"]
 2843.      1            ], [
 2844.      1                ["if(0%0){}", "condition", "unexpected_a", "&", 5],
 2845.      1                ["inFn", "shown", "via"]
 2846.      1            ], [
 2847.      1                ["if(0%0){}", "condition", "empty_block", "{", 8],
 2848.      1                ["inFn", "via"]
 2849.      1            ], [
 2850.      1                ["if(0%0){}", "warn", "unexpected_a", "%", 5],
 2851.      1                ["inFn"]
 2852.      1            ], [
 2853.      1                ["if(0&0){}", "condition", "unexpected_a", "&", 5],
 2854.      1                ["inFn", "live", "via"]
 2855.      1            ]
 2856.     11        ].map(function ([bad, expect]) {
 2857.     11            return [
 2858.     11                "[\"if(0%0){}\",\"condition\",\"unexpected_a\",\"%\",5]",
 2859.     11                bad,
 2860.     11                expect
 2861.     11            ];
 2862.     11        }).concat([
 2863.      1            [
 2864.      1                "[\"let aa=!!0;\",\"post_u_unary\",\"expected_a_b\",\"!!\",8]",
 2865.      1                ["!!0", "post_u_unary", "expected_a_b", "!!", 1],
 2866.      1                ["inFn", "shown", "via"]
 2867.      1            ], [
 2868.      1                "[\"aa=/./vu\",\"lex_regexp\",\"unexpected_a\",\"u\",8]",
 2869.      1                ["aa=/./u;if(0){}", "lex_regexp", "unexpected_a", "0", 12],
 2870.      1                ["inFn", "live", "via"]
 2871.      1            ], [
 2872.      1
 2873.      1// Filed up the stack above the wrong caller: <check_left> raises it through
 2874.      1// <infix_lbracket>, not through the call under this block in <infix_dot>.
 2875.      1
 2876.      1                "[\"aa=[]?.aa\",\"check_left\",\"unexpected_a\",\"?.\",6]",
 2877.      1                ["\"\".aa;0[0]", "check_left", "unexpected_a", "[", 8],
 2878.      1                ["inFn", "via"]
 2879.      1            ], [
 2880.      1
 2881.      1// Raised here but dropped, since <post_a_pluseq> warned on the token first,
 2882.      1// so the warning shown is another site's.
 2883.      1
 2884.      1                (
 2885.      1                    "[\"aa-=undefined\",\"post_a_assignment\"," +
 2886.      1                    "\"unexpected_a\",\"undefined\",5]"
 2887.      1                ),
 2888.      1                [
 2889.      1                    "aa+=undefined",
 2890.      1                    "post_a_assignment",
 2891.      1                    "unexpected_a",
 2892.      1                    "undefined",
 2893.      1                    5
 2894.      1                ],
 2895.      1                ["inFn", "via"]
 2896.      1            ]
 2897.     15        ])) {
 2898.   4053            const found = fixtureList.find(function ({cause}) {
 2899.   4053                return cause === good;
 2900.   4053            });
 2901.     15            assertOrThrow(found, `control's good fixture is missing: ${good}`);
 2902.     15            fixturePush(controlList, bad, found.anchor);
 2903.     15            controlList.at(-1).expect = expect;
 2904.     15        }
 2905.      1
 2906.      1// Measure each fixture's coverage in a child, since taking precise coverage
 2907.      1// resets the counters that NODE_V8_COVERAGE dumps at exit.
 2908.      1
 2909.      1        await childRun({
 2910.      1            NODE_V8_COVERAGE: ""
 2911.      1        }, String(`
 2912.      1import moduleFs from "fs";
 2913.      1import moduleInspector from "inspector/promises";
 2914.      1const fixtureList = JSON.parse(moduleFs.readFileSync(0, "utf8"));
 2915.      1const resultList = [];
 2916.      1const session = new moduleInspector.Session();
 2917.      1session.connect();
 2918.      1await session.post("Profiler.enable");
 2919.      1await session.post("Profiler.startPreciseCoverage", {
 2920.      1    callCount: true,
 2921.      1    detailed: true
 2922.      1});
 2923.      1for (const [offset, source] of fixtureList) {
 2924.      1    const result = [0, ""];
 2925.      1    const span = [Infinity, Infinity];
 2926.      1    jslint(source, {
 2927.      1        beta: true
 2928.      1    });
 2929.      1    for (const {functionName, ranges} of (
 2930.      1        await session.post("Profiler.takePreciseCoverage")
 2931.      1    ).result.find(function ({url}) {
 2932.      1        return url.endsWith("/jslint.mjs");
 2933.      1    }).functions) {
 2934.      1        for (const range of ranges) {
 2935.      1            const width = range.endOffset - range.startOffset;
 2936.      1            if (range.startOffset <= offset && offset < range.endOffset) {
 2937.      1                if (width <= span[0]) {
 2938.      1                    result[0] = range.count;
 2939.      1                    span[0] = width;
 2940.      1                }
 2941.      1                if (functionName && width < span[1]) {
 2942.      1                    result[1] = functionName;
 2943.      1                    span[1] = width;
 2944.      1                }
 2945.      1            }
 2946.      1        }
 2947.      1    }
 2948.      1    resultList.push(result);
 2949.      1}
 2950.      1process.stdout.write(JSON.stringify(resultList));
 2951.      1        `).trim() + "\n", JSON.stringify(
 2952.    765            fixtureList.concat(controlList).map(function ({anchor, source}) {
 2953.    765                return [anchor, source];
 2954.    765            })
 2955.      1        )).then(function ([exitCode, stderr, stdout]) {
 2956.      1            const hostDict = {};
 2957.      1            const raiseDict = {};
 2958.      1            let recordList;
 2959.      1            assertOrThrow(exitCode === 0, stderr);
 2960.    765            recordList = JSON.parse(stdout).map(function ([count, name], ii) {
 2961.    765                const {
 2962.    765                    at,
 2963.    765                    cause,
 2964.    765                    code,
 2965.    765                    codeless,
 2966.    765                    expect = [],
 2967.    765                    fn,
 2968.    765                    known,
 2969.    765                    raise,
 2970.    765                    raiser,
 2971.    765                    shown,
 2972.    765                    silent,
 2973.    765                    via
 2974.    765                } = fixtureList.concat(controlList)[ii];
 2975.    765                let check;
 2976.    750                if (ii < fixtureList.length) {
 2977.    750                    raiseDict[raise?.[1]] = true;
 2978.    750
 2979.    750// A fixture filed up the stack pairs the function holding its block with the
 2980.    750// one that raised it.
 2981.    750
 2982.    750                    if (name !== fn) {
 2983.    750                        hostDict[name + " <- " + fn] = true;
 2984.    750                    }
 2985.    750                }
 2986.    765                check = {
 2987.    765                    codeless: !codeless,
 2988.    765
 2989.    765// Field 2 of a (live) fixture names the function holding the block.
 2990.    765
 2991.    765                    inFn: fn === (
 2992.    765                        code === "(live)"
 2993.    180                        ? name
 2994.    585                        : raiser
 2995.    765                    ),
 2996.    765                    known,
 2997.    765                    live: count > 0,
 2998.    765                    shown,
 2999.    765                    silent,
 3000.    765                    via
 3001.    765                };
 3002.    765                return {
 3003.    765                    at,
 3004.    765                    cause,
 3005.    765                    expect,
 3006.   5355                    fail: Object.keys(check).filter(function (key) {
 3007.   5355                        return !check[key];
 3008.   5355                    })
 3009.    765                };
 3010.    765            });
 3011.      1
 3012.      1// List every fixture whose failed checks differ from those expected: none for
 3013.      1// a fixture, exactly the named ones for a negative control.
 3014.      1
 3015.    765            assertJsonEqual(recordList.filter(function ({expect, fail}) {
 3016.    765                return String(fail) !== String(expect);
 3017.    765            }), []);
 3018.      1
 3019.      1// Validate the roster of fixtures filed up the stack, as "host <- raiser"
 3020.      1// pairs, so each new pair is a reviewed decision and a filing far up the stack
 3021.      1// fails, which <via> alone accepts from any frame. A rename of either function
 3022.      1// shows as one pair missing and one extra. No counts: a fixture added or moved
 3023.      1// within a known pair is not a review.
 3024.      1
 3025.      1            assertJsonEqual(Object.keys(hostDict).sort(), [
 3026.      1                "infix_dot <- check_left",
 3027.      1                "infix_grave <- check_left",
 3028.      1                "infix_lbracket <- check_left",
 3029.      1                "infix_lparen <- check_left",
 3030.      1                "jslint_phase3_parse <- check_ordered",
 3031.      1                "post_s_var <- name_lookup",
 3032.      1                "prefix_destructure <- check_ordered",
 3033.      1                "prefix_destructure <- name_parse",
 3034.      1                "prefix_function <- check_ordered",
 3035.      1                "prefix_lbrace <- check_ordered",
 3036.      1                "stmt_export <- check_ordered",
 3037.      1                "stmt_export <- semicolon",
 3038.      1                "stmt_switch <- check_ordered_case",
 3039.      1                "whitage_default <- one_space_only"
 3040.      1            ]);
 3041.      1
 3042.      1// Validate each raise site in jslint.mjs raises the warning of some fixture,
 3043.      1// except the raisers' own calls, and a test hook raising an unknown code.
 3044.      1
 3045.      1            assertJsonEqual(sourceJslintMjs.replace((
 3046.      1                /^ {4}function (?:stop|warn)(?:_at)?\([\S\s]*?\n {4}\}\n/gm
 3047.      4            ), function (match0) {
 3048.      4                return match0.replace(/[^\n]/g, "");
 3049.  13977            }).split("\n").map(function (text, ii) {
 3050.  13977                return [ii + 1, text.trim()];
 3051.  13977            }).filter(function ([line, text]) {
 3052.  13977                return (
 3053.  11224                    !text.startsWith("//") &&
 3054.  11224                    (/(?:^|[^\w.])(?:stop|warn)(?:_at)?\(/m).test(text) &&
 3055.    292                    !text.includes("\"test_unknown_warning_code\"") &&
 3056.    291                    !raiseDict[line]
 3057.  13977                );
 3058.  13977            }), []);
 3059.      1        });
 3060.      1    });
 3061.      1});
 3062.      1
 3063.      1jstestDescribe((
 3064.      1    "test jslint_wrapper_vscode handling-behavior"
 3065.      1), function () {
 3066.      1    jstestIt((
 3067.      1        "test jslint_wrapper_vscode commands handling-behavior"
 3068.      1    ), async function () {
 3069.      1
 3070.      1// Load the extension against a stub vscode api, then drive every command.
 3071.      1// Like vscode, the stub's <registerTextEditorCommand> runs its callback inside
 3072.      1// <edit>, and <edit> applies the builder's edits once the callback returns.
 3073.      1
 3074.      1        const commandDict = {};
 3075.      1        const moduleStub = {
 3076.      1            exports: {}
 3077.      1        };
 3078.      1        const sourceWrapper = await moduleFs.promises.readFile(
 3079.      1            "jslint_wrapper_vscode.js",
 3080.      1            "utf8"
 3081.      1        );
 3082.      1        const state = {};
 3083.      1        const subscriptions = [];
 3084.      1        const vscode = {
 3085.      2            Diagnostic: function (ignore, message) {
 3086.      2                return {
 3087.      2                    message
 3088.      2                };
 3089.      2            },
 3090.      1            DiagnosticSeverity: {},
 3091.      1            ProgressLocation: {},
 3092.      1            Range: noop,
 3093.      1            commands: {
 3094.      4                registerCommand: function (id, callback) {
 3095.      4                    commandDict[id] = callback;
 3096.      4                    return [id, "registerCommand"];
 3097.      4                },
 3098.      2                registerTextEditorCommand: function (id, callback) {
 3099.      4                    commandDict[id] = function () {
 3100.      4                        return state.editor.edit(function (edit) {
 3101.      4                            callback(state.editor, edit);
 3102.      4                        });
 3103.      4                    };
 3104.      2                    return [id, "registerTextEditorCommand"];
 3105.      2                }
 3106.      1            },
 3107.      1            languages: {
 3108.      1                createDiagnosticCollection: function () {
 3109.      1                    return {
 3110.      4                        clear: function () {
 3111.      4                            delete state.diagnosticList;
 3112.      4                        },
 3113.      3                        set: function (ignore, list) {
 3114.      2                            state.diagnosticList = list.map(function ({
 3115.      2                                message
 3116.      2                            }) {
 3117.      2                                return message;
 3118.      2                            });
 3119.      3                        }
 3120.      1                    };
 3121.      1                }
 3122.      1            },
 3123.      1            window: {
 3124.      4                withProgress: function (ignore, callback) {
 3125.      4                    return callback({
 3126.      4                        report: noop
 3127.      4                    });
 3128.      4                }
 3129.      1            }
 3130.      1        };
 3131.      7        function editorCreate(text, selection) {
 3132.      7            state.source = text;
 3133.      7            state.editor = {
 3134.      7                document: {
 3135.      7                    getText: function (range) {
 3136.      7                        return (
 3137.      7                            range
 3138.      3                            ? state.source.slice(
 3139.      3                                offsetAt(range.start),
 3140.      3                                offsetAt(range.end)
 3141.      3                            )
 3142.      4                            : state.source
 3143.      7                        );
 3144.      7                    },
 3145.      4                    lineAt: function ({
 3146.      4                        line
 3147.      4                    }) {
 3148.      4                        const lineList = state.source.split("\n");
 3149.      4                        return {
 3150.      4                            range: {
 3151.      4                                end: {
 3152.      4                                    character: lineList[line].length,
 3153.      4                                    line
 3154.      4                                },
 3155.      4                                start: {
 3156.      4                                    character: 0,
 3157.      4                                    line
 3158.      4                                }
 3159.      4                            },
 3160.      4                            rangeIncludingLineBreak: {
 3161.      4                                end: (
 3162.      4                                    line + 1 < lineList.length
 3163.      3                                    ? {
 3164.      3                                        character: 0,
 3165.      3                                        line: line + 1
 3166.      3                                    }
 3167.      1                                    : {
 3168.      1                                        character: lineList[line].length,
 3169.      1                                        line
 3170.      1                                    }
 3171.      4                                ),
 3172.      4                                start: {
 3173.      4                                    character: 0,
 3174.      4                                    line
 3175.      4                                }
 3176.      4                            }
 3177.      4                        };
 3178.      4                    },
 3179.      1                    save: function () {
 3180.      1
 3181.      1// Stand in for a format-on-save that rewrites the text.
 3182.      1
 3183.      1                        state.source = "let cc = 3;\n";
 3184.      1                        return Promise.resolve(true);
 3185.      1                    },
 3186.      7                    validateRange: noop
 3187.      7                },
 3188.      5                edit: function (callback) {
 3189.      5                    const editList = [];
 3190.      5                    callback({
 3191.      4                        insert: function (position, text) {
 3192.      4                            editList.push([position, position, text]);
 3193.      4                        },
 3194.      4                        replace: function (range, text) {
 3195.      4
 3196.      4// An undefined range, from the stub <validateRange>, is the whole document.
 3197.      4
 3198.      4                            editList.push([range?.start, range?.end, text]);
 3199.      4                        }
 3200.      5                    });
 3201.      5
 3202.      5// Resolve offsets against the text before any edit, then apply right to left.
 3203.      5// On a tie the later edit goes first, so an insert lands before a replace.
 3204.      5
 3205.      8                    editList.map(function ([start, end, text], ii) {
 3206.      8                        return [
 3207.      8                            (
 3208.      8                                start
 3209.      7                                ? offsetAt(start)
 3210.      1                                : 0
 3211.      8                            ),
 3212.      8                            (
 3213.      8                                end
 3214.      7                                ? offsetAt(end)
 3215.      1                                : state.source.length
 3216.      8                            ),
 3217.      8                            text,
 3218.      8                            ii
 3219.      8                        ];
 3220.      3                    }).sort(function (aa, bb) {
 3221.      2                        return bb[0] - aa[0] || bb[3] - aa[3];
 3222.      8                    }).forEach(function ([start, end, text]) {
 3223.      8                        state.source = (
 3224.      8                            state.source.slice(0, start) +
 3225.      8                            text +
 3226.      8                            state.source.slice(end)
 3227.      8                        );
 3228.      8                    });
 3229.      5                    return Promise.resolve(true);
 3230.      5                },
 3231.      7                selection
 3232.      7            };
 3233.      7            vscode.window.activeTextEditor = state.editor;
 3234.      7        }
 3235.     20        function offsetAt({
 3236.     20            character,
 3237.     20            line
 3238.     20        }) {
 3239.     14            return state.source.split("\n").slice(0, line).reduce(function (
 3240.     14                sum,
 3241.     14                text
 3242.     14            ) {
 3243.     14                return sum + text.length + 1;
 3244.     14            }, character);
 3245.     20        }
 3246.      1        moduleVm.runInThisContext(String(`
 3247.      1(function (__dirname, exports, module, require) {
 3248.      1${sourceWrapper}
 3249.      1})
 3250.      1        `).trim() + "\n")(
 3251.      1            modulePath.resolve("."),
 3252.      1            moduleStub.exports,
 3253.      1            moduleStub,
 3254.      3            function (id) {
 3255.      3                return (
 3256.      3                    id === "vscode"
 3257.      1                    ? vscode
 3258.      2                    : id === "vm"
 3259.      2                    ? moduleVm
 3260.      2                    : moduleFs
 3261.      3                );
 3262.      3            }
 3263.      1        );
 3264.      1
 3265.      1// Activation reuses moduleStub to load jslint, so read activate first.
 3266.      1
 3267.      1        moduleStub.exports.activate({
 3268.      1            subscriptions
 3269.      1        });
 3270.      1        assertJsonEqual(subscriptions, [
 3271.      1            ["jslint.autofix", "registerCommand"],
 3272.      1            ["jslint.clear", "registerCommand"],
 3273.      1            ["jslint.disableRegion", "registerTextEditorCommand"],
 3274.      1            ["jslint.ignoreLine", "registerTextEditorCommand"],
 3275.      1            ["jslint.lint", "registerCommand"],
 3276.      1            ["jslint.lintAndSave", "registerCommand"]
 3277.      1        ]);
 3278.      1
 3279.      1// With no active editor, clear still clears and the rest return quietly.
 3280.      1
 3281.      1        state.diagnosticList = ["aa"];
 3282.      1        await commandDict["jslint.clear"]();
 3283.      1        assertJsonEqual(state.diagnosticList, undefined);
 3284.      1        await commandDict["jslint.autofix"]();
 3285.      1        await commandDict["jslint.lint"]();
 3286.      1        await commandDict["jslint.lintAndSave"]();
 3287.      1        assertJsonEqual(state.diagnosticList, undefined);
 3288.      1
 3289.      1// Lint ignores the context menu's uri argument, and resolves only after the
 3290.      1// warnings are set.
 3291.      1
 3292.      1        editorCreate("let aa = 1;\n");
 3293.      1        await commandDict["jslint.lint"]("file:///aa.js");
 3294.      1        assertJsonEqual(state.diagnosticList, ["JSLint - Unused 'aa'."]);
 3295.      1
 3296.      1// Lint-and-save lints the text as saved.
 3297.      1
 3298.      1        editorCreate("let bb = 2;\n");
 3299.      1        await commandDict["jslint.lintAndSave"]();
 3300.      1        assertJsonEqual(state.diagnosticList, ["JSLint - Unused 'cc'."]);
 3301.      1
 3302.      1// Autofix rewrites the text, then re-lints it.
 3303.      1
 3304.      1        editorCreate("function aa() {\n  return 1;\n}\naa();\n");
 3305.      1        await commandDict["jslint.autofix"]();
 3306.      1        assertJsonEqual(
 3307.      1            state.source,
 3308.      1            "function aa() {\n    return 1;\n}\naa();\n"
 3309.      1        );
 3310.      1        assertJsonEqual(state.diagnosticList, []);
 3311.      1
 3312.      1// Disable-region, with a cursor: wrap the cursor's line.
 3313.      1
 3314.      1        editorCreate("aa();\nbb();\n", {
 3315.      1            end: {
 3316.      1                character: 2,
 3317.      1                line: 0
 3318.      1            },
 3319.      1            isEmpty: true,
 3320.      1            start: {
 3321.      1                character: 2,
 3322.      1                line: 0
 3323.      1            }
 3324.      1        });
 3325.      1        await commandDict["jslint.disableRegion"]();
 3326.      1        assertJsonEqual(
 3327.      1            state.source,
 3328.      1            "/*jslint-disable*/\naa();\n/*jslint-enable*/\nbb();\n"
 3329.      1        );
 3330.      1
 3331.      1// Disable-region, with a selection ending at the start of a line: the enable
 3332.      1// directive goes before that line, not after it.
 3333.      1
 3334.      1        editorCreate("aa();\nbb();\ncc();\n", {
 3335.      1            end: {
 3336.      1                character: 0,
 3337.      1                line: 2
 3338.      1            },
 3339.      1            isEmpty: false,
 3340.      1            start: {
 3341.      1                character: 0,
 3342.      1                line: 0
 3343.      1            }
 3344.      1        });
 3345.      1        await commandDict["jslint.disableRegion"]();
 3346.      1        assertJsonEqual(
 3347.      1            state.source,
 3348.      1            "/*jslint-disable*/\naa();\nbb();\n/*jslint-enable*/\ncc();\n"
 3349.      1        );
 3350.      1
 3351.      1// Disable-region, on a last line with no line break: add one first.
 3352.      1
 3353.      1        editorCreate("aa();", {
 3354.      1            end: {
 3355.      1                character: 0,
 3356.      1                line: 0
 3357.      1            },
 3358.      1            isEmpty: true,
 3359.      1            start: {
 3360.      1                character: 0,
 3361.      1                line: 0
 3362.      1            }
 3363.      1        });
 3364.      1        await commandDict["jslint.disableRegion"]();
 3365.      1        assertJsonEqual(
 3366.      1            state.source,
 3367.      1            "/*jslint-disable*/\naa();\n/*jslint-enable*/"
 3368.      1        );
 3369.      1
 3370.      1// Ignore-line: append the directive to the end of the selection's last line.
 3371.      1
 3372.      1        editorCreate("aa();\nbb();\n", {
 3373.      1            end: {
 3374.      1                character: 2,
 3375.      1                line: 1
 3376.      1            },
 3377.      1            isEmpty: true,
 3378.      1            start: {
 3379.      1                character: 2,
 3380.      1                line: 1
 3381.      1            }
 3382.      1        });
 3383.      1        await commandDict["jslint.ignoreLine"]();
 3384.      1        assertJsonEqual(state.source, "aa();\nbb(); //jslint-ignore-line\n");
 3385.      1    });
 3386.      1});
 3387.      1
 3388.      1jstestDescribe((
 3389.      1    "test jstestXxx handling-behavior"
 3390.      1), function () {
 3391.      1    jstestIt((
 3392.      1        "test jstestDescribe-body-hang handling-behavior"
 3393.      1    ), async function () {
 3394.      1
 3395.      1// An async body that hangs before registering any test fails at exit as a
 3396.      1// pending body, instead of passing with 0 tests. With nothing alive, the hang
 3397.      1// exits at once.
 3398.      1
 3399.      1        const [exitCode, stderr] = await childRun({}, String(`
 3400.      1jslint.jstestDescribe("aa", async function () {
 3401.      1    await new Promise(jslint.noop);
 3402.      1    jslint.jstestIt("bb", jslint.noop);
 3403.      1});
 3404.      1        `));
 3405.      1        assertJsonEqual(exitCode, 1);
 3406.      1        assertMatch(stderr, /1\. test it pending - aa - jstestDescribe body\n {2}tests total {2}- 1\n {2}tests failed - 1\n/);
 3407.      1    });
 3408.      1    jstestIt((
 3409.      1        "test jstestDescribe-body-throw handling-behavior"
 3410.      1    ), async function () {
 3411.      1
 3412.      1// A describe body that throws crashes node, and the exit report lists the body
 3413.      1// and the tests it did register as pending; an invalid filter regexp throws
 3414.      1// from that body too. A falsy throw fails the same.
 3415.      1
 3416.      1        const [
 3417.      1            [exitCode, stderr],
 3418.      1            [exitCode2, stderr2],
 3419.      1            [exitCode3, stderr3]
 3420.      1        ] = await Promise.all([
 3421.      1            childRun({}, String(`
 3422.      1jslint.jstestDescribe("aa", function () {
 3423.      1    jslint.jstestIt("bb", jslint.noop);
 3424.      1    throw new Error("aa body broke");
 3425.      1});
 3426.      1            `)),
 3427.      1            childRun({
 3428.      1                npm_config_mode_test_filter: "("
 3429.      1            }, String(`
 3430.      1jslint.jstestDescribe("aa", function () {
 3431.      1    jslint.jstestIt("bb", jslint.noop);
 3432.      1});
 3433.      1            `)),
 3434.      1            childRun({}, String(`
 3435.      1jslint.jstestDescribe("aa", function () {
 3436.      1    jslint.jstestIt("bb", jslint.noop);
 3437.      1    throw undefined;
 3438.      1});
 3439.      1            `))
 3440.      1        ]);
 3441.      1        assertJsonEqual([exitCode, exitCode2, exitCode3], [1, 1, 1]);
 3442.      1        assertMatch(stderr, /1\. test it pending - aa - jstestDescribe body\n[\s\S]*2\. test it pending - aa - bb\n[\s\S]*tests failed - 2\n[\s\S]*Error: aa body broke\b/);
 3443.      1        assertMatch(stderr2, /1\. test it pending - aa - jstestDescribe body\n[\s\S]*SyntaxError: Invalid regular/);
 3444.      1        assertMatch(stderr3, /1\. test it pending - aa - jstestDescribe body\n[\s\S]*tests failed - 2\n[\s\S]*ERR_UNHANDLED_REJECTION/);
 3445.      1    });
 3446.      1    jstestIt((
 3447.      1        "test jstestDescribe-concurrent handling-behavior"
 3448.      1    ), async function () {
 3449.      1
 3450.      1// A describe's tests run concurrently: bb waits on an event cc emits, which
 3451.      1// hangs if they run one after another.
 3452.      1
 3453.      1        const [exitCode, stderr] = await childRun({}, String(`
 3454.      1import {EventEmitter} from "node:events";
 3455.      1const ee = new EventEmitter();
 3456.      1jslint.jstestDescribe("aa", function () {
 3457.      1    jslint.jstestIt("bb", function () {
 3458.      1        return new Promise(function (resolve) {
 3459.      1            ee.once("go", resolve);
 3460.      1        });
 3461.      1    });
 3462.      1    jslint.jstestIt("cc", function () {
 3463.      1        ee.emit("go");
 3464.      1    });
 3465.      1});
 3466.      1        `));
 3467.      1        assertJsonEqual(exitCode, 0);
 3468.      1        assertMatch(stderr, /tests total {2}- 2\n {2}tests failed - 0\n/);
 3469.      1    });
 3470.      1    jstestIt((
 3471.      1        "test jstestDescribe-order handling-behavior"
 3472.      1    ), async function () {
 3473.      1
 3474.      1// The runner fails a describe's tests out of order, and a describe out of order
 3475.      1// with the one before it, each as one more failed test.
 3476.      1
 3477.      1        const [exitCode, stderr] = await childRun({}, String(`
 3478.      1jslint.jstestDescribe("cc", function () {
 3479.      1    jslint.jstestIt("bb", jslint.noop);
 3480.      1    jslint.jstestIt("aa", jslint.noop);
 3481.      1});
 3482.      1jslint.jstestDescribe("aa", function () {
 3483.      1    jslint.jstestIt("dd", jslint.noop);
 3484.      1});
 3485.      1        `));
 3486.      1        assertJsonEqual(exitCode, 1);
 3487.      1        assertMatch(stderr, /tests failed - 2\n/);
 3488.      1        assertOrThrow(stderr.includes(
 3489.      1            "\"aa\" must sort before \"bb\""
 3490.      1        ), stderr);
 3491.      1        assertOrThrow(stderr.includes(
 3492.      1            "\"aa\" must sort before \"cc\""
 3493.      1        ), stderr);
 3494.      1
 3495.      1// A failure its describe printed is not listed again at exit.
 3496.      1
 3497.      1        assertOrThrow(!stderr.includes("test it failed"), stderr);
 3498.      1    });
 3499.      1    jstestIt((
 3500.      1        "test jstestDescribe-order-edge handling-behavior"
 3501.      1    ), async function () {
 3502.      1
 3503.      1// Only a describe's first bad pair fails. A duplicate fails, and so does a
 3504.      1// non-string name, since '>=' would be false for it and let it pass.
 3505.      1
 3506.      1        const resultList = await Promise.all([
 3507.      1            ["aa", "cc", "bb", "aa"],
 3508.      1            ["aa", "aa"],
 3509.      1            [undefined, "bb"]
 3510.      3        ].map(function (descriptionList) {
 3511.      3            return childRun({}, String(`
 3512.      3jslint.jstestDescribe("aa", function () {
 3513.      3    for (const description of ${JSON.stringify(descriptionList)}) {
 3514.      3        jslint.jstestIt(description ?? undefined, jslint.noop);
 3515.      3    }
 3516.      3});
 3517.      3            `));
 3518.      3        }));
 3519.      3        assertJsonEqual(resultList.map(function ([exitCode, stderr]) {
 3520.      3            return [exitCode, stderr.match(/\S+ must sort before .*|duplicate description .*/g)];
 3521.      3        }), [
 3522.      1            [1, ["\"bb\" must sort before \"cc\""]],
 3523.      1            [1, ["duplicate description \"aa\""]],
 3524.      1            [1, ["\"bb\" must sort before undefined"]]
 3525.      1        ]);
 3526.      1    });
 3527.      1    jstestIt((
 3528.      1        "test jstestIt-filter handling-behavior"
 3529.      1    ), async function () {
 3530.      1
 3531.      1// Opt-in npm_config_mode_test_filter runs only "cc - dd", and a describe left
 3532.      1// with no test prints nothing.
 3533.      1
 3534.      1        const [exitCode, stderr] = await childRun({
 3535.      1            npm_config_mode_test_filter: "^cc - dd$"
 3536.      1        }, String(`
 3537.      1jslint.jstestDescribe("aa", function () {
 3538.      1    jslint.jstestIt("bb", jslint.noop);
 3539.      1});
 3540.      1jslint.jstestDescribe("cc", function () {
 3541.      1    jslint.jstestIt("dd", jslint.noop);
 3542.      1    jslint.jstestIt("ee", function () {
 3543.      1        throw new Error();
 3544.      1    });
 3545.      1});
 3546.      1        `));
 3547.      1        assertJsonEqual(exitCode, 0);
 3548.      1        assertMatch(stderr, /test describe - cc\n.*1\. test it - dd\b[\s\S]*tests total {2}- 1\n/);
 3549.      1        assertOrThrow(!stderr.includes("test describe - aa"), stderr);
 3550.      1        assertOrThrow(!stderr.includes("test it - ee"), stderr);
 3551.      1    });
 3552.      1    jstestIt((
 3553.      1        "test jstestIt-filter-empty handling-behavior"
 3554.      1    ), async function () {
 3555.      1
 3556.      1// A filter that matches no test fails the run, so a stray or mistyped filter
 3557.      1// cannot skip the whole suite and pass.
 3558.      1
 3559.      1        const [exitCode, stderr] = await childRun({
 3560.      1            npm_config_mode_test_filter: "^zz$"
 3561.      1        }, String(`
 3562.      1jslint.jstestDescribe("aa", function () {
 3563.      1    jslint.jstestIt("bb", jslint.noop);
 3564.      1});
 3565.      1        `));
 3566.      1        assertJsonEqual(exitCode, 1);
 3567.      1        assertMatch(stderr, /no test matched npm_config_mode_test_filter="\^zz\$"\n {2}tests total {2}- 0\n/);
 3568.      1    });
 3569.      1    jstestIt((
 3570.      1        "test jstestIt-late handling-behavior"
 3571.      1    ), async function () {
 3572.      1
 3573.      1// A jstestIt after an await in an async describe body, from a timer after the
 3574.      1// body settled, or before any describe, throws: only the body's synchronous
 3575.      1// part registers. The first crashes the body, leaving it and bb pending.
 3576.      1
 3577.      1        const resultList = await Promise.all([
 3578.      1            String(`
 3579.      1jslint.jstestDescribe("aa", async function () {
 3580.      1    jslint.jstestIt("bb", jslint.noop);
 3581.      1    await null;
 3582.      1    jslint.jstestIt("cc", jslint.noop);
 3583.      1});
 3584.      1            `),
 3585.      1            String(`
 3586.      1jslint.jstestDescribe("aa", function () {
 3587.      1    setTimeout(function () {
 3588.      1        jslint.jstestIt("cc", jslint.noop);
 3589.      1    }, 10);
 3590.      1    jslint.jstestIt("bb", function () {
 3591.      1        return new Promise(function (resolve) {
 3592.      1            setTimeout(resolve, 50);
 3593.      1        });
 3594.      1    });
 3595.      1});
 3596.      1            `),
 3597.      1            String(`
 3598.      1jslint.jstestIt("cc", jslint.noop);
 3599.      1            `)
 3600.      3        ].map(function (source) {
 3601.      3            return childRun({}, source);
 3602.      3        }));
 3603.      3        assertJsonEqual(resultList.map(function ([exitCode]) {
 3604.      3            return exitCode;
 3605.      3        }), [1, 1, 1]);
 3606.      1        assertMatch(resultList[0][1], /1\. test it pending - aa - jstestDescribe body\n[\s\S]*2\. test it pending - aa - bb\n[\s\S]*tests failed - 2\n/);
 3607.      3        resultList.forEach(function ([ignore, stderr]) {
 3608.      3            assertOrThrow(stderr.includes(
 3609.      3                "jstestIt \"cc\" called outside a jstestDescribe body, or" +
 3610.      3                " after an await"
 3611.      3            ), stderr);
 3612.      3        });
 3613.      1    });
 3614.      1    jstestIt((
 3615.      1        "test jstestIt-late-filtered handling-behavior"
 3616.      1    ), async function () {
 3617.      1
 3618.      1// A late jstestIt throws even when the filter would skip it, so a filter never
 3619.      1// hides a test registered after its describe settled.
 3620.      1
 3621.      1        const [exitCode, stderr] = await childRun({
 3622.      1            npm_config_mode_test_filter: "^aa - bb$"
 3623.      1        }, String(`
 3624.      1jslint.jstestDescribe("aa", function () {
 3625.      1    setTimeout(function () {
 3626.      1        jslint.jstestIt("cc", jslint.noop);
 3627.      1    }, 10);
 3628.      1    jslint.jstestIt("bb", function () {
 3629.      1        return new Promise(function (resolve) {
 3630.      1            setTimeout(resolve, 50);
 3631.      1        });
 3632.      1    });
 3633.      1});
 3634.      1        `));
 3635.      1        assertJsonEqual(exitCode, 1);
 3636.      1        assertOrThrow(stderr.includes(
 3637.      1            "jstestIt \"cc\" called outside a jstestDescribe body, or after" +
 3638.      1            " an await"
 3639.      1        ), stderr);
 3640.      1    });
 3641.      1    jstestIt((
 3642.      1        "test jstestIt-throw-non-error handling-behavior"
 3643.      1    ), async function () {
 3644.      1
 3645.      1// A test that throws undefined or a string, or rejects with no reason, fails
 3646.      1// and prints what it threw, without crashing the runner's report. The exit
 3647.      1// report prints a string too, for a failure a hung sibling kept unprinted.
 3648.      1
 3649.      1        const [[exitCode, stderr], [exitCode2, stderr2]] = await Promise.all([
 3650.      1            childRun({}, String(`
 3651.      1jslint.jstestDescribe("aa", function () {
 3652.      1    jslint.jstestIt("bb", function () {
 3653.      1        throw undefined;
 3654.      1    });
 3655.      1    jslint.jstestIt("cc", function () {
 3656.      1        return Promise.reject();
 3657.      1    });
 3658.      1    jslint.jstestIt("dd", function () {
 3659.      1        throw "dd string";
 3660.      1    });
 3661.      1    jslint.jstestIt("ee", function () {
 3662.      1        throw Object.create(null);
 3663.      1    });
 3664.      1});
 3665.      1            `)),
 3666.      1            childRun({}, String(`
 3667.      1jslint.jstestDescribe("aa", function () {
 3668.      1    jslint.jstestIt("bb", function () {
 3669.      1        throw "bb string";
 3670.      1    });
 3671.      1    jslint.jstestIt("bc", function () {
 3672.      1        throw 0;
 3673.      1    });
 3674.      1    jslint.jstestIt("cc", function () {
 3675.      1        setTimeout(process.exit, 100);
 3676.      1        return new Promise(jslint.noop);
 3677.      1    });
 3678.      1});
 3679.      1            `))
 3680.      1        ]);
 3681.      1        assertJsonEqual([exitCode, exitCode2], [1, 1]);
 3682.      1        assertMatch(stderr, /1\. test it - bb\nundefined\b[\s\S]*2\. test it - cc\nundefined\b[\s\S]*3\. test it - dd\ndd string\b[\s\S]*4\. test it - ee\n\[object\][\s\S]*tests failed - 4\n/);
 3683.      1        assertOrThrow(!stderr.includes("TypeError"), stderr);
 3684.      1        assertMatch(stderr2, /test it failed - aa - bb\nbb string\n[\s\S]*test it failed - aa - bc\n0\n[\s\S]*tests failed - 3\n/);
 3685.      1    });
 3686.      1    jstestIt((
 3687.      1        "test jstestOnExit-exit-code handling-behavior"
 3688.      1    ), async function () {
 3689.      1
 3690.      1// 256 failed tests exit 1, not their count, which an 8-bit exit status would
 3691.      1// wrap to a passing 0.
 3692.      1
 3693.      1        const [exitCode, stderr] = await childRun({}, String(`
 3694.      1jslint.jstestDescribe("aa", function () {
 3695.      1    let ii = 0;
 3696.      1    while (ii < 256) {
 3697.      1        jslint.jstestIt(String(1000 + ii), function () {
 3698.      1            throw new Error();
 3699.      1        });
 3700.      1        ii += 1;
 3701.      1    }
 3702.      1});
 3703.      1        `));
 3704.      1        assertJsonEqual(exitCode, 1);
 3705.      1        assertMatch(stderr, /tests total {2}- 256\n {2}tests failed - 256\n/);
 3706.      1    });
 3707.      1    jstestIt((
 3708.      1        "test jstestOnExit-pending handling-behavior"
 3709.      1    ), async function () {
 3710.      1
 3711.      1// A test still pending at exit counts as failed, in red, though its describe
 3712.      1// never prints. With nothing alive, the hang exits at once, since jstest keeps
 3713.      1// no timer; else <childRun>'s 10 s watchdog kills it.
 3714.      1
 3715.      1        const [exitCode, stderr] = await childRun({}, String(`
 3716.      1jslint.jstestDescribe("aa", function () {
 3717.      1    jslint.jstestIt("bb", function () {
 3718.      1        return new Promise(jslint.noop);
 3719.      1    });
 3720.      1});
 3721.      1        `));
 3722.      1        assertJsonEqual(exitCode, 1);
 3723.      1        assertMatch(stderr, /\[31m {2}\S+ 1\. test it pending - aa - bb\n {2}tests total {2}- 1\n {2}tests failed - 1\n/);
 3724.      1        assertOrThrow(!stderr.includes("test describe - aa"), stderr);
 3725.      1    });
 3726.      1    jstestIt((
 3727.      1        "test jstestOnExit-unprinted handling-behavior"
 3728.      1    ), async function () {
 3729.      1
 3730.      1// betadog's flake: bb fails before its emit, cc waits on that emit forever,
 3731.      1// then something ends the process. bb's error, stored in a describe that never
 3732.      1// prints, still shows and counts.
 3733.      1
 3734.      1        const [exitCode, stderr] = await childRun({}, String(`
 3735.      1import {EventEmitter} from "node:events";
 3736.      1const ee = new EventEmitter();
 3737.      1jslint.jstestDescribe("aa", function () {
 3738.      1    jslint.jstestIt("bb", async function () {
 3739.      1        throw new Error("bb real error");
 3740.      1    });
 3741.      1    jslint.jstestIt("cc", function () {
 3742.      1        setTimeout(process.exit, 100);
 3743.      1        return new Promise(function (resolve) {
 3744.      1            ee.once("done", resolve);
 3745.      1        });
 3746.      1    });
 3747.      1});
 3748.      1        `));
 3749.      1        assertJsonEqual(exitCode, 1);
 3750.      1        assertMatch(stderr, /1\. test it failed - aa - bb\nError: bb real error\n[\s\S]*2\. test it pending - aa - cc\n {2}tests total {2}- 2\n {2}tests failed - 2\n/);
 3751.      1    });
 3752.      1    jstestIt((
 3753.      1        "test jstestReport-numbering handling-behavior"
 3754.      1    ), async function () {
 3755.      1
 3756.      1// The exit report numbers on from the tests already printed, and leaves out a
 3757.      1// passed test whose describe never printed, here ee beside its hung sibling.
 3758.      1
 3759.      1        const [exitCode, stderr] = await childRun({}, String(`
 3760.      1jslint.jstestDescribe("aa", function () {
 3761.      1    jslint.jstestIt("bb", jslint.noop);
 3762.      1});
 3763.      1jslint.jstestDescribe("cc", function () {
 3764.      1    jslint.jstestIt("dd", function () {
 3765.      1        setTimeout(process.exit, 100);
 3766.      1        return new Promise(jslint.noop);
 3767.      1    });
 3768.      1    jslint.jstestIt("ee", jslint.noop);
 3769.      1});
 3770.      1        `));
 3771.      1        assertJsonEqual(exitCode, 1);
 3772.      1        assertMatch(stderr, /1\. test it - bb\b[\s\S]*✘ 2\. test it pending - cc - dd\n/);
 3773.      1        assertOrThrow(!stderr.includes("cc - ee"), stderr);
 3774.      1    });
 3775.      1});
 3776.      1
 3777.      1jstestDescribe((
 3778.      1    "test v8CoverageListMerge handling-behavior"
 3779.      1), function () {
 3780.      1    let functionsInput = JSON.stringify([
 3781.      1        {
 3782.      1            functionName: "test",
 3783.      1            isBlockCoverage: true,
 3784.      1            ranges: [
 3785.      1                {
 3786.      1                    count: 2,
 3787.      1                    endOffset: 4,
 3788.      1                    startOffset: 0
 3789.      1                },
 3790.      1                {
 3791.      1                    count: 1,
 3792.      1                    endOffset: 2,
 3793.      1                    startOffset: 1
 3794.      1                },
 3795.      1                {
 3796.      1                    count: 1,
 3797.      1                    endOffset: 3,
 3798.      1                    startOffset: 2
 3799.      1                }
 3800.      1            ]
 3801.      1        }
 3802.      1    ]);
 3803.      1    jstestIt((
 3804.      1        "test merge-empty-list handling-behavior"
 3805.      1    ), function () {
 3806.      1        assertJsonEqual(v8CoverageListMerge([]), {
 3807.      1            result: []
 3808.      1        });
 3809.      1    });
 3810.      1    jstestIt((
 3811.      1        "test merge-fixture handling-behavior"
 3812.      1    ), function () {
 3813.      1        for (const file of [
 3814.      1            "test_coverage_merge_is_block_coverage_test.json",
 3815.      1            "test_coverage_merge_issue_2_mixed_is_block_coverage_test.json",
 3816.      1            "test_coverage_merge_node_10_internal_errors_one_of_test.json",
 3817.      1            "test_coverage_merge_reduced_test.json",
 3818.      1            "test_coverage_merge_simple_test.json",
 3819.      1            "test_coverage_merge_various_test.json"
 3820.      6        ]) {
 3821.     84            for (const {expected, inputs} of testCoverageMergeData[file]) {
 3822.     84                assertJsonEqual(v8CoverageListMerge(inputs), expected, file);
 3823.     84            }
 3824.      6        }
 3825.      1    });
 3826.      1    jstestIt((
 3827.      1        "test merge-node-sqlite-files handling-behavior"
 3828.      1    ), function () {
 3829.      1        let data1 = [
 3830.      1            "test_v8_coverage_node_sqlite_9884_1633662346346_0.json",
 3831.      1            "test_v8_coverage_node_sqlite_13216_1633662333140_0.json"
 3832.      2        ].map(function (file) {
 3833.      2            return testCoverageMergeData[file];
 3834.      2        });
 3835.      1        let data2 = testCoverageMergeData[
 3836.      1            "test_v8_coverage_node_sqlite_merged.json"
 3837.      1        ];
 3838.      1        data1 = v8CoverageListMerge(data1);
 3839.      1        data1 = v8CoverageListMerge([data1]);
 3840.      1
 3841.      1// Debug data1.
 3842.      1// await moduleFs.promises.writeFile(
 3843.      1//     ".test_v8_coverage_node_sqlite_merged.json",
 3844.      1//     JSON.stringify(objectDeepCopyWithKeysSorted(data1), undefined, 4) + "\n"
 3845.      1// );
 3846.      1
 3847.      1        assertJsonEqual(data1, data2);
 3848.      1    });
 3849.      1    jstestIt((
 3850.      1        "test merge-one-list handling-behavior"
 3851.      1    ), function () {
 3852.      1        assertJsonEqual(v8CoverageListMerge([
 3853.      1            {
 3854.      1                result: [
 3855.      1                    {
 3856.      1                        functions: JSON.parse(functionsInput),
 3857.      1                        moduleUrl: "/lib.js",
 3858.      1                        scriptId: "123"
 3859.      1                    }
 3860.      1                ]
 3861.      1            }
 3862.      1        ]), {
 3863.      1            result: [
 3864.      1                {
 3865.      1                    functions: [
 3866.      1                        {
 3867.      1                            functionName: "test",
 3868.      1                            isBlockCoverage: true,
 3869.      1                            ranges: [
 3870.      1                                {
 3871.      1                                    count: 2,
 3872.      1                                    endOffset: 4,
 3873.      1                                    startOffset: 0
 3874.      1                                },
 3875.      1                                {
 3876.      1                                    count: 1,
 3877.      1                                    endOffset: 3,
 3878.      1                                    startOffset: 1
 3879.      1                                }
 3880.      1                            ]
 3881.      1                        }
 3882.      1                    ],
 3883.      1                    moduleUrl: "/lib.js",
 3884.      1                    scriptId: "0"
 3885.      1                }
 3886.      1            ]
 3887.      1        });
 3888.      1    });
 3889.      1    jstestIt((
 3890.      1        "test merge-two-identical-lists handling-behavior"
 3891.      1    ), function () {
 3892.      1        assertJsonEqual(v8CoverageListMerge([
 3893.      1            {
 3894.      1                result: [
 3895.      1                    {
 3896.      1                        functions: JSON.parse(functionsInput),
 3897.      1                        scriptId: "123",
 3898.      1                        url: "/lib.js"
 3899.      1                    }, {
 3900.      1                        functions: JSON.parse(functionsInput),
 3901.      1                        scriptId: "123",
 3902.      1                        url: "/lib.js"
 3903.      1                    }
 3904.      1                ]
 3905.      1            }
 3906.      1        ]), {
 3907.      1            result: [
 3908.      1                {
 3909.      1                    functions: [
 3910.      1                        {
 3911.      1                            functionName: "test",
 3912.      1                            isBlockCoverage: true,
 3913.      1                            ranges: [
 3914.      1                                {
 3915.      1                                    count: 4,
 3916.      1                                    endOffset: 4,
 3917.      1                                    startOffset: 0
 3918.      1                                },
 3919.      1                                {
 3920.      1                                    count: 2,
 3921.      1                                    endOffset: 3,
 3922.      1                                    startOffset: 1
 3923.      1                                }
 3924.      1                            ]
 3925.      1                        }
 3926.      1                    ],
 3927.      1                    scriptId: "0",
 3928.      1                    url: "/lib.js"
 3929.      1                }
 3930.      1            ]
 3931.      1        });
 3932.      1    });
 3933.      1    jstestIt((
 3934.      1        "test merge-unshared-function handling-behavior"
 3935.      1    ), function () {
 3936.      1        assertJsonEqual(v8CoverageListMerge([
 3937.      1            {
 3938.      1                result: [
 3939.      1                    {
 3940.      1                        functions: [
 3941.      1                            {
 3942.      1                                functionName: "test",
 3943.      1                                isBlockCoverage: true,
 3944.      1                                ranges: [
 3945.      1                                    {
 3946.      1                                        count: 2,
 3947.      1                                        endOffset: 4,
 3948.      1                                        startOffset: 0
 3949.      1                                    }
 3950.      1                                ]
 3951.      1                            }
 3952.      1                        ],
 3953.      1                        moduleUrl: "/lib.js",
 3954.      1                        scriptId: "1"
 3955.      1                    }
 3956.      1                ]
 3957.      1            },
 3958.      1            {
 3959.      1                result: [
 3960.      1                    {
 3961.      1                        functions: [],
 3962.      1                        moduleUrl: "/lib.js",
 3963.      1                        scriptId: "2"
 3964.      1                    }
 3965.      1                ]
 3966.      1            }
 3967.      1        ]), {
 3968.      1            result: [
 3969.      1                {
 3970.      1                    functions: [
 3971.      1                        {
 3972.      1                            functionName: "test",
 3973.      1                            isBlockCoverage: true,
 3974.      1                            ranges: [
 3975.      1                                {
 3976.      1                                    count: 2,
 3977.      1                                    endOffset: 4,
 3978.      1                                    startOffset: 0
 3979.      1                                }
 3980.      1                            ]
 3981.      1                        }
 3982.      1                    ],
 3983.      1                    scriptId: "0"
 3984.      1                }
 3985.      1            ]
 3986.      1        });
 3987.      1    });
 3988.      1});
 3989.      1
 3990.      1jstestDescribe((
 3991.      1    "test v8CoverageReportCreate handling-behavior"
 3992.      1), function () {
 3993.      1    jstestIt((
 3994.      1        "test coverage-hole-closing-midline handling-behavior"
 3995.      1    ), async function () {
 3996.      1
 3997.      1// Pin two branches of <v8CoverageReportCreate> that line coverage cannot see.
 3998.      1// A hole ending before end-of-line must close with a bare span, the
 3999.      1// deadcode-dispelled case, and a hole on an ignored line must render "ignore".
 4000.      1// Passing 0 makes each "&& ..." a hole, while the ";" after it is covered.
 4001.      1
 4002.      1        const dir = ".tmp/coverage_hole/";
 4003.      1        const file = dir + "coverage_hole.js";
 4004.      1        await fsWriteFileWithParents(file, (
 4005.      1            "function aa(bb) {\n" +
 4006.      1            "    return bb && bb.cc;\n" +
 4007.      1            "}\n" +
 4008.      1            "function dd(ee) {\n" +
 4009.      1            "    return ee && ee.ff; //coverage-ignore-line\n" +
 4010.      1            "}\n" +
 4011.      1            "aa(0);\n" +
 4012.      1            "dd(0);\n"
 4013.      1        ));
 4014.      1        await jslint.jslint_cli({
 4015.      1            console_error: noop, // comment to debug
 4016.      1            mode_cli: true,
 4017.      1            process_argv: [
 4018.      1                "node", "jslint.mjs",
 4019.      1                "v8_coverage_report=" + dir,
 4020.      1                "node",
 4021.      1                file
 4022.      1            ]
 4023.      1        });
 4024.      1        assertOrThrow((
 4025.      1            await moduleFs.promises.readFile(dir + file + ".html", "utf8")
 4026.      1        ).includes(
 4027.      1            "<span class=\"uncovered\">&amp;&amp; bb.cc</span><span>;</span>"
 4028.      1        ), "expected a hole closing mid-line in " + dir + file + ".html");
 4029.      1        assertOrThrow((
 4030.      1            await moduleFs.promises.readFile(dir + file + ".html", "utf8")
 4031.      1        ).includes(
 4032.      1            "<span class=\"ignore\">&amp;&amp; ee.ff</span><span>;"
 4033.      1        ), "expected an ignored hole in " + dir + file + ".html");
 4034.      1    });
 4035.      1    jstestIt((
 4036.      1        "test coverage-ignore handling-behavior"
 4037.      1    ), function () {
 4038.     -0        switch (noop() && noop()) { //coverage-ignore-line
 4039.     -0        case 1: //coverage-ignore-line
 4040.     -0            break; //coverage-ignore-line
 4041.      1/*coverage-disable*/
 4042.     -0        case 2:
 4043.     -0            break;
 4044.      1/*coverage-enable*/
 4045.      1        case undefined:
 4046.      1            break;
 4047.      1        }
 4048.      1    });
 4049.      1    jstestIt((
 4050.      1        "test coverage-report-jslint-mjs handling-behavior"
 4051.      1    ), async function () {
 4052.      1        // test remove-old-coverage handling-behavior
 4053.      1        await fsWriteFileWithParents(
 4054.      1            ".tmp/coverage_jslint/coverage-0-0-0.json",
 4055.      1            ""
 4056.      1        );
 4057.      1        await jslint.jslint_cli({
 4058.      1            console_error: noop, // comment to debug
 4059.      1            mode_cli: true,
 4060.      1            process_argv: [
 4061.      1                "node", "jslint.mjs",
 4062.      1                "v8_coverage_report=.tmp/coverage_jslint",
 4063.      1                "--exclude=aa.js",
 4064.      1                "--include-node-modules=1",
 4065.      1                "--include=jslint.mjs",
 4066.      1                "node", "jslint.mjs"
 4067.      1            ]
 4068.      1        });
 4069.      1    });
 4070.      1    jstestIt((
 4071.      1        "test misc handling-behavior"
 4072.      1    ), async function () {
 4073.      1        await Promise.all([
 4074.      1            [
 4075.      1                ".tmp/coverage_misc/aa.js", "\n".repeat(0x100)
 4076.      1            ], [
 4077.      1                ".tmp/coverage_misc/coverage-0-0-0.json", JSON.stringify({
 4078.      1                    "result": [
 4079.      1                        {
 4080.      1                            "functions": [
 4081.      1                                {
 4082.      1                                    "functionName": "",
 4083.      1                                    "isBlockCoverage": true,
 4084.      1                                    "ranges": [
 4085.      1                                        {
 4086.      1                                            "count": 1,
 4087.      1                                            "endOffset": 0xf0,
 4088.      1                                            "startOffset": 0x10
 4089.      1                                        },
 4090.      1                                        {
 4091.      1                                            "count": 1,
 4092.      1                                            "endOffset": 0x40,
 4093.      1                                            "startOffset": 0x20
 4094.      1                                        },
 4095.      1                                        {
 4096.      1                                            "count": 1,
 4097.      1                                            "endOffset": 0x80,
 4098.      1                                            "startOffset": 0x60
 4099.      1                                        },
 4100.      1                                        {
 4101.      1                                            "count": 0,
 4102.      1                                            "endOffset": 0x45,
 4103.      1                                            "startOffset": 0x25
 4104.      1                                        },
 4105.      1                                        {
 4106.      1                                            "count": 0,
 4107.      1                                            "endOffset": 0x85,
 4108.      1                                            "startOffset": 0x65
 4109.      1                                        }
 4110.      1                                    ]
 4111.      1                                }
 4112.      1                            ],
 4113.      1                            "scriptId": "0",
 4114.      1                            "url": "file:///" + modulePath.resolve(
 4115.      1                                ".tmp/coverage_misc/aa.js"
 4116.      1                            )
 4117.      1                        }
 4118.      1                    ]
 4119.      1                }, undefined, 4)
 4120.      1            ]
 4121.      2        ].map(async function ([
 4122.      2            file, data
 4123.      2        ]) {
 4124.      2            await fsWriteFileWithParents(file, data);
 4125.      2        }));
 4126.      1        await jslint.jslint_cli({
 4127.      1            console_error: noop, // comment to debug
 4128.      1            mode_cli: true,
 4129.      1            process_argv: [
 4130.      1                "node", "jslint.mjs",
 4131.      1                "v8_coverage_report=.tmp/coverage_misc"
 4132.      1                // "node", ".tmp/coverage_misc/aa.js"
 4133.      1            ]
 4134.      1        });
 4135.      1    });
 4136.      1    jstestIt((
 4137.      1        "test npm handling-behavior"
 4138.      1    ), async function () {
 4139.      1        await jslint.jslint_cli({
 4140.      1            console_error: noop, // comment to debug
 4141.      1            mode_cli: true,
 4142.      1            process_argv: [
 4143.      1                "node", "jslint.mjs",
 4144.      1                "v8_coverage_report=.tmp/coverage_npm",
 4145.      1                "npm", "--version"
 4146.      1            ]
 4147.      1        });
 4148.      1    });
 4149.      1    jstestIt((
 4150.      1        "test null-case handling-behavior"
 4151.      1    ), async function () {
 4152.      1        await assertErrorThrownAsync(function () {
 4153.      1            return v8CoverageReportCreate({});
 4154.      1        }, "invalid coverageDir");
 4155.      1    });
 4156.      1    jstestIt((
 4157.      1        "test report-fixture handling-behavior"
 4158.      1    ), async function () {
 4159.      1        const fixtureList = [
 4160.      1            [
 4161.      1                "v8CoverageReportCreate_high.js", (
 4162.      1                    "switch(0){\n" +
 4163.      1                    "case 0:break;\n" +
 4164.      1                    "}\n"
 4165.      1                )
 4166.      1            ], [
 4167.      1                "v8CoverageReportCreate_ignore.js", (
 4168.      1                    "/*coverage-ignore-file*/\n" +
 4169.      1                    "switch(0){\n" +
 4170.      1                    "case 0:break;\n" +
 4171.      1                    "case 1:break;//coverage-ignore-line\n" +
 4172.      1                    "/*coverage-disable*/\n" +
 4173.      1                    "case 2:break;\n" +
 4174.      1                    "/*coverage-enable*/\n" +
 4175.      1                    "}\n"
 4176.      1                )
 4177.      1            ], [
 4178.      1                "v8CoverageReportCreate_low.js", (
 4179.      1                    "switch(0){\n" +
 4180.      1                    "case 1:break;\n" +
 4181.      1                    "case 2:break;\n" +
 4182.      1                    "case 3:break;\n" +
 4183.      1                    "case 4:break;\n" +
 4184.      1                    "}\n"
 4185.      1                )
 4186.      1            ], [
 4187.      1                "v8CoverageReportCreate_medium.js", (
 4188.      1                    "switch(0){\n" +
 4189.      1                    "case 0:break;\n" +
 4190.      1                    "case 1:break;\n" +
 4191.      1                    "case 2:break;\n" +
 4192.      1                    "}\n"
 4193.      1                )
 4194.      1            ]
 4195.      1        ];
 4196.      4        await Promise.all(fixtureList.map(async function ([
 4197.      4            file, data
 4198.      4        ], ii) {
 4199.      4            const dir = ".tmp/coverage_" + ii + "/";
 4200.      4            file = dir + file;
 4201.      4            await fsWriteFileWithParents(file, data);
 4202.      4            await jslint.jslint_cli({
 4203.      4                console_error: noop, // comment to debug
 4204.      4                mode_cli: true,
 4205.      4                process_argv: [
 4206.      4                    "node", "jslint.mjs",
 4207.      4                    "v8_coverage_report=" + dir,
 4208.      4                    "node",
 4209.      4                    file
 4210.      4                ]
 4211.      4            });
 4212.      4        }));
 4213.      1    });
 4214.      1});
 4215.      1