V8 Coverage Report
Files covered Lines
. / jslint.mjs
99.75 %
10931 / 10958
    1.      1// #!/usr/bin/env node
    2.      1// JSLint
    3.      1// Original Author: Douglas Crockford (https://www.jslint.com).
    4.      1
    5.      1// This is free and unencumbered software released into the public domain.
    6.      1
    7.      1// Anyone is free to copy, modify, publish, use, compile, sell, or
    8.      1// distribute this software, either in source code form or as a compiled
    9.      1// binary, for any purpose, commercial or non-commercial, and by any
   10.      1// means.
   11.      1
   12.      1// In jurisdictions that recognize copyright laws, the author or authors
   13.      1// of this software dedicate any and all copyright interest in the
   14.      1// software to the public domain. We make this dedication for the benefit
   15.      1// of the public at large and to the detriment of our heirs and
   16.      1// successors. We intend this dedication to be an overt act of
   17.      1// relinquishment in perpetuity of all present and future rights to this
   18.      1// software under copyright law.
   19.      1
   20.      1// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   21.      1// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   22.      1// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   23.      1// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
   24.      1// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
   25.      1// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   26.      1// OTHER DEALINGS IN THE SOFTWARE.
   27.      1
   28.      1// For more information, please refer to <https://unlicense.org/>
   29.      1
   30.      1
   31.      1// jslint(source, option_dict, global_list) is a function that takes 3
   32.      1// arguments. The second two arguments are optional.
   33.      1
   34.      1//      source          A text to analyze.
   35.      1//      option_dict     An object whose keys correspond to option names.
   36.      1//      global_list     An array of strings containing global variables that
   37.      1//                      the file is allowed readonly access.
   38.      1
   39.      1// jslint returns an object containing its results. The object contains a lot
   40.      1// of valuable information. It can be used to generate reports. The object
   41.      1// contains:
   42.      1
   43.      1//      directives: an array of directive comment tokens.
   44.      1//      edition: the version of JSLint that did the analysis.
   45.      1//      exports: the names exported from the module.
   46.      1//      froms: an array of strings representing each of the imports.
   47.      1//      functions: an array of objects that represent all functions
   48.      1//              declared in the file.
   49.      1//      global: an object representing the global object. Its .context property
   50.      1//              is an object containing a property for each global variable.
   51.      1//      id: "(JSLint)"
   52.      1//      json: true if the file is a JSON text.
   53.      1//      lines: an array of strings, the source.
   54.      1//      module: true if an import or export statement was used.
   55.      1//      ok: true if no warnings were generated. This is what you want.
   56.      1//      option: the option argument.
   57.      1//      property: a property object.
   58.      1//      stop: true if JSLint was unable to finish. You don't want this.
   59.      1//      tokens: an array of objects representing the tokens in the file.
   60.      1//      tree: the token objects arranged in a tree.
   61.      1//      warnings: an array of warning objects. A warning object can contain:
   62.      1//          name: "JSLintError"
   63.      1//          column: A column number in the file.
   64.      1//          line: A line number in the file.
   65.      1//          code: A warning code string.
   66.      1//          message: The warning message string.
   67.      1//          a: Exhibit A.
   68.      1//          b: Exhibit B.
   69.      1//          c: Exhibit C.
   70.      1//          d: Exhibit D.
   71.      1
   72.      1// jslint works in several phases. In any of these phases, errors might be
   73.      1// found. Sometimes JSLint is able to recover from an error and continue
   74.      1// parsing. In some cases, it cannot and will stop early. If that should happen,
   75.      1// repair your code and try again.
   76.      1
   77.      1// Phases:
   78.      1
   79.      1// PHASE 1. Split <source> by newlines into <line_list>.
   80.      1// PHASE 2. Lex <line_list> into <token_list>.
   81.      1// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
   82.      1// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
   83.      1//          recursive traversal. Each node may be processed on the way down
   84.      1//          (preaction) and on the way up (postaction).
   85.      1// PHASE 5. Check whitespace between tokens in <token_list>.
   86.      1
   87.      1// jslint can also examine JSON text. It decides that a file is JSON text if
   88.      1// the first token is "[" or "{". Processing of JSON text is much simpler than
   89.      1// the processing of JavaScript programs. Only the first three phases are
   90.      1// required.
   91.      1
   92.      1// WARNING: JSLint will hurt your feelings.
   93.      1
   94.      1/*jslint beta, node*/
   95.      1
   96.      1/*property
   97.      1    NODE_V8_COVERAGE,
   98.      1    char, consoleError, coverageDir,
   99.      1    fileList,
  100.      1    holeList,
  101.      1    isHole,
  102.      1    lineList, linesCovered, linesTotal,
  103.      1    modeCoverageIgnoreFile, modeIndex,
  104.      1    npm_config_mode_coverage,
  105.      1    v8CoverageReportCreate
  106.      1
  107.      1    children, clear, count,
  108.      1    delta,
  109.      1    end, endOffset, entries,
  110.      1    functionName,
  111.      1    get,
  112.      1    isBlockCoverage,
  113.      1    parentIi,
  114.      1    ranges, result,
  115.      1    scriptId, set, splice, start, startOffset,
  116.      1    unshift,
  117.      1    v8CoverageListMerge,
  118.      1
  119.      1    assertErrorThrownAsync, assertJsonEqual,
  120.      1    jstestDescribe, jstestIt, jstestOnExit,
  121.      1    processEnv,
  122.      1
  123.      1    floor,
  124.      1    on,
  125.      1    padEnd, platform,
  126.      1    rename, reverse, round,
  127.      1    sep, spawn, stdio,
  128.      1
  129.      1    JSLINT_BETA, a, all, argv, arity, artifact, assertOrThrow, assign, async,
  130.      1    b, beta, bitwise, block, body, browser, c, calls, catch, catch_list,
  131.      1    catch_stack, causes, cjs_module, cjs_require, closer, closure, code, column,
  132.      1    concat, console_error, console_log, constant, context, convert, create, cwd,
  133.      1    d, dead, debugInline, default, devel, directive, directive_list,
  134.      1    directive_quiet, directives, dirname, disrupt, dot, edition, elem_list,
  135.      1    ellipsis, else, endsWith, env, error, eval, every, example_list, exec,
  136.      1    execArgv, exit, export_dict, exports, expression, extra, file,
  137.      1    fileURLToPath, filter, finally, flag, for, forEach, formatted_message, free,
  138.      1    freeze, from, froms, fsRmRecursive, fsWriteFileWithParents, fud,
  139.      1    function_list, function_stack, functions, getset, github_repo, global,
  140.      1    global_dict, global_list, htmlEscape, id, identifier, import, import_list,
  141.      1    inc, indent2, index, indexOf, init, initial, isArray, isNaN, is_equal,
  142.      1    is_weird, join, jslint, jslint_apidoc, jslint_assert, jslint_charset_ascii,
  143.      1    jslint_cli, jslint_edition, jslint_phase1_split, jslint_phase2_lex,
  144.      1    jslint_phase3_parse, jslint_phase4_walk, jslint_phase5_whitage,
  145.      1    jslint_report, json, keys, label, lbp, led, length, level, line, line_list,
  146.      1    line_offset, line_source, lines, live, log, long, loop, m, main, map,
  147.      1    margin, match, max, message, meta, min, mkdir, mode_cli, mode_json,
  148.      1    mode_module, mode_noop, mode_property, mode_shebang, mode_stop, module,
  149.      1    moduleFsInit, module_list, moduleName, name, names, node, noop, now, nr,
  150.      1    nud, ok, open, opening, option, option_dict, order, package_name, padStart,
  151.      1    parameters, parent, parse, pathname, pop, processArgv, process_exit,
  152.      1    process_version, promises, property, property_dict, push, quote, readFile,
  153.      1    readdir, readonly, recursive, reduce, repeat, replace, resolve, rm, rmdir,
  154.      1    role, search, shebang, shift, signature, single, slice, some, sort, source,
  155.      1    split, stack, stack_trace, startsWith, statement, statement_prv, stop,
  156.      1    stop_at, stringify, switch, syntax_dict, tenure, test, test_cause,
  157.      1    test_internal_error, this, thru, toString, token, token_global, token_list,
  158.      1    token_nxt, token_tree, tokens, trace, tree, trim, trimEnd, trimRight, try,
  159.      1    type, unlink, unordered, url, used, value, variable, version, versions,
  160.      1    warn, warn_at, warning, warning_list, warnings, white, wrapped, writeFile
  161.      1*/
  162.      1
  163.      1// init debugInline
  164.      1let debugInline = (function () {
  165.      3    let consoleError = function () {
  166.      3        return;
  167.      3    };
  168.      1    return function (...argv) {
  169.      1
  170.      1// This function will both print <argv> to stderr and return <argv>[0].
  171.      1
  172.      1        consoleError("\n\ndebugInline");
  173.      1        consoleError(...argv);
  174.      1        consoleError("\n");
  175.      1        consoleError = console.error;
  176.      1        return argv[0];
  177.      1    };
  178.      1}());
  179.      1let jslint_charset_ascii = (
  180.      1    "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"
  181.      1    + "\b\t\n\u000b\f\r\u000e\u000f"
  182.      1    + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"
  183.      1    + "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"
  184.      1    + " !\"#$%&'()*+,-./0123456789:;<=>?"
  185.      1    + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
  186.      1    + "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"
  187.      1);
  188.      1let jslint_edition = "v2021.10.1-beta";
  189.      1let jslint_export;                      // The jslint object to be exported.
  190.      1let jslint_fudge = 1;                   // Fudge starting line and starting
  191.      1                                        // ... column to 1.
  192.      1let jslint_import_meta_url = "";        // import.meta.url used by cli.
  193.      1let jstestCountFailed = 0;
  194.      1let jstestCountTotal = 0;
  195.      1let jstestItCount = 0;
  196.      1let jstestItList = [];
  197.      1let jstestTimeStart;
  198.      1let moduleChildProcess;
  199.      1let moduleFs;
  200.      1let moduleFsInitResolveList;
  201.      1let modulePath;
  202.      1let moduleUrl;
  203.      1
  204.      6async function assertErrorThrownAsync(asyncFunc, regexp) {
  205.      6
  206.      6// This function will assert <asyncFunc> throws an error.
  207.      6
  208.      6    let err;
  209.      6    try {
  210.      1        await asyncFunc();
  211.      5    } catch (errCaught) {
  212.      5        err = errCaught;
  213.      5    }
  214.      6    assertOrThrow(err, "no error thrown");
  215.      6    assertOrThrow(
  216.      1        regexp === undefined || new RegExp(regexp).test(err.message),
  217.      6        err
  218.      6    );
  219.      6}
  220.      1
  221.     90function assertJsonEqual(aa, bb) {
  222.     90
  223.     90// This function will assert JSON.stringify(<aa>) === JSON.stringify(<bb>).
  224.     90
  225.     90    aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa));
  226.     90    bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb));
  227.      1    if (aa !== bb) {
  228.      1        throw new Error(
  229.      1            JSON.stringify(aa) + " !== " + JSON.stringify(bb)
  230.      1        );
  231.      1    }
  232.     90}
  233.      1
  234.   1738function assertOrThrow(condition, message) {
  235.   1738
  236.   1738// This function will throw <message> if <condition> is falsy.
  237.   1738
  238.      4    if (!condition) {
  239.      4        throw (
  240.      4            (!message || typeof message === "string")
  241.      4            ? new Error(String(message).slice(0, 2048))
  242.      4            : message
  243.      4        );
  244.      4    }
  245.   1738}
  246.      1
  247.  88031function empty() {
  248.  88031
  249.  88031// The empty function produces a new empty object that inherits nothing. This is
  250.  88031// much better than '{}' because confusions around accidental method names like
  251.  88031// 'constructor' are completely avoided.
  252.  88031
  253.  88031    return Object.create(null);
  254.  88031}
  255.      1
  256.      3async function fsRmRecursive(path, option_dict) {
  257.      3
  258.      3// This function will 'rm -r' <path>.
  259.      3
  260.      3    await moduleFsInit();
  261.      3    console.error("rm -r path " + path);
  262.      3    if (((
  263.      1        option_dict && option_dict.process_version
  264.      2    ) || process.version) < "v14") {
  265.      1
  266.      1// Legacy rmdir for nodejs v12
  267.      1
  268.      1        await Promise.all([
  269.      1            moduleFs.promises.unlink(path).catch(noop),
  270.      1            moduleFs.promises.rmdir(path, {
  271.      1                recursive: true
  272.      1            }).catch(noop)
  273.      1        ]);
  274.      1        return;
  275.      2    }
  276.      2    await moduleFs.promises.rm(path, {
  277.      2        recursive: true
  278.      2    }).catch(noop);
  279.      2}
  280.      1
  281.     46async function fsWriteFileWithParents(pathname, data) {
  282.     46
  283.     46// This function will write <data> to <pathname> and lazy-mkdirp if necessary.
  284.     46
  285.     46    await moduleFsInit();
  286.     46
  287.     46// Try writing to pathname.
  288.     46
  289.     46    try {
  290.     36        await moduleFs.promises.writeFile(pathname, data);
  291.     36    } catch (ignore) {
  292.     10
  293.     10// Lazy mkdirp.
  294.     10
  295.     10        await moduleFs.promises.mkdir(modulePath.dirname(pathname), {
  296.     10            recursive: true
  297.     10        });
  298.     10
  299.     10// Retry writing to pathname.
  300.     10
  301.     10        await moduleFs.promises.writeFile(pathname, data);
  302.     10    }
  303.     46    console.error("wrote file " + pathname);
  304.     46}
  305.      1
  306.  13490function htmlEscape(str) {
  307.  13490
  308.  13490// This function will make <str> html-safe by escaping & < >.
  309.  13490
  310.  13490    return String(str).replace((
  311.  13490        /&/g
  312.  13490    ), "&amp;").replace((
  313.  13490        /</g
  314.  13490    ), "&lt;").replace((
  315.  13490        />/g
  316.  13490    ), "&gt;");
  317.  13490}
  318.      1
  319.    628function jslint(
  320.    628    source = "",                // A text to analyze.
  321.    628    option_dict = empty(),      // An object whose keys correspond to option
  322.    628                                // ... names.
  323.    628    global_list = []            // An array of strings containing global
  324.    628                                // ... variables that the file is allowed
  325.    628                                // ... readonly access.
  326.    628) {
  327.    628
  328.    628// The jslint function itself.
  329.    628
  330.    628    let catch_list = [];        // The array containing all catch-blocks.
  331.    628    let catch_stack = [         // The stack of catch-blocks.
  332.    628        {
  333.    628            context: empty()
  334.    628        }
  335.    628    ];
  336.    628    let cause_dict = empty();   // The object of test-causes.
  337.    628    let directive_list = [];    // The directive comments.
  338.    628    let export_dict = empty();  // The exported names and values.
  339.    628    let function_list = [];     // The array containing all functions.
  340.    628    let function_stack = [];    // The stack of functions.
  341.    628    let global_dict = empty();  // The object containing the global
  342.    628                                // ... declarations.
  343.    628    let import_list = [];       // The array collecting all import-from strings.
  344.    628    let line_list = String(     // The array containing source lines.
  345.    628        "\n" + source
  346.    628    ).split(
  347.    628        // rx_crlf
  348.    628        /\n|\r\n?/
  349.  88788    ).map(function (line_source) {
  350.  88788        return {
  351.  88788            line_source
  352.  88788        };
  353.  88788    });
  354.    628    let mode_stop = false;      // true if JSLint cannot finish.
  355.    628    let property_dict = empty();        // The object containing the tallied
  356.    628                                        // ... property names.
  357.    628    let state = empty();        // jslint state-object to be passed between
  358.    628                                // jslint functions.
  359.    628    let syntax_dict = empty();  // The object containing the parser.
  360.    628    let tenure = empty();       // The predefined property registry.
  361.    628    let token_global = {        // The global object; the outermost context.
  362.    628        async: 0,
  363.    628        body: true,
  364.    628        context: empty(),
  365.    628        finally: 0,
  366.    628        from: 0,
  367.    628        id: "(global)",
  368.    628        level: 0,
  369.    628        line: jslint_fudge,
  370.    628        live: [],
  371.    628        loop: 0,
  372.    628        switch: 0,
  373.    628        thru: 0,
  374.    628        try: 0
  375.    628    };
  376.    628    let token_list = [];        // The array of tokens.
  377.    628    let warning_list = [];      // The array collecting all generated warnings.
  378.    628
  379.    628// Error reportage functions:
  380.    628
  381.   7296    function artifact(the_token) {
  382.   7296
  383.   7296// Return a string representing an artifact.
  384.   7296
  385.    252        the_token = the_token || state.token_nxt;
  386.   7296        return (
  387.   4878            (the_token.id === "(string)" || the_token.id === "(number)")
  388.   2549            ? String(the_token.value)
  389.   4747            : the_token.id
  390.   7296        );
  391.   7296    }
  392.    628
  393.  30811    function is_equal(aa, bb) {
  394.  30811        let aa_value;
  395.  30811        let bb_value;
  396.  30811
  397.  30811// test_cause:
  398.  30811// ["0&&0", "is_equal", "", "", 0]
  399.  30811
  400.  30811        test_cause("");
  401.  30811
  402.  30811// Probably deadcode.
  403.  30811// if (aa === bb) {
  404.  30811//     return true;
  405.  30811// }
  406.  30811
  407.  30811        jslint_assert(!(aa === bb), `Expected !(aa === bb).`);
  408.      9        if (Array.isArray(aa)) {
  409.      9            return (
  410.      9                Array.isArray(bb)
  411.      9                && aa.length === bb.length
  412.      9                && aa.every(function (value, index) {
  413.      9
  414.      9// test_cause:
  415.      9// ["`${0}`&&`${0}`", "is_equal", "recurse_isArray", "", 0]
  416.      9
  417.      9                    test_cause("recurse_isArray");
  418.      9                    return is_equal(value, bb[index]);
  419.      9                })
  420.      9            );
  421.  30802        }
  422.  30802
  423.  30802// Probably deadcode.
  424.  30802// if (Array.isArray(bb)) {
  425.  30802//     return false;
  426.  30802// }
  427.  30802
  428.  30802        jslint_assert(!Array.isArray(bb), `Expected !Array.isArray(bb).`);
  429.  30802        if (aa.id === "(number)" && bb.id === "(number)") {
  430.     67            return aa.value === bb.value;
  431.  30735        }
  432.  30735        if (aa.id === "(string)") {
  433.  22409            aa_value = aa.value;
  434.  22409        } else if (aa.id === "`" && aa.constant) {
  435.   8326            aa_value = aa.value[0];
  436.  30735        }
  437.  30735        if (bb.id === "(string)") {
  438.  24879            bb_value = bb.value;
  439.  24879        } else if (bb.id === "`" && bb.constant) {
  440.   5856            bb_value = bb.value[0];
  441.  30735        }
  442.  30735        if (typeof aa_value === "string") {
  443.  22409            return aa_value === bb_value;
  444.  22409        }
  445.   8326        if (is_weird(aa) || is_weird(bb)) {
  446.     66
  447.     66// test_cause:
  448.     66// ["aa(/./)||{}", "is_equal", "false", "", 0]
  449.     66
  450.     66            test_cause("false");
  451.     66            return false;
  452.   8260        }
  453.   8260        if (aa.arity === bb.arity && aa.id === bb.id) {
  454.   2102            if (aa.id === ".") {
  455.   2102
  456.   2102// test_cause:
  457.   2102// ["aa.bb&&aa.bb", "is_equal", "recurse_arity_id", "", 0]
  458.   2102
  459.   2102                test_cause("recurse_arity_id");
  460.   2102                return (
  461.   2102                    is_equal(aa.expression, bb.expression)
  462.   2102                    && is_equal(aa.name, bb.name)
  463.   2102                );
  464.   2102            }
  465.   2102            if (aa.arity === "unary") {
  466.   2102
  467.   2102// test_cause:
  468.   2102// ["+0&&+0", "is_equal", "recurse_unary", "", 0]
  469.   2102
  470.   2102                test_cause("recurse_unary");
  471.   2102                return is_equal(aa.expression, bb.expression);
  472.   2102            }
  473.   2102            if (aa.arity === "binary") {
  474.   2102
  475.   2102// test_cause:
  476.   2102// ["aa[0]&&aa[0]", "is_equal", "recurse_binary", "", 0]
  477.   2102
  478.   2102                test_cause("recurse_binary");
  479.   2102                return (
  480.   2102                    aa.id !== "("
  481.   2102                    && is_equal(aa.expression[0], bb.expression[0])
  482.   2102                    && is_equal(aa.expression[1], bb.expression[1])
  483.   2102                );
  484.   2102            }
  485.   2102            if (aa.arity === "ternary") {
  486.   2102
  487.   2102// test_cause:
  488.   2102// ["aa=(``?``:``)&&(``?``:``)", "is_equal", "recurse_ternary", "", 0]
  489.   2102
  490.   2102                test_cause("recurse_ternary");
  491.   2102                return (
  492.   2102                    is_equal(aa.expression[0], bb.expression[0])
  493.   2102                    && is_equal(aa.expression[1], bb.expression[1])
  494.   2102                    && is_equal(aa.expression[2], bb.expression[2])
  495.   2102                );
  496.   2102            }
  497.   2102
  498.   2102// Probably deadcode.
  499.   2102// if (aa.arity === "function" || aa.arity === "regexp") {
  500.   2102//     return false;
  501.   2102// }
  502.   2102
  503.   2102            jslint_assert(
  504.   2102                !(aa.arity === "function" || aa.arity === "regexp"),
  505.   2102                `Expected !(aa.arity === "function" || aa.arity === "regexp").`
  506.   2102            );
  507.   2102
  508.   2102// test_cause:
  509.   2102// ["undefined&&undefined", "is_equal", "true", "", 0]
  510.   2102
  511.   2102            test_cause("true");
  512.   2102            return true;
  513.   6158        }
  514.   6158
  515.   6158// test_cause:
  516.   6158// ["null&&undefined", "is_equal", "false", "", 0]
  517.   6158
  518.   6158        test_cause("false");
  519.   6158        return false;
  520.   6158    }
  521.    628
  522.  28222    function is_weird(thing) {
  523.  28222        switch (thing.id) {
  524.     36        case "(regexp)":
  525.     36            return true;
  526.      1        case "=>":
  527.      1            return true;
  528.    536        case "[":
  529.    536            return thing.arity === "unary";
  530.     14        case "function":
  531.     14            return true;
  532.      7        case "{":
  533.      7            return true;
  534.  27628        default:
  535.  27628            return false;
  536.  28222        }
  537.  28222    }
  538.    628
  539.    111    function stop(code, the_token, a, b, c, d) {
  540.    111
  541.    111// Similar to warn and stop_at. If the token already had a warning, that
  542.    111// warning will be replaced with this new one. It is likely that the stopping
  543.    111// warning will be the more meaningful.
  544.    111
  545.     38        the_token = the_token || state.token_nxt;
  546.    111        delete the_token.warning;
  547.    111        throw warn(code, the_token, a, b, c, d);
  548.    111    }
  549.    628
  550.     28    function stop_at(code, line, column, a, b, c, d) {
  551.     28
  552.     28// Same as warn_at, except that it stops the analysis.
  553.     28
  554.     28        throw warn_at(code, line, column, a, b, c, d);
  555.     28    }
  556.    628
  557. 316290    function test_cause(code, aa, column) {
  558. 316290
  559. 316290// This function will instrument <cause> to <cause_dict> for test-purposes.
  560. 316290
  561.   4726        if (option_dict.test_cause) {
  562.   4726            cause_dict[JSON.stringify([
  563.   4726                String(new Error().stack).replace((
  564.   4726                    /^    at (?:file|stop|stop_at|test_cause|warn|warn_at)\b.*?\n/gm
  565.   4726                ), "").match(
  566.   4726                    /\n    at ((?:Object\.\w+?_)?\w+?) /
  567.   4726                )[1].replace((
  568.   4726                    /^Object\./
  569.   4726                ), ""),
  570.   4726                code,
  571.   4726                String(
  572.   4726                    (aa === undefined || aa === token_global)
  573.   4726                    ? ""
  574.   4726                    : aa
  575.   4726                ),
  576.   4726                column || 0
  577.   4726            ])] = true;
  578.   4726        }
  579. 316290    }
  580.    628
  581.   1063    function warn(code, the_token, a, b, c, d) {
  582.   1063
  583.   1063// Same as warn_at, except the warning will be associated with a specific token.
  584.   1063// If there is already a warning on this token, suppress the new one. It is
  585.   1063// likely that the first warning will be the most meaningful.
  586.   1063
  587.   1063        let the_warning;
  588.     18        the_token = the_token || state.token_nxt;
  589.   1063        the_warning = warn_at(
  590.   1063            code,
  591.   1063            the_token.line,
  592.    373            (the_token.from || 0) + jslint_fudge,
  593.    814            a || artifact(the_token),
  594.   1063            b,
  595.   1063            c,
  596.   1063            d
  597.   1063        );
  598.    880        if (the_token.warning === undefined) {
  599.    880            the_token.warning = the_warning;
  600.    880        } else {
  601.    183            warning_list.pop();
  602.    183        }
  603.   1063        return the_warning;
  604.   1063    }
  605.    628
  606.   1362    function warn_at(code, line, column, a, b, c, d) {
  607.   1362
  608.   1362// Report an error at some line and column of the program. The warning object
  609.   1362// resembles an exception.
  610.   1362
  611.   1362        let mm;
  612.   1362        let warning = Object.assign(empty(), {
  613.   1362            a,
  614.   1362            b,
  615.   1362            c,
  616.   1362            code,
  617.   1362
  618.   1362// Fudge column numbers in warning message.
  619.   1362
  620.     22            column: column || jslint_fudge,
  621.   1362            d,
  622.   1362            line,
  623.   1362            line_source: "",
  624.   1362            name: "JSLintError"
  625.   1362        }, line_list[line]);
  626.   1362        warning.column = Math.max(
  627.   1362            Math.min(warning.column, warning.line_source.length),
  628.   1362            jslint_fudge
  629.   1362        );
  630.    892        test_cause(code, b || a, warning.column);
  631.   1362        switch (code) {
  632.   1362
  633.   1362// The bundle contains the raw text messages that are generated by jslint. It
  634.   1362// seems that they are all error messages and warnings. There are no "Atta
  635.   1362// boy!" or "You are so awesome!" messages. There is no positive reinforcement
  636.   1362// or encouragement. This relentless negativity can undermine self-esteem and
  637.   1362// wound the inner child. But if you accept it as sound advice rather than as
  638.   1362// personal criticism, it can make your programs better.
  639.   1362
  640.      1        case "and":
  641.      1            mm = `The '&&' subexpression should be wrapped in parens.`;
  642.      1            break;
  643.     67        case "bad_assignment_a":
  644.     67            mm = `Bad assignment to '${a}'.`;
  645.     67            break;
  646.      1        case "bad_directive_a":
  647.      1            mm = `Bad directive '${a}'.`;
  648.      1            break;
  649.      1        case "bad_get":
  650.      1            mm = `A get function takes no parameters.`;
  651.      1            break;
  652.      1        case "bad_module_name_a":
  653.      1            mm = `Bad module name '${a}'.`;
  654.      1            break;
  655.      2        case "bad_option_a":
  656.      2            mm = `Bad option '${a}'.`;
  657.      2            break;
  658.      1        case "bad_set":
  659.      1            mm = `A set function takes one parameter.`;
  660.      1            break;
  661.      6        case "duplicate_a":
  662.      6            mm = `Duplicate '${a}'.`;
  663.      6            break;
  664.     67        case "empty_block":
  665.     67            mm = `Empty block.`;
  666.     67            break;
  667.      5        case "expected_a":
  668.      5            mm = `Expected '${a}'.`;
  669.      5            break;
  670.     25        case "expected_a_at_b_c":
  671.     25            mm = `Expected '${a}' at column ${b}, not column ${c}.`;
  672.     25            break;
  673.    284        case "expected_a_b":
  674.    284            mm = `Expected '${a}' and instead saw '${b}'.`;
  675.    284            break;
  676.     16        case "expected_a_b_before_c_d":
  677.     16            mm = `Expected ${a} '${b}' to be ordered before ${c} '${d}'.`;
  678.     16            break;
  679.      2        case "expected_a_b_from_c_d":
  680.      2            mm = (
  681.      2                `Expected '${a}' to match '${b}' from line ${c}`
  682.      2                + ` and instead saw '${d}'.`
  683.      2            );
  684.      2            break;
  685.     36        case "expected_a_before_b":
  686.     36            mm = `Expected '${a}' before '${b}'.`;
  687.     36            break;
  688.      1        case "expected_digits_after_a":
  689.      1            mm = `Expected digits after '${a}'.`;
  690.      1            break;
  691.      1        case "expected_four_digits":
  692.      1            mm = `Expected four digits after '\\u'.`;
  693.      1            break;
  694.     32        case "expected_identifier_a":
  695.     32            mm = `Expected an identifier and instead saw '${a}'.`;
  696.     32            break;
  697.      6        case "expected_line_break_a_b":
  698.      6            mm = `Expected a line break between '${a}' and '${b}'.`;
  699.      6            break;
  700.      3        case "expected_regexp_factor_a":
  701.      3            mm = `Expected a regexp factor and instead saw '${a}'.`;
  702.      3            break;
  703.     76        case "expected_space_a_b":
  704.     76            mm = `Expected one space between '${a}' and '${b}'.`;
  705.     76            break;
  706.      2        case "expected_statements_a":
  707.      2            mm = `Expected statements before '${a}'.`;
  708.      2            break;
  709.      1        case "expected_string_a":
  710.      1            mm = `Expected a string and instead saw '${a}'.`;
  711.      1            break;
  712.      1        case "expected_type_string_a":
  713.      1            mm = `Expected a type string and instead saw '${a}'.`;
  714.      1            break;
  715.      5        case "freeze_exports":
  716.      5            mm = (
  717.      5                `Expected 'Object.freeze('. All export values should be frozen.`
  718.      5            );
  719.      5            break;
  720.      2        case "function_in_loop":
  721.      2            mm = `Don't create functions within a loop.`;
  722.      2            break;
  723.      1        case "infix_in":
  724.      1            mm = (
  725.      1                `Unexpected 'in'. Compare with undefined,`
  726.      1                + ` or use the hasOwnProperty method instead.`
  727.      1            );
  728.      1            break;
  729.      1        case "label_a":
  730.      1            mm = `'${a}' is a statement label.`;
  731.      1            break;
  732.      1        case "misplaced_a":
  733.      1            mm = `Place '${a}' at the outermost level.`;
  734.      1            break;
  735.      1        case "misplaced_directive_a":
  736.      1            mm = `Place the '/*${a}*/' directive before the first statement.`;
  737.      1            break;
  738.      1        case "missing_await_statement":
  739.      1            mm = `Expected await statement in async function.`;
  740.      1            break;
  741.   1362
  742.   1362// PR-347 - Disable warning "missing_browser".
  743.   1362//         case "missing_browser":
  744.   1362//             mm = `/*global*/ requires the Assume a browser option.`;
  745.   1362//             break;
  746.   1362
  747.      1        case "missing_m":
  748.      1            mm = `Expected 'm' flag on a multiline regular expression.`;
  749.      1            break;
  750.      5        case "naked_block":
  751.      5            mm = `Naked block.`;
  752.      5            break;
  753.      2        case "nested_comment":
  754.      2            mm = `Nested comment.`;
  755.      2            break;
  756.      1        case "not_label_a":
  757.      1            mm = `'${a}' is not a label.`;
  758.      1            break;
  759.      2        case "number_isNaN":
  760.      2            mm = `Use Number.isNaN function to compare with NaN.`;
  761.      2            break;
  762.      4        case "out_of_scope_a":
  763.      4            mm = `'${a}' is out of scope.`;
  764.      4            break;
  765.     11        case "redefinition_a_b":
  766.     11            mm = `Redefinition of '${a}' from line ${b}.`;
  767.     11            break;
  768.      1        case "redefinition_global_a_b":
  769.      1            mm = `Redefinition of global ${a} variable '${b}'.`;
  770.      1            break;
  771.      6        case "required_a_optional_b":
  772.      6            mm = `Required parameter '${a}' after optional parameter '${b}'.`;
  773.      6            break;
  774.      1        case "reserved_a":
  775.      1            mm = `Reserved name '${a}'.`;
  776.      1            break;
  777.      1        case "subscript_a":
  778.      1            mm = `['${a}'] is better written in dot notation.`;
  779.      1            break;
  780.     16        case "todo_comment":
  781.     16            mm = `Unexpected TODO comment.`;
  782.     16            break;
  783.      8        case "too_long":
  784.      8            mm = `Line is longer than 80 characters.`;
  785.      8            break;
  786.      1        case "too_many_digits":
  787.      1            mm = `Too many digits.`;
  788.      1            break;
  789.      3        case "unclosed_comment":
  790.      3            mm = `Unclosed comment.`;
  791.      3            break;
  792.      3        case "unclosed_disable":
  793.      3            mm = (
  794.      3                `Directive '/*jslint-disable*/' was not closed`
  795.      3                + ` with '/*jslint-enable*/'.`
  796.      3            );
  797.      3            break;
  798.      3        case "unclosed_mega":
  799.      3            mm = `Unclosed mega literal.`;
  800.      3            break;
  801.      2        case "unclosed_string":
  802.      2            mm = `Unclosed string.`;
  803.      2            break;
  804.    126        case "undeclared_a":
  805.    126            mm = `Undeclared '${a}'.`;
  806.    126            break;
  807.    238        case "unexpected_a":
  808.    238            mm = `Unexpected '${a}'.`;
  809.    238            break;
  810.      1        case "unexpected_a_after_b":
  811.      1            mm = `Unexpected '${a}' after '${b}'.`;
  812.      1            break;
  813.      2        case "unexpected_a_before_b":
  814.      2            mm = `Unexpected '${a}' before '${b}'.`;
  815.      2            break;
  816.     36        case "unexpected_at_top_level_a":
  817.     36            mm = `Expected '${a}' to be in a function.`;
  818.     36            break;
  819.      1        case "unexpected_char_a":
  820.      1            mm = `Unexpected character '${a}'.`;
  821.      1            break;
  822.      2        case "unexpected_comment":
  823.      2            mm = `Unexpected comment.`;
  824.      2            break;
  825.   1362
  826.   1362// PR-347 - Disable warning "unexpected_directive_a".
  827.   1362//         case "unexpected_directive_a":
  828.   1362//             mm = `When using modules, don't use directive '/\u002a${a}'.`;
  829.   1362//             break;
  830.   1362
  831.    123        case "unexpected_expression_a":
  832.    123            mm = `Unexpected expression '${a}' in statement position.`;
  833.    123            break;
  834.      4        case "unexpected_label_a":
  835.      4            mm = `Unexpected label '${a}'.`;
  836.      4            break;
  837.      3        case "unexpected_parens":
  838.      3            mm = `Don't wrap function literals in parens.`;
  839.      3            break;
  840.      8        case "unexpected_space_a_b":
  841.      8            mm = `Unexpected space between '${a}' and '${b}'.`;
  842.      8            break;
  843.      1        case "unexpected_statement_a":
  844.      1            mm = `Unexpected statement '${a}' in expression position.`;
  845.      1            break;
  846.      2        case "unexpected_trailing_space":
  847.      2            mm = `Unexpected trailing space.`;
  848.      2            break;
  849.      1        case "unexpected_typeof_a":
  850.      1            mm = (
  851.      1                `Unexpected 'typeof'. Use '===' to compare directly with ${a}.`
  852.      1            );
  853.      1            break;
  854.      1        case "uninitialized_a":
  855.      1            mm = `Uninitialized '${a}'.`;
  856.      1            break;
  857.      1        case "unopened_enable":
  858.      1            mm = (
  859.      1                `Directive '/*jslint-enable*/' was not opened`
  860.      1                + ` with '/*jslint-disable*/'.`
  861.      1            );
  862.      1            break;
  863.      1        case "unreachable_a":
  864.      1            mm = `Unreachable '${a}'.`;
  865.      1            break;
  866.      1        case "unregistered_property_a":
  867.      1            mm = `Unregistered property name '${a}'.`;
  868.      1            break;
  869.      6        case "unused_a":
  870.      6            mm = `Unused '${a}'.`;
  871.      6            break;
  872.      2        case "use_double":
  873.      2            mm = `Use double quotes, not single quotes.`;
  874.      2            break;
  875.      7        case "use_open":
  876.      7            mm = (
  877.      7                `Wrap a ternary expression in parens,`
  878.      7                + ` with a line break after the left paren.`
  879.      7            );
  880.      7            break;
  881.      1        case "use_spaces":
  882.      1            mm = `Use spaces, not tabs.`;
  883.      1            break;
  884.      5        case "var_on_top":
  885.      5            mm = `Move variable declaration to top of function or script.`;
  886.      5            break;
  887.      1        case "var_switch":
  888.      1            mm = `Don't declare variables in a switch.`;
  889.      1            break;
  890.     21        case "weird_condition_a":
  891.     21            mm = `Weird condition '${a}'.`;
  892.     21            break;
  893.      5        case "weird_expression_a":
  894.      5            mm = `Weird expression '${a}'.`;
  895.      5            break;
  896.      3        case "weird_loop":
  897.      3            mm = `Weird loop.`;
  898.      3            break;
  899.      8        case "weird_property_a":
  900.      8            mm = `Weird property name '${a}'.`;
  901.      8            break;
  902.      8        case "weird_relation_a":
  903.      8            mm = `Weird relation '${a}'.`;
  904.      8            break;
  905.      1        case "wrap_condition":
  906.      1            mm = `Wrap the condition in parens.`;
  907.      1            break;
  908.      1        case "wrap_immediate":
  909.      1            mm = (
  910.      1                `Wrap an immediate function invocation in parentheses to assist`
  911.      1                + ` the reader in understanding that the expression is the`
  912.      1                + ` result of a function, and not the function itself.`
  913.      1            );
  914.      1            break;
  915.      1        case "wrap_parameter":
  916.      1            mm = `Wrap the parameter in parens.`;
  917.      1            break;
  918.     18        case "wrap_regexp":
  919.     18            mm = `Wrap this regexp in parens to avoid confusion.`;
  920.     18            break;
  921.      1        case "wrap_unary":
  922.      1            mm = `Wrap the unary expression in parens.`;
  923.      1            break;
  924.   1362        }
  925.   1362
  926.   1362// Validate mm.
  927.   1362
  928.   1362        jslint_assert(mm, code);
  929.   1362        warning.message = mm;
  930.   1362
  931.   1362// PR-242 - Include stack_trace for jslint to debug itself for errors.
  932.   1362
  933.      6        if (option_dict.trace) {
  934.      6            warning.stack_trace = new Error().stack;
  935.      6        }
  936.     30        if (warning.directive_quiet) {
  937.     30
  938.     30// test_cause:
  939.     30// ["0 //jslint-quiet", "semicolon", "directive_quiet", "", 0]
  940.     30
  941.     30            test_cause("directive_quiet");
  942.     30            return warning;
  943.   1332        }
  944.   1332        warning_list.push(warning);
  945.   1332        return warning;
  946.   1332    }
  947.    628
  948.    628    try {
  949.    628
  950.    628// tokenize takes a source and produces from it an array of token objects.
  951.    628// JavaScript is notoriously difficult to tokenize because of the horrible
  952.    628// interactions between automatic semicolon insertion, regular expression
  953.    628// literals, and now megastring literals. JSLint benefits from eliminating
  954.    628// automatic semicolon insertion and nested megastring literals, which allows
  955.    628// full tokenization to precede parsing.
  956.    628
  957.    628        option_dict = Object.assign(empty(), option_dict);
  958.    628        Object.assign(state, {
  959.    628            artifact,
  960.    628            catch_list,
  961.    628            catch_stack,
  962.    628            directive_list,
  963.    628            export_dict,
  964.    628            function_list,
  965.    628            function_stack,
  966.    628            global_dict,
  967.    628            global_list,
  968.    628            import_list,
  969.    628            is_equal,
  970.    628            is_weird,
  971.    628            line_list,
  972.    628            mode_json: false,           // true if parsing JSON.
  973.    628            mode_module: false,         // true if import or export was used.
  974.    628            mode_property: false,       // true if directive /*property*/ is
  975.    628                                        // used.
  976.    628            mode_shebang: false,        // true if #! is seen on the first line.
  977.    628            option_dict,
  978.    628            property_dict,
  979.    628            source,
  980.    628            stop,
  981.    628            stop_at,
  982.    628            syntax_dict,
  983.    628            tenure,
  984.    628            test_cause,
  985.    628            token_global,
  986.    628            token_list,
  987.    628            token_nxt: token_global,
  988.    628            warn,
  989.    628            warn_at,
  990.    628            warning_list
  991.    628        });
  992.    628
  993.    628// PHASE 1. Split <source> by newlines into <line_list>.
  994.    628
  995.    628        jslint_phase1_split(state);
  996.    628        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
  997.    628        jslint_assert(
  998.    628            function_stack.length === 0,
  999.    628            `function_stack.length === 0.`
 1000.    628        );
 1001.    628
 1002.    628// PHASE 2. Lex <line_list> into <token_list>.
 1003.    628
 1004.    628        jslint_phase2_lex(state);
 1005.    628        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1006.    628        jslint_assert(
 1007.    628            function_stack.length === 0,
 1008.    628            `function_stack.length === 0.`
 1009.    628        );
 1010.    628
 1011.    628// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
 1012.    628
 1013.    628        jslint_phase3_parse(state);
 1014.    628        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1015.    628        jslint_assert(
 1016.    628            function_stack.length === 0,
 1017.    628            `function_stack.length === 0.`
 1018.    628        );
 1019.    628
 1020.    628// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
 1021.    628//          recursive traversal. Each node may be processed on the way down
 1022.    628//          (preaction) and on the way up (postaction).
 1023.    628
 1024.    473        if (!state.mode_json) {
 1025.    473            jslint_phase4_walk(state);
 1026.    488        }
 1027.    488        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1028.    488        jslint_assert(
 1029.    488            function_stack.length === 0,
 1030.    488            `function_stack.length === 0.`
 1031.    488        );
 1032.    488
 1033.    488// PHASE 5. Check whitespace between tokens in <token_list>.
 1034.    488
 1035.    488        if (!state.mode_json && warning_list.length === 0) {
 1036.    176            jslint_phase5_whitage(state);
 1037.    488        }
 1038.    488        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1039.    488        jslint_assert(
 1040.    488            function_stack.length === 0,
 1041.    488            `function_stack.length === 0.`
 1042.    488        );
 1043.    488
 1044.    488// PR-347 - Disable warning "missing_browser".
 1045.    488//         if (!option_dict.browser) {
 1046.    488//             directive_list.forEach(function (comment) {
 1047.    488//                 if (comment.directive === "global") {
 1048.    488//
 1049.    488// // test_cause:
 1050.    488// // ["/*global aa*/", "jslint", "missing_browser", "(comment)", 1]
 1051.    488//
 1052.    488//                     warn("missing_browser", comment);
 1053.    488//                 }
 1054.    488//             });
 1055.    488//         }
 1056.    488
 1057.    488        if (option_dict.test_internal_error) {
 1058.      1            jslint_assert(undefined, "test_internal_error");
 1059.      1        }
 1060.    141    } catch (err) {
 1061.    141        mode_stop = true;
 1062.    141        err.message = "[JSLint was unable to finish] " + err.message;
 1063.    141        err.mode_stop = true;
 1064.    141        if (err.name !== "JSLintError") {
 1065.    141            Object.assign(err, {
 1066.    141                column: jslint_fudge,
 1067.    141                line: jslint_fudge,
 1068.    141                line_source: "",
 1069.    141                stack_trace: err.stack
 1070.    141            });
 1071.    141        }
 1072.    141        if (warning_list.indexOf(err) === -1) {
 1073.    141            warning_list.push(err);
 1074.    141        }
 1075.    141    }
 1076.    628
 1077.    628// Sort warning_list by mode_stop first, line, column respectively.
 1078.    628
 1079.    973    warning_list.sort(function (aa, bb) {
 1080.    973        return (
 1081.    973            Boolean(bb.mode_stop) - Boolean(aa.mode_stop)
 1082.    878            || aa.line - bb.line
 1083.    857            || aa.column - bb.column
 1084.    973        );
 1085.    973
 1086.    973// Update each warning with formatted_message ready-for-use by jslint_cli.
 1087.    973
 1088.   1151    }).map(function ({
 1089.   1151        column,
 1090.   1151        line,
 1091.   1151        line_source,
 1092.   1151        message,
 1093.   1151        stack_trace = ""
 1094.   1151    }, ii, list) {
 1095.   1151        list[ii].formatted_message = String(
 1096.   1151            String(ii + 1).padStart(2, " ")
 1097.   1151            + ". \u001b[31m" + message + "\u001b[39m"
 1098.   1151            + " \u001b[90m\/\/ line " + line + ", column " + column
 1099.   1151            + "\u001b[39m\n"
 1100.   1151            + ("    " + line_source.trim()).slice(0, 72) + "\n"
 1101.   1151            + stack_trace
 1102.   1151        ).trimRight();
 1103.   1151    });
 1104.    628
 1105.    628    return {
 1106.    628        causes: cause_dict,
 1107.    628        directives: directive_list,
 1108.    628        edition: jslint_edition,
 1109.    628        exports: export_dict,
 1110.    628        froms: import_list,
 1111.    628        functions: function_list,
 1112.    628        global: token_global,
 1113.    628        id: "(JSLint)",
 1114.    628        json: state.mode_json,
 1115.    628        lines: line_list,
 1116.    628        module: state.mode_module === true,
 1117.    133        ok: warning_list.length === 0 && !mode_stop,
 1118.    628        option: option_dict,
 1119.    628        property: property_dict,
 1120.    628        shebang: (
 1121.    628            state.mode_shebang
 1122.      2            ? line_list[jslint_fudge].line_source
 1123.    626            : undefined
 1124.    628        ),
 1125.    628        stop: mode_stop,
 1126.    628        tokens: token_list,
 1127.    628        tree: state.token_tree,
 1128.    628        warnings: warning_list
 1129.    628    };
 1130.    628}
 1131.      1
 1132.      1// PR-362 - Add API Doc.
 1133.      1
 1134.      1async function jslint_apidoc({
 1135.      1    example_list,
 1136.      1    github_repo,
 1137.      1    module_list,
 1138.      1    package_name,
 1139.      1    pathname,
 1140.      1    version
 1141.      1}) {
 1142.      1
 1143.      1// This function will create API Doc from <module_list>.
 1144.      1
 1145.      1    let elem_ii = 0;
 1146.      1    let html;
 1147.      1
 1148.     26    function elem_create(moduleObj, key, moduleName) {
 1149.     26
 1150.     26// This function will create a sub API Doc from elem <moduleObj>[<key>].
 1151.     26
 1152.     26        let example = "N/A";
 1153.     26        let id = encodeURIComponent("apidoc.elem." + moduleName + "." + key);
 1154.     26        let name;
 1155.     26        let signature;
 1156.     26        let source;
 1157.     26        name = htmlEscape((typeof moduleObj[key]) + " " + key);
 1158.      2        if (typeof moduleObj[key] !== "function") {
 1159.      2            return {
 1160.      2                name,
 1161.      2                signature: (`
 1162.      2<a class="apidocElementLiA" href="#${id}">
 1163.      2${name}
 1164.      2</a>
 1165.      2                `),
 1166.      2                source: (`
 1167.      2<li>
 1168.      2    <h2>
 1169.      2    <a href="#${id}" id="${id}">
 1170.      2    ${name}
 1171.      2    </a>
 1172.      2    </h2>
 1173.      2</li>
 1174.      2                `)
 1175.      2            };
 1176.     24        }
 1177.     24        // init source
 1178.     24        source = htmlEscape(trim_start(moduleObj[key].toString()));
 1179.     24        // init signature
 1180.     24        source = source.replace((
 1181.     24            /(\([\S\s]*?\)) \{/
 1182.     24        ), function (match0, match1) {
 1183.     24            signature = htmlEscape(
 1184.     24                match1.replace((
 1185.     24                    / *?\/\*[\S\s]*?\*\/ */g
 1186.     24                ), "").replace((
 1187.     24                    / *?\/\/.*/g
 1188.     24                ), "").replace((
 1189.     24                    /\n{2,}/g
 1190.     24                ), "\n")
 1191.     24            );
 1192.     24            return match0;
 1193.     24        });
 1194.     24        // init comment
 1195.     24        source = source.replace((
 1196.     24            /\n(?:\/\/.*?\n)+\n/
 1197.     24        ), "<span class=\"apidocCodeCommentSpan\">$&</span>");
 1198.     24        // init example
 1199.     58        example_list.some(function (example2) {
 1200.     58            example2.replace(
 1201.     58                new RegExp((
 1202.     58                    "((?:\\n.*?){8}(function )?)\\b"
 1203.     58                    + key
 1204.     58                    + "(\\((?:.*?\\n){8})"
 1205.     58                ), "g"),
 1206.    100                function (ignore, header, isDeclaration, footer) {
 1207.     90                    if (!isDeclaration) {
 1208.     90                        example = "..." + trim_start(
 1209.     90                            htmlEscape(header)
 1210.     90                            + "<span class=\"apidocCodeKeywordSpan\">"
 1211.     90                            + htmlEscape(key)
 1212.     90                            + "</span>"
 1213.     90                            + htmlEscape(footer)
 1214.     90                        ).trimEnd() + "\n...";
 1215.     90                    }
 1216.    100                    return "";
 1217.    100                }
 1218.     58            );
 1219.     58            return example !== "N/A";
 1220.     58        });
 1221.     24        if (source.length > 2048) {
 1222.     10            source = source.slice(0, 2048) + "...\n}\n";
 1223.     24        }
 1224.     24        return {
 1225.     24            name,
 1226.     24            signature: (`
 1227.     24<a class="apidocElementLiA" href="#${id}">
 1228.     24${name}<span class="apidocSignatureSpan">${signature}</span>
 1229.     24</a>
 1230.     24            `),
 1231.     24            source: (`
 1232.     24<li>
 1233.     24    <h2>
 1234.     24    <a href="#${id}" id="${id}">
 1235.     24    ${name}<span class="apidocSignatureSpan">${signature}</span>
 1236.     24    </a>
 1237.     24    </h2>
 1238.     24</li>
 1239.     24<li>Description and source-code:<pre class="apidocCodePre">${source}</pre></li>
 1240.     24<li>Example usage:<pre class="apidocCodePre">${example}</pre></li>
 1241.     24            `)
 1242.     24        };
 1243.     24    }
 1244.      1
 1245.    114    function trim_start(str) {
 1246.    114
 1247.    114// This function will normalize whitespace before <str>.
 1248.    114
 1249.    114        let whitespace = "";
 1250.    114        str.trim().replace((
 1251.    114            /^ */gm
 1252.  11961        ), function (match0) {
 1253.   7759            if (whitespace === "" || match0.length < whitespace.length) {
 1254.   5982                whitespace = match0;
 1255.   5982            }
 1256.  11961            return "";
 1257.  11961        });
 1258.    114        str = str.replace(new RegExp("^" + whitespace, "gm"), "");
 1259.    114        return str;
 1260.    114    }
 1261.      1    await moduleFsInit();
 1262.      1
 1263.      1// Html-escape params.
 1264.      1
 1265.      1    github_repo = htmlEscape(github_repo);
 1266.      1    package_name = htmlEscape(package_name);
 1267.      1    version = htmlEscape(version);
 1268.      1
 1269.      1// Init example_list.
 1270.      1
 1271.      3    example_list = await Promise.all(example_list.map(async function (file) {
 1272.      3
 1273.      3// This function will read example from given file.
 1274.      3
 1275.      3        let result = await moduleFs.promises.readFile(file, "utf8");
 1276.      3        result = (
 1277.      3            "\n\n\n\n\n\n\n\n"
 1278.      3            // bug-workaround - truncate example to manageable size
 1279.      3            + result.slice(0, 524288)
 1280.      3            + "\n\n\n\n\n\n\n\n"
 1281.      3        );
 1282.      3        result = result.replace((
 1283.      3            /\r\n*/g
 1284.      3        ), "\n");
 1285.      3        return result;
 1286.      3    }));
 1287.      1    // init module_list
 1288.      1    module_list = await Promise.all(module_list.map(async function ({
 1289.      1        pathname
 1290.      1    }) {
 1291.      1        let moduleName = htmlEscape(JSON.stringify(pathname));
 1292.      1        let moduleObj = await import(pathname);
 1293.      1        if (moduleObj.default) {
 1294.      1            moduleObj = moduleObj.default;
 1295.      1        }
 1296.      1        return {
 1297.     26            elem_list: Object.keys(moduleObj).map(function (key) {
 1298.     26                return elem_create(moduleObj, key, moduleName);
 1299.     73            }).sort(function (aa, bb) {
 1300.     73                return (
 1301.     73                    aa.name < bb.name
 1302.     20                    ? -1
 1303.     53                    : 1
 1304.     73                );
 1305.     26            }).map(function (elem) {
 1306.     26                elem_ii += 1;
 1307.     26                elem.signature = elem.signature.replace(
 1308.     26                    ">",
 1309.     26                    ">" + elem_ii + ". "
 1310.     26                );
 1311.     26                elem.source = elem.source.replace(
 1312.     26                    "\">",
 1313.     26                    "\">" + elem_ii + ". "
 1314.     26                );
 1315.     26                return elem;
 1316.     26            }),
 1317.      1            id: encodeURIComponent("apidoc.module." + moduleName),
 1318.      1            moduleName
 1319.      1        };
 1320.      1    }));
 1321.      1    html = (`
 1322.      1<!DOCTYPE html>
 1323.      1<html lang="en">
 1324.      1<head>
 1325.      1<meta charset="utf-8">
 1326.      1<meta name="viewport" content="width=device-width, initial-scale=1">
 1327.      1<meta name="description" content="${package_name} API Doc">
 1328.      1<title>${package_name} apidoc</title>
 1329.      1<style>
 1330.      1/* jslint utility2:true */
 1331.      1/*csslint*/
 1332.      1body {
 1333.      1    margin: 0;
 1334.      1    padding: 20px;
 1335.      1}
 1336.      1.apidocCodeCommentSpan,
 1337.      1.apidocCodeKeywordSpan {
 1338.      1    background: royalblue;
 1339.      1    color: white;
 1340.      1}
 1341.      1.apidocCodeCommentSpan {
 1342.      1    display: block;
 1343.      1}
 1344.      1.apidocCodePre {
 1345.      1    background: #eef;
 1346.      1    border: 1px solid;
 1347.      1    font-size: 14px;
 1348.      1    overflow-wrap: break-word;
 1349.      1    padding: 5px;
 1350.      1    white-space: pre-wrap;
 1351.      1}
 1352.      1.apidocDiv {
 1353.      1    color: #555;
 1354.      1    font-family: sans-serif;
 1355.      1}
 1356.      1.apidocDiv a[href] {
 1357.      1    color: royalblue;
 1358.      1    text-decoration: none;
 1359.      1}
 1360.      1.apidocDiv a[href]:hover {
 1361.      1    text-decoration: underline;
 1362.      1}
 1363.      1.apidocDiv li a {
 1364.      1    display: inline-block;
 1365.      1    padding: 8px 0;
 1366.      1}
 1367.      1.apidocDiv ul {
 1368.      1    list-style: none;
 1369.      1    padding-left: 20px;
 1370.      1}
 1371.      1.apidocFooterDiv {
 1372.      1    margin-top: 20px;
 1373.      1    text-align: center;
 1374.      1}
 1375.      1.apidocModuleA {
 1376.      1    font-size: 24px;
 1377.      1    font-weight: bold;
 1378.      1}
 1379.      1.apidocSectionDiv {
 1380.      1    border-top: 1px solid;
 1381.      1    margin-top: 20px;
 1382.      1}
 1383.      1.apidocSignatureSpan {
 1384.      1    color: #666;
 1385.      1    white-space: pre-wrap;
 1386.      1}
 1387.      1</style>
 1388.      1</head>
 1389.      1<body>
 1390.      1<div class="apidocDiv">
 1391.      1<h1>API Doc for <a href="${github_repo}">${package_name} (${version})</a></h1>
 1392.      1<div class="apidocSectionDiv">
 1393.      1    <a href="#apidocTableOfContents1" id="apidocTableOfContents1">
 1394.      1        <h1>Table of Contents</h1>
 1395.      1    </a>
 1396.      1    <ul>
 1397.      1    `) + module_list.map(function ({
 1398.      1        elem_list,
 1399.      1        id,
 1400.      1        moduleName
 1401.      1    }) {
 1402.      1        return (
 1403.      1            (`
 1404.      1        <li>
 1405.      1            <a class="apidocModuleA" href="#${id}">Module ${moduleName}</a>
 1406.      1            <ul>
 1407.      1            `)
 1408.     26            + elem_list.map(function ({
 1409.     26                signature
 1410.     26            }) {
 1411.     26                return "<li>\n" + signature + "\n</li>\n";
 1412.     26            }).join("")
 1413.      1            + (`
 1414.      1            </ul>
 1415.      1        </li>
 1416.      1            `)
 1417.      1        );
 1418.      1    }).join("") + (`
 1419.      1    </ul>
 1420.      1</div>
 1421.      1    `) + module_list.map(function ({
 1422.      1        elem_list,
 1423.      1        id,
 1424.      1        moduleName
 1425.      1    }) {
 1426.      1        return (
 1427.      1            (`
 1428.      1<div class="apidocSectionDiv">
 1429.      1    <h1><a href="#${id}" id="${id}">Module ${moduleName}</a></h1>
 1430.      1    <ul>
 1431.      1            `)
 1432.     26            + elem_list.map(function ({
 1433.     26                source
 1434.     26            }) {
 1435.     26                return source;
 1436.     26            }).join("")
 1437.      1            + (`
 1438.      1    </ul>
 1439.      1</div>
 1440.      1            `)
 1441.      1        );
 1442.      1    }).join("") + (`
 1443.      1<div class="apidocFooterDiv">
 1444.      1    [
 1445.      1    This document was created with
 1446.      1    <a href="https://github.com/jslint-org/jslint">JSLint</a>
 1447.      1    ]
 1448.      1</div>
 1449.      1</div>
 1450.      1</body>
 1451.      1</html>
 1452.      1    `);
 1453.      1    html = html.trim().replace((
 1454.      1        / +?$/gm
 1455.      1    ), "") + "\n";
 1456.      1    await fsWriteFileWithParents(pathname, html);
 1457.      1}
 1458.      1
 1459.  97663function jslint_assert(condition, message) {
 1460.  97663
 1461.  97663// This function will throw <message> if <condition> is falsy.
 1462.  97663
 1463.  97662    if (condition) {
 1464.  97662        return condition;
 1465.  97662    }
 1466.      1    throw new Error(
 1467.      1        `This was caused by a bug in JSLint.
 1468.      1Please open an issue with this stack-trace (and possible example-code) at
 1469.      1https://github.com/jslint-org/jslint/issues.
 1470.      1edition = "${jslint_edition}";
 1471.      1${String(message).slice(0, 2000)}`
 1472.      1    );
 1473.      1}
 1474.      1
 1475.     21async function jslint_cli({
 1476.     21    cjs_module,
 1477.     21    cjs_require,
 1478.     21    console_error,
 1479.     21    console_log,
 1480.     21    file,
 1481.     21    mode_cli,
 1482.     21    mode_noop,
 1483.     21    option,
 1484.     21    processArgv,
 1485.     21    processEnv,
 1486.     21    process_exit,
 1487.     21    source
 1488.     21}) {
 1489.     21
 1490.     21// This function will run jslint from nodejs-cli.
 1491.     21
 1492.     21    let command;
 1493.     21    let data;
 1494.     21    let exit_code = 0;
 1495.     21    let mode_plugin_vim;
 1496.     21    let mode_report;
 1497.     21    let result;
 1498.     21
 1499.     32    function jslint_from_file({
 1500.     32        code,
 1501.     32        file,
 1502.     32        line_offset = 0,
 1503.     32        option = empty()
 1504.     32    }) {
 1505.     32        let result_from_file;
 1506.     32        option = Object.assign(empty(), option, {
 1507.     32            file
 1508.     32        });
 1509.     32        switch ((
 1510.     32            /\.\w+?$|$/m
 1511.     32        ).exec(file)[0]) {
 1512.      0        case ".html":
 1513.      0
 1514.      0// Recursively jslint embedded "<script>\n...\n</script>".
 1515.      0
 1516.      0            code.replace((
 1517.      0                /^<script\b[^>]*?>\n([\S\s]*?\n)<\/script>$/gm
 1518.      0            ), function (ignore, match1, ii) {
 1519.      0                jslint_from_file({
 1520.      0                    code: match1,
 1521.      0                    file: file + ".<script>.js",
 1522.      0                    line_offset: string_line_count(code.slice(0, ii)) + 1,
 1523.      0                    option: Object.assign(empty(), {
 1524.      0                        browser: true
 1525.      0                    }, option)
 1526.      0                });
 1527.      0                return "";
 1528.      0            });
 1529.      0            return;
 1530.      2        case ".sh":
 1531.      2
 1532.      2// Recursively jslint embedded "node -e '\n...\n'".
 1533.      2
 1534.      2            code.replace((
 1535.      2                /\bnode\b.*? -e '\n([\S\s]*?\n)'/gm
 1536.     16            ), function (ignore, match1, ii) {
 1537.     16                jslint_from_file({
 1538.     16                    code: match1,
 1539.     16                    file: file + ".<node -e>.js",
 1540.     16                    line_offset: string_line_count(code.slice(0, ii)) + 1,
 1541.     16                    option: Object.assign(empty(), {
 1542.     16                        beta: Boolean(
 1543.     16                            processEnv.JSLINT_BETA
 1544.     16                            && !(
 1545.     16                                /0|false|null|undefined/
 1546.     16                            ).test(processEnv.JSLINT_BETA)
 1547.     16                        ),
 1548.     16                        node: true
 1549.     16                    }, option)
 1550.     16                });
 1551.     16                return "";
 1552.     16            });
 1553.      2            return;
 1554.     30        default:
 1555.     30            result_from_file = jslint("\n".repeat(line_offset) + code, option);
 1556.     30        }
 1557.     30
 1558.     30// Print only first 10 warnings to stderr.
 1559.     30
 1560.     30        if (result_from_file.warnings.length > 0) {
 1561.      5            exit_code = 1;
 1562.      5            console_error(
 1563.      5                mode_plugin_vim
 1564.      5
 1565.      5// PR-349 - Print warnings in format readable by vim.
 1566.      5
 1567.      5                ? result_from_file.warnings.slice(0, 10).map(function ({
 1568.      5                    column,
 1569.      5                    line,
 1570.      5                    message
 1571.      5                }, ii) {
 1572.      5                    return (
 1573.      5                        file
 1574.      5                        + ":" + ii
 1575.      5                        + ":" + line
 1576.      5                        + ":" + column
 1577.      5                        + ":" + message
 1578.      5                    );
 1579.      5                }).join("\n")
 1580.      5
 1581.      5// Print warnings in format readable by human.
 1582.      5
 1583.      5                : "\u001b[1mjslint " + file + "\u001b[22m\n"
 1584.     11                + result_from_file.warnings.slice(0, 10).map(function ({
 1585.     11                    formatted_message
 1586.     11                }) {
 1587.     11                    return formatted_message;
 1588.     11                }).join("\n")
 1589.      5            );
 1590.     30        }
 1591.     30        return result_from_file;
 1592.     30    }
 1593.     21
 1594.     16    function string_line_count(code) {
 1595.     16
 1596.     16// This function will count number of newlines in <code>.
 1597.     16
 1598.     16        let count;
 1599.     16        let ii;
 1600.     16
 1601.     16// https://jsperf.com/regexp-counting-2/8
 1602.     16
 1603.     16        count = 0;
 1604.     16        ii = 0;
 1605.  11345        while (true) {
 1606.  11345            ii = code.indexOf("\n", ii) + 1;
 1607.  11345            if (ii === 0) {
 1608.  11345                break;
 1609.  11345            }
 1610.  11345            count += 1;
 1611.  11345        }
 1612.     16        return count;
 1613.     16    }
 1614.     21
 1615.     21// Feature-detect nodejs.
 1616.     21
 1617.     21    if (!(
 1618.     21        typeof process === "object"
 1619.     21        && process
 1620.     21        && process.versions
 1621.     21        && typeof process.versions.node === "string"
 1622.     21        && !mode_noop
 1623.      1    )) {
 1624.      1        return exit_code;
 1625.     20    }
 1626.     20    console_error = console_error || console.error;
 1627.     20    console_log = console_log || console.log;
 1628.      7    processArgv = processArgv || process.argv;
 1629.     17    processEnv = processEnv || process.env;
 1630.      7    process_exit = process_exit || process.exit;
 1631.     20    await moduleFsInit();
 1632.     20    if (!(
 1633.     20
 1634.     20// Feature-detect nodejs-cjs-cli.
 1635.     20
 1636.     20        (cjs_module && cjs_require)
 1637.      1        ? cjs_module === cjs_require.main
 1638.     21
 1639.     21// Feature-detect nodejs-esm-cli.
 1640.     21
 1641.     19        : (
 1642.     19            process.execArgv.indexOf("--eval") === -1
 1643.     19            && process.execArgv.indexOf("-e") === -1
 1644.     19            && (
 1645.     19                (
 1646.     19                    /[\/|\\]jslint(?:\.[cm]?js)?$/m
 1647.     19                ).test(processArgv[1])
 1648.     19                || mode_cli
 1649.     19            )
 1650.     19            && moduleUrl.fileURLToPath(jslint_import_meta_url) ===
 1651.     19            modulePath.resolve(processArgv[1])
 1652.     19        )
 1653.      7    ) && !mode_cli) {
 1654.      2        return exit_code;
 1655.     18    }
 1656.     18
 1657.     18// init commmand
 1658.     18
 1659.     18    command = String(processArgv[2]).split("=");
 1660.     18    command[1] = command.slice(1).join("=");
 1661.     18
 1662.     18    switch (command[0]) {
 1663.     18
 1664.     18// PR-362 - Add API Doc.
 1665.     18
 1666.     18    case "jslint_apidoc":
 1667.      1        await jslint_apidoc(Object.assign(JSON.parse(processArgv[3]), {
 1668.      1            pathname: command[1]
 1669.      1        }));
 1670.      1        return;
 1671.     21
 1672.     21// COMMIT-b26d6df2 - Add command jslint_plugin_vim.
 1673.     21
 1674.      1    case "jslint_plugin_vim":
 1675.      1        mode_plugin_vim = true;
 1676.      1        processArgv = processArgv.slice(1);
 1677.      1        break;
 1678.     21
 1679.     21// PR-363 - Add command jslint_report.
 1680.     21
 1681.      5    case "jslint_report":
 1682.      5        mode_report = command[1];
 1683.      5        processArgv = processArgv.slice(1);
 1684.      5        break;
 1685.     21
 1686.     21// PR-364 - Add command v8_coverage_report.
 1687.     21
 1688.      6    case "v8_coverage_report":
 1689.      6        await v8CoverageReportCreate({
 1690.      6            coverageDir: command[1],
 1691.      6            processArgv: processArgv.slice(3)
 1692.      6        });
 1693.      6        return;
 1694.     11    }
 1695.     11
 1696.     11// PR-349 - Detect cli-option --mode-vim-plugin.
 1697.     11
 1698.     11    mode_plugin_vim = (
 1699.     11        processArgv.slice(2).indexOf("--mode-vim-plugin") >= 0
 1700.     11        || mode_plugin_vim
 1701.     21    );
 1702.     21
 1703.     21// Normalize file relative to process.cwd().
 1704.     21
 1705.      6    processArgv.slice(2).some(function (arg) {
 1706.      6        if (!arg.startsWith("-")) {
 1707.      6            file = file || arg;
 1708.      6            return true;
 1709.      6        }
 1710.      6    });
 1711.      1    if (!file) {
 1712.      1        return;
 1713.     10    }
 1714.     10    file = modulePath.resolve(file) + "/";
 1715.     10    if (file.startsWith(process.cwd() + "/")) {
 1716.     10        file = file.replace(process.cwd() + "/", "").slice(0, -1) || ".";
 1717.     10    }
 1718.     10    file = file.replace((
 1719.     10        /\\/g
 1720.     10    ), "/").replace((
 1721.     10        /\/$/g
 1722.     10    ), "");
 1723.     10    if (source) {
 1724.      6        data = source;
 1725.      6    } else {
 1726.      4
 1727.      4// jslint_cli - jslint directory.
 1728.      4
 1729.      4        try {
 1730.      4            data = await moduleFs.promises.readdir(file, "utf8");
 1731.      4        } catch (ignore) {}
 1732.      4        if (data) {
 1733.     17            await Promise.all(data.map(async function (file2) {
 1734.     17                let code;
 1735.     17                let time_start = Date.now();
 1736.     17                file2 = file + "/" + file2;
 1737.     17                switch ((
 1738.     17                    /\.\w+?$|$/m
 1739.     17                ).exec(file2)[0]) {
 1740.      0                case ".cjs":
 1741.      0                case ".html":
 1742.      0                case ".js":
 1743.      4                case ".json":
 1744.      6                case ".mjs":
 1745.      8                case ".sh":
 1746.      8                    break;
 1747.      9                default:
 1748.      9                    return;
 1749.      8                }
 1750.      8                try {
 1751.      8                    code = await moduleFs.promises.readFile(file2, "utf8");
 1752.      0                } catch (ignore) {
 1753.      0                    return;
 1754.      0                }
 1755.      8                if (!(
 1756.      8                    !(
 1757.      8                        /(?:\b|_)(?:lock|min|raw|rollup)(?:\b|_)/
 1758.      8                    ).test(file2) && code && code.length < 1048576
 1759.      0                )) {
 1760.      0                    return;
 1761.      0                }
 1762.      8                jslint_from_file({
 1763.      8                    code,
 1764.      8                    file: file2,
 1765.      8                    option
 1766.      8                });
 1767.      8                console_error(
 1768.      8                    "jslint - " + (Date.now() - time_start) + "ms - " + file2
 1769.      8                );
 1770.      8            }));
 1771.      4            process_exit(exit_code);
 1772.      4            return exit_code;
 1773.      4        }
 1774.      4
 1775.      4// jslint_cli - jslint file.
 1776.      4
 1777.      4        try {
 1778.      4            data = await moduleFs.promises.readFile(file, "utf8");
 1779.      4        } catch (err) {
 1780.      4            console_error(err);
 1781.      4            exit_code = 1;
 1782.      4            process_exit(exit_code);
 1783.      4            return exit_code;
 1784.      4        }
 1785.      8    }
 1786.      8    result = jslint_from_file({
 1787.      8        code: data,
 1788.      8        file,
 1789.      8        option
 1790.      8    });
 1791.      8    if (mode_report) {
 1792.      5        await fsWriteFileWithParents(mode_report, jslint_report(result));
 1793.      8    }
 1794.      8    process_exit(exit_code);
 1795.      8    return exit_code;
 1796.      8}
 1797.      1
 1798.    628function jslint_phase1_split() {
 1799.    628
 1800.    628// PHASE 1. Split <source> by newlines into <line_list>.
 1801.    628
 1802.    628    return;
 1803.    628}
 1804.      1
 1805.    628function jslint_phase2_lex(state) {
 1806.    628
 1807.    628// PHASE 2. Lex <line_list> into <token_list>.
 1808.    628
 1809.    628    let {
 1810.    628        artifact,
 1811.    628        directive_list,
 1812.    628        global_dict,
 1813.    628        global_list,
 1814.    628        line_list,
 1815.    628        option_dict,
 1816.    628        stop,
 1817.    628        stop_at,
 1818.    628        tenure,
 1819.    628        test_cause,
 1820.    628        token_global,
 1821.    628        token_list,
 1822.    628        warn,
 1823.    628        warn_at
 1824.    628    } = state;
 1825.    628    let char;                   // The current character being lexed.
 1826.    628    let column = 0;             // The column number of the next character.
 1827.    628    let from;                   // The starting column number of the token.
 1828.    628    let from_mega;              // The starting column of megastring.
 1829.    628    let line = 0;               // The line number of the next character.
 1830.    628    let line_disable;           // The starting line of "/*jslint-disable*/".
 1831.    628    let line_mega;              // The starting line of megastring.
 1832.    628    let line_source = "";       // The remaining line source string.
 1833.    628    let line_whole = "";        // The whole line source string.
 1834.    628    let mode_directive = true;  // true if directives are still allowed.
 1835.    628    let mode_mega = false;      // true if currently parsing a megastring
 1836.    628                                // ... literal.
 1837.    628    let mode_regexp;            // true if regular expression literal seen on
 1838.    628                                // ... this line.
 1839.    628    let rx_token = new RegExp(
 1840.    628        "^("
 1841.    628        + "(\\s+)"
 1842.    628        + "|([a-zA-Z_$][a-zA-Z0-9_$]*)"
 1843.    628        + "|[(){}\\[\\],:;'\"~\\`]"
 1844.    628        + "|\\?[?.]?"
 1845.    628        + "|=(?:==?|>)?"
 1846.    628        + "|\\.+"
 1847.    628        + "|\\*[*\\/=]?"
 1848.    628        + "|\\/[*\\/]?"
 1849.    628        + "|\\+[=+]?"
 1850.    628        + "|-[=\\-]?"
 1851.    628        + "|[\\^%]=?"
 1852.    628        + "|&[&=]?"
 1853.    628        + "|\\"
 1854.    628        + "|[|=]?"
 1855.    628        + "|>{1,3}=?"
 1856.    628        + "|<<?=?"
 1857.    628        + "|!(?:!|==?)?"
 1858.    628
 1859.    628// PR-351 - Add BigInt support.
 1860.    628
 1861.    628        + "|(0n?|[1-9][0-9]*n?)"
 1862.    628        + ")"
 1863.    628        + "(.*)$"
 1864.    628    );
 1865.    628    let snippet = "";           // A piece of string.
 1866.    628    let token_1;                // The first token.
 1867.    628    let token_prv = token_global;       // The previous token including
 1868.    628                                        // ... comments.
 1869.    628    let token_prv_expr = token_global;  // The previous token excluding
 1870.    628                                        // ... comments.
 1871.    628
 1872.    628// Most tokens, including the identifiers, operators, and punctuators, can be
 1873.    628// found with a regular expression. Regular expressions cannot correctly match
 1874.    628// regular expression literals, so we will match those the hard way. String
 1875.    628// literals and number literals can be matched by regular expressions, but they
 1876.    628// don't provide good warnings. The functions char_after, char_before,
 1877.    628// read_digits, and char_after_escape help in the parsing of literals.
 1878.    628
 1879. 219681    function char_after(match) {
 1880. 219681
 1881. 219681// Get the next character from the source line. Remove it from the line_source,
 1882. 219681// and append it to the snippet. Optionally check that the previous character
 1883. 219681// matched an expected value.
 1884. 219681
 1885.   4365        if (match !== undefined && char !== match) {
 1886.     10
 1887.     10// test_cause:
 1888.     10// ["aa=/[", "char_after", "expected_a", "]", 5]
 1889.     10// ["aa=/aa{/", "char_after", "expected_a_b", "/", 8]
 1890.     10
 1891.     10            return (
 1892.     10                char === ""
 1893.     10                ? stop_at("expected_a", line, column - 1, match)
 1894.     10                : stop_at("expected_a_b", line, column, match, char)
 1895.     10            );
 1896. 219671        }
 1897. 219671        char = line_source.slice(0, 1);
 1898. 219671        line_source = line_source.slice(1);
 1899. 219671        snippet += char || " ";
 1900. 219681        column += 1;
 1901. 219681        return char;
 1902. 219681    }
 1903.    628
 1904.   2210    function char_after_escape(extra) {
 1905.   2210
 1906.   2210// Validate char after escape "\\".
 1907.   2210
 1908.   2210        char_after("\\");
 1909.   2210        switch (char) {
 1910.      1        case "":
 1911.      1
 1912.      1// test_cause:
 1913.      1// ["\"\\", "char_after_escape", "unclosed_string", "", 2]
 1914.      1
 1915.      1            return stop_at("unclosed_string", line, column);
 1916.    132        case "/":
 1917.    132            return char_after();
 1918.    212        case "\\":
 1919.    212            return char_after();
 1920.      1        case "`":
 1921.      1            return char_after();
 1922.     58        case "b":
 1923.     58            return char_after();
 1924.      6        case "f":
 1925.      6            return char_after();
 1926.    864        case "n":
 1927.    864            return char_after();
 1928.     19        case "r":
 1929.     19            return char_after();
 1930.     24        case "t":
 1931.     24
 1932.     24// test_cause:
 1933.     24// ["\"\\/\\\\\\`\\b\\f\\n\\r\\t\"", "char_after_escape", "char_after", "", 0]
 1934.     24
 1935.     24            test_cause("char_after");
 1936.     24            return char_after();
 1937.    262        case "u":
 1938.    262            if (char_after("u") === "{") {
 1939.    262                if (state.mode_json) {
 1940.    262
 1941.    262// test_cause:
 1942.    262// ["[\"\\u{12345}\"]", "char_after_escape", "unexpected_a", "{", 5]
 1943.    262
 1944.    262                    warn_at("unexpected_a", line, column, char);
 1945.    262                }
 1946.    262                if (read_digits("x") > 5) {
 1947.    262
 1948.    262// test_cause:
 1949.    262// ["\"\\u{123456}\"", "char_after_escape", "too_many_digits", "", 11]
 1950.    262
 1951.    262                    warn_at("too_many_digits", line, column);
 1952.    262                }
 1953.    262                if (char !== "}") {
 1954.    262
 1955.    262// test_cause:
 1956.    262// ["\"\\u{12345\"", "char_after_escape", "expected_a_before_b", "\"", 10]
 1957.    262
 1958.    262                    stop_at("expected_a_before_b", line, column, "}", char);
 1959.    262                }
 1960.    262                return char_after();
 1961.    262            }
 1962.    262            char_before();
 1963.    262            if (read_digits("x", true) < 4) {
 1964.    262
 1965.    262// test_cause:
 1966.    262// ["\"\\u0\"", "char_after_escape", "expected_four_digits", "", 5]
 1967.    262
 1968.    262                warn_at("expected_four_digits", line, column);
 1969.    262            }
 1970.    262            return;
 1971.    631        default:
 1972.    631            if (extra && extra.indexOf(char) >= 0) {
 1973.    631                return char_after();
 1974.    631            }
 1975.    631
 1976.    631// test_cause:
 1977.    631// ["\"\\0\"", "char_after_escape", "unexpected_a_before_b", "0", 3]
 1978.    631
 1979.    631            warn_at("unexpected_a_before_b", line, column, "\\", char);
 1980.   2210        }
 1981.   2210    }
 1982.    628
 1983.   9351    function char_before() {
 1984.   9351
 1985.   9351// Back up one character by moving a character from the end of the snippet to
 1986.   9351// the front of the line_source.
 1987.   9351
 1988.   9351        char = snippet.slice(-1);
 1989.   9351        line_source = char + line_source;
 1990.   9351        column -= char.length;
 1991.   9351
 1992.   9351// Remove last character from snippet.
 1993.   9351
 1994.   9351        snippet = snippet.slice(0, -1);
 1995.   9351        return char;
 1996.   9351    }
 1997.    628
 1998.  10021    function lex_comment() {
 1999.  10021        let body;
 2000.  10021        let ii = 0;
 2001.  10021        let jj = 0;
 2002.  10021        let the_comment;
 2003.  10021
 2004.  10021// Create a comment object. Comments are not allowed in JSON text. Comments can
 2005.  10021// include directives and notices of incompletion.
 2006.  10021
 2007.  10021// Create token from comment //....
 2008.  10021
 2009.   9928        if (snippet === "//") {
 2010.   9928            snippet = line_source;
 2011.   9928            line_source = "";
 2012.   9928            the_comment = token_create("(comment)", snippet);
 2013.   9928            if (mode_mega) {
 2014.   9928
 2015.   9928// test_cause:
 2016.   9928// ["`${//}`", "lex_comment", "unexpected_comment", "`", 4]
 2017.   9928
 2018.   9928                warn("unexpected_comment", the_comment, "`");
 2019.   9928            }
 2020.   9928
 2021.   9928// Create token from comment /*...*/.
 2022.   9928
 2023.   9928        } else {
 2024.     93            snippet = [];
 2025.     93            if (line_source[0] === "/") {
 2026.     93
 2027.     93// test_cause:
 2028.     93// ["/*/", "lex_comment", "unexpected_a", "/", 2]
 2029.     93
 2030.     93                warn_at("unexpected_a", line, column + ii, "/");
 2031.     93            }
 2032.     93
 2033.     93// Lex/loop through each line until "*/".
 2034.     93
 2035.    730            while (true) {
 2036.    730                // rx_star_slash
 2037.    730                ii = line_source.indexOf("*/");
 2038.    730                if (ii >= 0) {
 2039.    730                    break;
 2040.    730                }
 2041.    730                // rx_slash_star
 2042.    730                ii = line_source.indexOf("/*");
 2043.    730                if (ii >= 0) {
 2044.    730
 2045.    730// test_cause:
 2046.    730// ["/*/*", "lex_comment", "nested_comment", "", 2]
 2047.    730
 2048.    730                    warn_at("nested_comment", line, column + ii);
 2049.    730                }
 2050.    730                snippet.push(line_source);
 2051.    730                line_source = read_line();
 2052.    730                if (line_source === undefined) {
 2053.    730
 2054.    730// test_cause:
 2055.    730// ["/*", "lex_comment", "unclosed_comment", "", 1]
 2056.    730
 2057.    730                    return stop_at("unclosed_comment", line, column);
 2058.    730                }
 2059.    730            }
 2060.     93            jj = line_source.slice(0, ii).search(
 2061.     93                // rx_slash_star_or_slash
 2062.     93                /\/\*|\/$/
 2063.     93            );
 2064.     93            if (jj >= 0) {
 2065.     93
 2066.     93// test_cause:
 2067.     93// ["/*/**/", "lex_comment", "nested_comment", "", 2]
 2068.     93
 2069.     93                warn_at("nested_comment", line, column + jj);
 2070.     93            }
 2071.     93            snippet.push(line_source.slice(0, ii));
 2072.     93            snippet = snippet.join(" ");
 2073.     93            column += ii + 2;
 2074.     93            line_source = line_source.slice(ii + 2);
 2075.     93            the_comment = token_create("(comment)", snippet);
 2076.  10018        }
 2077.  10018
 2078.  10018// Uncompleted work comment.
 2079.  10018
 2080.  10018        if (
 2081.  10018            !option_dict.devel
 2082.  10018            && (
 2083.  10018                // rx_todo
 2084.  10018                /\b(?:todo|TO\s?DO|HACK)\b/
 2085.  10018            ).test(snippet)
 2086.     16        ) {
 2087.     16
 2088.     16// test_cause:
 2089.     16// ["//todo", "lex_comment", "todo_comment", "(comment)", 1] //jslint-quiet
 2090.     16
 2091.     16            warn("todo_comment", the_comment);
 2092.  10018        }
 2093.  10018
 2094.  10018// Lex directives in comment.
 2095.  10018
 2096.  10018        [
 2097.  10018            the_comment.directive, body
 2098.  10018        ] = Array.from(snippet.match(
 2099.  10018            // rx_directive
 2100.  10018            /^(jslint|property|global)\s+(.*)$/
 2101.  10018        ) || []).slice(1);
 2102.   9960        if (the_comment.directive === undefined) {
 2103.   9960            return the_comment;
 2104.   9960        }
 2105.     58        directive_list.push(the_comment);
 2106.     58        if (!mode_directive) {
 2107.      1
 2108.      1// test_cause:
 2109.      1// ["0\n/*global aa*/", "lex_comment", "misplaced_directive_a", "global", 1]
 2110.      1
 2111.      1            warn_at("misplaced_directive_a", line, from, the_comment.directive);
 2112.      1            return the_comment;
 2113.     57        }
 2114.     57
 2115.     57// lex_directive();
 2116.     57// JSLint recognizes three directives that can be encoded in comments. This
 2117.     57// function processes one item, and calls itself recursively to process the
 2118.     57// next one.
 2119.     57
 2120.     57// Lex/loop through each directive in /*...*/
 2121.     57
 2122.     57        ii = 0;
 2123.     57        body.replace((
 2124.     57            // rx_directive_part
 2125.     57            /([a-zA-Z$_][a-zA-Z0-9$_]*)(?::\s*(true|false))?,?\s*|$/g
 2126.   1623        ), function (match0, key, val, jj) {
 2127.     57            if (ii !== jj) {
 2128.     57
 2129.     57// test_cause:
 2130.     57// ["/*jslint !*/", "lex_comment", "bad_directive_a", "!", 1]
 2131.     57
 2132.     57                return stop("bad_directive_a", the_comment, body.slice(ii));
 2133.   1622            }
 2134.   1622            if (match0 === "") {
 2135.     57                return "";
 2136.   1566            }
 2137.   1566            ii += match0.length;
 2138.   1566            switch (the_comment.directive) {
 2139.   1566            case "global":
 2140.     57                if (val) {
 2141.     57
 2142.     57// test_cause:
 2143.     57// ["/*global aa:false*/", "lex_comment", "bad_option_a", "aa:false", 1]
 2144.     57
 2145.     57                    warn("bad_option_a", the_comment, key + ":" + val);
 2146.     57                }
 2147.     57                global_dict[key] = "user-defined";
 2148.     57
 2149.     57// PR-347 - Disable warning "unexpected_directive_a".
 2150.     57//                 state.mode_module = the_comment;
 2151.     57
 2152.     57                break;
 2153.     76            case "jslint":
 2154.     76                if (!option_set_item(key, val !== "false")) {
 2155.     76
 2156.     76// test_cause:
 2157.     76// ["/*jslint undefined*/", "lex_comment", "bad_option_a", "undefined", 1]
 2158.     76
 2159.     76                    warn("bad_option_a", the_comment, key);
 2160.     76                }
 2161.     76                break;
 2162.   1488            case "property":
 2163.   1488                state.mode_property = true;
 2164.   1488                tenure[key] = true;
 2165.   1488                break;
 2166.   1566            }
 2167.   1566            return "";
 2168.   1566        });
 2169.     57        return the_comment;
 2170.     57    }
 2171.    628
 2172.    709    function lex_megastring() {
 2173.    709        let id;
 2174.    709        let match;
 2175.    709
 2176.    709// The token is a megastring. We don't allow any kind of mega nesting.
 2177.    709
 2178.      1        if (mode_mega) {
 2179.      1
 2180.      1// test_cause:
 2181.      1// ["`${`", "lex_megastring", "expected_a_b", "`", 4]
 2182.      1
 2183.      1            return stop_at("expected_a_b", line, column, "}", "`");
 2184.    708        }
 2185.    708        from_mega = from;
 2186.    708        line_mega = line;
 2187.    708        mode_mega = true;
 2188.    708        snippet = "";
 2189.    708
 2190.    708// Parsing a mega literal is tricky. First create a ` token.
 2191.    708
 2192.    708        token_create("`");
 2193.    708        from += 1;
 2194.    708
 2195.    708// Then loop, building up a string, possibly from many lines, until seeing
 2196.    708// the end of file, a closing `, or a ${ indicting an expression within the
 2197.    708// string.
 2198.    708
 2199.   5443        while (true) {
 2200.   5443            match = line_source.match(
 2201.   5443
 2202.   5443// Vim-hack - vim-editor has trouble parsing '`' in regexp
 2203.   5443
 2204.   5443                // rx_mega
 2205.   5443                /[\u0060\\]|\$\{/
 2206.   5443            ) || {
 2207.   5443                "0": "",
 2208.   5443                index: 0
 2209.   5443            };
 2210.   5443            snippet += line_source.slice(0, match.index);
 2211.   5443            column += match.index;
 2212.   5443            line_source = line_source.slice(match.index);
 2213.   5443            match = match[0];
 2214.   5443            switch (match) {
 2215.   5443            case "${":
 2216.   5443
 2217.   5443// if either ` or ${ was found, then the preceding joins the snippet to become
 2218.   5443// a string token.
 2219.   5443
 2220.   5443                token_create("(string)", snippet).quote = "`";
 2221.   5443                snippet = "";
 2222.   5443
 2223.   5443// If ${, then create tokens that will become part of an expression until
 2224.   5443// a } token is made.
 2225.   5443
 2226.   5443                column += 2;
 2227.   5443                token_create("${");
 2228.   5443                line_source = line_source.slice(2);
 2229.   5443
 2230.   5443// Lex/loop through each token inside megastring-expression `${...}`.
 2231.   5443
 2232.   5443                while (true) {
 2233.   5443                    id = lex_token().id;
 2234.   5443                    if (id === "{") {
 2235.   5443
 2236.   5443// test_cause:
 2237.   5443// ["`${{", "lex_megastring", "expected_a_b", "{", 4]
 2238.   5443
 2239.   5443                        return stop_at("expected_a_b", line, column, "}", "{");
 2240.   5443                    }
 2241.   5443                    if (id === "}") {
 2242.   5443                        break;
 2243.   5443                    }
 2244.   5443                }
 2245.   5443                break;
 2246.   5443            case "\\":
 2247.   5443                snippet += line_source.slice(0, 2);
 2248.   5443                line_source = line_source.slice(2);
 2249.   5443                column += 2;
 2250.   5443                break;
 2251.   5443            case "`":
 2252.   5443
 2253.   5443// if either ` or ${ was found, then the preceding joins the snippet to become
 2254.   5443// a string token.
 2255.   5443
 2256.   5443                token_create("(string)", snippet).quote = "`";
 2257.   5443                snippet = "";
 2258.   5443
 2259.   5443// Terminate megastring with `.
 2260.   5443
 2261.   5443                line_source = line_source.slice(1);
 2262.   5443                column += 1;
 2263.   5443                mode_mega = false;
 2264.   5443                return token_create("`");
 2265.   5443            default:
 2266.   5443
 2267.   5443// If neither ` nor ${ is seen, then the whole line joins the snippet.
 2268.   5443
 2269.   5443                snippet += line_source + "\n";
 2270.   5443                if (read_line() === undefined) {
 2271.   5443
 2272.   5443// test_cause:
 2273.   5443// ["`", "lex_megastring", "unclosed_mega", "", 1]
 2274.   5443
 2275.   5443                    return stop_at("unclosed_mega", line_mega, from_mega);
 2276.   5443                }
 2277.   5443            }
 2278.   5443        }
 2279.    709    }
 2280.    628
 2281.   8597    function lex_number() {
 2282.   8597        let prefix = snippet;
 2283.   8597        char_after();
 2284.   2812        switch (prefix === "0" && char) {
 2285.      2        case "b":
 2286.      4        case "o":
 2287.      9        case "x":
 2288.      9            read_digits(char);
 2289.      9
 2290.      9// PR-351 - Ignore BigInt suffix 'n'.
 2291.      9
 2292.      9            if (char === "n") {
 2293.      9                char_after("n");
 2294.      9            }
 2295.      9            break;
 2296.   8588        default:
 2297.   8588            if (char === ".") {
 2298.   8588                read_digits("d");
 2299.   8588            }
 2300.   8588            if (char === "E" || char === "e") {
 2301.   8588                char_after(char);
 2302.   8588                if (char !== "+" && char !== "-") {
 2303.   8588                    char_before();
 2304.   8588                }
 2305.   8588                read_digits("d");
 2306.   8588            }
 2307.   8597        }
 2308.   8597
 2309.   8597// If the next character after a number is a digit or letter, then something
 2310.   8597// unexpected is going on.
 2311.   8597
 2312.   8597        if (
 2313.   1475            (char >= "0" && char <= "9")
 2314.     39            || (char >= "a" && char <= "z")
 2315.   8596            || (char >= "A" && char <= "Z")
 2316.      1        ) {
 2317.      1
 2318.      1// test_cause:
 2319.      1// ["0a", "lex_number", "unexpected_a_after_b", "0", 2]
 2320.      1
 2321.      1            return stop_at(
 2322.      1                "unexpected_a_after_b",
 2323.      1                line,
 2324.      1                column,
 2325.      1                snippet.slice(-1),
 2326.      1                snippet.slice(0, -1)
 2327.      1            );
 2328.   8596        }
 2329.   8596        char_before();
 2330.   8596        return token_create("(number)", snippet);
 2331.   8596    }
 2332.    628
 2333.    402    function lex_regexp() {
 2334.    402
 2335.    402// Regexp
 2336.    402// Lex a regular expression literal.
 2337.    402
 2338.    402        let flag;
 2339.    402        let mode_regexp_multiline;
 2340.    402        let result;
 2341.    402        let value;
 2342.    402        mode_regexp = true;
 2343.    402
 2344.    134        function lex_regexp_bracketed() {
 2345.    134            let mode_regexp_range;
 2346.    134
 2347.    134// RegExp
 2348.    134// Match a class.
 2349.    134
 2350.    134            char_after("[");
 2351.     10            if (char === "^") {
 2352.     10                char_after("^");
 2353.     10            }
 2354.    562            while (true) {
 2355.    562
 2356.    562// RegExp
 2357.    562// Match a character in a character class.
 2358.    562
 2359.    562                switch (char) {
 2360.    562                case "":
 2361.    562                case "]":
 2362.    562
 2363.    562// test_cause:
 2364.    562// ["aa=/[", "lex_regexp_bracketed", "closer", "", 0]
 2365.    562// ["aa=/[]/", "lex_regexp_bracketed", "closer", "", 0]
 2366.    562
 2367.    562                    test_cause("closer");
 2368.    562                    if (mode_regexp_range) {
 2369.    562
 2370.    562// test_cause:
 2371.    562// ["aa=/[0-]/", "lex_regexp_bracketed", "unexpected_a", "-", 7]
 2372.    562
 2373.    562                        warn_at("unexpected_a", line, column - 1, "-");
 2374.    562                    }
 2375.    562                    return char_after("]");
 2376.    562
 2377.    562// PR-362 - Relax regexp-warning against using <space>.
 2378.    562//                 case " ":
 2379.    562//
 2380.    562// // test_cause:
 2381.    562// // ["aa=/[ ]/", "lex_regexp_bracketed", "expected_a_b", " ", 6]
 2382.    562//
 2383.    562//                     warn_at("expected_a_b", line, column, "\\u0020", " ");
 2384.    562//                     break;
 2385.    562
 2386.    562                case "-":
 2387.    562                case "/":
 2388.    562                case "[":
 2389.    562                case "^":
 2390.    562
 2391.    562// test_cause:
 2392.    562// ["aa=/[-]/", "lex_regexp_bracketed", "expected_a_before_b", "-", 6]
 2393.    562// ["aa=/[.^]/", "lex_regexp_bracketed", "expected_a_before_b", "^", 7]
 2394.    562// ["aa=/[/", "lex_regexp_bracketed", "expected_a_before_b", "/", 6]
 2395.    562// ["aa=/[\\\\/]/", "lex_regexp_bracketed", "expected_a_before_b", "/", 8]
 2396.    562// ["aa=/[\\\\[]/", "lex_regexp_bracketed", "expected_a_before_b", "[", 8]
 2397.    562
 2398.    562                    warn_at("expected_a_before_b", line, column, "\\", char);
 2399.    562                    break;
 2400.    562                case "\\":
 2401.    562                    char_after_escape("BbDdSsWw-[]^");
 2402.    562                    char_before();
 2403.    562                    break;
 2404.    562                case "`":
 2405.    562                    if (mode_mega) {
 2406.    562
 2407.    562// test_cause:
 2408.    562// ["`${/[`]/}`", "lex_regexp_bracketed", "unexpected_a", "`", 6]
 2409.    562
 2410.    562                        warn_at("unexpected_a", line, column, "`");
 2411.    562                    }
 2412.    562                    break;
 2413.    562                }
 2414.    562                char_after();
 2415.    562                mode_regexp_range = false;
 2416.    562                if (char === "-") {
 2417.    562
 2418.    562// RegExp
 2419.    562// Match a range of subclasses.
 2420.    562
 2421.    562                    mode_regexp_range = true;
 2422.    562                    char_after("-");
 2423.    562                }
 2424.    562            }
 2425.    134        }
 2426.    402
 2427.    551        function lex_regexp_group() {
 2428.    551
 2429.    551// RegExp
 2430.    551// Lex sequence of characters in regexp.
 2431.    551
 2432.    551            switch (char) {
 2433.      1            case "":
 2434.      1                warn_at("expected_regexp_factor_a", line, column, char);
 2435.      1                break;
 2436.      1            case ")":
 2437.      1                warn_at("expected_regexp_factor_a", line, column, char);
 2438.      1                break;
 2439.      1            case "]":
 2440.      1
 2441.      1// test_cause:
 2442.      1// ["/ /", "lex_regexp_group", "expected_regexp_factor_a", "", 3]
 2443.      1// ["aa=/)", "lex_regexp_group", "expected_regexp_factor_a", ")", 5]
 2444.      1// ["aa=/]", "lex_regexp_group", "expected_regexp_factor_a", "]", 5]
 2445.      1
 2446.      1                warn_at("expected_regexp_factor_a", line, column, char);
 2447.      1                break;
 2448.    551            }
 2449.   3728            while (true) {
 2450.   3728                switch (char) {
 2451.   3728                case "":
 2452.   3728                case ")":
 2453.   3728                case "/":
 2454.   3728                case "]":
 2455.   3728                    return;
 2456.   3728
 2457.   3728// PR-362 - Relax regexp-warning against using <space>.
 2458.   3728//                 case " ":
 2459.   3728//
 2460.   3728// // test_cause:
 2461.   3728// // ["aa=/ /", "lex_regexp_group", "expected_a_b", " ", 5]
 2462.   3728//
 2463.   3728//                     warn_at("expected_a_b", line, column, "\\s", " ");
 2464.   3728//                     char_after();
 2465.   3728//                     break;
 2466.   3728
 2467.   3728                case "$":
 2468.   3728                    if (line_source[0] !== "/") {
 2469.   3728                        mode_regexp_multiline = true;
 2470.   3728                    }
 2471.   3728                    char_after();
 2472.   3728                    break;
 2473.   3728                case "(":
 2474.   3728
 2475.   3728// RegExp
 2476.   3728// Match a group that starts with left paren.
 2477.   3728
 2478.   3728                    char_after("(");
 2479.   3728                    if (char === "?") {
 2480.   3728                        char_after("?");
 2481.   3728                        if (char === "=" || char === "!") {
 2482.   3728                            char_after();
 2483.   3728                        } else {
 2484.   3728                            char_after(":");
 2485.   3728                        }
 2486.   3728                    } else if (char === ":") {
 2487.   3728
 2488.   3728// test_cause:
 2489.   3728// ["aa=/(:)/", "lex_regexp_group", "expected_a_before_b", ":", 6]
 2490.   3728// ["aa=/?/", "lex_regexp_group", "expected_a_before_b", "?", 5]
 2491.   3728
 2492.   3728                        warn_at("expected_a_before_b", line, column, "?", ":");
 2493.   3728                    }
 2494.   3728
 2495.   3728// RegExp
 2496.   3728// Recurse lex_regexp_group().
 2497.   3728
 2498.   3728                    lex_regexp_group();
 2499.   3728                    char_after(")");
 2500.   3728                    break;
 2501.   3728                case "*":
 2502.   3728                case "+":
 2503.   3728                case "?":
 2504.   3728                case "{":
 2505.   3728                case "}":
 2506.   3728
 2507.   3728// test_cause:
 2508.   3728// ["aa=/+/", "lex_regexp_group", "expected_a_before_b", "+", 5]
 2509.   3728// ["aa=/.**/", "lex_regexp_group", "expected_a_before_b", "*", 7]
 2510.   3728// ["aa=/?/", "lex_regexp_group", "expected_a_before_b", "?", 5]
 2511.   3728// ["aa=/{/", "lex_regexp_group", "expected_a_before_b", "{", 5]
 2512.   3728// ["aa=/}/", "lex_regexp_group", "expected_a_before_b", "}", 5]
 2513.   3728
 2514.   3728                    warn_at("expected_a_before_b", line, column, "\\", char);
 2515.   3728                    char_after();
 2516.   3728                    break;
 2517.   3728                case "[":
 2518.   3728                    lex_regexp_bracketed();
 2519.   3728                    break;
 2520.   3728                case "\\":
 2521.   3728
 2522.   3728// test_cause:
 2523.   3728// ["aa=/\\/", "lex_regexp_group", "escape", "", 0]
 2524.   3728
 2525.   3728                    test_cause("escape");
 2526.   3728                    char_after_escape("BbDdSsWw^${}[]():=!.|*+?");
 2527.   3728                    break;
 2528.   3728                case "^":
 2529.   3728                    if (snippet !== "^") {
 2530.   3728                        mode_regexp_multiline = true;
 2531.   3728                    }
 2532.   3728                    char_after();
 2533.   3728                    break;
 2534.   3728                case "`":
 2535.   3728                    if (mode_mega) {
 2536.   3728
 2537.   3728// test_cause:
 2538.   3728// ["`${/`/}`", "lex_regexp_group", "unexpected_a", "`", 5]
 2539.   3728
 2540.   3728                        warn_at("unexpected_a", line, column, "`");
 2541.   3728                    }
 2542.   3728                    char_after();
 2543.   3728                    break;
 2544.   3728                default:
 2545.   3728                    char_after();
 2546.   3728                }
 2547.   3728
 2548.   3728// RegExp
 2549.   3728// Match an optional quantifier.
 2550.   3728
 2551.   3728                switch (char) {
 2552.   3728                case "*":
 2553.   3728                case "+":
 2554.   3728                    if (char_after(char) === "?") {
 2555.   3728
 2556.   3728// test_cause:
 2557.   3728// ["aa=/.*?/", "lex_regexp_group", "?", "", 0]
 2558.   3728// ["aa=/.+?/", "lex_regexp_group", "?", "", 0]
 2559.   3728
 2560.   3728                        test_cause("?");
 2561.   3728                        char_after("?");
 2562.   3728                    }
 2563.   3728                    break;
 2564.   3728                case "?":
 2565.   3728                    if (char_after("?") === "?") {
 2566.   3728
 2567.   3728// test_cause:
 2568.   3728// ["aa=/.??/", "lex_regexp_group", "unexpected_a", "?", 7]
 2569.   3728
 2570.   3728                        warn_at("unexpected_a", line, column, char);
 2571.   3728                        char_after("?");
 2572.   3728                    }
 2573.   3728                    break;
 2574.   3728                case "{":
 2575.   3728                    if (read_digits("d", true) === 0) {
 2576.   3728
 2577.   3728// test_cause:
 2578.   3728// ["aa=/aa{/", "lex_regexp_group", "expected_a_before_b", ",", 8]
 2579.   3728
 2580.   3728                        warn_at("expected_a_before_b", line, column, "0", ",");
 2581.   3728                    }
 2582.   3728                    if (char === ",") {
 2583.   3728
 2584.   3728// test_cause:
 2585.   3728// ["aa=/.{,/", "lex_regexp_group", "comma", "", 0]
 2586.   3728
 2587.   3728                        test_cause("comma");
 2588.   3728                        read_digits("d", true);
 2589.   3728                    }
 2590.   3728                    if (char_after("}") === "?") {
 2591.   3728
 2592.   3728// test_cause:
 2593.   3728// ["aa=/.{0}?/", "lex_regexp_group", "unexpected_a", "?", 9]
 2594.   3728
 2595.   3728                        warn_at("unexpected_a", line, column, char);
 2596.   3728                        char_after("?");
 2597.   3728                    }
 2598.   3728                    break;
 2599.   3728                }
 2600.   3728            }
 2601.    551        }
 2602.    402
 2603.    402// RegExp
 2604.    402// Scan the regexp literal. Give a warning if the first character is = because
 2605.    402// /= looks like a division assignment operator.
 2606.    402
 2607.    402        snippet = "";
 2608.    402        char_after();
 2609.      1        if (char === "=") {
 2610.      1
 2611.      1// test_cause:
 2612.      1// ["aa=/=/", "lex_regexp", "expected_a_before_b", "=", 5]
 2613.      1
 2614.      1            warn_at("expected_a_before_b", line, column, "\\", "=");
 2615.      1        }
 2616.    402        lex_regexp_group();
 2617.    402
 2618.    402// RegExp
 2619.    402// Remove last character from snippet.
 2620.    402
 2621.    402        snippet = snippet.slice(0, -1);
 2622.    402
 2623.    402// RegExp
 2624.    402// Make sure there is a closing slash.
 2625.    402
 2626.    402        value = snippet;
 2627.    402        char_after("/");
 2628.    402
 2629.    402// RegExp
 2630.    402// Create flag.
 2631.    402
 2632.    402        flag = empty();
 2633.    402        while (
 2634.    402
 2635.    402// Regexp
 2636.    402// char is a letter.
 2637.    402
 2638.    274            (char >= "a" && char <= "z\uffff")
 2639.    392            || (char >= "A" && char <= "Z\uffff")
 2640.    272        ) {
 2641.    272
 2642.    272// RegExp
 2643.    272// Process dangling flag letters.
 2644.    272
 2645.    272            switch (!flag[char] && char) {
 2646.    272            case "g":
 2647.    272                break;
 2648.    272            case "i":
 2649.    272                break;
 2650.    272            case "m":
 2651.    272                break;
 2652.    272            case "u":
 2653.    272                break;
 2654.    272            case "y":
 2655.    272
 2656.    272// test_cause:
 2657.    272// ["aa=/./gimuy", "lex_regexp", "flag", "", 0]
 2658.    272
 2659.    272                test_cause("flag");
 2660.    272                break;
 2661.    272            default:
 2662.    272
 2663.    272// test_cause:
 2664.    272// ["aa=/./gg", "lex_regexp", "unexpected_a", "g", 8]
 2665.    272// ["aa=/./z", "lex_regexp", "unexpected_a", "z", 7]
 2666.    272
 2667.    272                warn_at("unexpected_a", line, column, char);
 2668.    272            }
 2669.    272            flag[char] = true;
 2670.    272            char_after();
 2671.    392        }
 2672.    392        char_before();
 2673.    392        if (char === "/" || char === "*") {
 2674.      1
 2675.      1// test_cause:
 2676.      1// ["aa=/.//", "lex_regexp", "unexpected_a", "/", 3]
 2677.      1
 2678.      1            return stop_at("unexpected_a", line, from, char);
 2679.    391        }
 2680.    391        result = token_create("(regexp)", char);
 2681.    391        result.flag = flag;
 2682.    391        result.value = value;
 2683.    391        if (mode_regexp_multiline && !flag.m) {
 2684.      1
 2685.      1// test_cause:
 2686.      1// ["aa=/$^/", "lex_regexp", "missing_m", "", 7]
 2687.      1
 2688.      1            warn_at("missing_m", line, column);
 2689.    391        }
 2690.    391        return result;
 2691.    391    }
 2692.    628
 2693.    416    function lex_slash_or_regexp() {
 2694.    416
 2695.    416// The / can be a division operator or the beginning of a regular expression
 2696.    416// literal. It is not possible to know which without doing a complete parse.
 2697.    416// We want to complete the tokenization before we begin to parse, so we will
 2698.    416// estimate. This estimator can fail in some cases. For example, it cannot
 2699.    416// know if "}" is ending a block or ending an object literal, so it can
 2700.    416// behave incorrectly in that case; it is not meaningful to divide an
 2701.    416// object, so it is likely that we can get away with it. We avoided the worst
 2702.    416// cases by eliminating automatic semicolon insertion.
 2703.    416
 2704.    416        let the_token;
 2705.    416        switch (
 2706.    416            token_prv_expr.identifier
 2707.     17            && !token_prv_expr.dot
 2708.     15            && token_prv_expr.id
 2709.    416        ) {
 2710.      1        case "case":
 2711.      2        case "delete":
 2712.      3        case "in":
 2713.      4        case "instanceof":
 2714.      5        case "new":
 2715.      6        case "typeof":
 2716.      7        case "void":
 2717.      8        case "yield":
 2718.      8            the_token = lex_regexp();
 2719.      8
 2720.      8// test_cause:
 2721.      8// ["case /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
 2722.      8// ["delete /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
 2723.      8// ["in /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 4]
 2724.      8// ["instanceof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 12]
 2725.      8// ["new /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 5]
 2726.      8// ["typeof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
 2727.      8// ["void /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
 2728.      8// ["yield /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 7]
 2729.      8
 2730.      8            return stop("unexpected_a", the_token);
 2731.      1        case "return":
 2732.      1            return lex_regexp();
 2733.    407        }
 2734.    407        switch (!token_prv_expr.identifier && token_prv_expr.id.slice(-1)) {
 2735.      1        case "!":
 2736.      2        case "%":
 2737.      4        case "&":
 2738.      5        case "*":
 2739.      6        case "+":
 2740.      7        case "-":
 2741.      9        case "/":
 2742.     10        case ";":
 2743.     11        case "<":
 2744.     12        case ">":
 2745.     13        case "^":
 2746.     16        case "{":
 2747.     17        case "|":
 2748.     18        case "}":
 2749.     19        case "~":
 2750.     19            the_token = lex_regexp();
 2751.     19
 2752.     19// test_cause:
 2753.     19// ["!/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2754.     19// ["%/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2755.     19// ["&/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2756.     19// ["+/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2757.     19// ["-/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2758.     19// ["0 * /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
 2759.     19// ["0 / /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
 2760.     19// [";/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2761.     19// ["</./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2762.     19// [">/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2763.     19// ["^/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2764.     19// ["{/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2765.     19// ["|/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2766.     19// ["}/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2767.     19// ["~/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 2768.     19
 2769.     19            warn("wrap_regexp", the_token);
 2770.     19            return the_token;
 2771.    333        case "(":
 2772.    334        case ",":
 2773.    335        case ":":
 2774.    372        case "=":
 2775.    373        case "?":
 2776.    374        case "[":
 2777.    374
 2778.    374// test_cause:
 2779.    374// ["(/./", "lex_slash_or_regexp", "recurse", "", 0]
 2780.    374// [",/./", "lex_slash_or_regexp", "recurse", "", 0]
 2781.    374// [":/./", "lex_slash_or_regexp", "recurse", "", 0]
 2782.    374// ["=/./", "lex_slash_or_regexp", "recurse", "", 0]
 2783.    374// ["?/./", "lex_slash_or_regexp", "recurse", "", 0]
 2784.    374// ["aa[/./", "lex_slash_or_regexp", "recurse", "", 0]
 2785.    374
 2786.    374            test_cause("recurse");
 2787.    374            return lex_regexp();
 2788.     14        }
 2789.     14        if (line_source[0] === "=") {
 2790.      1            column += 1;
 2791.      1            line_source = line_source.slice(1);
 2792.      1            snippet = "/=";
 2793.      1            warn_at("unexpected_a", line, column, "/=");
 2794.     14        }
 2795.     14        return token_create(snippet);
 2796.     14    }
 2797.    628
 2798.  23090    function lex_string(quote) {
 2799.  23090
 2800.  23090// Create a string token.
 2801.  23090
 2802.  23090        let the_token;
 2803.  23088        if (!option_dict.single && quote === "'") {
 2804.      2
 2805.      2// test_cause:
 2806.      2// ["''", "lex_string", "use_double", "", 1]
 2807.      2
 2808.      2            warn_at("use_double", line, column);
 2809.      2        }
 2810.  23090        snippet = "";
 2811.  23090        char_after();
 2812.  23090
 2813.  23090// Lex/loop through each character in "...".
 2814.  23090
 2815. 202707        while (true) {
 2816. 202707            switch (char) {
 2817. 202707            case "":
 2818. 202707
 2819. 202707// test_cause:
 2820. 202707// ["\"", "lex_string", "unclosed_string", "", 1]
 2821. 202707
 2822. 202707                return stop_at("unclosed_string", line, column);
 2823. 202707            case "\\":
 2824. 202707                char_after_escape(quote);
 2825. 202707                break;
 2826. 202707            case "`":
 2827. 202707                if (mode_mega) {
 2828. 202707
 2829. 202707// test_cause:
 2830. 202707// ["`${\"`\"}`", "lex_string", "unexpected_a", "`", 5]
 2831. 202707
 2832. 202707                    warn_at("unexpected_a", line, column, "`");
 2833. 202707                }
 2834. 202707                char_after("`");
 2835. 202707                break;
 2836. 202707            case quote:
 2837. 202707
 2838. 202707// Remove last character from snippet.
 2839. 202707
 2840. 202707                snippet = snippet.slice(0, -1);
 2841. 202707                the_token = token_create("(string)", snippet);
 2842. 202707                the_token.quote = quote;
 2843. 202707                return the_token;
 2844. 202707            default:
 2845. 202707                char_after();
 2846. 202707            }
 2847. 202707        }
 2848.  23090    }
 2849.    628
 2850. 236979    function lex_token() {
 2851. 236979        let match;
 2852. 236979
 2853. 236979// Lex/loop through each whitespace.
 2854. 236979
 2855. 354078        while (true) {
 2856. 354078
 2857. 354078// Lex/loop through each blank-line.
 2858. 354078
 2859. 354078            while (!line_source) {
 2860. 354078                line_source = read_line();
 2861. 354078                from = 0;
 2862. 354078                if (line_source === undefined) {
 2863. 354078                    return (
 2864. 354078                        mode_mega
 2865. 354078
 2866. 354078// test_cause:
 2867. 354078// ["`${//}`", "lex_token", "unclosed_mega", "", 1]
 2868. 354078
 2869. 354078                        ? stop_at("unclosed_mega", line_mega, from_mega)
 2870. 354078                        : line_disable !== undefined
 2871. 354078
 2872. 354078// test_cause:
 2873. 354078// ["/*jslint-disable*/", "lex_token", "unclosed_disable", "", 1]
 2874. 354078
 2875. 354078                        ? stop_at("unclosed_disable", line_disable)
 2876. 354078                        : token_create("(end)")
 2877. 354078                    );
 2878. 354078                }
 2879. 354078            }
 2880. 354078            from = column;
 2881. 354078            match = line_source.match(rx_token);
 2882. 354078
 2883. 354078// match[1] token
 2884. 354078// match[2] whitespace
 2885. 354078// match[3] identifier
 2886. 354078// match[4] number
 2887. 354078// match[5] rest
 2888. 354078
 2889. 354078            if (!match) {
 2890. 354078
 2891. 354078// test_cause:
 2892. 354078// ["#", "lex_token", "unexpected_char_a", "#", 1]
 2893. 354078
 2894. 354078                return stop_at(
 2895. 354078                    "unexpected_char_a",
 2896. 354078                    line,
 2897. 354078                    column,
 2898. 354078                    line_source[0]
 2899. 354078                );
 2900. 354078            }
 2901. 354078            snippet = match[1];
 2902. 354078            column += snippet.length;
 2903. 354078            line_source = match[5];
 2904. 354078            if (!match[2]) {
 2905. 354078                break;
 2906. 354078            }
 2907. 354078        }
 2908. 236376
 2909. 236376// The token is an identifier.
 2910. 236376
 2911. 236376        if (match[3]) {
 2912.  63540            return token_create(snippet, undefined, true);
 2913. 172836        }
 2914. 172836
 2915. 172836// Create token from number.
 2916. 172836
 2917. 172836        if (match[4]) {
 2918.   8597            return lex_number();
 2919. 164239        }
 2920. 164239
 2921. 164239// Create token from string "..." or '...'.
 2922. 164239
 2923. 164239        if (snippet === "\"" || snippet === "'") {
 2924.  23090            return lex_string(snippet);
 2925. 141149        }
 2926. 141149
 2927. 141149// Create token from megastring `...`.
 2928. 141149
 2929. 141149        if (snippet === "`") {
 2930.    709            return lex_megastring();
 2931. 140440        }
 2932. 140440
 2933. 140440// Create token from comment /*...*/ or //....
 2934. 140440
 2935. 140440        if (snippet === "/*" || snippet === "//") {
 2936.  10021            return lex_comment();
 2937. 130419        }
 2938. 130419
 2939. 130419// Create token from slash /.
 2940. 130419
 2941. 130419        if (snippet === "/") {
 2942.    416            return lex_slash_or_regexp();
 2943. 130003        }
 2944. 130003        return token_create(snippet);
 2945. 130003    }
 2946.    628
 2947.   2490    function option_set_item(key, val) {
 2948.   2490
 2949.   2490// These are the options that are recognized in the option object or that may
 2950.   2490// appear in a /*jslint*/ directive. Most options will have a boolean value,
 2951.   2490// usually true. Some options will also predefine some number of global
 2952.   2490// variables.
 2953.   2490
 2954.   2490        switch (key) {
 2955.    619        case "beta":            // Enable experimental warnings.
 2956.    621        case "bitwise":         // Allow bitwise operators.
 2957.    624        case "browser":         // Assume browser environment.
 2958.    626        case "convert":         // Allow conversion operators.
 2959.    628        case "couch":           // Assume CouchDb environment.
 2960.    630        case "devel":           // Allow console.log() and friends.
 2961.   1886        case "ecma":            // Assume ECMAScript environment.
 2962.   1890        case "eval":            // Allow eval().
 2963.   1895        case "for":             // Allow for-statement.
 2964.   1901        case "getset":          // Allow get() and set().
 2965.   1906        case "indent2":         // Use 2-space indent.
 2966.   1908        case "long":            // Allow long lines.
 2967.   1910        case "name":            // Allow weird property names.
 2968.   1944        case "node":            // Assume Node.js environment.
 2969.   1946        case "single":          // Allow single-quote strings.
 2970.   2443        case "test_cause":      // Test jslint's causes.
 2971.   2444        case "test_internal_error":     // Test jslint's internal-error
 2972.   2490                                        // ... handling-ability.
 2973.   2446        case "this":            // Allow 'this'.
 2974.   2449        case "trace":           // Include jslint stack-trace in warnings.
 2975.   2453        case "unordered":       // Allow unordered cases, params, properties,
 2976.   2490                                // ... and variables.
 2977.   2457        case "variable":        // Allow unordered const and let declarations
 2978.   2490                                // ... that are not at top of function-scope.
 2979.   2459        case "white":           // Allow messy whitespace.
 2980.   2459            option_dict[key] = val;
 2981.   2459            break;
 2982.     31        default:
 2983.     31            return false;
 2984.   2459        }
 2985.   2459
 2986.   2459// Initialize global-variables.
 2987.   2459
 2988.   2459        switch (val && key) {
 2989.   2490
 2990.   2490// Assign global browser variables to global_dict.
 2991.   2490// /*jslint beta, browser, devel*/
 2992.   2490// console.log(JSON.stringify(Array.from([
 2993.   2490//     ...
 2994.   2490// ]).filter(function (key) {
 2995.   2490//     return window.hasOwnProperty(key);
 2996.   2490// }), undefined, 4));
 2997.   2490
 2998.      2        case "browser":
 2999.      2            object_assign_from_list(global_dict, [
 3000.      2
 3001.      2// Shared with Node.js.
 3002.      2
 3003.      2                "AbortController",
 3004.      2                "DOMException",
 3005.      2                "Event",
 3006.      2                "EventTarget",
 3007.      2                "MessageChannel",
 3008.      2                "MessageEvent",
 3009.      2                "MessagePort",
 3010.      2                "TextDecoder",
 3011.      2                "TextEncoder",
 3012.      2                "URL",
 3013.      2                "URLSearchParams",
 3014.      2                "WebAssembly",
 3015.      2                // "atob",
 3016.      2                // "btoa",
 3017.      2                "clearInterval",
 3018.      2                "clearTimeout",
 3019.      2                // "console",
 3020.      2                "performance",
 3021.      2                "queueMicrotask",
 3022.      2                "setInterval",
 3023.      2                "setTimeout",
 3024.      2
 3025.      2// Browser only.
 3026.      2
 3027.      2                // "CharacterData",
 3028.      2                // "DocumentType",
 3029.      2                // "Element",
 3030.      2                // "Event",
 3031.      2                "FileReader",
 3032.      2                // "FontFace",
 3033.      2                "FormData",
 3034.      2                "IntersectionObserver",
 3035.      2                "MutationObserver",
 3036.      2                // "Storage",
 3037.      2                // "TextDecoder",
 3038.      2                // "TextEncoder",
 3039.      2                // "URL",
 3040.      2                "Worker",
 3041.      2                "XMLHttpRequest",
 3042.      2                // "caches",
 3043.      2                // "clearInterval",
 3044.      2                // "clearTimeout",
 3045.      2                "document",
 3046.      2                // "event",
 3047.      2                "fetch",
 3048.      2                // "history",
 3049.      2                "localStorage",
 3050.      2                "location",
 3051.      2                // "name",
 3052.      2                "navigator",
 3053.      2                // "screen",
 3054.      2                "sessionStorage",
 3055.      2                // "setInterval",
 3056.      2                // "setTimeout",
 3057.      2                "window"
 3058.      2            ], "browser");
 3059.      2            break;
 3060.   2490
 3061.   2490// https://docs.couchdb.org/en/stable/query-server/javascript.html#javascript
 3062.   2490
 3063.      2        case "couch":
 3064.      2            object_assign_from_list(global_dict, [
 3065.      2                "emit",
 3066.      2                "getRow",
 3067.      2                "isArray",
 3068.      2                "log",
 3069.      2                "provides",
 3070.      2                "registerType",
 3071.      2                "require",
 3072.      2                "send",
 3073.      2                "start",
 3074.      2                "sum",
 3075.      2                "toJSON"
 3076.      2            ], "CouchDb");
 3077.      2            break;
 3078.      2        case "devel":
 3079.      2            object_assign_from_list(global_dict, [
 3080.      2                "alert", "confirm", "console", "prompt"
 3081.      2            ], "development");
 3082.      2            break;
 3083.   2490
 3084.   2490// These are the globals that are provided by the language standard.
 3085.   2490// Assign global ECMAScript variables to global_dict.
 3086.   2490/*
 3087.   2490node --input-type=module -e '
 3088.   2490// /\*jslint beta, node*\/
 3089.   2490import https from "https";
 3090.   2490(async function () {
 3091.   2490    let dict = {import: true};
 3092.   2490    let result = "";
 3093.   2490    await new Promise(function (resolve) {
 3094.   2490        https.get((
 3095.   2490            "https://raw.githubusercontent.com/mdn/content/main/files/"
 3096.   2490            + "en-us/web/javascript/reference/global_objects/index.md"
 3097.   2490        ), function (res) {
 3098.   2490            res.on("data", function (chunk) {
 3099.   2490                result += chunk;
 3100.   2490            }).on("end", resolve).setEncoding("utf8");
 3101.   2490        });
 3102.   2490    });
 3103.   2490    result.replace((
 3104.   2490        /\n- \{\{JSxRef\("(?:Global_Objects\/)?([^"\/]+?)"/g
 3105.   2490    ), function (ignore, key) {
 3106.   2490        if (globalThis.hasOwnProperty(key)) {
 3107.   2490            dict[key] = true;
 3108.   2490        }
 3109.   2490        return "";
 3110.   2490    });
 3111.   2490    console.log(JSON.stringify(Object.keys(dict).sort(), undefined, 4));
 3112.   2490}());
 3113.   2490'
 3114.   2490*/
 3115.   2490
 3116.   1256        case "ecma":
 3117.   1256            object_assign_from_list(global_dict, [
 3118.   1256                "Array",
 3119.   1256                "ArrayBuffer",
 3120.   1256                "Atomics",
 3121.   1256                "BigInt",
 3122.   1256                "BigInt64Array",
 3123.   1256                "BigUint64Array",
 3124.   1256                "Boolean",
 3125.   1256                "DataView",
 3126.   1256                "Date",
 3127.   1256                "Error",
 3128.   1256                "EvalError",
 3129.   1256                "Float32Array",
 3130.   1256                "Float64Array",
 3131.   1256                "Function",
 3132.   1256                "Infinity",
 3133.   1256                "Int16Array",
 3134.   1256                "Int32Array",
 3135.   1256                "Int8Array",
 3136.   1256                "Intl",
 3137.   1256                "JSON",
 3138.   1256                "Map",
 3139.   1256                "Math",
 3140.   1256                "NaN",
 3141.   1256                "Number",
 3142.   1256                "Object",
 3143.   1256                "Promise",
 3144.   1256                "Proxy",
 3145.   1256                "RangeError",
 3146.   1256                "ReferenceError",
 3147.   1256                "Reflect",
 3148.   1256                "RegExp",
 3149.   1256                "Set",
 3150.   1256                "SharedArrayBuffer",
 3151.   1256                "String",
 3152.   1256                "Symbol",
 3153.   1256                "SyntaxError",
 3154.   1256                "TypeError",
 3155.   1256                "URIError",
 3156.   1256                "Uint16Array",
 3157.   1256                "Uint32Array",
 3158.   1256                "Uint8Array",
 3159.   1256                "Uint8ClampedArray",
 3160.   1256                "WeakMap",
 3161.   1256                "WeakSet",
 3162.   1256                "WebAssembly",
 3163.   1256                "decodeURI",
 3164.   1256                "decodeURIComponent",
 3165.   1256                "encodeURI",
 3166.   1256                "encodeURIComponent",
 3167.   1256                "eval",
 3168.   1256                "globalThis",
 3169.   1256                "import",
 3170.   1256                "isFinite",
 3171.   1256                "isNaN",
 3172.   1256                "parseFloat",
 3173.   1256                "parseInt",
 3174.   1256                "undefined"
 3175.   1256            ], "ECMAScript");
 3176.   1256            break;
 3177.   2490
 3178.   2490// Assign global Node.js variables to global_dict.
 3179.   2490/*
 3180.   2490node --input-type=module -e '
 3181.   2490// /\*jslint beta, node*\/
 3182.   2490import moduleHttps from "https";
 3183.   2490(async function () {
 3184.   2490    let dict = {};
 3185.   2490    let result = "";
 3186.   2490    await new Promise(function (resolve) {
 3187.   2490        moduleHttps.get((
 3188.   2490            "https://raw.githubusercontent.com/nodejs/node/master/doc/api/"
 3189.   2490            + "globals.md"
 3190.   2490        ), function (res) {
 3191.   2490            res.on("data", function (chunk) {
 3192.   2490                result += chunk;
 3193.   2490            }).on("end", resolve).setEncoding("utf8");
 3194.   2490        });
 3195.   2490    });
 3196.   2490    result.replace((
 3197.   2490        /\n(?:\* \[`|## |## Class: )`\w+/g
 3198.   2490    ), function (match0) {
 3199.   2490        dict[match0.split("`")[1]] = true;
 3200.   2490        return "";
 3201.   2490    });
 3202.   2490    console.log(JSON.stringify(Object.keys(dict).sort(), undefined, 4));
 3203.   2490}());
 3204.   2490'
 3205.   2490*/
 3206.   2490
 3207.     34        case "node":
 3208.     34            object_assign_from_list(global_dict, [
 3209.     34                "AbortController",
 3210.     34                "Buffer",
 3211.     34                "DOMException",
 3212.     34                "Event",
 3213.     34                "EventTarget",
 3214.     34                "MessageChannel",
 3215.     34                "MessageEvent",
 3216.     34                "MessagePort",
 3217.     34                "TextDecoder",
 3218.     34                "TextEncoder",
 3219.     34                "URL",
 3220.     34                "URLSearchParams",
 3221.     34                "WebAssembly",
 3222.     34                "__dirname",
 3223.     34                "__filename",
 3224.     34                // "atob",
 3225.     34                // "btoa",
 3226.     34                "clearImmediate",
 3227.     34                "clearInterval",
 3228.     34                "clearTimeout",
 3229.     34                "console",
 3230.     34                "exports",
 3231.     34                "global",
 3232.     34                "module",
 3233.     34                "performance",
 3234.     34                "process",
 3235.     34                "queueMicrotask",
 3236.     34                "require",
 3237.     34                "setImmediate",
 3238.     34                "setInterval",
 3239.     34                "setTimeout"
 3240.     34            ], "Node.js");
 3241.     34            break;
 3242.   2459        }
 3243.   2459        return true;
 3244.   2459    }
 3245.    628
 3246.    323    function read_digits(base, quiet) {
 3247.    323        let digits = line_source.match(
 3248.    323            base === "b"
 3249.      2            ? (
 3250.      2                // rx_bits
 3251.      2                /^[01]*/
 3252.      2            )
 3253.    321            : base === "o"
 3254.    321            ? (
 3255.    321                // rx_octals
 3256.    321                /^[0-7]*/
 3257.    321            )
 3258.    321            : base === "x"
 3259.    321            ? (
 3260.    321                // rx_hexs
 3261.    321                /^[0-9A-F]*/i
 3262.    321            )
 3263.    321            : (
 3264.    321                // rx_digits
 3265.    321                /^[0-9]*/
 3266.    321            )
 3267.    323        )[0];
 3268.    323        let length = digits.length;
 3269.     46        if (!quiet && length === 0) {
 3270.      1
 3271.      1// test_cause:
 3272.      1// ["0x", "read_digits", "expected_digits_after_a", "0x", 2]
 3273.      1
 3274.      1            warn_at("expected_digits_after_a", line, column, snippet);
 3275.      1        }
 3276.    323        column += length;
 3277.    323        line_source = line_source.slice(length);
 3278.    323        snippet += digits;
 3279.    323        char_after();
 3280.    323        return length;
 3281.    323    }
 3282.    628
 3283.  88763    function read_line() {
 3284.  88763
 3285.  88763// Put the next line of source in line_source. If the line contains tabs,
 3286.  88763// replace them with spaces and give a warning. Also warn if the line contains
 3287.  88763// unsafe characters or is too damn long.
 3288.  88763
 3289.  88763        if (
 3290.  88763            !option_dict.long
 3291.  88759            && line_whole.length > 80
 3292.     46            && line_disable === undefined
 3293.     46            && !state.mode_json
 3294.     12            && token_1
 3295.     12            && !mode_regexp
 3296.      8        ) {
 3297.      8
 3298.      8// test_cause:
 3299.      8// ["/////////////////////////////////////////////////////////////////////////////////", "read_line", "too_long", "", 1] //jslint-quiet
 3300.      8
 3301.      8            warn_at("too_long", line);
 3302.      8        }
 3303.  88763        column = 0;
 3304.  88763        line += 1;
 3305.  88763        mode_regexp = false;
 3306.  88763        line_source = undefined;
 3307.  88763        line_whole = "";
 3308.    605        if (line_list[line] === undefined) {
 3309.    605            return line_source;
 3310.  88158        }
 3311.  88158        line_source = line_list[line].line_source;
 3312.  88158        line_whole = line_source;
 3313.  88158
 3314.  88158// Scan each line for following ignore-directives:
 3315.  88158// "/*jslint-disable*/"
 3316.  88158// "/*jslint-enable*/"
 3317.  88158// "//jslint-quiet"
 3318.  88158
 3319.  88158        if (line_source === "/*jslint-disable*/") {
 3320.      4
 3321.      4// test_cause:
 3322.      4// ["/*jslint-disable*/", "read_line", "jslint_disable", "", 0]
 3323.      4
 3324.      4            test_cause("jslint_disable");
 3325.      4            line_disable = line;
 3326.  88154        } else if (line_source === "/*jslint-enable*/") {
 3327.  88154            if (line_disable === undefined) {
 3328.  88154
 3329.  88154// test_cause:
 3330.  88154// ["/*jslint-enable*/", "read_line", "unopened_enable", "", 1]
 3331.  88154
 3332.  88154                stop_at("unopened_enable", line);
 3333.  88154            }
 3334.  88154            line_disable = undefined;
 3335.  88154        } else if (line_source.endsWith(" //jslint-quiet")) {
 3336.  88154
 3337.  88154// test_cause:
 3338.  88154// ["0 //jslint-quiet", "read_line", "jslint_quiet", "", 0]
 3339.  88154
 3340.  88154            test_cause("jslint_quiet");
 3341.  88154            line_list[line].directive_quiet = true;
 3342.  88157        }
 3343.  88157        if (line_disable !== undefined) {
 3344.      6
 3345.      6// test_cause:
 3346.      6// ["/*jslint-disable*/\n0", "read_line", "line_disable", "", 0]
 3347.      6
 3348.      6            test_cause("line_disable");
 3349.      6            line_source = "";
 3350.  88157        }
 3351.  88157        if (line_source.indexOf("\t") >= 0) {
 3352.      3            if (!option_dict.white) {
 3353.      3
 3354.      3// test_cause:
 3355.      3// ["\t", "read_line", "use_spaces", "", 1]
 3356.      3
 3357.      3                warn_at("use_spaces", line, line_source.indexOf("\t") + 1);
 3358.      3            }
 3359.      3            line_source = line_source.replace((
 3360.      3                // rx_tab
 3361.      3                /\t/g
 3362.      3            ), " ");
 3363.  88157        }
 3364.  88157        if (!option_dict.white && line_source.endsWith(" ")) {
 3365.      2
 3366.      2// test_cause:
 3367.      2// [" ", "read_line", "unexpected_trailing_space", "", 1]
 3368.      2
 3369.      2            warn_at("unexpected_trailing_space", line, line_source.length - 1);
 3370.  88157        }
 3371.  88157        return line_source;
 3372.  88157    }
 3373.    628
 3374. 239621    function token_create(id, value, identifier) {
 3375. 239621
 3376. 239621// Create the token object and append it to token_list.
 3377. 239621
 3378. 239621        let the_token = {
 3379. 239621            from,
 3380. 239621            id,
 3381. 239621            identifier: Boolean(identifier),
 3382. 239621            line,
 3383. 239621            nr: token_list.length,
 3384. 239621            thru: column
 3385. 239621        };
 3386. 239621        token_list.push(the_token);
 3387. 239621
 3388. 239621// Directives must appear before the first statement.
 3389. 239621
 3390. 229603        if (id !== "(comment)" && id !== ";") {
 3391. 214619            mode_directive = false;
 3392. 214619        }
 3393. 239621
 3394. 239621// If the token is to have a value, give it one.
 3395. 239621
 3396.  43426        if (value !== undefined) {
 3397.  43426            the_token.value = value;
 3398.  43426        }
 3399. 239621
 3400. 239621// If this token is an identifier that touches a preceding number, or
 3401. 239621// a "/", comment, or regular expression literal that touches a preceding
 3402. 239621// comment or regular expression literal, then give a missing space warning.
 3403. 239621// This warning is not suppressed by option_dict.white.
 3404. 239621
 3405. 239621        if (
 3406. 239621            token_prv.line === line
 3407. 174883            && token_prv.thru === from
 3408. 112528            && (id === "(comment)" || id === "(regexp)" || id === "/")
 3409.    108            && (token_prv.id === "(comment)" || token_prv.id === "(regexp)")
 3410.      1        ) {
 3411.      1
 3412.      1// test_cause:
 3413.      1// ["/**//**/", "token_create", "expected_space_a_b", "(comment)", 5]
 3414.      1
 3415.      1            warn(
 3416.      1                "expected_space_a_b",
 3417.      1                the_token,
 3418.      1                artifact(token_prv),
 3419.      1                artifact(the_token)
 3420.      1            );
 3421.      1        }
 3422.  10929        if (token_prv.id === "." && id === "(number)") {
 3423.      4
 3424.      4// test_cause:
 3425.      4// [".0", "token_create", "expected_a_before_b", ".", 1]
 3426.      4
 3427.      4            warn("expected_a_before_b", token_prv, "0", ".");
 3428.      4        }
 3429.  10929        if (token_prv_expr.id === "." && the_token.identifier) {
 3430.  10924            the_token.dot = true;
 3431.  10924        }
 3432. 239621
 3433. 239621// The previous token is used to detect adjacency problems.
 3434. 239621
 3435. 239621        token_prv = the_token;
 3436. 239621
 3437. 239621// The token_prv_expr token is a previous token that was not a comment.
 3438. 239621// The token_prv_expr token
 3439. 239621// is used to disambiguate "/", which can mean division or regular expression
 3440. 239621// literal.
 3441. 239621
 3442. 229603        if (token_prv.id !== "(comment)") {
 3443. 229603            token_prv_expr = token_prv;
 3444. 229603        }
 3445. 239621        return the_token;
 3446. 239621    }
 3447.    628
 3448.    628// Init global_dict and option_dict.
 3449.    628
 3450.    628    option_set_item("ecma", true);
 3451.   1786    Object.keys(option_dict).sort().forEach(function (key) {
 3452.   1786        option_set_item(key, option_dict[key] === true);
 3453.   1786    });
 3454.    628    object_assign_from_list(global_dict, global_list, "user-defined");
 3455.    628
 3456.    628// Scan first line for "#!" and ignore it.
 3457.    628
 3458.      2    if (line_list[jslint_fudge].line_source.startsWith("#!")) {
 3459.      2        line += 1;
 3460.      2        state.mode_shebang = true;
 3461.      2    }
 3462.    628    token_1 = lex_token();
 3463.    601    state.mode_json = token_1.id === "{" || token_1.id === "[";
 3464.    628
 3465.    628// Lex/loop through each token until (end).
 3466.    628
 3467. 234499    while (true) {
 3468. 234499        if (lex_token().id === "(end)") {
 3469. 234499            break;
 3470. 234499        }
 3471. 234499    }
 3472.    628}
 3473.      1
 3474.    591function jslint_phase3_parse(state) {
 3475.    591
 3476.    591// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
 3477.    591
 3478.    591// Parsing:
 3479.    591
 3480.    591// Parsing weaves the tokens into an abstract syntax tree. During that process,
 3481.    591// a token may be given any of these properties:
 3482.    591
 3483.    591//      arity       string
 3484.    591//      label       identifier
 3485.    591//      name        identifier
 3486.    591//      expression  expressions
 3487.    591//      block       statements
 3488.    591//      else        statements (else, default, catch)
 3489.    591
 3490.    591// Specialized tokens may have additional properties.
 3491.    591
 3492.    591    let anon = "anonymous";     // The guessed name for anonymous functions.
 3493.    591    let {
 3494.    591        artifact,
 3495.    591        catch_list,
 3496.    591        catch_stack,
 3497.    591        export_dict,
 3498.    591        function_list,
 3499.    591        function_stack,
 3500.    591        global_dict,
 3501.    591        import_list,
 3502.    591        is_equal,
 3503.    591        option_dict,
 3504.    591        property_dict,
 3505.    591        stop,
 3506.    591        syntax_dict,
 3507.    591        tenure,
 3508.    591        test_cause,
 3509.    591        token_global,
 3510.    591        token_list,
 3511.    591        warn,
 3512.    591        warn_at
 3513.    591    } = state;
 3514.    591    let catchage = catch_stack[0];      // The current catch-block.
 3515.    591    let functionage = token_global;     // The current function.
 3516.    591    let mode_var;               // "var" if using var; "let" if using let.
 3517.    591    let rx_identifier = (
 3518.    591        /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/
 3519.    591    );
 3520.    591    let token_ii = 0;           // The number of the next token.
 3521.    591    let token_now = token_global;       // The current token being examined in
 3522.    591                                        // ... the parse.
 3523.    591    let token_nxt = token_global;       // The next token to be examined in
 3524.    591                                        // ... <token_list>.
 3525.    591
 3526. 229893    function advance(id, match) {
 3527. 229893
 3528. 229893// Produce the next token.
 3529. 229893
 3530. 229893// Attempt to give helpful names to anonymous functions.
 3531. 229893
 3532.  63499        if (token_now.identifier && token_now.id !== "function") {
 3533.  61671            anon = token_now.id;
 3534. 168222        } else if (
 3535. 168222            token_now.id === "(string)"
 3536. 168222            && rx_identifier.test(token_now.value)
 3537. 168222        ) {
 3538. 168222            anon = token_now.value;
 3539. 168222        }
 3540. 229893
 3541. 229893// Attempt to match token_nxt with an expected id.
 3542. 229893
 3543. 114088        if (id !== undefined && token_nxt.id !== id) {
 3544.     26            return (
 3545.     26                match === undefined
 3546.     26
 3547.     26// test_cause:
 3548.     26// ["()", "advance", "expected_a_b", "(end)", 1]
 3549.     26
 3550.     26                ? stop("expected_a_b", token_nxt, id, artifact())
 3551.     26
 3552.     26// test_cause:
 3553.     26// ["{\"aa\":0", "advance", "expected_a_b_from_c_d", "{", 1]
 3554.     26
 3555.     26                : stop(
 3556.     26                    "expected_a_b_from_c_d",
 3557.     26                    token_nxt,
 3558.     26                    id,
 3559.     26                    artifact(match),
 3560.     26                    match.line,
 3561.     26                    artifact()
 3562.     26                )
 3563.     26            );
 3564. 229867        }
 3565. 229867
 3566. 229867// Promote the tokens, skipping comments.
 3567. 229867
 3568. 229867        token_now = token_nxt;
 3569. 239882        while (true) {
 3570. 239882            token_nxt = token_list[token_ii];
 3571. 239882            state.token_nxt = token_nxt;
 3572. 239882            token_ii += 1;
 3573. 239882            if (token_nxt.id !== "(comment)") {
 3574. 239882                if (token_nxt.id === "(end)") {
 3575. 239882                    token_ii -= 1;
 3576. 239882                }
 3577. 239882                break;
 3578. 239882            }
 3579. 239882            if (state.mode_json) {
 3580. 239882
 3581. 239882// test_cause:
 3582. 239882// ["[//]", "advance", "unexpected_a", "(comment)", 2]
 3583. 239882
 3584. 239882                warn("unexpected_a");
 3585. 239882            }
 3586. 239882        }
 3587. 229893    }
 3588.    591
 3589.   7092    function assignment(id) {
 3590.   7092
 3591.   7092// Create an assignment operator. The one true assignment is different because
 3592.   7092// its left side, when it is a variable, is not treated as an expression.
 3593.   7092// That case is special because that is when a variable gets initialized. The
 3594.   7092// other assignment operators can modify, but they cannot initialize.
 3595.   7092
 3596.   7092        const the_symbol = symbol(id, 20);
 3597.   4721        the_symbol.led = function (left) {
 3598.   4721            const the_token = token_now;
 3599.   4721            let right;
 3600.   4721            the_token.arity = "assignment";
 3601.   4721            right = parse_expression(20 - 1);
 3602.   4009            if (id === "=" && left.arity === "variable") {
 3603.   2596                the_token.names = left;
 3604.   2596                the_token.expression = right;
 3605.   2596            } else {
 3606.   2121                the_token.expression = [left, right];
 3607.   4717            }
 3608.   4717            if (
 3609.   4717                right.arity === "assignment"
 3610.   4717                || right.arity === "preassign"
 3611.   4715                || right.arity === "postassign"
 3612.      2            ) {
 3613.      2                warn("unexpected_a", right);
 3614.   4717            }
 3615.   4717            check_mutation(left);
 3616.   4717            return the_token;
 3617.   4717        };
 3618.   7092        return the_symbol;
 3619.   7092    }
 3620.    591
 3621.   5511    function block(special) {
 3622.   5511
 3623.   5511// Parse a block, a sequence of statements wrapped in braces.
 3624.   5511//  special "body"      The block is a function body.
 3625.   5511//          "ignore"    No warning on an empty block.
 3626.   5511//          "naked"     No advance.
 3627.   5511//          undefined   An ordinary block.
 3628.   5511
 3629.   5511        let stmts;
 3630.   5511        let the_block;
 3631.   5506        if (special !== "naked") {
 3632.   5506            advance("{");
 3633.   5510        }
 3634.   5510        the_block = token_now;
 3635.   5510        if (special !== "body") {
 3636.   3678            functionage.statement_prv = the_block;
 3637.   5510        }
 3638.   5510        the_block.arity = "statement";
 3639.   5510        the_block.body = special === "body";
 3640.   5510
 3641.   5510// Top level function bodies may include the "use strict" pragma.
 3642.   5510
 3643.   5510        if (
 3644.   5510            special === "body"
 3645.   5510            && function_stack.length === 1
 3646.    255            && token_nxt.value === "use strict"
 3647.      2        ) {
 3648.      2            token_nxt.statement = true;
 3649.      2            advance("(string)");
 3650.      2            advance(";");
 3651.   5510        }
 3652.   5510        stmts = parse_statements();
 3653.   5510        the_block.block = stmts;
 3654.   5510        if (stmts.length === 0) {
 3655.     82            if (!option_dict.devel && special !== "ignore") {
 3656.     82
 3657.     82// test_cause:
 3658.     82// ["function aa(){}", "block", "empty_block", "{", 14]
 3659.     82
 3660.     82                warn("empty_block", the_block);
 3661.     82            }
 3662.     82            the_block.disrupt = false;
 3663.   5421        } else {
 3664.   5421            the_block.disrupt = stmts[stmts.length - 1].disrupt;
 3665.   5503        }
 3666.   5503        advance("}");
 3667.   5503        return the_block;
 3668.   5503    }
 3669.    591
 3670.  21724    function check_left(left, right) {
 3671.  21724
 3672.  21724// Warn if the left is not one of these:
 3673.  21724//      ?.
 3674.  21724//      ?:
 3675.  21724//      e()
 3676.  21724//      e.b
 3677.  21724//      e[b]
 3678.  21724//      identifier
 3679.  21724
 3680.  21724        const id = left.id;
 3681.  21724        if (
 3682.  21724            !left.identifier
 3683.   5580            && (
 3684.   5580                left.arity !== "ternary"
 3685.   5580                || (
 3686.   5580                    !check_left(left.expression[1])
 3687.   5580                    && !check_left(left.expression[2])
 3688.   5580                )
 3689.   5580            )
 3690.   5580            && (
 3691.   5580                left.arity !== "binary"
 3692.   5580                || (id !== "." && id !== "?." && id !== "(" && id !== "[")
 3693.   5580            )
 3694.     11        ) {
 3695.     11            warn("unexpected_a", right || token_nxt);
 3696.     11            return false;
 3697.  21713        }
 3698.  21713        return true;
 3699.  21713    }
 3700.    591
 3701.   4720    function check_mutation(the_thing) {
 3702.   4720
 3703.   4720// The only expressions that may be assigned to are
 3704.   4720//      e.b
 3705.   4720//      e[b]
 3706.   4720//      v
 3707.   4720//      [destructure]
 3708.   4720//      {destructure}
 3709.   4720
 3710.   4720        if (
 3711.   4720            the_thing.arity !== "variable"
 3712.   1540            && the_thing.id !== "."
 3713.    164            && the_thing.id !== "["
 3714.      7            && the_thing.id !== "{"
 3715.      7        ) {
 3716.      7
 3717.      7// test_cause:
 3718.      7// ["0=0", "check_mutation", "bad_assignment_a", "0", 1]
 3719.      7
 3720.      7            warn("bad_assignment_a", the_thing);
 3721.      7            return false;
 3722.   4713        }
 3723.   4713        return true;
 3724.   4713    }
 3725.    591
 3726.   2084    function check_not_top_level(thing) {
 3727.   2084
 3728.   2084// Some features should not be at the outermost level.
 3729.   2084
 3730.     36        if (functionage === token_global) {
 3731.     36
 3732.     36// test_cause:
 3733.     36// ["
 3734.     36// while(0){}
 3735.     36// ", "check_not_top_level", "unexpected_at_top_level_a", "while", 1]
 3736.     36
 3737.     36            warn("unexpected_at_top_level_a", thing);
 3738.     36        }
 3739.   2084    }
 3740.    591
 3741.   3013    function check_ordered(type, token_list) {
 3742.   3013
 3743.   3013// This function will warn if <token_list> is unordered.
 3744.   3013
 3745.   3561        token_list.reduce(function (aa, token) {
 3746.   3561            const bb = artifact(token);
 3747.   3547            if (!option_dict.unordered && aa > bb) {
 3748.      3                warn("expected_a_b_before_c_d", token, type, bb, type, aa);
 3749.      3            }
 3750.   3561            return bb;
 3751.   3561        }, "");
 3752.   3013    }
 3753.    591
 3754.   1168    function check_ordered_case(case_list) {
 3755.   1168
 3756.   1168// This function will warn if <case_list> is unordered.
 3757.   1168
 3758.   2460        case_list.filter(noop).map(function (token) {
 3759.   2419            switch (token.identifier || token.id) {
 3760.     40            case "(number)":
 3761.     40                return {
 3762.     40                    order: 1,
 3763.     40                    token,
 3764.     40                    type: "number",
 3765.     40                    value: Number(artifact(token))
 3766.     40                };
 3767.   2379            case "(string)":
 3768.   2379                return {
 3769.   2379                    order: 2,
 3770.   2379                    token,
 3771.   2379                    type: "string",
 3772.   2379                    value: artifact(token)
 3773.   2379                };
 3774.     41            case true:
 3775.     41                return {
 3776.     41                    order: 3,
 3777.     41                    token,
 3778.     41                    type: "identifier",
 3779.     41                    value: artifact(token)
 3780.     41                };
 3781.   2460            }
 3782.   2460        }).reduce(function (aa, bb) {
 3783.   2460            if (
 3784.   2460                !option_dict.unordered
 3785.   2452                && aa && bb
 3786.   1292                && (
 3787.   1292                    aa.order > bb.order
 3788.   1292                    || (aa.order === bb.order && aa.value > bb.value)
 3789.   1292                )
 3790.     10            ) {
 3791.     10                warn(
 3792.     10                    "expected_a_b_before_c_d",
 3793.     10                    bb.token,
 3794.     10                    `case-${bb.type}`,
 3795.     10                    bb.value,
 3796.     10                    `case-${aa.type}`,
 3797.     10                    aa.value
 3798.     10                );
 3799.     10            }
 3800.   2460            return bb;
 3801.   2460        }, undefined);
 3802.   1168    }
 3803.    591
 3804.   3211    function condition() {
 3805.   3211
 3806.   3211// Parse the condition part of a do, if, while.
 3807.   3211
 3808.   3211        const the_paren = token_nxt;
 3809.   3211        let the_value;
 3810.   3211
 3811.   3211// test_cause:
 3812.   3211// ["do{}while()", "condition", "", "", 0]
 3813.   3211// ["if(){}", "condition", "", "", 0]
 3814.   3211// ["while(){}", "condition", "", "", 0]
 3815.   3211
 3816.   3211        test_cause("");
 3817.   3211        the_paren.free = true;
 3818.   3211        advance("(");
 3819.   3211        the_value = parse_expression(0);
 3820.   3211        advance(")");
 3821.      1        if (the_value.wrapped === true) {
 3822.      1
 3823.      1// test_cause:
 3824.      1// ["while((0)){}", "condition", "unexpected_a", "(", 6]
 3825.      1
 3826.      1            warn("unexpected_a", the_paren);
 3827.   3207        }
 3828.   3207
 3829.   3207// Check for anticondition.
 3830.   3207
 3831.   3207        switch (the_value.id) {
 3832.   3207        case "%":
 3833.      1            warn("unexpected_a", the_value);
 3834.      1            break;
 3835.      1        case "&":
 3836.      1            warn("unexpected_a", the_value);
 3837.      1            break;
 3838.     19        case "(number)":
 3839.     19            warn("unexpected_a", the_value);
 3840.     19            break;
 3841.      1        case "(string)":
 3842.      1            warn("unexpected_a", the_value);
 3843.      1            break;
 3844.      1        case "*":
 3845.      1            warn("unexpected_a", the_value);
 3846.      1            break;
 3847.      1        case "+":
 3848.      1            warn("unexpected_a", the_value);
 3849.      1            break;
 3850.      1        case "-":
 3851.      1            warn("unexpected_a", the_value);
 3852.      1            break;
 3853.      1        case "/":
 3854.      1            warn("unexpected_a", the_value);
 3855.      1            break;
 3856.      1        case "<<":
 3857.      1            warn("unexpected_a", the_value);
 3858.      1            break;
 3859.      1        case ">>":
 3860.      1            warn("unexpected_a", the_value);
 3861.      1            break;
 3862.      1        case ">>>":
 3863.      1            warn("unexpected_a", the_value);
 3864.      1            break;
 3865.      1        case "?":
 3866.      1            warn("unexpected_a", the_value);
 3867.      1            break;
 3868.      1        case "^":
 3869.      1            warn("unexpected_a", the_value);
 3870.      1            break;
 3871.      1        case "typeof":
 3872.      1            warn("unexpected_a", the_value);
 3873.      1            break;
 3874.      1        case "|":
 3875.      1            warn("unexpected_a", the_value);
 3876.      1            break;
 3877.      1        case "~":
 3878.      1
 3879.      1// test_cause:
 3880.      1// ["if(0%0){}", "condition", "unexpected_a", "%", 5]
 3881.      1// ["if(0&0){}", "condition", "unexpected_a", "&", 5]
 3882.      1// ["if(0){}", "condition", "unexpected_a", "0", 4]
 3883.      1// ["if(0*0){}", "condition", "unexpected_a", "*", 5]
 3884.      1// ["if(0+0){}", "condition", "unexpected_a", "+", 5]
 3885.      1// ["if(0-0){}", "condition", "unexpected_a", "-", 5]
 3886.      1// ["if(0/0){}", "condition", "unexpected_a", "/", 5]
 3887.      1// ["if(0<<0){}", "condition", "unexpected_a", "<<", 5]
 3888.      1// ["if(0>>0){}", "condition", "unexpected_a", ">>", 5]
 3889.      1// ["if(0>>>0){}", "condition", "unexpected_a", ">>>", 5]
 3890.      1// ["if(0?0:0){}", "condition", "unexpected_a", "?", 5]
 3891.      1// ["if(0^0){}", "condition", "unexpected_a", "^", 5]
 3892.      1// ["if(0|0){}", "condition", "unexpected_a", "|", 5]
 3893.      1// ["if(\"aa\"){}", "condition", "unexpected_a", "aa", 4]
 3894.      1// ["if(typeof 0){}", "condition", "unexpected_a", "typeof", 4]
 3895.      1// ["if(~0){}", "condition", "unexpected_a", "~", 4]
 3896.      1
 3897.      1            warn("unexpected_a", the_value);
 3898.      1            break;
 3899.   3207        }
 3900.   3207        return the_value;
 3901.   3207    }
 3902.    591
 3903.   9456    function constant(id, type, value) {
 3904.   9456
 3905.   9456// Create a constant symbol.
 3906.   9456
 3907.   9456        const the_symbol = symbol(id);
 3908.   9456        the_symbol.constant = true;
 3909.   9456        the_symbol.nud = (
 3910.   9456            typeof value === "function"
 3911.   4137            ? value
 3912.  17136            : function () {
 3913.  17136                token_now.constant = true;
 3914.   5319                if (value !== undefined) {
 3915.   5319                    token_now.value = value;
 3916.   5319                }
 3917.  17136                return token_now;
 3918.  17136            }
 3919.   9456        );
 3920.   9456        the_symbol.type = type;
 3921.   9456        the_symbol.value = value;
 3922.   9456        return the_symbol;
 3923.   9456    }
 3924.    591
 3925.      5    function constant_Function() {
 3926.      2        if (!option_dict.eval) {
 3927.      2
 3928.      2// test_cause:
 3929.      2// ["Function", "constant_Function", "unexpected_a", "Function", 1]
 3930.      2
 3931.      2            warn("unexpected_a", token_now);
 3932.      3        } else if (token_nxt.id !== "(") {
 3933.      3
 3934.      3// test_cause:
 3935.      3// ["
 3936.      3// /*jslint eval*/
 3937.      3// Function
 3938.      3// ", "constant_Function", "expected_a_before_b", "(end)", 1]
 3939.      3
 3940.      3            warn("expected_a_before_b", token_nxt, "(", artifact());
 3941.      3        }
 3942.      5        return token_now;
 3943.      5    }
 3944.    591
 3945.      1    function constant_arguments() {
 3946.      1
 3947.      1// test_cause:
 3948.      1// ["arguments", "constant_arguments", "unexpected_a", "arguments", 1]
 3949.      1
 3950.      1        warn("unexpected_a", token_now);
 3951.      1        return token_now;
 3952.      1    }
 3953.    591
 3954.      4    function constant_eval() {
 3955.      1        if (!option_dict.eval) {
 3956.      1
 3957.      1// test_cause:
 3958.      1// ["eval", "constant_eval", "unexpected_a", "eval", 1]
 3959.      1
 3960.      1            warn("unexpected_a", token_now);
 3961.      3        } else if (token_nxt.id !== "(") {
 3962.      3
 3963.      3// test_cause:
 3964.      3// ["/*jslint eval*/\neval", "constant_eval", "expected_a_before_b", "(end)", 1]
 3965.      3
 3966.      3            warn("expected_a_before_b", token_nxt, "(", artifact());
 3967.      3        }
 3968.      4        return token_now;
 3969.      4    }
 3970.    591
 3971.      1    function constant_ignore() {
 3972.      1
 3973.      1// test_cause:
 3974.      1// ["ignore", "constant_ignore", "unexpected_a", "ignore", 1]
 3975.      1
 3976.      1        warn("unexpected_a", token_now);
 3977.      1        return token_now;
 3978.      1    }
 3979.    591
 3980.      1    function constant_isInfinite() {
 3981.      1
 3982.      1// test_cause:
 3983.      1// ["isFinite", "constant_isInfinite", "expected_a_b", "isFinite", 1]
 3984.      1
 3985.      1        warn("expected_a_b", token_now, "Number.isFinite", "isFinite");
 3986.      1        return token_now;
 3987.      1    }
 3988.    591
 3989.      1    function constant_isNaN() {
 3990.      1
 3991.      1// test_cause:
 3992.      1// ["isNaN(0)", "constant_isNaN", "number_isNaN", "isNaN", 1]
 3993.      1
 3994.      1        warn("number_isNaN", token_now);
 3995.      1        return token_now;
 3996.      1    }
 3997.    591
 3998.      3    function constant_this() {
 3999.      1        if (!option_dict.this) {
 4000.      1
 4001.      1// test_cause:
 4002.      1// ["this", "constant_this", "unexpected_a", "this", 1]
 4003.      1
 4004.      1            warn("unexpected_a", token_now);
 4005.      1        }
 4006.      3        return token_now;
 4007.      3    }
 4008.    591
 4009.   5860    function enroll(name, role, readonly) {
 4010.   5860
 4011.   5860// Enroll a name into the current function context. The role can be exception,
 4012.   5860// function, label, parameter, or variable. We look for variable redefinition
 4013.   5860// because it causes confusion.
 4014.   5860
 4015.   5860        let earlier;
 4016.   5860        let id = name.id;
 4017.   5860
 4018.   5860// Reserved words may not be enrolled.
 4019.   5860
 4020.     36        if (syntax_dict[id] !== undefined && id !== "ignore") {
 4021.      1
 4022.      1// test_cause:
 4023.      1// ["let undefined", "enroll", "reserved_a", "undefined", 5]
 4024.      1
 4025.      1            warn("reserved_a", name);
 4026.      1            return;
 4027.   5859        }
 4028.   5859
 4029.   5859// Has the name been enrolled in this context?
 4030.   5859
 4031.   5859        earlier = functionage.context[id] || catchage.context[id];
 4032.      7        if (earlier) {
 4033.      7
 4034.      7// test_cause:
 4035.      7// ["let aa;let aa", "enroll", "redefinition_a_b", "1", 12]
 4036.      7
 4037.      7            warn("redefinition_a_b", name, id, earlier.line);
 4038.      7            return;
 4039.   5852        }
 4040.   5852
 4041.   5852// Has the name been enrolled in an outer context?
 4042.   5852
 4043.  10101        function_stack.forEach(function ({
 4044.  10101            context
 4045.  10101        }) {
 4046.   9994            earlier = context[id] || earlier;
 4047.  10101        });
 4048.   5852        if (earlier && id === "ignore") {
 4049.      4            if (earlier.role === "variable") {
 4050.      4
 4051.      4// test_cause:
 4052.      4// ["let ignore;function aa(ignore){}", "enroll", "redefinition_a_b", "1", 24]
 4053.      4
 4054.      4                warn("redefinition_a_b", name, id, earlier.line);
 4055.      4            }
 4056.   5848        } else if (
 4057.   5848            earlier
 4058.   5848            && role !== "parameter" && role !== "function"
 4059.   5848            && (role !== "exception" || earlier.role !== "exception")
 4060.   5848        ) {
 4061.   5848
 4062.   5848// test_cause:
 4063.   5848// ["
 4064.   5848// function aa(){try{aa();}catch(aa){aa();}}
 4065.   5848// ", "enroll", "redefinition_a_b", "1", 31]
 4066.   5848// ["function aa(){var aa;}", "enroll", "redefinition_a_b", "1", 19]
 4067.   5848
 4068.   5848            warn("redefinition_a_b", name, id, earlier.line);
 4069.   5848        } else if (
 4070.   5848            option_dict.beta
 4071.   5848            && global_dict[id]
 4072.   5848            && role !== "parameter"
 4073.   5848        ) {
 4074.   5848
 4075.   5848// test_cause:
 4076.   5848// ["let Array", "enroll", "redefinition_global_a_b", "Array", 5]
 4077.   5848
 4078.   5848            warn("redefinition_global_a_b", name, global_dict[id], id);
 4079.   5852        }
 4080.   5852
 4081.   5852// Enroll it.
 4082.   5852
 4083.   5852        Object.assign(name, {
 4084.   5852            dead: true,
 4085.   5852            init: false,
 4086.   5852            parent: (
 4087.   5852                role === "exception"
 4088.   5852                ? catchage
 4089.   5824                : functionage
 4090.   5860            ),
 4091.   5860            readonly,
 4092.   5860            role,
 4093.   5860            used: 0
 4094.   5860        });
 4095.   5860        name.parent.context[id] = name;
 4096.   5860    }
 4097.    591
 4098.  17730    function infix(bp, id, f) {
 4099.  17730
 4100.  17730// Create an infix operator.
 4101.  17730
 4102.  17730        const the_symbol = symbol(id, bp);
 4103.  30000        the_symbol.led = function (left) {
 4104.  30000            const the_token = token_now;
 4105.  30000            the_token.arity = "binary";
 4106.  21897            if (f !== undefined) {
 4107.  21897                return f(left);
 4108.  21897            }
 4109.   8103            the_token.expression = [left, parse_expression(bp)];
 4110.   8103            return the_token;
 4111.   8103        };
 4112.  17730        return the_symbol;
 4113.  17730    }
 4114.    591
 4115.  10923    function infix_dot(left) {
 4116.  10923        const the_token = token_now;
 4117.  10923        let name = token_nxt;
 4118.  10923        if (
 4119.  10923            (
 4120.  10923                left.id !== "(string)"
 4121.     31                || (name.id !== "indexOf" && name.id !== "repeat")
 4122.  10923            )
 4123.  10893            && (
 4124.  10893                left.id !== "["
 4125.  10893                || (
 4126.  10893                    name.id !== "concat"
 4127.  10893                    && name.id !== "forEach"
 4128.  10893                    && name.id !== "join"
 4129.  10893                    && name.id !== "map"
 4130.  10893                )
 4131.  10893            )
 4132.  10876            && (left.id !== "+" || name.id !== "slice")
 4133.  10871            && (
 4134.  10871                left.id !== "(regexp)"
 4135.  10871                || (name.id !== "exec" && name.id !== "test")
 4136.  10871            )
 4137.  10790        ) {
 4138.  10790
 4139.  10790// test_cause:
 4140.  10790// ["\"\".aa", "check_left", "unexpected_a", ".", 3]
 4141.  10790
 4142.  10790            check_left(left, the_token);
 4143.  10790        }
 4144.      1        if (!name.identifier) {
 4145.      1
 4146.      1// test_cause:
 4147.      1// ["aa.0", "infix_dot", "expected_identifier_a", "0", 4]
 4148.      1
 4149.      1            stop("expected_identifier_a");
 4150.  10922        }
 4151.  10922        advance();
 4152.  10922        survey(name);
 4153.  10922
 4154.  10922// The property name is not an expression.
 4155.  10922
 4156.  10922        the_token.name = name;
 4157.  10922        the_token.expression = left;
 4158.  10922        return the_token;
 4159.  10922    }
 4160.    591
 4161.      1    function infix_fart_unwrapped(left) {
 4162.      1
 4163.      1// test_cause:
 4164.      1// ["aa=>0", "infix_fart_unwrapped", "wrap_parameter", "aa", 1]
 4165.      1
 4166.      1        return stop("wrap_parameter", left);
 4167.      1    }
 4168.    591
 4169.      1    function infix_grave(left) {
 4170.      1        const the_tick = prefix_tick();
 4171.      1
 4172.      1// test_cause:
 4173.      1// ["0``", "check_left", "unexpected_a", "`", 2]
 4174.      1
 4175.      1        check_left(left, the_tick);
 4176.      1        the_tick.expression = [left].concat(the_tick.expression);
 4177.      1        return the_tick;
 4178.      1    }
 4179.    591
 4180.   1355    function infix_lbracket(left) {
 4181.   1355        const the_token = token_now;
 4182.   1355        let name;
 4183.   1355        let the_subscript = parse_expression(0);
 4184.   1345        if (the_subscript.id === "(string)" || the_subscript.id === "`") {
 4185.     12            name = survey(the_subscript);
 4186.     12            if (rx_identifier.test(name)) {
 4187.     12
 4188.     12// test_cause:
 4189.     12// ["aa[`aa`]", "infix_lbracket", "subscript_a", "aa", 4]
 4190.     12
 4191.     12                warn("subscript_a", the_subscript, name);
 4192.     12            }
 4193.     12        }
 4194.   1355
 4195.   1355// test_cause:
 4196.   1355// ["0[0]", "check_left", "unexpected_a", "[", 2]
 4197.   1355
 4198.   1355        check_left(left, the_token);
 4199.   1355        the_token.expression = [left, the_subscript];
 4200.   1355        advance("]");
 4201.   1355        return the_token;
 4202.   1355    }
 4203.    591
 4204.   9609    function infix_lparen(left) {
 4205.   9609        const the_paren = token_now;
 4206.   9609        let ellipsis;
 4207.   9609        let the_argument;
 4208.   9568        if (left.id !== "function") {
 4209.   9568
 4210.   9568// test_cause:
 4211.   9568// ["(0?0:0)()", "check_left", "unexpected_a", "(", 8]
 4212.   9568// ["0()", "check_left", "unexpected_a", "(", 2]
 4213.   9568
 4214.   9568            check_left(left, the_paren);
 4215.   9568        }
 4216.   7296        if (functionage.arity === "statement" && left.identifier) {
 4217.   5371            functionage.name.calls[left.id] = left;
 4218.   5371        }
 4219.   9609        the_paren.expression = [left];
 4220.   8207        if (token_nxt.id !== ")") {
 4221.   8207
 4222.   8207// Parse/loop through each token in expression (...).
 4223.   8207
 4224.  13100            while (true) {
 4225.  13100                if (token_nxt.id === "...") {
 4226.  13100                    ellipsis = true;
 4227.  13100                    advance("...");
 4228.  13100                }
 4229.  13100                the_argument = parse_expression(10);
 4230.  13100                if (ellipsis) {
 4231.  13100                    the_argument.ellipsis = true;
 4232.  13100                }
 4233.  13100                the_paren.expression.push(the_argument);
 4234.  13100                if (token_nxt.id !== ",") {
 4235.  13100                    break;
 4236.  13100                }
 4237.  13100                advance(",");
 4238.  13100            }
 4239.   8207        }
 4240.   9609        advance(")", the_paren);
 4241.   4917        if (the_paren.expression.length === 2) {
 4242.   4917
 4243.   4917// test_cause:
 4244.   4917// ["aa(0)", "infix_lparen", "free", "", 0]
 4245.   4917
 4246.   4917            test_cause("free");
 4247.   4917            the_paren.free = true;
 4248.   4917            if (the_argument.wrapped === true) {
 4249.   4917
 4250.   4917// test_cause:
 4251.   4917// ["aa((0))", "infix_lparen", "unexpected_a", "(", 3]
 4252.   4917
 4253.   4917                warn("unexpected_a", the_paren);
 4254.   4917            }
 4255.   4917            if (the_argument.id === "(") {
 4256.   4917                the_argument.wrapped = true;
 4257.   4917            }
 4258.   4917        } else {
 4259.   4692
 4260.   4692// test_cause:
 4261.   4692// ["aa()", "infix_lparen", "not_free", "", 0]
 4262.   4692// ["aa(0,0)", "infix_lparen", "not_free", "", 0]
 4263.   4692
 4264.   4692            test_cause("not_free");
 4265.   4692            the_paren.free = false;
 4266.   4692        }
 4267.   9609        return the_paren;
 4268.   9609    }
 4269.    591
 4270.      8    function infix_option_chain(left) {
 4271.      8        const the_token = token_now;
 4272.      8        let name;
 4273.      8        name = token_nxt;
 4274.      8        if (
 4275.      8            (
 4276.      8                left.id !== "(string)"
 4277.      1                || (name.id !== "indexOf" && name.id !== "repeat")
 4278.      8            )
 4279.      8            && (
 4280.      8                left.id !== "["
 4281.      1                || (
 4282.      1                    name.id !== "concat"
 4283.      1                    && name.id !== "forEach"
 4284.      1                    && name.id !== "join"
 4285.      1                    && name.id !== "map"
 4286.      1                )
 4287.      8            )
 4288.      8
 4289.      8// test_cause:
 4290.      8// ["(0+0)?.0", "infix_option_chain", "check_left", "", 0]
 4291.      8
 4292.      1            && (left.id !== "+" || name.id !== "slice")
 4293.      8            && (
 4294.      8                left.id !== "(regexp)"
 4295.      1                || (name.id !== "exec" && name.id !== "test")
 4296.      8            )
 4297.      8        ) {
 4298.      8            test_cause("check_left");
 4299.      8
 4300.      8// test_cause:
 4301.      8// ["(/./)?.0", "check_left", "unexpected_a", "?.", 6]
 4302.      8// ["\"aa\"?.0", "check_left", "unexpected_a", "?.", 5]
 4303.      8// ["aa=[]?.aa", "check_left", "unexpected_a", "?.", 6]
 4304.      8
 4305.      8            check_left(left, the_token);
 4306.      8        }
 4307.      4        if (!name.identifier) {
 4308.      4
 4309.      4// test_cause:
 4310.      4// ["aa?.0", "infix_option_chain", "expected_identifier_a", "0", 5]
 4311.      4
 4312.      4            stop("expected_identifier_a");
 4313.      4        }
 4314.      4        advance();
 4315.      4        survey(name);
 4316.      4
 4317.      4// The property name is not an expression.
 4318.      4
 4319.      4        the_token.name = name;
 4320.      4        the_token.expression = left;
 4321.      4        return the_token;
 4322.      4    }
 4323.    591
 4324.    591    function infixr(bp, id) {
 4325.    591
 4326.    591// Create a right associative infix operator.
 4327.    591
 4328.    591        const the_symbol = symbol(id, bp);
 4329.      1        the_symbol.led = function parse_infixr_led(left) {
 4330.      1            const the_token = token_now;
 4331.      1
 4332.      1// test_cause:
 4333.      1// ["0**0", "parse_infixr_led", "led", "", 0]
 4334.      1
 4335.      1            test_cause("led");
 4336.      1            the_token.arity = "binary";
 4337.      1            the_token.expression = [left, parse_expression(bp - 1)];
 4338.      1            return the_token;
 4339.      1        };
 4340.    591        return the_symbol;
 4341.    591    }
 4342.    591
 4343.   1357    function lookahead() {
 4344.   1357
 4345.   1357// Look ahead one token without advancing, skipping comments.
 4346.   1357
 4347.   1357        let cadet;
 4348.   1357        let ii = token_ii;
 4349.   1372        while (true) {
 4350.   1372            cadet = token_list[ii];
 4351.   1372            if (cadet.id !== "(comment)") {
 4352.   1372                return cadet;
 4353.   1372            }
 4354.   1372            ii += 1;
 4355.   1372        }
 4356.   1357    }
 4357.    591
 4358.  51795    function parse_expression(rbp, initial) {
 4359.  51795
 4360.  51795// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
 4361.  51795// is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
 4362.  51795// like .nud except that it is only used on the first token of a statement.
 4363.  51795// Having .fud makes it much easier to define statement-oriented languages like
 4364.  51795// JavaScript. I retained Pratt's nomenclature.
 4365.  51795// They are elements of the parsing method called Top Down Operator Precedence.
 4366.  51795
 4367.  51795// .nud     Null denotation
 4368.  51795// .fud     First null denotation
 4369.  51795// .led     Left denotation
 4370.  51795//  lbp     Left binding power
 4371.  51795//  rbp     Right binding power
 4372.  51795
 4373.  51795// It processes a nud (variable, constant, prefix operator). It will then
 4374.  51795// process leds (infix operators) until the bind powers cause it to stop. It
 4375.  51795// returns the expression's parse tree.
 4376.  51795
 4377.  51795        let left;
 4378.  51795        let the_symbol;
 4379.  51795
 4380.  51795// Statements will have already advanced, so advance now only if the token is
 4381.  51795// not the first of a statement.
 4382.  51795
 4383.  41128        if (!initial) {
 4384.  41128            advance();
 4385.  41128        }
 4386.  51795        the_symbol = syntax_dict[token_now.id];
 4387.  22179        if (the_symbol !== undefined && the_symbol.nud !== undefined) {
 4388.  22121
 4389.  22121// test_cause:
 4390.  22121// ["0", "parse_expression", "symbol", "", 0]
 4391.  22121
 4392.  22121            test_cause("symbol");
 4393.  22121            left = the_symbol.nud();
 4394.  29674        } else if (token_now.identifier) {
 4395.  29674
 4396.  29674// test_cause:
 4397.  29674// ["aa", "parse_expression", "identifier", "", 0]
 4398.  29674
 4399.  29674            test_cause("identifier");
 4400.  29674            left = token_now;
 4401.  29674            left.arity = "variable";
 4402.  29674        } else {
 4403.  29674
 4404.  29674// test_cause:
 4405.  29674// ["!", "parse_expression", "unexpected_a", "(end)", 1]
 4406.  29674// ["/./", "parse_expression", "unexpected_a", "/", 1]
 4407.  29674// ["let aa=`${}`;", "parse_expression", "unexpected_a", "}", 11]
 4408.  29674
 4409.  29674            return stop("unexpected_a", token_now);
 4410.  51753        }
 4411.  51753
 4412.  51753// Parse/loop through each symbol in expression.
 4413.  51753
 4414.  86678        while (true) {
 4415.  86678            the_symbol = syntax_dict[token_nxt.id];
 4416.  86678            if (
 4417.  86678                the_symbol === undefined
 4418.  86678                || the_symbol.led === undefined
 4419.  86678                || the_symbol.lbp <= rbp
 4420.  86678            ) {
 4421.  86678                break;
 4422.  86678            }
 4423.  86678            advance();
 4424.  86678            left = the_symbol.led(left);
 4425.  86678        }
 4426.  51742        return left;
 4427.  51742    }
 4428.    591
 4429.     10    function parse_fart(pl) {
 4430.     10        let the_fart;
 4431.     10        advance("=>");
 4432.     10        the_fart = token_now;
 4433.     10        the_fart.arity = "binary";
 4434.     10        the_fart.name = "=>";
 4435.     10        the_fart.level = functionage.level + 1;
 4436.     10        function_list.push(the_fart);
 4437.      1        if (functionage.loop > 0) {
 4438.      1
 4439.      1// test_cause:
 4440.      1// ["while(0){aa.map(()=>0);}", "parse_fart", "function_in_loop", "=>", 19]
 4441.      1
 4442.      1            warn("function_in_loop", the_fart);
 4443.      9        }
 4444.      9
 4445.      9// Give the function properties storing its names and for observing the depth
 4446.      9// of loops and switches.
 4447.      9
 4448.      9        the_fart.context = empty();
 4449.      9        the_fart.finally = 0;
 4450.      9        the_fart.loop = 0;
 4451.      9        the_fart.switch = 0;
 4452.      9        the_fart.try = 0;
 4453.      9
 4454.      9// Push the current function context and establish a new one.
 4455.      9
 4456.      9        function_stack.push(functionage);
 4457.      9        functionage = the_fart;
 4458.      9        the_fart.parameters = pl[0];
 4459.      9        the_fart.signature = pl[1];
 4460.      9        the_fart.parameters.forEach(function (name) {
 4461.      9
 4462.      9// test_cause:
 4463.      9// ["(aa)=>{}", "parse_fart", "parameter", "", 0]
 4464.      9
 4465.      9            test_cause("parameter");
 4466.      9            enroll(name, "parameter", true);
 4467.      9        });
 4468.      9        if (token_nxt.id === "{") {
 4469.      2
 4470.      2// test_cause:
 4471.      2// ["()=>{}", "parse_fart", "expected_a_b", "=>", 3]
 4472.      2
 4473.      2            warn("expected_a_b", the_fart, "function", "=>");
 4474.      2            the_fart.block = block("body");
 4475.      7        } else {
 4476.      7            the_fart.expression = parse_expression(0);
 4477.      9        }
 4478.      9        functionage = function_stack.pop();
 4479.      9        return the_fart;
 4480.      9    }
 4481.    591
 4482.  12943    function parse_json() {
 4483.  12943        let container;
 4484.  12943        let is_dup;
 4485.  12943        let name;
 4486.  12943        let negative;
 4487.  12943        switch (token_nxt.id) {
 4488.   5260        case "(number)":
 4489.   5260            if (!(
 4490.   5260
 4491.   5260// https://datatracker.ietf.org/doc/html/rfc7159#section-6
 4492.   5260// number = [ minus ] int [ frac ] [ exp ]
 4493.   5260
 4494.   5260                /^-?(?:0|[1-9]\d*?)(?:\.\d*?)?(?:[eE][+\-]?\d+?)?$/
 4495.   5260            ).test(token_nxt.value)) {
 4496.   5260
 4497.   5260// test_cause:
 4498.   5260// ["[-.0]", "parse_json", "unexpected_a", ".", 3]
 4499.   5260// ["[-0x0]", "parse_json", "unexpected_a", "0x0", 3]
 4500.   5260// ["[.0]", "parse_json", "unexpected_a", ".", 2]
 4501.   5260// ["[0x0]", "parse_json", "unexpected_a", "0x0", 2]
 4502.   5260
 4503.   5260                warn("unexpected_a");
 4504.   5260            }
 4505.   5260            advance("(number)");
 4506.   5260            return token_now;
 4507.   1756        case "(string)":
 4508.   1756            if (token_nxt.quote !== "\"") {
 4509.   1756
 4510.   1756// test_cause:
 4511.   1756// ["['']", "parse_json", "unexpected_a", "'", 2]
 4512.   1756
 4513.   1756                warn("unexpected_a", token_nxt, token_nxt.quote);
 4514.   1756            }
 4515.   1756            advance("(string)");
 4516.   1756            return token_now;
 4517.      3        case "-":
 4518.      3            negative = token_nxt;
 4519.      3            negative.arity = "unary";
 4520.      3            advance("-");
 4521.      3
 4522.      3// Recurse parse_json().
 4523.      3
 4524.      3            negative.expression = parse_json();
 4525.      3            return negative;
 4526.   1648        case "[":
 4527.   1648
 4528.   1648// test_cause:
 4529.   1648// ["[]", "parse_json", "bracket", "", 0]
 4530.   1648
 4531.   1648            test_cause("bracket");
 4532.   1648            container = token_nxt;
 4533.   1648            container.expression = [];
 4534.   1648            advance("[");
 4535.   1648            if (token_nxt.id !== "]") {
 4536.   3294                while (true) {
 4537.   3294
 4538.   3294// Recurse parse_json().
 4539.   3294
 4540.   3294                    container.expression.push(parse_json());
 4541.   3294                    if (token_nxt.id !== ",") {
 4542.   3294
 4543.   3294// test_cause:
 4544.   3294// ["[0,0]", "parse_json", "comma", "", 0]
 4545.   3294
 4546.   3294                        test_cause("comma");
 4547.   3294                        break;
 4548.   3294                    }
 4549.   3294                    advance(",");
 4550.   3294                }
 4551.   1648            }
 4552.   1648            advance("]", container);
 4553.   1648            return container;
 4554.    509        case "false":
 4555.    511        case "null":
 4556.    896        case "true":
 4557.    896
 4558.    896// test_cause:
 4559.    896// ["[false]", "parse_json", "constant", "", 0]
 4560.    896// ["[null]", "parse_json", "constant", "", 0]
 4561.    896// ["[true]", "parse_json", "constant", "", 0]
 4562.    896
 4563.    896            test_cause("constant");
 4564.    896            advance();
 4565.    896            return token_now;
 4566.   3375        case "{":
 4567.   3375
 4568.   3375// test_cause:
 4569.   3375// ["{}", "parse_json", "brace", "", 0]
 4570.   3375
 4571.   3375            test_cause("brace");
 4572.   3375            container = token_nxt;
 4573.   3375
 4574.   3375// Explicit empty-object required to detect "__proto__".
 4575.   3375
 4576.   3375            is_dup = empty();
 4577.   3375            container.expression = [];
 4578.   3375            advance("{");
 4579.   3375            if (token_nxt.id !== "}") {
 4580.   3375
 4581.   3375// JSON
 4582.   3375// Parse/loop through each property in {...}.
 4583.   3375
 4584.   9624                while (true) {
 4585.   9624                    if (token_nxt.quote !== "\"") {
 4586.   9624
 4587.   9624// test_cause:
 4588.   9624// ["{0:0}", "parse_json", "unexpected_a", "0", 2]
 4589.   9624
 4590.   9624                        warn(
 4591.   9624                            "unexpected_a",
 4592.   9624                            token_nxt,
 4593.   9624                            token_nxt.quote
 4594.   9624                        );
 4595.   9624                    }
 4596.   9624                    name = token_nxt;
 4597.   9624                    advance("(string)");
 4598.   9624                    if (is_dup[token_now.value] !== undefined) {
 4599.   9624
 4600.   9624// test_cause:
 4601.   9624// ["{\"aa\":0,\"aa\":0}", "parse_json", "duplicate_a", "aa", 9]
 4602.   9624
 4603.   9624                        warn("duplicate_a", token_now);
 4604.   9624                    } else if (token_now.value === "__proto__") {
 4605.   9624
 4606.   9624// test_cause:
 4607.   9624// ["{\"__proto__\":0}", "parse_json", "weird_property_a", "__proto__", 2]
 4608.   9624
 4609.   9624                        warn("weird_property_a", token_now);
 4610.   9624                    } else {
 4611.   9624                        is_dup[token_now.value] = token_now;
 4612.   9624                    }
 4613.   9624                    advance(":");
 4614.   9624                    container.expression.push(
 4615.   9624
 4616.   9624// Recurse parse_json().
 4617.   9624
 4618.   9624                        Object.assign(parse_json(), {
 4619.   9624                            label: name
 4620.   9624                        })
 4621.   9624                    );
 4622.   9624                    if (token_nxt.id !== ",") {
 4623.   9624                        break;
 4624.   9624                    }
 4625.   9624                    advance(",");
 4626.   9624                }
 4627.   3375            }
 4628.   3375            advance("}", container);
 4629.   3375            return container;
 4630.      5        default:
 4631.      5
 4632.      5// test_cause:
 4633.      5// ["[undefined]", "parse_json", "unexpected_a", "undefined", 2]
 4634.      5
 4635.      5            stop("unexpected_a");
 4636.  12943        }
 4637.  12943    }
 4638.    591
 4639.  19773    function parse_statement() {
 4640.  19773
 4641.  19773// Parse a statement. Any statement may have a label, but only four statements
 4642.  19773// have use for one. A statement can be one of the standard statements, or
 4643.  19773// an assignment expression, or an invocation expression.
 4644.  19773
 4645.  19773        let first;
 4646.  19773        let the_label;
 4647.  19773        let the_statement;
 4648.  19773        let the_symbol;
 4649.  19773        advance();
 4650.  19592        if (token_now.identifier && token_nxt.id === ":") {
 4651.     13            the_label = token_now;
 4652.     13            if (the_label.id === "ignore") {
 4653.     13
 4654.     13// test_cause:
 4655.     13// ["ignore:", "parse_statement", "unexpected_a", "ignore", 1]
 4656.     13
 4657.     13                warn("unexpected_a", the_label);
 4658.     13            }
 4659.     13            advance(":");
 4660.     13            switch (token_nxt.id) {
 4661.     13            case "do":
 4662.     13            case "for":
 4663.     13            case "switch":
 4664.     13            case "while":
 4665.     13
 4666.     13// test_cause:
 4667.     13// ["aa:do{}", "parse_statement", "the_statement_label", "do", 0]
 4668.     13// ["aa:for{}", "parse_statement", "the_statement_label", "for", 0]
 4669.     13// ["aa:switch{}", "parse_statement", "the_statement_label", "switch", 0]
 4670.     13// ["aa:while{}", "parse_statement", "the_statement_label", "while", 0]
 4671.     13
 4672.     13                test_cause("the_statement_label", token_nxt.id);
 4673.     13                enroll(the_label, "label", true);
 4674.     13                the_label.dead = false;
 4675.     13                the_label.init = true;
 4676.     13                the_statement = parse_statement();
 4677.     13                functionage.statement_prv = the_statement;
 4678.     13                the_statement.label = the_label;
 4679.     13                the_statement.statement = true;
 4680.     13                return the_statement;
 4681.     13            }
 4682.     13            advance();
 4683.     13
 4684.     13// test_cause:
 4685.     13// ["aa:", "parse_statement", "unexpected_label_a", "aa", 1]
 4686.     13
 4687.     13            warn("unexpected_label_a", the_label);
 4688.  19764        }
 4689.  19764
 4690.  19764// Parse the statement.
 4691.  19764
 4692.  19764        first = token_now;
 4693.  19764        first.statement = true;
 4694.  19764        the_symbol = syntax_dict[first.id];
 4695.  19764        if (
 4696.  19764            the_symbol !== undefined
 4697.  19764            && the_symbol.fud !== undefined
 4698.  19773
 4699.  19773// PR-318 - Bugfix - Fixes issues #316, #317 - dynamic-import().
 4700.  19773
 4701.   9617            && !(the_symbol.id === "import" && token_nxt.id === "(")
 4702.   9615        ) {
 4703.   9615            the_symbol.disrupt = false;
 4704.   9615            the_symbol.statement = true;
 4705.   9615            token_now.arity = "statement";
 4706.   9615            the_statement = the_symbol.fud();
 4707.   9615            functionage.statement_prv = the_statement;
 4708.  10149        } else {
 4709.  10149
 4710.  10149// It is an expression statement.
 4711.  10149
 4712.  10149            the_statement = parse_expression(0, true);
 4713.  10149            functionage.statement_prv = the_statement;
 4714.  10149            if (the_statement.wrapped && the_statement.id !== "(") {
 4715.  10149
 4716.  10149// test_cause:
 4717.  10149// ["(0)", "parse_statement", "unexpected_a", "(", 1]
 4718.  10149
 4719.  10149                warn("unexpected_a", first);
 4720.  10149            }
 4721.  10149            semicolon();
 4722.  19664        }
 4723.  19664        if (the_label !== undefined) {
 4724.      1            the_label.dead = true;
 4725.  19664        }
 4726.  19664        return the_statement;
 4727.  19664    }
 4728.    591
 4729.   7150    function parse_statements() {
 4730.   7150
 4731.   7150// Parse a list of statements. Give a warning if an unreachable statement
 4732.   7150// follows a disruptive statement.
 4733.   7150
 4734.   7150        const statement_list = [];
 4735.   7150        let a_statement;
 4736.   7150        let disrupt = false;
 4737.   7150
 4738.   7150// Parse/loop each statement until a statement-terminator is reached.
 4739.   7150
 4740.  26488        while (true) {
 4741.  26488            switch (token_nxt.id) {
 4742.  26488            case "(end)":
 4743.  26488            case "case":
 4744.  26488            case "default":
 4745.  26488            case "else":
 4746.  26488            case "}":
 4747.  26488
 4748.  26488// test_cause:
 4749.  26488// [";", "parse_statements", "closer", "", 0]
 4750.  26488// ["case", "parse_statements", "closer", "", 0]
 4751.  26488// ["default", "parse_statements", "closer", "", 0]
 4752.  26488// ["else", "parse_statements", "closer", "", 0]
 4753.  26488// ["}", "parse_statements", "closer", "", 0]
 4754.  26488
 4755.  26488                test_cause("closer");
 4756.  26488                return statement_list;
 4757.  26488            }
 4758.  26488            a_statement = parse_statement();
 4759.  26488            statement_list.push(a_statement);
 4760.  26488            if (disrupt) {
 4761.  26488
 4762.  26488// test_cause:
 4763.  26488// ["while(0){break;0;}", "parse_statements", "unreachable_a", "0", 16]
 4764.  26488
 4765.  26488                warn("unreachable_a", a_statement);
 4766.  26488            }
 4767.  26488            disrupt = a_statement.disrupt;
 4768.  26488        }
 4769.   7150    }
 4770.    591
 4771.   1182    function postassign(id) {
 4772.   1182
 4773.   1182// Create one of the postassign operators.
 4774.   1182
 4775.   1182        const the_symbol = symbol(id, 150);
 4776.      1        the_symbol.led = function (left) {
 4777.      1            token_now.expression = left;
 4778.      1            token_now.arity = "postassign";
 4779.      1            check_mutation(token_now.expression);
 4780.      1            return token_now;
 4781.      1        };
 4782.   1182        return the_symbol;
 4783.   1182    }
 4784.    591
 4785.   1182    function preassign(id) {
 4786.   1182
 4787.   1182// Create one of the preassign operators.
 4788.   1182
 4789.   1182        const the_symbol = symbol(id);
 4790.      2        the_symbol.nud = function () {
 4791.      2            const the_token = token_now;
 4792.      2            the_token.arity = "preassign";
 4793.      2            the_token.expression = parse_expression(150);
 4794.      2            check_mutation(the_token.expression);
 4795.      2            return the_token;
 4796.      2        };
 4797.   1182        return the_symbol;
 4798.   1182    }
 4799.    591
 4800.  10047    function prefix(id, f) {
 4801.  10047
 4802.  10047// Create a prefix operator.
 4803.  10047
 4804.  10047        const the_symbol = symbol(id);
 4805.   4967        the_symbol.nud = function () {
 4806.   4967            const the_token = token_now;
 4807.   4967            the_token.arity = "unary";
 4808.   4211            if (typeof f === "function") {
 4809.   4211                return f();
 4810.   4211            }
 4811.    756            the_token.expression = parse_expression(150);
 4812.    756            return the_token;
 4813.    756        };
 4814.  10047        return the_symbol;
 4815.  10047    }
 4816.    591
 4817.      1    function prefix_assign_divide() {
 4818.      1
 4819.      1// test_cause:
 4820.      1// ["/=", "prefix_assign_divide", "expected_a_b", "/=", 1]
 4821.      1
 4822.      1        stop("expected_a_b", token_now, "/\\=", "/=");
 4823.      1    }
 4824.    591
 4825.    113    function prefix_async() {
 4826.    113        let the_async;
 4827.    113        let the_function;
 4828.    113        the_async = token_now;
 4829.    113        advance("function");
 4830.    113        the_function = Object.assign(token_now, {
 4831.    113            arity: the_async.arity,
 4832.    113            async: 1
 4833.    113        });
 4834.    113        prefix_function();
 4835.      1        if (the_function.async === 1) {
 4836.      1
 4837.      1// test_cause:
 4838.      1// ["
 4839.      1// async function aa(){}
 4840.      1// ", "prefix_async", "missing_await_statement", "function", 7]
 4841.      1
 4842.      1            warn("missing_await_statement", the_function);
 4843.      1        }
 4844.    113        return the_function;
 4845.    113    }
 4846.    591
 4847.    260    function prefix_await() {
 4848.    260        const the_await = token_now;
 4849.      3        if (functionage.async === 0) {
 4850.      3
 4851.      3// test_cause:
 4852.      3// ["await", "prefix_await", "unexpected_a", "await", 1]
 4853.      3// ["function aa(){aa=await 0;}", "prefix_await", "unexpected_a", "await", 18]
 4854.      3// ["function aa(){await 0;}", "prefix_await", "unexpected_a", "await", 15]
 4855.      3
 4856.      3            warn("unexpected_a", the_await);
 4857.    257        } else {
 4858.    257            functionage.async += 1;
 4859.    257        }
 4860.    160        if (the_await.arity === "statement") {
 4861.    160            the_await.block = parse_expression();
 4862.    160            semicolon();
 4863.    160        } else {
 4864.    100            the_await.expression = parse_expression();
 4865.    259        }
 4866.    259        return the_await;
 4867.    259    }
 4868.    591
 4869.      1    function prefix_fart() {
 4870.      1
 4871.      1// test_cause:
 4872.      1// ["=>0", "prefix_fart", "expected_a_before_b", "=>", 1]
 4873.      1
 4874.      1        return stop("expected_a_before_b", token_now, "()", "=>");
 4875.      1    }
 4876.    591
 4877.   1841    function prefix_function(the_function) {
 4878.     11        let name = the_function && the_function.name;
 4879.   1830        if (the_function === undefined) {
 4880.   1830            the_function = token_now;
 4881.   1830
 4882.   1830// A function statement must have a name that will be in the parent's scope.
 4883.   1830
 4884.   1830            if (the_function.arity === "statement") {
 4885.   1830                if (!token_nxt.identifier) {
 4886.   1830
 4887.   1830// test_cause:
 4888.   1830// ["function(){}", "prefix_function", "expected_identifier_a", "(", 9]
 4889.   1830// ["function*aa(){}", "prefix_function", "expected_identifier_a", "*", 9]
 4890.   1830
 4891.   1830                    return stop("expected_identifier_a");
 4892.   1830                }
 4893.   1830                name = token_nxt;
 4894.   1830                enroll(name, "variable", true);
 4895.   1830                the_function.name = Object.assign(name, {
 4896.   1830                    calls: empty(),
 4897.   1830
 4898.   1830// PR-331 - Bugfix - Fixes issue #272 - function hoisting not allowed.
 4899.   1830
 4900.   1830                    dead: false,
 4901.   1830                    init: true
 4902.   1830                });
 4903.   1830                advance();
 4904.   1830            } else if (name === undefined) {
 4905.   1830
 4906.   1830// A function expression may have an optional name.
 4907.   1830
 4908.   1830                the_function.name = anon;
 4909.   1830                if (token_nxt.identifier) {
 4910.   1830                    name = token_nxt;
 4911.   1830                    the_function.name = name;
 4912.   1830                    advance();
 4913.   1830                }
 4914.   1830            }
 4915.   1839        }
 4916.   1839        the_function.level = functionage.level + 1;
 4917.   1839
 4918.   1839//  Probably deadcode.
 4919.   1839//  if (mode_mega) {
 4920.   1839//      warn("unexpected_a", the_function);
 4921.   1839//  }
 4922.   1839//  jslint_assert(!mode_mega, `Expected !mode_mega.`);
 4923.   1839
 4924.   1839// Don't create functions in loops. It is inefficient, and it can lead to
 4925.   1839// scoping errors.
 4926.   1839
 4927.   1839        if (functionage.loop > 0) {
 4928.      1
 4929.      1// test_cause:
 4930.      1// ["
 4931.      1// while(0){aa.map(function(){});}
 4932.      1// ", "prefix_function", "function_in_loop", "function", 17]
 4933.      1
 4934.      1            warn("function_in_loop", the_function);
 4935.   1839        }
 4936.   1839
 4937.   1839// Give the function properties for storing its names and for observing the
 4938.   1839// depth of loops and switches.
 4939.   1839
 4940.   1839        Object.assign(the_function, {
 4941.   1839            async: the_function.async || 0,
 4942.   1841            context: empty(),
 4943.   1841            finally: 0,
 4944.   1841            loop: 0,
 4945.   1841            statement_prv: undefined,
 4946.   1841            switch: 0,
 4947.   1841            try: 0
 4948.   1841        });
 4949.    801        if (the_function.arity !== "statement" && typeof name === "object") {
 4950.     38
 4951.     38// test_cause:
 4952.     38// ["let aa=function bb(){return;};", "prefix_function", "expression", "", 0]
 4953.     38
 4954.     38            test_cause("expression");
 4955.     38            enroll(name, "function", true);
 4956.     38            name.dead = false;
 4957.     38            name.init = true;
 4958.     38            name.used = 1;
 4959.   1839        }
 4960.   1839
 4961.   1839// Bugfix - fix function-redefinitions not warned inside function-calls.
 4962.   1839// Push the current function context and establish a new one.
 4963.   1839
 4964.   1839        function_stack.push(functionage);
 4965.   1839        function_list.push(the_function);
 4966.   1839        functionage = the_function;
 4967.   1839
 4968.   1839// Parse the parameter list.
 4969.   1839
 4970.   1839        advance("(");
 4971.   1839
 4972.   1839// test_cause:
 4973.   1839// ["function aa(){}", "prefix_function", "opener", "", 0]
 4974.   1839
 4975.   1839        test_cause("opener");
 4976.   1839        token_now.free = false;
 4977.   1839        token_now.arity = "function";
 4978.   1839        [functionage.parameters, functionage.signature] = prefix_function_arg();
 4979.   2513        functionage.parameters.forEach(function enroll_parameter(name) {
 4980.   2288            if (name.identifier) {
 4981.   2288                enroll(name, "parameter", false);
 4982.   2288            } else {
 4983.   1839                name.names.forEach(enroll_parameter);
 4984.   1839            }
 4985.   2513        });
 4986.   1839
 4987.   1839// The function's body is a block.
 4988.   1839
 4989.   1839        the_function.block = block("body");
 4990.   1839        if (
 4991.   1839            the_function.arity === "statement"
 4992.   1839            && token_nxt.line === token_now.line
 4993.      2        ) {
 4994.      2
 4995.      2// test_cause:
 4996.      2// ["function aa(){}0", "prefix_function", "unexpected_a", "0", 16]
 4997.      2
 4998.      2            return stop("unexpected_a");
 4999.   1826        }
 5000.   1826        if (
 5001.   1826            token_nxt.id === "."
 5002.   1826            || token_nxt.id === "?."
 5003.   1824            || token_nxt.id === "["
 5004.      3        ) {
 5005.      3
 5006.      3// test_cause:
 5007.      3// ["function aa(){}\n.aa", "prefix_function", "unexpected_a", ".", 1]
 5008.      3// ["function aa(){}\n?.aa", "prefix_function", "unexpected_a", "?.", 1]
 5009.      3// ["function aa(){}\n[]", "prefix_function", "unexpected_a", "[", 1]
 5010.      3
 5011.      3            warn("unexpected_a");
 5012.   1826        }
 5013.   1826
 5014.   1826// Check functions are ordered.
 5015.   1826
 5016.   1826        check_ordered(
 5017.   1826            "function",
 5018.   1826            function_list.slice(
 5019.   1826                function_list.indexOf(the_function) + 1
 5020.   2311            ).map(function ({
 5021.   2311                level,
 5022.   2311                name
 5023.   2311            }) {
 5024.   1826                return (level === the_function.level + 1) && name;
 5025.   2311            }).filter(function (name) {
 5026.   1826                return option_dict.beta && name && name.id;
 5027.   2311            })
 5028.   1826        );
 5029.   1826
 5030.   1826// Restore the previous context.
 5031.   1826
 5032.   1826        functionage = function_stack.pop();
 5033.   1826        return the_function;
 5034.   1826    }
 5035.    591
 5036.   1847    function prefix_function_arg() {
 5037.   1847        const list = [];
 5038.   1847        const signature = ["("];
 5039.   1847        let optional;
 5040.   1847        let subparam;
 5041.   1912        function parameter() {
 5042.   1912            let ellipsis = false;
 5043.   1912            let param;
 5044.    198            if (token_nxt.id === "{") {
 5045.    198                if (optional !== undefined) {
 5046.    198
 5047.    198// test_cause:
 5048.    198// ["function aa(aa=0,{}){}", "parameter", "required_a_optional_b", "aa", 18]
 5049.    198
 5050.    198                    warn(
 5051.    198                        "required_a_optional_b",
 5052.    198                        token_nxt,
 5053.    198                        token_nxt.id,
 5054.    198                        optional.id
 5055.    198                    );
 5056.    198                }
 5057.    198                param = token_nxt;
 5058.    198                param.names = [];
 5059.    198                advance("{");
 5060.    198                signature.push("{");
 5061.    548                while (true) {
 5062.    548                    subparam = token_nxt;
 5063.    548                    if (!subparam.identifier) {
 5064.    548
 5065.    548// test_cause:
 5066.    548// ["function aa(aa=0,{}){}", "parameter", "expected_identifier_a", "}", 19]
 5067.    548// ["function aa({0}){}", "parameter", "expected_identifier_a", "0", 14]
 5068.    548
 5069.    548                        return stop("expected_identifier_a");
 5070.    548                    }
 5071.    548                    survey(subparam);
 5072.    548                    advance();
 5073.    548                    signature.push(subparam.id);
 5074.    548                    if (token_nxt.id === ":") {
 5075.    548                        advance(":");
 5076.    548                        advance();
 5077.    548                        token_now.label = subparam;
 5078.    548                        subparam = token_now;
 5079.    548                        if (!subparam.identifier) {
 5080.    548
 5081.    548// test_cause:
 5082.    548// ["function aa({aa:0}){}", "parameter", "expected_identifier_a", "}", 18]
 5083.    548
 5084.    548                            return stop(
 5085.    548                                "expected_identifier_a",
 5086.    548                                token_nxt
 5087.    548                            );
 5088.    548                        }
 5089.    548                    }
 5090.    548
 5091.    548// test_cause:
 5092.    548// ["function aa({aa=aa},aa){}", "parameter", "equal", "", 0]
 5093.    548
 5094.    548                    test_cause("equal");
 5095.    548                    if (token_nxt.id === "=") {
 5096.    548                        advance("=");
 5097.    548                        subparam.expression = parse_expression();
 5098.    548                        param.open = true;
 5099.    548                    }
 5100.    548                    param.names.push(subparam);
 5101.    548                    if (token_nxt.id === ",") {
 5102.    548                        advance(",");
 5103.    548                        signature.push(", ");
 5104.    548                    } else {
 5105.    548                        break;
 5106.    548                    }
 5107.    548                }
 5108.    198                list.push(param);
 5109.    198
 5110.    198// test_cause:
 5111.    198// ["
 5112.    198// function aa({bb,aa}){}
 5113.    198// ", "check_ordered", "expected_a_b_before_c_d", "aa", 17]
 5114.    198
 5115.    198                check_ordered("parameter", param.names);
 5116.    198                advance("}");
 5117.    198                signature.push("}");
 5118.    198                if (token_nxt.id === ",") {
 5119.    198                    advance(",");
 5120.    198                    signature.push(", ");
 5121.    198                    return parameter();
 5122.    198                }
 5123.   1714            } else if (token_nxt.id === "[") {
 5124.   1714                if (optional !== undefined) {
 5125.   1714
 5126.   1714// test_cause:
 5127.   1714// ["function aa(aa=0,[]){}", "parameter", "required_a_optional_b", "aa", 18]
 5128.   1714
 5129.   1714                    warn(
 5130.   1714                        "required_a_optional_b",
 5131.   1714                        token_nxt,
 5132.   1714                        token_nxt.id,
 5133.   1714                        optional.id
 5134.   1714                    );
 5135.   1714                }
 5136.   1714                param = token_nxt;
 5137.   1714                param.names = [];
 5138.   1714                advance("[");
 5139.   1714                signature.push("[]");
 5140.   1714                while (true) {
 5141.   1714                    subparam = token_nxt;
 5142.   1714                    if (!subparam.identifier) {
 5143.   1714
 5144.   1714// test_cause:
 5145.   1714// ["function aa(aa=0,[]){}", "parameter", "expected_identifier_a", "]", 19]
 5146.   1714
 5147.   1714                        return stop("expected_identifier_a");
 5148.   1714                    }
 5149.   1714                    advance();
 5150.   1714                    param.names.push(subparam);
 5151.   1714
 5152.   1714// test_cause:
 5153.   1714// ["function aa([aa=aa],aa){}", "parameter", "id", "", 0]
 5154.   1714
 5155.   1714                    test_cause("id");
 5156.   1714                    if (token_nxt.id === "=") {
 5157.   1714                        advance("=");
 5158.   1714                        subparam.expression = parse_expression();
 5159.   1714                        param.open = true;
 5160.   1714                    }
 5161.   1714                    if (token_nxt.id === ",") {
 5162.   1714                        advance(",");
 5163.   1714                    } else {
 5164.   1714                        break;
 5165.   1714                    }
 5166.   1714                }
 5167.   1714                list.push(param);
 5168.   1714                advance("]");
 5169.   1714                if (token_nxt.id === ",") {
 5170.   1714                    advance(",");
 5171.   1714                    signature.push(", ");
 5172.   1714                    return parameter();
 5173.   1714                }
 5174.   1714            } else {
 5175.   1714                if (token_nxt.id === "...") {
 5176.   1714                    ellipsis = true;
 5177.   1714                    signature.push("...");
 5178.   1714                    advance("...");
 5179.   1714                    if (optional !== undefined) {
 5180.   1714
 5181.   1714// test_cause:
 5182.   1714// ["function aa(aa=0,...){}", "parameter", "required_a_optional_b", "aa", 21]
 5183.   1714
 5184.   1714                        warn(
 5185.   1714                            "required_a_optional_b",
 5186.   1714                            token_nxt,
 5187.   1714                            token_nxt.id,
 5188.   1714                            optional.id
 5189.   1714                        );
 5190.   1714                    }
 5191.   1714                }
 5192.   1714                if (!token_nxt.identifier) {
 5193.   1714
 5194.   1714// test_cause:
 5195.   1714// ["function aa(0){}", "parameter", "expected_identifier_a", "0", 13]
 5196.   1714
 5197.   1714                    return stop("expected_identifier_a");
 5198.   1714                }
 5199.   1714                param = token_nxt;
 5200.   1714                list.push(param);
 5201.   1714                advance();
 5202.   1714                signature.push(param.id);
 5203.   1714                if (ellipsis) {
 5204.   1714                    param.ellipsis = true;
 5205.   1714                } else {
 5206.   1714                    if (token_nxt.id === "=") {
 5207.   1714                        optional = param;
 5208.   1714                        advance("=");
 5209.   1714                        param.expression = parse_expression(0);
 5210.   1714                    } else {
 5211.   1714                        if (optional !== undefined) {
 5212.   1714
 5213.   1714// test_cause:
 5214.   1714// ["function aa(aa=0,bb){}", "parameter", "required_a_optional_b", "aa", 18]
 5215.   1714
 5216.   1714                            warn(
 5217.   1714                                "required_a_optional_b",
 5218.   1714                                param,
 5219.   1714                                param.id,
 5220.   1714                                optional.id
 5221.   1714                            );
 5222.   1714                        }
 5223.   1714                    }
 5224.   1714                    if (token_nxt.id === ",") {
 5225.   1714                        advance(",");
 5226.   1714                        signature.push(", ");
 5227.   1714                        return parameter();
 5228.   1714                    }
 5229.   1714                }
 5230.   1714            }
 5231.   1912        }
 5232.   1359        if (token_nxt.id !== ")" && token_nxt.id !== "(end)") {
 5233.   1359            parameter();
 5234.   1839        }
 5235.   1839        advance(")");
 5236.   1839        signature.push(")");
 5237.   1839        return [list, signature.join("")];
 5238.   1839    }
 5239.    591
 5240.    485    function prefix_lbrace() {
 5241.    485        const seen = empty();
 5242.    485        const the_brace = token_now;
 5243.    485        let extra;
 5244.    485        let full;
 5245.    485        let id;
 5246.    485        let name;
 5247.    485        let the_colon;
 5248.    485        let value;
 5249.    485        the_brace.expression = [];
 5250.    445        if (token_nxt.id !== "}") {
 5251.    445
 5252.    445// Parse/loop through each property in {...}.
 5253.    445
 5254.   1632            while (true) {
 5255.   1632                name = token_nxt;
 5256.   1632                advance();
 5257.   1632                if (
 5258.   1632                    (name.id === "get" || name.id === "set")
 5259.   1632                    && token_nxt.identifier
 5260.   1632                ) {
 5261.   1632                    if (!option_dict.getset) {
 5262.   1632
 5263.   1632// test_cause:
 5264.   1632// ["aa={get aa(){}}", "prefix_lbrace", "unexpected_a", "get", 5]
 5265.   1632
 5266.   1632                        warn("unexpected_a", name);
 5267.   1632                    }
 5268.   1632                    extra = name.id;
 5269.   1632                    full = extra + " " + token_nxt.id;
 5270.   1632                    name = token_nxt;
 5271.   1632                    advance();
 5272.   1632                    id = survey(name);
 5273.   1632                    if (seen[full] === true || seen[id] === true) {
 5274.   1632
 5275.   1632// test_cause:
 5276.   1632// ["aa={get aa(){},get aa(){}}", "prefix_lbrace", "duplicate_a", "aa", 20]
 5277.   1632
 5278.   1632                        warn("duplicate_a", name);
 5279.   1632                    }
 5280.   1632                    seen[id] = false;
 5281.   1632                    seen[full] = true;
 5282.   1632                } else if (name.id === "`") {
 5283.   1632
 5284.   1632// test_cause:
 5285.   1632// ["aa={`aa`:0}", "prefix_lbrace", "unexpected_a", "`", 5]
 5286.   1632
 5287.   1632                    stop("unexpected_a", name);
 5288.   1632
 5289.   1632                } else {
 5290.   1632                    id = survey(name);
 5291.   1632                    if (typeof seen[id] === "boolean") {
 5292.   1632
 5293.   1632// test_cause:
 5294.   1632// ["aa={aa,aa}", "prefix_lbrace", "duplicate_a", "aa", 8]
 5295.   1632
 5296.   1632                        warn("duplicate_a", name);
 5297.   1632                    }
 5298.   1632                    seen[id] = true;
 5299.   1632                }
 5300.   1632                if (name.identifier) {
 5301.   1632                    if (token_nxt.id === "}" || token_nxt.id === ",") {
 5302.   1632                        if (typeof extra === "string") {
 5303.   1632
 5304.   1632// test_cause:
 5305.   1632// ["aa={get aa}", "prefix_lbrace", "closer", "", 0]
 5306.   1632
 5307.   1632                            test_cause("closer");
 5308.   1632                            advance("(");
 5309.   1632                        }
 5310.   1632                        value = parse_expression(Infinity, true);
 5311.   1632                    } else if (token_nxt.id === "(") {
 5312.   1632
 5313.   1632// test_cause:
 5314.   1632// ["aa={aa()}", "prefix_lbrace", "paren", "", 0]
 5315.   1632// ["aa={get aa(){}}", "prefix_lbrace", "paren", "", 0]
 5316.   1632
 5317.   1632                        test_cause("paren");
 5318.   1632                        value = prefix_function({
 5319.   1632                            arity: "unary",
 5320.   1632                            from: name.from,
 5321.   1632                            id: "function",
 5322.   1632                            line: name.line,
 5323.   1632                            name: (
 5324.   1632                                typeof extra === "string"
 5325.   1632                                ? extra
 5326.   1632                                : id
 5327.   1632                            ),
 5328.   1632                            thru: name.from
 5329.   1632                        });
 5330.   1632                    } else {
 5331.   1632                        if (typeof extra === "string") {
 5332.   1632
 5333.   1632// test_cause:
 5334.   1632// ["aa={get aa.aa}", "prefix_lbrace", "paren", "", 0]
 5335.   1632
 5336.   1632                            test_cause("paren");
 5337.   1632                            advance("(");
 5338.   1632                        }
 5339.   1632                        the_colon = token_nxt;
 5340.   1632                        advance(":");
 5341.   1632                        value = parse_expression(0);
 5342.   1632                        if (
 5343.   1632                            value.id === name.id
 5344.   1632                            && value.id !== "function"
 5345.   1632                        ) {
 5346.   1632
 5347.   1632// test_cause:
 5348.   1632// ["aa={aa:aa}", "prefix_lbrace", "unexpected_a", ": aa", 7]
 5349.   1632
 5350.   1632                            warn("unexpected_a", the_colon, ": " + name.id);
 5351.   1632                        }
 5352.   1632                    }
 5353.   1632                    value.label = name;
 5354.   1632                    if (typeof extra === "string") {
 5355.   1632                        value.extra = extra;
 5356.   1632                    }
 5357.   1632                    the_brace.expression.push(value);
 5358.   1632                } else {
 5359.   1632
 5360.   1632// test_cause:
 5361.   1632// ["aa={\"aa\":0}", "prefix_lbrace", "colon", "", 0]
 5362.   1632
 5363.   1632                    test_cause("colon");
 5364.   1632                    advance(":");
 5365.   1632                    value = parse_expression(0);
 5366.   1632                    value.label = name;
 5367.   1632                    the_brace.expression.push(value);
 5368.   1632                }
 5369.   1632                if (token_nxt.id !== ",") {
 5370.   1632                    break;
 5371.   1632                }
 5372.   1632
 5373.   1632// test_cause:
 5374.   1632// ["aa={\"aa\":0,\"bb\":0}", "prefix_lbrace", "comma", "", 0]
 5375.   1632
 5376.   1632                test_cause("comma");
 5377.   1632                advance(",");
 5378.   1632                if (token_nxt.id === "}") {
 5379.   1632
 5380.   1632// test_cause:
 5381.   1632// ["let aa={aa:0,}", "prefix_lbrace", "unexpected_a", ",", 13]
 5382.   1632
 5383.   1632                    warn("unexpected_a", token_now);
 5384.   1632                    break;
 5385.   1632                }
 5386.   1632            }
 5387.    480        }
 5388.    480
 5389.    480// test_cause:
 5390.    480// ["aa={bb,aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
 5391.    480
 5392.    480        check_ordered(
 5393.    480            "property",
 5394.   1627            the_brace.expression.map(function ({
 5395.   1627                label
 5396.   1627            }) {
 5397.   1627                return label;
 5398.   1627            })
 5399.    480        );
 5400.    480        advance("}");
 5401.    480        return the_brace;
 5402.    480    }
 5403.    591
 5404.    651    function prefix_lbracket() {
 5405.    651        const the_token = token_now;
 5406.    651        let element;
 5407.    651        let ellipsis;
 5408.    651        the_token.expression = [];
 5409.    331        if (token_nxt.id !== "]") {
 5410.    331
 5411.    331// Parse/loop through each element in [...].
 5412.    331
 5413.   1546            while (true) {
 5414.   1546                ellipsis = false;
 5415.   1546                if (token_nxt.id === "...") {
 5416.   1546                    ellipsis = true;
 5417.   1546                    advance("...");
 5418.   1546                }
 5419.   1546                element = parse_expression(10);
 5420.   1546                if (ellipsis) {
 5421.   1546                    element.ellipsis = true;
 5422.   1546                }
 5423.   1546                the_token.expression.push(element);
 5424.   1546                if (token_nxt.id !== ",") {
 5425.   1546                    break;
 5426.   1546                }
 5427.   1546                advance(",");
 5428.   1546                if (token_nxt.id === "]") {
 5429.   1546
 5430.   1546// test_cause:
 5431.   1546// ["let aa=[0,]", "prefix_lbracket", "unexpected_a", ",", 10]
 5432.   1546
 5433.   1546                    warn("unexpected_a", token_now);
 5434.   1546                    break;
 5435.   1546                }
 5436.   1546            }
 5437.    331        }
 5438.    651        advance("]");
 5439.    651        return the_token;
 5440.    651    }
 5441.    591
 5442.   1357    function prefix_lparen() {
 5443.   1357        const cadet = lookahead().id;
 5444.   1357        const the_paren = token_now;
 5445.   1357        let the_value;
 5446.   1357
 5447.   1357// We can distinguish between a parameter list for => and a wrapped expression
 5448.   1357// with one token of lookahead.
 5449.   1357
 5450.   1357        if (
 5451.   1357            token_nxt.id === ")"
 5452.   1349            || token_nxt.id === "..."
 5453.   1349            || (token_nxt.identifier && (cadet === "," || cadet === "="))
 5454.      8        ) {
 5455.      8
 5456.      8// test_cause:
 5457.      8// ["()=>0", "prefix_lparen", "fart", "", 0]
 5458.      8
 5459.      8            test_cause("fart");
 5460.      8            the_paren.free = false;
 5461.      8            return parse_fart(prefix_function_arg());
 5462.   1349        }
 5463.   1349
 5464.   1349// test_cause:
 5465.   1349// ["(0)", "prefix_lparen", "expr", "", 0]
 5466.   1349
 5467.   1349        test_cause("expr");
 5468.   1349        the_paren.free = true;
 5469.   1349        the_value = parse_expression(0);
 5470.   1349        if (the_value.wrapped === true) {
 5471.      1
 5472.      1// test_cause:
 5473.      1// ["((0))", "prefix_lparen", "unexpected_a", "(", 1]
 5474.      1
 5475.      1            warn("unexpected_a", the_paren);
 5476.   1349        }
 5477.   1349        the_value.wrapped = true;
 5478.   1349        advance(")", the_paren);
 5479.   1349        if (token_nxt.id === "=>") {
 5480.      7            if (the_value.arity !== "variable") {
 5481.      7                if (the_value.id === "{" || the_value.id === "[") {
 5482.      7
 5483.      7// test_cause:
 5484.      7// ["([])=>0", "prefix_lparen", "expected_a_before_b", "(", 1]
 5485.      7// ["({})=>0", "prefix_lparen", "expected_a_before_b", "(", 1]
 5486.      7
 5487.      7                    warn("expected_a_before_b", the_paren, "function", "(");
 5488.      7
 5489.      7// test_cause:
 5490.      7// ["([])=>0", "prefix_lparen", "expected_a_b", "=>", 5]
 5491.      7// ["({})=>0", "prefix_lparen", "expected_a_b", "=>", 5]
 5492.      7
 5493.      7                    return stop("expected_a_b", token_nxt, "{", "=>");
 5494.      7                }
 5495.      7
 5496.      7// test_cause:
 5497.      7// ["(0)=>0", "prefix_lparen", "expected_identifier_a", "0", 2]
 5498.      7
 5499.      7                return stop("expected_identifier_a", the_value);
 5500.      7            }
 5501.      7            the_paren.expression = [the_value];
 5502.      7            return parse_fart([the_paren.expression, "(" + the_value.id + ")"]);
 5503.   1341        }
 5504.   1341        return the_value;
 5505.   1341    }
 5506.    591
 5507.    123    function prefix_new() {
 5508.    123        const the_new = token_now;
 5509.    123        let right;
 5510.    123        right = parse_expression(160);
 5511.      1        if (token_nxt.id !== "(") {
 5512.      1
 5513.      1// test_cause:
 5514.      1// ["new aa", "prefix_new", "expected_a_before_b", "(end)", 1]
 5515.      1
 5516.      1            warn("expected_a_before_b", token_nxt, "()", artifact());
 5517.      1        }
 5518.    123        the_new.expression = right;
 5519.    123        return the_new;
 5520.    123    }
 5521.    591
 5522.    702    function prefix_tick() {
 5523.    702        const the_tick = token_now;
 5524.    702        the_tick.value = [];
 5525.    702        the_tick.expression = [];
 5526.    702        if (token_nxt.id !== "`") {
 5527.    702
 5528.    702// Parse/loop through each token in `${...}`.
 5529.    702
 5530.   1327            while (true) {
 5531.   1327                advance("(string)");
 5532.   1327                the_tick.value.push(token_now);
 5533.   1327                if (token_nxt.id !== "${") {
 5534.   1327                    break;
 5535.   1327                }
 5536.   1327                advance("${");
 5537.   1327
 5538.   1327// test_cause:
 5539.   1327// ["let aa=`${}`;", "prefix_tick", "${", "", 0]
 5540.   1327
 5541.   1327                test_cause("${");
 5542.   1327                the_tick.expression.push(parse_expression(0));
 5543.   1327                advance("}");
 5544.   1327            }
 5545.    700        }
 5546.    700        advance("`");
 5547.    700        return the_tick;
 5548.    700    }
 5549.    591
 5550.      2    function prefix_void() {
 5551.      2        const the_void = token_now;
 5552.      2
 5553.      2// test_cause:
 5554.      2// ["void 0", "prefix_void", "unexpected_a", "void", 1]
 5555.      2// ["void", "prefix_void", "unexpected_a", "void", 1]
 5556.      2
 5557.      2        warn("unexpected_a", the_void);
 5558.      2        the_void.expression = parse_expression(0);
 5559.      2        return the_void;
 5560.      2    }
 5561.    591
 5562.  12545    function semicolon() {
 5563.  12545
 5564.  12545// Try to match a semicolon.
 5565.  12545
 5566.  12327        if (token_nxt.id === ";") {
 5567.  12327            advance(";");
 5568.  12327        } else {
 5569.    218
 5570.    218// test_cause:
 5571.    218// ["0", "semicolon", "expected_a_b", "(end)", 1]
 5572.    218
 5573.    218            warn_at(
 5574.    218                "expected_a_b",
 5575.    218                token_now.line,
 5576.    218                token_now.thru + 1,
 5577.    218                ";",
 5578.    218                artifact()
 5579.    218            );
 5580.    218        }
 5581.  12545        anon = "anonymous";
 5582.  12545    }
 5583.    591
 5584.  13593    function stmt(id, fud) {
 5585.  13593
 5586.  13593// Create a statement.
 5587.  13593
 5588.  13593        const the_symbol = symbol(id);
 5589.  13593        the_symbol.fud = fud;
 5590.  13593        return the_symbol;
 5591.  13593    }
 5592.    591
 5593.    959    function stmt_break() {
 5594.    959        const the_break = token_now;
 5595.    959        let the_label;
 5596.    959        if (
 5597.    688            (functionage.loop < 1 && functionage.switch < 1)
 5598.    952            || functionage.finally > 0
 5599.      7        ) {
 5600.      7
 5601.      7// test_cause:
 5602.      7// ["break", "stmt_break", "unexpected_a", "break", 1]
 5603.      7
 5604.      7            warn("unexpected_a", the_break);
 5605.      7        }
 5606.    959        the_break.disrupt = true;
 5607.      5        if (token_nxt.identifier && token_now.line === token_nxt.line) {
 5608.      5            the_label = functionage.context[token_nxt.id];
 5609.      5            if (
 5610.      5                the_label === undefined
 5611.      5                || the_label.role !== "label"
 5612.      5                || the_label.dead
 5613.      5            ) {
 5614.      5                if (the_label !== undefined && the_label.dead) {
 5615.      5
 5616.      5// test_cause:
 5617.      5// ["aa:{function aa(aa){break aa;}}", "stmt_break", "out_of_scope_a", "aa", 27]
 5618.      5
 5619.      5                    warn("out_of_scope_a");
 5620.      5                } else {
 5621.      5
 5622.      5// test_cause:
 5623.      5// ["aa:{break aa;}", "stmt_break", "not_label_a", "aa", 11]
 5624.      5
 5625.      5                    warn("not_label_a");
 5626.      5                }
 5627.      5            } else {
 5628.      5                the_label.used += 1;
 5629.      5            }
 5630.      5            the_break.label = token_nxt;
 5631.      5            advance();
 5632.      5        }
 5633.    959        advance(";");
 5634.    959        return the_break;
 5635.    959    }
 5636.    591
 5637.      2    function stmt_continue() {
 5638.      2        const the_continue = token_now;
 5639.      1        if (functionage.loop < 1 || functionage.finally > 0) {
 5640.      2
 5641.      2// test_cause:
 5642.      2// ["continue", "stmt_continue", "unexpected_a", "continue", 1]
 5643.      2// ["
 5644.      2// function aa(){while(0){try{}finally{continue}}}
 5645.      2// ", "stmt_continue", "unexpected_a", "continue", 37]
 5646.      2
 5647.      2            warn("unexpected_a", the_continue);
 5648.      2        }
 5649.      2        check_not_top_level(the_continue);
 5650.      2        the_continue.disrupt = true;
 5651.      2        warn("unexpected_a", the_continue);
 5652.      2        advance(";");
 5653.      2        return the_continue;
 5654.      2    }
 5655.    591
 5656.      3    function stmt_debugger() {
 5657.      3        const the_debug = token_now;
 5658.      1        if (!option_dict.devel) {
 5659.      1
 5660.      1// test_cause:
 5661.      1// ["debugger", "stmt_debugger", "unexpected_a", "debugger", 1]
 5662.      1
 5663.      1            warn("unexpected_a", the_debug);
 5664.      1        }
 5665.      3        semicolon();
 5666.      3        return the_debug;
 5667.      3    }
 5668.    591
 5669.     71    function stmt_delete() {
 5670.     71        const the_token = token_now;
 5671.     71        const the_value = parse_expression(0);
 5672.     71        if (
 5673.      1            (the_value.id !== "." && the_value.id !== "[")
 5674.     70            || the_value.arity !== "binary"
 5675.      1        ) {
 5676.      1
 5677.      1// test_cause:
 5678.      1// ["delete 0", "stmt_delete", "expected_a_b", "0", 8]
 5679.      1
 5680.      1            stop("expected_a_b", the_value, ".", artifact(the_value));
 5681.     70        }
 5682.     70        the_token.expression = the_value;
 5683.     70        semicolon();
 5684.     70        return the_token;
 5685.     70    }
 5686.    591
 5687.      5    function stmt_do() {
 5688.      5        const the_do = token_now;
 5689.      5        check_not_top_level(the_do);
 5690.      5        functionage.loop += 1;
 5691.      5        the_do.block = block();
 5692.      5        advance("while");
 5693.      5        the_do.expression = condition();
 5694.      5        semicolon();
 5695.      1        if (the_do.block.disrupt === true) {
 5696.      1
 5697.      1// test_cause:
 5698.      1// ["function aa(){do{break;}while(0)}", "stmt_do", "weird_loop", "do", 15]
 5699.      1
 5700.      1            warn("weird_loop", the_do);
 5701.      3        }
 5702.      3        functionage.loop -= 1;
 5703.      3        return the_do;
 5704.      3    }
 5705.    591
 5706.     22    function stmt_export() {
 5707.     22        const the_export = token_now;
 5708.     22        let the_id;
 5709.     22        let the_name;
 5710.     22        let the_thing;
 5711.     22
 5712.     22        the_export.expression = [];
 5713.     11        if (token_nxt.id === "default") {
 5714.     11            if (export_dict.default !== undefined) {
 5715.     11
 5716.     11// test_cause:
 5717.     11// ["
 5718.     11// export default 0;export default 0
 5719.     11// ", "stmt_export", "duplicate_a", "default", 25]
 5720.     11
 5721.     11                warn("duplicate_a");
 5722.     11            }
 5723.     11            advance("default");
 5724.     11            the_thing = parse_expression(0);
 5725.     11            if (
 5726.     11                the_thing.id !== "("
 5727.     11                || the_thing.expression[0].id !== "."
 5728.     11                || the_thing.expression[0].expression.id !== "Object"
 5729.     11                || the_thing.expression[0].name.id !== "freeze"
 5730.     11            ) {
 5731.     11
 5732.     11// test_cause:
 5733.     11// ["export default {}", "stmt_export", "freeze_exports", "{", 16]
 5734.     11
 5735.     11                warn("freeze_exports", the_thing);
 5736.     11
 5737.     11// PR-301 - Bugfix - Fixes issues #282 - optional-semicolon.
 5738.     11
 5739.     11            } else {
 5740.     11
 5741.     11// test_cause:
 5742.     11// ["
 5743.     11// export default Object.freeze({})
 5744.     11// ", "semicolon", "expected_a_b", "(end)", 32]
 5745.     11
 5746.     11                semicolon();
 5747.     11            }
 5748.     11            export_dict.default = the_thing;
 5749.     11            the_export.expression.push(the_thing);
 5750.     11        } else {
 5751.     11            if (token_nxt.id === "function") {
 5752.     11
 5753.     11// test_cause:
 5754.     11// ["export function aa(){}", "stmt_export", "freeze_exports", "function", 8]
 5755.     11
 5756.     11                warn("freeze_exports");
 5757.     11                the_thing = parse_statement();
 5758.     11                the_name = the_thing.name;
 5759.     11                the_id = the_name.id;
 5760.     11                the_name.used += 1;
 5761.     11                if (export_dict[the_id] !== undefined) {
 5762.     11
 5763.     11// test_cause:
 5764.     11// ["
 5765.     11// let aa;export{aa};export function aa(){}
 5766.     11// ", "stmt_export", "duplicate_a", "aa", 35]
 5767.     11
 5768.     11                    warn("duplicate_a", the_name);
 5769.     11                }
 5770.     11                export_dict[the_id] = the_thing;
 5771.     11                the_export.expression.push(the_thing);
 5772.     11                the_thing.statement = false;
 5773.     11                the_thing.arity = "unary";
 5774.     11            } else if (
 5775.     11                token_nxt.id === "var"
 5776.     11                || token_nxt.id === "let"
 5777.     11                || token_nxt.id === "const"
 5778.     11            ) {
 5779.     11
 5780.     11// test_cause:
 5781.     11// ["export const", "stmt_export", "unexpected_a", "const", 8]
 5782.     11// ["export let", "stmt_export", "unexpected_a", "let", 8]
 5783.     11// ["export var", "stmt_export", "unexpected_a", "var", 8]
 5784.     11
 5785.     11                warn("unexpected_a");
 5786.     11                parse_statement();
 5787.     11            } else if (token_nxt.id === "{") {
 5788.     11
 5789.     11// test_cause:
 5790.     11// ["export {}", "stmt_export", "advance{", "", 0]
 5791.     11
 5792.     11                test_cause("advance{");
 5793.     11                advance("{");
 5794.     11                while (true) {
 5795.     11                    if (!token_nxt.identifier) {
 5796.     11
 5797.     11// test_cause:
 5798.     11// ["export {}", "stmt_export", "expected_identifier_a", "}", 9]
 5799.     11
 5800.     11                        stop("expected_identifier_a");
 5801.     11                    }
 5802.     11                    the_id = token_nxt.id;
 5803.     11                    the_name = token_global.context[the_id];
 5804.     11                    if (the_name === undefined) {
 5805.     11
 5806.     11// test_cause:
 5807.     11// ["export {aa}", "stmt_export", "unexpected_a", "aa", 9]
 5808.     11
 5809.     11                        warn("unexpected_a");
 5810.     11                    } else {
 5811.     11                        the_name.used += 1;
 5812.     11                        if (export_dict[the_id] !== undefined) {
 5813.     11
 5814.     11// test_cause:
 5815.     11// ["let aa;export{aa,aa}", "stmt_export", "duplicate_a", "aa", 18]
 5816.     11
 5817.     11                            warn("duplicate_a");
 5818.     11                        }
 5819.     11                        export_dict[the_id] = the_name;
 5820.     11                    }
 5821.     11                    advance();
 5822.     11                    the_export.expression.push(the_thing);
 5823.     11                    if (token_nxt.id === ",") {
 5824.     11                        advance(",");
 5825.     11                    } else {
 5826.     11                        break;
 5827.     11                    }
 5828.     11                }
 5829.     11                advance("}");
 5830.     11                semicolon();
 5831.     11            } else {
 5832.     11
 5833.     11// test_cause:
 5834.     11// ["export", "stmt_export", "unexpected_a", "(end)", 1]
 5835.     11
 5836.     11                stop("unexpected_a");
 5837.     11            }
 5838.     16        }
 5839.     16        state.mode_module = true;
 5840.     16        return the_export;
 5841.     16    }
 5842.    591
 5843.     12    function stmt_for() {
 5844.     12        let first;
 5845.     12        let the_for = token_now;
 5846.      7        if (!option_dict.for) {
 5847.      7
 5848.      7// test_cause:
 5849.      7// ["for", "stmt_for", "unexpected_a", "for", 1]
 5850.      7
 5851.      7            warn("unexpected_a", the_for);
 5852.      7        }
 5853.     12        check_not_top_level(the_for);
 5854.     12        functionage.loop += 1;
 5855.     12        advance("(");
 5856.     12        token_now.free = true;
 5857.      1        if (token_nxt.id === ";") {
 5858.      1
 5859.      1// test_cause:
 5860.      1// ["for(;;){}", "stmt_for", "expected_a_b", "for (;", 1]
 5861.      1
 5862.      1            return stop("expected_a_b", the_for, "while (", "for (;");
 5863.      9        }
 5864.      9        switch (token_nxt.id) {
 5865.      9        case "const":
 5866.      1        case "let":
 5867.      1        case "var":
 5868.      1
 5869.      1// test_cause:
 5870.      1// ["for(const aa in aa){}", "stmt_for", "unexpected_a", "const", 5]
 5871.      1
 5872.      1            return stop("unexpected_a");
 5873.      8        }
 5874.      8        first = parse_expression(0);
 5875.      8        if (first.id === "in") {
 5876.      2            if (first.expression[0].arity !== "variable") {
 5877.      2
 5878.      2// test_cause:
 5879.      2// ["for(0 in aa){}", "stmt_for", "bad_assignment_a", "0", 5]
 5880.      2
 5881.      2                warn("bad_assignment_a", first.expression[0]);
 5882.      2            }
 5883.      2            the_for.name = first.expression[0];
 5884.      2            the_for.expression = first.expression[1];
 5885.      2            warn("expected_a_b", the_for, "Object.keys", "for in");
 5886.      6        } else {
 5887.      6            the_for.initial = first;
 5888.      6            advance(";");
 5889.      6            the_for.expression = parse_expression(0);
 5890.      6            advance(";");
 5891.      6            the_for.inc = parse_expression(0);
 5892.      6            if (the_for.inc.id === "++") {
 5893.      6
 5894.      6// test_cause:
 5895.      6// ["for(aa;aa;aa++){}", "stmt_for", "expected_a_b", "++", 13]
 5896.      6
 5897.      6                warn("expected_a_b", the_for.inc, "+= 1", "++");
 5898.      6            }
 5899.      8        }
 5900.      8        advance(")");
 5901.      8        the_for.block = block();
 5902.      8        if (the_for.block.disrupt === true) {
 5903.      1
 5904.      1// test_cause:
 5905.      1// ["
 5906.      1// /*jslint for*/
 5907.      1// function aa(bb,cc){for(0;0;0){break;}}
 5908.      1// ", "stmt_for", "weird_loop", "for", 20]
 5909.      1
 5910.      1            warn("weird_loop", the_for);
 5911.      8        }
 5912.      8        functionage.loop -= 1;
 5913.      8        return the_for;
 5914.      8    }
 5915.    591
 5916.   2999    function stmt_if() {
 5917.   2999        const the_if = token_now;
 5918.   2999        let the_else;
 5919.   2999        the_if.expression = condition();
 5920.   2999        the_if.block = block();
 5921.    658        if (token_nxt.id === "else") {
 5922.    658            advance("else");
 5923.    658            the_else = token_now;
 5924.    658            the_if.else = (
 5925.    658                token_nxt.id === "if"
 5926.    658                ? parse_statement()
 5927.    658                : block()
 5928.    658            );
 5929.    658
 5930.    658// test_cause:
 5931.    658// ["if(0){0}else if(0){0}", "stmt_if", "else", "", 0]
 5932.    658// ["if(0){0}else{0}", "stmt_if", "else", "", 0]
 5933.    658
 5934.    658            test_cause("else");
 5935.    658            if (the_if.block.disrupt === true) {
 5936.    658                if (the_if.else.disrupt === true) {
 5937.    658
 5938.    658// test_cause:
 5939.    658// ["if(0){break;}else{break;}", "stmt_if", "disrupt", "", 0]
 5940.    658
 5941.    658                    test_cause("disrupt");
 5942.    658                    the_if.disrupt = true;
 5943.    658                } else {
 5944.    658
 5945.    658// test_cause:
 5946.    658// ["if(0){break;}else{}", "stmt_if", "unexpected_a", "else", 14]
 5947.    658
 5948.    658                    warn("unexpected_a", the_else);
 5949.    658                }
 5950.    658            }
 5951.   2998        }
 5952.   2998        return the_if;
 5953.   2998    }
 5954.    591
 5955.     42    function stmt_import() {
 5956.     42        const the_import = token_now;
 5957.     42        let name;
 5958.     42        let names;
 5959.     42
 5960.     42// PR-347 - Disable warning "unexpected_directive_a".
 5961.     42//         if (typeof state.mode_module === "object") {
 5962.     42//
 5963.     42// // test_cause:
 5964.     42// // ["
 5965.     42// // /*global aa*/
 5966.     42// // import aa from "aa"
 5967.     42// // ", "stmt_import", "unexpected_directive_a", "global", 1]
 5968.     42//
 5969.     42//             warn(
 5970.     42//                 "unexpected_directive_a",
 5971.     42//                 state.mode_module,
 5972.     42//                 state.mode_module.directive
 5973.     42//             );
 5974.     42//         }
 5975.     42
 5976.     42        state.mode_module = true;
 5977.     38        if (token_nxt.identifier) {
 5978.     38            name = token_nxt;
 5979.     38            advance();
 5980.     38            if (name.id === "ignore") {
 5981.     38
 5982.     38// test_cause:
 5983.     38// ["import ignore from \"aa\"", "stmt_import", "unexpected_a", "ignore", 8]
 5984.     38
 5985.     38                warn("unexpected_a", name);
 5986.     38            }
 5987.     38            enroll(name, "variable", true);
 5988.     38            the_import.name = name;
 5989.     38        } else {
 5990.      4            names = [];
 5991.      4            advance("{");
 5992.      4            if (token_nxt.id !== "}") {
 5993.      4                while (true) {
 5994.      4                    if (!token_nxt.identifier) {
 5995.      4
 5996.      4// test_cause:
 5997.      4// ["import {", "stmt_import", "expected_identifier_a", "(end)", 1]
 5998.      4
 5999.      4                        stop("expected_identifier_a");
 6000.      4                    }
 6001.      4                    name = token_nxt;
 6002.      4                    advance();
 6003.      4                    if (name.id === "ignore") {
 6004.      4
 6005.      4// test_cause:
 6006.      4// ["import {ignore} from \"aa\"", "stmt_import", "unexpected_a", "ignore", 9]
 6007.      4
 6008.      4                        warn("unexpected_a", name);
 6009.      4                    }
 6010.      4                    enroll(name, "variable", true);
 6011.      4                    names.push(name);
 6012.      4                    if (token_nxt.id !== ",") {
 6013.      4                        break;
 6014.      4                    }
 6015.      4                    advance(",");
 6016.      4                }
 6017.      4            }
 6018.      4            advance("}");
 6019.      4            the_import.name = names;
 6020.     41        }
 6021.     41        advance("from");
 6022.     41        advance("(string)");
 6023.     41        the_import.import = token_now;
 6024.     41        if (!(
 6025.     41            // rx_module
 6026.     41            /^[a-zA-Z0-9_$:.@\-\/]+$/
 6027.     41        ).test(token_now.value)) {
 6028.      1
 6029.      1// test_cause:
 6030.      1// ["import aa from \"!aa\"", "stmt_import", "bad_module_name_a", "!aa", 16]
 6031.      1
 6032.      1            warn("bad_module_name_a", token_now);
 6033.     41        }
 6034.     41        import_list.push(token_now.value);
 6035.     41        semicolon();
 6036.     41        return the_import;
 6037.     41    }
 6038.    591
 6039.      5    function stmt_lbrace() {
 6040.      5
 6041.      5// test_cause:
 6042.      5// [";{}", "stmt_lbrace", "naked_block", "{", 2]
 6043.      5// ["class aa{}", "stmt_lbrace", "naked_block", "{", 9]
 6044.      5
 6045.      5        warn("naked_block", token_now);
 6046.      5        return block("naked");
 6047.      5    }
 6048.    591
 6049.   1673    function stmt_return() {
 6050.   1673        const the_return = token_now;
 6051.   1673        check_not_top_level(the_return);
 6052.      1        if (functionage.finally > 0) {
 6053.      1
 6054.      1// test_cause:
 6055.      1// ["
 6056.      1// function aa(){try{}finally{return;}}
 6057.      1// ", "stmt_return", "unexpected_a", "return", 28]
 6058.      1
 6059.      1            warn("unexpected_a", the_return);
 6060.      1        }
 6061.   1673        the_return.disrupt = true;
 6062.   1480        if (token_nxt.id !== ";" && the_return.line === token_nxt.line) {
 6063.   1480            the_return.expression = parse_expression(10);
 6064.   1480        }
 6065.   1673        advance(";");
 6066.   1673        return the_return;
 6067.   1673    }
 6068.    591
 6069.      5    function stmt_semicolon() {
 6070.      5
 6071.      5// test_cause:
 6072.      5// [";", "stmt_semicolon", "unexpected_a", ";", 1]
 6073.      5
 6074.      5        warn("unexpected_a", token_now);
 6075.      5        return token_now;
 6076.      5    }
 6077.    591
 6078.    184    function stmt_switch() {
 6079.    184        const the_cases = [];
 6080.    184        const the_switch = token_now;
 6081.    184        let dups = [];
 6082.    184        let exp;
 6083.    184        let last;
 6084.    184        let stmts;
 6085.    184        let the_case;
 6086.    184        let the_default;
 6087.    184        let the_disrupt = true;
 6088.    184        let the_last;
 6089.  22077        function is_dup(thing) {
 6090.  22077            return is_equal(thing, exp);
 6091.  22077        }
 6092.    184        check_not_top_level(the_switch);
 6093.      1        if (functionage.finally > 0) {
 6094.      1
 6095.      1// test_cause:
 6096.      1// ["
 6097.      1// function aa(){try{}finally{switch(0){}}}
 6098.      1// ", "stmt_switch", "unexpected_a", "switch", 28]
 6099.      1
 6100.      1            warn("unexpected_a", the_switch);
 6101.      1        }
 6102.    184        functionage.switch += 1;
 6103.    184        advance("(");
 6104.    184        token_now.free = true;
 6105.    184        the_switch.expression = parse_expression(0);
 6106.    184        the_switch.block = the_cases;
 6107.    184        advance(")");
 6108.    184        advance("{");
 6109.    988        while (true) {
 6110.    988
 6111.    988// Loop through cases with breaks.
 6112.    988
 6113.    988            the_case = token_nxt;
 6114.    988            the_case.arity = "statement";
 6115.    988            the_case.expression = [];
 6116.   1478            while (true) {
 6117.   1478
 6118.   1478// Loop through fallthrough cases.
 6119.   1478
 6120.   1478                advance("case");
 6121.   1478                token_now.switch = true;
 6122.   1478                exp = parse_expression(0);
 6123.   1478                if (dups.some(is_dup)) {
 6124.   1478
 6125.   1478// test_cause:
 6126.   1478// ["
 6127.   1478// switch(0){case 0:break;case 0:break}
 6128.   1478// ", "stmt_switch", "unexpected_a", "0", 29]
 6129.   1478
 6130.   1478                    warn("unexpected_a", exp);
 6131.   1478                }
 6132.   1478                dups.push(exp);
 6133.   1478                the_case.expression.push(exp);
 6134.   1478                advance(":");
 6135.   1478                if (token_nxt.id !== "case") {
 6136.   1478                    break;
 6137.   1478                }
 6138.   1478            }
 6139.    988
 6140.    988// test_cause:
 6141.    988// ["
 6142.    988// switch(0){case 1:case 0:break;}
 6143.    988// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 23]
 6144.    988// ["
 6145.    988// switch(0){case "aa":case 0:break;}
 6146.    988// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 26]
 6147.    988// ["
 6148.    988// switch(0){case "bb":case "aa":break;}
 6149.    988// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 26]
 6150.    988// ["
 6151.    988// switch(0){case aa:case "aa":break;}
 6152.    988// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
 6153.    988// ["
 6154.    988// switch(0){case bb:case aa:break;}
 6155.    988// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
 6156.    988
 6157.    988            check_ordered_case(the_case.expression);
 6158.    988            stmts = parse_statements();
 6159.    988            if (stmts.length < 1) {
 6160.    988
 6161.    988// test_cause:
 6162.    988// ["
 6163.    988// switch(0){case 0:default:}
 6164.    988// ", "stmt_switch", "expected_statements_a", "default", 18]
 6165.    988// ["switch(0){case 0:}", "stmt_switch", "expected_statements_a", "}", 18]
 6166.    988
 6167.    988                warn("expected_statements_a");
 6168.    988
 6169.    988// PR-359 - Bugfix - Fixes issue #358 - switch-statement crashes jslint.
 6170.    988
 6171.    988                break;
 6172.    988            }
 6173.    988            the_case.block = stmts;
 6174.    988            the_cases.push(the_case);
 6175.    988            last = stmts[stmts.length - 1];
 6176.    988            if (last.disrupt) {
 6177.    988                if (last.id === "break" && last.label === undefined) {
 6178.    988                    the_disrupt = false;
 6179.    988                }
 6180.    988            } else {
 6181.    988                warn("expected_a_before_b", token_nxt, "break;", artifact());
 6182.    988            }
 6183.    988            if (token_nxt.id !== "case") {
 6184.    988                break;
 6185.    988            }
 6186.    988        }
 6187.    181
 6188.    181// test_cause:
 6189.    181// ["
 6190.    181// switch(0){case 1:break;case 0:break;}
 6191.    181// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 29]
 6192.    181// ["
 6193.    181// switch(0){case "aa":break;case 0:break;}
 6194.    181// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 32]
 6195.    181// ["
 6196.    181// switch(0){case "bb":break;case "aa":break;}
 6197.    181// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 32]
 6198.    181// ["
 6199.    181// switch(0){case aa:break;case "aa":break;}
 6200.    181// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
 6201.    181// ["
 6202.    181// switch(0){case bb:break;case aa:break;}
 6203.    181// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
 6204.    181
 6205.    983        check_ordered_case(the_cases.map(function ({
 6206.    983            expression
 6207.    983        }) {
 6208.    983            return expression[0];
 6209.    983        }));
 6210.    181        dups = undefined;
 6211.    181        if (token_nxt.id === "default") {
 6212.     86            the_default = token_nxt;
 6213.     86            advance("default");
 6214.     86            token_now.switch = true;
 6215.     86            advance(":");
 6216.     86            the_switch.else = parse_statements();
 6217.     86            if (the_switch.else.length < 1) {
 6218.     86
 6219.     86// test_cause:
 6220.     86// ["
 6221.     86// switch(0){case 0:break;default:}
 6222.     86// ", "stmt_switch", "unexpected_a", "default", 24]
 6223.     86
 6224.     86                warn("unexpected_a", the_default);
 6225.     86                the_disrupt = false;
 6226.     86            } else {
 6227.     86                the_last = the_switch.else[
 6228.     86                    the_switch.else.length - 1
 6229.     86                ];
 6230.     86                if (
 6231.     86                    the_last.id === "break"
 6232.     86                    && the_last.label === undefined
 6233.     86                ) {
 6234.     86
 6235.     86// test_cause:
 6236.     86// ["
 6237.     86// switch(0){case 0:break;default:break;}
 6238.     86// ", "stmt_switch", "unexpected_a", "break", 32]
 6239.     86
 6240.     86                    warn("unexpected_a", the_last);
 6241.     86                    the_last.disrupt = false;
 6242.     86                }
 6243.     86                the_disrupt = the_disrupt && the_last.disrupt;
 6244.     86            }
 6245.     95        } else {
 6246.     95            the_disrupt = false;
 6247.    181        }
 6248.    181        advance("}", the_switch);
 6249.    181        functionage.switch -= 1;
 6250.    181        the_switch.disrupt = the_disrupt;
 6251.    181        return the_switch;
 6252.    181    }
 6253.    591
 6254.     34    function stmt_throw() {
 6255.     34        const the_throw = token_now;
 6256.     34        the_throw.disrupt = true;
 6257.     34        the_throw.expression = parse_expression(10);
 6258.     34        semicolon();
 6259.      1        if (functionage.try > 0) {
 6260.      1
 6261.      1// test_cause:
 6262.      1// ["try{throw 0}catch(){}", "stmt_throw", "unexpected_a", "throw", 5]
 6263.      1
 6264.      1            warn("unexpected_a", the_throw);
 6265.      1        }
 6266.     34        return the_throw;
 6267.     34    }
 6268.    591
 6269.     63    function stmt_try() {
 6270.     63        const the_try = token_now;
 6271.     63        let ignored;
 6272.     63        let the_catch;
 6273.     63        let the_disrupt;
 6274.      1        if (functionage.try > 0) {
 6275.      1
 6276.      1// test_cause:
 6277.      1// ["try{try{}catch(){}}catch(){}", "stmt_try", "unexpected_a", "try", 5]
 6278.      1
 6279.      1            warn("unexpected_a", the_try);
 6280.      1        }
 6281.     63        functionage.try += 1;
 6282.     63        the_try.block = block();
 6283.     63        the_disrupt = the_try.block.disrupt;
 6284.     58        if (token_nxt.id === "catch") {
 6285.     58            ignored = "ignore";
 6286.     58            the_catch = token_nxt;
 6287.     58            the_try.catch = the_catch;
 6288.     58            advance("catch");
 6289.     58
 6290.     58// Create new catch-scope for catch-parameter.
 6291.     58
 6292.     58            catch_stack.push(catchage);
 6293.     58            catchage = the_catch;
 6294.     58            catch_list.push(catchage);
 6295.     58            the_catch.context = empty();
 6296.     58            if (token_nxt.id === "(") {
 6297.     58                advance("(");
 6298.     58                if (!token_nxt.identifier) {
 6299.     58
 6300.     58// test_cause:
 6301.     58// ["try{}catch(){}", "stmt_try", "expected_identifier_a", ")", 12]
 6302.     58
 6303.     58                    return stop("expected_identifier_a");
 6304.     58                }
 6305.     58                if (token_nxt.id !== "ignore") {
 6306.     58                    ignored = undefined;
 6307.     58                    the_catch.name = token_nxt;
 6308.     58                    enroll(token_nxt, "exception", true);
 6309.     58                }
 6310.     58                advance();
 6311.     58                advance(")");
 6312.     58            }
 6313.     58            the_catch.block = block(ignored);
 6314.     58            if (the_catch.block.disrupt !== true) {
 6315.     58                the_disrupt = false;
 6316.     58            }
 6317.     58
 6318.     58// Restore previous catch-scope after catch-block.
 6319.     58
 6320.     58            catchage = catch_stack.pop();
 6321.     58        } else {
 6322.      4
 6323.      4// test_cause:
 6324.      4// ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
 6325.      4
 6326.      4            warn("expected_a_before_b", token_nxt, "catch", artifact());
 6327.     59        }
 6328.     59        if (token_nxt.id === "finally") {
 6329.      4            functionage.finally += 1;
 6330.      4            advance("finally");
 6331.      4            the_try.else = block();
 6332.      4            the_disrupt = the_try.else.disrupt;
 6333.      4            functionage.finally -= 1;
 6334.     57        }
 6335.     57        the_try.disrupt = the_disrupt;
 6336.     57        functionage.try -= 1;
 6337.     57        return the_try;
 6338.     57    }
 6339.    591
 6340.   2127    function stmt_var() {
 6341.   2127        let ellipsis;
 6342.   2127        let mode_const;
 6343.   2127        let name;
 6344.   2127        let the_brace;
 6345.   2127        let the_bracket;
 6346.   2127        let the_variable = token_now;
 6347.   2127        let variable_prv;
 6348.   2127        mode_const = the_variable.id === "const";
 6349.   2127        the_variable.names = [];
 6350.   2127
 6351.   2127// A program may use var or let, but not both.
 6352.   2127
 6353.   1826        if (!mode_const) {
 6354.   1826            if (mode_var === undefined) {
 6355.   1826                mode_var = the_variable.id;
 6356.   1826            } else if (the_variable.id !== mode_var) {
 6357.   1826
 6358.   1826// test_cause:
 6359.   1826// ["let aa;var aa", "stmt_var", "expected_a_b", "var", 8]
 6360.   1826
 6361.   1826                warn("expected_a_b", the_variable, mode_var, the_variable.id);
 6362.   1826            }
 6363.   1826        }
 6364.   2127
 6365.   2127// We don't expect to see variables created in switch statements.
 6366.   2127
 6367.      1        if (functionage.switch > 0) {
 6368.      1
 6369.      1// test_cause:
 6370.      1// ["switch(0){case 0:var aa}", "stmt_var", "var_switch", "var", 18]
 6371.      1
 6372.      1            warn("var_switch", the_variable);
 6373.      1        }
 6374.   2127        switch (
 6375.   2127            Boolean(functionage.statement_prv)
 6376.   1270            && functionage.statement_prv.id
 6377.   2127        ) {
 6378.    132        case "const":
 6379.   1259        case "let":
 6380.   1261        case "var":
 6381.   1261
 6382.   1261// test_cause:
 6383.   1261// ["const aa=0;const bb=0;", "stmt_var", "var_prv", "const", 0]
 6384.   1261// ["let aa=0;let bb=0;", "stmt_var", "var_prv", "let", 0]
 6385.   1261// ["var aa=0;var bb=0;", "stmt_var", "var_prv", "var", 0]
 6386.   1261
 6387.   1261            test_cause("var_prv", functionage.statement_prv.id);
 6388.   1261            variable_prv = functionage.statement_prv;
 6389.   1261            break;
 6390.      2        case "import":
 6391.      2
 6392.      2// test_cause:
 6393.      2// ["import aa from \"aa\";\nlet bb=0;", "stmt_var", "import_prv", "", 0]
 6394.      2
 6395.      2            test_cause("import_prv");
 6396.      2            break;
 6397.    857        case false:
 6398.    857            break;
 6399.      7        default:
 6400.      7            if (
 6401.      7                (option_dict.beta && !option_dict.variable)
 6402.      7                || the_variable.id === "var"
 6403.      7            ) {
 6404.      7
 6405.      7// test_cause:
 6406.      7// ["console.log();let aa=0;", "stmt_var", "var_on_top", "let", 15]
 6407.      7// ["console.log();var aa=0;", "stmt_var", "var_on_top", "var", 15]
 6408.      7// ["try{aa();}catch(aa){var aa=0;}", "stmt_var", "var_on_top", "var", 21]
 6409.      7// ["while(0){var aa;}", "stmt_var", "var_on_top", "var", 10]
 6410.      7
 6411.      7                warn("var_on_top", token_now);
 6412.      7            }
 6413.   2127        }
 6414.   2128        while (true) {
 6415.   2128            if (token_nxt.id === "{") {
 6416.   2128                if (the_variable.id === "var") {
 6417.   2128
 6418.   2128// test_cause:
 6419.   2128// ["var{aa}=0", "stmt_var", "unexpected_a", "var", 1]
 6420.   2128
 6421.   2128                    warn("unexpected_a", the_variable);
 6422.   2128                }
 6423.   2128                the_brace = token_nxt;
 6424.   2128                advance("{");
 6425.   2128                while (true) {
 6426.   2128                    name = token_nxt;
 6427.   2128                    if (!name.identifier) {
 6428.   2128
 6429.   2128// test_cause:
 6430.   2128// ["let {0}", "stmt_var", "expected_identifier_a", "0", 6]
 6431.   2128
 6432.   2128                        return stop("expected_identifier_a");
 6433.   2128                    }
 6434.   2128                    survey(name);
 6435.   2128                    advance();
 6436.   2128                    if (token_nxt.id === ":") {
 6437.   2128                        advance(":");
 6438.   2128                        if (!token_nxt.identifier) {
 6439.   2128
 6440.   2128// test_cause:
 6441.   2128// ["let {aa:0}", "stmt_var", "expected_identifier_a", "0", 9]
 6442.   2128// ["let {aa:{aa}}", "stmt_var", "expected_identifier_a", "{", 9]
 6443.   2128
 6444.   2128                            return stop("expected_identifier_a");
 6445.   2128                        }
 6446.   2128
 6447.   2128// PR-363 - Bugfix - fix false-warning
 6448.   2128// <uninitialized 'bb'> in code '/*jslint node*/\nlet {aa:bb} = {}; bb();'
 6449.   2128
 6450.   2128                        // token_nxt.label = name;
 6451.   2128                        // the_variable.names.push(token_nxt);
 6452.   2128                        // enroll(token_nxt, "variable", mode_const);
 6453.   2128                        name = token_nxt;
 6454.   2128                        the_variable.names.push(name);
 6455.   2128                        survey(name);
 6456.   2128                        enroll(name, "variable", mode_const);
 6457.   2128
 6458.   2128                        advance();
 6459.   2128                        the_brace.open = true;
 6460.   2128                    } else {
 6461.   2128                        the_variable.names.push(name);
 6462.   2128                        enroll(name, "variable", mode_const);
 6463.   2128                    }
 6464.   2128                    name.dead = false;
 6465.   2128                    name.init = true;
 6466.   2128                    if (token_nxt.id === "=") {
 6467.   2128
 6468.   2128// test_cause:
 6469.   2128// ["let {aa=0}", "stmt_var", "assign", "", 0]
 6470.   2128
 6471.   2128                        test_cause("assign");
 6472.   2128                        advance("=");
 6473.   2128                        name.expression = parse_expression();
 6474.   2128                        the_brace.open = true;
 6475.   2128                    }
 6476.   2128                    if (token_nxt.id !== ",") {
 6477.   2128                        break;
 6478.   2128                    }
 6479.   2128                    advance(",");
 6480.   2128                }
 6481.   2128
 6482.   2128// test_cause:
 6483.   2128// ["let{bb,aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
 6484.   2128
 6485.   2128                check_ordered(the_variable.id, the_variable.names);
 6486.   2128                advance("}");
 6487.   2128                advance("=");
 6488.   2128                the_variable.expression = parse_expression(0);
 6489.   2128            } else if (token_nxt.id === "[") {
 6490.   2128                if (the_variable.id === "var") {
 6491.   2128
 6492.   2128// test_cause:
 6493.   2128// ["var[aa]=0", "stmt_var", "unexpected_a", "var", 1]
 6494.   2128
 6495.   2128                    warn("unexpected_a", the_variable);
 6496.   2128                }
 6497.   2128                the_bracket = token_nxt;
 6498.   2128                advance("[");
 6499.   2128                while (true) {
 6500.   2128                    ellipsis = false;
 6501.   2128                    if (token_nxt.id === "...") {
 6502.   2128                        ellipsis = true;
 6503.   2128                        advance("...");
 6504.   2128                    }
 6505.   2128                    if (!token_nxt.identifier) {
 6506.   2128
 6507.   2128// test_cause:
 6508.   2128// ["let[]", "stmt_var", "expected_identifier_a", "]", 5]
 6509.   2128
 6510.   2128                        return stop("expected_identifier_a");
 6511.   2128                    }
 6512.   2128                    name = token_nxt;
 6513.   2128                    advance();
 6514.   2128                    the_variable.names.push(name);
 6515.   2128                    enroll(name, "variable", mode_const);
 6516.   2128                    name.dead = false;
 6517.   2128                    name.init = true;
 6518.   2128                    if (ellipsis) {
 6519.   2128                        name.ellipsis = true;
 6520.   2128                        break;
 6521.   2128                    }
 6522.   2128                    if (token_nxt.id === "=") {
 6523.   2128                        advance("=");
 6524.   2128                        name.expression = parse_expression();
 6525.   2128                        the_bracket.open = true;
 6526.   2128                    }
 6527.   2128                    if (token_nxt.id !== ",") {
 6528.   2128                        break;
 6529.   2128                    }
 6530.   2128                    advance(",");
 6531.   2128                }
 6532.   2128                advance("]");
 6533.   2128                advance("=");
 6534.   2128                the_variable.expression = parse_expression(0);
 6535.   2128            } else if (token_nxt.identifier) {
 6536.   2128                name = token_nxt;
 6537.   2128                advance();
 6538.   2128                if (name.id === "ignore") {
 6539.   2128
 6540.   2128// test_cause:
 6541.   2128// ["
 6542.   2128// let ignore;function aa(ignore) {}
 6543.   2128// ", "stmt_var", "unexpected_a", "ignore", 5]
 6544.   2128
 6545.   2128                    warn("unexpected_a", name);
 6546.   2128                }
 6547.   2128                enroll(name, "variable", mode_const);
 6548.   2128                if (token_nxt.id === "=" || mode_const) {
 6549.   2128                    advance("=");
 6550.   2128                    name.dead = false;
 6551.   2128                    name.init = true;
 6552.   2128                    name.expression = parse_expression(0);
 6553.   2128                }
 6554.   2128                the_variable.names.push(name);
 6555.   2128            } else {
 6556.   2128
 6557.   2128// test_cause:
 6558.   2128// ["let 0", "stmt_var", "expected_identifier_a", "0", 5]
 6559.   2128// ["var{aa:{aa}}", "stmt_var", "expected_identifier_a", "{", 8]
 6560.   2128
 6561.   2128                return stop("expected_identifier_a");
 6562.   2128            }
 6563.   2128            if (token_nxt.id !== ",") {
 6564.   2128                break;
 6565.   2128            }
 6566.   2128
 6567.   2128// test_cause:
 6568.   2128// ["let aa,bb;", "stmt_var", "expected_a_b", ",", 7]
 6569.   2128
 6570.   2128            warn("expected_a_b", token_nxt, ";", ",");
 6571.   2128            advance(",");
 6572.   2128        }
 6573.   2113
 6574.   2113// Warn if variable declarations are unordered.
 6575.   2113
 6576.   2113        if (
 6577.   2113            option_dict.beta
 6578.   2113            && !option_dict.unordered
 6579.   2111            && !option_dict.variable
 6580.   2105            && variable_prv
 6581.   1259            && (
 6582.   1259                variable_prv.id + " " + variable_prv.names[0].id
 6583.   1259                > the_variable.id + " " + the_variable.names[0].id
 6584.   1259            )
 6585.      3        ) {
 6586.      3
 6587.      3// test_cause:
 6588.      3// ["const bb=0;const aa=0;", "stmt_var", "expected_a_b_before_c_d", "aa", 12]
 6589.      3// ["let bb;let aa;", "stmt_var", "expected_a_b_before_c_d", "aa", 8]
 6590.      3// ["var bb;var aa;", "stmt_var", "expected_a_b_before_c_d", "aa", 8]
 6591.      3
 6592.      3            warn(
 6593.      3                "expected_a_b_before_c_d",
 6594.      3                the_variable,
 6595.      3                the_variable.id,
 6596.      3                the_variable.names[0].id,
 6597.      3                variable_prv.id,
 6598.      3                variable_prv.names[0].id
 6599.      3            );
 6600.   2113        }
 6601.   2113        semicolon();
 6602.   2113        return the_variable;
 6603.   2113    }
 6604.    591
 6605.    208    function stmt_while() {
 6606.    208        const the_while = token_now;
 6607.    208        check_not_top_level(the_while);
 6608.    208        functionage.loop += 1;
 6609.    208        the_while.expression = condition();
 6610.    208        the_while.block = block();
 6611.      1        if (the_while.block.disrupt === true) {
 6612.      1
 6613.      1// test_cause:
 6614.      1// ["function aa(){while(0){break;}}", "stmt_while", "weird_loop", "while", 15]
 6615.      1
 6616.      1            warn("weird_loop", the_while);
 6617.    205        }
 6618.    205        functionage.loop -= 1;
 6619.    205        return the_while;
 6620.    205    }
 6621.    591
 6622.      1    function stmt_with() {
 6623.      1
 6624.      1// test_cause:
 6625.      1// ["with", "stmt_with", "unexpected_a", "with", 1]
 6626.      1
 6627.      1        stop("unexpected_a", token_now);
 6628.      1    }
 6629.    591
 6630.  13452    function survey(name) {
 6631.  13452        let id = name.id;
 6632.  13452
 6633.  13452// Tally the property name. If it is a string, only tally strings that conform
 6634.  13452// to the identifier rules.
 6635.  13452
 6636.     40        if (id === "(string)") {
 6637.     40            id = name.value;
 6638.     40            if (!rx_identifier.test(id)) {
 6639.     40                return id;
 6640.     40            }
 6641.  13412        } else if (id === "`") {
 6642.  13412            if (name.value.length === 1) {
 6643.  13412                id = name.value[0].value;
 6644.  13412                if (!rx_identifier.test(id)) {
 6645.  13412                    return id;
 6646.  13412                }
 6647.  13412            }
 6648.  13412        } else if (!name.identifier) {
 6649.  13412
 6650.  13412// test_cause:
 6651.  13412// ["let aa={0:0}", "survey", "expected_identifier_a", "0", 9]
 6652.  13412
 6653.  13412            return stop("expected_identifier_a", name);
 6654.  13413        }
 6655.  13413
 6656.  13413// If we have seen this name before, increment its count.
 6657.  13413
 6658.  13413        if (typeof property_dict[id] === "number") {
 6659.  11370            property_dict[id] += 1;
 6660.  11370
 6661.  11370// If this is the first time seeing this property name, and if there is a
 6662.  11370// tenure list, then it must be on the list. Otherwise, it must conform to
 6663.  11370// the rules for good property names.
 6664.  11370
 6665.  11370        } else {
 6666.   2043            if (state.mode_property) {
 6667.   2043                if (tenure[id] !== true) {
 6668.   2043
 6669.   2043// test_cause:
 6670.   2043// ["/*property aa*/\naa.bb", "survey", "unregistered_property_a", "bb", 4]
 6671.   2043
 6672.   2043                    warn("unregistered_property_a", name);
 6673.   2043                }
 6674.   2043            } else if (
 6675.   2043                !option_dict.name
 6676.   2043                && name.identifier
 6677.   2043                && (
 6678.   2043                    // rx_weird_property
 6679.   2043                    /^_|\$|Sync$|_$/m
 6680.   2043                ).test(id)
 6681.   2043            ) {
 6682.   2043
 6683.   2043// test_cause:
 6684.   2043// ["aa.$", "survey", "weird_property_a", "$", 4]
 6685.   2043// ["aa._", "survey", "weird_property_a", "_", 4]
 6686.   2043// ["aa._aa", "survey", "weird_property_a", "_aa", 4]
 6687.   2043// ["aa.aaSync", "survey", "weird_property_a", "aaSync", 4]
 6688.   2043// ["aa.aa_", "survey", "weird_property_a", "aa_", 4]
 6689.   2043
 6690.   2043                warn("weird_property_a", name);
 6691.   2043            }
 6692.   2043            property_dict[id] = 1;
 6693.  13413        }
 6694.  13413        return id;
 6695.  13413    }
 6696.    591
 6697.    591// These functions are used to specify the grammar of our language:
 6698.    591
 6699.  76830    function symbol(id, bp) {
 6700.  76830
 6701.  76830// Create a symbol if it does not already exist in the language's syntax.
 6702.  76830
 6703.  76830        let the_symbol = syntax_dict[id];
 6704.  66783        if (the_symbol === undefined) {
 6705.  66783            the_symbol = empty();
 6706.  66783            the_symbol.id = id;
 6707.  66783            the_symbol.lbp = bp || 0;
 6708.  66783            syntax_dict[id] = the_symbol;
 6709.  66783        }
 6710.  76830        return the_symbol;
 6711.  76830    }
 6712.    591
 6713.    591    function ternary(id1, id2) {
 6714.    591
 6715.    591// Create a ternary operator.
 6716.    591
 6717.    591        const the_symbol = symbol(id1, 30);
 6718.    213        the_symbol.led = function parse_ternary_led(left) {
 6719.    213            const the_token = token_now;
 6720.    213            let second;
 6721.    213            second = parse_expression(20);
 6722.    213            advance(id2);
 6723.    213            token_now.arity = "ternary";
 6724.    213            the_token.arity = "ternary";
 6725.    213            the_token.expression = [left, second, parse_expression(10)];
 6726.      5            if (token_nxt.id !== ")") {
 6727.      5
 6728.      5// test_cause:
 6729.      5// ["0?0:0", "parse_ternary_led", "use_open", "?", 2]
 6730.      5
 6731.      5                warn("use_open", the_token);
 6732.      5            }
 6733.    213            return the_token;
 6734.    213        };
 6735.    591        return the_symbol;
 6736.    591    }
 6737.    591
 6738.    591// Now we parse JavaScript.
 6739.    591// Begin defining the language.
 6740.    591
 6741.    591    assignment("%=");
 6742.    591    assignment("&=");
 6743.    591    assignment("*=");
 6744.    591    assignment("+=");
 6745.    591    assignment("-=");
 6746.    591    assignment("/=");
 6747.    591    assignment("<<=");
 6748.    591    assignment("=");
 6749.    591    assignment(">>=");
 6750.    591    assignment(">>>=");
 6751.    591    assignment("^=");
 6752.    591    assignment("|=");
 6753.    591    constant("(number)", "number");
 6754.    591    constant("(regexp)", "regexp");
 6755.    591    constant("(string)", "string");
 6756.    591    constant("Function", "function", constant_Function);
 6757.    591    constant("Infinity", "number", Infinity);
 6758.    591    constant("NaN", "number", NaN);
 6759.    591    constant("arguments", "object", constant_arguments);
 6760.    591    constant("eval", "function", constant_eval);
 6761.    591    constant("false", "boolean", false);
 6762.    591    constant("ignore", "undefined", constant_ignore);
 6763.    591    constant("isFinite", "function", constant_isInfinite);
 6764.    591    constant("isNaN", "function", constant_isNaN);
 6765.    591    constant("null", "null", null);
 6766.    591    constant("this", "object", constant_this);
 6767.    591    constant("true", "boolean", true);
 6768.    591    constant("undefined", "undefined");
 6769.    591    infix(100, "!=");
 6770.    591    infix(100, "!==");
 6771.    591    infix(100, "==");
 6772.    591    infix(100, "===");
 6773.    591    infix(110, "<");
 6774.    591    infix(110, "<=");
 6775.    591    infix(110, ">");
 6776.    591    infix(110, ">=");
 6777.    591    infix(110, "in");
 6778.    591    infix(110, "instanceof");
 6779.    591    infix(120, "<<");
 6780.    591    infix(120, ">>");
 6781.    591    infix(120, ">>>");
 6782.    591    infix(130, "+");
 6783.    591    infix(130, "-");
 6784.    591    infix(140, "%");
 6785.    591    infix(140, "*");
 6786.    591    infix(140, "/");
 6787.    591    infix(160, "(", infix_lparen);
 6788.    591    infix(160, "`", infix_grave);
 6789.    591    infix(170, ".", infix_dot);
 6790.    591    infix(170, "=>", infix_fart_unwrapped);
 6791.    591    infix(170, "?.", infix_option_chain);
 6792.    591    infix(170, "[", infix_lbracket);
 6793.    591    infix(35, "??");
 6794.    591    infix(40, "||");
 6795.    591    infix(50, "&&");
 6796.    591    infix(70, "|");
 6797.    591    infix(80, "^");
 6798.    591    infix(90, "&");
 6799.    591    infixr(150, "**");
 6800.    591    postassign("++");
 6801.    591    postassign("--");
 6802.    591    preassign("++");
 6803.    591    preassign("--");
 6804.    591    prefix("!!");
 6805.    591    prefix("!");
 6806.    591    prefix("(", prefix_lparen);
 6807.    591    prefix("+");
 6808.    591    prefix("-");
 6809.    591    prefix("/=", prefix_assign_divide);
 6810.    591    prefix("=>", prefix_fart);
 6811.    591    prefix("[", prefix_lbracket);
 6812.    591    prefix("`", prefix_tick);
 6813.    591    prefix("async", prefix_async);
 6814.    591    prefix("await", prefix_await);
 6815.    591    prefix("function", prefix_function);
 6816.    591    prefix("new", prefix_new);
 6817.    591    prefix("typeof");
 6818.    591    prefix("void", prefix_void);
 6819.    591    prefix("{", prefix_lbrace);
 6820.    591    prefix("~");
 6821.    591    stmt(";", stmt_semicolon);
 6822.    591    stmt("async", prefix_async);
 6823.    591    stmt("await", prefix_await);
 6824.    591    stmt("break", stmt_break);
 6825.    591    stmt("const", stmt_var);
 6826.    591    stmt("continue", stmt_continue);
 6827.    591    stmt("debugger", stmt_debugger);
 6828.    591    stmt("delete", stmt_delete);
 6829.    591    stmt("do", stmt_do);
 6830.    591    stmt("export", stmt_export);
 6831.    591    stmt("for", stmt_for);
 6832.    591    stmt("function", prefix_function);
 6833.    591    stmt("if", stmt_if);
 6834.    591    stmt("import", stmt_import);
 6835.    591    stmt("let", stmt_var);
 6836.    591    stmt("return", stmt_return);
 6837.    591    stmt("switch", stmt_switch);
 6838.    591    stmt("throw", stmt_throw);
 6839.    591    stmt("try", stmt_try);
 6840.    591    stmt("var", stmt_var);
 6841.    591    stmt("while", stmt_while);
 6842.    591    stmt("with", stmt_with);
 6843.    591    stmt("{", stmt_lbrace);
 6844.    591    symbol(")");
 6845.    591    symbol("*/");
 6846.    591    symbol(",");
 6847.    591    symbol(":");
 6848.    591    symbol(";");
 6849.    591    symbol("]");
 6850.    591    symbol("async");
 6851.    591    symbol("await");
 6852.    591    symbol("case");
 6853.    591    symbol("catch");
 6854.    591    symbol("class");
 6855.    591    symbol("default");
 6856.    591    symbol("else");
 6857.    591    symbol("enum");
 6858.    591    symbol("finally");
 6859.    591    symbol("implements");
 6860.    591    symbol("interface");
 6861.    591    symbol("package");
 6862.    591    symbol("private");
 6863.    591    symbol("protected");
 6864.    591    symbol("public");
 6865.    591    symbol("static");
 6866.    591    symbol("super");
 6867.    591    symbol("void");
 6868.    591    symbol("yield");
 6869.    591    symbol("}");
 6870.    591    ternary("?", ":");
 6871.    591
 6872.    591// Init token_nxt.
 6873.    591
 6874.    591    advance();
 6875.    591
 6876.    591// Parsing of JSON is simple:
 6877.    591
 6878.     24    if (state.mode_json) {
 6879.     24        state.token_tree = parse_json();
 6880.     24        advance("(end)");
 6881.     24        return;
 6882.    567    }
 6883.    567
 6884.    567// Because browsers encourage combining of script files, the first token might
 6885.    567// be a semicolon to defend against a missing semicolon in the preceding file.
 6886.    567
 6887.    567    if (option_dict.browser) {
 6888.      2        if (token_nxt.id === ";") {
 6889.      2            advance(";");
 6890.      2        }
 6891.      2
 6892.      2// If we are not in a browser, then the file form of strict pragma may be used.
 6893.      2
 6894.    565    } else if (token_nxt.value === "use strict") {
 6895.    565        advance("(string)");
 6896.    565        advance(";");
 6897.    567    }
 6898.    567    state.token_tree = parse_statements();
 6899.    567    advance("(end)");
 6900.    567
 6901.    567// Check global functions are ordered.
 6902.    567
 6903.    567    check_ordered(
 6904.    567        "function",
 6905.   1833        function_list.map(function ({
 6906.   1833            level,
 6907.   1833            name
 6908.   1833        }) {
 6909.    567            return (level === 1) && name;
 6910.   1833        }).filter(function (name) {
 6911.   1831            return option_dict.beta && name && name.id;
 6912.   1833        })
 6913.    567    );
 6914.    567}
 6915.      1
 6916.    473function jslint_phase4_walk(state) {
 6917.    473
 6918.    473// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
 6919.    473//          recursive traversal. Each node may be processed on the way down
 6920.    473//          (preaction) and on the way up (postaction).
 6921.    473
 6922.    473    let {
 6923.    473        artifact,
 6924.    473        catch_stack,
 6925.    473        function_stack,
 6926.    473        global_dict,
 6927.    473        is_equal,
 6928.    473        is_weird,
 6929.    473        option_dict,
 6930.    473        syntax_dict,
 6931.    473        test_cause,
 6932.    473        token_global,
 6933.    473        warn
 6934.    473    } = state;
 6935.    473    let block_stack = [];               // The stack of blocks.
 6936.    473    let blockage = token_global;        // The current block.
 6937.    473    let catchage = catch_stack[0];      // The current catch-block.
 6938.    473    let functionage = token_global;     // The current function.
 6939.    473    let postaction;
 6940.    473    let postamble;
 6941.    473    let posts = empty();
 6942.    473    let preaction;
 6943.    473    let preamble;
 6944.    473    let pres = empty();
 6945.    473
 6946.    473// The relational operators.
 6947.    473
 6948.    473    let relationop = object_assign_from_list(empty(), [
 6949.    473        "!=", "!==", "<", "<=", "==", "===", ">", ">="
 6950.    473    ], true);
 6951.    473
 6952.    473// Ambulation of the parse tree.
 6953.    473
 6954.    946    function action(when) {
 6955.    946
 6956.    946// Produce a function that will register task functions that will be called as
 6957.    946// the tree is traversed.
 6958.    946
 6959.  17974        return function (arity, id, task) {
 6960.  17974            let a_set = when[arity];
 6961.  17974            let i_set;
 6962.  17974
 6963.  17974// The id parameter is optional. If excluded, the task will be applied to all
 6964.  17974// ids.
 6965.  17974
 6966.   3784            if (typeof id !== "string") {
 6967.   3784                task = id;
 6968.   3784                id = "(all)";
 6969.   3784            }
 6970.  17974
 6971.  17974// If this arity has no registrations yet, then create a set object to hold
 6972.  17974// them.
 6973.  17974
 6974.   4730            if (a_set === undefined) {
 6975.   4730                a_set = empty();
 6976.   4730                when[arity] = a_set;
 6977.   4730            }
 6978.  17974
 6979.  17974// If this id has no registrations yet, then create a set array to hold them.
 6980.  17974
 6981.  17974            i_set = a_set[id];
 6982.  17501            if (i_set === undefined) {
 6983.  17501                i_set = [];
 6984.  17501                a_set[id] = i_set;
 6985.  17501            }
 6986.  17974
 6987.  17974// Register the task with the arity and the id.
 6988.  17974
 6989.  17974            i_set.push(task);
 6990.  17974        };
 6991.    946    }
 6992.    473
 6993.    946    function amble(when) {
 6994.    946
 6995.    946// Produce a function that will act on the tasks registered by an action
 6996.    946// function while walking the tree.
 6997.    946
 6998. 197392        return function (the_token) {
 6999. 197392
 7000. 197392// Given a task set that was built by an action function, run all
 7001. 197392// relevant tasks on the token.
 7002. 197392
 7003. 197392            let a_set = when[the_token.arity];
 7004. 197392            let i_set;
 7005. 197392
 7006. 197392// If there are tasks associated with the token's arity...
 7007. 197392
 7008. 135909            if (a_set !== undefined) {
 7009. 135909
 7010. 135909// If there are tasks associated with the token's id...
 7011. 135909
 7012. 135909                i_set = a_set[the_token.id];
 7013. 135909                if (i_set !== undefined) {
 7014. 135909                    i_set.forEach(function (task) {
 7015. 135909                        return task(the_token);
 7016. 135909                    });
 7017. 135909                }
 7018. 135909
 7019. 135909// If there are tasks for all ids.
 7020. 135909
 7021. 135909                i_set = a_set["(all)"];
 7022. 135909                if (i_set !== undefined) {
 7023. 135909                    i_set.forEach(function (task) {
 7024. 135909                        return task(the_token);
 7025. 135909                    });
 7026. 135909                }
 7027. 135909            }
 7028. 197392        };
 7029.    946    }
 7030.    473
 7031.   2596    function init_variable(name) {
 7032.   2596        let the_variable = lookup(name);
 7033.   2541        if (!the_variable || the_variable.readonly) {
 7034.     57            warn("bad_assignment_a", name);
 7035.     57            return;
 7036.   2539        }
 7037.   2539        the_variable.init = true;
 7038.   2539    }
 7039.    473
 7040.  29634    function lookup(thing) {
 7041.  29634        let id = thing.id;
 7042.  29634        let the_variable;
 7043.      1        if (thing.arity !== "variable") {
 7044.      1            return;
 7045.  29633        }
 7046.  29633
 7047.  29633// Look up the variable in the current context.
 7048.  29633
 7049.  29633        the_variable = (
 7050.  29633            functionage.context[id] || catchage.context[id]
 7051.  29634        );
 7052.  29634
 7053.  29634// If it isn't local, search all the other contexts. If there are name
 7054.  29634// collisions, take the most recent.
 7055.  29634
 7056.  23353        if (the_variable && the_variable.role === "label") {
 7057.      1
 7058.      1// test_cause:
 7059.      1// ["aa:while(0){aa;}", "lookup", "label_a", "aa", 13]
 7060.      1
 7061.      1            warn("label_a", thing);
 7062.      1            return the_variable;
 7063.  29632        }
 7064.  29632        if (!the_variable) {
 7065.  13479            function_stack.forEach(function ({
 7066.  13479                context
 7067.  13479            }) {
 7068.   6280                if (context[id] && context[id].role !== "label") {
 7069.   6280                    the_variable = context[id];
 7070.   6280                }
 7071.  13479            });
 7072.   6280
 7073.   6280// If it isn't in any of those either, perhaps it is a predefined global.
 7074.   6280// If so, add it to the global context.
 7075.   6280
 7076.   6280            if (!the_variable && global_dict[id] === undefined) {
 7077.   6280
 7078.   6280// test_cause:
 7079.   6280// ["aa", "lookup", "undeclared_a", "aa", 1]
 7080.   6280// ["class aa{}", "lookup", "undeclared_a", "aa", 7]
 7081.   6280// ["
 7082.   6280// let aa=0;try{aa();}catch(bb){bb();}bb();
 7083.   6280// ", "lookup", "undeclared_a", "bb", 36]
 7084.   6280// ["
 7085.   6280// let aa=0;try{aa();}catch(ignore){bb();}
 7086.   6280// ", "lookup", "undeclared_a", "bb", 34]
 7087.   6280
 7088.   6280                warn("undeclared_a", thing);
 7089.   6280                return;
 7090.   6280            }
 7091.   6280            if (!the_variable) {
 7092.   6280                the_variable = {
 7093.   6280                    dead: false,
 7094.   6280                    id,
 7095.   6280                    init: true,
 7096.   6280                    parent: token_global,
 7097.   6280                    readonly: true,
 7098.   6280                    role: "variable",
 7099.   6280                    used: 0
 7100.   6280                };
 7101.   6280                token_global.context[id] = the_variable;
 7102.   6280            }
 7103.   6280            the_variable.closure = true;
 7104.   6280            functionage.context[id] = the_variable;
 7105.  29506        }
 7106.  29506        if (
 7107.  29506            (
 7108.  29506                the_variable.calls === undefined
 7109.  29506                || functionage.name === undefined
 7110.   4276                || the_variable.calls[functionage.name.id] === undefined
 7111.  29634            )
 7112.  29336            && the_variable.dead
 7113.      3        ) {
 7114.      3
 7115.      3// test_cause:
 7116.      3// ["let aa;if(aa){let bb;}bb;", "lookup", "out_of_scope_a", "bb", 23]
 7117.      3
 7118.      3            warn("out_of_scope_a", thing);
 7119.  29506        }
 7120.  29506        return the_variable;
 7121.  29506    }
 7122.    473
 7123.   4717    function post_a(thing) {
 7124.   4717
 7125.   4717// Assignment using = sets the init property of a variable. No other assignment
 7126.   4717// operator can do this. A = token keeps that variable (or array of variables
 7127.   4717// in case of destructuring) in its name property.
 7128.   4717
 7129.   4717        const lvalue = thing.expression[0];
 7130.   4717        let right;
 7131.   4009        if (thing.id === "=") {
 7132.   4009            if (thing.names !== undefined) {
 7133.   4009
 7134.   4009// test_cause:
 7135.   4009// ["if(0){aa=0}", "post_a", "=", "", 0]
 7136.   4009
 7137.   4009                test_cause("=");
 7138.   4009
 7139.   4009// Probably deadcode.
 7140.   4009// if (Array.isArray(thing.names)) {
 7141.   4009//     thing.names.forEach(init_variable);
 7142.   4009// } else {
 7143.   4009//     init_variable(thing.names);
 7144.   4009// }
 7145.   4009
 7146.   4009                jslint_assert(
 7147.   4009                    !Array.isArray(thing.names),
 7148.   4009                    `Expected !Array.isArray(thing.names).`
 7149.   4009                );
 7150.   4009                init_variable(thing.names);
 7151.   4009            } else {
 7152.   4009                if (lvalue.id === "[" || lvalue.id === "{") {
 7153.   4009                    lvalue.expression.forEach(function (thing) {
 7154.   4009                        if (thing.variable) {
 7155.   4009                            thing.variable.init = true;
 7156.   4009                        }
 7157.   4009                    });
 7158.   4009                } else if (
 7159.   4009                    lvalue.id === "."
 7160.   4009                    && thing.expression[1].id === "undefined"
 7161.   4009                ) {
 7162.   4009
 7163.   4009// test_cause:
 7164.   4009// ["aa.aa=undefined", "post_a", "expected_a_b", "undefined", 1]
 7165.   4009
 7166.   4009                    warn(
 7167.   4009                        "expected_a_b",
 7168.   4009                        lvalue.expression,
 7169.   4009                        "delete",
 7170.   4009                        "undefined"
 7171.   4009                    );
 7172.   4009                }
 7173.   4009            }
 7174.   4009        } else {
 7175.    708            if (lvalue.arity === "variable") {
 7176.    708                if (!lvalue.variable || lvalue.variable.readonly) {
 7177.    708                    warn("bad_assignment_a", lvalue);
 7178.    708                }
 7179.    708            }
 7180.    708            right = syntax_dict[thing.expression[1].id];
 7181.    708            if (
 7182.    708                right !== undefined
 7183.    708                && (
 7184.    708                    right.id === "function"
 7185.    708                    || right.id === "=>"
 7186.    708                    || (
 7187.    708                        right.constant
 7188.    708                        && right.id !== "(number)"
 7189.    708                        && (right.id !== "(string)" || thing.id !== "+=")
 7190.    708                    )
 7191.    708                )
 7192.    708            ) {
 7193.    708
 7194.    708// test_cause:
 7195.    708// ["aa+=undefined", "post_a", "unexpected_a", "undefined", 5]
 7196.    708
 7197.    708                warn("unexpected_a", thing.expression[1]);
 7198.    708            }
 7199.    708        }
 7200.   4717    }
 7201.    473
 7202.    645    function post_a_pluseq(thing) {
 7203.    645        const right = thing.expression[1];
 7204.    342        if (right.constant) {
 7205.    342            if (
 7206.    342                right.value === ""
 7207.    342                || (right.id === "(number)" && right.value === "0")
 7208.    342                || right.id === "(boolean)"
 7209.    342                || right.id === "null"
 7210.    342                || right.id === "undefined"
 7211.    342                || Number.isNaN(right.value)
 7212.    342            ) {
 7213.    342                warn("unexpected_a", right);
 7214.    342            }
 7215.    342        }
 7216.    645    }
 7217.    473
 7218.  29995    function post_b(thing) {
 7219.  29995        let right;
 7220.   3951        if (relationop[thing.id]) {
 7221.   3951            if (
 7222.   3951                is_weird(thing.expression[0])
 7223.   3951                || is_weird(thing.expression[1])
 7224.   3951                || is_equal(thing.expression[0], thing.expression[1])
 7225.   3951                || (
 7226.   3951                    thing.expression[0].constant === true
 7227.   3951                    && thing.expression[1].constant === true
 7228.   3951                )
 7229.   3951            ) {
 7230.   3951
 7231.   3951// test_cause:
 7232.   3951// ["if(0===0){0}", "post_b", "weird_relation_a", "===", 5]
 7233.   3951
 7234.   3951                warn("weird_relation_a", thing);
 7235.   3951            }
 7236.   3951        }
 7237.   1784        if (thing.id === "+") {
 7238.   1784            if (!option_dict.convert) {
 7239.   1784                if (thing.expression[0].value === "") {
 7240.   1784
 7241.   1784// test_cause:
 7242.   1784// ["\"\"+0", "post_b", "expected_a_b", "\"\" +", 3]
 7243.   1784
 7244.   1784                    warn("expected_a_b", thing, "String(...)", "\"\" +");
 7245.   1784                } else if (thing.expression[1].value === "") {
 7246.   1784
 7247.   1784// test_cause:
 7248.   1784// ["0+\"\"", "post_b", "expected_a_b", "+ \"\"", 2]
 7249.   1784
 7250.   1784                    warn("expected_a_b", thing, "String(...)", "+ \"\"");
 7251.   1784                }
 7252.   1784            }
 7253.  28211        } else if (thing.id === "[") {
 7254.  28211            if (thing.expression[0].id === "window") {
 7255.  28211
 7256.  28211// test_cause:
 7257.  28211// ["aa=window[0]", "post_b", "weird_expression_a", "window[...]", 10]
 7258.  28211
 7259.  28211                warn("weird_expression_a", thing, "window[...]");
 7260.  28211            }
 7261.  28211            if (thing.expression[0].id === "self") {
 7262.  28211
 7263.  28211// test_cause:
 7264.  28211// ["aa=self[0]", "post_b", "weird_expression_a", "self[...]", 8]
 7265.  28211
 7266.  28211                warn("weird_expression_a", thing, "self[...]");
 7267.  28211            }
 7268.  28211        } else if (thing.id === "." || thing.id === "?.") {
 7269.  28211            if (thing.expression.id === "RegExp") {
 7270.  28211
 7271.  28211// test_cause:
 7272.  28211// ["aa=RegExp.aa", "post_b", "weird_expression_a", ".", 10]
 7273.  28211
 7274.  28211                warn("weird_expression_a", thing);
 7275.  28211            }
 7276.  28211        } else if (thing.id !== "=>" && thing.id !== "(") {
 7277.  28211            right = thing.expression[1];
 7278.  28211            if (
 7279.  28211                (thing.id === "+" || thing.id === "-")
 7280.  28211                && right.id === thing.id
 7281.  28211                && right.arity === "unary"
 7282.  28211                && !right.wrapped
 7283.  28211            ) {
 7284.  28211
 7285.  28211// test_cause:
 7286.  28211// ["0- -0", "post_b", "wrap_unary", "-", 4]
 7287.  28211
 7288.  28211                warn("wrap_unary", right);
 7289.  28211            }
 7290.  28211            if (
 7291.  28211                thing.expression[0].constant === true
 7292.  28211                && right.constant === true
 7293.  28211            ) {
 7294.  28211                thing.constant = true;
 7295.  28211            }
 7296.  28211        }
 7297.  29995    }
 7298.    473
 7299.   1160    function post_b_and(thing) {
 7300.   1160        if (
 7301.   1160            is_weird(thing.expression[0])
 7302.   1155            || is_equal(thing.expression[0], thing.expression[1])
 7303.   1142            || thing.expression[0].constant === true
 7304.   1141            || thing.expression[1].constant === true
 7305.     19        ) {
 7306.     19
 7307.     19// test_cause:
 7308.     19// ["aa=(()=>0)&&(()=>0)", "post_b_and", "weird_condition_a", "&&", 11]
 7309.     19// ["aa=(``?``:``)&&(``?``:``)", "post_b_and", "weird_condition_a", "&&", 14]
 7310.     19// ["aa=/./&&/./", "post_b_and", "weird_condition_a", "&&", 7]
 7311.     19// ["aa=0&&0", "post_b_and", "weird_condition_a", "&&", 5]
 7312.     19// ["aa=[]&&[]", "post_b_and", "weird_condition_a", "&&", 6]
 7313.     19// ["aa=`${0}`&&`${0}`", "post_b_and", "weird_condition_a", "&&", 10]
 7314.     19// ["
 7315.     19// aa=function aa(){}&&function aa(){}
 7316.     19// ", "post_b_and", "weird_condition_a", "&&", 19]
 7317.     19// ["aa={}&&{}", "post_b_and", "weird_condition_a", "&&", 6]
 7318.     19
 7319.     19            warn("weird_condition_a", thing);
 7320.     19        }
 7321.   1160    }
 7322.    473
 7323.   1354    function post_b_lbracket(thing) {
 7324.      1        if (thing.expression[0].id === "RegExp") {
 7325.      1
 7326.      1// test_cause:
 7327.      1// ["aa=RegExp[0]", "post_b_lbracket", "weird_expression_a", "[", 10]
 7328.      1
 7329.      1            warn("weird_expression_a", thing);
 7330.      1        }
 7331.      1        if (is_weird(thing.expression[1])) {
 7332.      1
 7333.      1// test_cause:
 7334.      1// ["aa[[0]]", "post_b_lbracket", "weird_expression_a", "[", 4]
 7335.      1
 7336.      1            warn("weird_expression_a", thing.expression[1]);
 7337.      1        }
 7338.   1354    }
 7339.    473
 7340.   9604    function post_b_lparen(thing) {
 7341.   9604        let arg;
 7342.   9604        let array;
 7343.   9604        let cack;
 7344.   9604        let left = thing.expression[0];
 7345.   9604        let new_date;
 7346.   9604        let paren;
 7347.   9604        let the_new;
 7348.    122        if (left.id === "new") {
 7349.    122            the_new = left;
 7350.    122            left = left.expression;
 7351.    122        }
 7352.     41        if (left.id === "function") {
 7353.     41            if (!thing.wrapped) {
 7354.     41
 7355.     41// test_cause:
 7356.     41// ["aa=function(){}()", "post_b_lparen", "wrap_immediate", "(", 16]
 7357.     41
 7358.     41                warn("wrap_immediate", thing);
 7359.     41            }
 7360.   9563        } else if (left.identifier) {
 7361.   9563            if (the_new !== undefined) {
 7362.   9563                if (
 7363.   9563                    left.id[0] > "Z"
 7364.   9563                    || left.id === "BigInt"
 7365.   9563                    || left.id === "Boolean"
 7366.   9563                    || left.id === "Number"
 7367.   9563                    || left.id === "String"
 7368.   9563                    || left.id === "Symbol"
 7369.   9563                ) {
 7370.   9563
 7371.   9563// test_cause:
 7372.   9563// ["new BigInt()", "post_b_lparen", "unexpected_a", "new", 1]
 7373.   9563// ["new Boolean()", "post_b_lparen", "unexpected_a", "new", 1]
 7374.   9563// ["new Number()", "post_b_lparen", "unexpected_a", "new", 1]
 7375.   9563// ["new String()", "post_b_lparen", "unexpected_a", "new", 1]
 7376.   9563// ["new Symbol()", "post_b_lparen", "unexpected_a", "new", 1]
 7377.   9563// ["new aa()", "post_b_lparen", "unexpected_a", "new", 1]
 7378.   9563
 7379.   9563                    warn("unexpected_a", the_new);
 7380.   9563                } else if (left.id === "Function") {
 7381.   9563                    if (!option_dict.eval) {
 7382.   9563
 7383.   9563// test_cause:
 7384.   9563// ["new Function()", "post_b_lparen", "unexpected_a", "new Function", 5]
 7385.   9563
 7386.   9563                        warn("unexpected_a", left, "new Function");
 7387.   9563                    }
 7388.   9563                } else if (left.id === "Array") {
 7389.   9563                    arg = thing.expression;
 7390.   9563                    if (arg.length !== 2 || arg[1].id === "(string)") {
 7391.   9563
 7392.   9563// test_cause:
 7393.   9563// ["new Array()", "post_b_lparen", "expected_a_b", "new Array", 5]
 7394.   9563
 7395.   9563                        warn("expected_a_b", left, "[]", "new Array");
 7396.   9563                    }
 7397.   9563                } else if (left.id === "Object") {
 7398.   9563
 7399.   9563// test_cause:
 7400.   9563// ["new Object()", "post_b_lparen", "expected_a_b", "new Object", 5]
 7401.   9563
 7402.   9563                    warn(
 7403.   9563                        "expected_a_b",
 7404.   9563                        left,
 7405.   9563                        "Object.create(null)",
 7406.   9563                        "new Object"
 7407.   9563                    );
 7408.   9563                }
 7409.   9563            } else {
 7410.   9563                if (
 7411.   9563                    left.id[0] >= "A"
 7412.   9563                    && left.id[0] <= "Z"
 7413.   9563                    && left.id !== "BigInt"
 7414.   9563                    && left.id !== "Boolean"
 7415.   9563                    && left.id !== "Number"
 7416.   9563                    && left.id !== "String"
 7417.   9563                    && left.id !== "Symbol"
 7418.   9563                ) {
 7419.   9563
 7420.   9563// test_cause:
 7421.   9563// ["let Aa=Aa()", "post_b_lparen", "expected_a_before_b", "Aa", 8]
 7422.   9563
 7423.   9563                    warn("expected_a_before_b", left, "new", artifact(left));
 7424.   9563                }
 7425.   9563            }
 7426.   9563        } else if (left.id === ".") {
 7427.   9563            cack = the_new !== undefined;
 7428.   9563            if (left.expression.id === "Date" && left.name.id === "UTC") {
 7429.   9563
 7430.   9563// test_cause:
 7431.   9563// ["new Date.UTC()", "post_b_lparen", "cack", "", 0]
 7432.   9563
 7433.   9563                test_cause("cack");
 7434.   9563                cack = !cack;
 7435.   9563            }
 7436.   9563            if ((
 7437.   9563                // rx_cap
 7438.   9563                /^[A-Z]/
 7439.   9563            ).test(left.name.id) !== cack) {
 7440.   9563                if (the_new !== undefined) {
 7441.   9563
 7442.   9563// test_cause:
 7443.   9563// ["new Date.UTC()", "post_b_lparen", "unexpected_a", "new", 1]
 7444.   9563
 7445.   9563                    warn("unexpected_a", the_new);
 7446.   9563                } else {
 7447.   9563
 7448.   9563// test_cause:
 7449.   9563// ["let Aa=Aa.Aa()", "post_b_lparen", "expected_a_before_b", "Aa", 8]
 7450.   9563
 7451.   9563                    warn(
 7452.   9563                        "expected_a_before_b",
 7453.   9563                        left.expression,
 7454.   9563                        "new",
 7455.   9563                        left.name.id
 7456.   9563                    );
 7457.   9563                }
 7458.   9563            }
 7459.   9563            if (left.name.id === "getTime") {
 7460.   9563                paren = left.expression;
 7461.   9563                if (paren.id === "(") {
 7462.   9563                    array = paren.expression;
 7463.   9563                    if (array.length === 1) {
 7464.   9563                        new_date = array[0];
 7465.   9563                        if (
 7466.   9563                            new_date.id === "new"
 7467.   9563                            && new_date.expression.id === "Date"
 7468.   9563                        ) {
 7469.   9563
 7470.   9563// test_cause:
 7471.   9563// ["
 7472.   9563// new Date().getTime()
 7473.   9563// ", "post_b_lparen", "expected_a_b", "new Date().getTime()", 1]
 7474.   9563
 7475.   9563                            warn(
 7476.   9563                                "expected_a_b",
 7477.   9563                                new_date,
 7478.   9563                                "Date.now()",
 7479.   9563                                "new Date().getTime()"
 7480.   9563                            );
 7481.   9563                        }
 7482.   9563                    }
 7483.   9563                }
 7484.   9563            }
 7485.   9563        }
 7486.   9604    }
 7487.    473
 7488.    956    function post_b_or(thing) {
 7489.    956        if (
 7490.    956            is_weird(thing.expression[0])
 7491.    956            || is_equal(thing.expression[0], thing.expression[1])
 7492.    955            || thing.expression[0].constant === true
 7493.      2        ) {
 7494.      2
 7495.      2// test_cause:
 7496.      2// ["aa=0||0", "post_b_or", "weird_condition_a", "||", 5]
 7497.      2
 7498.      2            warn("weird_condition_a", thing);
 7499.      2        }
 7500.    956    }
 7501.    473
 7502.     57    function post_s_export(the_thing) {
 7503.     57
 7504.     57// Some features must be at the most outermost level.
 7505.     57
 7506.      1        if (blockage !== token_global) {
 7507.      1
 7508.      1// test_cause:
 7509.      1// ["
 7510.      1// if(0){import aa from "aa";}
 7511.      1// ", "post_s_export", "misplaced_a", "import", 7]
 7512.      1
 7513.      1            warn("misplaced_a", the_thing);
 7514.      1        }
 7515.     57    }
 7516.    473
 7517.      8    function post_s_for(thing) {
 7518.      8
 7519.      8// Recurse walk_statement().
 7520.      8
 7521.      8        walk_statement(thing.inc);
 7522.      8    }
 7523.    473
 7524.   1833    function post_s_function(thing) {
 7525.   1833        delete functionage.async;
 7526.   1833        delete functionage.finally;
 7527.   1833        delete functionage.loop;
 7528.   1833        delete functionage.statement_prv;
 7529.   1833        delete functionage.switch;
 7530.   1833        delete functionage.try;
 7531.   1833        functionage = function_stack.pop();
 7532.      3        if (thing.wrapped) {
 7533.      3
 7534.      3// test_cause:
 7535.      3// ["aa=(function(){})", "post_s_function", "unexpected_parens", "function", 5]
 7536.      3
 7537.      3            warn("unexpected_parens", thing);
 7538.      3        }
 7539.   1833        return post_s_lbrace();
 7540.   1833    }
 7541.    473
 7542.     41    function post_s_import(the_thing) {
 7543.     41        const name = the_thing.name;
 7544.     41        if (name) {
 7545.      3            if (Array.isArray(name)) {
 7546.      3                name.forEach(function (name) {
 7547.      3                    name.dead = false;
 7548.      3                    name.init = true;
 7549.      3                    blockage.live.push(name);
 7550.      3                });
 7551.     38            } else {
 7552.     38                name.dead = false;
 7553.     38                name.init = true;
 7554.     38                blockage.live.push(name);
 7555.     38            }
 7556.     41            return post_s_export(the_thing);
 7557.     41        }
 7558.     41    }
 7559.    473
 7560.   7325    function post_s_lbrace() {
 7561.   2787        blockage.live.forEach(function (name) {
 7562.   2787            name.dead = true;
 7563.   2787        });
 7564.   7325        delete blockage.live;
 7565.   7325        blockage = block_stack.pop();
 7566.   7325    }
 7567.    473
 7568.     57    function post_s_try(thing) {
 7569.     55        if (thing.catch) {
 7570.     55            if (thing.catch.name) {
 7571.     55                Object.assign(catchage.context[thing.catch.name.id], {
 7572.     55                    dead: false,
 7573.     55                    init: true
 7574.     55                });
 7575.     55            }
 7576.     55
 7577.     55// Recurse walk_statement().
 7578.     55
 7579.     55            walk_statement(thing.catch.block);
 7580.     55
 7581.     55// Restore previous catch-scope after catch-block.
 7582.     55
 7583.     55            catchage = catch_stack.pop();
 7584.     55        }
 7585.     57    }
 7586.    473
 7587.   2113    function post_s_var(thing) {
 7588.   2410        thing.names.forEach(function (name) {
 7589.   2410            name.dead = false;
 7590.   1063            if (name.expression !== undefined) {
 7591.   1063                walk_expression(name.expression);
 7592.   1063
 7593.   1063// Probably deadcode.
 7594.   1063// if (name.id === "{" || name.id === "[") {
 7595.   1063//     name.names.forEach(subactivate);
 7596.   1063// } else {
 7597.   1063//     name.init = true;
 7598.   1063// }
 7599.   1063
 7600.   1063                jslint_assert(
 7601.   1063                    !(name.id === "{" || name.id === "["),
 7602.   1063                    `Expected !(name.id === "{" || name.id === "[").`
 7603.   1063                );
 7604.   1063                name.init = true;
 7605.   1063            }
 7606.   2410            blockage.live.push(name);
 7607.   2410        });
 7608.   2113    }
 7609.    473
 7610.    213    function post_t(thing) {
 7611.    213        if (
 7612.    213            is_weird(thing.expression[0])
 7613.    213            || thing.expression[0].constant === true
 7614.    206            || is_equal(thing.expression[1], thing.expression[2])
 7615.      7        ) {
 7616.      7            warn("unexpected_a", thing);
 7617.    206        } else if (is_equal(thing.expression[0], thing.expression[1])) {
 7618.    206
 7619.    206// test_cause:
 7620.    206// ["aa?aa:0", "post_t", "expected_a_b", "?", 3]
 7621.    206
 7622.    206            warn("expected_a_b", thing, "||", "?");
 7623.    206        } else if (is_equal(thing.expression[0], thing.expression[2])) {
 7624.    206
 7625.    206// test_cause:
 7626.    206// ["aa?0:aa", "post_t", "expected_a_b", "?", 3]
 7627.    206
 7628.    206            warn("expected_a_b", thing, "&&", "?");
 7629.    206        } else if (
 7630.    206            thing.expression[1].id === "true"
 7631.    206            && thing.expression[2].id === "false"
 7632.    206        ) {
 7633.    206
 7634.    206// test_cause:
 7635.    206// ["aa?true:false", "post_t", "expected_a_b", "?", 3]
 7636.    206
 7637.    206            warn("expected_a_b", thing, "!!", "?");
 7638.    206        } else if (
 7639.    206            thing.expression[1].id === "false"
 7640.    206            && thing.expression[2].id === "true"
 7641.    206        ) {
 7642.    206
 7643.    206// test_cause:
 7644.    206// ["aa?false:true", "post_t", "expected_a_b", "?", 3]
 7645.    206
 7646.    206            warn("expected_a_b", thing, "!", "?");
 7647.    206        } else if (
 7648.    206            thing.expression[0].wrapped !== true
 7649.    206            && (
 7650.    206                thing.expression[0].id === "||"
 7651.    206                || thing.expression[0].id === "&&"
 7652.    206            )
 7653.    206        ) {
 7654.    206
 7655.    206// test_cause:
 7656.    206// ["(aa&&!aa?0:1)", "post_t", "wrap_condition", "&&", 4]
 7657.    206
 7658.    206            warn("wrap_condition", thing.expression[0]);
 7659.    206        }
 7660.    213    }
 7661.    473
 7662.   3601    function post_u(thing) {
 7663.    699        if (thing.id === "`") {
 7664.    699            if (thing.expression.every(function (thing) {
 7665.    699                return thing.constant;
 7666.    699            })) {
 7667.    699                thing.constant = true;
 7668.    699            }
 7669.   2902        } else if (thing.id === "!") {
 7670.   2902            if (thing.expression.constant === true) {
 7671.   2902                warn("unexpected_a", thing);
 7672.   2902            }
 7673.   2902        } else if (thing.id === "!!") {
 7674.   2902            if (!option_dict.convert) {
 7675.   2902
 7676.   2902// test_cause:
 7677.   2902// ["!!0", "post_u", "expected_a_b", "!!", 1]
 7678.   2902
 7679.   2902                warn("expected_a_b", thing, "Boolean(...)", "!!");
 7680.   2902            }
 7681.   2902        } else if (
 7682.   2902            thing.id !== "["
 7683.   2902            && thing.id !== "{"
 7684.   2902            && thing.id !== "function"
 7685.   2902            && thing.id !== "new"
 7686.   2902        ) {
 7687.   2902            if (thing.expression.constant === true) {
 7688.   2902                thing.constant = true;
 7689.   2902            }
 7690.   2902        }
 7691.   3601    }
 7692.    473
 7693.      7    function post_u_plus(thing) {
 7694.      7        const right = thing.expression;
 7695.      7        if (!option_dict.convert) {
 7696.      7
 7697.      7// test_cause:
 7698.      7// ["aa=+0", "post_u_plus", "expected_a_b", "+", 4]
 7699.      7
 7700.      7            warn("expected_a_b", thing, "Number(...)", "+");
 7701.      7        }
 7702.      1        if (right.id === "(" && right.expression[0].id === "new") {
 7703.      1            warn("unexpected_a_before_b", thing, "+", "new");
 7704.      6        } else if (
 7705.      6            right.constant
 7706.      6            || right.id === "{"
 7707.      6            || (right.id === "[" && right.arity !== "binary")
 7708.      6        ) {
 7709.      6            warn("unexpected_a", thing, "+");
 7710.      6        }
 7711.      7    }
 7712.    473
 7713.  34715    function pre_a_bitwise(thing) {
 7714.  34715
 7715.  34715// These are the bitwise operators.
 7716.  34715
 7717.  34713        switch (!option_dict.bitwise && thing.id) {
 7718.      2        case "&":
 7719.      3        case "&=":
 7720.      5        case "<<":
 7721.      6        case "<<=":
 7722.      8        case ">>":
 7723.      9        case ">>=":
 7724.     11        case ">>>":
 7725.     12        case ">>>=":
 7726.     14        case "^":
 7727.     15        case "^=":
 7728.     17        case "|":
 7729.     18        case "|=":
 7730.     21        case "~":
 7731.     21
 7732.     21// test_cause:
 7733.     21// ["0&0", "pre_a_bitwise", "unexpected_a", "&", 2]
 7734.     21// ["0&=0", "pre_a_bitwise", "unexpected_a", "&=", 2]
 7735.     21// ["0<<0", "pre_a_bitwise", "unexpected_a", "<<", 2]
 7736.     21// ["0<<=0", "pre_a_bitwise", "unexpected_a", "<<=", 2]
 7737.     21// ["0>>0", "pre_a_bitwise", "unexpected_a", ">>", 2]
 7738.     21// ["0>>=0", "pre_a_bitwise", "unexpected_a", ">>=", 2]
 7739.     21// ["0>>>0", "pre_a_bitwise", "unexpected_a", ">>>", 2]
 7740.     21// ["0>>>=0", "pre_a_bitwise", "unexpected_a", ">>>=", 2]
 7741.     21// ["0^0", "pre_a_bitwise", "unexpected_a", "^", 2]
 7742.     21// ["0^=0", "pre_a_bitwise", "unexpected_a", "^=", 2]
 7743.     21// ["0|0", "pre_a_bitwise", "unexpected_a", "|", 2]
 7744.     21// ["0|=0", "pre_a_bitwise", "unexpected_a", "|=", 2]
 7745.     21// ["~0", "pre_a_bitwise", "unexpected_a", "~", 1]
 7746.     21
 7747.     21            warn("unexpected_a", thing);
 7748.     21            break;
 7749.  34715        }
 7750.  34715        if (
 7751.  34715            thing.id !== "("
 7752.  25111            && thing.id !== "&&"
 7753.  23951            && thing.id !== "||"
 7754.  22995            && thing.id !== "="
 7755.  18986            && Array.isArray(thing.expression)
 7756.   8048            && thing.expression.length === 2
 7757.   8047            && (
 7758.   8047                relationop[thing.expression[0].id] === true
 7759.   8047                || relationop[thing.expression[1].id] === true
 7760.   8047            )
 7761.      1        ) {
 7762.      1
 7763.      1// test_cause:
 7764.      1// ["0<0<0", "pre_a_bitwise", "unexpected_a", "<", 4]
 7765.      1
 7766.      1            warn("unexpected_a", thing);
 7767.      1        }
 7768.  34715    }
 7769.    473
 7770.  29995    function pre_b(thing) {
 7771.  29995        let left;
 7772.  29995        let right;
 7773.  29995        let value;
 7774.   3951        if (relationop[thing.id] === true) {
 7775.   3951            left = thing.expression[0];
 7776.   3951            right = thing.expression[1];
 7777.   3951            if (left.id === "NaN" || right.id === "NaN") {
 7778.   3951
 7779.   3951// test_cause:
 7780.   3951// ["NaN===NaN", "pre_b", "number_isNaN", "===", 4]
 7781.   3951
 7782.   3951                warn("number_isNaN", thing);
 7783.   3951            } else if (left.id === "typeof") {
 7784.   3951                if (right.id !== "(string)") {
 7785.   3951                    if (right.id !== "typeof") {
 7786.   3951
 7787.   3951// test_cause:
 7788.   3951// ["typeof 0===0", "pre_b", "expected_string_a", "0", 12]
 7789.   3951
 7790.   3951                        warn("expected_string_a", right);
 7791.   3951                    }
 7792.   3951                } else {
 7793.   3951                    value = right.value;
 7794.   3951                    if (value === "null" || value === "undefined") {
 7795.   3951
 7796.   3951// test_cause:
 7797.   3951// ["
 7798.   3951// typeof aa==="undefined"
 7799.   3951// ", "pre_b", "unexpected_typeof_a", "undefined", 13]
 7800.   3951
 7801.   3951                        warn("unexpected_typeof_a", right, value);
 7802.   3951                    } else if (
 7803.   3951                        value !== "bigint"
 7804.   3951                        && value !== "boolean"
 7805.   3951                        && value !== "function"
 7806.   3951                        && value !== "number"
 7807.   3951                        && value !== "object"
 7808.   3951                        && value !== "string"
 7809.   3951                        && value !== "symbol"
 7810.   3951                    ) {
 7811.   3951
 7812.   3951// test_cause:
 7813.   3951// ["typeof 0===\"aa\"", "pre_b", "expected_type_string_a", "aa", 12]
 7814.   3951
 7815.   3951                        warn("expected_type_string_a", right, value);
 7816.   3951                    }
 7817.   3951                }
 7818.   3951            }
 7819.   3951        }
 7820.  29995    }
 7821.    473
 7822.      1    function pre_b_eqeq(thing) {
 7823.      1
 7824.      1// test_cause:
 7825.      1// ["0==0", "pre_b_eqeq", "expected_a_b", "==", 2]
 7826.      1
 7827.      1        warn("expected_a_b", thing, "===", "==");
 7828.      1    }
 7829.    473
 7830.      1    function pre_b_in(thing) {
 7831.      1
 7832.      1// test_cause:
 7833.      1// ["aa in aa", "pre_b_in", "infix_in", "in", 4]
 7834.      1
 7835.      1        warn("infix_in", thing);
 7836.      1    }
 7837.    473
 7838.      1    function pre_b_instanceof(thing) {
 7839.      1
 7840.      1// test_cause:
 7841.      1// ["0 instanceof 0", "pre_b_instanceof", "unexpected_a", "instanceof", 3]
 7842.      1
 7843.      1        warn("unexpected_a", thing);
 7844.      1    }
 7845.    473
 7846.   9604    function pre_b_lparen(thing) {
 7847.   9604        const left = thing.expression[0];
 7848.   9604        let left_variable;
 7849.   9604        let parent;
 7850.   9604        if (
 7851.   9604            left.identifier
 7852.   6444            && functionage.context[left.id] === undefined
 7853.   2904            && typeof functionage.name === "object"
 7854.   2321        ) {
 7855.   2321            parent = functionage.name.parent;
 7856.   2321            if (parent) {
 7857.   2321                left_variable = parent.context[left.id];
 7858.   2321                if (
 7859.   2321                    left_variable !== undefined
 7860.   2321                    // Coverage-hack.
 7861.   2321                    // && left_variable.dead
 7862.   2321                    && left_variable.parent === parent
 7863.   2321                    && left_variable.calls !== undefined
 7864.   2321                    && left_variable.calls[functionage.name.id] !== undefined
 7865.   2321                ) {
 7866.   2321                    left_variable.dead = false;
 7867.   2321                }
 7868.   2321            }
 7869.   2321        }
 7870.   9604    }
 7871.    473
 7872.      1    function pre_b_noteq(thing) {
 7873.      1
 7874.      1// test_cause:
 7875.      1// ["0!=0", "pre_b_noteq", "expected_a_b", "!=", 2]
 7876.      1
 7877.      1        warn("expected_a_b", thing, "!==", "!=");
 7878.      1    }
 7879.    473
 7880.    956    function pre_b_or(thing) {
 7881.   1912        thing.expression.forEach(function (thang) {
 7882.    186            if (thang.id === "&&" && !thang.wrapped) {
 7883.      1
 7884.      1// test_cause:
 7885.      1// ["0&&0||0", "pre_b_or", "and", "&&", 2]
 7886.      1
 7887.      1                warn("and", thang);
 7888.      1            }
 7889.   1912        });
 7890.    956    }
 7891.    473
 7892.      8    function pre_s_for(thing) {
 7893.      8        let the_variable;
 7894.      2        if (thing.name !== undefined) {
 7895.      2            thing.name.dead = false;
 7896.      2            the_variable = lookup(thing.name);
 7897.      2            if (the_variable !== undefined) {
 7898.      2                if (the_variable.init && the_variable.readonly) {
 7899.      2
 7900.      2// test_cause:
 7901.      2// ["const aa=0;for(aa in aa){}", "pre_s_for", "bad_assignment_a", "aa", 16]
 7902.      2
 7903.      2                    warn("bad_assignment_a", thing.name);
 7904.      2                }
 7905.      2                the_variable.init = true;
 7906.      2            }
 7907.      2        }
 7908.      8
 7909.      8// Recurse walk_statement().
 7910.      8
 7911.      8        walk_statement(thing.initial);
 7912.      8    }
 7913.    473
 7914.   1833    function pre_s_function(thing) {
 7915.   1833
 7916.   1833// test_cause:
 7917.   1833// ["()=>0", "pre_s_function", "", "", 0]
 7918.   1833// ["(function (){}())", "pre_s_function", "", "", 0]
 7919.   1833// ["function aa(){}", "pre_s_function", "", "", 0]
 7920.   1833
 7921.   1833        test_cause("");
 7922.   1022        if (thing.arity === "statement" && blockage.body !== true) {
 7923.      1
 7924.      1// test_cause:
 7925.      1// ["if(0){function aa(){}\n}", "pre_s_function", "unexpected_a", "function", 7]
 7926.      1
 7927.      1            warn("unexpected_a", thing);
 7928.      1        }
 7929.   1833        function_stack.push(functionage);
 7930.   1833        block_stack.push(blockage);
 7931.   1833        functionage = thing;
 7932.   1833        blockage = thing;
 7933.   1833        thing.live = [];
 7934.   1062        if (typeof thing.name === "object") {
 7935.   1062            thing.name.dead = false;
 7936.   1062            thing.name.init = true;
 7937.   1062        }
 7938.      7        if (thing.extra === "get") {
 7939.      7            if (thing.parameters.length !== 0) {
 7940.      7
 7941.      7// test_cause:
 7942.      7// ["
 7943.      7// /*jslint getset*/
 7944.      7// aa={get aa(aa){}}
 7945.      7// ", "pre_s_function", "bad_get", "function", 9]
 7946.      7
 7947.      7                warn("bad_get", thing);
 7948.      7            }
 7949.   1826        } else if (thing.extra === "set") {
 7950.   1826            if (thing.parameters.length !== 1) {
 7951.   1826
 7952.   1826// test_cause:
 7953.   1826// ["
 7954.   1826// /*jslint getset*/
 7955.   1826// aa={set aa(){}}
 7956.   1826// ", "pre_s_function", "bad_set", "function", 9]
 7957.   1826
 7958.   1826                warn("bad_set", thing);
 7959.   1826            }
 7960.   1826        }
 7961.   1900        thing.parameters.forEach(function (name) {
 7962.   1900            walk_expression(name.expression);
 7963.   1706            if (name.id === "{" || name.id === "[") {
 7964.    225                name.names.forEach(subactivate);
 7965.   1675            } else {
 7966.   1675                name.dead = false;
 7967.   1675                name.init = true;
 7968.   1675            }
 7969.   1900        });
 7970.   1833    }
 7971.    473
 7972.   5492    function pre_s_lbrace(thing) {
 7973.   5492        block_stack.push(blockage);
 7974.   5492        blockage = thing;
 7975.   5492        thing.live = [];
 7976.   5492    }
 7977.    473
 7978.     57    function pre_try(thing) {
 7979.     55        if (thing.catch !== undefined) {
 7980.     55
 7981.     55// Create new catch-scope for catch-parameter.
 7982.     55
 7983.     55            catch_stack.push(catchage);
 7984.     55            catchage = thing.catch;
 7985.     55        }
 7986.     57    }
 7987.    473
 7988.  27036    function pre_v(thing) {
 7989.  27036        const the_variable = lookup(thing);
 7990.  26965        if (the_variable !== undefined) {
 7991.  26965            thing.variable = the_variable;
 7992.  26965            the_variable.used += 1;
 7993.  26965        }
 7994.  27036    }
 7995.    473
 7996.    614    function subactivate(name) {
 7997.    614        name.init = true;
 7998.    614        name.dead = false;
 7999.    614        blockage.live.push(name);
 8000.    614    }
 8001.    473
 8002. 153443    function walk_expression(thing) {
 8003.  96610        if (thing) {
 8004.  96610            if (Array.isArray(thing)) {
 8005.  96610
 8006.  96610// test_cause:
 8007.  96610// ["(function(){}())", "walk_expression", "isArray", "", 0]
 8008.  96610// ["0&&0", "walk_expression", "isArray", "", 0]
 8009.  96610
 8010.  96610                test_cause("isArray");
 8011.  96610                thing.forEach(walk_expression);
 8012.  96610            } else {
 8013.  96610                preamble(thing);
 8014.  96610                walk_expression(thing.expression);
 8015.  96610                if (thing.id === "function") {
 8016.  96610
 8017.  96610// test_cause:
 8018.  96610// ["aa=function(){}", "walk_expression", "function", "", 0]
 8019.  96610
 8020.  96610                    test_cause("function");
 8021.  96610
 8022.  96610// Recurse walk_statement().
 8023.  96610
 8024.  96610                    walk_statement(thing.block);
 8025.  96610                }
 8026.  96610                if (
 8027.  96610                    thing.arity === "preassign" || thing.arity === "postassign"
 8028.  96610                ) {
 8029.  96610
 8030.  96610// test_cause:
 8031.  96610// ["aa=++aa", "walk_expression", "unexpected_a", "++", 4]
 8032.  96610// ["aa=--aa", "walk_expression", "unexpected_a", "--", 4]
 8033.  96610
 8034.  96610                    warn("unexpected_a", thing);
 8035.  96610                } else if (
 8036.  96610                    thing.arity === "statement"
 8037.  96610                    || thing.arity === "assignment"
 8038.  96610                ) {
 8039.  96610
 8040.  96610// test_cause:
 8041.  96610// ["aa[aa=0]", "walk_expression", "unexpected_statement_a", "=", 6]
 8042.  96610
 8043.  96610                    warn("unexpected_statement_a", thing);
 8044.  96610                }
 8045.  96610
 8046.  96610// test_cause:
 8047.  96610// ["aa=0", "walk_expression", "default", "", 0]
 8048.  96610
 8049.  96610                test_cause("default");
 8050.  96610                postamble(thing);
 8051.  96610            }
 8052.  96610        }
 8053. 153443    }
 8054.    473
 8055.  74260    function walk_statement(thing) {
 8056.  33514        if (thing) {
 8057.  33514            if (Array.isArray(thing)) {
 8058.  33514
 8059.  33514// test_cause:
 8060.  33514// ["+[]", "walk_statement", "isArray", "", 0]
 8061.  33514
 8062.  33514                test_cause("isArray");
 8063.  33514
 8064.  33514// Recurse walk_statement().
 8065.  33514
 8066.  33514                thing.forEach(walk_statement);
 8067.  33514            } else {
 8068.  33514                preamble(thing);
 8069.  33514                walk_expression(thing.expression);
 8070.  33514                if (thing.arity === "binary") {
 8071.  33514                    if (thing.id !== "(") {
 8072.  33514
 8073.  33514// test_cause:
 8074.  33514// ["0&&0", "walk_statement", "unexpected_expression_a", "&&", 2]
 8075.  33514
 8076.  33514                        warn("unexpected_expression_a", thing);
 8077.  33514                    }
 8078.  33514                } else if (
 8079.  33514                    thing.arity !== "statement"
 8080.  33514                    && thing.arity !== "assignment"
 8081.  33514                    && thing.id !== "import"
 8082.  33514                ) {
 8083.  33514
 8084.  33514// test_cause:
 8085.  33514// ["!0", "walk_statement", "unexpected_expression_a", "!", 1]
 8086.  33514// ["+[]", "walk_statement", "unexpected_expression_a", "+", 1]
 8087.  33514// ["+new aa()", "walk_statement", "unexpected_expression_a", "+", 1]
 8088.  33514// ["0", "walk_statement", "unexpected_expression_a", "0", 1]
 8089.  33514// ["
 8090.  33514// async function aa(){await 0;}
 8091.  33514// ", "walk_statement", "unexpected_expression_a", "0", 27]
 8092.  33514// ["typeof 0", "walk_statement", "unexpected_expression_a", "typeof", 1]
 8093.  33514
 8094.  33514                    warn("unexpected_expression_a", thing);
 8095.  33514                }
 8096.  33514
 8097.  33514// Recurse walk_statement().
 8098.  33514
 8099.  33514                walk_statement(thing.block);
 8100.  33514                walk_statement(thing.else);
 8101.  33514                postamble(thing);
 8102.  33514            }
 8103.  33514        }
 8104.  74260    }
 8105.    473
 8106.    473    postaction = action(posts);
 8107.    473    postamble = amble(posts);
 8108.    473    preaction = action(pres);
 8109.    473    preamble = amble(pres);
 8110.    473    postaction("assignment", "+=", post_a_pluseq);
 8111.    473    postaction("assignment", post_a);
 8112.    473    postaction("binary", "&&", post_b_and);
 8113.    473    postaction("binary", "(", post_b_lparen);
 8114.    473    postaction("binary", "=>", post_s_function);
 8115.    473    postaction("binary", "[", post_b_lbracket);
 8116.    473    postaction("binary", "||", post_b_or);
 8117.    473    postaction("binary", post_b);
 8118.    473    postaction("statement", "const", post_s_var);
 8119.    473    postaction("statement", "export", post_s_export);
 8120.    473    postaction("statement", "for", post_s_for);
 8121.    473    postaction("statement", "function", post_s_function);
 8122.    473    postaction("statement", "import", post_s_import);
 8123.    473    postaction("statement", "let", post_s_var);
 8124.    473    postaction("statement", "try", post_s_try);
 8125.    473    postaction("statement", "var", post_s_var);
 8126.    473    postaction("statement", "{", post_s_lbrace);
 8127.    473    postaction("ternary", post_t);
 8128.    473    postaction("unary", "+", post_u_plus);
 8129.    473    postaction("unary", "function", post_s_function);
 8130.    473    postaction("unary", post_u);
 8131.    473    preaction("assignment", pre_a_bitwise);
 8132.    473    preaction("binary", "!=", pre_b_noteq);
 8133.    473    preaction("binary", "(", pre_b_lparen);
 8134.    473    preaction("binary", "==", pre_b_eqeq);
 8135.    473    preaction("binary", "=>", pre_s_function);
 8136.    473    preaction("binary", "in", pre_b_in);
 8137.    473    preaction("binary", "instanceof", pre_b_instanceof);
 8138.    473    preaction("binary", "||", pre_b_or);
 8139.    473    preaction("binary", pre_b);
 8140.    473    preaction("binary", pre_a_bitwise);
 8141.    473    preaction("statement", "for", pre_s_for);
 8142.    473    preaction("statement", "function", pre_s_function);
 8143.    473    preaction("statement", "try", pre_try);
 8144.    473    preaction("statement", "{", pre_s_lbrace);
 8145.    473    preaction("unary", "function", pre_s_function);
 8146.    473    preaction("unary", "~", pre_a_bitwise);
 8147.    473    preaction("variable", pre_v);
 8148.    473
 8149.    473    walk_statement(state.token_tree);
 8150.    473}
 8151.      1
 8152.    176function jslint_phase5_whitage(state) {
 8153.    176
 8154.    176// PHASE 5. Check whitespace between tokens in <token_list>.
 8155.    176
 8156.    176    let {
 8157.    176        artifact,
 8158.    176        catch_list,
 8159.    176        function_list,
 8160.    176        function_stack,
 8161.    176        option_dict,
 8162.    176        test_cause,
 8163.    176        token_global,
 8164.    176        token_list,
 8165.    176        warn
 8166.    176    } = state;
 8167.    176    let closer = "(end)";
 8168.    176    let free = false;
 8169.    176
 8170.    176// free = false
 8171.    176
 8172.    176// cause:
 8173.    176// "()=>0"
 8174.    176// "aa()"
 8175.    176// "aa(0,0)"
 8176.    176// "function(){}"
 8177.    176
 8178.    176// free = true
 8179.    176
 8180.    176// cause:
 8181.    176// "(0)"
 8182.    176// "(aa)"
 8183.    176// "aa(0)"
 8184.    176// "do{}while()"
 8185.    176// "for(){}"
 8186.    176// "if(){}"
 8187.    176// "switch(){}"
 8188.    176// "while(){}"
 8189.    176
 8190.    176    let left = token_global;
 8191.    176    let margin = 0;
 8192.    176    let mode_indent = (
 8193.    176
 8194.    176// PR-330 - Allow 2-space indent.
 8195.    176
 8196.    176        option_dict.indent2
 8197.      5        ? 2
 8198.    171        : 4
 8199.    176    );
 8200.    176    let nr_comments_skipped = 0;
 8201.    176    let open = true;
 8202.    176    let opening = true;
 8203.    176    let right;
 8204.    176
 8205.    176// This is the set of infix operators that require a space on each side.
 8206.    176
 8207.    176    let spaceop = object_assign_from_list(empty(), [
 8208.    176        "!=", "!==", "%", "%=", "&", "&&", "&=", "*", "*=", "+=", "-=", "/",
 8209.    176        "/=", "<", "<<", "<<=", "<=", "=", "==", "===", "=>", ">", ">=", ">>",
 8210.    176        ">>=", ">>>", ">>>=", "^", "^=", "|", "|=", "||"
 8211.    176    ], true);
 8212.    176
 8213.  34811    function at_margin(fit) {
 8214.  34811        const at = margin + fit;
 8215.     21        if (right.from !== at) {
 8216.     21            return expected_at(at);
 8217.     21        }
 8218.  34811    }
 8219.    176
 8220.   1878    function delve(the_function) {
 8221.  11915        Object.keys(the_function.context).forEach(function (id) {
 8222.  11915            const name = the_function.context[id];
 8223.  11886            if (id !== "ignore" && name.parent === the_function) {
 8224.   5763
 8225.   5763// test_cause:
 8226.   5763// ["function aa(aa) {return aa;}", "delve", "id", "", 0]
 8227.   5763
 8228.   5763                test_cause("id");
 8229.   5763                if (
 8230.   5763                    name.used === 0
 8231.   5763
 8232.   5763// Probably deadcode.
 8233.   5763// && (
 8234.   5763//     name.role !== "function"
 8235.   5763//     || name.parent.arity !== "unary"
 8236.   5763// )
 8237.   5763
 8238.   5763                    && jslint_assert(
 8239.   5763                        name.role !== "function",
 8240.   5763                        `Expected name.role !== "function".`
 8241.   5763                    )
 8242.   5763                ) {
 8243.   5763
 8244.   5763// test_cause:
 8245.   5763// ["/*jslint node*/\nlet aa;", "delve", "unused_a", "aa", 5]
 8246.   5763// ["function aa(aa){return;}", "delve", "unused_a", "aa", 13]
 8247.   5763// ["let aa=0;try{aa();}catch(bb){aa();}", "delve", "unused_a", "bb", 26]
 8248.   5763
 8249.   5763                    warn("unused_a", name);
 8250.   5763                } else if (!name.init) {
 8251.   5763
 8252.   5763// test_cause:
 8253.   5763// ["/*jslint node*/\nlet aa;aa();", "delve", "uninitialized_a", "aa", 5]
 8254.   5763
 8255.   5763                    warn("uninitialized_a", name);
 8256.   5763                }
 8257.   5763            }
 8258.  11915        });
 8259.   1878    }
 8260.    176
 8261.     25    function expected_at(at) {
 8262.     25
 8263.     25// Probably deadcode.
 8264.     25// if (right === undefined) {
 8265.     25//     right = token_nxt;
 8266.     25// }
 8267.     25
 8268.     25        jslint_assert(
 8269.     25            !(right === undefined),
 8270.     25            `Expected !(right === undefined).`
 8271.     25        );
 8272.     25        warn(
 8273.     25            "expected_a_at_b_c",
 8274.     25            right,
 8275.     25            artifact(right),
 8276.     25
 8277.     25// Fudge column numbers in warning message.
 8278.     25
 8279.     25            at + jslint_fudge,
 8280.     25            right.from + jslint_fudge
 8281.     25        );
 8282.     25    }
 8283.    176
 8284.   2866    function no_space() {
 8285.   2865        if (left.line === right.line) {
 8286.   2865
 8287.   2865// from:
 8288.   2865// if (left.line === right.line) {
 8289.   2865//     no_space();
 8290.   2865// } else {
 8291.   2865
 8292.   2865            if (left.thru !== right.from && nr_comments_skipped === 0) {
 8293.   2865
 8294.   2865// test_cause:
 8295.   2865// ["let aa = aa( );", "no_space", "unexpected_space_a_b", ")", 14]
 8296.   2865
 8297.   2865                warn(
 8298.   2865                    "unexpected_space_a_b",
 8299.   2865                    right,
 8300.   2865                    artifact(left),
 8301.   2865                    artifact(right)
 8302.   2865                );
 8303.   2865            }
 8304.   2865        } else {
 8305.      1
 8306.      1// from:
 8307.      1// } else if (
 8308.      1//     right.arity === "binary"
 8309.      1//     && right.id === "("
 8310.      1//     && free
 8311.      1// ) {
 8312.      1//     no_space();
 8313.      1// } else if (
 8314.      1
 8315.      1// Probably deadcode.
 8316.      1// if (open) {
 8317.      1//     const at = (
 8318.      1//         free
 8319.      1//         ? margin
 8320.      1//         : margin + 8
 8321.      1//     );
 8322.      1//     if (right.from < at) {
 8323.      1//         expected_at(at);
 8324.      1//     }
 8325.      1// } else {
 8326.      1//     if (right.from !== margin + 8) {
 8327.      1//         expected_at(margin + 8);
 8328.      1//     }
 8329.      1// }
 8330.      1
 8331.      1            jslint_assert(open, `Expected open.`);
 8332.      1            jslint_assert(free, `Expected free.`);
 8333.      1            if (right.from < margin) {
 8334.      1
 8335.      1// test_cause:
 8336.      1// ["let aa = aa(\naa\n()\n);", "expected_at", "expected_a_at_b_c", "5", 1]
 8337.      1
 8338.      1                expected_at(margin);
 8339.      1            }
 8340.      1        }
 8341.   2866    }
 8342.    176
 8343.  89050    function no_space_only() {
 8344.  89050        if (
 8345.  89050            left.id !== "(global)"
 8346.  89048            && left.nr + 1 === right.nr
 8347.  89048            && (
 8348.  89048                left.line !== right.line
 8349.  89048                || left.thru !== right.from
 8350.  89048            )
 8351.      5        ) {
 8352.      5            warn(
 8353.      5                "unexpected_space_a_b",
 8354.      5                right,
 8355.      5                artifact(left),
 8356.      5                artifact(right)
 8357.      5            );
 8358.      5        }
 8359.  89050    }
 8360.    176
 8361.  43175    function one_space() {
 8362.  41445        if (left.line === right.line || !open) {
 8363.  41445            if (left.thru + 1 !== right.from && nr_comments_skipped === 0) {
 8364.  41445                warn(
 8365.  41445                    "expected_space_a_b",
 8366.  41445                    right,
 8367.  41445                    artifact(left),
 8368.  41445                    artifact(right)
 8369.  41445                );
 8370.  41445            }
 8371.  41445        } else {
 8372.   1730            if (right.from !== margin) {
 8373.   1730                expected_at(margin);
 8374.   1730            }
 8375.   1730        }
 8376.  43175    }
 8377.    176
 8378.   8955    function one_space_only() {
 8379.      8        if (left.line !== right.line || left.thru + 1 !== right.from) {
 8380.      8            warn("expected_space_a_b", right, artifact(left), artifact(right));
 8381.      8        }
 8382.   8955    }
 8383.    176
 8384.  22789    function pop() {
 8385.  22789        const previous = function_stack.pop();
 8386.  22789        closer = previous.closer;
 8387.  22789        free = previous.free;
 8388.  22789        margin = previous.margin;
 8389.  22789        open = previous.open;
 8390.  22789        opening = previous.opening;
 8391.  22789    }
 8392.    176
 8393.  22789    function push() {
 8394.  22789        function_stack.push({
 8395.  22789            closer,
 8396.  22789            free,
 8397.  22789            margin,
 8398.  22789            open,
 8399.  22789            opening
 8400.  22789        });
 8401.  22789    }
 8402.    176
 8403.    176// uninitialized_and_unused();
 8404.    176// Delve into the functions looking for variables that were not initialized
 8405.    176// or used. If the file imports or exports, then its global object is also
 8406.    176// delved.
 8407.    176
 8408.    150    if (state.mode_module === true || option_dict.node) {
 8409.     40        delve(token_global);
 8410.     40    }
 8411.    176    catch_list.forEach(delve);
 8412.    176    function_list.forEach(delve);
 8413.    176
 8414.      2    if (option_dict.white) {
 8415.      2        return;
 8416.    174    }
 8417.    174
 8418.    174// whitage();
 8419.    174// Go through the token list, looking at usage of whitespace.
 8420.    174
 8421. 191641    token_list.forEach(function whitage(the_token) {
 8422. 191641        right = the_token;
 8423. 181642        if (right.id === "(comment)" || right.id === "(end)") {
 8424.  10175            nr_comments_skipped += 1;
 8425. 181466        } else {
 8426. 181466
 8427. 181466// If left is an opener and right is not the closer, then push the previous
 8428. 181466// state. If the token following the opener is on the next line, then this is
 8429. 181466// an open form. If the tokens are on the same line, then it is a closed form.
 8430. 181466// Open form is more readable, with each item (statement, argument, parameter,
 8431. 181466// etc) starting on its own line. Closed form is more compact. Statement blocks
 8432. 181466// are always in open form.
 8433. 181466
 8434. 181466// The open and close pairs.
 8435. 181466
 8436. 181466            switch (left.id) {
 8437. 181466            case "${":
 8438. 181466            case "(":
 8439. 181466            case "[":
 8440. 181466            case "{":
 8441. 181466
 8442. 181466// test_cause:
 8443. 181466// ["let aa=[];", "whitage", "opener", "", 0]
 8444. 181466// ["let aa=`${0}`;", "whitage", "opener", "", 0]
 8445. 181466// ["let aa=aa();", "whitage", "opener", "", 0]
 8446. 181466// ["let aa={};", "whitage", "opener", "", 0]
 8447. 181466
 8448. 181466                test_cause("opener");
 8449. 181466
 8450. 181466// Probably deadcode.
 8451. 181466// case "${}":
 8452. 181466
 8453. 181466                jslint_assert(
 8454. 181466                    !(left.id + right.id === "${}"),
 8455. 181466                    "Expected !(left.id + right.id === \"${}\")."
 8456. 181466                );
 8457. 181466                switch (left.id + right.id) {
 8458. 181466                case "()":
 8459. 181466                case "[]":
 8460. 181466                case "{}":
 8461. 181466
 8462. 181466// If left and right are opener and closer, then the placement of right depends
 8463. 181466// on the openness. Illegal pairs (like '{]') have already been detected.
 8464. 181466
 8465. 181466// test_cause:
 8466. 181466// ["let aa=[];", "whitage", "opener_closer", "", 0]
 8467. 181466// ["let aa=aa();", "whitage", "opener_closer", "", 0]
 8468. 181466// ["let aa={};", "whitage", "opener_closer", "", 0]
 8469. 181466
 8470. 181466                    test_cause("opener_closer");
 8471. 181466                    if (left.line === right.line) {
 8472. 181466
 8473. 181466// test_cause:
 8474. 181466// ["let aa = aa( );", "no_space", "unexpected_space_a_b", ")", 14]
 8475. 181466
 8476. 181466                        no_space();
 8477. 181466                    } else {
 8478. 181466
 8479. 181466// test_cause:
 8480. 181466// ["let aa = aa(\n );", "expected_at", "expected_a_at_b_c", "1", 2]
 8481. 181466
 8482. 181466                        at_margin(0);
 8483. 181466                    }
 8484. 181466                    break;
 8485. 181466                default:
 8486. 181466
 8487. 181466// test_cause:
 8488. 181466// ["let aa=(0);", "whitage", "opener_operand", "", 0]
 8489. 181466// ["let aa=[0];", "whitage", "opener_operand", "", 0]
 8490. 181466// ["let aa=`${0}`;", "whitage", "opener_operand", "", 0]
 8491. 181466// ["let aa=aa(0);", "whitage", "opener_operand", "", 0]
 8492. 181466// ["let aa={aa:0};", "whitage", "opener_operand", "", 0]
 8493. 181466
 8494. 181466                    test_cause("opener_operand");
 8495. 181466                    opening = left.open || (left.line !== right.line);
 8496. 181466                    push();
 8497. 181466                    switch (left.id) {
 8498. 181466                    case "${":
 8499. 181466                        closer = "}";
 8500. 181466                        break;
 8501. 181466                    case "(":
 8502. 181466                        closer = ")";
 8503. 181466                        break;
 8504. 181466                    case "[":
 8505. 181466                        closer = "]";
 8506. 181466                        break;
 8507. 181466                    case "{":
 8508. 181466                        closer = "}";
 8509. 181466                        break;
 8510. 181466                    }
 8511. 181466                    if (opening) {
 8512. 181466
 8513. 181466// test_cause:
 8514. 181466// ["function aa(){\nreturn;\n}", "whitage", "opening", "", 0]
 8515. 181466// ["let aa=(\n0\n);", "whitage", "opening", "", 0]
 8516. 181466// ["let aa=[\n0\n];", "whitage", "opening", "", 0]
 8517. 181466// ["let aa=`${\n0\n}`;", "whitage", "opening", "", 0]
 8518. 181466// ["let aa={\naa:0\n};", "whitage", "opening", "", 0]
 8519. 181466
 8520. 181466                        test_cause("opening");
 8521. 181466                        free = closer === ")" && left.free;
 8522. 181466                        open = true;
 8523. 181466                        margin += mode_indent;
 8524. 181466                        if (right.role === "label") {
 8525. 181466                            if (right.from !== 0) {
 8526. 181466
 8527. 181466// test_cause:
 8528. 181466// ["
 8529. 181466// function aa() {
 8530. 181466//  bb:
 8531. 181466//     while (aa) {
 8532. 181466//         if (aa) {
 8533. 181466//             break bb;
 8534. 181466//         }
 8535. 181466//     }
 8536. 181466// }
 8537. 181466// ", "expected_at", "expected_a_at_b_c", "1", 2]
 8538. 181466
 8539. 181466                                expected_at(0);
 8540. 181466                            }
 8541. 181466                        } else if (right.switch) {
 8542. 181466                            at_margin(-mode_indent);
 8543. 181466                        } else {
 8544. 181466                            at_margin(0);
 8545. 181466                        }
 8546. 181466                    } else {
 8547. 181466                        if (right.statement || right.role === "label") {
 8548. 181466
 8549. 181466// test_cause:
 8550. 181466// ["
 8551. 181466// function aa() {bb:
 8552. 181466//     while (aa) {
 8553. 181466//         aa();
 8554. 181466//     }
 8555. 181466// }
 8556. 181466// ", "whitage", "expected_line_break_a_b", "bb", 16]
 8557. 181466
 8558. 181466                            warn(
 8559. 181466                                "expected_line_break_a_b",
 8560. 181466                                right,
 8561. 181466                                artifact(left),
 8562. 181466                                artifact(right)
 8563. 181466                            );
 8564. 181466                        }
 8565. 181466
 8566. 181466// test_cause:
 8567. 181466// ["let aa=(0);", "whitage", "not_free", "", 0]
 8568. 181466// ["let aa=[0];", "whitage", "not_free", "", 0]
 8569. 181466// ["let aa=`${0}`;", "whitage", "not_free", "", 0]
 8570. 181466// ["let aa={aa:0};", "whitage", "not_free", "", 0]
 8571. 181466
 8572. 181466                        test_cause("not_free");
 8573. 181466                        free = false;
 8574. 181466                        open = false;
 8575. 181466
 8576. 181466// test_cause:
 8577. 181466// ["let aa = ( 0 );", "no_space_only", "unexpected_space_a_b", "0", 12]
 8578. 181466
 8579. 181466                        no_space_only();
 8580. 181466                    }
 8581. 181466                }
 8582. 181466                break;
 8583. 181466            default:
 8584. 181466                if (right.statement === true) {
 8585. 181466                    if (left.id === "else") {
 8586. 181466
 8587. 181466// test_cause:
 8588. 181466// ["
 8589. 181466// let aa = 0;
 8590. 181466// if (aa) {
 8591. 181466//     aa();
 8592. 181466// } else  if (aa) {
 8593. 181466//     aa();
 8594. 181466// }
 8595. 181466// ", "one_space_only", "expected_space_a_b", "if", 9]
 8596. 181466
 8597. 181466                        one_space_only();
 8598. 181466                    } else {
 8599. 181466
 8600. 181466// test_cause:
 8601. 181466// [" let aa = 0;", "expected_at", "expected_a_at_b_c", "1", 2]
 8602. 181466
 8603. 181466                        at_margin(0);
 8604. 181466                        open = false;
 8605. 181466                    }
 8606. 181466
 8607. 181466// If right is a closer, then pop the previous state.
 8608. 181466
 8609. 181466                } else if (right.id === closer) {
 8610. 181466                    pop();
 8611. 181466                    if (opening && right.id !== ";") {
 8612. 181466                        at_margin(0);
 8613. 181466                    } else {
 8614. 181466                        no_space_only();
 8615. 181466                    }
 8616. 181466                } else {
 8617. 181466
 8618. 181466// Left is not an opener, and right is not a closer.
 8619. 181466// The nature of left and right will determine the space between them.
 8620. 181466
 8621. 181466// If left is ',' or ';' or right is a statement then if open,
 8622. 181466// right must go at the margin, or if closed, a space between.
 8623. 181466
 8624. 181466                    if (right.switch) {
 8625. 181466                        at_margin(-mode_indent);
 8626. 181466                    } else if (right.role === "label") {
 8627. 181466                        if (right.from !== 0) {
 8628. 181466
 8629. 181466// test_cause:
 8630. 181466// ["
 8631. 181466// function aa() {
 8632. 181466//     aa();cc:
 8633. 181466//     while (aa) {
 8634. 181466//         if (aa) {
 8635. 181466//             break cc;
 8636. 181466//         }
 8637. 181466//     }
 8638. 181466// }
 8639. 181466// ", "expected_at", "expected_a_at_b_c", "1", 10]
 8640. 181466
 8641. 181466                            expected_at(0);
 8642. 181466                        }
 8643. 181466                    } else if (left.id === ",") {
 8644. 181466                        if (!open || (
 8645. 181466                            (free || closer === "]")
 8646. 181466                            && left.line === right.line
 8647. 181466                        )) {
 8648. 181466
 8649. 181466// test_cause:
 8650. 181466// ["let {aa,bb} = 0;", "one_space", "expected_space_a_b", "bb", 9]
 8651. 181466
 8652. 181466                            one_space();
 8653. 181466                        } else {
 8654. 181466
 8655. 181466// test_cause:
 8656. 181466// ["
 8657. 181466// function aa() {
 8658. 181466//     aa(
 8659. 181466//         0,0
 8660. 181466//     );
 8661. 181466// }
 8662. 181466// ", "expected_at", "expected_a_at_b_c", "9", 11]
 8663. 181466
 8664. 181466                            at_margin(0);
 8665. 181466                        }
 8666. 181466
 8667. 181466// If right is a ternary operator, line it up on the margin.
 8668. 181466
 8669. 181466                    } else if (right.arity === "ternary") {
 8670. 181466                        if (open) {
 8671. 181466
 8672. 181466// test_cause:
 8673. 181466// ["
 8674. 181466// let aa = (
 8675. 181466//     aa
 8676. 181466//     ? 0
 8677. 181466// : 1
 8678. 181466// );
 8679. 181466// ", "expected_at", "expected_a_at_b_c", "5", 1]
 8680. 181466
 8681. 181466                            at_margin(0);
 8682. 181466                        } else {
 8683. 181466
 8684. 181466// test_cause:
 8685. 181466// ["let aa = (aa ? 0 : 1);", "whitage", "use_open", "?", 14]
 8686. 181466
 8687. 181466                            warn("use_open", right);
 8688. 181466                        }
 8689. 181466                    } else if (
 8690. 181466                        right.arity === "binary"
 8691. 181466                        && right.id === "("
 8692. 181466                        && free
 8693. 181466                    ) {
 8694. 181466
 8695. 181466// test_cause:
 8696. 181466// ["let aa = aa(\naa ()\n);", "no_space", "unexpected_space_a_b", "(", 4]
 8697. 181466
 8698. 181466                        no_space();
 8699. 181466                    } else if (
 8700. 181466                        left.id === "."
 8701. 181466                        || left.id === "?."
 8702. 181466                        || left.id === "..."
 8703. 181466                        || right.id === ","
 8704. 181466                        || right.id === ";"
 8705. 181466                        || right.id === ":"
 8706. 181466                        || (
 8707. 181466                            right.arity === "binary"
 8708. 181466                            && (right.id === "(" || right.id === "[")
 8709. 181466                        )
 8710. 181466                        || (
 8711. 181466                            right.arity === "function"
 8712. 181466                            && left.id !== "function"
 8713. 181466                        )
 8714. 181466                        || (right.id === "." || right.id === "?.")
 8715. 181466                    ) {
 8716. 181466
 8717. 181466// test_cause:
 8718. 181466// ["let aa = 0 ;", "no_space_only", "unexpected_space_a_b", ";", 12]
 8719. 181466// ["let aa = aa ?.aa;", "no_space_only", "unexpected_space_a_b", "?.", 13]
 8720. 181466
 8721. 181466                        no_space_only();
 8722. 181466                    } else if (left.id === ";") {
 8723. 181466
 8724. 181466// test_cause:
 8725. 181466// ["
 8726. 181466// /*jslint for*/
 8727. 181466// function aa() {
 8728. 181466//     for (
 8729. 181466//         aa();
 8730. 181466// aa;
 8731. 181466//         aa()
 8732. 181466//     ) {
 8733. 181466//         aa();
 8734. 181466//     }
 8735. 181466// }
 8736. 181466// ", "expected_at", "expected_a_at_b_c", "9", 1]
 8737. 181466
 8738. 181466                        if (open) {
 8739. 181466                            at_margin(0);
 8740. 181466                        }
 8741. 181466                    } else if (
 8742. 181466                        left.arity === "ternary"
 8743. 181466                        || left.id === "case"
 8744. 181466                        || left.id === "catch"
 8745. 181466                        || left.id === "else"
 8746. 181466                        || left.id === "finally"
 8747. 181466                        || left.id === "while"
 8748. 181466                        || left.id === "await"
 8749. 181466                        || right.id === "catch"
 8750. 181466                        || right.id === "else"
 8751. 181466                        || right.id === "finally"
 8752. 181466                        || (right.id === "while" && !right.statement)
 8753. 181466                        || (left.id === ")" && right.id === "{")
 8754. 181466                    ) {
 8755. 181466
 8756. 181466// test_cause:
 8757. 181466// ["
 8758. 181466// function aa() {
 8759. 181466//     do {
 8760. 181466//         aa();
 8761. 181466//     } while(aa());
 8762. 181466// }
 8763. 181466// ", "one_space_only", "expected_space_a_b", "(", 12]
 8764. 181466
 8765. 181466                        one_space_only();
 8766. 181466                    } else if (
 8767. 181466
 8768. 181466// There is a space between left and right.
 8769. 181466
 8770. 181466                        spaceop[left.id] === true
 8771. 181466                        || spaceop[right.id] === true
 8772. 181466                        || (
 8773. 181466                            left.arity === "binary"
 8774. 181466                            && (left.id === "+" || left.id === "-")
 8775. 181466                        )
 8776. 181466                        || (
 8777. 181466                            right.arity === "binary"
 8778. 181466                            && (right.id === "+" || right.id === "-")
 8779. 181466                        )
 8780. 181466                        || left.id === "function"
 8781. 181466                        || left.id === ":"
 8782. 181466                        || (
 8783. 181466                            (
 8784. 181466                                left.identifier
 8785. 181466                                || left.id === "(string)"
 8786. 181466                                || left.id === "(number)"
 8787. 181466                            )
 8788. 181466                            && (
 8789. 181466                                right.identifier
 8790. 181466                                || right.id === "(string)"
 8791. 181466                                || right.id === "(number)"
 8792. 181466                            )
 8793. 181466                        )
 8794. 181466                        || (left.arity === "statement" && right.id !== ";")
 8795. 181466                    ) {
 8796. 181466
 8797. 181466// test_cause:
 8798. 181466// ["let aa=0;", "one_space", "expected_space_a_b", "0", 8]
 8799. 181466// ["let aa={\naa:\n0\n};", "expected_at", "expected_a_at_b_c", "5", 1]
 8800. 181466
 8801. 181466                        one_space();
 8802. 181466                    } else if (left.arity === "unary" && left.id !== "`") {
 8803. 181466                        no_space_only();
 8804. 181466                    }
 8805. 181466                }
 8806. 181466            }
 8807. 181466            nr_comments_skipped = 0;
 8808. 181466            delete left.calls;
 8809. 181466            delete left.dead;
 8810. 181466            delete left.free;
 8811. 181466            delete left.init;
 8812. 181466            delete left.open;
 8813. 181466            delete left.used;
 8814. 181466            left = right;
 8815. 181466        }
 8816. 191641    });
 8817.    174}
 8818.      1
 8819.      5function jslint_report({
 8820.      5    exports,
 8821.      5    froms,
 8822.      5    functions,
 8823.      5    global,
 8824.      5    json,
 8825.      5    module,
 8826.      5    property,
 8827.      5    stop,
 8828.      5    warnings
 8829.      5}) {
 8830.      5
 8831.      5// This function will create human-readable, html-report
 8832.      5// for warnings, properties, and functions from jslint-result-object.
 8833.      5// Example usage:
 8834.      5//  let result = jslint("console.log('hello world')");
 8835.      5//  let html = jslint_report(result);
 8836.      5
 8837.      5    let html = "";
 8838.      5    let length_80 = 1111;
 8839.      5
 8840.   2190    function detail(title, list) {
 8841.   2190        return (
 8842.   2190            (Array.isArray(list) && list.length > 0)
 8843.    751            ? (
 8844.    751
 8845.    751// Google Lighthouse Accessibility - <dl>'s do not contain only properly-ordered
 8846.    751// <dt> and <dd> groups, <script>, <template> or <div> elements.
 8847.    751
 8848.    751                "<dl>"
 8849.    751                + "<dt>" + htmlEscape(title) + "</dt>"
 8850.    751                + "<dd>" + list.join(", ") + "</dd>"
 8851.    751                + "</dl>"
 8852.    751            )
 8853.   1439            : ""
 8854.   2190        );
 8855.   2190    }
 8856.      5
 8857.      5    html += "<div class=\"JSLINT_\" id=\"JSLINT_REPORT_HTML\">\n";
 8858.      5    html += String(`
 8859.      5<style class="JSLINT_REPORT_STYLE">
 8860.      5/* jslint utility2:true */
 8861.      5/*csslint box-model: false, ids:false */
 8862.      5/*csslint ignore:start*/
 8863.      5@font-face {
 8864.      5    font-display: swap;
 8865.      5    font-family: "Daley";
 8866.      5    src: url(
 8867.      5"data:font/woff2;base64,d09GMgABAAAAABy4AA4AAAAAThwAABxiAAEAAAAAAAAAAAAA\
 8868.      5AAAAAAAAAAAAAAAABmAAgiQINAmcDBEICuc41DEBNgIkA4R2C4I+AAQgBYkuByAMgScfYUIF\
 8869.      57NgjsHGAbcDVFkXZ5Jwd+P96IGPc9rl9ETBEaCzCJkvY2UpziRZ7zftZWk8052U9+NqX6vXL\
 8870.      5KDflSQnlJ0bP+QnPQAy744n9mup6H9PaCDFwM5zjf8exB89bZ1cdrYOP0NgnuRDRWlk9u/fE\
 8871.      5llkxqmfH8lmRQ/DAmER9opk9wR6suc1LvTiXNEe1vbhUCH2USgnEwH3vUm05JQqejGvZvOtz\
 8872.      57sIKEGgLdDNl/IrfqWVZG/wr42ekomEm91VA1p4LhHBuFzHF8//u7vvbREHMQqGtNLmiOOD/\
 8873.      5X7WWiwqyCE98qt0jk5JJmgR5WJJElBmzRb1F7a66MmSLTNWZ2XSHfKBSKHoVteSEJ6EOdvVw\
 8874.      5fNZOtXKDe39jXdRlkmMnOWIOFBgeEK/b0mFsgffnPyyAitNyutKky7J8a8MSEkAKGLgfptnS\
 8875.      5/gDRSo7vwdNUmQDB7oP6pK7QF5d9SrY8M/tkrXcurSIQAmX7tz7pd33LIB7GQkBQ/k81s/0D\
 8876.      5gpt4gbw7x0Cn/PocitK5KIGPGQIzQzAMuCeC2ERAidx9TySVqX06goT0SFFOOV9Kuxdi5Rg7\
 8877.      5l6n3c+nKRemidOm2dtFV1jXMk4rP2m6RJ8xEdPYONLTbeMgaJ1nwS2W4su3MHwqkkvJ2PdDU\
 8878.      5r7pgAnVRt4Kh789FXlD0r3p6jUtNO19O1s74U9pnIxqFpw+mBgF+8y30PAyw1dzlknLLVcSB\
 8879.      5J2OuCr9eV5Efew6cOGd47ZEfhrW7HXI+FBNFvWgWnugUU4UvlrV63niv2ZPeKu8M76y/HQaG\
 8880.      5weU+4Gzp+Y+cfb9R9djDWcd1Svr1xG7l+j/yf3eM996548qlC+dOzOqQ8//Lo0uaSEQCFuLD\
 8881.      5/bXyWhJ6aPmyaRonVPxGABFL4/0slcKI6f+PmT0M+QRsplmWnv4F49VT+JsPifoa6aeyr2Hz\
 8882.      5EeLdP1FEOV/ZN+c9sAuoNh0BRS0xgCCc9wME5s0HOKj/wc0fWYsTbFQpsZL5SayJPkL45kDo\
 8883.      5DcJJ10MvD0ZSq7FEIr1TfqZ7NC6s75zSp8viaNO5/PczYCV9z6NTa0KBdnGBg6kbdeBkRLfU\
 8884.      5qRd3D9Pqw5jWCc5WM/i95OE8731MBd1u2EmsXIa5dCvavY32U1Ytza4nfbERg6OVRZka7jq0\
 8885.      5r2FcXNDyEhXheaHtaU1o1kvO9MuBOHqugLUEzN+4jznu0oK9wZPur1lWVFfxl8lZzn2XwcjZ\
 8886.      5Csg/RJy0mAMMmgnqXS8ELhOCRUSLzvsM5gAPudEh2lVoRxGgyUVnArZMruE0YS1PqFMD3upb\
 8887.      5jVoecGj1KpWl6/ZysuyzkG4SGA4bps6FBQSg4e4IxNUgdmosmoDn0TpIex/s1BFau6GBNO4z\
 8888.      5cvWXypm4hEg5k3llelySFqNmUtRZ3PHBA7p4MBX1nK4awwAV6kWzIVbUA67A55QKYbMsgVaH\
 8889.      5c1ZxKuZ0DCyqxCsJjLyCEY36gf0wjAu3t0zemc87PmBCJbU9Lso0YAaYJUx8wsR02hYz5hGy\
 8890.      5Js0+A4uHGZgfuf5SOR9iBQuLhpOExaIFrHj6JlXanebzGHp2ELDh6av09PVE1fmdsj2oHRWs\
 8891.      5fOtYrV6wRCyx7XogHqvpnZiPBBdNcL6kIoS9UI/DOIlumlveSgv9oqMBYp7WZ2fGxAXmZmaG\
 8892.      5OCyJG6+wAszZFCQw/EXVjx+YA2uVyN6bhNWiZhgtYjAwR5U/7uV1scghiTGiAPZbA5ZqHw5u\
 8893.      5Yu1cDjhRwREBFyq2wa0R8GgceDUKPo2BX+MhoAkQ1EQIaZqVHMwH3xM+P32TTA34tmOMNZ4n\
 8894.      5mHXqn49fmE3qX1+wMNYoYetOsPx6wxKzkURImERJIjGSSJwkkiCJJEkiKZJImiSSIYlkSYqK\
 8895.      5UBu0UOopuLMmasiJW0PMFOO2UgbDif2NaQUqkBbyaGjdTUvuyamEQwCq9DWsxsG9qPt+VFqV\
 8896.      56cIsXcyWujWIEtNFdeia9ssNrJUpe3IDMPQZOReC8x+qvt17drPWdcHeL0gTarWwoQ6o828o\
 8897.      50EJzrA20yZsgVyVHdlCJOF3NaACxHbP38TA+MGx3St9c5t2CxbGtunB4J9AF4Px2rSr1wyK9\
 8898.      59KoXBR13vw9Fk9qhTX0ivZoanrvhLa5oiJO8cqR0lX7QtJ2c1a62V3PMtutaaoit+hxtXuC5\
 8899.      5ZUXJePSR6btQlt5g7PqPQ822g7F8D123pc4kaGXz7qYztJxDXCxJr7foKqxwy4rikI/NvINx\
 8900.      5bkArRTTnnMWy6YA8J39LfTweThKsqlt7Mz078NDSOPOGgtGTpeG8ZRBF+xKBjdSoNe8gE6uC\
 8901.      5ucOH98jE4+cv1JEjI555TFjYj4+0KdFlojzJGWp2wc1tCaYGSeO8dBfT0u3lpDY3tazzu4wn\
 8902.      5lF9wzy2nK+sTr/qEVdANoZ0ToBdD+MY4ewOHNnkXPBvKVXLSbEGfGVD0Nzr0Fs3HID3Y1Kqx\
 8903.      5mzJ6p1C1/R6Xneyw/q9YRDLahbnsI1u76XzMLPqsK0yvQDeQ4TMR41709sIssmEgs0XH1lcj\
 8904.      57HLnUG6u2Xpy5vbOowIGqrR6cwF0TLGI5PF7pkbzIVYQU0sIaoNgul3LGAH2B1nREFYXUMia\
 8905.      5prCeAzggGxrC5gIK2dK0exs/AIRKdlIIuxkUspdSsU+rqXagqXaooXakqTiWS/a0E7zA6QIK\
 8906.      5OdMUznMAh+RCQ7hcQCFXmspr3ciuds/6gPsZFPIgpfJhwUIepRAeZ1DIk5Tue4oKfSfKZyNV\
 8907.      5pKU/J7J4Abx1EMV5mXSRDl6lMfU6jfBmBww4k7f6gLzTB+J9od/kA/uGj2mET2nkn7+zQ/JF\
 8908.      5H5Kv+pB804fkOyvwI43wM438V5sdkd/6iPzRR+SvPiL/WIH/aYRxGqMb/Oqe3d54+LWR1vr2\
 8909.      5knnnc467iD247eXBA3YYBAiFfierClXz/8jyL3Qh/zP8y+Y/1eN8jq+SKZAML/lIidjwZ8N4\
 8910.      5aLthvhxGUkGPo+p0eHKZ0sT5FsqJcQCy9UhHIvcJFIlIvANTPFWUTUhSiVdsNRnvwEQxm5uc\
 8911.      5ksjdv5evJfpOgI6c7juH8pnG2RKwlXaDYe9g8rMwYfML3A2SMWeBDopJJsmS5dUE2KttnmQa\
 8912.      5JZlMspvEpJioiEDFNpPUTbwqG3Zjhx2VCeJrIf60s2mI6blZMZVyAyYzI+1a2Y0AIqcbLUgR\
 8913.      56iRbNtnp82GrImXW0YbcbczDgqQDWNdTenvtTAlT9iPHenluV+d3eed1/5MjMBrX2LgrK2ml\
 8914.      5FuoDOz036n/kaHbAeszR3jHoI4NWB3lusTfuVgkMUkLQaH0F6+pSCS11fXRwT421vs9s7axd\
 8915.      5nvtF7/eeIeq9s1aCLsLWdh+w7sXz3IYdEsSQ0LVsebmES/vXDU9k653W4MiNq8bMj5nLioCY\
 8916.      5edGgOT6tmYwqiOW1ugiEmew6iwjvvYb3SaeZJb7XNufOo9oH8FTneWGL+BLiclptpnhPwcui\
 8917.      5T+rzcF34+ycsL7p3AveuML9i9h13beylyg8CzEz5HppadqmmDxKrAquG9L3ztedRoWxEsAYt\
 8918.      5OM1Eu0G0gyTHkxf7cSkHJQRbA4xmlqHWkv1C0KhFhBq1z81Wq1CZoWic8TJ570WfSj5qsM+Q\
 8919.      5nl4k3H5+P+P3zlv9ltQrzv41qyiSwV/gOadyQBchsmwDGu/JI8tXflE8jqUVA0Zw0SKbdDC9\
 8920.      5c4FR+fak95SdF7uqpoRe9z6YRv+85YUzF4qJy6Q8GOVNwUn/ymyjNNbmcuVfXYeH2osLdCte\
 8921.      5ebmZRyUfQQZA1BSCLK4PWA/z1kBvDZm0t+i3or1LkMD6en95pGG0UOa8ZJXgS9TdEA1I2mZw\
 8922.      51JOWWxDu0NEh4rM19H55rvueMBUZV1RjkmB3oxkXhAckpa5gzzxUDA2VLOrWFAXx+4gmfU17\
 8923.      55o3v9H7EYdvGFuM+tDB3TA4ITjVUKduO/R4bXRAcPXZusWkN+t59sFz7Hyi0FkSdzrHXQVFq\
 8924.      5b8c9k9eLRjVlBbNvt4172CanYg/F3Rket1zCTc77UZ61Gq/Be9J8hrKrxbDZMEotf5o8zHDc\
 8925.      5/UJaEtdhgwHEcBEQKM+6NBWIewLmI1sHuWYAedZCw8U1hJfSWcld+2tv3jpCFc5FnosLWC0+\
 8926.      5DnAlnOXUXLoMXrmCVerNQkZHvRm8YtE12vG8+N/vOnPcu3vM1uOnzE3u3VP2ppmLZawm2NuO\
 8927.      5tPa7xwHFCgVKpox5PVrOmaDHrThk1tX864a2+/qhJd3nCFRQ+bfUKI4O+Wgk5byB3saMcUfV\
 8928.      5C8G137yMd16zRm3ZSq+UrDlk5ha3TiAj0b74prWO/vYG+RC+ronP1/McDtefBtY1XhZE0PIB\
 8929.      5wTe7CBTte2U6KPbYd5GffApQlDGssdfmxYGSlnHrQt7++KEwUg3ikkoQyKPixgUDB6Lozjv5\
 8930.      5vM5PBnllt+UzMnP6DStFsOfossbXOefWhQApACCNpkTYGAONIowDfndqDKRFuzn685nthZPe\
 8931.      5vEL7TIWkXAG2yxKBH90+yMzuRzWn3KMmyKGwZWnIErlJ9Vwt8OtR6+4TKad5y9+ViBtTzVG+\
 8932.      5tpv/xiLrcGKJRtYvCUlGeL4Dwy1jo1CSQe0X71EXK1YG44ztxTONjIslL8SwY0Cki0k0vsX/\
 8933.      5/xz7CxkAc9dEdJZhMy/JCGzD2FAGtUcag0tc2e2miJkp477V2qTKB+nFnDl/noxpXJ+yqVdO\
 8934.      5wNjbplmeiuburg9ii1Z1zwtG8QjcJAiVPSOV2mHzq1Qt7p2+YCcIKPmFusE5O+m8s+Wd8o3t\
 8935.      5qO1b1IZF8N0tx6RQnZ9Ux3gXijHlolixst6vhJV6ao0ZFzSprfAc3x0MLvxU0OsmXEVddMVK\
 8936.      529CC6mPgPtXTUW7tVnZxwm0DTJwNOeVRV4axMSPlpgyv1Va1MQhQqWwUOb0s+gVLOecos4Nf\
 8937.      5eqlFW3fLQrlP86R4XRxrDHF0VIx6ArM5/sTWtObY6U2aosgxbN6FUa1iNTUpMThk1sUfJOC6\
 8938.      5s1SKo9D0g1NfiVmavyful/K7nZdDgutV1A26i7FR3r16bv3zz1cGw+ta17IX/+ripyutix3C\
 8939.      5xNmCxs7uiqKu9/Zjjn06tblXpJxlaLF5Od0d5W9QhQrs2u6UN0trQlCyEK2j9VYgCEIDrhQN\
 8940.      5c00rxg/FOfZ1N+nLV7RXDsYP+p0EzqKcuPujzuzEQsu2mFf4nYvf3Yp32rq/RYLetDLuOOTc\
 8941.      50WXBtgoech7AHUxAxPBg81qWCsYlzTofRU5/MpuyNoegR6mCJO5ckrLOhWbG7xo/VGwGgpRb\
 8942.      5+Ch+TmlcuY6Qct/2x3gxzeDUU9u+ltexrjelJ0VRR9KXH/AqrbYxHa0vmQ/kBnE5EORBK1ZH\
 8943.      5mTSy7A8DJMgzzqDsu9ML5J3ufkuUNDCfN5UKAjBgw2I/QlS8MQ6o/ll9dTAdoM7HYtV4cNWE\
 8944.      5U4pOl5Y4SIzdMbNSjXFmsBV1uXXf7GaBZZslpFGFiIpokSzxWj4hjlGl4VKJDACo7ScxQf29\
 8945.      5kM8gHD3nUJkwkN2aW2TGttqwOrygJ7r9nYX2tYqy7Z3TQV5ocWzUI8l871y3LsQLoTgEO76B\
 8946.      5Upp69hy6VKRpZvpvgfQ2T06qgXjxh38eatREitX6bzKggIYmN4sAkA3a5oeJZDK3ahQrVJwa\
 8947.      5AD65cEGBkS/tKH9TtybiREEWCMcKD0HH0gELtjB+KNSk7bspmpr6eb0CscIiFyZpmXu8+gxw\
 8948.      5O7pJNbAK2h9q2c5dMHBaoi5DylbNGdweVVdN3Jm9u6YXXlmx4nYY2vIPfSkrE/vyv9gn/Z+j\
 8949.      5R3HKExaUhdV0Az77YWbQPhNfjw+F0vTteSMin+wIfxyPe0DEoI4uz6o2IXwsZC7sg8MicQ3o\
 8950.      5wys+NJYKVW72YiVQ5LKDVwrEg2jNVM6XdNjbsHlRDcAkD08o5iWtFB2dVoydRmmDRLalE+4t\
 8951.      53gBbAPa7n7qXXXbTZTJXZKy5+1W0K7dgYEcIlu90ovC0C+5gxXiKtZisT14qDJ7f2ksyK59U\
 8952.      5r3QeHtBb24mPz7YDB3rgMTyUZ/fxM8h2i1Z21B8/VA5+9l7BKaOJZ15lWsyPv/z6CjU32ZKq\
 8953.      5+QFeyUywxYnUxUmcQfGc1Sp69oE2n6zFL8BXf5rc3cJMM6S97gagTT1bi7cmAV4MibkC4rz/\
 8954.      5icmmFtMlo5aN1Wp3uxsBfd4+9T42xmxvd79FV/hfuviBcrIaX092PrY5rle9FR4wTnDzrwj4\
 8955.      57frD2d0KsMcdcADQ1Yu1LECg9Wj3yOS8OhrJdQBqXqsam17vmt2wjjjouHE/EO9sGPdqt23v\
 8956.      5j8rL6wid6ulagtNK5p1hjRkFtUxTIaZnIXk63Zb3P0t5MQ+3vxHIFrmgAdWwiDuA67tbVIF6\
 8957.      5wJ53z0uhyhsfH9bgF0kPT9v2hrT3HKIBgUXIYoxsVU+uryemiUiQEwh+BfxP//qLShlumR26\
 8958.      5I8OqjD+x3hHDj/IrEWmvyL6ioG/atfxe+5GzIqRgfaoayWOiTk+YixO15KDO6Os3XACDjboe\
 8959.      5ryXXOuEmTpDsc7czk+H04Kw1PNJazW32CAURHwBldqK0/nqYHtcrtLyyTYmoD8hbcnJUfa3U\
 8960.      53FxWNus7uic3Qm1BzEecJW0MAz+W2CyN9FLIy+EpSy6CjkXsllZw1uBs1SxrQWM97/vnHu7m\
 8961.      5OtrkRl8AtBN3RDxI/fg7dZLLtDFYuCYYPMwXiO6ZIpwJ1GGydI9oUYYgnQQKDKoMTcwsjrfe\
 8962.      5Tcht6y18bLcpNfX41WE27447vLNzHuF+j15co5N7Py8vKUpTCoghHMEYKkM6y02lvX+9XiFg\
 8963.      5xBKMRNiwX69+LJb2Xa5WGqo7Rlk0cxsLVd0l2UXAW5jORg31sFMKYWXsDcRUKRDP8Q87OjiM\
 8964.      5dI1hNEt43netf8rOyfp+L58fq3holY9gxXwRJLY6gahgLQi4hS8w9LS+rFcJtdSCBrQLWsMs\
 8965.      5aDg/n8/P8/N+fcyoLepYr3W/CIUT7HsRQTtkduddbVfbo6Twt6fyJVPRrUGqRkWp3rdry65v\
 8966.      5sPYInyq1mPHrQDrqGJYI/LzA/QAzAXLnx+lu9uxHTEka9xgWgRvqEioskh+UWgD4nDvTAxaz\
 8967.      53v9BqqmFuQwy1wSXye1Df1NXVF7G8bUFxUE4F9axG5fm+vFQJvP8iuYjrFveB6++AqmJTQJ0\
 8968.      59GHjbPhzdSzkZGxokQzONVs0R0FCPJz1hJKbvDKsaj9hT0vp/gH5oiT8pAbWsBChwAbxHgDd\
 8969.      559iJVZE3bAzPRN1RuG+MT7th+J3i6KFwVJvPvsGRDIZW4P2rVfiKjDVBM2Va+w6PgI0c5u3K\
 8970.      5O7MrWryPhXFFdBoAwi2JCaW9sZ3fTagQ4Tld6u4djwcWzeCdiYoeNbfalsRYo740afYQ1Rid\
 8971.      5Bp/E9mbcTemEjoWWXIU7I5nK5H/BEqmZnPMyhDV234BTLQKCe6nhU+frwQo1gNFWf+eQGN62\
 8972.      5aeF7BuzaN/94W2xlKd8t8KMA/3uoxymFt19OlCjYZeaMWbTKM9Yog9zDhptYMOzIQAoO7kn6\
 8973.      5nTao8CxjrRRgjKe7mKa+tzuufhAAZtgjA92THkulWvIzEi0++j1DvXMnupDUS8aVusWain+c\
 8974.      5CcvmR5orC+RcJs3wVahLYyEcqbvAS2e0QJ6BlU36R/IEd9Aol9q+M+UGvlo8EyRzISvqusNS\
 8975.      57ePQ6cQzG1s725db4jNYNHAfF3KFG8wHqDwZDpWDsJ5qRLXR1ulFx85GhkypPubYaCiOQ5DR\
 8976.      5PQUiNpgk4fLJHenSMLMiswXsqW4Cpln1rFoHzpOoBbuZIixmVyhKajeqlFmp8zNAEsbEJz0g\
 8977.      5X0qlQuykZhf82pkhq2hWtCtYUdBODn6iPTBJT5Zk8IqFxqfBeFKjXk/sMeumhT8muOtq2Bgn\
 8978.      5dR4fj6RoOi0zI25kajAXlDZhUhS39jipk39h/69AfDPBLmOxhDj7Lg/WUTbOwJiJ3p7WtOpm\
 8979.      5ypARmhorQifINNm1CNS99GfDcLbD8sn8Fvlmvn7CmW65Pdmu6bKtuE0tn7NglIX1e/JAJP+G\
 8980.      5gB3At7cSOp92rl0lp0pp0xVb5YaQedwGgcJA1pT4cy24lS+jvzDw86YTfb2igJm5MysHmejW\
 8981.      5ZTGXpoAoLBLucUGEz/DwbjqOdzGAl5jy5VoCQws5zNYl4SVt030aZulYMgpDBPZd+kL0wV+w\
 8982.      5nob2LPRDQGEbdUoeFm4fEKio9c/ferVlpSO8Bx7OFZyHip1PIizvoqFe02kpmS17TvIOty42\
 8983.      5+Q0QaCnOpeLsPwwo+vixIeIeUjucUsKejVlez35qyuC0mm5pJJJLEVP2JAe/LTOwUUfKJkNy\
 8984.      5lEe3Kdth241ZNQmkVcAIh6DZJBzvQov5fn3JZA0phBWdNq5iTsm5N2D8gyve3V3X2o3zF3VY\
 8985.      5OqEBgTIADAbC69z7vOKJjGOzHRmUUwLU66iabtIbqR6SPOHCL+fCTfvpKcB/oG2p3wRKErEJ\
 8986.      5v1YOfu9iaKEMLXS3ptdH8fwN2Rdww9bZ7rFa2bwrzcyux3o+hPV6bJZpb71j7lLAdzge3VX7\
 8987.      59uSCdz6f/FDb7+wzWnbbDSPj9R20+PybDUm/lVAsTuF0aycFQwJfPCUwcBvCGWEq6xoTIEOy\
 8988.      5b0bLta20+LYRYdyEceX7ypfezQKIy5OvJTAHCJy/WyOYaDVyPucMsHnZ0GCH75Cd//te1Bv2\
 8989.      5RkMykqYurBiNbuH3Xfuprirr4Dd453O6abAYGb5tw1d6wrBL8p1J1Sx9Lgw7yxqYn0FTrc0y\
 8990.      559yLlV+4zIkLfZlPFRVnanHpTyrIlpn4lGkt269+JXnIWhEQWNvuVsrt531jr+8AHkVZfQU8\
 8991.      58U/4AUZMuOj5iliigFrof/usmloYEI1f8erhJku75snYW7YmFmUcoC7UtG/KfJRuz6j0tWPa\
 8992.      556J5QA0rJHwSIhNT4GWvez19HT2lia+Pz7/+MVEWlvjY6+9P85a0y9qWkTzQ7nF0wDXpQpw3\
 8993.      5K4xnfK2L08b5MrxdeI+DDfVDeV2JY0Fp6KH602tj2MbxxKM8oG+wTkE/dr8jyo4Sfs/IV6uf\
 8994.      5+IIXpH2Nca1+WCJV5qEv193bcUELLR4iFu83xUedKy9353tn+3o01dF2bNEQ3fK9Q5tCXrCi\
 8995.      5La+woCuvEeYrr+PiN2+i2V/eDJck580pyra8BV5ZIZbpe3kr5vJD3pqoGsnbcl/d+ndvR23b\
 8996.      5K41M4dKwaAwDaMA1gZGBoQWAcYE9mYkmQOnAjkaG41FkGkIP2BAIgKvUvzhpE5JbA6lze2iL\
 8997.      55Nr+AwiDo2W4BStvK30dKy0JGNbzAY5akexsrV0xo5K8rY50LOTLvDyukIZNbRLKOCk18mD3\
 8998.      5WxmZGlsCMxNdGFYGNJnetUWyCPgo4BONEL4I9b8UeEBGYXuCdCd+DkctrqVLYXGSfE46kvAu\
 8999.      5+ltK5SRxQPnjUqyJXsSYs6VY6WPKfns9+IXjHhd5wQvGipgFdMwVEQ+A7a2AAS0clQwH7KHW\
 9000.      5SEGjhnklSVRghMtPy6gEtJRIKJeYkpQyQiequQunFOOU4BLdK1yp55olZS6npyPhMnvK7xIa\
 9001.      5pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
 9002.      51R8uVi8Zu9nRFqk/t0gR6wmWOlzuKRqk33HpO8qQ+nbGoEZLL/0Va156SJ+u+t86/os7ic49\
 9003.      5/7xoEqvL+2E8VOyCTuT/7j269Zy4jUtN+g4="
 9004.      5    ) format("woff2");
 9005.      5}
 9006.      5*,
 9007.      5*:after,
 9008.      5*:before {
 9009.      5    border: 0;
 9010.      5    box-sizing: border-box;
 9011.      5    margin: 0;
 9012.      5    padding: 0;
 9013.      5}
 9014.      5.JSLINT_ {
 9015.      5    -ms-text-size-adjust: none;
 9016.      5    -webkit-text-size-adjust: none;
 9017.      5    text-size-adjust: none;
 9018.      5}
 9019.      5/*csslint ignore:end*/
 9020.      5
 9021.      5.JSLINT_ {
 9022.      5    font-family: daley, sans-serif;
 9023.      5    font-size: 14px;
 9024.      5}
 9025.      5.JSLINT_ fieldset legend,
 9026.      5.JSLINT_ .center {
 9027.      5    font-family: daley, sans-serif;
 9028.      5    font-size: 14px;
 9029.      5    text-align: center;
 9030.      5}
 9031.      5.JSLINT_ fieldset textarea,
 9032.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS dt,
 9033.      5.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
 9034.      5    font-size: 12px;
 9035.      5}
 9036.      5.JSLINT_ fieldset textarea,
 9037.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS > div {
 9038.      5    font-family: monospace;
 9039.      5}
 9040.      5.JSLINT_ fieldset > div {
 9041.      5    font-family: sans-serif;
 9042.      5}
 9043.      5
 9044.      5body {
 9045.      5    background: antiquewhite;
 9046.      5}
 9047.      5.JSLINT_ fieldset {
 9048.      5    background: gainsboro;
 9049.      5    clear: both;
 9050.      5    margin: 16px 40px;
 9051.      5    width: auto;
 9052.      5}
 9053.      5.JSLINT_ fieldset address {
 9054.      5    float: right;
 9055.      5}
 9056.      5.JSLINT_ fieldset legend {
 9057.      5    background: darkslategray;
 9058.      5    color: white;
 9059.      5    padding: 4px 0;
 9060.      5    width: 100%;
 9061.      5}
 9062.      5.JSLINT_ fieldset textarea {
 9063.      5    padding: 4px;
 9064.      5    resize: none;
 9065.      5    white-space: pre;
 9066.      5    width: 100%;
 9067.      5}
 9068.      5.JSLINT_ fieldset textarea::selection {
 9069.      5    background: wheat;
 9070.      5}
 9071.      5.JSLINT_ fieldset > div {
 9072.      5    padding: 16px;
 9073.      5    width: 100%;
 9074.      5    word-wrap: break-word;
 9075.      5}
 9076.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level {
 9077.      5    background: cornsilk;
 9078.      5    padding: 8px 16px;
 9079.      5}
 9080.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dd {
 9081.      5    line-height: 20px;
 9082.      5    padding-left: 120px;
 9083.      5}
 9084.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dfn {
 9085.      5    display: block;
 9086.      5    font-style: normal;
 9087.      5    font-weight: bold;
 9088.      5    line-height: 20px;
 9089.      5}
 9090.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dl {
 9091.      5    position: relative
 9092.      5}
 9093.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dt {
 9094.      5    font-style: italic;
 9095.      5    line-height: 20px;
 9096.      5    position: absolute;
 9097.      5    text-align: right;
 9098.      5    width: 100px;
 9099.      5}
 9100.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level0 {
 9101.      5    background: white;
 9102.      5}
 9103.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level1 {
 9104.      5    /* yellow */
 9105.      5    background: #ffffe0;
 9106.      5    margin-left: 16px;
 9107.      5}
 9108.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level2 {
 9109.      5    /* green */
 9110.      5    background: #e0ffe0;
 9111.      5    margin-left: 32px;
 9112.      5}
 9113.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level3 {
 9114.      5    /* blue */
 9115.      5    background: #D0D0ff;
 9116.      5    margin-left: 48px;
 9117.      5}
 9118.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level4 {
 9119.      5    /* purple */
 9120.      5    background: #ffe0ff;
 9121.      5    margin-left: 64px;
 9122.      5}
 9123.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level5 {
 9124.      5    /* red */
 9125.      5    background: #ffe0e0;
 9126.      5    margin-left: 80px;
 9127.      5}
 9128.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level6 {
 9129.      5    /* orange */
 9130.      5    background: #ffe390;
 9131.      5    margin-left: 96px;
 9132.      5}
 9133.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level7 {
 9134.      5    /* gray */
 9135.      5    background: #e0e0e0;
 9136.      5    margin-left: 112px;
 9137.      5}
 9138.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level8 {
 9139.      5    margin-left: 128px;
 9140.      5}
 9141.      5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level9 {
 9142.      5    margin-left: 144px;
 9143.      5}
 9144.      5.JSLINT_ #JSLINT_REPORT_PROPERTIES {
 9145.      5    background: transparent;
 9146.      5}
 9147.      5.JSLINT_ #JSLINT_REPORT_PROPERTIES textarea {
 9148.      5    background: honeydew;
 9149.      5    height: 100px;
 9150.      5}
 9151.      5.JSLINT_ #JSLINT_REPORT_TITLE {
 9152.      5    color: darkslategray;
 9153.      5    font-size: 32px;
 9154.      5    padding-top: 16px;
 9155.      5    text-align: center;
 9156.      5}
 9157.      5.JSLINT_ #JSLINT_REPORT_WARNINGS cite {
 9158.      5    display: block;
 9159.      5    margin: 16px 0 4px 0;
 9160.      5    overflow-x: hidden;
 9161.      5    white-space: pre-line;
 9162.      5}
 9163.      5.JSLINT_ #JSLINT_REPORT_WARNINGS cite:nth-child(1) {
 9164.      5    margin-top: 0;
 9165.      5}
 9166.      5.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
 9167.      5    background: lavenderblush;
 9168.      5    display: block;
 9169.      5    padding: 4px;
 9170.      5    white-space: pre-wrap;
 9171.      5}
 9172.      5.JSLINT_ #JSLINT_REPORT_WARNINGS > div {
 9173.      5    background: pink;
 9174.      5    max-height: 400px;
 9175.      5    overflow-y: auto;
 9176.      5}
 9177.      5.JSLINT_ #JSLINT_REPORT_WARNINGS > legend {
 9178.      5/* Google Lighthouse Accessibility - Background and foreground colors do not */
 9179.      5/* have a sufficient contrast ratio. */
 9180.      5    /* background: indianred; */
 9181.      5    background: #b44;
 9182.      5}
 9183.      5</style>
 9184.      5            `).trim() + "\n";
 9185.      5
 9186.      5// Produce the Title.
 9187.      5
 9188.      5    html += "<div id=\"JSLINT_REPORT_TITLE\">\n";
 9189.      5    html += "JSLint Report\n";
 9190.      5    html += "</div>\n";
 9191.      5
 9192.      5// Produce the HTML Error Report.
 9193.      5// <cite>
 9194.      5//     <address>LINE_NUMBER</address>
 9195.      5//     MESSAGE
 9196.      5// </cite>
 9197.      5// <samp>EVIDENCE</samp>
 9198.      5
 9199.      5    html += "<fieldset id=\"JSLINT_REPORT_WARNINGS\">\n";
 9200.      5    html += "<legend>Report: Warnings (" + warnings.length + ")</legend>\n";
 9201.      5    html += "<div>\n";
 9202.      1    if (stop) {
 9203.      1        html += "<div class=\"center\">JSLint was unable to finish.</div>\n";
 9204.      1    }
 9205.      7    warnings.forEach(function ({
 9206.      7        column,
 9207.      7        line,
 9208.      7        line_source,
 9209.      7        message,
 9210.      7        stack_trace = ""
 9211.      7    }, ii) {
 9212.      7        html += (
 9213.      7            "<cite>"
 9214.      7            + "<address>" + htmlEscape(line + ": " + column) + "</address>"
 9215.      7            + htmlEscape((ii + 1) + ". " + message)
 9216.      7            + "</cite>"
 9217.      7            + "<samp>"
 9218.      7            + htmlEscape(line_source.slice(0, 400) + "\n" + stack_trace)
 9219.      7            + "</samp>\n"
 9220.      7        );
 9221.      7    });
 9222.      2    if (warnings.length === 0) {
 9223.      2        html += "<div class=\"center\">There are no warnings.</div>\n";
 9224.      2    }
 9225.      5    html += "</div>\n";
 9226.      5    html += "</fieldset>\n";
 9227.      5
 9228.      5// Produce the /*property*/ directive.
 9229.      5
 9230.      5    html += "<fieldset id=\"JSLINT_REPORT_PROPERTIES\">\n";
 9231.      5    html += (
 9232.      5        "<legend>Report: Properties ("
 9233.      5        + Object.keys(property).length
 9234.      5        + ")</legend>\n"
 9235.      5    );
 9236.      5    html += "<label>\n";
 9237.      5    html += "<textarea readonly>";
 9238.      5    html += "/*property";
 9239.    295    Object.keys(property).sort().forEach(function (key, ii) {
 9240.    294        if (ii !== 0) {
 9241.    294            html += ",";
 9242.    294            length_80 += 2;
 9243.    294        }
 9244.     41        if (length_80 + key.length >= 80) {
 9245.     41            length_80 = 4;
 9246.     41            html += "\n   ";
 9247.     41        }
 9248.    295        html += " " + key;
 9249.    295        length_80 += key.length;
 9250.    295    });
 9251.      5    html += "\n*/\n";
 9252.      5    html += "</textarea>\n";
 9253.      5    html += "</label>\n";
 9254.      5    html += "</fieldset>\n";
 9255.      5
 9256.      5// Produce the HTML Function Report.
 9257.      5// <div class=LEVEL>
 9258.      5//     <address>LINE_NUMBER</address>
 9259.      5//     <dfn>FUNCTION_NAME_AND_SIGNATURE</dfn>
 9260.      5//     <dl>
 9261.      5//         <dt>DETAIL</dt>
 9262.      5//         <dd>NAMES</dd>
 9263.      5//     </dl>
 9264.      5// </div>
 9265.      5
 9266.      5    html += "<fieldset id=\"JSLINT_REPORT_FUNCTIONS\">\n";
 9267.      5    html += "<legend>Report: Functions (" + functions.length + ")</legend>\n";
 9268.      5    html += "<div>\n";
 9269.      2    if (json) {
 9270.      2
 9271.      2// Bugfix - fix website crashing when linting pure json-object.
 9272.      2// return (
 9273.      2
 9274.      2        html += (
 9275.      2            warnings.length === 0
 9276.      2            ? "<div class=\"center\">JSON: good.</div>\n"
 9277.      2            : "<div class=\"center\">JSON: bad.</div>\n"
 9278.      2        );
 9279.      3    } else if (functions.length === 0) {
 9280.      3        html += "<div class=\"center\">There are no functions.</div>\n";
 9281.      3    }
 9282.      5    exports = Object.keys(exports).sort();
 9283.      5    froms.sort();
 9284.      5    global = Object.keys(global.context).sort();
 9285.      5    module = (
 9286.      5        module
 9287.      1        ? "module"
 9288.      4        : "global"
 9289.      5    );
 9290.      2    if (global.length + froms.length + exports.length > 0) {
 9291.      2        html += "<div class=\"level level0\">\n";
 9292.      2        html += detail(module, global);
 9293.      2        html += detail("import from", froms);
 9294.      2        html += detail("export", exports);
 9295.      2        html += "</div>\n";
 9296.      2    }
 9297.    312    functions.forEach(function (the_function) {
 9298.    312        let {
 9299.    312            context,
 9300.    312            level,
 9301.    312            line,
 9302.    312            name,
 9303.    312
 9304.    312// Bugfix - fix html-report from crashing if parameters is undefined.
 9305.    312
 9306.    312            parameters = [],
 9307.    312            signature
 9308.    312        } = the_function;
 9309.    312        let list = Object.keys(context);
 9310.    312        let params;
 9311.    312        html += (
 9312.    312            "<div class=\"level level" + htmlEscape(level) + "\">"
 9313.    312            + "<address>" + htmlEscape(line) + "</address>"
 9314.    312            + "<dfn>"
 9315.    312            + (
 9316.    312                name === "=>"
 9317.      1                ? htmlEscape(signature) + " =>"
 9318.    311                : (
 9319.    311                    typeof name === "string"
 9320.    311                    ? "\u00ab" + htmlEscape(name) + "\u00bb"
 9321.    311                    : htmlEscape(name.id)
 9322.    311                )
 9323.    312            ) + htmlEscape(signature)
 9324.    312            + "</dfn>"
 9325.    312        );
 9326.    312        params = [];
 9327.    447        parameters.forEach(function extract({
 9328.    447            id,
 9329.    447            names
 9330.    447        }) {
 9331.    447            switch (id) {
 9332.      5            case "[":
 9333.     39            case "{":
 9334.     39
 9335.     39// Recurse extract().
 9336.     39
 9337.     39                names.forEach(extract);
 9338.     39                break;
 9339.      3            case "ignore":
 9340.      3                break;
 9341.    405            default:
 9342.    405                params.push(id);
 9343.    447            }
 9344.    447        });
 9345.    312        html += detail("parameter", params.sort());
 9346.    312        list.sort();
 9347.   2114        html += detail("variable", list.filter(function (id) {
 9348.   2114            return (
 9349.   2114                context[id].role === "variable"
 9350.   1630                && context[id].parent === the_function
 9351.   2114            );
 9352.   2114        }));
 9353.   2114        html += detail("exception", list.filter(function (id) {
 9354.   2114            return context[id].role === "exception";
 9355.   2114        }));
 9356.   2114        html += detail("closure", list.filter(function (id) {
 9357.   2114            return (
 9358.   2114                context[id].closure === true
 9359.   1414                && context[id].parent === the_function
 9360.   2114            );
 9361.   2114        }));
 9362.   2114        html += detail("outer", list.filter(function (id) {
 9363.   2114            return (
 9364.   2114                context[id].parent !== the_function
 9365.   1131                && context[id].parent.id !== "(global)"
 9366.   2114            );
 9367.   2114        }));
 9368.   2114        html += detail(module, list.filter(function (id) {
 9369.   2114            return context[id].parent.id === "(global)";
 9370.   2114        }));
 9371.   2114        html += detail("label", list.filter(function (id) {
 9372.   2114            return context[id].role === "label";
 9373.   2114        }));
 9374.    312        html += "</div>\n";
 9375.    312    });
 9376.      5    html += "</div>\n";
 9377.      5    html += "</fieldset>\n";
 9378.      5    html += "</div>\n";
 9379.      5    return html;
 9380.      5}
 9381.      1
 9382.      3async function jstestDescribe(description, testFunction) {
 9383.      3
 9384.      3// This function will create-and-run test-group <testFunction>
 9385.      3// with given <description>.
 9386.      3
 9387.      3    let message;
 9388.      3    let result;
 9389.      3
 9390.      3// Init jstestTimeStart.
 9391.      3
 9392.      1    if (jstestTimeStart === undefined) {
 9393.      1        jstestTimeStart = jstestTimeStart || Date.now();
 9394.      1        process.on("exit", jstestOnExit);
 9395.      1    }
 9396.      3
 9397.      3// Init jstestItList.
 9398.      3
 9399.      3    jstestItList = [];
 9400.      3    testFunction();
 9401.      3
 9402.      3// Wait for jstestItList to resolve.
 9403.      3
 9404.      3    result = await Promise.all(jstestItList);
 9405.      3
 9406.      3// Print test results.
 9407.      3
 9408.      3    message = (
 9409.      3        "\n  " + (Date.now() - jstestTimeStart) + "ms"
 9410.      3        + " - test describe - " + description + "\n"
 9411.     19        + result.map(function ([
 9412.     19            err, description, mode
 9413.     19        ]) {
 9414.     19            jstestItCount += 1;
 9415.      1            if (err) {
 9416.      1                jstestCountFailed += 1;
 9417.      1                err = (
 9418.      1                    "    \u001b[31m\u2718 " + jstestItCount + ". test it - "
 9419.      1                    + description + "\n" + err.stack + "\u001b[39m"
 9420.      1                );
 9421.      1                if (mode === "pass") {
 9422.      1                    jstestCountFailed -= 1;
 9423.      1                    err = "";
 9424.      1                }
 9425.      1            }
 9426.     19            return err || (
 9427.     19                "    \u001b[32m\u2714 " + jstestItCount + ". test it - "
 9428.     19                + description + "\u001b[39m"
 9429.     19            );
 9430.     19        }).join("\n")
 9431.      3    );
 9432.      3    console.error(message);
 9433.      3}
 9434.      1
 9435.     19function jstestIt(description, testFunction, mode) {
 9436.     19
 9437.     19// This function will create-and-run test-case <testFunction>
 9438.     19// inside current test-group with given <description>.
 9439.     19
 9440.     19    jstestCountTotal += 1;
 9441.     19    jstestItList.push(new Promise(async function (resolve) {
 9442.     19        let err;
 9443.     19        try {
 9444.     18            await testFunction();
 9445.     18        } catch (errCaught) {
 9446.      1            err = errCaught;
 9447.      1        }
 9448.     19        resolve([
 9449.     19            err, description, mode
 9450.     19        ]);
 9451.     19    }));
 9452.     19}
 9453.      1
 9454.      2function jstestOnExit(exitCode, processExit, countFailed) {
 9455.      2
 9456.      2// This function will on process-exit, print test-report
 9457.      2// and exit with non-zero exit-code if any test failed.
 9458.      2
 9459.      2    let message = (
 9460.      2        (
 9461.      2            (jstestCountFailed || countFailed)
 9462.      1            ? "\n\u001b[31m"
 9463.      1            : "\n\u001b[32m"
 9464.      2        )
 9465.      2        + "  tests total  - " + jstestCountTotal + "\n"
 9466.      2        + "  tests failed - " + jstestCountFailed + "\n"
 9467.      2        + "\u001b[39m"
 9468.      2    );
 9469.      1    if (!processExit) {
 9470.      1        console.error(message);
 9471.      1        processExit = process.exit;
 9472.      1    }
 9473.      2    processExit(exitCode || jstestCountFailed);
 9474.      2    return message;
 9475.      2}
 9476.      1
 9477.     77async function moduleFsInit() {
 9478.     77
 9479.     77// This function will import nodejs builtin-modules if they have not yet been
 9480.     77// imported.
 9481.     77
 9482.     77// State 3 - Modules already imported.
 9483.     77
 9484.     73    if (moduleFs !== undefined) {
 9485.     73        return;
 9486.     73    }
 9487.      4
 9488.      4// State 2 - Wait while modules are importing.
 9489.      4
 9490.      4    if (moduleFsInitResolveList !== undefined) {
 9491.      3        return new Promise(function (resolve) {
 9492.      3            moduleFsInitResolveList.push(resolve);
 9493.      3        });
 9494.      3    }
 9495.      1
 9496.      1// State 1 - Start importing modules.
 9497.      1
 9498.      1    moduleFsInitResolveList = [];
 9499.      1    [
 9500.      1        moduleChildProcess,
 9501.      1        moduleFs,
 9502.      1        modulePath,
 9503.      1        moduleUrl
 9504.      1    ] = await Promise.all([
 9505.      1        import("child_process"),
 9506.      1        import("fs"),
 9507.      1        import("path"),
 9508.      1        import("url")
 9509.      1    ]);
 9510.      3    while (moduleFsInitResolveList.length > 0) {
 9511.      3        moduleFsInitResolveList.shift()();
 9512.      3    }
 9513.     77}
 9514.      1
 9515.   2480function noop(val) {
 9516.   2480
 9517.   2480// This function will do nothing except return <val>.
 9518.   2480
 9519.   2480    return val;
 9520.   2480}
 9521.      1
 9522.  10077function objectDeepCopyWithKeysSorted(obj) {
 9523.  10077
 9524.  10077// This function will recursively deep-copy <obj> with keys sorted.
 9525.  10077
 9526.  10077    let sorted;
 9527.   6357    if (typeof obj !== "object" || !obj) {
 9528.   6357        return obj;
 9529.   6357    }
 9530.   3720
 9531.   3720// recursively deep-copy list with child-keys sorted
 9532.   3720
 9533.   3720    if (Array.isArray(obj)) {
 9534.   1126        return obj.map(objectDeepCopyWithKeysSorted);
 9535.   2594    }
 9536.   2594
 9537.   2594// recursively deep-copy obj with keys sorted
 9538.   2594
 9539.   2594    sorted = {};
 9540.   7481    Object.keys(obj).sort().forEach(function (key) {
 9541.   7481        sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
 9542.   7481    });
 9543.   2594    return sorted;
 9544.   2594}
 9545.      1
 9546.   2573function object_assign_from_list(dict, list, val) {
 9547.   2573
 9548.   2573// Assign each property-name from <list> to <dict>.
 9549.   2573
 9550.  82087    list.forEach(function (key) {
 9551.  82087        dict[key] = val;
 9552.  82087    });
 9553.   2573    return dict;
 9554.   2573}
 9555.      1
 9556.     96function v8CoverageListMerge(processCovs) {
 9557.     96
 9558.     96// This function is derived from MIT Licensed v8-coverage at
 9559.     96// https://github.com/demurgos/v8-coverage/tree/master/ts
 9560.     96// https://github.com/demurgos/v8-coverage/blob/master/ts/LICENSE.md
 9561.     96//
 9562.     96// Merges a list of v8 process coverages.
 9563.     96// The result is normalized.
 9564.     96// The input values may be mutated, it is not safe to use them after passing
 9565.     96// them to this function.
 9566.     96// The computation is synchronous.
 9567.     96// @param processCovs Process coverages to merge.
 9568.     96// @return Merged process coverage.
 9569.     96
 9570.     96    let resultMerged = [];      // List of merged scripts from processCovs.
 9571.     96    let urlToScriptDict = new Map();    // Map scriptCov.url to scriptCovs.
 9572.     96
 9573.   1090    function compareRangeList(aa, bb) {
 9574.   1090
 9575.   1090// Compares two range coverages.
 9576.   1090// The ranges are first ordered by ascending `startOffset` and then by
 9577.   1090// descending `endOffset`.
 9578.   1090// This corresponds to a pre-order tree traversal.
 9579.   1090
 9580.   1061        if (aa.startOffset !== bb.startOffset) {
 9581.   1061            return aa.startOffset - bb.startOffset;
 9582.   1061        }
 9583.     29        return bb.endOffset - aa.endOffset;
 9584.     29    }
 9585.     96
 9586.   1668    function dictKeyValueAppend(dict, key, val) {
 9587.   1668
 9588.   1668// This function will append <val> to list <dict>[<key>].
 9589.   1668
 9590.   1668        let list = dict.get(key);
 9591.   1130        if (list === undefined) {
 9592.   1130            list = [];
 9593.   1130            dict.set(key, list);
 9594.   1130        }
 9595.   1668        list.push(val);
 9596.   1668    }
 9597.     96
 9598.    381    function mergeTreeList(parentTrees) {
 9599.    381
 9600.    381// This function will return RangeTree object with <parentTrees> merged into
 9601.    381// property-children.
 9602.    381// @precondition Same `start` and `end` for all the parentTrees
 9603.    381
 9604.    119        if (parentTrees.length <= 1) {
 9605.    119            return parentTrees[0];
 9606.    262        }
 9607.    262
 9608.    262// new RangeTree().
 9609.    262
 9610.    262        return {
 9611.    262
 9612.    262// Merge parentTrees into property-children.
 9613.    262
 9614.    262            children: mergeTreeListToChildren(parentTrees),
 9615.    663            delta: parentTrees.reduce(function (aa, bb) {
 9616.    663                return aa + bb.delta;
 9617.    663            }, 0),
 9618.    262            end: parentTrees[0].end,
 9619.    262            start: parentTrees[0].start
 9620.    262        };
 9621.    262    }
 9622.     96
 9623.    262    function mergeTreeListToChildren(parentTrees) {
 9624.    262
 9625.    262// This function will return <resultChildren> with <parentTrees> merged.
 9626.    262
 9627.    262        let openRange;
 9628.    262        let parentToChildDict = new Map();      // Map parent to child.
 9629.    262        let queueList;
 9630.    262        let queueListIi = 0;
 9631.    262        let queueOffset;
 9632.    262        let queueTrees;
 9633.    262        let resultChildren = [];
 9634.    262        let startToTreeDict = new Map();        // Map tree.start to tree.
 9635.    634        function nextXxx() {
 9636.    634
 9637.    634// Increment nextOffset, nextTrees.
 9638.    634
 9639.    634            let [
 9640.    634                nextOffset, nextTrees
 9641.    297            ] = queueList[queueListIi] || [];
 9642.    634            let openRangeEnd;
 9643.    578            if (queueTrees === undefined) {
 9644.    578                queueListIi += 1;
 9645.    578
 9646.    578// Increment nextOffset, nextTrees.
 9647.    578
 9648.    578            } else if (nextOffset === undefined || nextOffset > queueOffset) {
 9649.     56                nextOffset = queueOffset;
 9650.     56                nextTrees = queueTrees;
 9651.     56                queueTrees = undefined;
 9652.     56
 9653.     56// Concat queueTrees to nextTrees.
 9654.     56
 9655.     56            } else {
 9656.     56                if (nextOffset === queueOffset) {
 9657.     56                    queueTrees.forEach(function (tree) {
 9658.     56                        nextTrees.push(tree);
 9659.     56                    });
 9660.     56                    queueTrees = undefined;
 9661.     56                }
 9662.     56                queueListIi += 1;
 9663.     56            }
 9664.    634
 9665.    634// Reached end of queueList.
 9666.    634
 9667.    262            if (nextOffset === undefined) {
 9668.    262                if (openRange !== undefined) {
 9669.    262
 9670.    262// Append nested-children from parentToChildDict (within openRange) to
 9671.    262// resultChildren.
 9672.    262
 9673.    262                    resultAppendNextChild();
 9674.    262                }
 9675.    262                return true;
 9676.    372            }
 9677.    372            if (openRange !== undefined && openRange.end <= nextOffset) {
 9678.    128
 9679.    128// Append nested-children from parentToChildDict (within openRange) to
 9680.    128// resultChildren.
 9681.    128
 9682.    128                resultAppendNextChild();
 9683.    128                openRange = undefined;
 9684.    372            }
 9685.    372            if (openRange === undefined) {
 9686.    290                openRangeEnd = nextOffset + 1;
 9687.    498                nextTrees.forEach(function ({
 9688.    498                    parentIi,
 9689.    498                    tree
 9690.    498                }) {
 9691.    498                    openRangeEnd = Math.max(openRangeEnd, tree.end);
 9692.    498
 9693.    498// Append children from nextTrees to parentToChildDict.
 9694.    498
 9695.    498                    dictKeyValueAppend(parentToChildDict, parentIi, tree);
 9696.    498                });
 9697.    290                queueOffset = openRangeEnd;
 9698.    290                openRange = {
 9699.    290                    end: openRangeEnd,
 9700.    290                    start: nextOffset
 9701.    290                };
 9702.    290            } else {
 9703.    114                nextTrees.forEach(function ({
 9704.    114                    parentIi,
 9705.    114                    tree
 9706.    114                }) {
 9707.    114                    let right;
 9708.     82                    if (tree.end > openRange.end) {
 9709.     82                        right = treeSplit(tree, openRange.end);
 9710.     82                        if (queueTrees === undefined) {
 9711.     82                            queueTrees = [];
 9712.     82                        }
 9713.     82
 9714.     82// new RangeTreeWithParent().
 9715.     82
 9716.     82                        queueTrees.push({
 9717.     82                            parentIi,
 9718.     82                            tree: right
 9719.     82                        });
 9720.     82                    }
 9721.    114
 9722.    114// Append children from nextTrees to parentToChildDict.
 9723.    114
 9724.    114                    dictKeyValueAppend(parentToChildDict, parentIi, tree);
 9725.    114                });
 9726.     82            }
 9727.    634        }
 9728.    290        function resultAppendNextChild() {
 9729.    290
 9730.    290// This function will append next child to <resultChildren>.
 9731.    290
 9732.    290            let treesMatching = [];
 9733.    585            parentToChildDict.forEach(function (nested) {
 9734.    585                if (
 9735.    585                    nested.length === 1
 9736.    559                    && nested[0].start === openRange.start
 9737.    476                    && nested[0].end === openRange.end
 9738.    464                ) {
 9739.    464                    treesMatching.push(nested[0]);
 9740.    464                } else {
 9741.    121
 9742.    121// new rangeTreeCreate().
 9743.    121
 9744.    121                    treesMatching.push({
 9745.    121                        children: nested,
 9746.    121                        delta: 0,
 9747.    121                        end: openRange.end,
 9748.    121                        start: openRange.start
 9749.    121                    });
 9750.    121                }
 9751.    585            });
 9752.    290            parentToChildDict.clear();
 9753.    290
 9754.    290// Recurse mergeTreeList().
 9755.    290
 9756.    290            resultChildren.push(mergeTreeList(treesMatching));
 9757.    290        }
 9758.     75        function treeSplit(tree, offset) {
 9759.     75
 9760.     75// This function will split <tree> along <offset> and return the right-side.
 9761.     75// @precondition `tree.start < offset && offset < tree.end`
 9762.     75// @return RangeTree Right part
 9763.     75
 9764.     75            let child;
 9765.     75            let ii = 0;
 9766.     75            let leftChildLen = tree.children.length;
 9767.     75            let mid;
 9768.     75            let resultTree;
 9769.     75            let rightChildren;
 9770.     75
 9771.     75// TODO(perf): Binary search (check overhead) //jslint-quiet
 9772.     75
 9773.     19            while (ii < tree.children.length) {
 9774.     19                child = tree.children[ii];
 9775.     19                if (child.start < offset && offset < child.end) {
 9776.     19
 9777.     19// Recurse treeSplit().
 9778.     19
 9779.     19                    mid = treeSplit(child, offset);
 9780.     19                    leftChildLen = ii + 1;
 9781.     19                    break;
 9782.     19                }
 9783.     19                if (child.start >= offset) {
 9784.     19                    leftChildLen = ii;
 9785.     19                    break;
 9786.     19                }
 9787.     19                ii += 1;
 9788.     19            }
 9789.     75            rightChildren = tree.children.splice(
 9790.     75                leftChildLen,
 9791.     75                tree.children.length - leftChildLen
 9792.     75            );
 9793.      4            if (mid !== undefined) {
 9794.      4                rightChildren.unshift(mid);
 9795.      4            }
 9796.     75
 9797.     75// new rangeTreeCreate().
 9798.     75
 9799.     75            resultTree = {
 9800.     75                children: rightChildren,
 9801.     75                delta: tree.delta,
 9802.     75                end: tree.end,
 9803.     75                start: offset
 9804.     75            };
 9805.     75            tree.end = offset;
 9806.     75            return resultTree;
 9807.     75        }
 9808.    262
 9809.    262// Init startToTreeDict.
 9810.    262
 9811.    663        parentTrees.forEach(function (parentTree, parentIi) {
 9812.    541            parentTree.children.forEach(function (child) {
 9813.    541
 9814.    541// Append child with child.start to startToTreeDict.
 9815.    541
 9816.    541                dictKeyValueAppend(startToTreeDict, child.start, {
 9817.    541                    parentIi,
 9818.    541                    tree: child
 9819.    541                });
 9820.    541            });
 9821.    663        });
 9822.    262
 9823.    262// init queueList.
 9824.    262
 9825.    333        queueList = Array.from(startToTreeDict).map(function ([
 9826.    333            startOffset, trees
 9827.    333        ]) {
 9828.    333
 9829.    333// new StartEvent().
 9830.    333
 9831.    333            return [
 9832.    333                startOffset, trees
 9833.    333            ];
 9834.    216        }).sort(function (aa, bb) {
 9835.    216            return aa[0] - bb[0];
 9836.    216        });
 9837.    634        while (true) {
 9838.    634            if (nextXxx()) {
 9839.    634                break;
 9840.    634            }
 9841.    634        }
 9842.    262        return resultChildren;
 9843.    262    }
 9844.     96
 9845.    689    function sortFunc(funcCov) {
 9846.    689
 9847.    689// This function will normalize-and-sort <funcCov>.ranges.
 9848.    689// Sorts the ranges (pre-order sort).
 9849.    689// TODO: Tree-based normalization of the ranges. //jslint-quiet
 9850.    689// @param funcCov Function coverage to normalize.
 9851.    689
 9852.    689        funcCov.ranges = treeToRanges(treeFromSortedRanges(
 9853.    689            funcCov.ranges.sort(compareRangeList)
 9854.    689        ));
 9855.    689        return funcCov;
 9856.    689    }
 9857.     96
 9858.     95    function sortProcess(processCov) {
 9859.     95
 9860.     95// This function will sort <processCov>.result.
 9861.     95// Sorts the scripts alphabetically by `url`.
 9862.     95// Reassigns script ids: the script at index `0` receives `"0"`, the script at
 9863.     95// index `1` receives `"1"` etc.
 9864.     95
 9865.     73        Object.entries(processCov.result.sort(function (aa, bb) {
 9866.     73            return (
 9867.     73                aa.url < bb.url
 9868.     32                ? -1
 9869.     41                : aa.url > bb.url
 9870.     41                ? 1
 9871.     41                : 0
 9872.     73            );
 9873.    129        })).forEach(function ([
 9874.    129            scriptId, scriptCov
 9875.    129        ]) {
 9876.    129            scriptCov.scriptId = scriptId.toString(10);
 9877.    129        });
 9878.     95        return processCov;
 9879.     95    }
 9880.     96
 9881.    129    function sortScript(scriptCov) {
 9882.    129
 9883.    129// This function will normalize-and-sort <scriptCov>.functions.
 9884.    129
 9885.    129// Normalize-and-sort functions[xxx].ranges.
 9886.    129
 9887.    688        scriptCov.functions.forEach(function (funcCov) {
 9888.    688            sortFunc(funcCov);
 9889.    688        });
 9890.    129
 9891.    129// Sort functions by root range (pre-order sort).
 9892.    129
 9893.    559        scriptCov.functions.sort(function (aa, bb) {
 9894.    559            return compareRangeList(aa.ranges[0], bb.ranges[0]);
 9895.    559        });
 9896.    129        return scriptCov;
 9897.    129    }
 9898.     96
 9899.    886    function treeFromSortedRanges(ranges) {
 9900.    886
 9901.    886// @precondition `ranges` are well-formed and pre-order sorted
 9902.    886
 9903.    886        let root;
 9904.    886        let stack = [];   // Stack of parent trees and parent counts.
 9905.   1849        ranges.forEach(function (range) {
 9906.   1849
 9907.   1849// new rangeTreeCreate().
 9908.   1849
 9909.   1849            let node = {
 9910.   1849                children: [],
 9911.   1849                delta: range.count,
 9912.   1849                end: range.endOffset,
 9913.   1849                start: range.startOffset
 9914.   1849            };
 9915.   1849            let parent;
 9916.   1849            let parentCount;
 9917.    886            if (root === undefined) {
 9918.    886                root = node;
 9919.    886                stack.push([
 9920.    886                    node, range.count
 9921.    886                ]);
 9922.    886                return;
 9923.    963            }
 9924.   1558            while (true) {
 9925.   1558                [
 9926.   1558                    parent, parentCount
 9927.   1558                ] = stack[stack.length - 1];
 9928.   1558
 9929.   1558// assert: `top !== undefined` (the ranges are sorted)
 9930.   1558
 9931.   1558                if (range.startOffset < parent.end) {
 9932.   1558                    break;
 9933.   1558                }
 9934.   1558                stack.pop();
 9935.   1558            }
 9936.    963            node.delta -= parentCount;
 9937.    963            parent.children.push(node);
 9938.    963            stack.push([
 9939.    963                node, range.count
 9940.    963            ]);
 9941.    963        });
 9942.    886        return root;
 9943.    886    }
 9944.     96
 9945.    780    function treeToRanges(tree) {
 9946.    780
 9947.    780// Get the range coverages corresponding to the tree.
 9948.    780// The ranges are pre-order sorted.
 9949.    780
 9950.    780        let count;
 9951.    780        let cur;
 9952.    780        let ii;
 9953.    780        let parentCount;
 9954.    780        let ranges = [];
 9955.    780        let stack = [           // Stack of parent trees and counts.
 9956.    780            [
 9957.    780                tree, 0
 9958.    780            ]
 9959.    780        ];
 9960.   1625        function normalizeRange(tree) {
 9961.   1625
 9962.   1625// @internal
 9963.   1625
 9964.   1625            let children = [];
 9965.   1625            let curEnd;
 9966.   1625            let head;
 9967.   1625            let tail = [];
 9968.    845            function endChain() {
 9969.     19                if (tail.length !== 0) {
 9970.     19                    head.end = tail[tail.length - 1].end;
 9971.     19                    tail.forEach(function (tailTree) {
 9972.     19                        tailTree.children.forEach(function (subChild) {
 9973.     19                            subChild.delta += tailTree.delta - head.delta;
 9974.     19                            head.children.push(subChild);
 9975.     19                        });
 9976.     19                    });
 9977.     19                    tail.length = 0;
 9978.     19                }
 9979.    845
 9980.    845// Recurse normalizeRange().
 9981.    845
 9982.    845                normalizeRange(head);
 9983.    845                children.push(head);
 9984.    845            }
 9985.    864            tree.children.forEach(function (child) {
 9986.    429                if (head === undefined) {
 9987.    429                    head = child;
 9988.    435                } else if (
 9989.    435                    child.delta === head.delta && child.start === curEnd
 9990.    435                ) {
 9991.    435                    tail.push(child);
 9992.    435                } else {
 9993.    435                    endChain();
 9994.    435                    head = child;
 9995.    435                }
 9996.    864                curEnd = child.end;
 9997.    864            });
 9998.    429            if (head !== undefined) {
 9999.    429                endChain();
10000.    429            }
10001.    236            if (children.length === 1) {
10002.    236                if (
10003.    236                    children[0].start === tree.start
10004.    236                    && children[0].end === tree.end
10005.    236                ) {
10006.    236                    tree.delta += children[0].delta;
10007.    236                    tree.children = children[0].children;
10008.    236
10009.    236// `.lazyCount` is zero for both (both are after normalization)
10010.    236
10011.    236                    return;
10012.    236                }
10013.   1619            }
10014.   1619            tree.children = children;
10015.   1619        }
10016.    780        normalizeRange(tree);
10017.   1619        while (stack.length > 0) {
10018.   1619            [
10019.   1619                cur, parentCount
10020.   1619            ] = stack.pop();
10021.   1619            count = parentCount + cur.delta;
10022.   1619            ranges.push({
10023.   1619                count,
10024.   1619                endOffset: cur.end,
10025.   1619                startOffset: cur.start
10026.   1619            });
10027.   1619            ii = cur.children.length - 1;
10028.   1619            while (ii >= 0) {
10029.   1619                stack.push([
10030.   1619                    cur.children[ii], count
10031.   1619                ]);
10032.   1619                ii -= 1;
10033.   1619            }
10034.   1619        }
10035.    780        return ranges;
10036.    780    }
10037.     96
10038.      1    if (processCovs.length === 0) {
10039.      1        return {
10040.      1            result: []
10041.      1        };
10042.     95    }
10043.     95    if (processCovs.length === 1) {
10044.     11
10045.     11// Normalize-and-sort scriptCov.
10046.     11
10047.     28        processCovs[0].result.forEach(function (scriptCov) {
10048.     28            sortScript(scriptCov);
10049.     28        });
10050.     11
10051.     11// Sort processCovs[0].result.
10052.     11
10053.     11        return sortProcess(processCovs[0]);
10054.     84    }
10055.     84
10056.     84// Init urlToScriptDict.
10057.     84
10058.    222    processCovs.forEach(function ({
10059.    222        result
10060.    222    }) {
10061.    240        result.forEach(function (scriptCov) {
10062.    240            dictKeyValueAppend(urlToScriptDict, scriptCov.url, scriptCov);
10063.    240        });
10064.    222    });
10065.    101    urlToScriptDict.forEach(function (scriptCovs) {
10066.    101
10067.    101// assert: `scriptCovs.length > 0`
10068.    101
10069.    101// function mergeScriptList(scriptCovs) {
10070.    101// Merges a list of matching script coverages.
10071.    101// Scripts are matching if they have the same `url`.
10072.    101// The result is normalized.
10073.    101// The input values may be mutated, it is not safe to use them after passing
10074.    101// them to this function.
10075.    101// The computation is synchronous.
10076.    101// @param scriptCovs Process coverages to merge.
10077.    101// @return Merged script coverage, or `undefined` if the input list was empty.
10078.    101
10079.    101        let functions = [];
10080.    101
10081.    101// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
10082.    101
10083.    101        let rangeToFuncDict = new Map();
10084.    101
10085.    101// Probably deadcode.
10086.    101// if (scriptCovs.length === 0) {
10087.    101//     return undefined;
10088.    101// }
10089.    101
10090.     84        if (scriptCovs.length === 1) {
10091.     84            resultMerged.push(sortScript(scriptCovs[0]));
10092.     84            return;
10093.     85        }
10094.     85
10095.     85// Init rangeToFuncDict.
10096.     85// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
10097.     85
10098.    224        scriptCovs.forEach(function ({
10099.    224            functions
10100.    224        }) {
10101.    275            functions.forEach(function (funcCov) {
10102.    275                dictKeyValueAppend(
10103.    275                    rangeToFuncDict,
10104.    275
10105.    275// This string can be used to match function with same root range.
10106.    275// The string is derived from the start and end offsets of the root range of
10107.    275// the function.
10108.    275// This assumes that `ranges` is non-empty (true for valid function coverages).
10109.    275
10110.    275                    (
10111.    275                        funcCov.ranges[0].startOffset
10112.    275                        + ";" + funcCov.ranges[0].endOffset
10113.    275                    ),
10114.    275                    funcCov
10115.    275                );
10116.    275            });
10117.    224        });
10118.    111        rangeToFuncDict.forEach(function (funcCovs) {
10119.    111
10120.    111// assert: `funcCovs.length > 0`
10121.    111
10122.    111// function mergeFuncList(funcCovs) {
10123.    111// Merges a list of matching function coverages.
10124.    111// Functions are matching if their root ranges have the same span.
10125.    111// The result is normalized.
10126.    111// The input values may be mutated, it is not safe to use them after passing
10127.    111// them to this function.
10128.    111// The computation is synchronous.
10129.    111// @param funcCovs Function coverages to merge.
10130.    111// @return Merged function coverage, or `undefined` if the input list was empty.
10131.    111
10132.    111            let count = 0;
10133.    111            let isBlockCoverage;
10134.    111            let merged;
10135.    111            let ranges;
10136.    111            let trees = [];
10137.    111
10138.    111// Probably deadcode.
10139.    111// if (funcCovs.length === 0) {
10140.    111//     return undefined;
10141.    111// }
10142.    111
10143.     85            if (funcCovs.length === 1) {
10144.     85                functions.push(sortFunc(funcCovs[0]));
10145.     85                return;
10146.    110            }
10147.    110
10148.    110// assert: `funcCovs[0].ranges.length > 0`
10149.    110
10150.    274            funcCovs.forEach(function (funcCov) {
10151.    274
10152.    274// assert: `funcCov.ranges.length > 0`
10153.    274// assert: `funcCov.ranges` is sorted
10154.    274
10155.    274                count += (
10156.    274                    funcCov.count !== undefined
10157.    110                    ? funcCov.count
10158.    272                    : funcCov.ranges[0].count
10159.    274                );
10160.    197                if (funcCov.isBlockCoverage) {
10161.    197                    trees.push(treeFromSortedRanges(funcCov.ranges));
10162.    197                }
10163.    274            });
10164.    110            if (trees.length > 0) {
10165.     91                isBlockCoverage = true;
10166.     91                ranges = treeToRanges(mergeTreeList(trees));
10167.     91            } else {
10168.     85                isBlockCoverage = false;
10169.     85                ranges = [
10170.     85                    {
10171.     85                        count,
10172.     85                        endOffset: funcCovs[0].ranges[0].endOffset,
10173.     85                        startOffset: funcCovs[0].ranges[0].startOffset
10174.     85                    }
10175.     85                ];
10176.    110            }
10177.    110            merged = {
10178.    110                functionName: funcCovs[0].functionName,
10179.    110                isBlockCoverage,
10180.    110                ranges
10181.    110            };
10182.    110            if (count !== ranges[0].count) {
10183.     85                merged.count = count;
10184.    110            }
10185.    110
10186.    110// assert: `merged` is normalized
10187.    110
10188.    110            functions.push(merged);
10189.    110        });
10190.     85        resultMerged.push(sortScript({
10191.     85            functions,
10192.     85            scriptId: scriptCovs[0].scriptId,
10193.     85            url: scriptCovs[0].url
10194.     85        }));
10195.     85    });
10196.     84    return sortProcess({
10197.     84        result: resultMerged
10198.     84    });
10199.     84}
10200.      1
10201.      7async function v8CoverageReportCreate({
10202.      7    consoleError,
10203.      7    coverageDir,
10204.      7    processArgv = []
10205.      7}) {
10206.      7
10207.      7// This function will create html-coverage-reports directly from
10208.      7// v8-coverage-files in <coverageDir>.
10209.      7// 1. Spawn node.js program <processArgv> with NODE_V8_COVERAGE.
10210.      7// 2. Merge JSON v8-coverage-files in <coverageDir>.
10211.      7// 3. Create html-coverage-reports in <coverageDir>.
10212.      7
10213.      7    let cwd;
10214.      7    let exitCode = 0;
10215.      7    let fileDict;
10216.      7    let promiseList = [];
10217.      7    let v8CoverageObj;
10218.      7
10219.     11    function htmlRender({
10220.     11        fileList,
10221.     11        lineList,
10222.     11        modeIndex,
10223.     11        pathname
10224.     11    }) {
10225.     11        let html;
10226.     11        let padLines;
10227.     11        let padPathname;
10228.     11        let txt;
10229.     11        let txtBorder;
10230.     11        html = "";
10231.     11        html += String(`
10232.     11<!DOCTYPE html>
10233.     11<html lang="en">
10234.     11<head>
10235.     11<title>V8 Coverage Report</title>
10236.     11<style>
10237.     11/* jslint utility2:true */
10238.     11/*csslint ignore:start*/
10239.     11* {
10240.     11box-sizing: border-box;
10241.     11    font-family: consolas, menlo, monospace;
10242.     11}
10243.     11/*csslint ignore:end*/
10244.     11body {
10245.     11    margin: 0;
10246.     11}
10247.     11.coverage pre {
10248.     11    margin: 5px 0;
10249.     11}
10250.     11.coverage table {
10251.     11    border-collapse: collapse;
10252.     11}
10253.     11.coverage td,
10254.     11.coverage th {
10255.     11    border: 1px solid #777;
10256.     11    margin: 0;
10257.     11    padding: 5px;
10258.     11}
10259.     11.coverage td span {
10260.     11    display: inline-block;
10261.     11    width: 100%;
10262.     11}
10263.     11.coverage .content {
10264.     11    padding: 0 5px;
10265.     11}
10266.     11.coverage .content a {
10267.     11    text-decoration: none;
10268.     11}
10269.     11.coverage .count {
10270.     11    margin: 0 5px;
10271.     11    padding: 0 5px;
10272.     11}
10273.     11.coverage .footer,
10274.     11.coverage .header {
10275.     11    padding: 20px;
10276.     11}
10277.     11.coverage .footer {
10278.     11    text-align: center;
10279.     11}
10280.     11.coverage .percentbar {
10281.     11    height: 12px;
10282.     11    margin: 2px 0;
10283.     11    min-width: 200px;
10284.     11    position: relative;
10285.     11    width: 100%;
10286.     11}
10287.     11.coverage .percentbar div {
10288.     11    height: 100%;
10289.     11    position: absolute;
10290.     11}
10291.     11.coverage .title {
10292.     11    font-size: large;
10293.     11    font-weight: bold;
10294.     11    margin-bottom: 10px;
10295.     11}
10296.     11
10297.     11.coverage td,
10298.     11.coverage th {
10299.     11    background: #fff;
10300.     11}
10301.     11.coverage .count {
10302.     11    background: #9d9;
10303.     11    color: #777;
10304.     11}
10305.     11.coverage .coverageHigh{
10306.     11    background: #9d9;
10307.     11}
10308.     11.coverage .coverageIgnore{
10309.     11    background: #ccc;
10310.     11}
10311.     11.coverage .coverageLow{
10312.     11    background: #ebb;
10313.     11}
10314.     11.coverage .coverageMedium{
10315.     11    background: #fd7;
10316.     11}
10317.     11.coverage .footer,
10318.     11.coverage .header {
10319.     11    background: #ddd;
10320.     11}
10321.     11.coverage .lineno {
10322.     11    background: #ddd;
10323.     11}
10324.     11.coverage .percentbar {
10325.     11    background: #999;
10326.     11}
10327.     11.coverage .percentbar div {
10328.     11    background: #666;
10329.     11}
10330.     11.coverage .uncovered {
10331.     11    background: #dbb;
10332.     11}
10333.     11
10334.     11.coverage pre:hover span,
10335.     11.coverage tr:hover td {
10336.     11    background: #7d7;
10337.     11}
10338.     11.coverage pre:hover span.uncovered,
10339.     11.coverage tr:hover td.coverageLow {
10340.     11    background: #d99;
10341.     11}
10342.     11</style>
10343.     11</head>
10344.     11<body class="coverage">
10345.     11<!-- header start -->
10346.     11<div class="header">
10347.     11<div class="title">V8 Coverage Report</div>
10348.     11<table>
10349.     11<thead>
10350.     11    <tr>
10351.     11    <th>Files covered</th>
10352.     11    <th>Lines</th>
10353.     11    </tr>
10354.     11</thead>
10355.     11<tbody>
10356.     11        `).trim() + "\n";
10357.      6        if (modeIndex) {
10358.      6            padLines = String("(ignore) 100.00 %").length;
10359.      6            padPathname = 32;
10360.      6            fileList.unshift({
10361.      6                linesCovered: 0,
10362.      6                linesTotal: 0,
10363.      6                modeCoverageIgnoreFile: "",
10364.      6                pathname: "./"
10365.      6            });
10366.      6            fileList.slice(1).forEach(function ({
10367.      6                linesCovered,
10368.      6                linesTotal,
10369.      6                modeCoverageIgnoreFile,
10370.      6                pathname
10371.      6            }) {
10372.      6                if (!modeCoverageIgnoreFile) {
10373.      6                    fileList[0].linesCovered += linesCovered;
10374.      6                    fileList[0].linesTotal += linesTotal;
10375.      6                }
10376.      6                padPathname = Math.max(padPathname, pathname.length + 2);
10377.      6                padLines = Math.max(
10378.      6                    padLines,
10379.      6                    String(linesCovered + " / " + linesTotal).length
10380.      6                );
10381.      6            });
10382.      6        }
10383.     11        txtBorder = (
10384.     11            "+" + "-".repeat(padPathname + 2) + "+"
10385.     11            + "-".repeat(padLines + 2) + "+\n"
10386.     11        );
10387.     11        txt = "";
10388.     11        txt += "V8 Coverage Report\n";
10389.     11        txt += txtBorder;
10390.     11        txt += (
10391.     11            "| " + String("Files covered").padEnd(padPathname, " ") + " | "
10392.     11            + String("Lines").padStart(padLines, " ") + " |\n"
10393.     11        );
10394.     11        txt += txtBorder;
10395.     16        fileList.forEach(function ({
10396.     16            linesCovered,
10397.     16            linesTotal,
10398.     16            modeCoverageIgnoreFile,
10399.     16            pathname
10400.     16        }, ii) {
10401.     16            let coverageLevel;
10402.     16            let coveragePct;
10403.     16            let fill;
10404.     16            let str1;
10405.     16            let str2;
10406.     16            let xx1;
10407.     16            let xx2;
10408.      2            coveragePct = Math.floor(10000 * linesCovered / linesTotal || 0);
10409.     16            coverageLevel = (
10410.     16                modeCoverageIgnoreFile
10411.      2                ? "coverageIgnore"
10412.     14                : coveragePct >= 8000
10413.     14                ? "coverageHigh"
10414.     14                : coveragePct >= 5000
10415.     14                ? "coverageMedium"
10416.     14                : "coverageLow"
10417.     16            );
10418.     16            coveragePct = String(coveragePct).replace((
10419.     16                /..$/m
10420.     16            ), ".$&");
10421.     11            if (modeIndex && ii === 0) {
10422.      6                fill = (
10423.      6
10424.      6// Badge-color rgb-red.
10425.      6
10426.      6                    "#" + Math.round(
10427.      6                        (100 - Number(coveragePct)) * 2.21
10428.      6                    ).toString(16).padStart(2, "0")
10429.      6
10430.      6// Badge-color rgb-green.
10431.      6
10432.      6                    + Math.round(
10433.      6                        Number(coveragePct) * 2.21
10434.      6                    ).toString(16).padStart(2, "0")
10435.      6
10436.      6// Badge-color rgb-blue.
10437.      6
10438.      6                    + "00"
10439.      6                );
10440.      6                str1 = "coverage";
10441.      6                str2 = coveragePct + " %";
10442.      6                xx1 = 6 * str1.length + 20;
10443.      6                xx2 = 6 * str2.length + 20;
10444.      6
10445.      6// Fs - write coverage_badge.svg
10446.      6
10447.      6                promiseList.push(fsWriteFileWithParents((
10448.      6                    coverageDir + "coverage_badge.svg"
10449.      6                ), String(`
10450.      6<svg height="20" width="${xx1 + xx2}" xmlns="http://www.w3.org/2000/svg">
10451.      6<rect fill="#555" height="20" width="${xx1 + xx2}"/>
10452.      6<rect fill="${fill}" height="20" width="${xx2}" x="${xx1}"/>
10453.      6<g
10454.      6    fill="#fff"
10455.      6    font-family="dejavu sans, verdana, geneva, sans-serif"
10456.      6    font-size="11"
10457.      6    font-weight="bold"
10458.      6    text-anchor="middle"
10459.      6>
10460.      6<text x="${0.5 * xx1}" y="14">${str1}</text>
10461.      6<text x="${xx1 + 0.5 * xx2}" y="14">${str2}</text>
10462.      6</g>
10463.      6</svg>
10464.      6                `).trim() + "\n"));
10465.      6                pathname = "";
10466.      6            }
10467.     16            txt += (
10468.     16                "| "
10469.     16                + String("./" + pathname).padEnd(padPathname, " ") + " | "
10470.     16                + String(
10471.     16                    modeCoverageIgnoreFile + " " + coveragePct + " %"
10472.     16                ).padStart(padLines, " ") + " |\n"
10473.     16            );
10474.     16            txt += (
10475.     16                "| " + "*".repeat(
10476.     16                    Math.round(0.01 * coveragePct * padPathname)
10477.     16                ).padEnd(padPathname, "_") + " | "
10478.     16                + String(
10479.     16                    linesCovered + " / " + linesTotal
10480.     16                ).padStart(padLines, " ") + " |\n"
10481.     16            );
10482.     16            txt += txtBorder;
10483.     16            pathname = htmlEscape(pathname);
10484.     16
10485.     16// CL-37251d17 - Bugfix - Fix incorrect http-link to index.html.
10486.     16
10487.     16            html += String(`
10488.     16    <tr>
10489.     16    <td class="${coverageLevel}">
10490.     16            ${(
10491.     16                modeIndex
10492.     11                ? (
10493.     11                    "<a href=\"" + (pathname || "index") + ".html\">. / "
10494.     11                    + pathname + "</a><br>"
10495.     11                )
10496.      5                : (
10497.      5                    "<a href=\""
10498.      5                    + "../".repeat(pathname.split("/").length - 1)
10499.      5                    + "index.html\">. / </a>"
10500.      5                    + pathname + "<br>"
10501.      5                )
10502.     16            )}
10503.     16        <div class="percentbar">
10504.     16            <div style="width: ${coveragePct}%;"></div>
10505.     16        </div>
10506.     16    </td>
10507.     16    <td style="text-align: right;">
10508.     16        ${modeCoverageIgnoreFile} ${coveragePct} %<br>
10509.     16        ${linesCovered} / ${linesTotal}
10510.     16    </td>
10511.     16    </tr>
10512.     16        `).trim() + "\n";
10513.     16        });
10514.     11        html += String(`
10515.     11</tbody>
10516.     11</table>
10517.     11</div>
10518.     11<!-- header end -->
10519.     11        `).trim() + "\n";
10520.      5        if (!modeIndex) {
10521.      5            html += String(`
10522.      5<!-- content start -->
10523.      5<div class="content">
10524.      5            `).trim() + "\n";
10525.  10980            lineList.forEach(function ({
10526.  10980                count,
10527.  10980                holeList,
10528.  10980                line,
10529.  10980                startOffset
10530.  10980            }, ii) {
10531.  10980                let chunk;
10532.  10980                let inHole;
10533.  10980                let lineHtml;
10534.  10980                let lineId;
10535.  10980                lineHtml = "";
10536.  10980                lineId = "line_" + (ii + 1);
10537.  10980                switch (count) {
10538.  10980
10539.  10980// PR-364 - Probably deadcode.
10540.  10980// case -1:
10541.  10980
10542.  10555                case 0:
10543.  10555                    if (holeList.length === 0) {
10544.  10555                        lineHtml += "</span>";
10545.  10555                        lineHtml += "<span class=\"uncovered\">";
10546.  10555                        lineHtml += htmlEscape(line);
10547.  10555                        break;
10548.  10555                    }
10549.  10555                    line = line.split("").map(function (char) {
10550.  10555                        return {
10551.  10555                            char,
10552.  10555                            isHole: undefined
10553.  10555                        };
10554.  10555                    });
10555.  10555                    holeList.forEach(function ([
10556.  10555                        aa, bb
10557.  10555                    ]) {
10558.  10555                        aa = Math.max(aa - startOffset, 0);
10559.  10555                        bb = Math.min(bb - startOffset, line.length);
10560.  10555                        while (aa < bb) {
10561.  10555                            line[aa].isHole = true;
10562.  10555                            aa += 1;
10563.  10555                        }
10564.  10555                    });
10565.  10555                    chunk = "";
10566.  10555                    line.forEach(function ({
10567.  10555                        char,
10568.  10555                        isHole
10569.  10555                    }) {
10570.  10555                        if (inHole !== isHole) {
10571.  10555                            lineHtml += htmlEscape(chunk);
10572.  10555                            lineHtml += (
10573.  10555                                isHole
10574.  10555                                ? "</span><span class=\"uncovered\">"
10575.  10555                                : "</span><span>"
10576.  10555                            );
10577.  10555                            chunk = "";
10578.  10555                            inHole = isHole;
10579.  10555                        }
10580.  10555                        chunk += char;
10581.  10555                    });
10582.  10555                    lineHtml += htmlEscape(chunk);
10583.  10555                    break;
10584.    425                default:
10585.    425                    lineHtml += htmlEscape(line);
10586.  10980                }
10587.  10980                html += String(`
10588.  10980<pre>
10589.  10980<span class="lineno">
10590.  10980<a href="#${lineId}" id="${lineId}">${String(ii + 1).padStart(5, " ")}.</a>
10591.  10980</span>
10592.  10980<span class="count
10593.  10980                ${(
10594.  10980                    count <= 0
10595.  10555                    ? "uncovered"
10596.    425                    : ""
10597.  10980                )}"
10598.  10980>
10599.  10980${String(count).padStart(7, " ")}
10600.  10980</span>
10601.  10980<span>${lineHtml}</span>
10602.  10980</pre>
10603.  10980                `).replace((
10604.  10980                    /\n/g
10605.  10980                ), "").trim() + "\n";
10606.  10980            });
10607.      5            html += String(`
10608.      5</div>
10609.      5<!-- content end -->
10610.      5            `).trim() + "\n";
10611.      5        }
10612.     11        html += String(`
10613.     11<div class="footer">
10614.     11    [
10615.     11    This document was created with
10616.     11    <a href="https://github.com/jslint-org/jslint">JSLint</a>
10617.     11    ]
10618.     11</div>
10619.     11</body>
10620.     11</html>
10621.     11        `).trim() + "\n";
10622.     11
10623.     11// Fs - write <file>.html
10624.     11
10625.     11        promiseList.push(fsWriteFileWithParents(pathname + ".html", html));
10626.      5        if (!modeIndex) {
10627.      5            return;
10628.      6        }
10629.      6
10630.      6// Fs - write coverage_report.txt
10631.      6
10632.      6        consoleError("\n" + txt);
10633.      6        promiseList.push(fsWriteFileWithParents((
10634.      6            coverageDir + "coverage_report.txt"
10635.      6        ), txt));
10636.      6    }
10637.      7
10638.    181    function pathnameRelativeCwd(pathname) {
10639.    181
10640.    181// This function will if <pathname> is inside <cwd>,
10641.    181// return it relative to <cwd>, else empty-string.
10642.    181
10643.    181        pathname = modulePath.resolve(pathname).replace((
10644.    181            /\\/g
10645.    181        ), "/");
10646.    176        if (!pathname.startsWith(cwd)) {
10647.    176            return;
10648.    176        }
10649.      5        pathname = pathname.slice(cwd.length);
10650.      5        return pathname;
10651.      5    }
10652.      7
10653.      7/*
10654.      7function sentinel() {}
10655.      7*/
10656.      7
10657.      7    await moduleFsInit();
10658.      7    consoleError = consoleError || console.error;
10659.      7    cwd = process.cwd().replace((
10660.      7        /\\/g
10661.      7    ), "/") + "/";
10662.      7
10663.      7// Init coverageDir.
10664.      7// Assert coverageDir is subdirectory of cwd.
10665.      7
10666.      7    assertOrThrow(coverageDir, "invalid coverageDir " + coverageDir);
10667.      7
10668.      7// CL-xxx - coverage - Relax requirement for coverageDir to be in cwd.
10669.      7//     assertOrThrow(
10670.      7//         pathnameRelativeCwd(coverageDir),
10671.      7//         "coverageDir " + coverageDir + " is not subdirectory of cwd " + cwd
10672.      7//     );
10673.      7
10674.      7    coverageDir = modulePath.resolve(coverageDir).replace((
10675.      7        /\\/g
10676.      7    ), "/") + "/";
10677.      7
10678.      7// 1. Spawn node.js program <processArgv> with coverage
10679.      7
10680.      6    if (processArgv.length > 0) {
10681.      6
10682.      6// Remove old coverage-files.
10683.      6
10684.      6        await fsWriteFileWithParents(coverageDir + "/touch.txt", "");
10685.      6        await Promise.all(Array.from(
10686.      6            await moduleFs.promises.readdir(coverageDir)
10687.     17        ).map(async function (file) {
10688.     17            if ((
10689.     17                /^coverage-\d+?-\d+?-\d+?\.json$/
10690.      6            ).test(file)) {
10691.      6                console.error("rm file " + coverageDir + file);
10692.      6                await moduleFs.promises.unlink(coverageDir + file);
10693.      6            }
10694.     17        }));
10695.      6        exitCode = await new Promise(function (resolve) {
10696.      6            moduleChildProcess.spawn((
10697.      6                processArgv[0] === "npm"
10698.      6
10699.      6// If win32 environment, then replace program npm with npm.cmd.
10700.      6// Coverage-hack - Ugly hack to get test-coverage under both win32 and linux.
10701.      6
10702.      6                ? process.platform.replace("win32", "npm.cmd").replace(
10703.      6                    process.platform,
10704.      6                    "npm"
10705.      6                )
10706.      6                : processArgv[0]
10707.      6            ), processArgv.slice(1), {
10708.      6                env: Object.assign({}, process.env, {
10709.      6                    NODE_V8_COVERAGE: coverageDir
10710.      6                }),
10711.      6                stdio: [
10712.      6                    "ignore", 1, 2
10713.      6                ]
10714.      6            }).on("exit", resolve);
10715.      6        });
10716.      6    }
10717.      6
10718.      6// 2. Merge JSON v8-coverage-files in <coverageDir>.
10719.      6
10720.      6    v8CoverageObj = await moduleFs.promises.readdir(coverageDir);
10721.     22    v8CoverageObj = v8CoverageObj.filter(function (file) {
10722.     22        return (
10723.     22            /^coverage-\d+?-\d+?-\d+?\.json$/
10724.     22        ).test(file);
10725.     22    });
10726.      6    v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
10727.      6        let data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
10728.      6        data = JSON.parse(data);
10729.    688        data.result = data.result.filter(function (scriptCov) {
10730.    688            let pathname = scriptCov.url;
10731.    688
10732.    688// Filter out internal coverages.
10733.    688
10734.    507            if (!pathname.startsWith("file:///")) {
10735.    507                return;
10736.    507            }
10737.    181
10738.    181// Normalize pathname.
10739.    181
10740.    181            pathname = pathnameRelativeCwd(moduleUrl.fileURLToPath(pathname));
10741.    181            if (
10742.    181
10743.    181// Filter files outside of cwd.
10744.    181
10745.    181                !pathname
10746.    181                || pathname.startsWith("[")
10747.    688
10748.    688// Filter directory node_modules.
10749.    688
10750.      6                || (
10751.      6                    process.env.npm_config_mode_coverage !== "all"
10752.      6                    && (
10753.      6                        /(?:^|\/)node_modules\//m
10754.      6                    ).test(pathname)
10755.      6                )
10756.    176            ) {
10757.    176                return;
10758.    176            }
10759.      6            scriptCov.url = pathname;
10760.      6            return true;
10761.      6        });
10762.      6        return data;
10763.      6    }));
10764.      6
10765.      6// Merge v8CoverageObj.
10766.      6
10767.      6    v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
10768.      6
10769.      6// debug v8CoverageObj.
10770.      6
10771.      6    await fsWriteFileWithParents(
10772.      6        coverageDir + "v8_coverage_merged.json",
10773.      6        JSON.stringify(v8CoverageObj)
10774.      6    );
10775.      6
10776.      6// 3. Create html-coverage-reports in <coverageDir>.
10777.      6
10778.      6    fileDict = {};
10779.      6    await Promise.all(v8CoverageObj.result.map(async function ({
10780.      6        functions,
10781.      6        url: pathname
10782.      6    }) {
10783.      6        let lineList;
10784.      6        let linesCovered;
10785.      6        let linesTotal;
10786.      6        let source;
10787.      6        source = await moduleFs.promises.readFile(pathname, "utf8");
10788.      6        lineList = [{}];
10789.      6        source.replace((
10790.      6            /^.*$/gm
10791.  10980        ), function (line, startOffset) {
10792.  10980            lineList[lineList.length - 1].endOffset = startOffset - 1;
10793.  10980            lineList.push({
10794.  10980                count: -1,
10795.  10980                endOffset: 0,
10796.  10980                holeList: [],
10797.  10980                line,
10798.  10980                startOffset
10799.  10980            });
10800.  10980            return "";
10801.  10980        });
10802.      6        lineList.shift();
10803.      6        lineList[lineList.length - 1].endOffset = source.length;
10804.     40        functions.reverse().forEach(function ({
10805.     40            ranges
10806.     40        }) {
10807.     60            ranges.reverse().forEach(function ({
10808.     60                count,
10809.     60                endOffset,
10810.     60                startOffset
10811.     60            }, ii, list) {
10812. 547962                lineList.forEach(function (elem) {
10813. 547962                    if (!(
10814. 547962                        (
10815. 547962                            elem.startOffset <= startOffset
10816. 197426                            && startOffset <= elem.endOffset
10817. 547902                        ) || (
10818. 547902                            elem.startOffset <= endOffset
10819. 547902                            && endOffset <= elem.endOffset
10820. 547902                        ) || (
10821. 547852                            startOffset <= elem.startOffset
10822. 547852                            && elem.endOffset <= endOffset
10823. 547852                        )
10824. 525980                    )) {
10825. 525980                        return;
10826. 525980                    }
10827.  21982
10828.  21982// Handle tree-root.
10829.  21982
10830.  21982                    if (ii + 1 === list.length) {
10831.  21852                        if (elem.count === -1) {
10832.  21852                            elem.count = count;
10833.  21852                        }
10834.  21852                        return;
10835.  21852                    }
10836.    130
10837.    130// Handle tree-children.
10838.    130
10839.    130                    if (elem.count !== 0) {
10840.     88                        elem.count = Math.max(count, elem.count);
10841.    130                    }
10842.    130                    if (count === 0) {
10843.    130                        elem.count = 0;
10844.    130                        elem.holeList.push([
10845.    130                            startOffset, endOffset
10846.    130                        ]);
10847.    130                    }
10848. 547962                });
10849.     60            });
10850.     40        });
10851.      6        linesTotal = lineList.length;
10852.  10980        linesCovered = lineList.filter(function ({
10853.  10980            count
10854.  10980        }) {
10855.  10980            return count > 0;
10856.  10980        }).length;
10857.      6        await moduleFs.promises.mkdir((
10858.      6            modulePath.dirname(coverageDir + pathname)
10859.      6        ), {
10860.      6            recursive: true
10861.      6        });
10862.      6        fileDict[pathname] = {
10863.      6            lineList,
10864.      6            linesCovered,
10865.      6            linesTotal,
10866.      6            modeCoverageIgnoreFile: (
10867.      6                (
10868.      6                    /^\/\*mode-coverage-ignore-file\*\/$/m
10869.      6                ).test(source.slice(0, 65536))
10870.      6                ? "(ignore)"
10871.      6                : ""
10872.      6            ),
10873.      6            pathname
10874.      6        };
10875.      6        htmlRender({
10876.      6            fileList: [
10877.      6                fileDict[pathname]
10878.      6            ],
10879.      6            lineList,
10880.      6            pathname: coverageDir + pathname
10881.      6        });
10882.      6    }));
10883.      6    htmlRender({
10884.      6        fileList: Object.keys(fileDict).sort().map(function (pathname) {
10885.      6            return fileDict[pathname];
10886.      6        }),
10887.      6        modeIndex: true,
10888.      6        pathname: coverageDir + "index"
10889.      6    });
10890.      6    assertOrThrow(
10891.      6        exitCode === 0,
10892.      6        "v8CoverageReportCreate - nonzero exitCode " + exitCode
10893.      6    );
10894.      6    await Promise.all(promiseList);
10895.      6}
10896.      1
10897.      1/*
10898.      1function sentinel() {}
10899.      1*/
10900.      1
10901.      1// Export jslint as cjs/esm.
10902.      1
10903.      1jslint_export = Object.freeze(Object.assign(jslint, {
10904.      1    assertErrorThrownAsync,
10905.      1    assertJsonEqual,
10906.      1    assertOrThrow,
10907.      1    debugInline,
10908.      1    fsRmRecursive,
10909.      1    fsWriteFileWithParents,
10910.      1    htmlEscape,
10911.      1    jslint,
10912.      1    jslint_apidoc,
10913.      1    jslint_assert,
10914.      1    jslint_charset_ascii,
10915.      1    jslint_cli,
10916.      1    jslint_edition,
10917.      1    jslint_phase1_split,
10918.      1    jslint_phase2_lex,
10919.      1    jslint_phase3_parse,
10920.      1    jslint_phase4_walk,
10921.      1    jslint_phase5_whitage,
10922.      1    jslint_report,
10923.      1    jstestDescribe,
10924.      1    jstestIt,
10925.      1    jstestOnExit,
10926.      1    moduleFsInit,
10927.      1    noop,
10928.      1    v8CoverageListMerge,
10929.      1    v8CoverageReportCreate
10930.      1}));
10931.      1// module.exports = jslint_export;              // Export jslint as cjs.
10932.      1export default Object.freeze(jslint_export);    // Export jslint as esm.
10933.      1jslint_import_meta_url = import.meta.url;
10934.      1
10935.      1// Run jslint_cli.
10936.      1
10937.      1(function () {
10938.      1    let cjs_module;
10939.      1    let cjs_require;
10940.      1
10941.      1// Coverage-hack.
10942.      1// Init commonjs builtins in try-catch-block in case we're in es-module-mode.
10943.      1
10944.      1    try {
10945.      1        cjs_module = module;
10946.      1    } catch (ignore) {}
10947.      1    try {
10948.      1        cjs_require = require;
10949.      1    } catch (ignore) {}
10950.      1    jslint_cli({
10951.      1        cjs_module,
10952.      1        cjs_require
10953.      1    });
10954.      1}());
10955.      1
10956.      1// Coverage-hack.
10957.      1debugInline();
10958.      1