V8 Coverage Report
Files covered Lines Remaining
. / jslint.mjs
100.00 %
11550 / 11550

0 / 11550
    1.      1// #!/usr/bin/env node
    2.      1// JSLint
    3.      1
    4.      1// The Unlicense
    5.      1//
    6.      1// This is free and unencumbered software released into the public domain.
    7.      1//
    8.      1// Anyone is free to copy, modify, publish, use, compile, sell, or
    9.      1// distribute this software, either in source code form or as a compiled
   10.      1// binary, for any purpose, commercial or non-commercial, and by any
   11.      1// means.
   12.      1//
   13.      1// In jurisdictions that recognize copyright laws, the author or authors
   14.      1// of this software dedicate any and all copyright interest in the
   15.      1// software to the public domain. We make this dedication for the benefit
   16.      1// of the public at large and to the detriment of our heirs and
   17.      1// successors. We intend this dedication to be an overt act of
   18.      1// relinquishment in perpetuity of all present and future rights to this
   19.      1// software under copyright law.
   20.      1//
   21.      1// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   22.      1// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   23.      1// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   24.      1// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
   25.      1// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
   26.      1// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   27.      1// OTHER DEALINGS IN THE SOFTWARE.
   28.      1
   29.      1
   30.      1// jslint(source, option_dict, global_list) is a function that takes 3
   31.      1// arguments. The second two arguments are optional.
   32.      1
   33.      1//      source          A text to analyze.
   34.      1//      option_dict     An object whose keys correspond to option names.
   35.      1//      global_list     An array of strings containing global variables that
   36.      1//                      the file is allowed readonly access.
   37.      1
   38.      1// jslint returns an object containing its results. The object contains a lot
   39.      1// of valuable information. It can be used to generate reports. The object
   40.      1// contains:
   41.      1
   42.      1//      directives: an array of directive comment tokens.
   43.      1//      edition: the version of JSLint that did the analysis.
   44.      1//      exports: the names exported from the module.
   45.      1//      froms: an array of strings representing each of the imports.
   46.      1//      functions: an array of objects that represent all functions
   47.      1//              declared in the file.
   48.      1//      global: an object representing the global object. Its .context property
   49.      1//              is an object containing a property for each global variable.
   50.      1//      id: "(JSLint)"
   51.      1//      json: true if the file is a JSON text.
   52.      1//      lines: an array of strings, the source.
   53.      1//      module: true if an import or export statement was used.
   54.      1//      ok: true if no warnings were generated. This is what you want.
   55.      1//      option: the option argument.
   56.      1//      property: a property object.
   57.      1//      stop: true if JSLint was unable to finish. You don't want this.
   58.      1//      tokens: an array of objects representing the tokens in the file.
   59.      1//      tree: the token objects arranged in a tree.
   60.      1//      warnings: an array of warning objects. A warning object can contain:
   61.      1//          name: "JSLintError"
   62.      1//          column: A column number in the file.
   63.      1//          line: A line number in the file.
   64.      1//          code: A warning code string.
   65.      1//          message: The warning message string.
   66.      1//          a: Exhibit A.
   67.      1//          b: Exhibit B.
   68.      1//          c: Exhibit C.
   69.      1//          d: Exhibit D.
   70.      1
   71.      1// jslint works in several phases. In any of these phases, errors might be
   72.      1// found. Sometimes JSLint is able to recover from an error and continue
   73.      1// parsing. In some cases, it cannot and will stop early. If that should happen,
   74.      1// repair your code and try again.
   75.      1
   76.      1// Phases:
   77.      1
   78.      1// PHASE 1. Split <source> by newlines into <line_list>.
   79.      1// PHASE 2. Lex <line_list> into <token_list>.
   80.      1// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
   81.      1// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
   82.      1//          recursive traversal. Each node may be processed on the way down
   83.      1//          (preaction) and on the way up (postaction).
   84.      1// PHASE 5. Check whitespace between tokens in <token_list>.
   85.      1
   86.      1// jslint can also examine JSON text. It decides that a file is JSON text if
   87.      1// the first token is "[" or "{". Processing of JSON text is much simpler than
   88.      1// the processing of JavaScript programs. Only the first three phases are
   89.      1// required.
   90.      1
   91.      1// WARNING: JSLint will hurt your feelings.
   92.      1
   93.      1/*jslint beta, node*/
   94.      1/*property
   95.      1    JSLINT_BETA, NODE_V8_COVERAGE, a, all, argv, arity, artifact,
   96.      1    assertErrorThrownAsync, assertJsonEqual, assertOrThrow, assign, async, b,
   97.      1    beta, bitwise, block, body, browser, c, calls, catch, catch_list,
   98.      1    catch_stack, causes, char, children, clear, closer, closure, code, column,
   99.      1    concat, consoleError, console_error, console_log, constant, context,
  100.      1    convert, count, coverageDir, create, cwd, d, dead, debugInline, default,
  101.      1    delta, devel, directive, directive_ignore_line, directive_list, directives,
  102.      1    dirname, disrupt, dot, edition, elem_list, ellipsis, else, end, endOffset,
  103.      1    endsWith, entries, env, error, eval, every, example_list, excludeList, exec,
  104.      1    execArgv, exit, exitCode, export_dict, exports, expression, extra, fart,
  105.      1    file, fileList, fileURLToPath, filter, finally, flag, floor, for, forEach,
  106.      1    formatted_message, free, freeze, from, froms, fsWriteFileWithParents,
  107.      1    fud_stmt, functionName, function_list, function_stack, functions, get,
  108.      1    getset, github_repo, globExclude, global, global_dict, global_list,
  109.      1    holeList, htmlEscape, id, identifier, import, import_list, import_meta_url,
  110.      1    inc, includeList, indent2, index, indexOf, init, initial, isArray,
  111.      1    isBlockCoverage, isHole, isNaN, is_equal, is_weird, join, jslint,
  112.      1    jslint_apidoc, jslint_assert, jslint_charset_ascii, jslint_cli,
  113.      1    jslint_edition, jslint_phase1_split, jslint_phase2_lex, jslint_phase3_parse,
  114.      1    jslint_phase4_walk, jslint_phase5_whitage, jslint_report, json,
  115.      1    jstestDescribe, jstestIt, jstestOnExit, keys, label, lbp, led_infix, length,
  116.      1    level, line, lineList, line_list, line_offset, line_source, lines,
  117.      1    linesCovered, linesTotal, live, log, long, loop, m, map, margin, match, max,
  118.      1    message, meta, min, mkdir, modeCoverageIgnoreFile, modeIndex, mode_cli,
  119.      1    mode_conditional, mode_json, mode_module, mode_noop, mode_property,
  120.      1    mode_shebang, mode_stop, module, moduleFsInit, moduleName, module_list,
  121.      1    name, names, node, nomen, noop, now, nr, nud_prefix,
  122.      1    objectDeepCopyWithKeysSorted, ok, on, open, opening, option, option_dict,
  123.      1    order, package_name, padEnd, padStart, parameters, parent, parentIi, parse,
  124.      1    pathname, pathnameList, platform, pop, processArgv, process_argv,
  125.      1    process_env, process_exit, promises, property, property_dict, push, quote,
  126.      1    ranges, readFile, readdir, readonly, recursive, reduce, repeat, replace,
  127.      1    resolve, result, reverse, role, round, scriptId, search, set, shebang,
  128.      1    shift, signature, single, slice, some, sort, source, spawn, splice, split,
  129.      1    stack, stack_trace, start, startOffset, startsWith, statement,
  130.      1    statement_prv, stdio, stop, stop_at, stringify, subscript, switch,
  131.      1    syntax_dict, tenure, test, test_cause, test_internal_error, this, thru,
  132.      1    toLocaleString, toString, token, token_global, token_list, token_nxt,
  133.      1    token_tree, tokens, trace, tree, trim, trimEnd, trimRight, try, type,
  134.      1    unlink, unordered, unshift, url, used, v8CoverageListMerge,
  135.      1    v8CoverageReportCreate, value, variable, version, versions, warn, warn_at,
  136.      1    warning, warning_list, warnings, white, wrapped, writeFile
  137.      1*/
  138.      1
  139.      1// init debugInline
  140.      1let debugInline = (function () {
  141.      3    let __consoleError = function () {
  142.      3        return;
  143.      3    };
  144.      1    function debug(...argv) {
  145.      1
  146.      1// This function will print <argv> to stderr and then return <argv>[0].
  147.      1
  148.      1        __consoleError("\n\ndebugInline");
  149.      1        __consoleError(...argv);
  150.      1        __consoleError("\n");
  151.      1        return argv[0];
  152.      1    }
  153.      1    debug(); // Coverage-hack.
  154.      1    __consoleError = console.error; //jslint-ignore-line
  155.      1    return debug;
  156.      1}());
  157.      1let jslint_charset_ascii = (
  158.      1    "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"
  159.      1    + "\b\t\n\u000b\f\r\u000e\u000f"
  160.      1    + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"
  161.      1    + "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"
  162.      1    + " !\"#$%&'()*+,-./0123456789:;<=>?"
  163.      1    + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
  164.      1    + "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"
  165.      1);
  166.      1let jslint_edition = "v2024.3.26";
  167.      1let jslint_export;                      // The jslint object to be exported.
  168.      1let jslint_fudge = 1;                   // Fudge starting line and starting
  169.      1                                        // ... column to 1.
  170.      1let jslint_import_meta_url = "";        // import.meta.url used by cli.
  171.      1let jslint_rgx_cap = (
  172.      1    /^[A-Z]/
  173.      1);
  174.      1let jslint_rgx_crlf = (
  175.      1    /\n|\r\n?/
  176.      1);
  177.      1let jslint_rgx_digits_bits = (
  178.      1    /^[01_]*/
  179.      1);
  180.      1let jslint_rgx_digits_decimals = (
  181.      1    /^[0-9_]*/
  182.      1);
  183.      1let jslint_rgx_digits_hexs = (
  184.      1    /^[0-9A-F_]*/i
  185.      1);
  186.      1let jslint_rgx_digits_octals = (
  187.      1    /^[0-7_]*/
  188.      1);
  189.      1let jslint_rgx_directive = (
  190.      1    /^(jslint|property|global)\s+(.*)$/
  191.      1);
  192.      1let jslint_rgx_directive_part = (
  193.      1    /([a-zA-Z$_][a-zA-Z0-9$_]*)(?::\s*(true|false))?,?\s*|$/g
  194.      1);
  195.      1let jslint_rgx_identifier = (
  196.      1    /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/
  197.      1);
  198.      1let jslint_rgx_json_number = (
  199.      1
  200.      1// https://datatracker.ietf.org/doc/html/rfc7159#section-6
  201.      1// number = [ minus ] int [ frac ] [ exp ]
  202.      1
  203.      1    /^-?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][\-+]?\d+)?$/
  204.      1);
  205.      1let jslint_rgx_mega = (
  206.      1
  207.      1// Vim-hack - vim-editor has trouble parsing naked '`' in regexp
  208.      1
  209.      1    /[\u0060\\]|\$\{/
  210.      1);
  211.      1let jslint_rgx_module = (
  212.      1    /^[a-zA-Z0-9_$:.@\-\/]+$/
  213.      1);
  214.      1let jslint_rgx_numeric_separator_illegal = (
  215.      1    /__|_$|_n$/m
  216.      1);
  217.      1let jslint_rgx_slash_star_or_slash = (
  218.      1    /\/\*|\/$/
  219.      1);
  220.      1let jslint_rgx_tab = (
  221.      1    /\t/g
  222.      1);
  223.      1let jslint_rgx_todo = (
  224.      1    /\b(?:todo|TO\s?DO|HACK)\b/
  225.      1);
  226.      1let jslint_rgx_token = new RegExp(
  227.      1    "^("
  228.      1    + "(\\s+)"
  229.      1    + "|([a-zA-Z_$][a-zA-Z0-9_$]*)"
  230.      1    + "|[(){}\\[\\],:;'\"~\\`]"
  231.      1    + "|\\?[?.]?"
  232.      1    + "|=(?:==?|>)?"
  233.      1    + "|\\.+"
  234.      1    + "|\\*[*\\/=]?"
  235.      1    + "|\\/[*\\/]?"
  236.      1    + "|\\+[=+]?"
  237.      1    + "|-[=\\-]?"
  238.      1    + "|[\\^%]=?"
  239.      1    + "|&[&=]?"
  240.      1    + "|\\"
  241.      1    + "|[|=]?"
  242.      1    + "|>{1,3}=?"
  243.      1    + "|<<?=?"
  244.      1    + "|!(?:!|==?)?"
  245.      1
  246.      1// PR-351 - Add BigInt support.
  247.      1// PR-390 - Add numeric-separator support.
  248.      1
  249.      1    + "|((?:0_?|[1-9][0-9_]*)n?)"
  250.      1    + ")"
  251.      1    + "(.*)$"
  252.      1);
  253.      1let jslint_rgx_url_search_window_jslint = (
  254.      1    /[&?]window_jslint=1(?:$|&)/m
  255.      1);
  256.      1let jslint_rgx_weird_property = (
  257.      1    /^_|\$|Sync$|_$/m
  258.      1);
  259.      1let jstestCountFailed = 0;
  260.      1let jstestCountTotal = 0;
  261.      1let jstestItCount = 0;
  262.      1let jstestItList = [];
  263.      1let jstestTimeStart;
  264.      1let moduleChildProcess;
  265.      1let moduleFs;
  266.      1let moduleFsInitResolveList;
  267.      1let modulePath;
  268.      1let moduleUrl;
  269.      1
  270.     11async function assertErrorThrownAsync(asyncFunc, regexp) {
  271.     11
  272.     11// This function will assert calling <asyncFunc> throws an error.
  273.     11
  274.     11    let err;
  275.     11    try {
  276.      1        await asyncFunc();
  277.     10    } catch (errCaught) {
  278.     10        err = errCaught;
  279.     10    }
  280.     11    assertOrThrow(err, "No error thrown.");
  281.     11    assertOrThrow(
  282.      4        !regexp || new RegExp(regexp).test(err.message),
  283.     11        err
  284.     11    );
  285.     11}
  286.      1
  287.    267function assertJsonEqual(aa, bb, message) {
  288.    267
  289.    267// This function will assert JSON.stringify(<aa>) === JSON.stringify(<bb>).
  290.    267
  291.    267    aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa), undefined, 1);
  292.    267    bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb), undefined, 1);
  293.      3    if (aa !== bb) {
  294.      3        throw new Error(
  295.      3            "\n" + aa + "\n!==\n" + bb
  296.      3            + (
  297.      3                typeof message === "string"
  298.      3                ? " - " + message
  299.      3                : message
  300.      3                ? " - " + JSON.stringify(message)
  301.      3                : ""
  302.      3            )
  303.      3        );
  304.      3    }
  305.    267}
  306.      1
  307.   1926function assertOrThrow(condition, message) {
  308.   1926
  309.   1926// This function will throw <message> if <condition> is falsy.
  310.   1926
  311.      4    if (!condition) {
  312.      4        throw (
  313.      4            (!message || typeof message === "string")
  314.      4            ? new Error(String(message).slice(0, 2048))
  315.      4            : message
  316.      4        );
  317.      4    }
  318.   1926}
  319.      1
  320.  93854function empty() {
  321.  93854
  322.  93854// The empty function produces a new empty object that inherits nothing. This is
  323.  93854// much better than '{}' because confusions around accidental method names like
  324.  93854// 'constructor' are completely avoided.
  325.  93854
  326.  93854    return Object.create(null);
  327.  93854}
  328.      1
  329.     59async function fsWriteFileWithParents(pathname, data) {
  330.     59
  331.     59// This function will write <data> to <pathname> and lazy-mkdirp if necessary.
  332.     59
  333.     59    await moduleFsInit();
  334.     59
  335.     59// Try writing to pathname.
  336.     59
  337.     59    try {
  338.     41        await moduleFs.promises.writeFile(pathname, data);
  339.     41    } catch (ignore) {
  340.     18
  341.     18// Lazy mkdirp.
  342.     18
  343.     18        await moduleFs.promises.mkdir(modulePath.dirname(pathname), {
  344.     18            recursive: true
  345.     18        });
  346.     18
  347.     18// Retry writing to pathname.
  348.     18
  349.     18        await moduleFs.promises.writeFile(pathname, data);
  350.     18    }
  351.     59    console.error("wrote file " + pathname);
  352.     59}
  353.      1
  354.    184function globExclude({
  355.    184    excludeList = [],
  356.    184    includeList = [],
  357.    184    pathnameList = []
  358.    184}) {
  359.    184
  360.    184// This function will
  361.    184// 1. Exclude pathnames in <pathnameList> that don't match glob-patterns in
  362.    184//    <includeList>.
  363.    184// 2. Exclude pathnames in <pathnameList> that match glob-patterns in
  364.    184//    <excludeList>.
  365.    184
  366.    552    function globAssertNotWeird(list, name) {
  367.    552
  368.    552// This function will check if <list> of strings contain weird characters.
  369.    552
  370.    552        [
  371.    552            [
  372.    552                "\n", (
  373.    552                    /^.*?([\u0000-\u0007\r]).*/gm
  374.    552                )
  375.    552            ],
  376.    552            [
  377.    552                "\r", (
  378.    552                    /^.*?([\n]).*/gm
  379.    552                )
  380.    552            ]
  381.   1102        ].forEach(function ([
  382.   1102            separator, rgx
  383.   1102        ]) {
  384.      3            list.join(separator).replace(rgx, function (match0, char) {
  385.      3                throw new Error(
  386.      3                    "Weird character "
  387.      3                    + JSON.stringify(char)
  388.      3                    + " found in " + name + " "
  389.      3                    + JSON.stringify(match0)
  390.      3                );
  391.      3            });
  392.   1102        });
  393.    552    }
  394.    184
  395.   1370    function globToRegexp(pattern) {
  396.   1370
  397.   1370// This function will translate glob <pattern> to javascript-regexp,
  398.   1370// which javascript can then use to "glob" pathnames.
  399.   1370
  400.   1370        let ii = 0;
  401.   1370        let isClass = false;
  402.   1370        let strClass = "";
  403.   1370        let strRegex = "";
  404.   1370        pattern = pattern.replace((
  405.   1370            /\/\/+/g
  406.   1370        ), "/");
  407.   1370        pattern = pattern.replace((
  408.   1370            /\*\*\*+/g
  409.   1370        ), "**");
  410.   1370        pattern.replace((
  411.   1370            /\\\\|\\\[|\\\]|\[|\]|./g
  412.  18691        ), function (match0) {
  413.  18691            switch (match0) {
  414.    310            case "[":
  415.    310                if (isClass) {
  416.    310                    strClass += "[";
  417.    310                    return;
  418.    310                }
  419.    310                strClass += "\u0000";
  420.    310                strRegex += "\u0000";
  421.    310                isClass = true;
  422.    310                return;
  423.    310            case "]":
  424.    310                if (isClass) {
  425.    310                    isClass = false;
  426.    310                    return;
  427.    310                }
  428.    310                strRegex += "]";
  429.    310                return;
  430.  18071            default:
  431.  18071                if (isClass) {
  432.  18071                    strClass += match0;
  433.  18071                    return;
  434.  18071                }
  435.  18071                strRegex += match0;
  436.  15021            }
  437.  15021            return "";
  438.  15021        });
  439.   1370        strClass += "\u0000";
  440.   1370
  441.   1370// An expression "[!...]" matches a single character, namely any character that
  442.   1370// is not matched by the expression obtained by removing the first '!' from it.
  443.   1370// (Thus, "[!a-]" matches any single character except 'a', and '-'.)
  444.   1370
  445.   1370        strClass = strClass.replace((
  446.   1370            /\u0000!/g
  447.   1370        ), "\u0000^");
  448.   1370
  449.   1370// One may include '-' in its literal meaning by making it the first or last
  450.   1370// character between the brackets.
  451.   1370
  452.   1370        strClass = strClass.replace((
  453.   1370            /\u0000-/g
  454.   1370        ), "\u0000\\-");
  455.   1370        strClass = strClass.replace((
  456.   1370            /-\u0000/g
  457.   1370        ), "\\-\u0000");
  458.   1370
  459.   1370// Escape brackets '[', ']' in character class.
  460.   1370
  461.   1370        strClass = strClass.replace((
  462.   1370            /[\[\]]/g
  463.   1370        ), "\\$&");
  464.   1370
  465.   1370// https://stackoverflow.com/questions/3561493
  466.   1370// /is-there-a-regexp-escape-function-in-javascript
  467.   1370// $()*+-./?[\]^{|}
  468.   1370
  469.   1370        strRegex = strRegex.replace((
  470.   1370
  471.   1370// Ignore [-/].
  472.   1370
  473.   1370            /[$()*+.?\[\\\]\^{|}]/g
  474.   1370        ), "\\$&");
  475.   1370
  476.   1370// Expand wildcard '**/*'.
  477.   1370
  478.   1370        strRegex = strRegex.replace((
  479.   1370            /\\\*\\\*\/(?:\\\*)+/g
  480.   1370        ), ".*?");
  481.   1370
  482.   1370// Expand wildcard '**'.
  483.   1370
  484.   1370        strRegex = strRegex.replace((
  485.   1370            /(^|\/)\\\*\\\*(\/|$)/gm
  486.   1370        ), "$1.*?$2");
  487.   1370
  488.   1370// Expand wildcard '*'.
  489.   1370
  490.   1370        strRegex = strRegex.replace((
  491.   1370            /(?:\\\*)+/g
  492.   1370        ), "[^\\/]*?");
  493.   1370
  494.   1370// Expand wildcard '?'.
  495.   1370
  496.   1370        strRegex = strRegex.replace((
  497.   1370            /\\\?/g
  498.   1370        ), "[^\\/]");
  499.   1370
  500.   1370// Expand directory-with-trailing-slash '.../'.
  501.   1370
  502.   1370        strRegex = strRegex.replace((
  503.   1370            /\/$/gm
  504.   1370        ), "\\/.*?");
  505.   1370
  506.   1370// Merge strClass into strRegex.
  507.   1370
  508.   1370        ii = 0;
  509.   1370        strClass = strClass.split("\u0000");
  510.   1370        strRegex = strRegex.replace((
  511.   1370            /\u0000/g
  512.    306        ), function () {
  513.    306            ii += 1;
  514.      2            if (strClass[ii] === "") {
  515.      2                return "";
  516.    304            }
  517.    304            return "[" + strClass[ii] + "]";
  518.    304        });
  519.   1370
  520.   1370// Change strRegex from string to regexp.
  521.   1370
  522.   1370        strRegex = new RegExp("^" + strRegex + "$", "gm");
  523.   1370        return strRegex;
  524.   1370    }
  525.    184
  526.    184// Validate excludeList, includeList, pathnameList.
  527.    184
  528.    184    globAssertNotWeird(excludeList, "pattern");
  529.    184    globAssertNotWeird(includeList, "pattern");
  530.    184    globAssertNotWeird(pathnameList, "pathname");
  531.    184
  532.    184// Optimization
  533.    184// Concat pathnames into a single, newline-separated string,
  534.    184// whose pathnames can all be filtered with a single, regexp-pass.
  535.    184
  536.    184    pathnameList = pathnameList.join("\n");
  537.    184
  538.    184// 1. Exclude pathnames in <pathnameList> that don't match glob-patterns in
  539.    184//    <includeList>.
  540.    184
  541.    142    if (includeList.length > 0) {
  542.    142        includeList = includeList.map(globToRegexp);
  543.    574        includeList.forEach(function (pattern) {
  544.    574            pathnameList = pathnameList.replace(pattern, "\u0000$&");
  545.    574        });
  546.    142        pathnameList = pathnameList.replace((
  547.    142            /^[^\u0000].*/gm
  548.    142        ), "");
  549.    142        pathnameList = pathnameList.replace((
  550.    142            /^\u0000+/gm
  551.    142        ), "");
  552.    181    }
  553.    181
  554.    181// 2. Exclude pathnames in <pathnameList> that match glob-patterns in
  555.    181//    <excludeList>.
  556.    181
  557.    181    excludeList = excludeList.map(globToRegexp);
  558.    796    excludeList.forEach(function (pattern) {
  559.    796        pathnameList = pathnameList.replace(pattern, "");
  560.    796    });
  561.    181
  562.    181// Split newline-separated pathnames back to list.
  563.    181
  564.  10117    pathnameList = pathnameList.split("\n").filter(function (elem) {
  565.  10117        return elem;
  566.  10117    });
  567.    181    return {
  568.    181        excludeList,
  569.    181        includeList,
  570.    181        pathnameList
  571.    181    };
  572.    181}
  573.      1
  574.  14189function htmlEscape(str) {
  575.  14189
  576.  14189// This function will make <str> html-safe by escaping & < >.
  577.  14189
  578.  14189    return String(str).replace((
  579.  14189        /&/g
  580.  14189    ), "&amp;").replace((
  581.  14189        /</g
  582.  14189    ), "&lt;").replace((
  583.  14189        />/g
  584.  14189    ), "&gt;");
  585.  14189}
  586.      1
  587.    666function jslint(
  588.    666    source = "",                // A text to analyze.
  589.    666    option_dict = empty(),      // An object whose keys correspond to option
  590.    666                                // ... names.
  591.    666    global_list = []            // An array of strings containing global
  592.    666                                // ... variables that the file is allowed
  593.    666                                // ... readonly access.
  594.    666) {
  595.    666
  596.    666// The jslint function itself.
  597.    666
  598.    666    let catch_list = [];        // The array containing all catch-blocks.
  599.    666    let catch_stack = [         // The stack of catch-blocks.
  600.    666        {
  601.    666            context: empty()
  602.    666        }
  603.    666    ];
  604.    666    let cause_dict = empty();   // The object of test-causes.
  605.    666    let directive_list = [];    // The directive comments.
  606.    666    let export_dict = empty();  // The exported names and values.
  607.    666    let function_list = [];     // The array containing all functions.
  608.    666    let function_stack = [];    // The stack of functions.
  609.    666    let global_dict = empty();  // The object containing the global
  610.    666                                // ... declarations.
  611.    666    let import_list = [];       // The array collecting all import-from strings.
  612.    666    let line_list = String(     // The array containing source lines.
  613.    666        "\n" + source
  614. 105205    ).split(jslint_rgx_crlf).map(function (line_source) {
  615. 105205        return {
  616. 105205            line_source
  617. 105205        };
  618. 105205    });
  619.    666    let mode_stop = false;      // true if JSLint cannot finish.
  620.    666    let property_dict = empty();        // The object containing the tallied
  621.    666                                        // ... property names.
  622.    666    let state = empty();        // jslint state-object to be passed between
  623.    666                                // jslint functions.
  624.    666    let syntax_dict = empty();  // The object containing the parser.
  625.    666    let tenure = empty();       // The predefined property registry.
  626.    666    let token_global = {        // The global object; the outermost context.
  627.    666        async: 0,
  628.    666        body: true,
  629.    666        context: empty(),
  630.    666        finally: 0,
  631.    666        from: 0,
  632.    666        id: "(global)",
  633.    666        level: 0,
  634.    666        line: jslint_fudge,
  635.    666        live: [],
  636.    666        loop: 0,
  637.    666        switch: 0,
  638.    666        thru: 0,
  639.    666        try: 0
  640.    666    };
  641.    666    let token_list = [];        // The array of tokens.
  642.    666    let warning_list = [];      // The array collecting all generated warnings.
  643.    666
  644.    666// Error reportage functions:
  645.    666
  646.   8028    function artifact(the_token) {
  647.   8028
  648.   8028// Return a string representing an artifact.
  649.   8028
  650.    254        the_token = the_token || state.token_nxt;
  651.   8028        return (
  652.   5253            (the_token.id === "(string)" || the_token.id === "(number)")
  653.   2900            ? String(the_token.value)
  654.   5128            : the_token.id
  655.   8028        );
  656.   8028    }
  657.    666
  658.  31933    function is_equal(aa, bb) {
  659.  31933
  660.  31933// test_cause:
  661.  31933// ["0&&0", "is_equal", "", "", 0]
  662.  31933
  663.  31933        test_cause("");
  664.  31933
  665.  31933// Probably deadcode.
  666.  31933// if (aa === bb) {
  667.  31933//     return true;
  668.  31933// }
  669.  31933
  670.  31933        jslint_assert(!(aa === bb), `Expected !(aa === bb).`);
  671.     27        if (Array.isArray(aa)) {
  672.     27            return (
  673.     27                Array.isArray(bb)
  674.     27                && aa.length === bb.length
  675.     27                && aa.every(function (value, index) {
  676.     27
  677.     27// test_cause:
  678.     27// ["`${0}`&&`${0}`", "is_equal", "recurse_isArray", "", 0]
  679.     27// ["`${0}`&&`${1}`", "is_equal", "recurse_isArray", "", 0]
  680.     27
  681.     27                    test_cause("recurse_isArray");
  682.     27                    return is_equal(value, bb[index]);
  683.     27                })
  684.     27            );
  685.  31906        }
  686.  31906
  687.  31906// Probably deadcode.
  688.  31906// if (Array.isArray(bb)) {
  689.  31906//     return false;
  690.  31906// }
  691.  31906
  692.  31906        jslint_assert(!Array.isArray(bb), `Expected !Array.isArray(bb).`);
  693.  31906        switch (aa.id === bb.id && aa.id) {
  694.     65        case "(number)":
  695.  23424        case "(string)":
  696.  23424            return aa.value === bb.value;
  697.  31933
  698.  31933// PR-394 - Bugfix
  699.  31933// Fix jslint falsely believing megastring literals `0` and `1` are similar.
  700.  31933
  701.     15        case "`":
  702.     15            if (!is_equal(aa.value, bb.value)) {
  703.     15                return false;
  704.     15            }
  705.     15            break;
  706.   8479        }
  707.   8479        if (is_weird(aa) || is_weird(bb)) {
  708.     34
  709.     34// test_cause:
  710.     34// ["aa(/./)||{}", "is_equal", "false", "", 0]
  711.     34
  712.     34            test_cause("false");
  713.     34            return false;
  714.   8445        }
  715.   8445        if (aa.arity === bb.arity && aa.id === bb.id) {
  716.   2121            if (aa.id === "." || aa.id === "?.") {
  717.   2121
  718.   2121// test_cause:
  719.   2121// ["aa.bb&&aa.bb", "is_equal", "recurse_arity_id", "", 0]
  720.   2121// ["aa?.bb&&aa?.bb", "is_equal", "recurse_arity_id", "", 0]
  721.   2121
  722.   2121                test_cause("recurse_arity_id");
  723.   2121                return (
  724.   2121                    is_equal(aa.expression, bb.expression)
  725.   2121                    && is_equal(aa.name, bb.name)
  726.   2121                );
  727.   2121            }
  728.   2121            if (aa.arity === "unary") {
  729.   2121
  730.   2121// test_cause:
  731.   2121// ["+0&&+0", "is_equal", "recurse_unary", "", 0]
  732.   2121
  733.   2121                test_cause("recurse_unary");
  734.   2121                return is_equal(aa.expression, bb.expression);
  735.   2121            }
  736.   2121            if (aa.arity === "binary") {
  737.   2121
  738.   2121// test_cause:
  739.   2121// ["aa[0]&&aa[0]", "is_equal", "recurse_binary", "", 0]
  740.   2121
  741.   2121                test_cause("recurse_binary");
  742.   2121                return (
  743.   2121                    aa.id !== "("
  744.   2121                    && is_equal(aa.expression[0], bb.expression[0])
  745.   2121                    && is_equal(aa.expression[1], bb.expression[1])
  746.   2121                );
  747.   2121            }
  748.   2121            if (aa.arity === "ternary") {
  749.   2121
  750.   2121// test_cause:
  751.   2121// ["aa=(``?``:``)&&(``?``:``)", "is_equal", "recurse_ternary", "", 0]
  752.   2121
  753.   2121                test_cause("recurse_ternary");
  754.   2121                return (
  755.   2121                    is_equal(aa.expression[0], bb.expression[0])
  756.   2121                    && is_equal(aa.expression[1], bb.expression[1])
  757.   2121                    && is_equal(aa.expression[2], bb.expression[2])
  758.   2121                );
  759.   2121            }
  760.   2121
  761.   2121// Probably deadcode.
  762.   2121// if (aa.arity === "function" || aa.arity === "regexp") {
  763.   2121//     return false;
  764.   2121// }
  765.   2121
  766.   2121            jslint_assert(
  767.   2121                !(aa.arity === "function" || aa.arity === "regexp"),
  768.   2121                `Expected !(aa.arity === "function" || aa.arity === "regexp").`
  769.   2121            );
  770.   2121
  771.   2121// test_cause:
  772.   2121// ["undefined&&undefined", "is_equal", "true", "", 0]
  773.   2121
  774.   2121            test_cause("true");
  775.   2121            return true;
  776.   6324        }
  777.   6324
  778.   6324// test_cause:
  779.   6324// ["null&&undefined", "is_equal", "false", "", 0]
  780.   6324
  781.   6324        test_cause("false");
  782.   6324        return false;
  783.   6324    }
  784.    666
  785.  28704    function is_weird(thing) {
  786.  28704        switch (thing.id) {
  787.      1        case "(regexp)":
  788.      1            return true;
  789.      1        case "=>":
  790.      1            return true;
  791.    617        case "[":
  792.    617            return thing.arity === "unary";
  793.     12        case "function":
  794.     12            return true;
  795.      8        case "{":
  796.      8            return true;
  797.  28065        default:
  798.  28065            return false;
  799.  28704        }
  800.  28704    }
  801.    666
  802.    106    function stop(code, the_token, a, b, c, d) {
  803.    106
  804.    106// Similar to warn and stop_at. If the token already had a warning, that
  805.    106// warning will be replaced with this new one. It is likely that the stopping
  806.    106// warning will be the more meaningful.
  807.    106
  808.     38        the_token = the_token || state.token_nxt;
  809.    106        delete the_token.warning;
  810.    106        throw warn(code, the_token, a, b, c, d);
  811.    106    }
  812.    666
  813.     28    function stop_at(code, line, column, a, b, c, d) {
  814.     28
  815.     28// Same as warn_at, except that it stops the analysis.
  816.     28
  817.     28        throw warn_at(code, line, column, a, b, c, d);
  818.     28    }
  819.    666
  820. 339116    function test_cause(code, aa, column) {
  821. 339116
  822. 339116// This function will instrument <cause> to <cause_dict> for test-purposes.
  823. 339116
  824.   4856        if (option_dict.test_cause) {
  825.   4856            cause_dict[JSON.stringify([
  826.   4856                String(new Error().stack).replace((
  827.   4856                    /^    at (?:file|stop|stop_at|test_cause|warn|warn_at)\b.*?\n/gm
  828.   4856                ), "").match(
  829.   4856                    /\n    at ((?:Object\.\w+?_)?\w+?) /
  830.   4856                )[1].replace((
  831.   4856                    /^Object\./
  832.   4856                ), ""),
  833.   4856                code,
  834.   4856                String(
  835.   4856                    (aa === undefined || aa === token_global)
  836.   4856                    ? ""
  837.   4856                    : aa
  838.   4856                ),
  839.   4856                column || 0
  840.   4856            ])] = true;
  841.   4856        }
  842. 339116    }
  843.    666
  844.   1070    function warn(code, the_token, a, b, c, d) {
  845.   1070
  846.   1070// Same as warn_at, except the warning will be associated with a specific token.
  847.   1070// If there is already a warning on this token, suppress the new one. It is
  848.   1070// likely that the first warning will be the most meaningful.
  849.   1070
  850.   1070        let the_warning;
  851.     20        the_token = the_token || state.token_nxt;
  852.   1070        the_warning = warn_at(
  853.   1070            code,
  854.   1070            the_token.line,
  855.    374            (the_token.from || 0) + jslint_fudge,
  856.    830            a || artifact(the_token),
  857.   1070            b,
  858.   1070            c,
  859.   1070            d
  860.   1070        );
  861.   1070
  862.   1070// Issue #408
  863.   1070// Warnings that should be ignored sometimes suppress legitimate warnings.
  864.   1070
  865.     26        if (the_warning.directive_ignore_line) {
  866.     26            return the_warning;
  867.   1044        }
  868.   1044
  869.   1044// If there is already a warning on this token, suppress the new one. It is
  870.   1044// likely that the first warning will be the most meaningful.
  871.   1044
  872.   1044        if (the_token.warning) {
  873.    192            warning_list.pop();
  874.    192            return the_warning;
  875.    852        }
  876.    852        the_token.warning = the_warning;
  877.    852        return the_warning;
  878.    852    }
  879.    666
  880.   1387    function warn_at(code, line, column, a, b, c, d) {
  881.   1387
  882.   1387// Report an error at some line and column of the program. The warning object
  883.   1387// resembles an exception.
  884.   1387
  885.   1387        let mm;
  886.   1387        let warning = Object.assign(empty(), {
  887.   1387            a,
  888.   1387            b,
  889.   1387            c,
  890.   1387            code,
  891.   1387
  892.   1387// Fudge column numbers in warning message.
  893.   1387
  894.     27            column: column || jslint_fudge,
  895.   1387            d,
  896.   1387            line,
  897.   1387            line_source: "",
  898.   1387            name: "JSLintError"
  899.   1387        }, line_list[line]);
  900.   1387        warning.column = Math.max(
  901.   1387            Math.min(warning.column, warning.line_source.length),
  902.   1387            jslint_fudge
  903.   1387        );
  904.    921        test_cause(code, b || a, warning.column);
  905.   1387        switch (code) {
  906.   1387
  907.   1387// The bundle contains the raw text messages that are generated by jslint. It
  908.   1387// seems that they are all error messages and warnings. There are no "Atta
  909.   1387// boy!" or "You are so awesome!" messages. There is no positive reinforcement
  910.   1387// or encouragement. This relentless negativity can undermine self-esteem and
  911.   1387// wound the inner child. But if you accept it as sound advice rather than as
  912.   1387// personal criticism, it can make your programs better.
  913.   1387
  914.      1        case "and":
  915.      1            mm = `The '&&' subexpression should be wrapped in parens.`;
  916.      1            break;
  917.     71        case "bad_assignment_a":
  918.     71            mm = `Bad assignment to '${a}'.`;
  919.     71            break;
  920.      1        case "bad_directive_a":
  921.      1            mm = `Bad directive '${a}'.`;
  922.      1            break;
  923.      1        case "bad_get":
  924.      1            mm = `A get function takes no parameters.`;
  925.      1            break;
  926.      1        case "bad_module_name_a":
  927.      1            mm = `Bad module name '${a}'.`;
  928.      1            break;
  929.      2        case "bad_option_a":
  930.      2            mm = `Bad option '${a}'.`;
  931.      2            break;
  932.      1        case "bad_set":
  933.      1            mm = `A set function takes one parameter.`;
  934.      1            break;
  935.      6        case "duplicate_a":
  936.      6            mm = `Duplicate '${a}'.`;
  937.      6            break;
  938.     64        case "empty_block":
  939.     64            mm = `Empty block.`;
  940.     64            break;
  941.      5        case "expected_a":
  942.      5            mm = `Expected '${a}'.`;
  943.      5            break;
  944.     25        case "expected_a_at_b_c":
  945.     25            mm = `Expected '${a}' at column ${b}, not column ${c}.`;
  946.     25            break;
  947.    284        case "expected_a_b":
  948.    284            mm = `Expected '${a}' and instead saw '${b}'.`;
  949.    284            break;
  950.     17        case "expected_a_b_before_c_d":
  951.     17            mm = `Expected ${a} '${b}' to be ordered before ${c} '${d}'.`;
  952.     17            break;
  953.      2        case "expected_a_b_from_c_d":
  954.      2            mm = (
  955.      2                `Expected '${a}' to match '${b}' from line ${c}`
  956.      2                + ` and instead saw '${d}'.`
  957.      2            );
  958.      2            break;
  959.     30        case "expected_a_before_b":
  960.     30            mm = `Expected '${a}' before '${b}'.`;
  961.     30            break;
  962.      2        case "expected_digits_after_a":
  963.      2            mm = `Expected digits after '${a}'.`;
  964.      2            break;
  965.      1        case "expected_four_digits":
  966.      1            mm = `Expected four digits after '\\u'.`;
  967.      1            break;
  968.     31        case "expected_identifier_a":
  969.     31            mm = `Expected an identifier and instead saw '${a}'.`;
  970.     31            break;
  971.      6        case "expected_line_break_a_b":
  972.      6            mm = `Expected a line break between '${a}' and '${b}'.`;
  973.      6            break;
  974.      3        case "expected_regexp_factor_a":
  975.      3            mm = `Expected a regexp factor and instead saw '${a}'.`;
  976.      3            break;
  977.     76        case "expected_space_a_b":
  978.     76            mm = `Expected one space between '${a}' and '${b}'.`;
  979.     76            break;
  980.      2        case "expected_statements_a":
  981.      2            mm = `Expected statements before '${a}'.`;
  982.      2            break;
  983.      1        case "expected_string_a":
  984.      1            mm = `Expected a string and instead saw '${a}'.`;
  985.      1            break;
  986.      1        case "expected_type_string_a":
  987.      1            mm = `Expected a type string and instead saw '${a}'.`;
  988.      1            break;
  989.      6        case "freeze_exports":
  990.      6            mm = (
  991.      6                `Expected 'Object.freeze('. All export values should be frozen.`
  992.      6            );
  993.      6            break;
  994.   1387
  995.   1387// PR-378 - Relax warning "function_in_loop".
  996.   1387//
  997.   1387//         case "function_in_loop":
  998.   1387//             mm = `Don't create functions within a loop.`;
  999.   1387//             break;
 1000.   1387
 1001.   1387// PR-390 - Add numeric-separator check.
 1002.   1387
 1003.      7        case "illegal_num_separator":
 1004.      7            mm = `Illegal numeric separator '_' at column ${column}.`;
 1005.      7            break;
 1006.      1        case "infix_in":
 1007.      1            mm = (
 1008.      1                `Unexpected 'in'. Compare with undefined,`
 1009.      1                + ` or use the hasOwnProperty method instead.`
 1010.      1            );
 1011.      1            break;
 1012.      1        case "label_a":
 1013.      1            mm = `'${a}' is a statement label.`;
 1014.      1            break;
 1015.      1        case "misplaced_a":
 1016.      1            mm = `Place '${a}' at the outermost level.`;
 1017.      1            break;
 1018.      1        case "misplaced_directive_a":
 1019.      1            mm = `Place the '/*${a}*/' directive before the first statement.`;
 1020.      1            break;
 1021.      3        case "missing_await_statement":
 1022.      3            mm = `Expected await statement in async function.`;
 1023.      3            break;
 1024.   1387
 1025.   1387// PR-347 - Disable warning "missing_browser".
 1026.   1387//
 1027.   1387//         case "missing_browser":
 1028.   1387//             mm = `/*global*/ requires the Assume a browser option.`;
 1029.   1387//             break;
 1030.   1387
 1031.      1        case "missing_m":
 1032.      1            mm = `Expected 'm' flag on a multiline regular expression.`;
 1033.      1            break;
 1034.      5        case "naked_block":
 1035.      5            mm = `Naked block.`;
 1036.      5            break;
 1037.      2        case "nested_comment":
 1038.      2            mm = `Nested comment.`;
 1039.      2            break;
 1040.      1        case "not_label_a":
 1041.      1            mm = `'${a}' is not a label.`;
 1042.      1            break;
 1043.      2        case "number_isNaN":
 1044.      2            mm = `Use Number.isNaN function to compare with NaN.`;
 1045.      2            break;
 1046.      4        case "out_of_scope_a":
 1047.      4            mm = `'${a}' is out of scope.`;
 1048.      4            break;
 1049.     11        case "redefinition_a_b":
 1050.     11            mm = `Redefinition of '${a}' from line ${b}.`;
 1051.     11            break;
 1052.      1        case "redefinition_global_a_b":
 1053.      1            mm = `Redefinition of global ${a} variable '${b}'.`;
 1054.      1            break;
 1055.      6        case "required_a_optional_b":
 1056.      6            mm = `Required parameter '${a}' after optional parameter '${b}'.`;
 1057.      6            break;
 1058.      1        case "reserved_a":
 1059.      1            mm = `Reserved name '${a}'.`;
 1060.      1            break;
 1061.      1        case "subscript_a":
 1062.      1            mm = `['${a}'] is better written in dot notation.`;
 1063.      1            break;
 1064.     16        case "todo_comment":
 1065.     16            mm = `Unexpected TODO comment.`;
 1066.     16            break;
 1067.     13        case "too_long":
 1068.     13            mm = `Line is longer than 80 characters.`;
 1069.     13            break;
 1070.      1        case "too_many_digits":
 1071.      1            mm = `Too many digits.`;
 1072.      1            break;
 1073.      3        case "unclosed_comment":
 1074.      3            mm = `Unclosed comment.`;
 1075.      3            break;
 1076.      3        case "unclosed_disable":
 1077.      3            mm = (
 1078.      3                `Directive '/*jslint-disable*/' was not closed`
 1079.      3                + ` with '/*jslint-enable*/'.`
 1080.      3            );
 1081.      3            break;
 1082.      3        case "unclosed_mega":
 1083.      3            mm = `Unclosed mega literal.`;
 1084.      3            break;
 1085.      2        case "unclosed_string":
 1086.      2            mm = `Unclosed string.`;
 1087.      2            break;
 1088.    133        case "undeclared_a":
 1089.    133            mm = `Undeclared '${a}'.`;
 1090.    133            break;
 1091.    237        case "unexpected_a":
 1092.    237            mm = `Unexpected '${a}'.`;
 1093.    237            break;
 1094.      2        case "unexpected_a_after_b":
 1095.      2            mm = `Unexpected '${a}' after '${b}'.`;
 1096.      2            break;
 1097.      2        case "unexpected_a_before_b":
 1098.      2            mm = `Unexpected '${a}' before '${b}'.`;
 1099.      2            break;
 1100.     34        case "unexpected_at_top_level_a":
 1101.     34            mm = `Expected '${a}' to be in a function.`;
 1102.     34            break;
 1103.      1        case "unexpected_char_a":
 1104.      1            mm = `Unexpected character '${a}'.`;
 1105.      1            break;
 1106.      2        case "unexpected_comment":
 1107.      2            mm = `Unexpected comment.`;
 1108.      2            break;
 1109.   1387
 1110.   1387// PR-347 - Disable warning "unexpected_directive_a".
 1111.   1387//
 1112.   1387//         case "unexpected_directive_a":
 1113.   1387//             mm = `When using modules, don't use directive '/\u002a${a}'.`;
 1114.   1387//             break;
 1115.   1387
 1116.    127        case "unexpected_expression_a":
 1117.    127            mm = `Unexpected expression '${a}' in statement position.`;
 1118.    127            break;
 1119.      4        case "unexpected_label_a":
 1120.      4            mm = `Unexpected label '${a}'.`;
 1121.      4            break;
 1122.      3        case "unexpected_parens":
 1123.      3            mm = `Don't wrap function literals in parens.`;
 1124.      3            break;
 1125.      8        case "unexpected_space_a_b":
 1126.      8            mm = `Unexpected space between '${a}' and '${b}'.`;
 1127.      8            break;
 1128.      1        case "unexpected_statement_a":
 1129.      1            mm = `Unexpected statement '${a}' in expression position.`;
 1130.      1            break;
 1131.      2        case "unexpected_trailing_space":
 1132.      2            mm = `Unexpected trailing space.`;
 1133.      2            break;
 1134.      1        case "unexpected_typeof_a":
 1135.      1            mm = (
 1136.      1                `Unexpected 'typeof'. Use '===' to compare directly with ${a}.`
 1137.      1            );
 1138.      1            break;
 1139.      1        case "uninitialized_a":
 1140.      1            mm = `Uninitialized '${a}'.`;
 1141.      1            break;
 1142.      1        case "unopened_enable":
 1143.      1            mm = (
 1144.      1                `Directive '/*jslint-enable*/' was not opened`
 1145.      1                + ` with '/*jslint-disable*/'.`
 1146.      1            );
 1147.      1            break;
 1148.      1        case "unreachable_a":
 1149.      1            mm = `Unreachable '${a}'.`;
 1150.      1            break;
 1151.      1        case "unregistered_property_a":
 1152.      1            mm = `Unregistered property name '${a}'.`;
 1153.      1            break;
 1154.      6        case "unused_a":
 1155.      6            mm = `Unused '${a}'.`;
 1156.      6            break;
 1157.      2        case "use_double":
 1158.      2            mm = `Use double quotes, not single quotes.`;
 1159.      2            break;
 1160.   1387
 1161.   1387// PR-386 - Fix issue #382 - Make fart-related warnings more readable.
 1162.   1387
 1163.      4        case "use_function_not_fart":
 1164.      4            mm = (
 1165.      4                `Use 'function (...)', not '(...) =>' when arrow functions`
 1166.      4                + ` become too complex.`
 1167.      4            );
 1168.      4            break;
 1169.      7        case "use_open":
 1170.      7            mm = (
 1171.      7                `Wrap a ternary expression in parens,`
 1172.      7                + ` with a line break after the left paren.`
 1173.      7            );
 1174.      7            break;
 1175.      1        case "use_spaces":
 1176.      1            mm = `Use spaces, not tabs.`;
 1177.      1            break;
 1178.      5        case "var_on_top":
 1179.      5            mm = `Move variable declaration to top of function or script.`;
 1180.      5            break;
 1181.      1        case "var_switch":
 1182.      1            mm = `Don't declare variables in a switch.`;
 1183.      1            break;
 1184.     23        case "weird_condition_a":
 1185.     23            mm = `Weird condition '${a}'.`;
 1186.     23            break;
 1187.      5        case "weird_expression_a":
 1188.      5            mm = `Weird expression '${a}'.`;
 1189.      5            break;
 1190.      3        case "weird_loop":
 1191.      3            mm = `Weird loop.`;
 1192.      3            break;
 1193.      9        case "weird_property_a":
 1194.      9            mm = `Weird property name '${a}'.`;
 1195.      9            break;
 1196.      8        case "weird_relation_a":
 1197.      8            mm = `Weird relation '${a}'.`;
 1198.      8            break;
 1199.      1        case "wrap_condition":
 1200.      1            mm = `Wrap the condition in parens.`;
 1201.      1            break;
 1202.   1387
 1203.   1387// PR-386 - Fix issue #382 - Make fart-related warnings more readable.
 1204.   1387
 1205.      1        case "wrap_fart_parameter":
 1206.      1            mm = `Wrap the parameter before '=>' in parens.`;
 1207.      1            break;
 1208.      1        case "wrap_immediate":
 1209.      1            mm = (
 1210.      1                `Wrap an immediate function invocation in parentheses to assist`
 1211.      1                + ` the reader in understanding that the expression is the`
 1212.      1                + ` result of a function, and not the function itself.`
 1213.      1            );
 1214.      1            break;
 1215.     18        case "wrap_regexp":
 1216.     18            mm = `Wrap this regexp in parens to avoid confusion.`;
 1217.     18            break;
 1218.      1        case "wrap_unary":
 1219.      1            mm = `Wrap the unary expression in parens.`;
 1220.      1            break;
 1221.   1387        }
 1222.   1387
 1223.   1387// Validate mm.
 1224.   1387
 1225.   1387        jslint_assert(mm, code);
 1226.   1387        warning.message = mm;
 1227.   1387
 1228.   1387// PR-242 - Include stack_trace for jslint to debug itself for errors.
 1229.   1387
 1230.      6        if (option_dict.trace) {
 1231.      6            warning.stack_trace = new Error().stack;
 1232.      6        }
 1233.     41        if (warning.directive_ignore_line) {
 1234.     41
 1235.     41// test_cause:
 1236.     41// ["0 //jslint-ignore-line", "semicolon", "directive_ignore_line", "", 0]
 1237.     41
 1238.     41            test_cause("directive_ignore_line");
 1239.     41            return warning;
 1240.   1346        }
 1241.   1346        warning_list.push(warning);
 1242.   1346        return warning;
 1243.   1346    }
 1244.    666
 1245.    666    try {
 1246.    666
 1247.    666// tokenize takes a source and produces from it an array of token objects.
 1248.    666// JavaScript is notoriously difficult to tokenize because of the horrible
 1249.    666// interactions between automatic semicolon insertion, regular expression
 1250.    666// literals, and now megastring literals. JSLint benefits from eliminating
 1251.    666// automatic semicolon insertion and nested megastring literals, which allows
 1252.    666// full tokenization to precede parsing.
 1253.    666
 1254.    666        option_dict = Object.assign(empty(), option_dict);
 1255.    666        Object.assign(state, {
 1256.    666            artifact,
 1257.    666            catch_list,
 1258.    666            catch_stack,
 1259.    666            directive_list,
 1260.    666            export_dict,
 1261.    666            function_list,
 1262.    666            function_stack,
 1263.    666            global_dict,
 1264.    666            global_list,
 1265.    666            import_list,
 1266.    666            is_equal,
 1267.    666            is_weird,
 1268.    666            line_list,
 1269.    666            mode_json: false,           // true if parsing JSON.
 1270.    666            mode_module: false,         // true if import or export was used.
 1271.    666            mode_property: false,       // true if directive /*property*/ is
 1272.    666                                        // ... used.
 1273.    666            mode_shebang: false,        // true if #! is seen on the first line.
 1274.    666            option_dict,
 1275.    666            property_dict,
 1276.    666            source,
 1277.    666            stop,
 1278.    666            stop_at,
 1279.    666            syntax_dict,
 1280.    666            tenure,
 1281.    666            test_cause,
 1282.    666            token_global,
 1283.    666            token_list,
 1284.    666            token_nxt: token_global,
 1285.    666            warn,
 1286.    666            warn_at,
 1287.    666            warning_list
 1288.    666        });
 1289.    666
 1290.    666// PHASE 1. Split <source> by newlines into <line_list>.
 1291.    666
 1292.    666        jslint_phase1_split(state);
 1293.    666        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1294.    666        jslint_assert(
 1295.    666            function_stack.length === 0,
 1296.    666            `function_stack.length === 0.`
 1297.    666        );
 1298.    666
 1299.    666// PHASE 2. Lex <line_list> into <token_list>.
 1300.    666
 1301.    666        jslint_phase2_lex(state);
 1302.    666        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1303.    666        jslint_assert(
 1304.    666            function_stack.length === 0,
 1305.    666            `function_stack.length === 0.`
 1306.    666        );
 1307.    666
 1308.    666// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
 1309.    666
 1310.    666        jslint_phase3_parse(state);
 1311.    666        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1312.    666        jslint_assert(
 1313.    666            function_stack.length === 0,
 1314.    666            `function_stack.length === 0.`
 1315.    666        );
 1316.    666
 1317.    666// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
 1318.    666//          recursive traversal. Each node may be processed on the way down
 1319.    666//          (preaction) and on the way up (postaction).
 1320.    666
 1321.    516        if (!state.mode_json) {
 1322.    516            jslint_phase4_walk(state);
 1323.    531        }
 1324.    531        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1325.    531        jslint_assert(
 1326.    531            function_stack.length === 0,
 1327.    531            `function_stack.length === 0.`
 1328.    531        );
 1329.    531
 1330.    531// PHASE 5. Check whitespace between tokens in <token_list>.
 1331.    531
 1332.    531        if (!state.mode_json && warning_list.length === 0) {
 1333.    208            jslint_phase5_whitage(state);
 1334.    531        }
 1335.    531        jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
 1336.    531        jslint_assert(
 1337.    531            function_stack.length === 0,
 1338.    531            `function_stack.length === 0.`
 1339.    531        );
 1340.    531
 1341.    531// PR-347 - Disable warning "missing_browser".
 1342.    531//
 1343.    531//         if (!option_dict.browser) {
 1344.    531//             directive_list.forEach(function (comment) {
 1345.    531//                 if (comment.directive === "global") {
 1346.    531//
 1347.    531// // test_cause:
 1348.    531// // ["/*global aa*/", "jslint", "missing_browser", "(comment)", 1]
 1349.    531//
 1350.    531//                     warn("missing_browser", comment);
 1351.    531//                 }
 1352.    531//             });
 1353.    531//         }
 1354.    531
 1355.    531        if (option_dict.test_internal_error) {
 1356.      2            jslint_assert(undefined, "test_internal_error");
 1357.      2        }
 1358.    137    } catch (err) {
 1359.    137        mode_stop = true;
 1360.    137        err.message = "[JSLint was unable to finish] " + err.message;
 1361.    137        err.mode_stop = true;
 1362.    137        if (err.name !== "JSLintError") {
 1363.    137            Object.assign(err, {
 1364.    137                column: jslint_fudge,
 1365.    137                line: jslint_fudge,
 1366.    137                line_source: "",
 1367.    137                stack_trace: err.stack
 1368.    137            });
 1369.    137        }
 1370.    137        if (warning_list.indexOf(err) === -1) {
 1371.    137            warning_list.push(err);
 1372.    137        }
 1373.    137    }
 1374.    666
 1375.    666// Sort warning_list by mode_stop first, line, column respectively.
 1376.    666
 1377.    976    warning_list.sort(function (aa, bb) {
 1378.    976        return (
 1379.    976            Boolean(bb.mode_stop) - Boolean(aa.mode_stop)
 1380.    886            || aa.line - bb.line
 1381.    866            || aa.column - bb.column
 1382.    976        );
 1383.    976
 1384.    976// Update each warning with formatted_message ready-for-use by jslint_cli.
 1385.    976
 1386.   1157    }).map(function ({
 1387.   1157        column,
 1388.   1157        line,
 1389.   1157        line_source,
 1390.   1157        message,
 1391.   1157        stack_trace = ""
 1392.   1157    }, ii, list) {
 1393.   1157        list[ii].formatted_message = String(
 1394.   1157            String(ii + 1).padStart(2, " ")
 1395.   1157            + ". \u001b[31m" + message + "\u001b[39m"
 1396.   1157            + " \u001b[90m\/\/ line " + line + ", column " + column
 1397.   1157            + "\u001b[39m\n"
 1398.   1157            + ("    " + line_source.trim()).slice(0, 72) + "\n"
 1399.   1157            + stack_trace
 1400.   1157        ).trimRight();
 1401.   1157    });
 1402.    666
 1403.    666    return {
 1404.    666        causes: cause_dict,
 1405.    666        directives: directive_list,
 1406.    666        edition: jslint_edition,
 1407.    666        exports: export_dict,
 1408.    666        froms: import_list,
 1409.    666        functions: function_list,
 1410.    666        global: token_global,
 1411.    666        id: "(JSLint)",
 1412.    666        json: state.mode_json,
 1413.    666        lines: line_list,
 1414.    666        module: state.mode_module === true,
 1415.    164        ok: warning_list.length === 0 && !mode_stop,
 1416.    666        option: option_dict,
 1417.    666        property: property_dict,
 1418.    666        shebang: (
 1419.    666            state.mode_shebang
 1420.      1            ? line_list[jslint_fudge].line_source
 1421.    665            : undefined
 1422.    666        ),
 1423.    666        stop: mode_stop,
 1424.    666        tokens: token_list,
 1425.    666        tree: state.token_tree,
 1426.    666        warnings: warning_list
 1427.    666    };
 1428.    666}
 1429.      1
 1430.      1// PR-362 - Add API Doc.
 1431.      1
 1432.      1async function jslint_apidoc({
 1433.      1    example_list,
 1434.      1    github_repo,
 1435.      1    module_list,
 1436.      1    package_name,
 1437.      1    pathname,
 1438.      1    version
 1439.      1}) {
 1440.      1
 1441.      1// This function will create API Doc from <module_list>.
 1442.      1
 1443.      1    let elem_ii = 0;
 1444.      1    let html;
 1445.      1
 1446.     27    function elem_create(moduleObj, key, moduleName) {
 1447.     27
 1448.     27// This function will create a sub API Doc from elem <moduleObj>[<key>].
 1449.     27
 1450.     27        let example = "N/A";
 1451.     27        let id = encodeURIComponent("apidoc.elem." + moduleName + "." + key);
 1452.     27        let name;
 1453.     27        let signature;
 1454.     27        let source;
 1455.     27        name = htmlEscape((typeof moduleObj[key]) + " " + key);
 1456.      2        if (typeof moduleObj[key] !== "function") {
 1457.      2            return {
 1458.      2                name,
 1459.      2                signature: (`
 1460.      2<a class="apidocElementLiA" href="#${id}">
 1461.      2${name}
 1462.      2</a>
 1463.      2                `),
 1464.      2                source: (`
 1465.      2<li>
 1466.      2    <h2>
 1467.      2    <a href="#${id}" id="${id}">
 1468.      2    ${name}
 1469.      2    </a>
 1470.      2    </h2>
 1471.      2</li>
 1472.      2                `)
 1473.      2            };
 1474.     25        }
 1475.     25        // init source
 1476.     25        source = htmlEscape(trim_start(moduleObj[key].toString()));
 1477.     25        // init signature
 1478.     25        source = source.replace((
 1479.     25            /(\([\S\s]*?\)) \{/
 1480.     25        ), function (match0, match1) {
 1481.     25            signature = htmlEscape(
 1482.     25                match1.replace((
 1483.     25                    / *?\/\*[\S\s]*?\*\/ */g
 1484.     25                ), "").replace((
 1485.     25                    / *?\/\/.*/g
 1486.     25                ), "").replace((
 1487.     25                    /\n{2,}/g
 1488.     25                ), "\n")
 1489.     25            );
 1490.     25            return match0;
 1491.     25        });
 1492.     25        // init comment
 1493.     25        source = source.replace((
 1494.     25            /\n(?:\/\/.*?\n)+\n/
 1495.     25        ), "<span class=\"apidocCodeCommentSpan\">$&</span>");
 1496.     25        // init example
 1497.     56        example_list.some(function (example2) {
 1498.     56            example2.replace(
 1499.     56                new RegExp((
 1500.     56                    "((?:\\n.*?){8}(function )?)\\b"
 1501.     56                    + key
 1502.     56                    + "(\\((?:.*?\\n){8})"
 1503.     56                ), "g"),
 1504.    132                function (ignore, header, isDeclaration, footer) {
 1505.    124                    if (!isDeclaration) {
 1506.    124                        example = "..." + trim_start(
 1507.    124                            htmlEscape(header)
 1508.    124                            + "<span class=\"apidocCodeKeywordSpan\">"
 1509.    124                            + htmlEscape(key)
 1510.    124                            + "</span>"
 1511.    124                            + htmlEscape(footer)
 1512.    124                        ).trimEnd() + "\n...";
 1513.    124                    }
 1514.    132                    return "";
 1515.    132                }
 1516.     56            );
 1517.     56            return example !== "N/A";
 1518.     56        });
 1519.     25        if (source.length > 2048) {
 1520.     11            source = source.slice(0, 2048) + "...\n}\n";
 1521.     25        }
 1522.     25        return {
 1523.     25            name,
 1524.     25            signature: (`
 1525.     25<a class="apidocElementLiA" href="#${id}">
 1526.     25${name}<span class="apidocSignatureSpan">${signature}</span>
 1527.     25</a>
 1528.     25            `),
 1529.     25            source: (`
 1530.     25<li>
 1531.     25    <h2>
 1532.     25    <a href="#${id}" id="${id}">
 1533.     25    ${name}<span class="apidocSignatureSpan">${signature}</span>
 1534.     25    </a>
 1535.     25    </h2>
 1536.     25</li>
 1537.     25<li>Description and source-code:<pre class="apidocCodePre">${source}</pre></li>
 1538.     25<li>Example usage:<pre class="apidocCodePre">${example}</pre></li>
 1539.     25            `)
 1540.     25        };
 1541.     25    }
 1542.      1
 1543.    149    function trim_start(str) {
 1544.    149
 1545.    149// This function will normalize whitespace before <str>.
 1546.    149
 1547.    149        let whitespace = "";
 1548.    149        str.trim().replace((
 1549.    149            /^ */gm
 1550.  13047        ), function (match0) {
 1551.   8402            if (whitespace === "" || match0.length < whitespace.length) {
 1552.   6592                whitespace = match0;
 1553.   6592            }
 1554.  13047            return "";
 1555.  13047        });
 1556.    149        str = str.replace(new RegExp("^" + whitespace, "gm"), "");
 1557.    149        return str;
 1558.    149    }
 1559.      1    await moduleFsInit();
 1560.      1
 1561.      1// Html-escape params.
 1562.      1
 1563.      1    github_repo = htmlEscape(github_repo);
 1564.      1    package_name = htmlEscape(package_name);
 1565.      1    version = htmlEscape(version);
 1566.      1
 1567.      1// Init example_list.
 1568.      1
 1569.      3    example_list = await Promise.all(example_list.map(async function (file) {
 1570.      3
 1571.      3// This function will read example from given file.
 1572.      3
 1573.      3        let result = await moduleFs.promises.readFile(file, "utf8");
 1574.      3        result = (
 1575.      3            "\n\n\n\n\n\n\n\n"
 1576.      3            // bug-workaround - truncate example to manageable size
 1577.      3            + result.slice(0, 524288)
 1578.      3            + "\n\n\n\n\n\n\n\n"
 1579.      3        );
 1580.      3        result = result.replace((
 1581.      3            /\r\n*/g
 1582.      3        ), "\n");
 1583.      3        return result;
 1584.      3    }));
 1585.      1
 1586.      1// Init module_list.
 1587.      1
 1588.      1    module_list = await Promise.all(module_list.map(async function ({
 1589.      1        pathname
 1590.      1    }) {
 1591.      1        let moduleName = htmlEscape(JSON.stringify(pathname));
 1592.      1        let moduleObj = await import(pathname);
 1593.      1        if (moduleObj.default) {
 1594.      1            moduleObj = moduleObj.default;
 1595.      1        }
 1596.      1        return {
 1597.     27            elem_list: Object.keys(moduleObj).map(function (key) {
 1598.     27                return elem_create(moduleObj, key, moduleName);
 1599.     78            }).sort(function (aa, bb) {
 1600.     78                return (
 1601.     78                    aa.name < bb.name
 1602.     22                    ? -1
 1603.     56                    : 1
 1604.     78                );
 1605.     27            }).map(function (elem) {
 1606.     27                elem_ii += 1;
 1607.     27                elem.signature = elem.signature.replace(
 1608.     27                    ">",
 1609.     27                    ">" + elem_ii + ". "
 1610.     27                );
 1611.     27                elem.source = elem.source.replace(
 1612.     27                    "\">",
 1613.     27                    "\">" + elem_ii + ". "
 1614.     27                );
 1615.     27                return elem;
 1616.     27            }),
 1617.      1            id: encodeURIComponent("apidoc.module." + moduleName),
 1618.      1            moduleName
 1619.      1        };
 1620.      1    }));
 1621.      1    html = (`
 1622.      1<!DOCTYPE html>
 1623.      1<html lang="en">
 1624.      1<head>
 1625.      1<meta charset="utf-8">
 1626.      1<meta name="viewport" content="width=device-width, initial-scale=1">
 1627.      1<meta name="description" content="${package_name} API Doc">
 1628.      1<title>${package_name} apidoc</title>
 1629.      1<style>
 1630.      1/* jslint utility2:true */
 1631.      1/*csslint*/
 1632.      1body {
 1633.      1    margin: 0;
 1634.      1    padding: 20px;
 1635.      1}
 1636.      1.apidocCodeCommentSpan,
 1637.      1.apidocCodeKeywordSpan {
 1638.      1    background: royalblue;
 1639.      1    color: white;
 1640.      1}
 1641.      1.apidocCodeCommentSpan {
 1642.      1    display: block;
 1643.      1}
 1644.      1.apidocCodePre {
 1645.      1    background: #eef;
 1646.      1    border: 1px solid;
 1647.      1    font-size: 14px;
 1648.      1    overflow-wrap: break-word;
 1649.      1    padding: 5px;
 1650.      1    white-space: pre-wrap;
 1651.      1}
 1652.      1.apidocDiv {
 1653.      1    color: #555;
 1654.      1    font-family: sans-serif;
 1655.      1}
 1656.      1.apidocDiv a[href] {
 1657.      1    color: royalblue;
 1658.      1    text-decoration: none;
 1659.      1}
 1660.      1.apidocDiv a[href]:hover {
 1661.      1    text-decoration: underline;
 1662.      1}
 1663.      1.apidocDiv li a {
 1664.      1    display: inline-block;
 1665.      1    padding: 8px 0;
 1666.      1}
 1667.      1.apidocDiv ul {
 1668.      1    list-style: none;
 1669.      1    padding-left: 20px;
 1670.      1}
 1671.      1.apidocFooterDiv {
 1672.      1    margin-top: 20px;
 1673.      1    text-align: center;
 1674.      1}
 1675.      1.apidocModuleA {
 1676.      1    font-size: 24px;
 1677.      1    font-weight: bold;
 1678.      1}
 1679.      1.apidocSectionDiv {
 1680.      1    border-top: 1px solid;
 1681.      1    margin-top: 20px;
 1682.      1}
 1683.      1.apidocSignatureSpan {
 1684.      1    color: #666;
 1685.      1    white-space: pre-wrap;
 1686.      1}
 1687.      1</style>
 1688.      1</head>
 1689.      1<body>
 1690.      1<div class="apidocDiv">
 1691.      1<h1>API Doc for <a href="${github_repo}">${package_name} (${version})</a></h1>
 1692.      1<div class="apidocSectionDiv">
 1693.      1    <a href="#apidocTableOfContents1" id="apidocTableOfContents1">
 1694.      1        <h1>Table of Contents</h1>
 1695.      1    </a>
 1696.      1    <ul>
 1697.      1    `) + module_list.map(function ({
 1698.      1        elem_list,
 1699.      1        id,
 1700.      1        moduleName
 1701.      1    }) {
 1702.      1        return (
 1703.      1            (`
 1704.      1        <li>
 1705.      1            <a class="apidocModuleA" href="#${id}">Module ${moduleName}</a>
 1706.      1            <ul>
 1707.      1            `)
 1708.     27            + elem_list.map(function ({
 1709.     27                signature
 1710.     27            }) {
 1711.     27                return "<li>\n" + signature + "\n</li>\n";
 1712.     27            }).join("")
 1713.      1            + (`
 1714.      1            </ul>
 1715.      1        </li>
 1716.      1            `)
 1717.      1        );
 1718.      1    }).join("") + (`
 1719.      1    </ul>
 1720.      1</div>
 1721.      1    `) + module_list.map(function ({
 1722.      1        elem_list,
 1723.      1        id,
 1724.      1        moduleName
 1725.      1    }) {
 1726.      1        return (
 1727.      1            (`
 1728.      1<div class="apidocSectionDiv">
 1729.      1    <h1><a href="#${id}" id="${id}">Module ${moduleName}</a></h1>
 1730.      1    <ul>
 1731.      1            `)
 1732.     27            + elem_list.map(function ({
 1733.     27                source
 1734.     27            }) {
 1735.     27                return source;
 1736.     27            }).join("")
 1737.      1            + (`
 1738.      1    </ul>
 1739.      1</div>
 1740.      1            `)
 1741.      1        );
 1742.      1    }).join("") + (`
 1743.      1<div class="apidocFooterDiv">
 1744.      1    [
 1745.      1    This document was created with
 1746.      1    <a href="https://github.com/jslint-org/jslint">JSLint</a>
 1747.      1    ]
 1748.      1</div>
 1749.      1</div>
 1750.      1</body>
 1751.      1</html>
 1752.      1    `);
 1753.      1    html = html.trim().replace((
 1754.      1        / +?$/gm
 1755.      1    ), "") + "\n";
 1756.      1    await fsWriteFileWithParents(pathname, html);
 1757.      1}
 1758.      1
 1759. 102718function jslint_assert(condition, message) {
 1760. 102718
 1761. 102718// This function will throw <message> if <condition> is falsy.
 1762. 102718
 1763. 102716    if (condition) {
 1764. 102716        return condition;
 1765. 102716    }
 1766.      2    throw new Error(
 1767.      2        `This was caused by a bug in JSLint.
 1768.      2Please open an issue with this stack-trace (and possible example-code) at
 1769.      2https://github.com/jslint-org/jslint/issues.
 1770.      2edition = "${jslint_edition}";
 1771.      2${String(message).slice(0, 2000)}`
 1772.      2    );
 1773.      2}
 1774.      1
 1775.     38async function jslint_cli({
 1776.     38    console_error,
 1777.     38    console_log,
 1778.     38    file,
 1779.     38    import_meta_url,
 1780.     38    mode_cli,
 1781.     38    mode_noop,
 1782.     38    option,
 1783.     38    process_argv,
 1784.     38    process_env,
 1785.     38    process_exit,
 1786.     38    source
 1787.     38}) {
 1788.     38
 1789.     38// This function will run jslint from nodejs-cli.
 1790.     38
 1791.     38    let command;
 1792.     38    let data;
 1793.     38    let exit_code = 0;
 1794.     38    let mode_report;
 1795.     38    let mode_wrapper_vim;
 1796.     38    let result;
 1797.     38
 1798.     51    function jslint_from_file({
 1799.     51        code,
 1800.     51        file,
 1801.     51        line_offset = 0,
 1802.     51        mode_conditional,
 1803.     51        option = empty()
 1804.     51    }) {
 1805.     51        let result_from_file;
 1806.     51        if (
 1807.     51            mode_conditional
 1808.      5            && !(
 1809.      5                /^\/\*jslint\b/m
 1810.      5            ).test(code.slice(0, 65536))
 1811.      1        ) {
 1812.      1            return;
 1813.     50        }
 1814.     50        option = Object.assign(empty(), option, {
 1815.     50            file
 1816.     50        });
 1817.     50        switch ((
 1818.     50            /\.\w+?$|$/m
 1819.     50        ).exec(file)[0]) {
 1820.     50        case ".html":
 1821.      3
 1822.      3// Recursively jslint embedded "<script>\n...\n</script>".
 1823.      3
 1824.      3            code.replace((
 1825.      3                /^<script\b[^>]*?>\n([\S\s]*?\n)<\/script>$/gm
 1826.      3            ), function (ignore, match1, ii) {
 1827.      3                jslint_from_file({
 1828.      3                    code: match1,
 1829.      3                    file: file + ".<script>.js",
 1830.      3                    line_offset: string_line_count(code.slice(0, ii)) + 1,
 1831.      3                    option: Object.assign(empty(), {
 1832.      3                        browser: true
 1833.      3                    }, option)
 1834.      3                });
 1835.      3                return "";
 1836.      3            });
 1837.      3            return;
 1838.      2        case ".md":
 1839.      2
 1840.      2// Recursively jslint embedded "node --eval '\n...\n'".
 1841.      2
 1842.      2            jslint_node_eval({
 1843.      2                code,
 1844.      2                file,
 1845.      2                mode_conditional: true,
 1846.      2                option
 1847.      2            });
 1848.      2            return;
 1849.      2        case ".sh":
 1850.      2
 1851.      2// Recursively jslint embedded "node --eval '\n...\n'".
 1852.      2
 1853.      2            jslint_node_eval({
 1854.      2                code,
 1855.      2                file,
 1856.      2                option
 1857.      2            });
 1858.      2            return;
 1859.     43        default:
 1860.     43            result_from_file = jslint("\n".repeat(line_offset) + code, option);
 1861.     43        }
 1862.     43
 1863.     43// Print only first 10 warnings to stderr.
 1864.     43
 1865.     43        if (result_from_file.warnings.length > 0) {
 1866.      5            exit_code = 1;
 1867.      5            console_error(
 1868.      5                mode_wrapper_vim
 1869.      5
 1870.      5// PR-349 - Print warnings in format readable by vim.
 1871.      5
 1872.      5                ? result_from_file.warnings.slice(0, 10).map(function ({
 1873.      5                    column,
 1874.      5                    line,
 1875.      5                    message
 1876.      5                }, ii) {
 1877.      5                    return (
 1878.      5                        file
 1879.      5                        + ":" + ii
 1880.      5                        + ":" + line
 1881.      5                        + ":" + column
 1882.      5                        + ":" + message
 1883.      5                    );
 1884.      5                }).join("\n")
 1885.      5
 1886.      5// Print warnings in format readable by human.
 1887.      5
 1888.      5                : "\u001b[1mjslint " + file + "\u001b[22m\n"
 1889.     11                + result_from_file.warnings.slice(0, 10).map(function ({
 1890.     11                    formatted_message
 1891.     11                }) {
 1892.     11                    return formatted_message;
 1893.     11                }).join("\n")
 1894.      5            );
 1895.     43        }
 1896.     43        return result_from_file;
 1897.     43    }
 1898.     38
 1899.      4    function jslint_node_eval({
 1900.      4        code,
 1901.      4        file,
 1902.      4        mode_conditional,
 1903.      4        option = empty()
 1904.      4    }) {
 1905.      4        code.replace((
 1906.      4            /\bnode\b.*? (?:--eval|-e) '\n([\S\s]*?\n)'/gm
 1907.     26        ), function (ignore, match1, ii) {
 1908.     26            jslint_from_file({
 1909.     26                code: match1,
 1910.     26                file: file + ".<node -e>.js",
 1911.     26                line_offset: string_line_count(code.slice(0, ii)) + 1,
 1912.     26                mode_conditional,
 1913.     26                option: Object.assign(empty(), {
 1914.     26                    beta: Boolean(
 1915.     26                        process_env.JSLINT_BETA
 1916.     26                        && !(
 1917.     26                            /0|false|null|undefined/
 1918.     26                        ).test(process_env.JSLINT_BETA)
 1919.     26                    ),
 1920.     26                    node: true
 1921.     26                }, option)
 1922.     26            });
 1923.     26            return "";
 1924.     26        });
 1925.      4    }
 1926.     38
 1927.     28    function string_line_count(code) {
 1928.     28
 1929.     28// This function will count number of newlines in <code>.
 1930.     28
 1931.     28        let count;
 1932.     28        let ii;
 1933.     28
 1934.     28// https://jsperf.com/regexp-counting-2/8
 1935.     28
 1936.     28        count = 0;
 1937.     28        ii = 0;
 1938.  23223        while (true) {
 1939.  23223            ii = code.indexOf("\n", ii) + 1;
 1940.  23223            if (ii === 0) {
 1941.  23223                break;
 1942.  23223            }
 1943.  23223            count += 1;
 1944.  23223        }
 1945.     28        return count;
 1946.     28    }
 1947.     38
 1948.     38// PR-396 - window.jslint
 1949.     38// Check import.meta.url for directive to export jslint to window-object.
 1950.     38// Useful for ES5-era browser-scripts that rely on window.jslint,
 1951.     38// like CodeMirror.
 1952.     38//
 1953.     38// Example usage:
 1954.     38// <script type="module" src="./jslint.mjs?window_jslint=1"></script>
 1955.     38
 1956.     22    import_meta_url = import_meta_url || jslint_import_meta_url;
 1957.     38    if (
 1958.     38        jslint_rgx_url_search_window_jslint.test(import_meta_url)
 1959.      4        && (typeof globalThis === "object" && globalThis)
 1960.      4    ) {
 1961.      4        globalThis.jslint = jslint;
 1962.      4    }
 1963.     38
 1964.     38// Feature-detect nodejs.
 1965.     38
 1966.     38    if (!(
 1967.     38        (typeof process === "object" && process)
 1968.     38        && process.versions
 1969.     38        && typeof process.versions.node === "string"
 1970.     38        && !mode_noop
 1971.      1    )) {
 1972.      1        return exit_code;
 1973.     37    }
 1974.     37    console_error = console_error || console.error;
 1975.     37    console_log = console_log || console.log;
 1976.     22    process_argv = process_argv || process.argv;
 1977.     34    process_env = process_env || process.env;
 1978.     24    process_exit = process_exit || process.exit;
 1979.     37    await moduleFsInit();
 1980.     37    if (
 1981.     37        !(
 1982.     37
 1983.     37// Feature-detect nodejs-cli.
 1984.     37
 1985.     37            process.execArgv.indexOf("--eval") === -1
 1986.     37            && process.execArgv.indexOf("-e") === -1
 1987.     37            && (
 1988.     37                (
 1989.     37                    /[\/|\\]jslint(?:\.[cm]?js)?$/m
 1990.     37                ).test(process_argv[1])
 1991.     37                || mode_cli
 1992.     37            )
 1993.     20            && (
 1994.     20                moduleUrl.fileURLToPath(import_meta_url)
 1995.     20                ===
 1996.     20                modulePath.resolve(process_argv[1])
 1997.     20            )
 1998.     38        )
 1999.     22        && !mode_cli
 2000.     17    ) {
 2001.     17        return exit_code;
 2002.     20    }
 2003.     20
 2004.     20// init commmand
 2005.     20
 2006.     20    command = String(process_argv[2]).split("=");
 2007.     20    command[1] = command.slice(1).join("=");
 2008.     20
 2009.     20    switch (command[0]) {
 2010.     20
 2011.     20// PR-362 - Add API Doc.
 2012.     20
 2013.     20    case "jslint_apidoc":
 2014.      1        await jslint_apidoc(Object.assign(JSON.parse(process_argv[3]), {
 2015.      1            pathname: command[1]
 2016.      1        }));
 2017.      1        return;
 2018.     38
 2019.     38// PR-363 - Add command jslint_report.
 2020.     38
 2021.      6    case "jslint_report":
 2022.      6        mode_report = command[1];
 2023.      6        process_argv = process_argv.slice(1);
 2024.      6        break;
 2025.     38
 2026.     38// COMMIT-b26d6df2 - Add command jslint_wrapper_vim.
 2027.     38
 2028.      1    case "jslint_wrapper_vim":
 2029.      1        mode_wrapper_vim = true;
 2030.      1        process_argv = process_argv.slice(1);
 2031.      1        break;
 2032.     38
 2033.     38// PR-364 - Add command v8_coverage_report.
 2034.     38
 2035.      7    case "v8_coverage_report":
 2036.      7        await v8CoverageReportCreate({
 2037.      7            consoleError: console_error,
 2038.      7            coverageDir: command[1],
 2039.      7            processArgv: process_argv.slice(3)
 2040.      7        });
 2041.      7        return;
 2042.     12    }
 2043.     12
 2044.     12// Normalize file relative to process.cwd().
 2045.     12
 2046.     12    process_argv.slice(2).some(function (arg) {
 2047.     12        if (!arg.startsWith("-")) {
 2048.     12            file = file || arg;
 2049.     12            return true;
 2050.     12        }
 2051.     12    });
 2052.     12    if (!file) {
 2053.      1        return;
 2054.     11    }
 2055.     11    file = modulePath.resolve(file) + "/";
 2056.     11    if (file.startsWith(process.cwd() + "/")) {
 2057.     11        file = file.replace(process.cwd() + "/", "").slice(0, -1) || ".";
 2058.     11    }
 2059.     11    file = file.replace((
 2060.     11        /\\/g
 2061.     11    ), "/").replace((
 2062.     11        /\/$/g
 2063.     11    ), "");
 2064.     11    if (source) {
 2065.      7        data = source;
 2066.      7    } else {
 2067.      4
 2068.      4// jslint_cli - jslint directory.
 2069.      4
 2070.      4        try {
 2071.      4            data = await moduleFs.promises.readdir(file, "utf8");
 2072.      4        } catch (ignore) {}
 2073.      4        if (data) {
 2074.     34            await Promise.all(data.map(async function (file2) {
 2075.     34                let code;
 2076.     34                let time_start = Date.now();
 2077.     34                file2 = file + "/" + file2;
 2078.     34                switch ((
 2079.     34                    /\.\w+?$|$/m
 2080.     34                ).exec(file2)[0]) {
 2081.      4                case ".cjs":
 2082.      5                case ".html":
 2083.      8                case ".js":
 2084.     10                case ".json":
 2085.     12                case ".md":
 2086.     14                case ".mjs":
 2087.     16                case ".sh":
 2088.     16                    break;
 2089.     18                default:
 2090.     18                    return;
 2091.     16                }
 2092.     16                try {
 2093.     16                    code = await moduleFs.promises.readFile(file2, "utf8");
 2094.     15                } catch (ignore) {
 2095.      4                    return;
 2096.     15                }
 2097.     15                if (
 2098.     15                    (
 2099.     15                        /(?:\b|_)(?:lock|min|raw|rollup)(?:\b|_)/
 2100.     15                    ).test(file2)
 2101.     15                    || !(code && code.length < 1048576)
 2102.      4                ) {
 2103.      4                    return;
 2104.     14                }
 2105.     14                jslint_from_file({
 2106.     14                    code,
 2107.     14                    file: file2,
 2108.     14                    option
 2109.     14                });
 2110.     14                console_error(
 2111.     14                    "jslint - " + (Date.now() - time_start) + "ms - " + file2
 2112.     14                );
 2113.     14            }));
 2114.      4            process_exit(exit_code);
 2115.      4            return exit_code;
 2116.      4        }
 2117.      4
 2118.      4// jslint_cli - jslint file.
 2119.      4
 2120.      4        try {
 2121.      4            data = await moduleFs.promises.readFile(file, "utf8");
 2122.      4        } catch (err) {
 2123.      4            console_error(err);
 2124.      4            exit_code = 1;
 2125.      4            process_exit(exit_code);
 2126.      4            return exit_code;
 2127.      4        }
 2128.      9    }
 2129.      9    result = jslint_from_file({
 2130.      9        code: data,
 2131.      9        file,
 2132.      9        option
 2133.      9    });
 2134.      9    if (mode_report) {
 2135.      6        result = jslint.jslint_report(result);
 2136.      6        result = `<body class="JSLINT_ JSLINT_REPORT_">\n${result}</body>\n`;
 2137.      6        await fsWriteFileWithParents(mode_report, result);
 2138.      9    }
 2139.      9    process_exit(exit_code);
 2140.      9    return exit_code;
 2141.      9}
 2142.      1
 2143.    666function jslint_phase1_split() {
 2144.    666
 2145.    666// PHASE 1. Split <source> by newlines into <line_list>.
 2146.    666
 2147.    666    return;
 2148.    666}
 2149.      1
 2150.    666function jslint_phase2_lex(state) {
 2151.    666
 2152.    666// PHASE 2. Lex <line_list> into <token_list>.
 2153.    666
 2154.    666    let {
 2155.    666        artifact,
 2156.    666        directive_list,
 2157.    666        global_dict,
 2158.    666        global_list,
 2159.    666        line_list,
 2160.    666        option_dict,
 2161.    666        stop,
 2162.    666        stop_at,
 2163.    666        tenure,
 2164.    666        test_cause,
 2165.    666        token_global,
 2166.    666        token_list,
 2167.    666        warn,
 2168.    666        warn_at
 2169.    666    } = state;
 2170.    666    let char;                   // The current character being lexed.
 2171.    666    let column = 0;             // The column number of the next character.
 2172.    666    let from;                   // The starting column number of the token.
 2173.    666    let from_mega;              // The starting column of megastring.
 2174.    666    let line = 0;               // The line number of the next character.
 2175.    666    let line_disable;           // The starting line of "/*jslint-disable*/".
 2176.    666    let line_mega;              // The starting line of megastring.
 2177.    666    let line_source = "";       // The remaining line source string.
 2178.    666    let line_whole = "";        // The whole line source string.
 2179.    666    let mode_digits_empty_string = 1;
 2180.    666    let mode_digits_numeric_separator = 2;
 2181.    666    let mode_directive = true;  // true if directives are still allowed.
 2182.    666    let mode_mega = false;      // true if currently parsing a megastring
 2183.    666                                // ... literal.
 2184.    666    let mode_regexp;            // true if regular expression literal seen on
 2185.    666                                // ... this line.
 2186.    666    let paren_backtrack_list = [];      // List of most recent "(" tokens at any
 2187.    666                                        // ... paren-depth.
 2188.    666    let paren_depth = 0;        // Keeps track of current paren-depth.
 2189.    666    let snippet = "";           // A piece of string.
 2190.    666    let token_1;                // The first token.
 2191.    666    let token_prv = token_global;       // The previous token including
 2192.    666                                        // ... comments.
 2193.    666    let token_prv_expr = token_global;  // The previous token excluding
 2194.    666                                        // ... comments.
 2195.    666
 2196.    666// Most tokens, including the identifiers, operators, and punctuators, can be
 2197.    666// found with a regular expression. Regular expressions cannot correctly match
 2198.    666// regular expression literals, so we will match those the hard way. String
 2199.    666// literals and number literals can be matched by regular expressions, but they
 2200.    666// don't provide good warnings. The functions char_after, char_before,
 2201.    666// read_digits, and char_after_escape help in the parsing of literals.
 2202.    666
 2203. 238033    function char_after(match) {
 2204. 238033
 2205. 238033// Get the next character from the source line. Remove it from the line_source,
 2206. 238033// and append it to the snippet. Optionally check that the previous character
 2207. 238033// matched an expected value.
 2208. 238033
 2209.   5980        if (match !== undefined && char !== match) {
 2210.     10
 2211.     10// test_cause:
 2212.     10// ["aa=/[", "char_after", "expected_a", "]", 5]
 2213.     10// ["aa=/aa{/", "char_after", "expected_a_b", "/", 8]
 2214.     10
 2215.     10            return (
 2216.     10                char === ""
 2217.     10                ? stop_at("expected_a", line, column - 1, match)
 2218.     10                : stop_at("expected_a_b", line, column, match, char)
 2219.     10            );
 2220. 238023        }
 2221. 238023        char = line_source.slice(0, 1);
 2222. 238023        line_source = line_source.slice(1);
 2223. 238023        snippet += char || " ";
 2224. 238033        column += 1;
 2225. 238033        return char;
 2226. 238033    }
 2227.    666
 2228.   2951    function char_after_escape(extra) {
 2229.   2951
 2230.   2951// Validate char after escape "\\".
 2231.   2951
 2232.   2951        char_after("\\");
 2233.   2951        switch (char) {
 2234.      1        case "":
 2235.      1
 2236.      1// test_cause:
 2237.      1// ["\"\\", "char_after_escape", "unclosed_string", "", 2]
 2238.      1
 2239.      1            return stop_at("unclosed_string", line, column);
 2240.    219        case "/":
 2241.    219            return char_after();
 2242.    355        case "\\":
 2243.    355            return char_after();
 2244.      1        case "`":
 2245.      1            return char_after();
 2246.     62        case "b":
 2247.     62            return char_after();
 2248.      6        case "f":
 2249.      6            return char_after();
 2250.   1013        case "n":
 2251.   1013            return char_after();
 2252.     32        case "r":
 2253.     32            return char_after();
 2254.     24        case "t":
 2255.     24
 2256.     24// test_cause:
 2257.     24// ["\"\\/\\\\\\`\\b\\f\\n\\r\\t\"", "char_after_escape", "char_after", "", 0]
 2258.     24
 2259.     24            test_cause("char_after");
 2260.     24            return char_after();
 2261.    376        case "u":
 2262.    376            if (char_after("u") === "{") {
 2263.    376                if (state.mode_json) {
 2264.    376
 2265.    376// test_cause:
 2266.    376// ["[\"\\u{12345}\"]", "char_after_escape", "unexpected_a", "{", 5]
 2267.    376
 2268.    376                    warn_at("unexpected_a", line, column, char);
 2269.    376                }
 2270.    376                if (read_digits("x", undefined) > 5) {
 2271.    376
 2272.    376// test_cause:
 2273.    376// ["\"\\u{123456}\"", "char_after_escape", "too_many_digits", "", 11]
 2274.    376
 2275.    376                    warn_at("too_many_digits", line, column);
 2276.    376                }
 2277.    376                if (char !== "}") {
 2278.    376
 2279.    376// test_cause:
 2280.    376// ["\"\\u{12345\"", "char_after_escape", "expected_a_before_b", "\"", 10]
 2281.    376
 2282.    376                    stop_at("expected_a_before_b", line, column, "}", char);
 2283.    376                }
 2284.    376                return char_after();
 2285.    376            }
 2286.    376            char_before();
 2287.    376            if (read_digits("x", mode_digits_empty_string) < 4) {
 2288.    376
 2289.    376// test_cause:
 2290.    376// ["\"\\u0\"", "char_after_escape", "expected_four_digits", "", 5]
 2291.    376
 2292.    376                warn_at("expected_four_digits", line, column);
 2293.    376            }
 2294.    376            return;
 2295.    862        default:
 2296.    862            if (extra && extra.indexOf(char) >= 0) {
 2297.    862                return char_after();
 2298.    862            }
 2299.    862
 2300.    862// test_cause:
 2301.    862// ["\"\\0\"", "char_after_escape", "unexpected_a_before_b", "0", 3]
 2302.    862
 2303.    862            warn_at("unexpected_a_before_b", line, column, "\\", char);
 2304.   2951        }
 2305.   2951    }
 2306.    666
 2307.  10019    function char_before() {
 2308.  10019
 2309.  10019// Back up one character by moving a character from the end of the snippet to
 2310.  10019// the front of the line_source.
 2311.  10019
 2312.  10019        char = snippet.slice(-1);
 2313.  10019        line_source = char + line_source;
 2314.  10019        column -= char.length;
 2315.  10019
 2316.  10019// Remove last character from snippet.
 2317.  10019
 2318.  10019        snippet = snippet.slice(0, -1);
 2319.  10019        return char;
 2320.  10019    }
 2321.    666
 2322.   8930    function check_numeric_separator(digits, column) {
 2323.   8930
 2324.   8930// This function will check for illegal numeric-separator in <digits>.
 2325.   8930
 2326.   8930        digits.replace((
 2327.   8930            jslint_rgx_numeric_separator_illegal
 2328.      6        ), function (ignore, ii) {
 2329.      6
 2330.      6// test_cause:
 2331.      6// ["0x0_0_;", "check_numeric_separator", "illegal_num_separator", "", 6]
 2332.      6// ["0x0_0__0;", "check_numeric_separator", "illegal_num_separator", "", 6]
 2333.      6// ["aa=1_2_;", "check_numeric_separator", "illegal_num_separator", "", 7]
 2334.      6// ["aa=1_2__3;", "check_numeric_separator", "illegal_num_separator", "", 7]
 2335.      6// ["aa=1_2_n;", "check_numeric_separator", "illegal_num_separator", "", 7]
 2336.      6
 2337.      6            warn_at("illegal_num_separator", line, column + ii + 1);
 2338.      6            return "";
 2339.      6        });
 2340.   8930    }
 2341.    666
 2342.  11181    function lex_comment() {
 2343.  11181        let body;
 2344.  11181        let ii = 0;
 2345.  11181        let jj = 0;
 2346.  11181        let the_comment;
 2347.  11181
 2348.  11181// Create a comment object. Comments are not allowed in JSON text. Comments can
 2349.  11181// include directives and notices of incompletion.
 2350.  11181
 2351.  11181// Create token from comment //....
 2352.  11181
 2353.  11067        if (snippet === "//") {
 2354.  11067            snippet = line_source;
 2355.  11067            line_source = "";
 2356.  11067            the_comment = token_create("(comment)", snippet);
 2357.  11067            if (mode_mega) {
 2358.  11067
 2359.  11067// test_cause:
 2360.  11067// ["`${//}`", "lex_comment", "unexpected_comment", "`", 4]
 2361.  11067
 2362.  11067                warn("unexpected_comment", the_comment, "`");
 2363.  11067            }
 2364.  11067
 2365.  11067// Create token from comment /*...*/.
 2366.  11067
 2367.  11067        } else {
 2368.    114            snippet = [];
 2369.    114            if (line_source[0] === "/") {
 2370.    114
 2371.    114// test_cause:
 2372.    114// ["/*/", "lex_comment", "unexpected_a", "/", 2]
 2373.    114
 2374.    114                warn_at("unexpected_a", line, column + ii, "/");
 2375.    114            }
 2376.    114
 2377.    114// Lex/loop through each line until "*/".
 2378.    114
 2379.    696            while (true) {
 2380.    696                // jslint_rgx_star_slash
 2381.    696                ii = line_source.indexOf("*/");
 2382.    696                if (ii >= 0) {
 2383.    696                    break;
 2384.    696                }
 2385.    696                // jslint_rgx_slash_star
 2386.    696                ii = line_source.indexOf("/*");
 2387.    696                if (ii >= 0) {
 2388.    696
 2389.    696// test_cause:
 2390.    696// ["/*/*", "lex_comment", "nested_comment", "", 2]
 2391.    696
 2392.    696                    warn_at("nested_comment", line, column + ii);
 2393.    696                }
 2394.    696                snippet.push(line_source);
 2395.    696                line_source = read_line();
 2396.    696                if (line_source === undefined) {
 2397.    696
 2398.    696// test_cause:
 2399.    696// ["/*", "lex_comment", "unclosed_comment", "", 1]
 2400.    696
 2401.    696                    return stop_at("unclosed_comment", line, column);
 2402.    696                }
 2403.    696            }
 2404.    114            jj = line_source.slice(0, ii).search(
 2405.    114                jslint_rgx_slash_star_or_slash
 2406.    114            );
 2407.    114            if (jj >= 0) {
 2408.    114
 2409.    114// test_cause:
 2410.    114// ["/*/**/", "lex_comment", "nested_comment", "", 2]
 2411.    114
 2412.    114                warn_at("nested_comment", line, column + jj);
 2413.    114            }
 2414.    114            snippet.push(line_source.slice(0, ii));
 2415.    114            snippet = snippet.join(" ");
 2416.    114            column += ii + 2;
 2417.    114            line_source = line_source.slice(ii + 2);
 2418.    114            the_comment = token_create("(comment)", snippet);
 2419.  11178        }
 2420.  11178
 2421.  11178// Uncompleted work comment.
 2422.  11178
 2423.  11178        if (!option_dict.devel && jslint_rgx_todo.test(snippet)) {
 2424.     16
 2425.     16// test_cause:
 2426.     16// ["//todo", "lex_comment", "todo_comment", "(comment)", 1] //jslint-ignore-line
 2427.     16
 2428.     16            warn("todo_comment", the_comment);
 2429.  11178        }
 2430.  11178
 2431.  11178// Lex directives in comment.
 2432.  11178
 2433.  11178        [
 2434.  11178            the_comment.directive, body
 2435.  11178        ] = Array.from(snippet.match(jslint_rgx_directive) || []).slice(1);
 2436.  11101        if (the_comment.directive === undefined) {
 2437.  11101            return the_comment;
 2438.  11101        }
 2439.     77        directive_list.push(the_comment);
 2440.     77        if (!mode_directive) {
 2441.      1
 2442.      1// test_cause:
 2443.      1// ["0\n/*global aa*/", "lex_comment", "misplaced_directive_a", "global", 1]
 2444.      1
 2445.      1            warn_at("misplaced_directive_a", line, from, the_comment.directive);
 2446.      1            return the_comment;
 2447.     76        }
 2448.     76
 2449.     76// lex_directive();
 2450.     76// JSLint recognizes three directives that can be encoded in comments. This
 2451.     76// function processes one item, and calls itself recursively to process the
 2452.     76// next one.
 2453.     76
 2454.     76// Lex/loop through each directive in /*...*/
 2455.     76
 2456.     76        ii = 0;
 2457.   1830        body.replace(jslint_rgx_directive_part, function (
 2458.   1830            match0,
 2459.   1830            key,
 2460.   1830            val,
 2461.   1830            jj
 2462.   1830        ) {
 2463.     76            if (ii !== jj) {
 2464.     76
 2465.     76// test_cause:
 2466.     76// ["/*jslint !*/", "lex_comment", "bad_directive_a", "!", 1]
 2467.     76
 2468.     76                return stop("bad_directive_a", the_comment, body.slice(ii));
 2469.   1829            }
 2470.   1829            if (match0 === "") {
 2471.     76                return "";
 2472.   1754            }
 2473.   1754            ii += match0.length;
 2474.   1754            switch (the_comment.directive) {
 2475.   1754            case "global":
 2476.     76                if (val) {
 2477.     76
 2478.     76// test_cause:
 2479.     76// ["/*global aa:false*/", "lex_comment", "bad_option_a", "aa:false", 1]
 2480.     76
 2481.     76                    warn("bad_option_a", the_comment, key + ":" + val);
 2482.     76                }
 2483.     76                global_dict[key] = "user-defined";
 2484.     76
 2485.     76// PR-347 - Disable warning "unexpected_directive_a".
 2486.     76//
 2487.     76//                 state.mode_module = the_comment;
 2488.     76
 2489.     76                break;
 2490.     99            case "jslint":
 2491.     99                if (!option_set_item(key, val !== "false")) {
 2492.     99
 2493.     99// test_cause:
 2494.     99// ["/*jslint undefined*/", "lex_comment", "bad_option_a", "undefined", 1]
 2495.     99
 2496.     99                    warn("bad_option_a", the_comment, key);
 2497.     99                }
 2498.     99                break;
 2499.   1646            case "property":
 2500.   1646                state.mode_property = true;
 2501.   1646                tenure[key] = true;
 2502.   1646                break;
 2503.   1754            }
 2504.   1754            return "";
 2505.   1754        });
 2506.     76        return the_comment;
 2507.     76    }
 2508.    666
 2509.    789    function lex_megastring() {
 2510.    789        let id;
 2511.    789        let match;
 2512.    789
 2513.    789// The token is a megastring. We don't allow any kind of mega nesting.
 2514.    789
 2515.      1        if (mode_mega) {
 2516.      1
 2517.      1// test_cause:
 2518.      1// ["`${`", "lex_megastring", "expected_a_b", "`", 4]
 2519.      1
 2520.      1            return stop_at("expected_a_b", line, column, "}", "`");
 2521.    788        }
 2522.    788        from_mega = from;
 2523.    788        line_mega = line;
 2524.    788        mode_mega = true;
 2525.    788        snippet = "";
 2526.    788
 2527.    788// Parsing a mega literal is tricky. First create a ` token.
 2528.    788
 2529.    788        token_create("`");
 2530.    788        from += 1;
 2531.    788
 2532.    788// Then loop, building up a string, possibly from many lines, until seeing
 2533.    788// the end of file, a closing `, or a ${ indicting an expression within the
 2534.    788// string.
 2535.    788
 2536.   5963        while (true) {
 2537.   5963            match = line_source.match(jslint_rgx_mega) || {
 2538.   5963                "0": "",
 2539.   5963                index: 0
 2540.   5963            };
 2541.   5963            snippet += line_source.slice(0, match.index);
 2542.   5963            column += match.index;
 2543.   5963            line_source = line_source.slice(match.index);
 2544.   5963            match = match[0];
 2545.   5963            switch (match) {
 2546.   5963            case "${":
 2547.   5963
 2548.   5963// if either ` or ${ was found, then the preceding joins the snippet to become
 2549.   5963// a string token.
 2550.   5963
 2551.   5963                token_create("(string)", snippet).quote = "`";
 2552.   5963                snippet = "";
 2553.   5963
 2554.   5963// If ${, then create tokens that will become part of an expression until
 2555.   5963// a } token is made.
 2556.   5963
 2557.   5963                column += 2;
 2558.   5963                token_create("${");
 2559.   5963                line_source = line_source.slice(2);
 2560.   5963
 2561.   5963// Lex/loop through each token inside megastring-expression `${...}`.
 2562.   5963
 2563.   5963                while (true) {
 2564.   5963                    id = lex_token().id;
 2565.   5963                    if (id === "{") {
 2566.   5963
 2567.   5963// test_cause:
 2568.   5963// ["`${{", "lex_megastring", "expected_a_b", "{", 4]
 2569.   5963
 2570.   5963                        return stop_at("expected_a_b", line, column, "}", "{");
 2571.   5963                    }
 2572.   5963                    if (id === "}") {
 2573.   5963                        break;
 2574.   5963                    }
 2575.   5963                }
 2576.   5963                break;
 2577.   5963            case "\\":
 2578.   5963                snippet += line_source.slice(0, 2);
 2579.   5963                line_source = line_source.slice(2);
 2580.   5963                column += 2;
 2581.   5963                break;
 2582.   5963            case "`":
 2583.   5963
 2584.   5963// if either ` or ${ was found, then the preceding joins the snippet to become
 2585.   5963// a string token.
 2586.   5963
 2587.   5963                token_create("(string)", snippet).quote = "`";
 2588.   5963                snippet = "";
 2589.   5963
 2590.   5963// Terminate megastring with `.
 2591.   5963
 2592.   5963                line_source = line_source.slice(1);
 2593.   5963                column += 1;
 2594.   5963                mode_mega = false;
 2595.   5963                return token_create("`");
 2596.   5963            default:
 2597.   5963
 2598.   5963// If neither ` nor ${ is seen, then the whole line joins the snippet.
 2599.   5963
 2600.   5963                snippet += line_source + "\n";
 2601.   5963                if (read_line() === undefined) {
 2602.   5963
 2603.   5963// test_cause:
 2604.   5963// ["`", "lex_megastring", "unclosed_mega", "", 1]
 2605.   5963
 2606.   5963                    return stop_at("unclosed_mega", line_mega, from_mega);
 2607.   5963                }
 2608.   5963            }
 2609.   5963        }
 2610.    789    }
 2611.    666
 2612.   8857    function lex_number() {
 2613.   8857        let prefix = snippet;
 2614.   8857
 2615.   8857// PR-390 - Add numeric-separator check.
 2616.   8857
 2617.   8857        check_numeric_separator(prefix, column - prefix.length);
 2618.   8857        char_after();
 2619.   2886        switch (prefix === "0" && char) {
 2620.      3        case "b":
 2621.      6        case "o":
 2622.     33        case "x":
 2623.     33            read_digits(char, mode_digits_numeric_separator);
 2624.     33
 2625.     33// PR-351 - Ignore BigInt suffix 'n'.
 2626.     33
 2627.     33            if (char === "n") {
 2628.     33                char_after("n");
 2629.     33            }
 2630.     33            break;
 2631.   8824        default:
 2632.   8824            if (char === ".") {
 2633.   8824                read_digits("d", mode_digits_numeric_separator);
 2634.   8824            }
 2635.   8824            if (char === "E" || char === "e") {
 2636.   8824                char_after(char);
 2637.   8824                if (char !== "+" && char !== "-") {
 2638.   8824                    char_before();
 2639.   8824                }
 2640.   8824                read_digits("d", mode_digits_numeric_separator);
 2641.   8824            }
 2642.   8857        }
 2643.   8857
 2644.   8857// If the next character after a number is a digit or letter, then something
 2645.   8857// unexpected is going on.
 2646.   8857
 2647.   8857        if (
 2648.   1573            (char >= "0" && char <= "9")
 2649.     44            || (char >= "a" && char <= "z")
 2650.   8856            || (char >= "A" && char <= "Z")
 2651.      1        ) {
 2652.      1
 2653.      1// test_cause:
 2654.      1// ["0a", "lex_number", "unexpected_a_after_b", "0", 2]
 2655.      1
 2656.      1            return stop_at(
 2657.      1                "unexpected_a_after_b",
 2658.      1                line,
 2659.      1                column,
 2660.      1                snippet.slice(-1),
 2661.      1                snippet.slice(0, -1)
 2662.      1            );
 2663.   8856        }
 2664.   8856        char_before();
 2665.   8856        return token_create("(number)", snippet);
 2666.   8856    }
 2667.    666
 2668.    583    function lex_regexp() {
 2669.    583
 2670.    583// Regexp
 2671.    583// Lex a regular expression literal.
 2672.    583
 2673.    583        let flag;
 2674.    583        let mode_regexp_multiline;
 2675.    583        let result;
 2676.    583        let value;
 2677.    583        mode_regexp = true;
 2678.    583
 2679.    209        function lex_regexp_bracketed() {
 2680.    209            let mode_regexp_range;
 2681.    209
 2682.    209// RegExp
 2683.    209// Match a class.
 2684.    209
 2685.    209            char_after("[");
 2686.     35            if (char === "^") {
 2687.     35                char_after("^");
 2688.     35            }
 2689.    902            while (true) {
 2690.    902
 2691.    902// RegExp
 2692.    902// Match a character in a character class.
 2693.    902
 2694.    902                switch (char) {
 2695.    902                case "":
 2696.    902                case "]":
 2697.    902
 2698.    902// test_cause:
 2699.    902// ["aa=/[", "lex_regexp_bracketed", "closer", "", 0]
 2700.    902// ["aa=/[]/", "lex_regexp_bracketed", "closer", "", 0]
 2701.    902
 2702.    902                    test_cause("closer");
 2703.    902                    if (mode_regexp_range) {
 2704.    902
 2705.    902// test_cause:
 2706.    902// ["aa=/[0-]/", "lex_regexp_bracketed", "unexpected_a", "-", 7]
 2707.    902
 2708.    902                        warn_at("unexpected_a", line, column - 1, "-");
 2709.    902                    }
 2710.    902                    return char_after("]");
 2711.    902
 2712.    902// PR-362 - Relax regexp-warning against using <space>.
 2713.    902//
 2714.    902//                 case " ":
 2715.    902//
 2716.    902// // test_cause:
 2717.    902// // ["aa=/[ ]/", "lex_regexp_bracketed", "expected_a_b", " ", 6]
 2718.    902//
 2719.    902//                     warn_at("expected_a_b", line, column, "\\u0020", " ");
 2720.    902//                     break;
 2721.    902
 2722.    902                case "-":
 2723.    902                case "/":
 2724.    902                case "[":
 2725.    902                case "^":
 2726.    902
 2727.    902// test_cause:
 2728.    902// ["aa=/[-]/", "lex_regexp_bracketed", "expected_a_before_b", "-", 6]
 2729.    902// ["aa=/[.^]/", "lex_regexp_bracketed", "expected_a_before_b", "^", 7]
 2730.    902// ["aa=/[/", "lex_regexp_bracketed", "expected_a_before_b", "/", 6]
 2731.    902// ["aa=/[\\\\/]/", "lex_regexp_bracketed", "expected_a_before_b", "/", 8]
 2732.    902// ["aa=/[\\\\[]/", "lex_regexp_bracketed", "expected_a_before_b", "[", 8]
 2733.    902
 2734.    902                    warn_at("expected_a_before_b", line, column, "\\", char);
 2735.    902                    break;
 2736.    902                case "\\":
 2737.    902                    char_after_escape("BbDdSsWw-[]^");
 2738.    902                    char_before();
 2739.    902                    break;
 2740.    902                case "`":
 2741.    902                    if (mode_mega) {
 2742.    902
 2743.    902// test_cause:
 2744.    902// ["`${/[`]/}`", "lex_regexp_bracketed", "unexpected_a", "`", 6]
 2745.    902
 2746.    902                        warn_at("unexpected_a", line, column, "`");
 2747.    902                    }
 2748.    902                    break;
 2749.    902                }
 2750.    902                char_after();
 2751.    902                mode_regexp_range = false;
 2752.    902                if (char === "-") {
 2753.    902
 2754.    902// RegExp
 2755.    902// Match a range of subclasses.
 2756.    902
 2757.    902                    mode_regexp_range = true;
 2758.    902                    char_after("-");
 2759.    902                }
 2760.    902            }
 2761.    209        }
 2762.    583
 2763.    793        function lex_regexp_group() {
 2764.    793
 2765.    793// RegExp
 2766.    793// Lex sequence of characters in regexp.
 2767.    793
 2768.    793            switch (char) {
 2769.      1            case "":
 2770.      1                warn_at("expected_regexp_factor_a", line, column, char);
 2771.      1                break;
 2772.      1            case ")":
 2773.      1                warn_at("expected_regexp_factor_a", line, column, char);
 2774.      1                break;
 2775.      1            case "]":
 2776.      1
 2777.      1// test_cause:
 2778.      1// ["/ /", "lex_regexp_group", "expected_regexp_factor_a", "", 3]
 2779.      1// ["aa=/)", "lex_regexp_group", "expected_regexp_factor_a", ")", 5]
 2780.      1// ["aa=/]", "lex_regexp_group", "expected_regexp_factor_a", "]", 5]
 2781.      1
 2782.      1                warn_at("expected_regexp_factor_a", line, column, char);
 2783.      1                break;
 2784.    793            }
 2785.   5584            while (true) {
 2786.   5584                switch (char) {
 2787.   5584                case "":
 2788.   5584                case ")":
 2789.   5584                case "/":
 2790.   5584                case "]":
 2791.   5584                    return;
 2792.   5584
 2793.   5584// PR-362 - Relax regexp-warning against using <space>.
 2794.   5584//
 2795.   5584//                 case " ":
 2796.   5584//
 2797.   5584// // test_cause:
 2798.   5584// // ["aa=/ /", "lex_regexp_group", "expected_a_b", " ", 5]
 2799.   5584//
 2800.   5584//                     warn_at("expected_a_b", line, column, "\\s", " ");
 2801.   5584//                     char_after();
 2802.   5584//                     break;
 2803.   5584
 2804.   5584                case "$":
 2805.   5584                    if (line_source[0] !== "/") {
 2806.   5584                        mode_regexp_multiline = true;
 2807.   5584                    }
 2808.   5584                    char_after();
 2809.   5584                    break;
 2810.   5584                case "(":
 2811.   5584
 2812.   5584// RegExp
 2813.   5584// Match a group that starts with left paren.
 2814.   5584
 2815.   5584                    char_after("(");
 2816.   5584                    switch (char) {
 2817.   5584                    case ":":
 2818.   5584
 2819.   5584// test_cause:
 2820.   5584// ["aa=/(:)/", "lex_regexp_group", "expected_a_before_b", ":", 6]
 2821.   5584// ["aa=/?/", "lex_regexp_group", "expected_a_before_b", "?", 5]
 2822.   5584
 2823.   5584                        warn_at("expected_a_before_b", line, column, "?", ":");
 2824.   5584                        break;
 2825.   5584                    case "?":
 2826.   5584                        char_after("?");
 2827.   5584                        switch (char) {
 2828.   5584                        case "!":
 2829.   5584
 2830.   5584// PR-437 - Add grammar for regexp-named-capture-group.
 2831.   5584
 2832.   5584                        case "<":
 2833.   5584                        case "=":
 2834.   5584                            char_after();
 2835.   5584                            break;
 2836.   5584                        default:
 2837.   5584                            char_after(":");
 2838.   5584                        }
 2839.   5584                        break;
 2840.   5584                    }
 2841.   5584
 2842.   5584// RegExp
 2843.   5584// Recurse lex_regexp_group().
 2844.   5584
 2845.   5584                    lex_regexp_group();
 2846.   5584                    char_after(")");
 2847.   5584                    break;
 2848.   5584                case "*":
 2849.   5584                case "+":
 2850.   5584                case "?":
 2851.   5584                case "{":
 2852.   5584                case "}":
 2853.   5584
 2854.   5584// test_cause:
 2855.   5584// ["aa=/+/", "lex_regexp_group", "expected_a_before_b", "+", 5]
 2856.   5584// ["aa=/.**/", "lex_regexp_group", "expected_a_before_b", "*", 7]
 2857.   5584// ["aa=/?/", "lex_regexp_group", "expected_a_before_b", "?", 5]
 2858.   5584// ["aa=/{/", "lex_regexp_group", "expected_a_before_b", "{", 5]
 2859.   5584// ["aa=/}/", "lex_regexp_group", "expected_a_before_b", "}", 5]
 2860.   5584
 2861.   5584                    warn_at("expected_a_before_b", line, column, "\\", char);
 2862.   5584                    char_after();
 2863.   5584                    break;
 2864.   5584                case "[":
 2865.   5584                    lex_regexp_bracketed();
 2866.   5584                    break;
 2867.   5584                case "\\":
 2868.   5584
 2869.   5584// test_cause:
 2870.   5584// ["aa=/\\/", "lex_regexp_group", "escape", "", 0]
 2871.   5584
 2872.   5584                    test_cause("escape");
 2873.   5584
 2874.   5584// PR-437 - Add grammar for regexp-named-backreference.
 2875.   5584
 2876.   5584                    char_after_escape("BbDdSsWw^${}[]():=!.|*+?k");
 2877.   5584                    break;
 2878.   5584                case "^":
 2879.   5584                    if (snippet !== "^") {
 2880.   5584                        mode_regexp_multiline = true;
 2881.   5584                    }
 2882.   5584                    char_after();
 2883.   5584                    break;
 2884.   5584                case "`":
 2885.   5584                    if (mode_mega) {
 2886.   5584
 2887.   5584// test_cause:
 2888.   5584// ["`${/`/}`", "lex_regexp_group", "unexpected_a", "`", 5]
 2889.   5584
 2890.   5584                        warn_at("unexpected_a", line, column, "`");
 2891.   5584                    }
 2892.   5584                    char_after();
 2893.   5584                    break;
 2894.   5584                default:
 2895.   5584                    char_after();
 2896.   5584                }
 2897.   5584
 2898.   5584// RegExp
 2899.   5584// Match an optional quantifier.
 2900.   5584
 2901.   5584                switch (char) {
 2902.   5584                case "*":
 2903.   5584                case "+":
 2904.   5584                    if (char_after(char) === "?") {
 2905.   5584
 2906.   5584// test_cause:
 2907.   5584// ["aa=/.*?/", "lex_regexp_group", "?", "", 0]
 2908.   5584// ["aa=/.+?/", "lex_regexp_group", "?", "", 0]
 2909.   5584
 2910.   5584                        test_cause("?");
 2911.   5584                        char_after("?");
 2912.   5584                    }
 2913.   5584                    break;
 2914.   5584                case "?":
 2915.   5584                    if (char_after("?") === "?") {
 2916.   5584
 2917.   5584// test_cause:
 2918.   5584// ["aa=/.??/", "lex_regexp_group", "unexpected_a", "?", 7]
 2919.   5584
 2920.   5584                        warn_at("unexpected_a", line, column, char);
 2921.   5584                        char_after("?");
 2922.   5584                    }
 2923.   5584                    break;
 2924.   5584                case "{":
 2925.   5584                    if (read_digits("d", mode_digits_empty_string) === 0) {
 2926.   5584
 2927.   5584// test_cause:
 2928.   5584// ["aa=/aa{/", "lex_regexp_group", "expected_a_before_b", ",", 8]
 2929.   5584
 2930.   5584                        warn_at("expected_a_before_b", line, column, "0", ",");
 2931.   5584                    }
 2932.   5584                    if (char === ",") {
 2933.   5584
 2934.   5584// test_cause:
 2935.   5584// ["aa=/.{,/", "lex_regexp_group", "comma", "", 0]
 2936.   5584
 2937.   5584                        test_cause("comma");
 2938.   5584                        read_digits("d", mode_digits_empty_string);
 2939.   5584                    }
 2940.   5584                    if (char_after("}") === "?") {
 2941.   5584
 2942.   5584// test_cause:
 2943.   5584// ["aa=/.{0}?/", "lex_regexp_group", "unexpected_a", "?", 9]
 2944.   5584
 2945.   5584                        warn_at("unexpected_a", line, column, char);
 2946.   5584                        char_after("?");
 2947.   5584                    }
 2948.   5584                    break;
 2949.   5584                }
 2950.   5584            }
 2951.    793        }
 2952.    583
 2953.    583// RegExp
 2954.    583// Scan the regexp literal. Give a warning if the first character is = because
 2955.    583// /= looks like a division assignment operator.
 2956.    583
 2957.    583        snippet = "";
 2958.    583        char_after();
 2959.      1        if (char === "=") {
 2960.      1
 2961.      1// test_cause:
 2962.      1// ["aa=/=/", "lex_regexp", "expected_a_before_b", "=", 5]
 2963.      1
 2964.      1            warn_at("expected_a_before_b", line, column, "\\", "=");
 2965.      1        }
 2966.    583        lex_regexp_group();
 2967.    583
 2968.    583// RegExp
 2969.    583// Remove last character from snippet.
 2970.    583
 2971.    583        snippet = snippet.slice(0, -1);
 2972.    583
 2973.    583// RegExp
 2974.    583// Make sure there is a closing slash.
 2975.    583
 2976.    583        value = snippet;
 2977.    583        char_after("/");
 2978.    583
 2979.    583// RegExp
 2980.    583// Create flag.
 2981.    583
 2982.    583        flag = empty();
 2983.    583        while (
 2984.    583
 2985.    583// Regexp
 2986.    583// char is a letter.
 2987.    583
 2988.    511            (char >= "a" && char <= "z\uffff")
 2989.    573            || (char >= "A" && char <= "Z\uffff")
 2990.    509        ) {
 2991.    509
 2992.    509// RegExp
 2993.    509// Process dangling flag letters.
 2994.    509
 2995.    509            switch (!flag[char] && char) {
 2996.    509            case "g":
 2997.    509                break;
 2998.    509            case "i":
 2999.    509                break;
 3000.    509            case "m":
 3001.    509                break;
 3002.    509            case "u":
 3003.    509                break;
 3004.    509            case "y":
 3005.    509
 3006.    509// test_cause:
 3007.    509// ["aa=/./gimuy", "lex_regexp", "flag", "", 0]
 3008.    509
 3009.    509                test_cause("flag");
 3010.    509                break;
 3011.    509            default:
 3012.    509
 3013.    509// test_cause:
 3014.    509// ["aa=/./gg", "lex_regexp", "unexpected_a", "g", 8]
 3015.    509// ["aa=/./z", "lex_regexp", "unexpected_a", "z", 7]
 3016.    509
 3017.    509                warn_at("unexpected_a", line, column, char);
 3018.    509            }
 3019.    509            flag[char] = true;
 3020.    509            char_after();
 3021.    573        }
 3022.    573        char_before();
 3023.    573        if (char === "/" || char === "*") {
 3024.      1
 3025.      1// test_cause:
 3026.      1// ["aa=/.//", "lex_regexp", "unexpected_a", "/", 3]
 3027.      1
 3028.      1            return stop_at("unexpected_a", line, from, char);
 3029.    572        }
 3030.    572        result = token_create("(regexp)", char);
 3031.    572        result.flag = flag;
 3032.    572        result.value = value;
 3033.    572        if (mode_regexp_multiline && !flag.m) {
 3034.      1
 3035.      1// test_cause:
 3036.      1// ["aa=/$^/", "lex_regexp", "missing_m", "", 7]
 3037.      1
 3038.      1            warn_at("missing_m", line, column);
 3039.    572        }
 3040.    572        return result;
 3041.    572    }
 3042.    666
 3043.    598    function lex_slash_or_regexp() {
 3044.    598
 3045.    598// The / can be a division operator or the beginning of a regular expression
 3046.    598// literal. It is not possible to know which without doing a complete parse.
 3047.    598// We want to complete the tokenization before we begin to parse, so we will
 3048.    598// estimate. This estimator can fail in some cases. For example, it cannot
 3049.    598// know if "}" is ending a block or ending an object literal, so it can
 3050.    598// behave incorrectly in that case; it is not meaningful to divide an
 3051.    598// object, so it is likely that we can get away with it. We avoided the worst
 3052.    598// cases by eliminating automatic semicolon insertion.
 3053.    598
 3054.    598        let the_token;
 3055.    598        switch (
 3056.    598            token_prv_expr.identifier
 3057.     18            && !token_prv_expr.dot
 3058.     15            && token_prv_expr.id
 3059.    598        ) {
 3060.      1        case "case":
 3061.      2        case "delete":
 3062.      3        case "in":
 3063.      4        case "instanceof":
 3064.      5        case "new":
 3065.      6        case "typeof":
 3066.      7        case "void":
 3067.      8        case "yield":
 3068.      8            the_token = lex_regexp();
 3069.      8
 3070.      8// test_cause:
 3071.      8// ["case /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
 3072.      8// ["delete /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
 3073.      8// ["in /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 4]
 3074.      8// ["instanceof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 12]
 3075.      8// ["new /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 5]
 3076.      8// ["typeof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
 3077.      8// ["void /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
 3078.      8// ["yield /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 7]
 3079.      8
 3080.      8            return stop("unexpected_a", the_token);
 3081.      1        case "return":
 3082.      1            return lex_regexp();
 3083.    589        }
 3084.    589        switch (!token_prv_expr.identifier && token_prv_expr.id.slice(-1)) {
 3085.      1        case "!":
 3086.      2        case "%":
 3087.      4        case "&":
 3088.      5        case "*":
 3089.      6        case "+":
 3090.      7        case "-":
 3091.      9        case "/":
 3092.     10        case ";":
 3093.     11        case "<":
 3094.     12        case ">":
 3095.     13        case "^":
 3096.     16        case "{":
 3097.     17        case "|":
 3098.     18        case "}":
 3099.     19        case "~":
 3100.     19            the_token = lex_regexp();
 3101.     19
 3102.     19// test_cause:
 3103.     19// ["!/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3104.     19// ["%/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3105.     19// ["&/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3106.     19// ["+/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3107.     19// ["-/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3108.     19// ["0 * /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
 3109.     19// ["0 / /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
 3110.     19// [";/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3111.     19// ["</./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3112.     19// [">/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3113.     19// ["^/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3114.     19// ["{/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3115.     19// ["|/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3116.     19// ["}/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3117.     19// ["~/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 3118.     19
 3119.     19            warn("wrap_regexp", the_token);
 3120.     19            return the_token;
 3121.    514        case "(":
 3122.    515        case ",":
 3123.    516        case ":":
 3124.    553        case "=":
 3125.    554        case "?":
 3126.    555        case "[":
 3127.    555
 3128.    555// test_cause:
 3129.    555// ["(/./", "lex_slash_or_regexp", "recurse", "", 0]
 3130.    555// [",/./", "lex_slash_or_regexp", "recurse", "", 0]
 3131.    555// [":/./", "lex_slash_or_regexp", "recurse", "", 0]
 3132.    555// ["=/./", "lex_slash_or_regexp", "recurse", "", 0]
 3133.    555// ["?/./", "lex_slash_or_regexp", "recurse", "", 0]
 3134.    555// ["aa[/./", "lex_slash_or_regexp", "recurse", "", 0]
 3135.    555
 3136.    555            test_cause("recurse");
 3137.    555            return lex_regexp();
 3138.     15        }
 3139.     15        if (line_source[0] === "=") {
 3140.      1            column += 1;
 3141.      1            line_source = line_source.slice(1);
 3142.      1            snippet = "/=";
 3143.      1            warn_at("unexpected_a", line, column, "/=");
 3144.     15        }
 3145.     15        return token_create(snippet);
 3146.     15    }
 3147.    666
 3148.  24308    function lex_string(quote) {
 3149.  24308
 3150.  24308// Create a string token.
 3151.  24308
 3152.  24308        let the_token;
 3153.  24306        if (!option_dict.single && quote === "'") {
 3154.      2
 3155.      2// test_cause:
 3156.      2// ["''", "lex_string", "use_double", "", 1]
 3157.      2
 3158.      2            warn_at("use_double", line, column);
 3159.      2        }
 3160.  24308        snippet = "";
 3161.  24308        char_after();
 3162.  24308
 3163.  24308// Lex/loop through each character in "...".
 3164.  24308
 3165. 216882        while (true) {
 3166. 216882            switch (char) {
 3167. 216882            case "":
 3168. 216882
 3169. 216882// test_cause:
 3170. 216882// ["\"", "lex_string", "unclosed_string", "", 1]
 3171. 216882
 3172. 216882                return stop_at("unclosed_string", line, column);
 3173. 216882            case "\\":
 3174. 216882                char_after_escape(quote);
 3175. 216882                break;
 3176. 216882            case "`":
 3177. 216882                if (mode_mega) {
 3178. 216882
 3179. 216882// test_cause:
 3180. 216882// ["`${\"`\"}`", "lex_string", "unexpected_a", "`", 5]
 3181. 216882
 3182. 216882                    warn_at("unexpected_a", line, column, "`");
 3183. 216882                }
 3184. 216882                char_after("`");
 3185. 216882                break;
 3186. 216882            case quote:
 3187. 216882
 3188. 216882// Remove last character from snippet.
 3189. 216882
 3190. 216882                snippet = snippet.slice(0, -1);
 3191. 216882                the_token = token_create("(string)", snippet);
 3192. 216882                the_token.quote = quote;
 3193. 216882                return the_token;
 3194. 216882            default:
 3195. 216882                char_after();
 3196. 216882            }
 3197. 216882        }
 3198.  24308    }
 3199.    666
 3200. 251943    function lex_token() {
 3201. 251943        let match;
 3202. 251943
 3203. 251943// Lex/loop through each whitespace.
 3204. 251943
 3205. 375587        while (true) {
 3206. 375587
 3207. 375587// Lex/loop through each blank-line.
 3208. 375587
 3209. 375587            while (!line_source) {
 3210. 375587                line_source = read_line();
 3211. 375587                from = 0;
 3212. 375587                if (line_source === undefined) {
 3213. 375587                    return (
 3214. 375587                        mode_mega
 3215. 375587
 3216. 375587// test_cause:
 3217. 375587// ["`${//}`", "lex_token", "unclosed_mega", "", 1]
 3218. 375587
 3219. 375587                        ? stop_at("unclosed_mega", line_mega, from_mega)
 3220. 375587                        : line_disable !== undefined
 3221. 375587
 3222. 375587// test_cause:
 3223. 375587// ["/*jslint-disable*/", "lex_token", "unclosed_disable", "", 1]
 3224. 375587
 3225. 375587                        ? stop_at("unclosed_disable", line_disable)
 3226. 375587                        : token_create("(end)")
 3227. 375587                    );
 3228. 375587                }
 3229. 375587            }
 3230. 375587            from = column;
 3231. 375587            match = line_source.match(jslint_rgx_token);
 3232. 375587
 3233. 375587// match[1] token
 3234. 375587// match[2] whitespace
 3235. 375587// match[3] identifier
 3236. 375587// match[4] number
 3237. 375587// match[5] rest
 3238. 375587
 3239. 375587            if (!match) {
 3240. 375587
 3241. 375587// test_cause:
 3242. 375587// ["#", "lex_token", "unexpected_char_a", "#", 1]
 3243. 375587
 3244. 375587                return stop_at(
 3245. 375587                    "unexpected_char_a",
 3246. 375587                    line,
 3247. 375587                    column,
 3248. 375587                    line_source[0]
 3249. 375587                );
 3250. 375587            }
 3251. 375587            snippet = match[1];
 3252. 375587            column += snippet.length;
 3253. 375587            line_source = match[5];
 3254. 375587            if (!match[2]) {
 3255. 375587                break;
 3256. 375587            }
 3257. 375587        }
 3258. 251302
 3259. 251302// The token is an identifier.
 3260. 251302
 3261. 251302        if (match[3]) {
 3262.  67598            return token_create(snippet, undefined, true);
 3263. 183704        }
 3264. 183704
 3265. 183704// Create token from number.
 3266. 183704
 3267. 183704        if (match[4]) {
 3268.   8857            return lex_number();
 3269. 174847        }
 3270. 174847
 3271. 174847// Create token from string "..." or '...'.
 3272. 174847
 3273. 174847        if (snippet === "\"" || snippet === "'") {
 3274.  24308            return lex_string(snippet);
 3275. 150539        }
 3276. 150539
 3277. 150539// Create token from megastring `...`.
 3278. 150539
 3279. 150539        if (snippet === "`") {
 3280.    789            return lex_megastring();
 3281. 149750        }
 3282. 149750
 3283. 149750// Create token from comment /*...*/ or //....
 3284. 149750
 3285. 149750        if (snippet === "/*" || snippet === "//") {
 3286.  11181            return lex_comment();
 3287. 138569        }
 3288. 138569
 3289. 138569// Create token from slash /.
 3290. 138569
 3291. 138569        if (snippet === "/") {
 3292.    598            return lex_slash_or_regexp();
 3293. 137971        }
 3294. 137971        return token_create(snippet);
 3295. 137971    }
 3296.    666
 3297.   2659    function option_set_item(key, val) {
 3298.   2659
 3299.   2659// These are the options that are recognized in the option object or that may
 3300.   2659// appear in a /*jslint*/ directive. Most options will have a boolean value,
 3301.   2659// usually true. Some options will also predefine some number of global
 3302.   2659// variables.
 3303.   2659
 3304.   2659        switch (key) {
 3305.    657        case "beta":            // Enable experimental warnings.
 3306.    659        case "bitwise":         // Allow bitwise operator.
 3307.    666        case "browser":         // Assume browser environment.
 3308.    668        case "convert":         // Allow conversion operator.
 3309.    670        case "couch":           // Assume CouchDb environment.
 3310.    676        case "devel":           // Allow console.log() and friends.
 3311.   2008        case "ecma":            // Assume ECMAScript environment.
 3312.   2014        case "eval":            // Allow eval().
 3313.   2018        case "fart":            // Allow complex fat-arrow.
 3314.   2023        case "for":             // Allow for-statement.
 3315.   2029        case "getset":          // Allow get() and set().
 3316.   2034        case "indent2":         // Use 2-space indent.
 3317.   2036        case "long":            // Allow long lines.
 3318.   2083        case "node":            // Assume Node.js environment.
 3319.   2087        case "nomen":           // Allow weird property name.
 3320.   2089        case "single":          // Allow single-quote strings.
 3321.   2091        case "subscript":       // Allow identifier in subscript-notation.
 3322.   2594        case "test_cause":      // Test jslint's causes.
 3323.   2596        case "test_internal_error":     // Test jslint's internal-error
 3324.   2659                                        // ... handling-ability.
 3325.   2598        case "this":            // Allow 'this'.
 3326.   2601        case "trace":           // Include jslint stack-trace in warnings.
 3327.   2605        case "unordered":       // Allow unordered cases, params, properties,
 3328.   2659                                // ... variables, and exports.
 3329.   2609        case "variable":        // Allow unordered const and let declarations
 3330.   2659                                // ... that are not at top of function-scope.
 3331.   2611        case "white":           // Allow messy whitespace.
 3332.   2611            option_dict[key] = val;
 3333.   2611            break;
 3334.   2659
 3335.   2659// PR-404 - Alias "evil" to jslint-directive "eval" for backwards-compat.
 3336.   2659
 3337.      2        case "evil":
 3338.      2            return option_set_item("eval", val);
 3339.   2659
 3340.   2659// PR-404 - Alias "nomen" to jslint-directive "name" for backwards-compat.
 3341.   2659
 3342.      2        case "name":
 3343.      2            return option_set_item("nomen", val);
 3344.     44        default:
 3345.     44            return false;
 3346.   2611        }
 3347.   2611
 3348.   2611// Initialize global-variables.
 3349.   2611
 3350.   2611        switch (val && key) {
 3351.   2659
 3352.   2659// Assign global browser variables to global_dict.
 3353.   2659/*
 3354.   2659// /\*jslint beta, browser, devel*\/
 3355.   2659console.log(JSON.stringify(Object.keys(window).sort(), undefined, 4));
 3356.   2659*/
 3357.   2659
 3358.      6        case "browser":
 3359.      6            object_assign_from_list(global_dict, [
 3360.      6
 3361.      6// Shared with Node.js.
 3362.      6
 3363.      6                "AbortController",
 3364.      6                // "Buffer",
 3365.      6                // "Crypto",
 3366.      6                // "CryptoKey",
 3367.      6                "Event",
 3368.      6                "EventTarget",
 3369.      6                "MessageChannel",
 3370.      6                "MessageEvent",
 3371.      6                "MessagePort",
 3372.      6                // "Request",
 3373.      6                // "Response",
 3374.      6                // "SubtleCrypto",
 3375.      6                "TextDecoder",
 3376.      6                "TextEncoder",
 3377.      6                "URL",
 3378.      6                "URLSearchParams",
 3379.      6                "WebAssembly",
 3380.      6                // "__dirname",
 3381.      6                // "__filename",
 3382.      6                // "atob",
 3383.      6                // "btoa",
 3384.      6                // "clearImmediate",
 3385.      6                "clearInterval",
 3386.      6                "clearTimeout",
 3387.      6                // "console",
 3388.      6                // "crypto",
 3389.      6                // "exports",
 3390.      6                // "fetch",
 3391.      6                // "global",
 3392.      6                // "module",
 3393.      6                "performance",
 3394.      6                // "process",
 3395.      6                "queueMicrotask",
 3396.      6                // "require",
 3397.      6                // "setImmediate",
 3398.      6                "setInterval",
 3399.      6                "setTimeout",
 3400.      6
 3401.      6// Web worker only.
 3402.      6// https://github.com/mdn/content/blob/main/files/en-us/web/api
 3403.      6// /workerglobalscope/index.md
 3404.      6
 3405.      6                "importScripts",
 3406.      6
 3407.      6// Window.
 3408.      6
 3409.      6                "Blob",
 3410.      6                // "CharacterData",
 3411.      6                // "DocumentType",
 3412.      6                // "Element",
 3413.      6                // "Event",
 3414.      6                "FileReader",
 3415.      6                // "FontFace",
 3416.      6                "FormData",
 3417.      6                "IntersectionObserver",
 3418.      6                "MutationObserver",
 3419.      6                // "Storage",
 3420.      6                // "TextDecoder",
 3421.      6                // "TextEncoder",
 3422.      6                // "URL",
 3423.      6                "Worker",
 3424.      6                "XMLHttpRequest",
 3425.      6                // "caches",
 3426.      6                // "clearInterval",
 3427.      6                // "clearTimeout",
 3428.      6                "document",
 3429.      6                // "event",
 3430.      6                "fetch",
 3431.      6                // "history",
 3432.      6                "indexedDb",
 3433.      6                "localStorage",
 3434.      6                "location",
 3435.      6                // "name",
 3436.      6                "navigator",
 3437.      6                "postMessage",
 3438.      6                // "screen",
 3439.      6                "sessionStorage",
 3440.      6                // "setInterval",
 3441.      6                // "setTimeout",
 3442.      6                "structuredClone",
 3443.      6                "window"
 3444.      6            ], "browser");
 3445.      6            break;
 3446.   2659
 3447.   2659// https://docs.couchdb.org/en/stable/query-server/javascript.html#javascript
 3448.   2659
 3449.      2        case "couch":
 3450.      2            object_assign_from_list(global_dict, [
 3451.      2                "emit",
 3452.      2                "getRow",
 3453.      2                "isArray",
 3454.      2                "log",
 3455.      2                "provides",
 3456.      2                "registerType",
 3457.      2                "require",
 3458.      2                "send",
 3459.      2                "start",
 3460.      2                "sum",
 3461.      2                "toJSON"
 3462.      2            ], "CouchDb");
 3463.      2            break;
 3464.      6        case "devel":
 3465.      6            object_assign_from_list(global_dict, [
 3466.      6                "alert", "confirm", "console", "prompt"
 3467.      6            ], "development");
 3468.      6            break;
 3469.   2659
 3470.   2659// These are the globals that are provided by the language standard.
 3471.   2659// Assign global ECMAScript variables to global_dict.
 3472.   2659/*
 3473.   2659node --input-type=module --eval '
 3474.   2659// /\*jslint beta, node*\/
 3475.   2659import https from "https";
 3476.   2659(async function () {
 3477.   2659    let dict = {import: true};
 3478.   2659    let result = "";
 3479.   2659    await new Promise(function (resolve) {
 3480.   2659        https.get((
 3481.   2659            "https://raw.githubusercontent.com/mdn/content/main/files"
 3482.   2659            + "/en-us/web/javascript/reference/global_objects/index.md"
 3483.   2659        ), function (res) {
 3484.   2659            res.on("data", function (chunk) {
 3485.   2659                result += chunk;
 3486.   2659            }).on("end", resolve).setEncoding("utf8");
 3487.   2659        });
 3488.   2659    });
 3489.   2659    result.replace((
 3490.   2659        /\n- \{\{JSxRef\("(?:Global_Objects\/)?([^"\/]+?)"/g
 3491.   2659    ), function (ignore, key) {
 3492.   2659        if (globalThis.hasOwnProperty(key)) {
 3493.   2659            dict[key] = true;
 3494.   2659        }
 3495.   2659        return "";
 3496.   2659    });
 3497.   2659    console.log(JSON.stringify(Object.keys(dict).sort(), undefined, 4));
 3498.   2659}());
 3499.   2659'
 3500.   2659*/
 3501.   2659
 3502.   1332        case "ecma":
 3503.   1332            object_assign_from_list(global_dict, [
 3504.   1332                "AggregateError",
 3505.   1332                "Array",
 3506.   1332                "ArrayBuffer",
 3507.   1332                "Atomics",
 3508.   1332                "BigInt",
 3509.   1332                "BigInt64Array",
 3510.   1332                "BigUint64Array",
 3511.   1332                "Boolean",
 3512.   1332                "DataView",
 3513.   1332                "Date",
 3514.   1332                "Error",
 3515.   1332                "EvalError",
 3516.   1332                "Float32Array",
 3517.   1332                "Float64Array",
 3518.   1332                "Function",
 3519.   1332                "Infinity",
 3520.   1332                "Int16Array",
 3521.   1332                "Int32Array",
 3522.   1332                "Int8Array",
 3523.   1332                "Intl",
 3524.   1332                "JSON",
 3525.   1332                "Map",
 3526.   1332                "Math",
 3527.   1332                "NaN",
 3528.   1332                "Number",
 3529.   1332                "Object",
 3530.   1332                "Promise",
 3531.   1332                "Proxy",
 3532.   1332                "RangeError",
 3533.   1332                "ReferenceError",
 3534.   1332                "Reflect",
 3535.   1332                "RegExp",
 3536.   1332                "Set",
 3537.   1332                "SharedArrayBuffer",
 3538.   1332                "String",
 3539.   1332                "Symbol",
 3540.   1332                "SyntaxError",
 3541.   1332                "TypeError",
 3542.   1332                "URIError",
 3543.   1332                "Uint16Array",
 3544.   1332                "Uint32Array",
 3545.   1332                "Uint8Array",
 3546.   1332                "Uint8ClampedArray",
 3547.   1332                "WeakMap",
 3548.   1332                "WeakSet",
 3549.   1332                "WebAssembly",
 3550.   1332                "decodeURI",
 3551.   1332                "decodeURIComponent",
 3552.   1332                "encodeURI",
 3553.   1332                "encodeURIComponent",
 3554.   1332                "eval",
 3555.   1332                "globalThis",
 3556.   1332                "import",
 3557.   1332                "isFinite",
 3558.   1332                "isNaN",
 3559.   1332                "parseFloat",
 3560.   1332                "parseInt",
 3561.   1332                "undefined"
 3562.   1332            ], "ECMAScript");
 3563.   1332            break;
 3564.   2659
 3565.   2659// Assign global Node.js variables to global_dict.
 3566.   2659/*
 3567.   2659node --input-type=module --eval '
 3568.   2659// /\*jslint beta, node*\/
 3569.   2659import moduleHttps from "https";
 3570.   2659(async function () {
 3571.   2659    let dict = Object.create(null);
 3572.   2659    let result = "";
 3573.   2659    await new Promise(function (resolve) {
 3574.   2659        moduleHttps.get((
 3575.   2659            "https://raw.githubusercontent.com/nodejs/node/v16.x/doc/api"
 3576.   2659            + "/globals.md"
 3577.   2659        ), function (res) {
 3578.   2659            res.on("data", function (chunk) {
 3579.   2659                result += chunk;
 3580.   2659            }).on("end", resolve).setEncoding("utf8");
 3581.   2659        });
 3582.   2659    });
 3583.   2659    result.replace((
 3584.   2659        /\n(?:\* \[`|## |## Class: )`\w+/g
 3585.   2659    ), function (match0) {
 3586.   2659        dict[match0.split("`")[1]] = true;
 3587.   2659        return "";
 3588.   2659    });
 3589.   2659    console.log(JSON.stringify(Object.keys(dict).sort(), undefined, 4));
 3590.   2659}());
 3591.   2659'
 3592.   2659*/
 3593.   2659
 3594.     47        case "node":
 3595.     47            object_assign_from_list(global_dict, [
 3596.     47                "AbortController",
 3597.     47                "Buffer",
 3598.     47                // "Crypto",
 3599.     47                // "CryptoKey",
 3600.     47                "Event",
 3601.     47                "EventTarget",
 3602.     47                "MessageChannel",
 3603.     47                "MessageEvent",
 3604.     47                "MessagePort",
 3605.     47                // "Request",
 3606.     47                // "Response",
 3607.     47                // "SubtleCrypto",
 3608.     47                "TextDecoder",
 3609.     47                "TextEncoder",
 3610.     47                "URL",
 3611.     47                "URLSearchParams",
 3612.     47                "WebAssembly",
 3613.     47                "__dirname",
 3614.     47                "__filename",
 3615.     47                // "atob",
 3616.     47                // "btoa",
 3617.     47                "clearImmediate",
 3618.     47                "clearInterval",
 3619.     47                "clearTimeout",
 3620.     47                "console",
 3621.     47                // "crypto",
 3622.     47                "exports",
 3623.     47                // "fetch",
 3624.     47                "global",
 3625.     47                "module",
 3626.     47                "performance",
 3627.     47                "process",
 3628.     47                "queueMicrotask",
 3629.     47                "require",
 3630.     47                "setImmediate",
 3631.     47                "setInterval",
 3632.     47                "setTimeout"
 3633.     47            ], "Node.js");
 3634.     47            break;
 3635.   2611        }
 3636.   2611        return true;
 3637.   2611    }
 3638.    666
 3639.    469    function read_digits(base, mode) {
 3640.    469        let digits = line_source.match(
 3641.    469            base === "b"
 3642.      3            ? jslint_rgx_digits_bits
 3643.    466            : base === "o"
 3644.    466            ? jslint_rgx_digits_octals
 3645.    466            : base === "x"
 3646.    466            ? jslint_rgx_digits_hexs
 3647.    466            : jslint_rgx_digits_decimals
 3648.    469        )[0];
 3649.    469        if (
 3650.     77            (mode !== mode_digits_empty_string && digits.length === 0)
 3651.    468            || digits[0] === "_"
 3652.      2        ) {
 3653.      2
 3654.      2// test_cause:
 3655.      2// ["0x", "read_digits", "expected_digits_after_a", "0x", 2]
 3656.      2// ["0x_", "read_digits", "expected_digits_after_a", "0x", 2]
 3657.      2
 3658.      2            warn_at("expected_digits_after_a", line, column, snippet);
 3659.      2        }
 3660.    469
 3661.    469// PR-390 - Add numeric-separator check.
 3662.    469
 3663.     73        if (mode === mode_digits_numeric_separator) {
 3664.     73            check_numeric_separator(digits, column);
 3665.    396        } else if (digits.indexOf("_") >= 0) {
 3666.    396
 3667.    396// test_cause:
 3668.    396// ["\"\\u{1_2}\"", "read_digits", "illegal_num_separator", "", 6]
 3669.    396
 3670.    396            warn_at(
 3671.    396                "illegal_num_separator",
 3672.    396                line,
 3673.    396                column + digits.indexOf("_") + 1
 3674.    396            );
 3675.    396        }
 3676.    469        column += digits.length;
 3677.    469        line_source = line_source.slice(digits.length);
 3678.    469        snippet += digits;
 3679.    469        char_after();
 3680.    469        return digits.length;
 3681.    469    }
 3682.    666
 3683. 105181    function read_line() {
 3684. 105181
 3685. 105181// Put the next line of source in line_source. If the line contains tabs,
 3686. 105181// replace them with spaces and give a warning. Also warn if the line contains
 3687. 105181// unsafe characters or is too damn long.
 3688. 105181
 3689. 105181        if (
 3690. 105181            !option_dict.long
 3691. 105177            && line_whole.length > 80
 3692.     56            && line_disable === undefined
 3693.     56            && !state.mode_json
 3694.     23            && token_1
 3695.     23            && !mode_regexp
 3696.     13        ) {
 3697.     13
 3698.     13// test_cause:
 3699.     13// ["/////////////////////////////////////////////////////////////////////////////////", "read_line", "too_long", "", 1] //jslint-ignore-line
 3700.     13
 3701.     13            warn_at("too_long", line);
 3702.     13        }
 3703. 105181        column = 0;
 3704. 105181        line += 1;
 3705. 105181        mode_regexp = false;
 3706. 105181        line_source = undefined;
 3707. 105181        line_whole = "";
 3708.    643        if (line_list[line] === undefined) {
 3709.    643            return line_source;
 3710. 104538        }
 3711. 104538        line_source = line_list[line].line_source;
 3712. 104538        line_whole = line_source;
 3713. 104538
 3714. 104538// Scan each line for following ignore-directives:
 3715. 104538// "/*jslint-disable*/"
 3716. 104538// "/*jslint-enable*/"
 3717. 104538// "//jslint-ignore-line"
 3718. 104538
 3719. 104538        if (line_source === "/*jslint-disable*/") {
 3720.      5
 3721.      5// test_cause:
 3722.      5// ["/*jslint-disable*/", "read_line", "jslint_disable", "", 0]
 3723.      5
 3724.      5            test_cause("jslint_disable");
 3725.      5            line_disable = line;
 3726. 104533        } else if (line_source === "/*jslint-enable*/") {
 3727. 104533            if (line_disable === undefined) {
 3728. 104533
 3729. 104533// test_cause:
 3730. 104533// ["/*jslint-enable*/", "read_line", "unopened_enable", "", 1]
 3731. 104533
 3732. 104533                stop_at("unopened_enable", line);
 3733. 104533            }
 3734. 104533            line_disable = undefined;
 3735. 104533        } else if (
 3736. 104533            line_source.endsWith(" //jslint-ignore-line")
 3737. 104533            || line_source.endsWith(" //jslint-quiet")
 3738. 104533        ) {
 3739. 104533
 3740. 104533// test_cause:
 3741. 104533// ["0 //jslint-ignore-line", "read_line", "jslint_ignore_line", "", 0]
 3742. 104533
 3743. 104533            test_cause("jslint_ignore_line");
 3744. 104533            line_list[line].directive_ignore_line = true;
 3745. 104537        }
 3746. 104537        if (line_disable !== undefined) {
 3747.      9
 3748.      9// test_cause:
 3749.      9// ["/*jslint-disable*/\n0", "read_line", "line_disable", "", 0]
 3750.      9
 3751.      9            test_cause("line_disable");
 3752.      9            line_source = "";
 3753. 104537        }
 3754. 104537        // jslint_rgx_tab
 3755. 104537        if (line_source.indexOf("\t") >= 0) {
 3756.      3            if (!option_dict.white) {
 3757.      3
 3758.      3// test_cause:
 3759.      3// ["\t", "read_line", "use_spaces", "", 1]
 3760.      3
 3761.      3                warn_at("use_spaces", line, line_source.indexOf("\t") + 1);
 3762.      3            }
 3763.      3            line_source = line_source.replace(jslint_rgx_tab, " ");
 3764. 104537        }
 3765. 104537        if (!option_dict.white && line_source.endsWith(" ")) {
 3766.      2
 3767.      2// test_cause:
 3768.      2// [" ", "read_line", "unexpected_trailing_space", "", 1]
 3769.      2
 3770.      2            warn_at("unexpected_trailing_space", line, line_source.length - 1);
 3771. 104537        }
 3772. 104537        return line_source;
 3773. 104537    }
 3774.    666
 3775. 254929    function token_create(id, value, identifier) {
 3776. 254929
 3777. 254929// Create the token object and append it to token_list.
 3778. 254929
 3779. 254929        let the_token = {
 3780. 254929            from,
 3781. 254929            id,
 3782. 254929            identifier: Boolean(identifier),
 3783. 254929            line,
 3784. 254929            nr: token_list.length,
 3785. 254929            thru: column,
 3786. 254929            value
 3787. 254929        };
 3788. 254929        token_list.push(the_token);
 3789. 254929
 3790. 254929// Directives must appear before the first statement.
 3791. 254929
 3792. 243751        if (id !== "(comment)" && id !== ";") {
 3793. 227751            mode_directive = false;
 3794. 227751        }
 3795. 254929
 3796. 254929// If this token is an identifier that touches a preceding number, or
 3797. 254929// a "/", comment, or regular expression literal that touches a preceding
 3798. 254929// comment or regular expression literal, then give a missing space warning.
 3799. 254929// This warning is not suppressed by option_dict.white.
 3800. 254929
 3801. 254929        if (
 3802. 254929            token_prv.line === line
 3803. 185625            && token_prv.thru === from
 3804. 119780            && (id === "(comment)" || id === "(regexp)" || id === "/")
 3805.    125            && (token_prv.id === "(comment)" || token_prv.id === "(regexp)")
 3806.      1        ) {
 3807.      1
 3808.      1// test_cause:
 3809.      1// ["/**//**/", "token_create", "expected_space_a_b", "(comment)", 5]
 3810.      1
 3811.      1            warn(
 3812.      1                "expected_space_a_b",
 3813.      1                the_token,
 3814.      1                artifact(token_prv),
 3815.      1                artifact(the_token)
 3816.      1            );
 3817.      1        }
 3818.  11580        if (token_prv.id === "." && id === "(number)") {
 3819.      4
 3820.      4// test_cause:
 3821.      4// [".0", "token_create", "expected_a_before_b", ".", 1]
 3822.      4
 3823.      4            warn("expected_a_before_b", token_prv, "0", ".");
 3824.      4        }
 3825.  11580        if (token_prv_expr.id === "." && the_token.identifier) {
 3826.  11575            the_token.dot = true;
 3827.  11575        }
 3828. 254929
 3829. 254929// PR-385 - Bugfix - Fixes issue #382 - failure to detect destructured fart.
 3830. 254929// Farts are now detected by keeping a list of most recent "(" tokens at any
 3831. 254929// given depth. When a "=>" token is encountered, the most recent "(" token at
 3832. 254929// current depth is marked as a fart.
 3833. 254929
 3834. 254929        switch (id) {
 3835.  17561        case "(":
 3836.  17561            paren_backtrack_list[paren_depth] = the_token;
 3837.  17561            paren_depth += 1;
 3838.  17561            break;
 3839.  17560        case ")":
 3840.  17560            paren_depth -= 1;
 3841.  17560            break;
 3842.     16        case "=>":
 3843.     16            if (
 3844.     16                token_prv_expr.id === ")"
 3845.     16                && paren_backtrack_list[paren_depth]
 3846.     16            ) {
 3847.     16                paren_backtrack_list[paren_depth].fart = the_token;
 3848.     16            }
 3849.     16            break;
 3850. 254929        }
 3851. 254929
 3852. 254929// The previous token is used to detect adjacency problems.
 3853. 254929
 3854. 254929        token_prv = the_token;
 3855. 254929
 3856. 254929// The token_prv_expr token is a previous token that was not a comment.
 3857. 254929// The token_prv_expr token
 3858. 254929// is used to disambiguate "/", which can mean division or regular expression
 3859. 254929// literal.
 3860. 254929
 3861. 243751        if (token_prv.id !== "(comment)") {
 3862. 243751            token_prv_expr = token_prv;
 3863. 243751        }
 3864. 254929        return the_token;
 3865. 254929    }
 3866.    666
 3867.    666// Init global_dict and option_dict.
 3868.    666
 3869.    666    option_set_item("ecma", true);
 3870.   1890    Object.keys(option_dict).sort().forEach(function (key) {
 3871.   1890        option_set_item(key, option_dict[key] === true);
 3872.   1890    });
 3873.    666    object_assign_from_list(global_dict, global_list, "user-defined");
 3874.    666
 3875.    666// Scan first line for "#!" and ignore it.
 3876.    666
 3877.      1    if (line_list[jslint_fudge].line_source.startsWith("#!")) {
 3878.      1        line += 1;
 3879.      1        state.mode_shebang = true;
 3880.      1    }
 3881.    666    token_1 = lex_token();
 3882.    638    state.mode_json = token_1.id === "{" || token_1.id === "[";
 3883.    666
 3884.    666// Lex/loop through each token until (end).
 3885.    666
 3886. 249164    while (true) {
 3887. 249164        if (lex_token().id === "(end)") {
 3888. 249164            break;
 3889. 249164        }
 3890. 249164    }
 3891.    666}
 3892.      1
 3893.    629function jslint_phase3_parse(state) {
 3894.    629
 3895.    629// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
 3896.    629
 3897.    629// Parsing:
 3898.    629
 3899.    629// Parsing weaves the tokens into an abstract syntax tree. During that process,
 3900.    629// a token may be given any of these properties:
 3901.    629
 3902.    629//      arity       string
 3903.    629//      label       identifier
 3904.    629//      name        identifier
 3905.    629//      expression  expressions
 3906.    629//      block       statements
 3907.    629//      else        statements (else, default, catch)
 3908.    629
 3909.    629// Specialized tokens may have additional properties.
 3910.    629
 3911.    629    let anon = "anonymous";     // The guessed name for anonymous functions.
 3912.    629    let {
 3913.    629        artifact,
 3914.    629        catch_list,
 3915.    629        catch_stack,
 3916.    629        export_dict,
 3917.    629        function_list,
 3918.    629        function_stack,
 3919.    629        global_dict,
 3920.    629        import_list,
 3921.    629        is_equal,
 3922.    629        option_dict,
 3923.    629        property_dict,
 3924.    629        stop,
 3925.    629        syntax_dict,
 3926.    629        tenure,
 3927.    629        test_cause,
 3928.    629        token_global,
 3929.    629        token_list,
 3930.    629        warn,
 3931.    629        warn_at
 3932.    629    } = state;
 3933.    629    let catchage = catch_stack[0];      // The current catch-block.
 3934.    629    let functionage = token_global;     // The current function.
 3935.    629    let mode_var;               // "var" if using var; "let" if using let.
 3936.    629    let token_ii = 0;           // The number of the next token.
 3937.    629    let token_now = token_global;       // The current token being examined in
 3938.    629                                        // ... the parse.
 3939.    629    let token_nxt = token_global;       // The next token to be examined in
 3940.    629                                        // ... <token_list>.
 3941.    629
 3942. 244087    function advance(id, match) {
 3943. 244087
 3944. 244087// Produce the next token.
 3945. 244087
 3946. 244087// Attempt to give helpful names to anonymous functions.
 3947. 244087
 3948. 244087        if (
 3949. 244087            token_now.identifier
 3950.  67555            && token_now.id !== "function"
 3951.  65563            && token_now.id !== "async"
 3952.  65382        ) {
 3953.  65382            anon = token_now.id;
 3954. 178705        } else if (
 3955. 178705            token_now.id === "(string)"
 3956. 178705            && jslint_rgx_identifier.test(token_now.value)
 3957. 178705        ) {
 3958. 178705            anon = token_now.value;
 3959. 178705        }
 3960. 244087
 3961. 244087// Attempt to match token_nxt with an expected id.
 3962. 244087
 3963. 119971        if (id !== undefined && token_nxt.id !== id) {
 3964.     26            return (
 3965.     26                match === undefined
 3966.     26
 3967.     26// test_cause:
 3968.     26// ["{0:0}", "advance", "expected_a_b", "0", 2]
 3969.     26
 3970.     26                ? stop("expected_a_b", token_nxt, id, artifact())
 3971.     26
 3972.     26// test_cause:
 3973.     26// ["{\"aa\":0", "advance", "expected_a_b_from_c_d", "{", 1]
 3974.     26
 3975.     26                : stop(
 3976.     26                    "expected_a_b_from_c_d",
 3977.     26                    token_nxt,
 3978.     26                    id,
 3979.     26                    artifact(match),
 3980.     26                    match.line,
 3981.     26                    artifact()
 3982.     26                )
 3983.     26            );
 3984. 244061        }
 3985. 244061
 3986. 244061// Promote the tokens, skipping comments.
 3987. 244061
 3988. 244061        token_now = token_nxt;
 3989. 255236        while (true) {
 3990. 255236            token_nxt = token_list[token_ii];
 3991. 255236            state.token_nxt = token_nxt;
 3992. 255236            token_ii += 1;
 3993. 255236            if (token_nxt.id !== "(comment)") {
 3994. 255236                if (token_nxt.id === "(end)") {
 3995. 255236                    token_ii -= 1;
 3996. 255236                }
 3997. 255236                break;
 3998. 255236            }
 3999. 255236            if (state.mode_json) {
 4000. 255236
 4001. 255236// test_cause:
 4002. 255236// ["[//]", "advance", "unexpected_a", "(comment)", 2]
 4003. 255236
 4004. 255236                warn("unexpected_a");
 4005. 255236            }
 4006. 255236        }
 4007. 244087    }
 4008.    629
 4009.   7548    function assignment(id) {
 4010.   7548
 4011.   7548// Create an assignment operator. The one true assignment is different because
 4012.   7548// its left side, when it is a variable, is not treated as an expression.
 4013.   7548// That case is special because that is when a variable gets initialized. The
 4014.   7548// other assignment operators can modify, but they cannot initialize.
 4015.   7548
 4016.   7548        const the_symbol = symbol(id, 20);
 4017.   5012        the_symbol.led_infix = function (left) {
 4018.   5012            const the_token = token_now;
 4019.   5012            let right;
 4020.   5012            the_token.arity = "assignment";
 4021.   5012            right = parse_expression(20 - 1);
 4022.   4233            if (id === "=" && left.arity === "variable") {
 4023.   2817                the_token.names = left;
 4024.   2817                the_token.expression = right;
 4025.   2817            } else {
 4026.   2191                the_token.expression = [left, right];
 4027.   5008            }
 4028.   5008            if (
 4029.   5008                right.arity === "assignment"
 4030.   5008                || right.arity === "preassign"
 4031.   5006                || right.arity === "postassign"
 4032.      2            ) {
 4033.      2                warn("unexpected_a", right);
 4034.   5008            }
 4035.   5008            check_mutation(left);
 4036.   5008            return the_token;
 4037.   5008        };
 4038.   7548        return the_symbol;
 4039.   7548    }
 4040.    629
 4041.   5702    function block(special) {
 4042.   5702
 4043.   5702// Parse a block, a sequence of statements wrapped in braces.
 4044.   5702//  special "body"      The block is a function body.
 4045.   5702//          "ignore"    No warning on an empty block.
 4046.   5702//          "naked"     No advance.
 4047.   5702//          undefined   An ordinary block.
 4048.   5702
 4049.   5702        let stmts;
 4050.   5702        let the_block;
 4051.   5697        if (special !== "naked") {
 4052.   5697            advance("{");
 4053.   5701        }
 4054.   5701        the_block = token_now;
 4055.   5701        if (special !== "body") {
 4056.   3704            functionage.statement_prv = the_block;
 4057.   5701        }
 4058.   5701        the_block.arity = "statement";
 4059.   5701        the_block.body = special === "body";
 4060.   5701
 4061.   5701// Top level function bodies may include the "use strict" pragma.
 4062.   5701
 4063.   5701        if (
 4064.   5701            special === "body"
 4065.   5701            && function_stack.length === 1
 4066.    281            && token_nxt.value === "use strict"
 4067.      4        ) {
 4068.      4            token_nxt.statement = true;
 4069.      4            advance("(string)");
 4070.      4            advance(";");
 4071.   5701        }
 4072.   5701        stmts = parse_statements();
 4073.   5701        the_block.block = stmts;
 4074.   5701        if (stmts.length === 0) {
 4075.     72            if (!option_dict.devel && special !== "ignore") {
 4076.     72
 4077.     72// test_cause:
 4078.     72// ["function aa(){}", "block", "empty_block", "{", 14]
 4079.     72
 4080.     72                warn("empty_block", the_block);
 4081.     72            }
 4082.     72            the_block.disrupt = false;
 4083.   5622        } else {
 4084.   5622            the_block.disrupt = stmts[stmts.length - 1].disrupt;
 4085.   5694        }
 4086.   5694        advance("}");
 4087.   5694        return the_block;
 4088.   5694    }
 4089.    629
 4090.  23258    function check_left(left, right) {
 4091.  23258
 4092.  23258// Warn if the left is not one of these:
 4093.  23258//      ?.
 4094.  23258//      ?:
 4095.  23258//      e()
 4096.  23258//      e.b
 4097.  23258//      e[b]
 4098.  23258//      identifier
 4099.  23258
 4100.  23258        const id = left.id;
 4101.  23258        if (
 4102.  23258            !left.identifier
 4103.   6285            && (
 4104.   6285                left.arity !== "ternary"
 4105.   6285                || (
 4106.   6285                    !check_left(left.expression[1])
 4107.   6285                    && !check_left(left.expression[2])
 4108.   6285                )
 4109.   6285            )
 4110.   6285            && (
 4111.   6285                left.arity !== "binary"
 4112.   6285                || (id !== "." && id !== "?." && id !== "(" && id !== "[")
 4113.   6285            )
 4114.     11        ) {
 4115.     11            warn("unexpected_a", right || token_nxt);
 4116.     11            return false;
 4117.  23247        }
 4118.  23247        return true;
 4119.  23247    }
 4120.    629
 4121.   5011    function check_mutation(the_thing) {
 4122.   5011
 4123.   5011// The only expressions that may be assigned to are
 4124.   5011//      e.b
 4125.   5011//      e[b]
 4126.   5011//      v
 4127.   5011//      [destructure]
 4128.   5011//      {destructure}
 4129.   5011
 4130.   5011        if (
 4131.   5011            the_thing.arity !== "variable"
 4132.   1543            && the_thing.id !== "."
 4133.    192            && the_thing.id !== "["
 4134.      7            && the_thing.id !== "{"
 4135.      7        ) {
 4136.      7
 4137.      7// test_cause:
 4138.      7// ["0=0", "check_mutation", "bad_assignment_a", "0", 1]
 4139.      7
 4140.      7            warn("bad_assignment_a", the_thing);
 4141.      7            return false;
 4142.   5004        }
 4143.   5004        return true;
 4144.   5004    }
 4145.    629
 4146.   2203    function check_not_top_level(thing) {
 4147.   2203
 4148.   2203// Some features should not be at the outermost level.
 4149.   2203
 4150.     34        if (functionage === token_global) {
 4151.     34
 4152.     34// test_cause:
 4153.     34// ["
 4154.     34// while(0){}
 4155.     34// ", "check_not_top_level", "unexpected_at_top_level_a", "while", 1]
 4156.     34
 4157.     34            warn("unexpected_at_top_level_a", thing);
 4158.     34        }
 4159.   2203    }
 4160.    629
 4161.   3358    function check_ordered(type, token_list) {
 4162.   3358
 4163.   3358// This function will warn if <token_list> is unordered.
 4164.   3358
 4165.   4056        token_list.reduce(function (aa, token) {
 4166.   4056            const bb = artifact(token);
 4167.   4042            if (!option_dict.unordered && aa > bb) {
 4168.      4                warn("expected_a_b_before_c_d", token, type, bb, type, aa);
 4169.      4            }
 4170.   4056            return bb;
 4171.   4056        }, "");
 4172.   3358    }
 4173.    629
 4174.   1301    function check_ordered_case(case_list) {
 4175.   1301
 4176.   1301// This function will warn if <case_list> is unordered.
 4177.   1301
 4178.   2691        case_list.filter(noop).map(function (token) {
 4179.   2650            switch (token.identifier || token.id) {
 4180.     34            case "(number)":
 4181.     34                return {
 4182.     34                    order: 1,
 4183.     34                    token,
 4184.     34                    type: "number",
 4185.     34                    value: Number(artifact(token))
 4186.     34                };
 4187.   2604            case "(string)":
 4188.   2604                return {
 4189.   2604                    order: 2,
 4190.   2604                    token,
 4191.   2604                    type: "string",
 4192.   2604                    value: artifact(token)
 4193.   2604                };
 4194.     41            case true:
 4195.     41                return {
 4196.     41                    order: 3,
 4197.     41                    token,
 4198.     41                    type: "identifier",
 4199.     41                    value: artifact(token)
 4200.     41                };
 4201.   2691            }
 4202.   2691        }).reduce(function (aa, bb) {
 4203.   2691            if (
 4204.   2691
 4205.   2691// PR-419 - Hide warning about unordered case-statements behind beta-flag.
 4206.   2691
 4207.   2691                option_dict.beta
 4208.   2691                && !option_dict.unordered
 4209.   2683                && aa && bb
 4210.   1384                && (
 4211.   1384                    aa.order > bb.order
 4212.   1384                    || (aa.order === bb.order && aa.value > bb.value)
 4213.   1384                )
 4214.     10            ) {
 4215.     10                warn(
 4216.     10                    "expected_a_b_before_c_d",
 4217.     10                    bb.token,
 4218.     10                    `case-${bb.type}`,
 4219.     10                    bb.value,
 4220.     10                    `case-${aa.type}`,
 4221.     10                    aa.value
 4222.     10                );
 4223.     10            }
 4224.   2691            return bb;
 4225.   2691        }, undefined);
 4226.   1301    }
 4227.    629
 4228.   3252    function condition() {
 4229.   3252
 4230.   3252// Parse the condition part of a do, if, while.
 4231.   3252
 4232.   3252        const the_paren = token_nxt;
 4233.   3252        let the_value;
 4234.   3252
 4235.   3252// test_cause:
 4236.   3252// ["do{}while()", "condition", "", "", 0]
 4237.   3252// ["if(){}", "condition", "", "", 0]
 4238.   3252// ["while(){}", "condition", "", "", 0]
 4239.   3252
 4240.   3252        test_cause("");
 4241.   3252        the_paren.free = true;
 4242.   3252        advance("(");
 4243.   3252        the_value = parse_expression(0);
 4244.   3252        advance(")");
 4245.      1        if (the_value.wrapped === true) {
 4246.      1
 4247.      1// test_cause:
 4248.      1// ["while((0)){}", "condition", "unexpected_a", "(", 6]
 4249.      1
 4250.      1            warn("unexpected_a", the_paren);
 4251.   3248        }
 4252.   3248
 4253.   3248// Check for anticondition.
 4254.   3248
 4255.   3248        switch (the_value.id) {
 4256.   3248        case "%":
 4257.      1            warn("unexpected_a", the_value);
 4258.      1            break;
 4259.      1        case "&":
 4260.      1            warn("unexpected_a", the_value);
 4261.      1            break;
 4262.     17        case "(number)":
 4263.     17            warn("unexpected_a", the_value);
 4264.     17            break;
 4265.      1        case "(string)":
 4266.      1            warn("unexpected_a", the_value);
 4267.      1            break;
 4268.      1        case "*":
 4269.      1            warn("unexpected_a", the_value);
 4270.      1            break;
 4271.      1        case "+":
 4272.      1            warn("unexpected_a", the_value);
 4273.      1            break;
 4274.      1        case "-":
 4275.      1            warn("unexpected_a", the_value);
 4276.      1            break;
 4277.      1        case "/":
 4278.      1            warn("unexpected_a", the_value);
 4279.      1            break;
 4280.      1        case "<<":
 4281.      1            warn("unexpected_a", the_value);
 4282.      1            break;
 4283.      1        case ">>":
 4284.      1            warn("unexpected_a", the_value);
 4285.      1            break;
 4286.      1        case ">>>":
 4287.      1            warn("unexpected_a", the_value);
 4288.      1            break;
 4289.      1        case "?":
 4290.      1            warn("unexpected_a", the_value);
 4291.      1            break;
 4292.      1        case "^":
 4293.      1            warn("unexpected_a", the_value);
 4294.      1            break;
 4295.      1        case "typeof":
 4296.      1            warn("unexpected_a", the_value);
 4297.      1            break;
 4298.      1        case "|":
 4299.      1            warn("unexpected_a", the_value);
 4300.      1            break;
 4301.      1        case "~":
 4302.      1
 4303.      1// test_cause:
 4304.      1// ["if(0%0){}", "condition", "unexpected_a", "%", 5]
 4305.      1// ["if(0&0){}", "condition", "unexpected_a", "&", 5]
 4306.      1// ["if(0){}", "condition", "unexpected_a", "0", 4]
 4307.      1// ["if(0*0){}", "condition", "unexpected_a", "*", 5]
 4308.      1// ["if(0+0){}", "condition", "unexpected_a", "+", 5]
 4309.      1// ["if(0-0){}", "condition", "unexpected_a", "-", 5]
 4310.      1// ["if(0/0){}", "condition", "unexpected_a", "/", 5]
 4311.      1// ["if(0<<0){}", "condition", "unexpected_a", "<<", 5]
 4312.      1// ["if(0>>0){}", "condition", "unexpected_a", ">>", 5]
 4313.      1// ["if(0>>>0){}", "condition", "unexpected_a", ">>>", 5]
 4314.      1// ["if(0?0:0){}", "condition", "unexpected_a", "?", 5]
 4315.      1// ["if(0^0){}", "condition", "unexpected_a", "^", 5]
 4316.      1// ["if(0|0){}", "condition", "unexpected_a", "|", 5]
 4317.      1// ["if(\"aa\"){}", "condition", "unexpected_a", "aa", 4]
 4318.      1// ["if(typeof 0){}", "condition", "unexpected_a", "typeof", 4]
 4319.      1// ["if(~0){}", "condition", "unexpected_a", "~", 4]
 4320.      1
 4321.      1            warn("unexpected_a", the_value);
 4322.      1            break;
 4323.   3248        }
 4324.   3248        return the_value;
 4325.   3248    }
 4326.    629
 4327.  10064    function constant(id, type, value) {
 4328.  10064
 4329.  10064// Create a constant symbol.
 4330.  10064
 4331.  10064        const the_symbol = symbol(id);
 4332.  10064        the_symbol.constant = true;
 4333.  10064        the_symbol.nud_prefix = (
 4334.  10064            typeof value === "function"
 4335.   4403            ? value
 4336.  18668            : function () {
 4337.  18668                token_now.constant = true;
 4338.   5661                if (value !== undefined) {
 4339.   5661                    token_now.value = value;
 4340.   5661                }
 4341.  18668                return token_now;
 4342.  18668            }
 4343.  10064        );
 4344.  10064        the_symbol.type = type;
 4345.  10064        the_symbol.value = value;
 4346.  10064        return the_symbol;
 4347.  10064    }
 4348.    629
 4349.      5    function constant_Function() {
 4350.      2        if (!option_dict.eval) {
 4351.      2
 4352.      2// test_cause:
 4353.      2// ["Function", "constant_Function", "unexpected_a", "Function", 1]
 4354.      2
 4355.      2            warn("unexpected_a", token_now);
 4356.      3        } else if (token_nxt.id !== "(") {
 4357.      3
 4358.      3// test_cause:
 4359.      3// ["
 4360.      3// /*jslint eval*/
 4361.      3// Function
 4362.      3// ", "constant_Function", "expected_a_before_b", "(end)", 1]
 4363.      3
 4364.      3            warn("expected_a_before_b", token_nxt, "(", artifact());
 4365.      3        }
 4366.      5        return token_now;
 4367.      5    }
 4368.    629
 4369.      1    function constant_arguments() {
 4370.      1
 4371.      1// test_cause:
 4372.      1// ["arguments", "constant_arguments", "unexpected_a", "arguments", 1]
 4373.      1
 4374.      1        warn("unexpected_a", token_now);
 4375.      1        return token_now;
 4376.      1    }
 4377.    629
 4378.      4    function constant_eval() {
 4379.      1        if (!option_dict.eval) {
 4380.      1
 4381.      1// test_cause:
 4382.      1// ["eval", "constant_eval", "unexpected_a", "eval", 1]
 4383.      1
 4384.      1            warn("unexpected_a", token_now);
 4385.      3        } else if (token_nxt.id !== "(") {
 4386.      3
 4387.      3// test_cause:
 4388.      3// ["/*jslint eval*/\neval", "constant_eval", "expected_a_before_b", "(end)", 1]
 4389.      3
 4390.      3            warn("expected_a_before_b", token_nxt, "(", artifact());
 4391.      3        }
 4392.      4        return token_now;
 4393.      4    }
 4394.    629
 4395.      1    function constant_ignore() {
 4396.      1
 4397.      1// test_cause:
 4398.      1// ["ignore", "constant_ignore", "unexpected_a", "ignore", 1]
 4399.      1
 4400.      1        warn("unexpected_a", token_now);
 4401.      1        return token_now;
 4402.      1    }
 4403.    629
 4404.      1    function constant_isInfinite() {
 4405.      1
 4406.      1// test_cause:
 4407.      1// ["isFinite", "constant_isInfinite", "expected_a_b", "isFinite", 1]
 4408.      1
 4409.      1        warn("expected_a_b", token_now, "Number.isFinite", "isFinite");
 4410.      1        return token_now;
 4411.      1    }
 4412.    629
 4413.      1    function constant_isNaN() {
 4414.      1
 4415.      1// test_cause:
 4416.      1// ["isNaN(0)", "constant_isNaN", "number_isNaN", "isNaN", 1]
 4417.      1
 4418.      1        warn("number_isNaN", token_now);
 4419.      1        return token_now;
 4420.      1    }
 4421.    629
 4422.      3    function constant_this() {
 4423.      1        if (!option_dict.this) {
 4424.      1
 4425.      1// test_cause:
 4426.      1// ["this", "constant_this", "unexpected_a", "this", 1]
 4427.      1
 4428.      1            warn("unexpected_a", token_now);
 4429.      1        }
 4430.      3        return token_now;
 4431.      3    }
 4432.    629
 4433.   6360    function enroll(name, role, readonly) {
 4434.   6360
 4435.   6360// Enroll a name into the current function context. The role can be exception,
 4436.   6360// function, label, parameter, or variable. We look for variable redefinition
 4437.   6360// because it causes confusion.
 4438.   6360
 4439.   6360        let earlier;
 4440.   6360        let id = name.id;
 4441.   6360
 4442.   6360// Reserved words may not be enrolled.
 4443.   6360
 4444.     42        if (syntax_dict[id] !== undefined && id !== "ignore") {
 4445.      1
 4446.      1// test_cause:
 4447.      1// ["let undefined", "enroll", "reserved_a", "undefined", 5]
 4448.      1
 4449.      1            warn("reserved_a", name);
 4450.      1            return;
 4451.   6359        }
 4452.   6359
 4453.   6359// Has the name been enrolled in this context?
 4454.   6359
 4455.   6359        earlier = functionage.context[id] || catchage.context[id];
 4456.      7        if (earlier) {
 4457.      7
 4458.      7// test_cause:
 4459.      7// ["let aa;let aa", "enroll", "redefinition_a_b", "1", 12]
 4460.      7
 4461.      7            warn("redefinition_a_b", name, id, earlier.line);
 4462.      7            return;
 4463.   6352        }
 4464.   6352
 4465.   6352// Has the name been enrolled in an outer context?
 4466.   6352
 4467.  10744        function_stack.forEach(function ({
 4468.  10744            context
 4469.  10744        }) {
 4470.  10589            earlier = context[id] || earlier;
 4471.  10744        });
 4472.   6352        if (earlier && id === "ignore") {
 4473.      4            if (earlier.role === "variable") {
 4474.      4
 4475.      4// test_cause:
 4476.      4// ["let ignore;function aa(ignore){}", "enroll", "redefinition_a_b", "1", 24]
 4477.      4
 4478.      4                warn("redefinition_a_b", name, id, earlier.line);
 4479.      4            }
 4480.   6348        } else if (
 4481.   6348            earlier
 4482.   6348            && role !== "parameter" && role !== "function"
 4483.   6348            && (role !== "exception" || earlier.role !== "exception")
 4484.   6348        ) {
 4485.   6348
 4486.   6348// test_cause:
 4487.   6348// ["
 4488.   6348// function aa(){try{aa();}catch(aa){aa();}}
 4489.   6348// ", "enroll", "redefinition_a_b", "1", 31]
 4490.   6348// ["function aa(){var aa;}", "enroll", "redefinition_a_b", "1", 19]
 4491.   6348
 4492.   6348            warn("redefinition_a_b", name, id, earlier.line);
 4493.   6348        } else if (
 4494.   6348            option_dict.beta
 4495.   6348            && global_dict[id]
 4496.   6348            && role !== "parameter"
 4497.   6348        ) {
 4498.   6348
 4499.   6348// test_cause:
 4500.   6348// ["let Array", "enroll", "redefinition_global_a_b", "Array", 5]
 4501.   6348
 4502.   6348            warn("redefinition_global_a_b", name, global_dict[id], id);
 4503.   6352        }
 4504.   6352
 4505.   6352// Enroll it.
 4506.   6352
 4507.   6352        Object.assign(name, {
 4508.   6352            dead: true,
 4509.   6352            init: false,
 4510.   6352            parent: (
 4511.   6352                role === "exception"
 4512.   6352                ? catchage
 4513.   6322                : functionage
 4514.   6360            ),
 4515.   6360            readonly,
 4516.   6360            role,
 4517.   6360            used: 0
 4518.   6360        });
 4519.   6360        name.parent.context[id] = name;
 4520.   6360    }
 4521.    629
 4522.  18870    function infix(bp, id, f) {
 4523.  18870
 4524.  18870// Create an infix operator.
 4525.  18870
 4526.  18870        const the_symbol = symbol(id, bp);
 4527.  31880        the_symbol.led_infix = function (left) {
 4528.  31880            const the_token = token_now;
 4529.  31880            the_token.arity = "binary";
 4530.  23454            if (f !== undefined) {
 4531.  23454                return f(left);
 4532.  23454            }
 4533.   8426            the_token.expression = [left, parse_expression(bp)];
 4534.   8426            return the_token;
 4535.   8426        };
 4536.  18870        return the_symbol;
 4537.  18870    }
 4538.    629
 4539.  11574    function infix_dot(left) {
 4540.  11574        const the_token = token_now;
 4541.  11574        let name = token_nxt;
 4542.  11574        if (
 4543.  11574            (
 4544.  11574                left.id !== "(string)"
 4545.     44                || (name.id !== "indexOf" && name.id !== "repeat")
 4546.  11574            )
 4547.  11531            && (
 4548.  11531                left.id !== "["
 4549.  11531                || (
 4550.  11531                    name.id !== "concat"
 4551.  11531                    && name.id !== "flat"
 4552.  11531                    && name.id !== "flatMap"
 4553.  11531                    && name.id !== "forEach"
 4554.  11531                    && name.id !== "join"
 4555.  11531                    && name.id !== "map"
 4556.  11531                )
 4557.  11531            )
 4558.  11486            && (left.id !== "+" || name.id !== "slice")
 4559.  11481            && (
 4560.  11481                left.id !== "(regexp)"
 4561.  11481                || (name.id !== "exec" && name.id !== "test")
 4562.  11481            )
 4563.  11414        ) {
 4564.  11414
 4565.  11414// test_cause:
 4566.  11414// ["\"\".aa", "check_left", "unexpected_a", ".", 3]
 4567.  11414
 4568.  11414            check_left(left, the_token);
 4569.  11414        }
 4570.      1        if (!name.identifier) {
 4571.      1
 4572.      1// test_cause:
 4573.      1// ["aa.0", "infix_dot", "expected_identifier_a", "0", 4]
 4574.      1
 4575.      1            stop("expected_identifier_a");
 4576.  11573        }
 4577.  11573        advance();
 4578.  11573        survey(name);
 4579.  11573
 4580.  11573// The property name is not an expression.
 4581.  11573
 4582.  11573        the_token.name = name;
 4583.  11573        the_token.expression = left;
 4584.  11573        return the_token;
 4585.  11573    }
 4586.    629
 4587.      1    function infix_fart_unwrapped() {
 4588.      1
 4589.      1// test_cause:
 4590.      1// ["aa=>0", "infix_fart_unwrapped", "wrap_fart_parameter", "=>", 3]
 4591.      1
 4592.      1        return stop("wrap_fart_parameter", token_now);
 4593.      1    }
 4594.    629
 4595.      1    function infix_grave(left) {
 4596.      1        const the_tick = prefix_tick();
 4597.      1
 4598.      1// test_cause:
 4599.      1// ["0``", "check_left", "unexpected_a", "`", 2]
 4600.      1
 4601.      1        check_left(left, the_tick);
 4602.      1        the_tick.expression = [left].concat(the_tick.expression);
 4603.      1        return the_tick;
 4604.      1    }
 4605.    629
 4606.   1466    function infix_lbracket(left) {
 4607.   1466        const the_token = token_now;
 4608.   1466        let name;
 4609.   1466        let the_subscript = parse_expression(0);
 4610.   1443        if (the_subscript.id === "(string)" || the_subscript.id === "`") {
 4611.     25            name = survey(the_subscript);
 4612.     25
 4613.     25// PR-404 - Add new directive "subscript" to play nice with Google Closure.
 4614.     25
 4615.     25            if (!option_dict.subscript && jslint_rgx_identifier.test(name)) {
 4616.     25
 4617.     25// test_cause:
 4618.     25// ["aa[`aa`]", "infix_lbracket", "subscript_a", "aa", 4]
 4619.     25
 4620.     25                warn("subscript_a", the_subscript, name);
 4621.     25            }
 4622.     25        }
 4623.   1466
 4624.   1466// test_cause:
 4625.   1466// ["0[0]", "check_left", "unexpected_a", "[", 2]
 4626.   1466
 4627.   1466        check_left(left, the_token);
 4628.   1466        the_token.expression = [left, the_subscript];
 4629.   1466        advance("]");
 4630.   1466        return the_token;
 4631.   1466    }
 4632.    629
 4633.  10402    function infix_lparen(left) {
 4634.  10402        const the_paren = token_now;
 4635.  10402        let ellipsis;
 4636.  10402        let the_argument;
 4637.  10365        if (left.id !== "function") {
 4638.  10365
 4639.  10365// test_cause:
 4640.  10365// ["(0?0:0)()", "check_left", "unexpected_a", "(", 8]
 4641.  10365// ["0()", "check_left", "unexpected_a", "(", 2]
 4642.  10365
 4643.  10365            check_left(left, the_paren);
 4644.  10365        }
 4645.   7694        if (functionage.arity === "statement" && left.identifier) {
 4646.   5498            functionage.name.calls[left.id] = left;
 4647.   5498        }
 4648.  10402        the_paren.expression = [left];
 4649.   8944        if (token_nxt.id !== ")") {
 4650.   8944
 4651.   8944// Parse/loop through each token in expression (...).
 4652.   8944
 4653.  14268            while (true) {
 4654.  14268                if (token_nxt.id === "...") {
 4655.  14268                    ellipsis = true;
 4656.  14268                    advance("...");
 4657.  14268                }
 4658.  14268                the_argument = parse_expression(10);
 4659.  14268                if (ellipsis) {
 4660.  14268                    the_argument.ellipsis = true;
 4661.  14268                }
 4662.  14268                the_paren.expression.push(the_argument);
 4663.  14268                if (token_nxt.id !== ",") {
 4664.  14268                    break;
 4665.  14268                }
 4666.  14268                advance(",");
 4667.  14268            }
 4668.   8944        }
 4669.  10402        advance(")", the_paren);
 4670.   5242        if (the_paren.expression.length === 2) {
 4671.   5242
 4672.   5242// test_cause:
 4673.   5242// ["aa(0)", "infix_lparen", "free", "", 0]
 4674.   5242
 4675.   5242            test_cause("free");
 4676.   5242            the_paren.free = true;
 4677.   5242            if (the_argument.wrapped === true) {
 4678.   5242
 4679.   5242// test_cause:
 4680.   5242// ["aa((0))", "infix_lparen", "unexpected_a", "(", 3]
 4681.   5242
 4682.   5242                warn("unexpected_a", the_paren);
 4683.   5242            }
 4684.   5242            if (the_argument.id === "(") {
 4685.   5242                the_argument.wrapped = true;
 4686.   5242            }
 4687.   5242        } else {
 4688.   5160
 4689.   5160// test_cause:
 4690.   5160// ["aa()", "infix_lparen", "not_free", "", 0]
 4691.   5160// ["aa(0,0)", "infix_lparen", "not_free", "", 0]
 4692.   5160
 4693.   5160            test_cause("not_free");
 4694.   5160            the_paren.free = false;
 4695.   5160        }
 4696.  10402        return the_paren;
 4697.  10402    }
 4698.    629
 4699.     10    function infix_option_chain(left) {
 4700.     10        const the_token = token_now;
 4701.     10        let name;
 4702.     10        name = token_nxt;
 4703.     10        if (
 4704.     10            (
 4705.     10                left.id !== "(string)"
 4706.      1                || (name.id !== "indexOf" && name.id !== "repeat")
 4707.     10            )
 4708.     10            && (
 4709.     10                left.id !== "["
 4710.      1                || (
 4711.      1                    name.id !== "concat"
 4712.      1                    && name.id !== "forEach"
 4713.      1                    && name.id !== "join"
 4714.      1                    && name.id !== "map"
 4715.      1                )
 4716.     10            )
 4717.     10
 4718.     10// test_cause:
 4719.     10// ["(0+0)?.0", "infix_option_chain", "check_left", "", 0]
 4720.     10
 4721.      1            && (left.id !== "+" || name.id !== "slice")
 4722.     10            && (
 4723.     10                left.id !== "(regexp)"
 4724.      1                || (name.id !== "exec" && name.id !== "test")
 4725.     10            )
 4726.     10        ) {
 4727.     10            test_cause("check_left");
 4728.     10
 4729.     10// test_cause:
 4730.     10// ["(/./)?.0", "check_left", "unexpected_a", "?.", 6]
 4731.     10// ["\"aa\"?.0", "check_left", "unexpected_a", "?.", 5]
 4732.     10// ["aa=[]?.aa", "check_left", "unexpected_a", "?.", 6]
 4733.     10
 4734.     10            check_left(left, the_token);
 4735.     10        }
 4736.      4        if (!name.identifier) {
 4737.      4
 4738.      4// test_cause:
 4739.      4// ["aa?.0", "infix_option_chain", "expected_identifier_a", "0", 5]
 4740.      4
 4741.      4            stop("expected_identifier_a");
 4742.      6        }
 4743.      6        advance();
 4744.      6        survey(name);
 4745.      6
 4746.      6// The property name is not an expression.
 4747.      6
 4748.      6        the_token.name = name;
 4749.      6        the_token.expression = left;
 4750.      6        return the_token;
 4751.      6    }
 4752.    629
 4753.    629    function infixr(bp, id) {
 4754.    629
 4755.    629// Create a right associative infix operator.
 4756.    629
 4757.    629        const the_symbol = symbol(id, bp);
 4758.      1        the_symbol.led_infix = function parse_infixr_led(left) {
 4759.      1            const the_token = token_now;
 4760.      1
 4761.      1// test_cause:
 4762.      1// ["0**0", "parse_infixr_led", "led_infix", "", 0]
 4763.      1
 4764.      1            test_cause("led_infix");
 4765.      1            the_token.arity = "binary";
 4766.      1            the_token.expression = [left, parse_expression(bp - 1)];
 4767.      1            return the_token;
 4768.      1        };
 4769.    629        return the_symbol;
 4770.    629    }
 4771.    629
 4772.  55937    function parse_expression(rbp, initial) {
 4773.  55937
 4774.  55937// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
 4775.  55937// is looking for ad hoc lint patterns. We add .fud_stmt to Pratt's model, which
 4776.  55937// is like .nud_prefix except that it is only used on the first token of a
 4777.  55937// statement. Having .fud_stmt makes it much easier to define statement-oriented
 4778.  55937// languages like JavaScript. I retained Pratt's nomenclature.
 4779.  55937// They are elements of the parsing method called Top Down Operator Precedence.
 4780.  55937
 4781.  55937// .nud_prefix  Null denotation. The prefix handler.
 4782.  55937// .fud_stmt    First null denotation. The statement handler.
 4783.  55937// .led_infix   Left denotation. The infix/postfix handler.
 4784.  55937//  lbp         Left binding power of infix operator. It tells us how strongly
 4785.  55937//              the operator binds to the argument at its left.
 4786.  55937//  rbp         Right binding power.
 4787.  55937
 4788.  55937// It processes a nud_prefix (variable, constant, prefix operator). It will then
 4789.  55937// process leds (infix operators) until the bind powers cause it to stop (it
 4790.  55937// consumes tokens until it meets a token whose lbp <= rbp). Specifically, it
 4791.  55937// means that it collects all tokens that bind together before returning to the
 4792.  55937// operator that called it. It returns the expression's parse tree.
 4793.  55937
 4794.  55937// For example, "3 + 1 * 2 * 4 + 5"
 4795.  55937// parses into
 4796.  55937// {
 4797.  55937//     "id": "+",
 4798.  55937//     "expression": [
 4799.  55937//         {
 4800.  55937//             "id": "+",
 4801.  55937//             "expression": [
 4802.  55937//                 {
 4803.  55937//                     "id": "(number)",
 4804.  55937//                     "value": "3"
 4805.  55937//                 },
 4806.  55937//                 {
 4807.  55937//                     "id": "*",
 4808.  55937//                     "expression": [
 4809.  55937//                         {
 4810.  55937//                             "id": "*",
 4811.  55937//                             "expression": [
 4812.  55937//                                 {
 4813.  55937//                                     "id": "(number)",
 4814.  55937//                                     "value": "1"
 4815.  55937//                                 },
 4816.  55937//                                 {
 4817.  55937//                                     "id": "(number)",
 4818.  55937//                                     "value": "2"
 4819.  55937//                                 }
 4820.  55937//                             ]
 4821.  55937//                         },
 4822.  55937//                         {
 4823.  55937//                             "id": "(number)",
 4824.  55937//                             "value": "4"
 4825.  55937//                         }
 4826.  55937//                     ]
 4827.  55937//                 }
 4828.  55937//             ]
 4829.  55937//         },
 4830.  55937//         {
 4831.  55937//             "id": "(number)",
 4832.  55937//             "value": "5"
 4833.  55937//         }
 4834.  55937//     ]
 4835.  55937// }
 4836.  55937
 4837.  55937        let left;
 4838.  55937        let the_symbol;
 4839.  55937
 4840.  55937// Statements will have already advanced, so advance now only if the token is
 4841.  55937// not the first of a statement.
 4842.  55937
 4843.  44585        if (!initial) {
 4844.  44585            advance();
 4845.  44585        }
 4846.  55937        the_symbol = syntax_dict[token_now.id];
 4847.  24489        if (the_symbol !== undefined && the_symbol.nud_prefix !== undefined) {
 4848.  24430
 4849.  24430// test_cause:
 4850.  24430// ["0", "parse_expression", "symbol", "", 0]
 4851.  24430
 4852.  24430            test_cause("symbol");
 4853.  24430            left = the_symbol.nud_prefix();
 4854.  31507        } else if (token_now.identifier) {
 4855.  31507
 4856.  31507// test_cause:
 4857.  31507// ["aa", "parse_expression", "identifier", "", 0]
 4858.  31507
 4859.  31507            test_cause("identifier");
 4860.  31507            left = token_now;
 4861.  31507            left.arity = "variable";
 4862.  31507        } else {
 4863.  31507
 4864.  31507// test_cause:
 4865.  31507// ["!", "parse_expression", "unexpected_a", "(end)", 1]
 4866.  31507// ["/./", "parse_expression", "unexpected_a", "/", 1]
 4867.  31507// ["let aa=`${}`;", "parse_expression", "unexpected_a", "}", 11]
 4868.  31507
 4869.  31507            return stop("unexpected_a", token_now);
 4870.  55901        }
 4871.  55901
 4872.  55901// Parse/loop through each symbol in expression.
 4873.  55901
 4874.  93003        while (true) {
 4875.  93003            the_symbol = syntax_dict[token_nxt.id];
 4876.  93003            if (
 4877.  93003                the_symbol === undefined
 4878.  93003                || the_symbol.led_infix === undefined
 4879.  93003                || the_symbol.lbp <= rbp
 4880.  93003            ) {
 4881.  93003                break;
 4882.  93003            }
 4883.  93003            advance();
 4884.  93003            left = the_symbol.led_infix(left);
 4885.  93003        }
 4886.  55890        return left;
 4887.  55890    }
 4888.    629
 4889.     14    function parse_fart(the_fart) {
 4890.     14
 4891.     14// Give the function properties storing its names and for observing the depth
 4892.     14// of loops and switches.
 4893.     14
 4894.     14        Object.assign(the_fart, {
 4895.     14            arity: "binary",
 4896.     14            context: empty(),
 4897.     14            finally: 0,
 4898.     14            level: functionage.level + 1,
 4899.     14            loop: 0,
 4900.     14            name: anon,
 4901.     14            switch: 0,
 4902.     14            try: 0
 4903.     14        });
 4904.     14
 4905.     14// PR-384 - Relax warning "function_in_loop".
 4906.     14//
 4907.     14//         if (functionage.loop > 0) {
 4908.     14
 4909.     14// // test_cause:
 4910.     14// // ["while(0){aa.map(()=>0);}", "parse_fart", "function_in_loop", "=>", 19]
 4911.     14//
 4912.     14//             warn("function_in_loop", the_fart);
 4913.     14//         }
 4914.     14
 4915.     14// Push the current function context and establish a new one.
 4916.     14
 4917.     14        function_list.push(the_fart);
 4918.     14        function_stack.push(functionage);
 4919.     14        functionage = the_fart;
 4920.     14
 4921.     14// Parse the parameter list.
 4922.     14
 4923.     14        prefix_function_parameter(the_fart);
 4924.     14        advance("=>");
 4925.     14
 4926.     14// The function's body is a block.
 4927.     14
 4928.      3        if (token_nxt.id === "{") {
 4929.      3            if (!option_dict.fart) {
 4930.      3
 4931.      3// test_cause:
 4932.      3// ["()=>{}", "parse_fart", "use_function_not_fart", "=>", 3]
 4933.      3
 4934.      3                warn("use_function_not_fart", the_fart);
 4935.      3            }
 4936.      3            the_fart.block = block("body");
 4937.     11        } else if (
 4938.     11            syntax_dict[token_nxt.id] !== undefined
 4939.     11            && syntax_dict[token_nxt.id].fud_stmt !== undefined
 4940.     11        ) {
 4941.     11
 4942.     11// PR-384 - Bugfix - Fixes issue #379 - warn against naked-statement in fart.
 4943.     11
 4944.     11// test_cause:
 4945.     11// ["()=>delete aa", "parse_fart", "unexpected_a_after_b", "=>", 5]
 4946.     11
 4947.     11            stop("unexpected_a_after_b", token_nxt, token_nxt.id, "=>");
 4948.     11
 4949.     11// The function's body is an expression.
 4950.     11
 4951.     11        } else {
 4952.     11            the_fart.expression = parse_expression(0);
 4953.     13        }
 4954.     13
 4955.     13// Restore the previous context.
 4956.     13
 4957.     13        functionage = function_stack.pop();
 4958.     13        return the_fart;
 4959.     13    }
 4960.    629
 4961.  12961    function parse_json() {
 4962.  12961        let container;
 4963.  12961        let is_dup;
 4964.  12961        let name;
 4965.  12961        let negative;
 4966.  12961        switch (token_nxt.id) {
 4967.   5262        case "(number)":
 4968.   5262            if (!jslint_rgx_json_number.test(token_nxt.value)) {
 4969.   5262
 4970.   5262// test_cause:
 4971.   5262// ["[-.0]", "parse_json", "unexpected_a", ".", 3]
 4972.   5262// ["[-0x0]", "parse_json", "unexpected_a", "0x0", 3]
 4973.   5262// ["[.0]", "parse_json", "unexpected_a", ".", 2]
 4974.   5262// ["[0x0]", "parse_json", "unexpected_a", "0x0", 2]
 4975.   5262
 4976.   5262                warn("unexpected_a");
 4977.   5262            }
 4978.   5262            advance("(number)");
 4979.   5262            return token_now;
 4980.   1767        case "(string)":
 4981.   1767            if (token_nxt.quote !== "\"") {
 4982.   1767
 4983.   1767// test_cause:
 4984.   1767// ["['']", "parse_json", "unexpected_a", "'", 2]
 4985.   1767
 4986.   1767                warn("unexpected_a", token_nxt, token_nxt.quote);
 4987.   1767            }
 4988.   1767            advance("(string)");
 4989.   1767            return token_now;
 4990.      3        case "-":
 4991.      3            negative = token_nxt;
 4992.      3            negative.arity = "unary";
 4993.      3            advance("-");
 4994.      3
 4995.      3// Recurse parse_json().
 4996.      3
 4997.      3            negative.expression = parse_json();
 4998.      3            return negative;
 4999.   1649        case "[":
 5000.   1649
 5001.   1649// test_cause:
 5002.   1649// ["[]", "parse_json", "bracket", "", 0]
 5003.   1649
 5004.   1649            test_cause("bracket");
 5005.   1649            container = token_nxt;
 5006.   1649            container.expression = [];
 5007.   1649            advance("[");
 5008.   1649            if (token_nxt.id !== "]") {
 5009.   3300                while (true) {
 5010.   3300
 5011.   3300// Recurse parse_json().
 5012.   3300
 5013.   3300                    container.expression.push(parse_json());
 5014.   3300                    if (token_nxt.id !== ",") {
 5015.   3300
 5016.   3300// test_cause:
 5017.   3300// ["[0,0]", "parse_json", "comma", "", 0]
 5018.   3300
 5019.   3300                        test_cause("comma");
 5020.   3300                        break;
 5021.   3300                    }
 5022.   3300                    advance(",");
 5023.   3300                }
 5024.   1649            }
 5025.   1649            advance("]", container);
 5026.   1649            return container;
 5027.    509        case "false":
 5028.    511        case "null":
 5029.    896        case "true":
 5030.    896
 5031.    896// test_cause:
 5032.    896// ["[false]", "parse_json", "constant", "", 0]
 5033.    896// ["[null]", "parse_json", "constant", "", 0]
 5034.    896// ["[true]", "parse_json", "constant", "", 0]
 5035.    896
 5036.    896            test_cause("constant");
 5037.    896            advance();
 5038.    896            return token_now;
 5039.   3379        case "{":
 5040.   3379
 5041.   3379// test_cause:
 5042.   3379// ["{}", "parse_json", "brace", "", 0]
 5043.   3379
 5044.   3379            test_cause("brace");
 5045.   3379            container = token_nxt;
 5046.   3379
 5047.   3379// Explicit empty-object required to detect "__proto__".
 5048.   3379
 5049.   3379            is_dup = empty();
 5050.   3379            container.expression = [];
 5051.   3379            advance("{");
 5052.   3379            if (token_nxt.id !== "}") {
 5053.   3379
 5054.   3379// JSON
 5055.   3379// Parse/loop through each property in {...}.
 5056.   3379
 5057.   9636                while (true) {
 5058.   9636                    if (token_nxt.quote !== "\"") {
 5059.   9636
 5060.   9636// test_cause:
 5061.   9636// ["{0:0}", "parse_json", "unexpected_a", "0", 2]
 5062.   9636
 5063.   9636                        warn(
 5064.   9636                            "unexpected_a",
 5065.   9636                            token_nxt,
 5066.   9636                            token_nxt.quote
 5067.   9636                        );
 5068.   9636                    }
 5069.   9636                    name = token_nxt;
 5070.   9636                    advance("(string)");
 5071.   9636                    if (is_dup[token_now.value] !== undefined) {
 5072.   9636
 5073.   9636// test_cause:
 5074.   9636// ["{\"aa\":0,\"aa\":0}", "parse_json", "duplicate_a", "aa", 9]
 5075.   9636
 5076.   9636                        warn("duplicate_a", token_now);
 5077.   9636                    } else if (token_now.value === "__proto__") {
 5078.   9636
 5079.   9636// test_cause:
 5080.   9636// ["{\"__proto__\":0}", "parse_json", "weird_property_a", "__proto__", 2]
 5081.   9636
 5082.   9636                        warn("weird_property_a", token_now);
 5083.   9636                    } else {
 5084.   9636                        is_dup[token_now.value] = token_now;
 5085.   9636                    }
 5086.   9636                    advance(":");
 5087.   9636                    container.expression.push(
 5088.   9636
 5089.   9636// Recurse parse_json().
 5090.   9636
 5091.   9636                        Object.assign(parse_json(), {
 5092.   9636                            label: name
 5093.   9636                        })
 5094.   9636                    );
 5095.   9636                    if (token_nxt.id !== ",") {
 5096.   9636                        break;
 5097.   9636                    }
 5098.   9636                    advance(",");
 5099.   9636                }
 5100.   3379            }
 5101.   3379            advance("}", container);
 5102.   3379            return container;
 5103.      5        default:
 5104.      5
 5105.      5// test_cause:
 5106.      5// ["[undefined]", "parse_json", "unexpected_a", "undefined", 2]
 5107.      5
 5108.      5            stop("unexpected_a");
 5109.  12961        }
 5110.  12961    }
 5111.    629
 5112.  20899    function parse_statement() {
 5113.  20899
 5114.  20899// Parse a statement. Any statement may have a label, but only four statements
 5115.  20899// have use for one. A statement can be one of the standard statements, or
 5116.  20899// an assignment expression, or an invocation expression.
 5117.  20899
 5118.  20899        let first;
 5119.  20899        let the_label;
 5120.  20899        let the_statement;
 5121.  20899        let the_symbol;
 5122.  20899        advance();
 5123.  20712        if (token_now.identifier && token_nxt.id === ":") {
 5124.     13            the_label = token_now;
 5125.     13            if (the_label.id === "ignore") {
 5126.     13
 5127.     13// test_cause:
 5128.     13// ["ignore:", "parse_statement", "unexpected_a", "ignore", 1]
 5129.     13
 5130.     13                warn("unexpected_a", the_label);
 5131.     13            }
 5132.     13            advance(":");
 5133.     13            switch (token_nxt.id) {
 5134.     13            case "do":
 5135.     13            case "for":
 5136.     13            case "switch":
 5137.     13            case "while":
 5138.     13
 5139.     13// test_cause:
 5140.     13// ["aa:do{}", "parse_statement", "the_statement_label", "do", 0]
 5141.     13// ["aa:for{}", "parse_statement", "the_statement_label", "for", 0]
 5142.     13// ["aa:switch{}", "parse_statement", "the_statement_label", "switch", 0]
 5143.     13// ["aa:while{}", "parse_statement", "the_statement_label", "while", 0]
 5144.     13
 5145.     13                test_cause("the_statement_label", token_nxt.id);
 5146.     13                enroll(the_label, "label", true);
 5147.     13                the_label.dead = false;
 5148.     13                the_label.init = true;
 5149.     13                the_statement = parse_statement();
 5150.     13                functionage.statement_prv = the_statement;
 5151.     13                the_statement.label = the_label;
 5152.     13                the_statement.statement = true;
 5153.     13                return the_statement;
 5154.     13            }
 5155.     13            advance();
 5156.     13
 5157.     13// test_cause:
 5158.     13// ["aa:", "parse_statement", "unexpected_label_a", "aa", 1]
 5159.     13
 5160.     13            warn("unexpected_label_a", the_label);
 5161.  20890        }
 5162.  20890
 5163.  20890// Parse the statement.
 5164.  20890
 5165.  20890        first = token_now;
 5166.  20890        first.statement = true;
 5167.  20890        the_symbol = syntax_dict[first.id];
 5168.  20890        if (
 5169.  20890            the_symbol !== undefined
 5170.  20890            && the_symbol.fud_stmt !== undefined
 5171.  20899
 5172.  20899// PR-318 - Bugfix - Fixes issues #316, #317 - dynamic-import().
 5173.  20899
 5174.  10132            && !(the_symbol.id === "import" && token_nxt.id === "(")
 5175.  10130        ) {
 5176.  10130            the_symbol.disrupt = false;
 5177.  10130            the_symbol.statement = true;
 5178.  10130            token_now.arity = "statement";
 5179.  10130            the_statement = the_symbol.fud_stmt();
 5180.  10130            functionage.statement_prv = the_statement;
 5181.  10760        } else {
 5182.  10760
 5183.  10760// It is an expression statement.
 5184.  10760
 5185.  10760            the_statement = parse_expression(0, true);
 5186.  10760            functionage.statement_prv = the_statement;
 5187.  10760            if (the_statement.wrapped && the_statement.id !== "(") {
 5188.  10760
 5189.  10760// test_cause:
 5190.  10760// ["(0)", "parse_statement", "unexpected_a", "(", 1]
 5191.  10760
 5192.  10760                warn("unexpected_a", first);
 5193.  10760            }
 5194.  10760            semicolon();
 5195.  20796        }
 5196.  20796        if (the_label !== undefined) {
 5197.      1            the_label.dead = true;
 5198.  20796        }
 5199.  20796        return the_statement;
 5200.  20796    }
 5201.    629
 5202.   7488    function parse_statements() {
 5203.   7488
 5204.   7488// Parse a list of statements. Give a warning if an unreachable statement
 5205.   7488// follows a disruptive statement.
 5206.   7488
 5207.   7488        const statement_list = [];
 5208.   7488        let a_statement;
 5209.   7488        let disrupt = false;
 5210.   7488
 5211.   7488// Parse/loop each statement until a statement-terminator is reached.
 5212.   7488
 5213.  27960        while (true) {
 5214.  27960            switch (token_nxt.id) {
 5215.  27960            case "(end)":
 5216.  27960            case "case":
 5217.  27960            case "default":
 5218.  27960            case "else":
 5219.  27960            case "}":
 5220.  27960
 5221.  27960// test_cause:
 5222.  27960// [";", "parse_statements", "closer", "", 0]
 5223.  27960// ["case", "parse_statements", "closer", "", 0]
 5224.  27960// ["default", "parse_statements", "closer", "", 0]
 5225.  27960// ["else", "parse_statements", "closer", "", 0]
 5226.  27960// ["}", "parse_statements", "closer", "", 0]
 5227.  27960
 5228.  27960                test_cause("closer");
 5229.  27960                return statement_list;
 5230.  27960            }
 5231.  27960            a_statement = parse_statement();
 5232.  27960            statement_list.push(a_statement);
 5233.  27960            if (disrupt) {
 5234.  27960
 5235.  27960// test_cause:
 5236.  27960// ["while(0){break;0;}", "parse_statements", "unreachable_a", "0", 16]
 5237.  27960
 5238.  27960                warn("unreachable_a", a_statement);
 5239.  27960            }
 5240.  27960            disrupt = a_statement.disrupt;
 5241.  27960        }
 5242.   7488    }
 5243.    629
 5244.   1258    function postassign(id) {
 5245.   1258
 5246.   1258// Create one of the postassign operators.
 5247.   1258
 5248.   1258        const the_symbol = symbol(id, 150);
 5249.      1        the_symbol.led_infix = function (left) {
 5250.      1            token_now.expression = left;
 5251.      1            token_now.arity = "postassign";
 5252.      1            check_mutation(token_now.expression);
 5253.      1            return token_now;
 5254.      1        };
 5255.   1258        return the_symbol;
 5256.   1258    }
 5257.    629
 5258.   1258    function preassign(id) {
 5259.   1258
 5260.   1258// Create one of the preassign operators.
 5261.   1258
 5262.   1258        const the_symbol = symbol(id);
 5263.      2        the_symbol.nud_prefix = function () {
 5264.      2            const the_token = token_now;
 5265.      2            the_token.arity = "preassign";
 5266.      2            the_token.expression = parse_expression(150);
 5267.      2            check_mutation(the_token.expression);
 5268.      2            return the_token;
 5269.      2        };
 5270.   1258        return the_symbol;
 5271.   1258    }
 5272.    629
 5273.  10693    function prefix(id, f) {
 5274.  10693
 5275.  10693// Create a prefix operator.
 5276.  10693
 5277.  10693        const the_symbol = symbol(id);
 5278.   5744        the_symbol.nud_prefix = function () {
 5279.   5744            const the_token = token_now;
 5280.   5744            the_token.arity = "unary";
 5281.   4932            if (typeof f === "function") {
 5282.   4932                return f();
 5283.   4932            }
 5284.    812            the_token.expression = parse_expression(150);
 5285.    812            return the_token;
 5286.    812        };
 5287.  10693        return the_symbol;
 5288.  10693    }
 5289.    629
 5290.      1    function prefix_assign_divide() {
 5291.      1
 5292.      1// test_cause:
 5293.      1// ["/=", "prefix_assign_divide", "expected_a_b", "/=", 1]
 5294.      1
 5295.      1        stop("expected_a_b", token_now, "/\\=", "/=");
 5296.      1    }
 5297.    629
 5298.    136    function prefix_async() {
 5299.    136        let the_async = token_now;
 5300.    136        let the_function;
 5301.    136        token_nxt.arity = the_async.arity;
 5302.    136
 5303.    136// PR-414 - Parse async fart.
 5304.    136
 5305.      3        if (token_nxt.fart) {
 5306.      3            advance("(");
 5307.      3            the_function = Object.assign(token_now.fart, {
 5308.      3                async: 1
 5309.      3            });
 5310.      3            if (!option_dict.fart) {
 5311.      3
 5312.      3// test_cause:
 5313.      3// ["async()=>0", "prefix_async", "use_function_not_fart", "=>", 8]
 5314.      3
 5315.      3                warn("use_function_not_fart", the_function);
 5316.      3            }
 5317.      3            prefix_lparen();
 5318.      3
 5319.      3// Parse async function.
 5320.      3
 5321.    133        } else {
 5322.    133            advance("function");
 5323.    133            the_function = Object.assign(token_now, {
 5324.    133                async: 1
 5325.    133            });
 5326.    133            prefix_function();
 5327.    133        }
 5328.      3        if (the_function.async === 1) {
 5329.      3
 5330.      3// test_cause:
 5331.      3// ["
 5332.      3// async function aa(){}
 5333.      3// ", "prefix_async", "missing_await_statement", "function", 7]
 5334.      3
 5335.      3            warn("missing_await_statement", the_function);
 5336.      3        }
 5337.    136        return the_function;
 5338.    136    }
 5339.    629
 5340.    297    function prefix_await() {
 5341.    297        const the_await = token_now;
 5342.    297
 5343.    297// PR-370 - Add top-level-await support.
 5344.    297
 5345.      4        if (functionage.async === 0 && functionage !== token_global) {
 5346.      2
 5347.      2// test_cause:
 5348.      2// ["function aa(){aa=await 0;}", "prefix_await", "unexpected_a", "await", 18]
 5349.      2// ["function aa(){await 0;}", "prefix_await", "unexpected_a", "await", 15]
 5350.      2
 5351.      2            warn("unexpected_a", the_await);
 5352.    295        } else {
 5353.    295            functionage.async += 1;
 5354.    295        }
 5355.    185        if (the_await.arity === "statement") {
 5356.    185
 5357.    185// PR-405 - Bugfix - fix expression after "await" mis-identified as statement.
 5358.    185
 5359.    185            the_await.expression = parse_expression(150);
 5360.    185            semicolon();
 5361.    185        } else {
 5362.    112            the_await.expression = parse_expression(150);
 5363.    112        }
 5364.    297        return the_await;
 5365.    297    }
 5366.    629
 5367.      1    function prefix_fart() {
 5368.      1
 5369.      1// test_cause:
 5370.      1// ["=>0", "prefix_fart", "expected_a_before_b", "=>", 1]
 5371.      1
 5372.      1        return stop("expected_a_before_b", token_now, "()", "=>");
 5373.      1    }
 5374.    629
 5375.   2005    function prefix_function(the_function) {
 5376.     11        let name = the_function && the_function.name;
 5377.   1994        if (the_function === undefined) {
 5378.   1994            the_function = token_now;
 5379.   1994
 5380.   1994// A function statement must have a name that will be in the parent's scope.
 5381.   1994
 5382.   1994            if (the_function.arity === "statement") {
 5383.   1994                if (!token_nxt.identifier) {
 5384.   1994
 5385.   1994// test_cause:
 5386.   1994// ["function(){}", "prefix_function", "expected_identifier_a", "(", 9]
 5387.   1994// ["function*aa(){}", "prefix_function", "expected_identifier_a", "*", 9]
 5388.   1994
 5389.   1994                    return stop("expected_identifier_a");
 5390.   1994                }
 5391.   1994                name = token_nxt;
 5392.   1994                enroll(name, "variable", true);
 5393.   1994                the_function.name = Object.assign(name, {
 5394.   1994                    calls: empty(),
 5395.   1994
 5396.   1994// PR-331 - Bugfix - Fixes issue #272 - function hoisting not allowed.
 5397.   1994
 5398.   1994                    dead: false,
 5399.   1994                    init: true
 5400.   1994                });
 5401.   1994                advance();
 5402.   1994            } else if (name === undefined) {
 5403.   1994
 5404.   1994// A function expression may have an optional name.
 5405.   1994
 5406.   1994                the_function.name = anon;
 5407.   1994                if (token_nxt.identifier) {
 5408.   1994                    name = token_nxt;
 5409.   1994                    the_function.name = name;
 5410.   1994                    advance();
 5411.   1994                }
 5412.   1994            }
 5413.   2003        }
 5414.   2003
 5415.   2003//  Probably deadcode.
 5416.   2003//  if (mode_mega) {
 5417.   2003//      warn("unexpected_a", the_function);
 5418.   2003//  }
 5419.   2003//  jslint_assert(!mode_mega, `Expected !mode_mega.`);
 5420.   2003
 5421.   2003// PR-378 - Relax warning "function_in_loop".
 5422.   2003//
 5423.   2003// // Don't create functions in loops. It is inefficient, and it can lead to
 5424.   2003// // scoping errors.
 5425.   2003//
 5426.   2003//         if (functionage.loop > 0) {
 5427.   2003//
 5428.   2003// // test_cause:
 5429.   2003// // ["
 5430.   2003// // while(0){aa.map(function(){});}
 5431.   2003// // ", "prefix_function", "function_in_loop", "function", 17]
 5432.   2003//
 5433.   2003//             warn("function_in_loop", the_function);
 5434.   2003//         }
 5435.   2003
 5436.   2003// Give the function properties for storing its names and for observing the
 5437.   2003// depth of loops and switches.
 5438.   2003
 5439.   2003        Object.assign(the_function, {
 5440.   2003            async: the_function.async || 0,
 5441.   2005            context: empty(),
 5442.   2005            finally: 0,
 5443.   2005            level: functionage.level + 1,
 5444.   2005            loop: 0,
 5445.   2005            statement_prv: undefined,
 5446.   2005            switch: 0,
 5447.   2005            try: 0
 5448.   2005        });
 5449.    929        if (the_function.arity !== "statement" && typeof name === "object") {
 5450.     38
 5451.     38// test_cause:
 5452.     38// ["let aa=function bb(){return;};", "prefix_function", "expression", "bb", 0]
 5453.     38
 5454.     38            test_cause("expression", name.id);
 5455.     38            enroll(name, "function", true);
 5456.     38            name.dead = false;
 5457.     38            name.init = true;
 5458.     38            name.used = 1;
 5459.   2003        }
 5460.   2003
 5461.   2003// PR-334 - Bugfix - fix function-redefinition not warned inside function-call.
 5462.   2003// Push the current function context and establish a new one.
 5463.   2003
 5464.   2003        function_list.push(the_function);
 5465.   2003        function_stack.push(functionage);
 5466.   2003        functionage = the_function;
 5467.   2003
 5468.   2003// Parse the parameter list.
 5469.   2003
 5470.   2003        advance("(");
 5471.   2003        token_now.arity = "function";
 5472.   2003        prefix_function_parameter(the_function);
 5473.   2003
 5474.   2003// The function's body is a block.
 5475.   2003
 5476.   2003        the_function.block = block("body");
 5477.   2003        if (
 5478.   2003            the_function.arity === "statement"
 5479.   2003            && token_nxt.line === token_now.line
 5480.      2        ) {
 5481.      2
 5482.      2// test_cause:
 5483.      2// ["function aa(){}0", "prefix_function", "unexpected_a", "0", 16]
 5484.      2
 5485.      2            return stop("unexpected_a");
 5486.   1990        }
 5487.   1990        if (
 5488.   1990            token_nxt.id === "."
 5489.   1990            || token_nxt.id === "?."
 5490.   2005
 5491.   2005// PR-459 - Allow destructuring-assignment after function-definition.
 5492.   2005
 5493.   2005            // || token_nxt.id === "["
 5494.      2        ) {
 5495.      2
 5496.      2// test_cause:
 5497.      2// ["function aa(){}\n.aa", "prefix_function", "unexpected_a", ".", 1]
 5498.      2// ["function aa(){}\n?.aa", "prefix_function", "unexpected_a", "?.", 1]
 5499.      2
 5500.      2            warn("unexpected_a");
 5501.   1990        }
 5502.   1990
 5503.   1990// Check functions are ordered.
 5504.   1990
 5505.   1990        check_ordered(
 5506.   1990            "function",
 5507.   1990            function_list.slice(
 5508.   1990                function_list.indexOf(the_function) + 1
 5509.   2515            ).map(function ({
 5510.   2515                level,
 5511.   2515                name
 5512.   2515            }) {
 5513.   1990                return (level === the_function.level + 1) && name;
 5514.   2515            }).filter(function (name) {
 5515.   2510                return option_dict.beta && name && name.id;
 5516.   2515            })
 5517.   1990        );
 5518.   1990
 5519.   1990// Restore the previous context.
 5520.   1990
 5521.   1990        functionage = function_stack.pop();
 5522.   1990        return the_function;
 5523.   1990    }
 5524.    629
 5525.   2017    function prefix_function_parameter(the_function) {
 5526.   2017
 5527.   2017// This function will parse input <parameters> at beginning of <the_function>
 5528.   2017
 5529.   2017        let optional;
 5530.   2017        let parameters = [];
 5531.   2017        let signature = ["("];
 5532.   2017        let subparam;
 5533.   2781        function param_enroll(name) {
 5534.   2514            if (name.identifier) {
 5535.   2514                enroll(name, "parameter", false);
 5536.   2514            } else {
 5537.    267
 5538.    267// test_cause:
 5539.    267// ["([aa])=>0", "param_enroll", "use_function_not_fart", "=>", 7]
 5540.    267// ["({aa})=>0", "param_enroll", "use_function_not_fart", "=>", 7]
 5541.    267
 5542.    267                if (the_function.id === "=>" && !option_dict.fart) {
 5543.    267                    warn("use_function_not_fart", the_function);
 5544.    267                }
 5545.    267
 5546.    267// Recurse param_enroll().
 5547.    267
 5548.    267                name.names.forEach(param_enroll);
 5549.    267            }
 5550.   2781        }
 5551.   2077        function param_parse() {
 5552.   2077            let ellipsis = false;
 5553.   2077            let param;
 5554.    227            if (token_nxt.id === "{") {
 5555.    227                if (optional !== undefined) {
 5556.    227
 5557.    227// test_cause:
 5558.    227// ["function aa(aa=0,{}){}", "param_parse", "required_a_optional_b", "aa", 18]
 5559.    227
 5560.    227                    warn(
 5561.    227                        "required_a_optional_b",
 5562.    227                        token_nxt,
 5563.    227                        token_nxt.id,
 5564.    227                        optional.id
 5565.    227                    );
 5566.    227                }
 5567.    227                param = token_nxt;
 5568.    227                param.names = [];
 5569.    227                advance("{");
 5570.    227                signature.push("{");
 5571.    625                while (true) {
 5572.    625                    subparam = token_nxt;
 5573.    625                    if (!subparam.identifier) {
 5574.    625
 5575.    625// test_cause:
 5576.    625// ["function aa(aa=0,{}){}", "param_parse", "expected_identifier_a", "}", 19]
 5577.    625// ["function aa({0}){}", "param_parse", "expected_identifier_a", "0", 14]
 5578.    625
 5579.    625                        return stop("expected_identifier_a");
 5580.    625                    }
 5581.    625                    survey(subparam);
 5582.    625                    advance();
 5583.    625                    signature.push(subparam.id);
 5584.    625                    if (token_nxt.id === ":") {
 5585.    625                        advance(":");
 5586.    625                        advance();
 5587.    625                        token_now.label = subparam;
 5588.    625                        subparam = token_now;
 5589.    625                        if (!subparam.identifier) {
 5590.    625
 5591.    625// test_cause:
 5592.    625// ["function aa({aa:0}){}", "param_parse", "expected_identifier_a", "}", 18]
 5593.    625
 5594.    625                            return stop(
 5595.    625                                "expected_identifier_a",
 5596.    625                                token_nxt
 5597.    625                            );
 5598.    625                        }
 5599.    625                    }
 5600.    625
 5601.    625// test_cause:
 5602.    625// ["function aa({aa=aa},aa){}", "param_parse", "equal", "", 0]
 5603.    625
 5604.    625                    test_cause("equal");
 5605.    625                    if (token_nxt.id === "=") {
 5606.    625                        advance("=");
 5607.    625                        subparam.expression = parse_expression();
 5608.    625                        param.open = true;
 5609.    625                    }
 5610.    625                    param.names.push(subparam);
 5611.    625                    if (token_nxt.id === ",") {
 5612.    625                        advance(",");
 5613.    625                        signature.push(", ");
 5614.    625                    } else {
 5615.    625                        break;
 5616.    625                    }
 5617.    625                }
 5618.    227                parameters.push(param);
 5619.    227
 5620.    227// test_cause:
 5621.    227// ["
 5622.    227// function aa({bb,aa}){}
 5623.    227// ", "check_ordered", "expected_a_b_before_c_d", "aa", 17]
 5624.    227
 5625.    227                check_ordered("parameter", param.names);
 5626.    227                advance("}");
 5627.    227                signature.push("}");
 5628.    227                if (token_nxt.id === ",") {
 5629.    227                    advance(",");
 5630.    227                    signature.push(", ");
 5631.    227                    param_parse();
 5632.    227                    return;
 5633.    227                }
 5634.   1850            } else if (token_nxt.id === "[") {
 5635.   1850                if (optional !== undefined) {
 5636.   1850
 5637.   1850// test_cause:
 5638.   1850// ["function aa(aa=0,[]){}", "param_parse", "required_a_optional_b", "aa", 18]
 5639.   1850
 5640.   1850                    warn(
 5641.   1850                        "required_a_optional_b",
 5642.   1850                        token_nxt,
 5643.   1850                        token_nxt.id,
 5644.   1850                        optional.id
 5645.   1850                    );
 5646.   1850                }
 5647.   1850                param = token_nxt;
 5648.   1850                param.names = [];
 5649.   1850                advance("[");
 5650.   1850                signature.push("[]");
 5651.   1850                while (true) {
 5652.   1850                    subparam = token_nxt;
 5653.   1850                    if (!subparam.identifier) {
 5654.   1850
 5655.   1850// test_cause:
 5656.   1850// ["function aa(aa=0,[]){}", "param_parse", "expected_identifier_a", "]", 19]
 5657.   1850
 5658.   1850                        return stop("expected_identifier_a");
 5659.   1850                    }
 5660.   1850                    advance();
 5661.   1850                    param.names.push(subparam);
 5662.   1850
 5663.   1850// test_cause:
 5664.   1850// ["function aa([aa=aa],aa){}", "param_parse", "id", "", 0]
 5665.   1850
 5666.   1850                    test_cause("id");
 5667.   1850                    if (token_nxt.id === "=") {
 5668.   1850                        advance("=");
 5669.   1850                        subparam.expression = parse_expression();
 5670.   1850                        param.open = true;
 5671.   1850                    }
 5672.   1850                    if (token_nxt.id === ",") {
 5673.   1850                        advance(",");
 5674.   1850                    } else {
 5675.   1850                        break;
 5676.   1850                    }
 5677.   1850                }
 5678.   1850                parameters.push(param);
 5679.   1850                advance("]");
 5680.   1850                if (token_nxt.id === ",") {
 5681.   1850                    advance(",");
 5682.   1850                    signature.push(", ");
 5683.   1850                    param_parse();
 5684.   1850                    return;
 5685.   1850                }
 5686.   1850            } else {
 5687.   1850                if (token_nxt.id === "...") {
 5688.   1850                    ellipsis = true;
 5689.   1850                    signature.push("...");
 5690.   1850                    advance("...");
 5691.   1850                    if (optional !== undefined) {
 5692.   1850
 5693.   1850// test_cause:
 5694.   1850// ["function aa(aa=0,...){}", "param_parse", "required_a_optional_b", "aa", 21]
 5695.   1850
 5696.   1850                        warn(
 5697.   1850                            "required_a_optional_b",
 5698.   1850                            token_nxt,
 5699.   1850                            token_nxt.id,
 5700.   1850                            optional.id
 5701.   1850                        );
 5702.   1850                    }
 5703.   1850                }
 5704.   1850                if (!token_nxt.identifier) {
 5705.   1850
 5706.   1850// test_cause:
 5707.   1850// ["function aa(0){}", "param_parse", "expected_identifier_a", "0", 13]
 5708.   1850
 5709.   1850                    return stop("expected_identifier_a");
 5710.   1850                }
 5711.   1850                param = token_nxt;
 5712.   1850                parameters.push(param);
 5713.   1850                advance();
 5714.   1850                signature.push(param.id);
 5715.   1850                if (ellipsis) {
 5716.   1850                    param.ellipsis = true;
 5717.   1850                } else {
 5718.   1850                    if (token_nxt.id === "=") {
 5719.   1850                        optional = param;
 5720.   1850                        advance("=");
 5721.   1850                        param.expression = parse_expression(0);
 5722.   1850                    } else {
 5723.   1850                        if (optional !== undefined) {
 5724.   1850
 5725.   1850// test_cause:
 5726.   1850// ["function aa(aa=0,bb){}", "param_parse", "required_a_optional_b", "aa", 18]
 5727.   1850
 5728.   1850                            warn(
 5729.   1850                                "required_a_optional_b",
 5730.   1850                                param,
 5731.   1850                                param.id,
 5732.   1850                                optional.id
 5733.   1850                            );
 5734.   1850                        }
 5735.   1850                    }
 5736.   1850                    if (token_nxt.id === ",") {
 5737.   1850                        advance(",");
 5738.   1850                        signature.push(", ");
 5739.   1850                        param_parse();
 5740.   1850                        return;
 5741.   1850                    }
 5742.   1850                }
 5743.   1850            }
 5744.   2077        }
 5745.   2017
 5746.   2017// test_cause:
 5747.   2017// ["function aa(){}", "prefix_function_parameter", "opener", "(", 0]
 5748.   2017
 5749.   2017        test_cause("opener", token_now.id);
 5750.   2017        token_now.free = false;
 5751.   1485        if (token_nxt.id !== ")" && token_nxt.id !== "(end)") {
 5752.   1485            param_parse();
 5753.   2009        }
 5754.   2009        advance(")");
 5755.   2009        signature.push(")");
 5756.   2009        parameters.forEach(param_enroll);
 5757.   2009        the_function.parameters = parameters;
 5758.   2009        the_function.signature = signature.join("");
 5759.   2009    }
 5760.    629
 5761.    588    function prefix_lbrace() {
 5762.    588        const seen = empty();
 5763.    588        const the_brace = token_now;
 5764.    588        let extra;
 5765.    588        let full;
 5766.    588        let id;
 5767.    588        let name;
 5768.    588        let the_colon;
 5769.    588        let value;
 5770.    588        the_brace.expression = [];
 5771.    548        if (token_nxt.id !== "}") {
 5772.    548
 5773.    548// Parse/loop through each property in {...}.
 5774.    548
 5775.   1990            while (true) {
 5776.   1990                name = token_nxt;
 5777.   1990                advance();
 5778.   1990                if (
 5779.   1990                    (name.id === "get" || name.id === "set")
 5780.   1990                    && token_nxt.identifier
 5781.   1990                ) {
 5782.   1990                    if (!option_dict.getset) {
 5783.   1990
 5784.   1990// test_cause:
 5785.   1990// ["aa={get aa(){}}", "prefix_lbrace", "unexpected_a", "get", 5]
 5786.   1990
 5787.   1990                        warn("unexpected_a", name);
 5788.   1990                    }
 5789.   1990                    extra = name.id;
 5790.   1990                    full = extra + " " + token_nxt.id;
 5791.   1990                    name = token_nxt;
 5792.   1990                    advance();
 5793.   1990                    id = survey(name);
 5794.   1990                    if (seen[full] === true || seen[id] === true) {
 5795.   1990
 5796.   1990// test_cause:
 5797.   1990// ["aa={get aa(){},get aa(){}}", "prefix_lbrace", "duplicate_a", "aa", 20]
 5798.   1990
 5799.   1990                        warn("duplicate_a", name);
 5800.   1990                    }
 5801.   1990                    seen[id] = false;
 5802.   1990                    seen[full] = true;
 5803.   1990                } else if (name.id === "`") {
 5804.   1990
 5805.   1990// test_cause:
 5806.   1990// ["aa={`aa`:0}", "prefix_lbrace", "unexpected_a", "`", 5]
 5807.   1990
 5808.   1990                    stop("unexpected_a", name);
 5809.   1990
 5810.   1990                } else {
 5811.   1990                    id = survey(name);
 5812.   1990                    if (typeof seen[id] === "boolean") {
 5813.   1990
 5814.   1990// test_cause:
 5815.   1990// ["aa={aa,aa}", "prefix_lbrace", "duplicate_a", "aa", 8]
 5816.   1990
 5817.   1990                        warn("duplicate_a", name);
 5818.   1990                    }
 5819.   1990                    seen[id] = true;
 5820.   1990                }
 5821.   1990                if (name.identifier) {
 5822.   1990                    if (token_nxt.id === "}" || token_nxt.id === ",") {
 5823.   1990                        if (typeof extra === "string") {
 5824.   1990
 5825.   1990// test_cause:
 5826.   1990// ["aa={get aa}", "prefix_lbrace", "closer", "", 0]
 5827.   1990
 5828.   1990                            test_cause("closer");
 5829.   1990                            advance("(");
 5830.   1990                        }
 5831.   1990                        value = parse_expression(Infinity, true);
 5832.   1990                    } else if (token_nxt.id === "(") {
 5833.   1990
 5834.   1990// test_cause:
 5835.   1990// ["aa={aa()}", "prefix_lbrace", "paren", "", 0]
 5836.   1990// ["aa={get aa(){}}", "prefix_lbrace", "paren", "", 0]
 5837.   1990
 5838.   1990                        test_cause("paren");
 5839.   1990                        value = prefix_function({
 5840.   1990                            arity: "unary",
 5841.   1990                            from: name.from,
 5842.   1990                            id: "function",
 5843.   1990                            line: name.line,
 5844.   1990                            name: (
 5845.   1990                                typeof extra === "string"
 5846.   1990                                ? extra
 5847.   1990                                : id
 5848.   1990                            ),
 5849.   1990                            thru: name.from
 5850.   1990                        });
 5851.   1990                    } else {
 5852.   1990                        if (typeof extra === "string") {
 5853.   1990
 5854.   1990// test_cause:
 5855.   1990// ["aa={get aa.aa}", "prefix_lbrace", "paren", "", 0]
 5856.   1990
 5857.   1990                            test_cause("paren");
 5858.   1990                            advance("(");
 5859.   1990                        }
 5860.   1990                        the_colon = token_nxt;
 5861.   1990                        advance(":");
 5862.   1990                        value = parse_expression(0);
 5863.   1990                        if (
 5864.   1990                            value.id === name.id
 5865.   1990                            && value.id !== "function"
 5866.   1990                        ) {
 5867.   1990
 5868.   1990// test_cause:
 5869.   1990// ["aa={aa:aa}", "prefix_lbrace", "unexpected_a", ": aa", 7]
 5870.   1990
 5871.   1990                            warn("unexpected_a", the_colon, ": " + name.id);
 5872.   1990                        }
 5873.   1990                    }
 5874.   1990                    value.label = name;
 5875.   1990                    if (typeof extra === "string") {
 5876.   1990                        value.extra = extra;
 5877.   1990                    }
 5878.   1990                    the_brace.expression.push(value);
 5879.   1990                } else {
 5880.   1990
 5881.   1990// test_cause:
 5882.   1990// ["aa={\"aa\":0}", "prefix_lbrace", "colon", "", 0]
 5883.   1990
 5884.   1990                    test_cause("colon");
 5885.   1990                    advance(":");
 5886.   1990                    value = parse_expression(0);
 5887.   1990                    value.label = name;
 5888.   1990                    the_brace.expression.push(value);
 5889.   1990                }
 5890.   1990                if (token_nxt.id !== ",") {
 5891.   1990                    break;
 5892.   1990                }
 5893.   1990
 5894.   1990// test_cause:
 5895.   1990// ["aa={\"aa\":0,\"bb\":0}", "prefix_lbrace", "comma", "", 0]
 5896.   1990
 5897.   1990                test_cause("comma");
 5898.   1990                advance(",");
 5899.   1990                if (token_nxt.id === "}") {
 5900.   1990
 5901.   1990// test_cause:
 5902.   1990// ["let aa={aa:0,}", "prefix_lbrace", "unexpected_a", ",", 13]
 5903.   1990
 5904.   1990                    warn("unexpected_a", token_now);
 5905.   1990                    break;
 5906.   1990                }
 5907.   1990            }
 5908.    583        }
 5909.    583
 5910.    583// test_cause:
 5911.    583// ["aa={bb,aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
 5912.    583
 5913.    583        check_ordered(
 5914.    583            "property",
 5915.   1985            the_brace.expression.map(function ({
 5916.   1985                label
 5917.   1985            }) {
 5918.   1985                return label;
 5919.   1985            })
 5920.    583        );
 5921.    583        advance("}");
 5922.    583        return the_brace;
 5923.    583    }
 5924.    629
 5925.    759    function prefix_lbracket() {
 5926.    759        const the_token = token_now;
 5927.    759        let element;
 5928.    759        let ellipsis;
 5929.    759        the_token.expression = [];
 5930.    392        if (token_nxt.id !== "]") {
 5931.    392
 5932.    392// Parse/loop through each element in [...].
 5933.    392
 5934.   1884            while (true) {
 5935.   1884                ellipsis = false;
 5936.   1884                if (token_nxt.id === "...") {
 5937.   1884                    ellipsis = true;
 5938.   1884                    advance("...");
 5939.   1884                }
 5940.   1884                element = parse_expression(10);
 5941.   1884                if (ellipsis) {
 5942.   1884                    element.ellipsis = true;
 5943.   1884                }
 5944.   1884                the_token.expression.push(element);
 5945.   1884                if (token_nxt.id !== ",") {
 5946.   1884                    break;
 5947.   1884                }
 5948.   1884                advance(",");
 5949.   1884                if (token_nxt.id === "]") {
 5950.   1884
 5951.   1884// test_cause:
 5952.   1884// ["let aa=[0,]", "prefix_lbracket", "unexpected_a", ",", 10]
 5953.   1884
 5954.   1884                    warn("unexpected_a", token_now);
 5955.   1884                    break;
 5956.   1884                }
 5957.   1884            }
 5958.    392        }
 5959.    759        advance("]");
 5960.    759        return the_token;
 5961.    759    }
 5962.    629
 5963.   1616    function prefix_lparen() {
 5964.   1616        let the_paren = token_now;
 5965.   1616        let the_value;
 5966.   1616
 5967.   1616// PR-385 - Bugfix - Fixes issue #382 - failure to detect destructured fart.
 5968.   1616
 5969.     14        if (token_now.fart) {
 5970.     14            return parse_fart(token_now.fart);
 5971.   1602        }
 5972.   1602
 5973.   1602// test_cause:
 5974.   1602// ["(0)", "prefix_lparen", "expr", "", 0]
 5975.   1602
 5976.   1602        test_cause("expr");
 5977.   1602        the_paren.free = true;
 5978.   1602        the_value = parse_expression(0);
 5979.   1602        if (the_value.wrapped === true) {
 5980.      1
 5981.      1// test_cause:
 5982.      1// ["((0))", "prefix_lparen", "unexpected_a", "(", 1]
 5983.      1
 5984.      1            warn("unexpected_a", the_paren);
 5985.   1602        }
 5986.   1602        the_value.wrapped = true;
 5987.   1602        advance(")", the_paren);
 5988.   1602        return the_value;
 5989.   1602    }
 5990.    629
 5991.    155    function prefix_new() {
 5992.    155        const the_new = token_now;
 5993.    155        let right;
 5994.    155        right = parse_expression(160);
 5995.      1        if (token_nxt.id !== "(") {
 5996.      1
 5997.      1// test_cause:
 5998.      1// ["new aa", "prefix_new", "expected_a_before_b", "(end)", 1]
 5999.      1
 6000.      1            warn("expected_a_before_b", token_nxt, "()", artifact());
 6001.      1        }
 6002.    155        the_new.expression = right;
 6003.    155        return the_new;
 6004.    155    }
 6005.    629
 6006.    782    function prefix_tick() {
 6007.    782        const the_tick = token_now;
 6008.    782        the_tick.value = [];
 6009.    782        the_tick.expression = [];
 6010.    782        if (token_nxt.id !== "`") {
 6011.    782
 6012.    782// Parse/loop through each token in `${...}`.
 6013.    782
 6014.   1499            while (true) {
 6015.   1499                advance("(string)");
 6016.   1499                the_tick.value.push(token_now);
 6017.   1499                if (token_nxt.id !== "${") {
 6018.   1499                    break;
 6019.   1499                }
 6020.   1499                advance("${");
 6021.   1499
 6022.   1499// test_cause:
 6023.   1499// ["let aa=`${}`;", "prefix_tick", "${", "", 0]
 6024.   1499
 6025.   1499                test_cause("${");
 6026.   1499                the_tick.expression.push(parse_expression(0));
 6027.   1499                advance("}");
 6028.   1499            }
 6029.    780        }
 6030.    780        advance("`");
 6031.    780        return the_tick;
 6032.    780    }
 6033.    629
 6034.      2    function prefix_void() {
 6035.      2        const the_void = token_now;
 6036.      2
 6037.      2// test_cause:
 6038.      2// ["void 0", "prefix_void", "unexpected_a", "void", 1]
 6039.      2// ["void", "prefix_void", "unexpected_a", "void", 1]
 6040.      2
 6041.      2        warn("unexpected_a", the_void);
 6042.      2        the_void.expression = parse_expression(0);
 6043.      2        return the_void;
 6044.      2    }
 6045.    629
 6046.  13416    function semicolon() {
 6047.  13416
 6048.  13416// Try to match a semicolon.
 6049.  13416
 6050.  13193        if (token_nxt.id === ";") {
 6051.  13193            advance(";");
 6052.  13193        } else {
 6053.    223
 6054.    223// test_cause:
 6055.    223// ["0", "semicolon", "expected_a_b", "(end)", 1]
 6056.    223
 6057.    223            warn_at(
 6058.    223                "expected_a_b",
 6059.    223                token_now.line,
 6060.    223                token_now.thru + 1,
 6061.    223                ";",
 6062.    223                artifact()
 6063.    223            );
 6064.    223        }
 6065.  13416        anon = "anonymous";
 6066.  13416    }
 6067.    629
 6068.  14467    function stmt(id, fud_stmt) {
 6069.  14467
 6070.  14467// Create a statement.
 6071.  14467
 6072.  14467        const the_symbol = symbol(id);
 6073.  14467        the_symbol.fud_stmt = fud_stmt;
 6074.  14467        return the_symbol;
 6075.  14467    }
 6076.    629
 6077.   1023    function stmt_break() {
 6078.   1023        const the_break = token_now;
 6079.   1023        let the_label;
 6080.   1023        if (
 6081.    719            (functionage.loop < 1 && functionage.switch < 1)
 6082.   1017            || functionage.finally > 0
 6083.      6        ) {
 6084.      6
 6085.      6// test_cause:
 6086.      6// ["break", "stmt_break", "unexpected_a", "break", 1]
 6087.      6
 6088.      6            warn("unexpected_a", the_break);
 6089.      6        }
 6090.   1023        the_break.disrupt = true;
 6091.      5        if (token_nxt.identifier && token_now.line === token_nxt.line) {
 6092.      5            the_label = functionage.context[token_nxt.id];
 6093.      5            if (
 6094.      5                the_label === undefined
 6095.      5                || the_label.role !== "label"
 6096.      5                || the_label.dead
 6097.      5            ) {
 6098.      5                if (the_label !== undefined && the_label.dead) {
 6099.      5
 6100.      5// test_cause:
 6101.      5// ["aa:{function aa(aa){break aa;}}", "stmt_break", "out_of_scope_a", "aa", 27]
 6102.      5
 6103.      5                    warn("out_of_scope_a");
 6104.      5                } else {
 6105.      5
 6106.      5// test_cause:
 6107.      5// ["aa:{break aa;}", "stmt_break", "not_label_a", "aa", 11]
 6108.      5
 6109.      5                    warn("not_label_a");
 6110.      5                }
 6111.      5            } else {
 6112.      5                the_label.used += 1;
 6113.      5            }
 6114.      5            the_break.label = token_nxt;
 6115.      5            advance();
 6116.      5        }
 6117.   1023        advance(";");
 6118.   1023        return the_break;
 6119.   1023    }
 6120.    629
 6121.      2    function stmt_continue() {
 6122.      2        const the_continue = token_now;
 6123.      1        if (functionage.loop < 1 || functionage.finally > 0) {
 6124.      2
 6125.      2// test_cause:
 6126.      2// ["continue", "stmt_continue", "unexpected_a", "continue", 1]
 6127.      2// ["
 6128.      2// function aa(){while(0){try{}finally{continue}}}
 6129.      2// ", "stmt_continue", "unexpected_a", "continue", 37]
 6130.      2
 6131.      2            warn("unexpected_a", the_continue);
 6132.      2        }
 6133.      2        check_not_top_level(the_continue);
 6134.      2        the_continue.disrupt = true;
 6135.      2        warn("unexpected_a", the_continue);
 6136.      2        advance(";");
 6137.      2        return the_continue;
 6138.      2    }
 6139.    629
 6140.      3    function stmt_debugger() {
 6141.      3        const the_debug = token_now;
 6142.      1        if (!option_dict.devel) {
 6143.      1
 6144.      1// test_cause:
 6145.      1// ["debugger", "stmt_debugger", "unexpected_a", "debugger", 1]
 6146.      1
 6147.      1            warn("unexpected_a", the_debug);
 6148.      1        }
 6149.      3        semicolon();
 6150.      3        return the_debug;
 6151.      3    }
 6152.    629
 6153.     72    function stmt_delete() {
 6154.     72        const the_token = token_now;
 6155.     72        const the_value = parse_expression(0);
 6156.     72        if (
 6157.      1            (the_value.id !== "." && the_value.id !== "[")
 6158.     71            || the_value.arity !== "binary"
 6159.      1        ) {
 6160.      1
 6161.      1// test_cause:
 6162.      1// ["delete 0", "stmt_delete", "expected_a_b", "0", 8]
 6163.      1
 6164.      1            stop("expected_a_b", the_value, ".", artifact(the_value));
 6165.     71        }
 6166.     71        the_token.expression = the_value;
 6167.     71        semicolon();
 6168.     71        return the_token;
 6169.     71    }
 6170.    629
 6171.      5    function stmt_do() {
 6172.      5        const the_do = token_now;
 6173.      5        check_not_top_level(the_do);
 6174.      5        functionage.loop += 1;
 6175.      5        the_do.block = block();
 6176.      5        advance("while");
 6177.      5        the_do.expression = condition();
 6178.      5        semicolon();
 6179.      1        if (the_do.block.disrupt === true) {
 6180.      1
 6181.      1// test_cause:
 6182.      1// ["function aa(){do{break;}while(0)}", "stmt_do", "weird_loop", "do", 15]
 6183.      1
 6184.      1            warn("weird_loop", the_do);
 6185.      3        }
 6186.      3        functionage.loop -= 1;
 6187.      3        return the_do;
 6188.      3    }
 6189.    629
 6190.     24    function stmt_export() {
 6191.     24        let export_list = [];
 6192.     24        let the_export = token_now;
 6193.     24        let the_id;
 6194.     24        let the_name;
 6195.     24        let the_thing;
 6196.     24
 6197.     24        the_export.expression = [];
 6198.     11        if (token_nxt.id === "default") {
 6199.     11            if (export_dict.default !== undefined) {
 6200.     11
 6201.     11// test_cause:
 6202.     11// ["
 6203.     11// export default 0;export default 0
 6204.     11// ", "stmt_export", "duplicate_a", "default", 25]
 6205.     11
 6206.     11                warn("duplicate_a");
 6207.     11            }
 6208.     11            advance("default");
 6209.     11            the_thing = parse_expression(0);
 6210.     11            if (
 6211.     11                the_thing.id !== "("
 6212.     11                || the_thing.expression[0].id !== "."
 6213.     11                || the_thing.expression[0].expression.id !== "Object"
 6214.     11                || the_thing.expression[0].name.id !== "freeze"
 6215.     11            ) {
 6216.     11
 6217.     11// test_cause:
 6218.     11// ["export default {}", "stmt_export", "freeze_exports", "{", 16]
 6219.     11
 6220.     11                warn("freeze_exports", the_thing);
 6221.     11
 6222.     11// PR-301 - Bugfix - Fixes issues #282 - optional-semicolon.
 6223.     11
 6224.     11            } else {
 6225.     11
 6226.     11// test_cause:
 6227.     11// ["
 6228.     11// export default Object.freeze({})
 6229.     11// ", "semicolon", "expected_a_b", "(end)", 32]
 6230.     11
 6231.     11                semicolon();
 6232.     11            }
 6233.     11            export_dict.default = the_thing;
 6234.     11            the_export.expression.push(the_thing);
 6235.     13        } else {
 6236.     13
 6237.     13// PR-439 - Add grammar for "export async function ...".
 6238.     13
 6239.     13            if (token_nxt.id === "function" || token_nxt.id === "async") {
 6240.     13
 6241.     13// test_cause:
 6242.     13// ["export async function aa(){}", "stmt_export", "freeze_exports", "async", 8]
 6243.     13// ["export function aa(){}", "stmt_export", "freeze_exports", "function", 8]
 6244.     13
 6245.     13                warn("freeze_exports");
 6246.     13                the_thing = parse_statement();
 6247.     13                the_name = the_thing.name;
 6248.     13                the_id = the_name.id;
 6249.     13                the_name.used += 1;
 6250.     13                if (export_dict[the_id] !== undefined) {
 6251.     13
 6252.     13// test_cause:
 6253.     13// ["
 6254.     13// let aa;export{aa};export function aa(){}
 6255.     13// ", "stmt_export", "duplicate_a", "aa", 35]
 6256.     13
 6257.     13                    warn("duplicate_a", the_name);
 6258.     13                }
 6259.     13                export_dict[the_id] = the_thing;
 6260.     13                the_export.expression.push(the_thing);
 6261.     13                the_thing.statement = false;
 6262.     13                the_thing.arity = "unary";
 6263.     13            } else if (
 6264.     13                token_nxt.id === "var"
 6265.     13                || token_nxt.id === "let"
 6266.     13                || token_nxt.id === "const"
 6267.     13            ) {
 6268.     13
 6269.     13// test_cause:
 6270.     13// ["export const", "stmt_export", "unexpected_a", "const", 8]
 6271.     13// ["export let", "stmt_export", "unexpected_a", "let", 8]
 6272.     13// ["export var", "stmt_export", "unexpected_a", "var", 8]
 6273.     13
 6274.     13                warn("unexpected_a");
 6275.     13                parse_statement();
 6276.     13            } else if (token_nxt.id === "{") {
 6277.     13
 6278.     13// test_cause:
 6279.     13// ["export {}", "stmt_export", "advance{", "", 0]
 6280.     13
 6281.     13                test_cause("advance{");
 6282.     13                advance("{");
 6283.     13                while (true) {
 6284.     13                    if (!token_nxt.identifier) {
 6285.     13
 6286.     13// test_cause:
 6287.     13// ["export {}", "stmt_export", "expected_identifier_a", "}", 9]
 6288.     13
 6289.     13                        stop("expected_identifier_a");
 6290.     13                    }
 6291.     13                    the_id = token_nxt.id;
 6292.     13                    export_list.push(token_nxt);
 6293.     13                    the_name = token_global.context[the_id];
 6294.     13                    if (the_name === undefined) {
 6295.     13
 6296.     13// test_cause:
 6297.     13// ["export {aa}", "stmt_export", "unexpected_a", "aa", 9]
 6298.     13
 6299.     13                        warn("unexpected_a");
 6300.     13                    } else {
 6301.     13                        the_name.used += 1;
 6302.     13                        if (export_dict[the_id] !== undefined) {
 6303.     13
 6304.     13// test_cause:
 6305.     13// ["let aa;export{aa,aa}", "stmt_export", "duplicate_a", "aa", 18]
 6306.     13
 6307.     13                            warn("duplicate_a");
 6308.     13                        }
 6309.     13                        export_dict[the_id] = the_name;
 6310.     13                    }
 6311.     13                    advance();
 6312.     13                    the_export.expression.push(the_thing);
 6313.     13                    if (token_nxt.id === ",") {
 6314.     13                        advance(",");
 6315.     13                    } else {
 6316.     13                        break;
 6317.     13                    }
 6318.     13                }
 6319.     13
 6320.     13// PR-439 - Check exported properties are ordered.
 6321.     13
 6322.     13// test_cause:
 6323.     13// ["export {bb, aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 13]
 6324.     13
 6325.     13                check_ordered("export", export_list);
 6326.     13                advance("}");
 6327.     13                semicolon();
 6328.     13            } else {
 6329.     13
 6330.     13// test_cause:
 6331.     13// ["export", "stmt_export", "unexpected_a", "(end)", 1]
 6332.     13
 6333.     13                stop("unexpected_a");
 6334.     13            }
 6335.     18        }
 6336.     18        state.mode_module = true;
 6337.     18        return the_export;
 6338.     18    }
 6339.    629
 6340.     12    function stmt_for() {
 6341.     12        let first;
 6342.     12        let the_for = token_now;
 6343.      7        if (!option_dict.for) {
 6344.      7
 6345.      7// test_cause:
 6346.      7// ["for", "stmt_for", "unexpected_a", "for", 1]
 6347.      7
 6348.      7            warn("unexpected_a", the_for);
 6349.      7        }
 6350.     12        check_not_top_level(the_for);
 6351.     12        functionage.loop += 1;
 6352.     12        advance("(");
 6353.     12        token_now.free = true;
 6354.      1        if (token_nxt.id === ";") {
 6355.      1
 6356.      1// test_cause:
 6357.      1// ["for(;;){}", "stmt_for", "expected_a_b", "for (;", 1]
 6358.      1
 6359.      1            return stop("expected_a_b", the_for, "while (", "for (;");
 6360.      9        }
 6361.      9        switch (token_nxt.id) {
 6362.      9        case "const":
 6363.      1        case "let":
 6364.      1        case "var":
 6365.      1
 6366.      1// test_cause:
 6367.      1// ["for(const aa in aa){}", "stmt_for", "unexpected_a", "const", 5]
 6368.      1
 6369.      1            return stop("unexpected_a");
 6370.      8        }
 6371.      8        first = parse_expression(0);
 6372.      8        if (first.id === "in") {
 6373.      2            if (first.expression[0].arity !== "variable") {
 6374.      2
 6375.      2// test_cause:
 6376.      2// ["for(0 in aa){}", "stmt_for", "bad_assignment_a", "0", 5]
 6377.      2
 6378.      2                warn("bad_assignment_a", first.expression[0]);
 6379.      2            }
 6380.      2            the_for.name = first.expression[0];
 6381.      2            the_for.expression = first.expression[1];
 6382.      2            warn("expected_a_b", the_for, "Object.keys", "for in");
 6383.      6        } else {
 6384.      6            the_for.initial = first;
 6385.      6            advance(";");
 6386.      6            the_for.expression = parse_expression(0);
 6387.      6            advance(";");
 6388.      6            the_for.inc = parse_expression(0);
 6389.      6            if (the_for.inc.id === "++") {
 6390.      6
 6391.      6// test_cause:
 6392.      6// ["for(aa;aa;aa++){}", "stmt_for", "expected_a_b", "++", 13]
 6393.      6
 6394.      6                warn("expected_a_b", the_for.inc, "+= 1", "++");
 6395.      6            }
 6396.      8        }
 6397.      8        advance(")");
 6398.      8        the_for.block = block();
 6399.      8        if (the_for.block.disrupt === true) {
 6400.      1
 6401.      1// test_cause:
 6402.      1// ["
 6403.      1// /*jslint for*/
 6404.      1// function aa(bb,cc){for(0;0;0){break;}}
 6405.      1// ", "stmt_for", "weird_loop", "for", 20]
 6406.      1
 6407.      1            warn("weird_loop", the_for);
 6408.      8        }
 6409.      8        functionage.loop -= 1;
 6410.      8        return the_for;
 6411.      8    }
 6412.    629
 6413.   3040    function stmt_if() {
 6414.   3040        const the_if = token_now;
 6415.   3040        let the_else;
 6416.   3040        the_if.expression = condition();
 6417.   3040        the_if.block = block();
 6418.    642        if (token_nxt.id === "else") {
 6419.    642            advance("else");
 6420.    642            the_else = token_now;
 6421.    642            the_if.else = (
 6422.    642                token_nxt.id === "if"
 6423.    642                ? parse_statement()
 6424.    642                : block()
 6425.    642            );
 6426.    642
 6427.    642// test_cause:
 6428.    642// ["if(0){0}else if(0){0}", "stmt_if", "else", "", 0]
 6429.    642// ["if(0){0}else{0}", "stmt_if", "else", "", 0]
 6430.    642
 6431.    642            test_cause("else");
 6432.    642            if (the_if.block.disrupt === true) {
 6433.    642                if (the_if.else.disrupt === true) {
 6434.    642
 6435.    642// test_cause:
 6436.    642// ["if(0){break;}else{break;}", "stmt_if", "disrupt", "", 0]
 6437.    642
 6438.    642                    test_cause("disrupt");
 6439.    642                    the_if.disrupt = true;
 6440.    642                } else {
 6441.    642
 6442.    642// test_cause:
 6443.    642// ["if(0){break;}else{}", "stmt_if", "unexpected_a", "else", 14]
 6444.    642
 6445.    642                    warn("unexpected_a", the_else);
 6446.    642                }
 6447.    642            }
 6448.   3039        }
 6449.   3039        return the_if;
 6450.   3039    }
 6451.    629
 6452.     62    function stmt_import() {
 6453.     62        const the_import = token_now;
 6454.     62        let name;
 6455.     62        let names;
 6456.     62
 6457.     62// PR-347 - Disable warning "unexpected_directive_a".
 6458.     62//
 6459.     62//         if (typeof state.mode_module === "object") {
 6460.     62//
 6461.     62// // test_cause:
 6462.     62// // ["
 6463.     62// // /*global aa*/
 6464.     62// // import aa from "aa"
 6465.     62// // ", "stmt_import", "unexpected_directive_a", "global", 1]
 6466.     62//
 6467.     62//             warn(
 6468.     62//                 "unexpected_directive_a",
 6469.     62//                 state.mode_module,
 6470.     62//                 state.mode_module.directive
 6471.     62//             );
 6472.     62//         }
 6473.     62
 6474.     62        state.mode_module = true;
 6475.     62
 6476.     62// PR-436 - Add grammar for side-effect import-statement.
 6477.     62
 6478.      1        if (token_nxt.id === "(string)") {
 6479.      1
 6480.      1// test_cause:
 6481.      1// ["import \"./aa.mjs\";", "stmt_import", "import_side_effect", "", 0]
 6482.      1
 6483.      1            test_cause("import_side_effect");
 6484.      1            warn("expected_a_b", token_nxt, "{", artifact());
 6485.      1            advance();
 6486.      1            semicolon();
 6487.      1            return the_import;
 6488.     61        }
 6489.     61        if (token_nxt.identifier) {
 6490.     57            name = token_nxt;
 6491.     57            advance();
 6492.     57            if (name.id === "ignore") {
 6493.     57
 6494.     57// test_cause:
 6495.     57// ["import ignore from \"aa\"", "stmt_import", "unexpected_a", "ignore", 8]
 6496.     57
 6497.     57                warn("unexpected_a", name);
 6498.     57            }
 6499.     57            enroll(name, "variable", true);
 6500.     57            the_import.name = name;
 6501.     57        } else {
 6502.      4            names = [];
 6503.      4            advance("{");
 6504.      4            if (token_nxt.id !== "}") {
 6505.      4                while (true) {
 6506.      4                    if (!token_nxt.identifier) {
 6507.      4
 6508.      4// test_cause:
 6509.      4// ["import {", "stmt_import", "expected_identifier_a", "(end)", 1]
 6510.      4
 6511.      4                        stop("expected_identifier_a");
 6512.      4                    }
 6513.      4                    name = token_nxt;
 6514.      4                    advance();
 6515.      4                    if (name.id === "ignore") {
 6516.      4
 6517.      4// test_cause:
 6518.      4// ["import {ignore} from \"aa\"", "stmt_import", "unexpected_a", "ignore", 9]
 6519.      4
 6520.      4                        warn("unexpected_a", name);
 6521.      4                    }
 6522.      4                    enroll(name, "variable", true);
 6523.      4                    names.push(name);
 6524.      4                    if (token_nxt.id !== ",") {
 6525.      4                        break;
 6526.      4                    }
 6527.      4                    advance(",");
 6528.      4                }
 6529.      4            }
 6530.      4            advance("}");
 6531.      4            the_import.name = names;
 6532.     60        }
 6533.     60        advance("from");
 6534.     60        advance("(string)");
 6535.     60        the_import.import = token_now;
 6536.     60        if (!jslint_rgx_module.test(token_now.value)) {
 6537.      1
 6538.      1// test_cause:
 6539.      1// ["import aa from \"!aa\"", "stmt_import", "bad_module_name_a", "!aa", 16]
 6540.      1
 6541.      1            warn("bad_module_name_a", token_now);
 6542.     60        }
 6543.     60        import_list.push(token_now.value);
 6544.     60        semicolon();
 6545.     60        return the_import;
 6546.     60    }
 6547.    629
 6548.      5    function stmt_lbrace() {
 6549.      5
 6550.      5// test_cause:
 6551.      5// [";{}", "stmt_lbrace", "naked_block", "{", 2]
 6552.      5// ["class aa{}", "stmt_lbrace", "naked_block", "{", 9]
 6553.      5
 6554.      5        warn("naked_block", token_now);
 6555.      5        return block("naked");
 6556.      5    }
 6557.    629
 6558.   1756    function stmt_return() {
 6559.   1756        const the_return = token_now;
 6560.   1756        check_not_top_level(the_return);
 6561.      1        if (functionage.finally > 0) {
 6562.      1
 6563.      1// test_cause:
 6564.      1// ["
 6565.      1// function aa(){try{}finally{return;}}
 6566.      1// ", "stmt_return", "unexpected_a", "return", 28]
 6567.      1
 6568.      1            warn("unexpected_a", the_return);
 6569.      1        }
 6570.   1756        the_return.disrupt = true;
 6571.   1504        if (token_nxt.id !== ";" && the_return.line === token_nxt.line) {
 6572.   1504            the_return.expression = parse_expression(10);
 6573.   1504        }
 6574.   1756        advance(";");
 6575.   1756        return the_return;
 6576.   1756    }
 6577.    629
 6578.      5    function stmt_semicolon() {
 6579.      5
 6580.      5// test_cause:
 6581.      5// [";", "stmt_semicolon", "unexpected_a", ";", 1]
 6582.      5
 6583.      5        warn("unexpected_a", token_now);
 6584.      5        return token_now;
 6585.      5    }
 6586.    629
 6587.    220    function stmt_switch() {
 6588.    220        const the_cases = [];
 6589.    220        const the_switch = token_now;
 6590.    220        let dups = [];
 6591.    220        let exp;
 6592.    220        let last;
 6593.    220        let stmts;
 6594.    220        let the_case;
 6595.    220        let the_default;
 6596.    220        let the_disrupt = true;
 6597.    220        let the_last;
 6598.  23088        function is_dup(thing) {
 6599.  23088            return is_equal(thing, exp);
 6600.  23088        }
 6601.    220        check_not_top_level(the_switch);
 6602.      1        if (functionage.finally > 0) {
 6603.      1
 6604.      1// test_cause:
 6605.      1// ["
 6606.      1// function aa(){try{}finally{switch(0){}}}
 6607.      1// ", "stmt_switch", "unexpected_a", "switch", 28]
 6608.      1
 6609.      1            warn("unexpected_a", the_switch);
 6610.      1        }
 6611.    220        functionage.switch += 1;
 6612.    220        advance("(");
 6613.    220        token_now.free = true;
 6614.    220        the_switch.expression = parse_expression(0);
 6615.    220        the_switch.block = the_cases;
 6616.    220        advance(")");
 6617.    220        advance("{");
 6618.   1085        while (true) {
 6619.   1085
 6620.   1085// Loop through cases with breaks.
 6621.   1085
 6622.   1085            the_case = token_nxt;
 6623.   1085            the_case.arity = "statement";
 6624.   1085            the_case.expression = [];
 6625.   1612            while (true) {
 6626.   1612
 6627.   1612// Loop through fallthrough cases.
 6628.   1612
 6629.   1612                advance("case");
 6630.   1612                token_now.switch = true;
 6631.   1612                exp = parse_expression(0);
 6632.   1612                if (dups.some(is_dup)) {
 6633.   1612
 6634.   1612// test_cause:
 6635.   1612// ["
 6636.   1612// switch(0){case 0:break;case 0:break}
 6637.   1612// ", "stmt_switch", "unexpected_a", "0", 29]
 6638.   1612
 6639.   1612                    warn("unexpected_a", exp);
 6640.   1612                }
 6641.   1612                dups.push(exp);
 6642.   1612                the_case.expression.push(exp);
 6643.   1612                advance(":");
 6644.   1612                if (token_nxt.id !== "case") {
 6645.   1612                    break;
 6646.   1612                }
 6647.   1612            }
 6648.   1085
 6649.   1085// test_cause:
 6650.   1085// ["
 6651.   1085// switch(0){case 1:case 0:break;}
 6652.   1085// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 23]
 6653.   1085// ["
 6654.   1085// switch(0){case "aa":case 0:break;}
 6655.   1085// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 26]
 6656.   1085// ["
 6657.   1085// switch(0){case "bb":case "aa":break;}
 6658.   1085// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 26]
 6659.   1085// ["
 6660.   1085// switch(0){case aa:case "aa":break;}
 6661.   1085// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
 6662.   1085// ["
 6663.   1085// switch(0){case bb:case aa:break;}
 6664.   1085// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
 6665.   1085
 6666.   1085            check_ordered_case(the_case.expression);
 6667.   1085            stmts = parse_statements();
 6668.   1085            if (stmts.length < 1) {
 6669.   1085
 6670.   1085// test_cause:
 6671.   1085// ["
 6672.   1085// switch(0){case 0:default:}
 6673.   1085// ", "stmt_switch", "expected_statements_a", "default", 18]
 6674.   1085// ["switch(0){case 0:}", "stmt_switch", "expected_statements_a", "}", 18]
 6675.   1085
 6676.   1085                warn("expected_statements_a");
 6677.   1085
 6678.   1085// PR-359 - Bugfix - Fixes issue #358 - switch-statement crashes jslint.
 6679.   1085
 6680.   1085                break;
 6681.   1085            }
 6682.   1085            the_case.block = stmts;
 6683.   1085            the_cases.push(the_case);
 6684.   1085            last = stmts[stmts.length - 1];
 6685.   1085            if (last.disrupt) {
 6686.   1085                if (last.id === "break" && last.label === undefined) {
 6687.   1085                    the_disrupt = false;
 6688.   1085                }
 6689.   1085            } else {
 6690.   1085                warn("expected_a_before_b", token_nxt, "break;", artifact());
 6691.   1085            }
 6692.   1085            if (token_nxt.id !== "case") {
 6693.   1085                break;
 6694.   1085            }
 6695.   1085        }
 6696.    217
 6697.    217// test_cause:
 6698.    217// ["
 6699.    217// switch(0){case 1:break;case 0:break;}
 6700.    217// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 29]
 6701.    217// ["
 6702.    217// switch(0){case "aa":break;case 0:break;}
 6703.    217// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 32]
 6704.    217// ["
 6705.    217// switch(0){case "bb":break;case "aa":break;}
 6706.    217// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 32]
 6707.    217// ["
 6708.    217// switch(0){case aa:break;case "aa":break;}
 6709.    217// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
 6710.    217// ["
 6711.    217// switch(0){case bb:break;case aa:break;}
 6712.    217// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
 6713.    217
 6714.   1080        check_ordered_case(the_cases.map(function ({
 6715.   1080            expression
 6716.   1080        }) {
 6717.   1080            return expression[0];
 6718.   1080        }));
 6719.    217        dups = undefined;
 6720.    217        if (token_nxt.id === "default") {
 6721.     99            the_default = token_nxt;
 6722.     99            advance("default");
 6723.     99            token_now.switch = true;
 6724.     99            advance(":");
 6725.     99            the_switch.else = parse_statements();
 6726.     99            if (the_switch.else.length < 1) {
 6727.     99
 6728.     99// test_cause:
 6729.     99// ["
 6730.     99// switch(0){case 0:break;default:}
 6731.     99// ", "stmt_switch", "unexpected_a", "default", 24]
 6732.     99
 6733.     99                warn("unexpected_a", the_default);
 6734.     99                the_disrupt = false;
 6735.     99            } else {
 6736.     99                the_last = the_switch.else[
 6737.     99                    the_switch.else.length - 1
 6738.     99                ];
 6739.     99                if (
 6740.     99                    the_last.id === "break"
 6741.     99                    && the_last.label === undefined
 6742.     99                ) {
 6743.     99
 6744.     99// test_cause:
 6745.     99// ["
 6746.     99// switch(0){case 0:break;default:break;}
 6747.     99// ", "stmt_switch", "unexpected_a", "break", 32]
 6748.     99
 6749.     99                    warn("unexpected_a", the_last);
 6750.     99                    the_last.disrupt = false;
 6751.     99                }
 6752.     99                the_disrupt = the_disrupt && the_last.disrupt;
 6753.     99            }
 6754.    118        } else {
 6755.    118            the_disrupt = false;
 6756.    217        }
 6757.    217        advance("}", the_switch);
 6758.    217        functionage.switch -= 1;
 6759.    217        the_switch.disrupt = the_disrupt;
 6760.    217        return the_switch;
 6761.    217    }
 6762.    629
 6763.     40    function stmt_throw() {
 6764.     40        const the_throw = token_now;
 6765.     40        the_throw.disrupt = true;
 6766.     40        the_throw.expression = parse_expression(10);
 6767.     40        semicolon();
 6768.      1        if (functionage.try > 0) {
 6769.      1
 6770.      1// test_cause:
 6771.      1// ["try{throw 0}catch(){}", "stmt_throw", "unexpected_a", "throw", 5]
 6772.      1
 6773.      1            warn("unexpected_a", the_throw);
 6774.      1        }
 6775.     40        return the_throw;
 6776.     40    }
 6777.    629
 6778.     62    function stmt_try() {
 6779.     62        const the_try = token_now;
 6780.     62        let ignored;
 6781.     62        let the_catch;
 6782.     62        let the_disrupt;
 6783.      1        if (functionage.try > 0) {
 6784.      1
 6785.      1// test_cause:
 6786.      1// ["try{try{}catch(){}}catch(){}", "stmt_try", "unexpected_a", "try", 5]
 6787.      1
 6788.      1            warn("unexpected_a", the_try);
 6789.      1        }
 6790.     62        functionage.try += 1;
 6791.     62        the_try.block = block();
 6792.     62        the_disrupt = the_try.block.disrupt;
 6793.     57        if (token_nxt.id === "catch") {
 6794.     57            ignored = "ignore";
 6795.     57            the_catch = token_nxt;
 6796.     57            the_try.catch = the_catch;
 6797.     57            advance("catch");
 6798.     57
 6799.     57// Create new catch-scope for catch-parameter.
 6800.     57
 6801.     57            catch_stack.push(catchage);
 6802.     57            catchage = the_catch;
 6803.     57            catch_list.push(catchage);
 6804.     57            the_catch.context = empty();
 6805.     57            if (token_nxt.id === "(") {
 6806.     57                advance("(");
 6807.     57                if (!token_nxt.identifier) {
 6808.     57
 6809.     57// test_cause:
 6810.     57// ["try{}catch(){}", "stmt_try", "expected_identifier_a", ")", 12]
 6811.     57
 6812.     57                    return stop("expected_identifier_a");
 6813.     57                }
 6814.     57                if (token_nxt.id !== "ignore") {
 6815.     57                    ignored = undefined;
 6816.     57                    the_catch.name = token_nxt;
 6817.     57                    enroll(token_nxt, "exception", true);
 6818.     57                }
 6819.     57                advance();
 6820.     57                advance(")");
 6821.     57            }
 6822.     57            the_catch.block = block(ignored);
 6823.     57            if (the_catch.block.disrupt !== true) {
 6824.     57                the_disrupt = false;
 6825.     57            }
 6826.     57
 6827.     57// Restore previous catch-scope after catch-block.
 6828.     57
 6829.     57            catchage = catch_stack.pop();
 6830.     57
 6831.     57// PR-404 - Relax warning about missing `catch` in `try...finally` statement.
 6832.     57//
 6833.     57//         } else {
 6834.     57//
 6835.     57// // test_cause:
 6836.     57// // ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
 6837.     57//
 6838.     57//             warn("expected_a_before_b", token_nxt, "catch", artifact());
 6839.     57
 6840.     58        }
 6841.     58        if (token_nxt.id === "finally") {
 6842.      4            functionage.finally += 1;
 6843.      4            advance("finally");
 6844.      4            the_try.else = block();
 6845.      4            the_disrupt = the_try.else.disrupt;
 6846.      4            functionage.finally -= 1;
 6847.     56        }
 6848.     56        the_try.disrupt = the_disrupt;
 6849.     56        functionage.try -= 1;
 6850.     56        return the_try;
 6851.     56    }
 6852.    629
 6853.   2328    function stmt_var() {
 6854.   2328        let ellipsis;
 6855.   2328        let mode_const;
 6856.   2328        let name;
 6857.   2328        let the_brace;
 6858.   2328        let the_bracket;
 6859.   2328        let the_variable = token_now;
 6860.   2328        let variable_prv;
 6861.   2328        mode_const = the_variable.id === "const";
 6862.   2328        the_variable.names = [];
 6863.   2328
 6864.   2328// A program may use var or let, but not both.
 6865.   2328
 6866.   2052        if (!mode_const) {
 6867.   2052            if (mode_var === undefined) {
 6868.   2052                mode_var = the_variable.id;
 6869.   2052            } else if (the_variable.id !== mode_var) {
 6870.   2052
 6871.   2052// test_cause:
 6872.   2052// ["let aa;var aa", "stmt_var", "expected_a_b", "var", 8]
 6873.   2052
 6874.   2052                warn("expected_a_b", the_variable, mode_var, the_variable.id);
 6875.   2052            }
 6876.   2052        }
 6877.   2328
 6878.   2328// We don't expect to see variables created in switch statements.
 6879.   2328
 6880.      1        if (functionage.switch > 0) {
 6881.      1
 6882.      1// test_cause:
 6883.      1// ["switch(0){case 0:var aa}", "stmt_var", "var_switch", "var", 18]
 6884.      1
 6885.      1            warn("var_switch", the_variable);
 6886.      1        }
 6887.   2328        switch (
 6888.   2328            Boolean(functionage.statement_prv)
 6889.   1449            && functionage.statement_prv.id
 6890.   2328        ) {
 6891.    107        case "const":
 6892.   1437        case "let":
 6893.   1439        case "var":
 6894.   1439
 6895.   1439// test_cause:
 6896.   1439// ["const aa=0;const bb=0;", "stmt_var", "var_prv", "const", 0]
 6897.   1439// ["let aa=0;let bb=0;", "stmt_var", "var_prv", "let", 0]
 6898.   1439// ["var aa=0;var bb=0;", "stmt_var", "var_prv", "var", 0]
 6899.   1439
 6900.   1439            test_cause("var_prv", functionage.statement_prv.id);
 6901.   1439            variable_prv = functionage.statement_prv;
 6902.   1439            break;
 6903.      3        case "import":
 6904.      3
 6905.      3// test_cause:
 6906.      3// ["import aa from \"aa\";\nlet bb=0;", "stmt_var", "import_prv", "", 0]
 6907.      3
 6908.      3            test_cause("import_prv");
 6909.      3            break;
 6910.    879        case false:
 6911.    879            break;
 6912.      7        default:
 6913.      7            if (
 6914.      7                (option_dict.beta && !option_dict.variable)
 6915.      7                || the_variable.id === "var"
 6916.      7            ) {
 6917.      7
 6918.      7// test_cause:
 6919.      7// ["console.log();let aa=0;", "stmt_var", "var_on_top", "let", 15]
 6920.      7// ["console.log();var aa=0;", "stmt_var", "var_on_top", "var", 15]
 6921.      7// ["try{aa();}catch(aa){var aa=0;}", "stmt_var", "var_on_top", "var", 21]
 6922.      7// ["while(0){var aa;}", "stmt_var", "var_on_top", "var", 10]
 6923.      7
 6924.      7                warn("var_on_top", token_now);
 6925.      7            }
 6926.   2328        }
 6927.   2329        while (true) {
 6928.   2329            if (token_nxt.id === "{") {
 6929.   2329                if (the_variable.id === "var") {
 6930.   2329
 6931.   2329// test_cause:
 6932.   2329// ["var{aa}=0", "stmt_var", "unexpected_a", "var", 1]
 6933.   2329
 6934.   2329                    warn("unexpected_a", the_variable);
 6935.   2329                }
 6936.   2329                the_brace = token_nxt;
 6937.   2329                advance("{");
 6938.   2329                while (true) {
 6939.   2329                    name = token_nxt;
 6940.   2329                    if (!name.identifier) {
 6941.   2329
 6942.   2329// test_cause:
 6943.   2329// ["let {0}", "stmt_var", "expected_identifier_a", "0", 6]
 6944.   2329
 6945.   2329                        return stop("expected_identifier_a");
 6946.   2329                    }
 6947.   2329                    survey(name);
 6948.   2329                    advance();
 6949.   2329                    if (token_nxt.id === ":") {
 6950.   2329                        advance(":");
 6951.   2329                        if (!token_nxt.identifier) {
 6952.   2329
 6953.   2329// test_cause:
 6954.   2329// ["let {aa:0}", "stmt_var", "expected_identifier_a", "0", 9]
 6955.   2329// ["let {aa:{aa}}", "stmt_var", "expected_identifier_a", "{", 9]
 6956.   2329
 6957.   2329                            return stop("expected_identifier_a");
 6958.   2329                        }
 6959.   2329
 6960.   2329// PR-363 - Bugfix
 6961.   2329// Add test against false-warning <uninitialized 'bb'> in code
 6962.   2329// '/*jslint node*/\nlet {aa:bb} = {}; bb();'.
 6963.   2329//
 6964.   2329//                         token_nxt.label = name;
 6965.   2329//                         the_variable.names.push(token_nxt);
 6966.   2329//                         enroll(token_nxt, "variable", mode_const);
 6967.   2329
 6968.   2329                        name = token_nxt;
 6969.   2329                        the_variable.names.push(name);
 6970.   2329                        survey(name);
 6971.   2329                        enroll(name, "variable", mode_const);
 6972.   2329
 6973.   2329                        advance();
 6974.   2329                        the_brace.open = true;
 6975.   2329                    } else {
 6976.   2329                        the_variable.names.push(name);
 6977.   2329                        enroll(name, "variable", mode_const);
 6978.   2329                    }
 6979.   2329                    name.dead = false;
 6980.   2329                    name.init = true;
 6981.   2329                    if (token_nxt.id === "=") {
 6982.   2329
 6983.   2329// test_cause:
 6984.   2329// ["let {aa=0}", "stmt_var", "assign", "", 0]
 6985.   2329
 6986.   2329                        test_cause("assign");
 6987.   2329                        advance("=");
 6988.   2329                        name.expression = parse_expression();
 6989.   2329                        the_brace.open = true;
 6990.   2329                    }
 6991.   2329                    if (token_nxt.id !== ",") {
 6992.   2329                        break;
 6993.   2329                    }
 6994.   2329                    advance(",");
 6995.   2329                }
 6996.   2329
 6997.   2329// test_cause:
 6998.   2329// ["let{bb,aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
 6999.   2329
 7000.   2329                check_ordered(the_variable.id, the_variable.names);
 7001.   2329                advance("}");
 7002.   2329                advance("=");
 7003.   2329                the_variable.expression = parse_expression(0);
 7004.   2329            } else if (token_nxt.id === "[") {
 7005.   2329                if (the_variable.id === "var") {
 7006.   2329
 7007.   2329// test_cause:
 7008.   2329// ["var[aa]=0", "stmt_var", "unexpected_a", "var", 1]
 7009.   2329
 7010.   2329                    warn("unexpected_a", the_variable);
 7011.   2329                }
 7012.   2329                the_bracket = token_nxt;
 7013.   2329                advance("[");
 7014.   2329                while (true) {
 7015.   2329                    ellipsis = false;
 7016.   2329                    if (token_nxt.id === "...") {
 7017.   2329                        ellipsis = true;
 7018.   2329                        advance("...");
 7019.   2329                    }
 7020.   2329                    if (!token_nxt.identifier) {
 7021.   2329
 7022.   2329// test_cause:
 7023.   2329// ["let[]", "stmt_var", "expected_identifier_a", "]", 5]
 7024.   2329
 7025.   2329                        return stop("expected_identifier_a");
 7026.   2329                    }
 7027.   2329                    name = token_nxt;
 7028.   2329                    advance();
 7029.   2329                    the_variable.names.push(name);
 7030.   2329                    enroll(name, "variable", mode_const);
 7031.   2329                    name.dead = false;
 7032.   2329                    name.init = true;
 7033.   2329                    if (ellipsis) {
 7034.   2329                        name.ellipsis = true;
 7035.   2329                        break;
 7036.   2329                    }
 7037.   2329                    if (token_nxt.id === "=") {
 7038.   2329                        advance("=");
 7039.   2329                        name.expression = parse_expression();
 7040.   2329                        the_bracket.open = true;
 7041.   2329                    }
 7042.   2329                    if (token_nxt.id !== ",") {
 7043.   2329                        break;
 7044.   2329                    }
 7045.   2329                    advance(",");
 7046.   2329                }
 7047.   2329                advance("]");
 7048.   2329                advance("=");
 7049.   2329                the_variable.expression = parse_expression(0);
 7050.   2329            } else if (token_nxt.identifier) {
 7051.   2329                name = token_nxt;
 7052.   2329                advance();
 7053.   2329                if (name.id === "ignore") {
 7054.   2329
 7055.   2329// test_cause:
 7056.   2329// ["
 7057.   2329// let ignore;function aa(ignore) {}
 7058.   2329// ", "stmt_var", "unexpected_a", "ignore", 5]
 7059.   2329
 7060.   2329                    warn("unexpected_a", name);
 7061.   2329                }
 7062.   2329                enroll(name, "variable", mode_const);
 7063.   2329                if (token_nxt.id === "=" || mode_const) {
 7064.   2329                    advance("=");
 7065.   2329                    name.dead = false;
 7066.   2329                    name.init = true;
 7067.   2329                    name.expression = parse_expression(0);
 7068.   2329                }
 7069.   2329                the_variable.names.push(name);
 7070.   2329            } else {
 7071.   2329
 7072.   2329// test_cause:
 7073.   2329// ["let 0", "stmt_var", "expected_identifier_a", "0", 5]
 7074.   2329// ["var{aa:{aa}}", "stmt_var", "expected_identifier_a", "{", 8]
 7075.   2329
 7076.   2329                return stop("expected_identifier_a");
 7077.   2329            }
 7078.   2329            if (token_nxt.id !== ",") {
 7079.   2329                break;
 7080.   2329            }
 7081.   2329
 7082.   2329// test_cause:
 7083.   2329// ["let aa,bb;", "stmt_var", "expected_a_b", ",", 7]
 7084.   2329
 7085.   2329            warn("expected_a_b", token_nxt, ";", ",");
 7086.   2329            advance(",");
 7087.   2329        }
 7088.   2314
 7089.   2314// Warn if variable declarations are unordered.
 7090.   2314
 7091.   2314        if (
 7092.   2314            option_dict.beta
 7093.   2314            && !option_dict.unordered
 7094.   2309            && !option_dict.variable
 7095.   2303            && variable_prv
 7096.   1437            && (
 7097.   1437                variable_prv.id + " " + variable_prv.names[0].id
 7098.   1437                > the_variable.id + " " + the_variable.names[0].id
 7099.   1437            )
 7100.      3        ) {
 7101.      3
 7102.      3// test_cause:
 7103.      3// ["const bb=0;const aa=0;", "stmt_var", "expected_a_b_before_c_d", "aa", 12]
 7104.      3// ["let bb;let aa;", "stmt_var", "expected_a_b_before_c_d", "aa", 8]
 7105.      3// ["var bb;var aa;", "stmt_var", "expected_a_b_before_c_d", "aa", 8]
 7106.      3
 7107.      3            warn(
 7108.      3                "expected_a_b_before_c_d",
 7109.      3                the_variable,
 7110.      3                the_variable.id,
 7111.      3                the_variable.names[0].id,
 7112.      3                variable_prv.id,
 7113.      3                variable_prv.names[0].id
 7114.      3            );
 7115.   2314        }
 7116.   2314        semicolon();
 7117.   2314        return the_variable;
 7118.   2314    }
 7119.    629
 7120.    208    function stmt_while() {
 7121.    208        const the_while = token_now;
 7122.    208        check_not_top_level(the_while);
 7123.    208        functionage.loop += 1;
 7124.    208        the_while.expression = condition();
 7125.    208        the_while.block = block();
 7126.      1        if (the_while.block.disrupt === true) {
 7127.      1
 7128.      1// test_cause:
 7129.      1// ["function aa(){while(0){break;}}", "stmt_while", "weird_loop", "while", 15]
 7130.      1
 7131.      1            warn("weird_loop", the_while);
 7132.    205        }
 7133.    205        functionage.loop -= 1;
 7134.    205        return the_while;
 7135.    205    }
 7136.    629
 7137.      1    function stmt_with() {
 7138.      1
 7139.      1// test_cause:
 7140.      1// ["with", "stmt_with", "unexpected_a", "with", 1]
 7141.      1
 7142.      1        stop("unexpected_a", token_now);
 7143.      1    }
 7144.    629
 7145.  14571    function survey(name) {
 7146.  14571        let id = name.id;
 7147.  14571
 7148.  14571// Tally the property name. If it is a string, only tally strings that conform
 7149.  14571// to the identifier rules.
 7150.  14571
 7151.    183        if (id === "(string)") {
 7152.    183            id = name.value;
 7153.    183            if (!jslint_rgx_identifier.test(id)) {
 7154.    183                return id;
 7155.    183            }
 7156.  14388        } else if (id === "`") {
 7157.  14388            if (name.value.length === 1) {
 7158.  14388                id = name.value[0].value;
 7159.  14388                if (!jslint_rgx_identifier.test(id)) {
 7160.  14388                    return id;
 7161.  14388                }
 7162.  14388            }
 7163.  14388        } else if (!name.identifier) {
 7164.  14388
 7165.  14388// test_cause:
 7166.  14388// ["let aa={0:0}", "survey", "expected_identifier_a", "0", 9]
 7167.  14388
 7168.  14388            return stop("expected_identifier_a", name);
 7169.  14484        }
 7170.  14484
 7171.  14484// If we have seen this name before, increment its count.
 7172.  14484
 7173.  14484        if (typeof property_dict[id] === "number") {
 7174.  12064            property_dict[id] += 1;
 7175.  12064
 7176.  12064// If this is the first time seeing this property name, and if there is a
 7177.  12064// tenure list, then it must be on the list. Otherwise, it must conform to
 7178.  12064// the rules for good property names.
 7179.  12064
 7180.  12064        } else {
 7181.   2420            if (state.mode_property) {
 7182.   2420                if (tenure[id] !== true) {
 7183.   2420
 7184.   2420// test_cause:
 7185.   2420// ["/*property aa*/\naa.bb", "survey", "unregistered_property_a", "bb", 4]
 7186.   2420
 7187.   2420                    warn("unregistered_property_a", name);
 7188.   2420                }
 7189.   2420            } else if (
 7190.   2420                !option_dict.nomen
 7191.   2420                && name.identifier
 7192.   2420                && jslint_rgx_weird_property.test(id)
 7193.   2420            ) {
 7194.   2420
 7195.   2420// test_cause:
 7196.   2420// ["aa.$", "survey", "weird_property_a", "$", 4]
 7197.   2420// ["aa._", "survey", "weird_property_a", "_", 4]
 7198.   2420// ["aa._aa", "survey", "weird_property_a", "_aa", 4]
 7199.   2420// ["aa.aaSync", "survey", "weird_property_a", "aaSync", 4]
 7200.   2420// ["aa.aa_", "survey", "weird_property_a", "aa_", 4]
 7201.   2420
 7202.   2420                warn("weird_property_a", name);
 7203.   2420            }
 7204.   2420            property_dict[id] = 1;
 7205.  14484        }
 7206.  14484        return id;
 7207.  14484    }
 7208.    629
 7209.    629// These functions are used to specify the grammar of our language:
 7210.    629
 7211.  81770    function symbol(id, bp) {
 7212.  81770
 7213.  81770// Create a symbol if it does not already exist in the language's syntax.
 7214.  81770
 7215.  81770        let the_symbol = syntax_dict[id];
 7216.  71077        if (the_symbol === undefined) {
 7217.  71077            the_symbol = empty();
 7218.  71077            the_symbol.id = id;
 7219.  71077            the_symbol.lbp = bp || 0;
 7220.  71077            syntax_dict[id] = the_symbol;
 7221.  71077        }
 7222.  81770        return the_symbol;
 7223.  81770    }
 7224.    629
 7225.    629    function ternary(id1, id2) {
 7226.    629
 7227.    629// Create a ternary operator.
 7228.    629
 7229.    629        const the_symbol = symbol(id1, 30);
 7230.    219        the_symbol.led_infix = function parse_ternary_led(left) {
 7231.    219            const the_token = token_now;
 7232.    219            let second;
 7233.    219            second = parse_expression(20);
 7234.    219            advance(id2);
 7235.    219            token_now.arity = "ternary";
 7236.    219            the_token.arity = "ternary";
 7237.    219            the_token.expression = [left, second, parse_expression(10)];
 7238.      5            if (token_nxt.id !== ")") {
 7239.      5
 7240.      5// test_cause:
 7241.      5// ["0?0:0", "parse_ternary_led", "use_open", "?", 2]
 7242.      5
 7243.      5                warn("use_open", the_token);
 7244.      5            }
 7245.    219            return the_token;
 7246.    219        };
 7247.    629        return the_symbol;
 7248.    629    }
 7249.    629
 7250.    629// Now we parse JavaScript.
 7251.    629// Begin defining the language.
 7252.    629
 7253.    629    assignment("%=");
 7254.    629    assignment("&=");
 7255.    629    assignment("*=");
 7256.    629    assignment("+=");
 7257.    629    assignment("-=");
 7258.    629    assignment("/=");
 7259.    629    assignment("<<=");
 7260.    629    assignment("=");
 7261.    629    assignment(">>=");
 7262.    629    assignment(">>>=");
 7263.    629    assignment("^=");
 7264.    629    assignment("|=");
 7265.    629    constant("(number)", "number");
 7266.    629    constant("(regexp)", "regexp");
 7267.    629    constant("(string)", "string");
 7268.    629    constant("Function", "function", constant_Function);
 7269.    629    constant("Infinity", "number", Infinity);
 7270.    629    constant("NaN", "number", NaN);
 7271.    629    constant("arguments", "object", constant_arguments);
 7272.    629    constant("eval", "function", constant_eval);
 7273.    629    constant("false", "boolean", false);
 7274.    629    constant("ignore", "undefined", constant_ignore);
 7275.    629    constant("isFinite", "function", constant_isInfinite);
 7276.    629    constant("isNaN", "function", constant_isNaN);
 7277.    629    constant("null", "null", null);
 7278.    629    constant("this", "object", constant_this);
 7279.    629    constant("true", "boolean", true);
 7280.    629    constant("undefined", "undefined");
 7281.    629    infix(100, "!=");
 7282.    629    infix(100, "!==");
 7283.    629    infix(100, "==");
 7284.    629    infix(100, "===");
 7285.    629    infix(110, "<");
 7286.    629    infix(110, "<=");
 7287.    629    infix(110, ">");
 7288.    629    infix(110, ">=");
 7289.    629    infix(110, "in");
 7290.    629    infix(110, "instanceof");
 7291.    629    infix(120, "<<");
 7292.    629    infix(120, ">>");
 7293.    629    infix(120, ">>>");
 7294.    629    infix(130, "+");
 7295.    629    infix(130, "-");
 7296.    629    infix(140, "%");
 7297.    629    infix(140, "*");
 7298.    629    infix(140, "/");
 7299.    629    infix(160, "(", infix_lparen);
 7300.    629    infix(160, "`", infix_grave);
 7301.    629    infix(170, ".", infix_dot);
 7302.    629    infix(170, "=>", infix_fart_unwrapped);
 7303.    629    infix(170, "?.", infix_option_chain);
 7304.    629    infix(170, "[", infix_lbracket);
 7305.    629    infix(35, "??");
 7306.    629    infix(40, "||");
 7307.    629    infix(50, "&&");
 7308.    629    infix(70, "|");
 7309.    629    infix(80, "^");
 7310.    629    infix(90, "&");
 7311.    629    infixr(150, "**");
 7312.    629    postassign("++");
 7313.    629    postassign("--");
 7314.    629    preassign("++");
 7315.    629    preassign("--");
 7316.    629    prefix("!!");
 7317.    629    prefix("!");
 7318.    629    prefix("(", prefix_lparen);
 7319.    629    prefix("+");
 7320.    629    prefix("-");
 7321.    629    prefix("/=", prefix_assign_divide);
 7322.    629    prefix("=>", prefix_fart);
 7323.    629    prefix("[", prefix_lbracket);
 7324.    629    prefix("`", prefix_tick);
 7325.    629    prefix("async", prefix_async);
 7326.    629    prefix("await", prefix_await);
 7327.    629    prefix("function", prefix_function);
 7328.    629    prefix("new", prefix_new);
 7329.    629    prefix("typeof");
 7330.    629    prefix("void", prefix_void);
 7331.    629    prefix("{", prefix_lbrace);
 7332.    629    prefix("~");
 7333.    629    stmt(";", stmt_semicolon);
 7334.    629    stmt("async", prefix_async);
 7335.    629    stmt("await", prefix_await);
 7336.    629    stmt("break", stmt_break);
 7337.    629    stmt("const", stmt_var);
 7338.    629    stmt("continue", stmt_continue);
 7339.    629    stmt("debugger", stmt_debugger);
 7340.    629    stmt("delete", stmt_delete);
 7341.    629    stmt("do", stmt_do);
 7342.    629    stmt("export", stmt_export);
 7343.    629    stmt("for", stmt_for);
 7344.    629    stmt("function", prefix_function);
 7345.    629    stmt("if", stmt_if);
 7346.    629    stmt("import", stmt_import);
 7347.    629    stmt("let", stmt_var);
 7348.    629    stmt("return", stmt_return);
 7349.    629    stmt("switch", stmt_switch);
 7350.    629    stmt("throw", stmt_throw);
 7351.    629    stmt("try", stmt_try);
 7352.    629    stmt("var", stmt_var);
 7353.    629    stmt("while", stmt_while);
 7354.    629    stmt("with", stmt_with);
 7355.    629    stmt("{", stmt_lbrace);
 7356.    629    symbol(")");
 7357.    629    symbol("*/");
 7358.    629    symbol(",");
 7359.    629    symbol(":");
 7360.    629    symbol(";");
 7361.    629    symbol("]");
 7362.    629    symbol("async");
 7363.    629    symbol("await");
 7364.    629    symbol("case");
 7365.    629    symbol("catch");
 7366.    629    symbol("class");
 7367.    629    symbol("default");
 7368.    629    symbol("else");
 7369.    629    symbol("enum");
 7370.    629    symbol("finally");
 7371.    629    symbol("implements");
 7372.    629    symbol("interface");
 7373.    629    symbol("package");
 7374.    629    symbol("private");
 7375.    629    symbol("protected");
 7376.    629    symbol("public");
 7377.    629    symbol("static");
 7378.    629    symbol("super");
 7379.    629    symbol("void");
 7380.    629    symbol("yield");
 7381.    629    symbol("}");
 7382.    629    ternary("?", ":");
 7383.    629
 7384.    629// Init token_nxt.
 7385.    629
 7386.    629    advance();
 7387.    629
 7388.    629// Parsing of JSON is simple:
 7389.    629
 7390.     25    if (state.mode_json) {
 7391.     25        state.token_tree = parse_json();
 7392.     25        advance("(end)");
 7393.     25        return;
 7394.    604    }
 7395.    604
 7396.    604// Because browsers encourage combining of script files, the first token might
 7397.    604// be a semicolon to defend against a missing semicolon in the preceding file.
 7398.    604
 7399.    604    if (option_dict.browser) {
 7400.      5        if (token_nxt.id === ";") {
 7401.      5            advance(";");
 7402.      5        }
 7403.      5
 7404.      5// If we are not in a browser, then the file form of strict pragma may be used.
 7405.      5
 7406.    599    } else if (token_nxt.value === "use strict") {
 7407.    599        advance("(string)");
 7408.    599        advance(";");
 7409.    604    }
 7410.    604    state.token_tree = parse_statements();
 7411.    604    advance("(end)");
 7412.    604
 7413.    604// Check global functions are ordered.
 7414.    604
 7415.    604    check_ordered(
 7416.    604        "function",
 7417.   2001        function_list.map(function ({
 7418.   2001            level,
 7419.   2001            name
 7420.   2001        }) {
 7421.    604            return (level === 1) && name;
 7422.   2001        }).filter(function (name) {
 7423.   1992            return option_dict.beta && name && name.id;
 7424.   2001        })
 7425.    604    );
 7426.    604}
 7427.      1
 7428.    516function jslint_phase4_walk(state) {
 7429.    516
 7430.    516// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
 7431.    516//          recursive traversal. Each node may be processed on the way down
 7432.    516//          (preaction) and on the way up (postaction).
 7433.    516
 7434.    516    let {
 7435.    516        artifact,
 7436.    516        catch_stack,
 7437.    516        function_stack,
 7438.    516        global_dict,
 7439.    516        is_equal,
 7440.    516        is_weird,
 7441.    516        option_dict,
 7442.    516        syntax_dict,
 7443.    516        test_cause,
 7444.    516        token_global,
 7445.    516        warn
 7446.    516    } = state;
 7447.    516    let block_stack = [];               // The stack of blocks.
 7448.    516    let blockage = token_global;        // The current block.
 7449.    516    let catchage = catch_stack[0];      // The current catch-block.
 7450.    516    let functionage = token_global;     // The current function.
 7451.    516    let postaction;
 7452.    516    let postamble;
 7453.    516    let posts = empty();
 7454.    516    let preaction;
 7455.    516    let preamble;
 7456.    516    let pres = empty();
 7457.    516
 7458.    516// The relational operators.
 7459.    516
 7460.    516    let relationop = object_assign_from_list(empty(), [
 7461.    516        "!=", "!==", "<", "<=", "==", "===", ">", ">="
 7462.    516    ], true);
 7463.    516
 7464.    516// Ambulation of the parse tree.
 7465.    516
 7466.   1032    function action(when) {
 7467.   1032
 7468.   1032// Produce a function that will register task functions that will be called as
 7469.   1032// the tree is traversed.
 7470.   1032
 7471.  19608        return function (arity, id, task) {
 7472.  19608            let a_set = when[arity];
 7473.  19608            let i_set;
 7474.  19608
 7475.  19608// The id parameter is optional. If excluded, the task will be applied to all
 7476.  19608// ids.
 7477.  19608
 7478.   4128            if (typeof id !== "string") {
 7479.   4128                task = id;
 7480.   4128                id = "(all)";
 7481.   4128            }
 7482.  19608
 7483.  19608// If this arity has no registrations yet, then create a set object to hold
 7484.  19608// them.
 7485.  19608
 7486.   5160            if (a_set === undefined) {
 7487.   5160                a_set = empty();
 7488.   5160                when[arity] = a_set;
 7489.   5160            }
 7490.  19608
 7491.  19608// If this id has no registrations yet, then create a set array to hold them.
 7492.  19608
 7493.  19608            i_set = a_set[id];
 7494.  19092            if (i_set === undefined) {
 7495.  19092                i_set = [];
 7496.  19092                a_set[id] = i_set;
 7497.  19092            }
 7498.  19608
 7499.  19608// Register the task with the arity and the id.
 7500.  19608
 7501.  19608            i_set.push(task);
 7502.  19608        };
 7503.   1032    }
 7504.    516
 7505.   1032    function amble(when) {
 7506.   1032
 7507.   1032// Produce a function that will act on the tasks registered by an action
 7508.   1032// function while walking the tree.
 7509.   1032
 7510. 210640        return function (the_token) {
 7511. 210640
 7512. 210640// Given a task set that was built by an action function, run all
 7513. 210640// relevant tasks on the token.
 7514. 210640
 7515. 210640            let a_set = when[the_token.arity];
 7516. 210640            let i_set;
 7517. 210640
 7518. 210640// If there are tasks associated with the token's arity...
 7519. 210640
 7520. 144479            if (a_set !== undefined) {
 7521. 144479
 7522. 144479// If there are tasks associated with the token's id...
 7523. 144479
 7524. 144479                i_set = a_set[the_token.id];
 7525. 144479                if (i_set !== undefined) {
 7526. 144479                    i_set.forEach(function (task) {
 7527. 144479                        task(the_token);
 7528. 144479                    });
 7529. 144479                }
 7530. 144479
 7531. 144479// If there are tasks for all ids.
 7532. 144479
 7533. 144479                i_set = a_set["(all)"];
 7534. 144479                if (i_set !== undefined) {
 7535. 144479                    i_set.forEach(function (task) {
 7536. 144479                        task(the_token);
 7537. 144479                    });
 7538. 144479                }
 7539. 144479            }
 7540. 210640        };
 7541.   1032    }
 7542.    516
 7543.   2817    function init_variable(name) {
 7544.   2817        let the_variable = lookup(name);
 7545.   2758        if (!the_variable || the_variable.readonly) {
 7546.     61            warn("bad_assignment_a", name);
 7547.     61            return;
 7548.   2756        }
 7549.   2756        the_variable.init = true;
 7550.   2756    }
 7551.    516
 7552.  31465    function lookup(thing) {
 7553.  31465        let id = thing.id;
 7554.  31465        let the_variable;
 7555.      1        if (thing.arity !== "variable") {
 7556.      1            return;
 7557.  31464        }
 7558.  31464
 7559.  31464// Look up the variable in the current context.
 7560.  31464
 7561.  31464        the_variable = functionage.context[id] || catchage.context[id];
 7562.  31465
 7563.  31465// If it isn't local, search all the other contexts. If there are name
 7564.  31465// collisions, take the most recent.
 7565.  31465
 7566.  24589        if (the_variable && the_variable.role === "label") {
 7567.      1
 7568.      1// test_cause:
 7569.      1// ["aa:while(0){aa;}", "lookup", "label_a", "aa", 13]
 7570.      1
 7571.      1            warn("label_a", thing);
 7572.      1            return the_variable;
 7573.  31463        }
 7574.  31463        if (!the_variable) {
 7575.  14775            function_stack.forEach(function ({
 7576.  14775                context
 7577.  14775            }) {
 7578.   6875                if (context[id] && context[id].role !== "label") {
 7579.   6875                    the_variable = context[id];
 7580.   6875                }
 7581.  14775            });
 7582.   6875
 7583.   6875// If it isn't in any of those either, perhaps it is a predefined global.
 7584.   6875// If so, add it to the global context.
 7585.   6875
 7586.   6875            if (!the_variable && global_dict[id] === undefined) {
 7587.   6875
 7588.   6875// test_cause:
 7589.   6875// ["aa", "lookup", "undeclared_a", "aa", 1]
 7590.   6875// ["class aa{}", "lookup", "undeclared_a", "aa", 7]
 7591.   6875// ["
 7592.   6875// let aa=0;try{aa();}catch(bb){bb();}bb();
 7593.   6875// ", "lookup", "undeclared_a", "bb", 36]
 7594.   6875// ["
 7595.   6875// let aa=0;try{aa();}catch(ignore){bb();}
 7596.   6875// ", "lookup", "undeclared_a", "bb", 34]
 7597.   6875
 7598.   6875                warn("undeclared_a", thing);
 7599.   6875                return;
 7600.   6875            }
 7601.   6875            if (!the_variable) {
 7602.   6875                the_variable = {
 7603.   6875                    dead: false,
 7604.   6875                    id,
 7605.   6875                    init: true,
 7606.   6875                    parent: token_global,
 7607.   6875                    readonly: true,
 7608.   6875                    role: "variable",
 7609.   6875                    used: 0
 7610.   6875                };
 7611.   6875                token_global.context[id] = the_variable;
 7612.   6875            }
 7613.   6875            the_variable.closure = true;
 7614.   6875            functionage.context[id] = the_variable;
 7615.  31330        }
 7616.  31330        if (
 7617.  31330            (
 7618.  31330                the_variable.calls === undefined
 7619.  31330                || functionage.name === undefined
 7620.   4364                || the_variable.calls[functionage.name.id] === undefined
 7621.  31465            )
 7622.  31145            && the_variable.dead
 7623.      3        ) {
 7624.      3
 7625.      3// test_cause:
 7626.      3// ["let aa;if(aa){let bb;}bb;", "lookup", "out_of_scope_a", "bb", 23]
 7627.      3
 7628.      3            warn("out_of_scope_a", thing);
 7629.  31330        }
 7630.  31330        return the_variable;
 7631.  31330    }
 7632.    516
 7633.   5008    function post_a(thing) {
 7634.   5008
 7635.   5008// Assignment using = sets the init property of a variable. No other assignment
 7636.   5008// operator can do this. A = token keeps that variable (or array of variables
 7637.   5008// in case of destructuring) in its name property.
 7638.   5008
 7639.   5008        const lvalue = thing.expression[0];
 7640.   5008        let right;
 7641.   4233        if (thing.id === "=") {
 7642.   4233            if (thing.names !== undefined) {
 7643.   4233
 7644.   4233// test_cause:
 7645.   4233// ["if(0){aa=0}", "post_a", "=", "", 0]
 7646.   4233
 7647.   4233                test_cause("=");
 7648.   4233
 7649.   4233// Probably deadcode.
 7650.   4233// if (Array.isArray(thing.names)) {
 7651.   4233//     thing.names.forEach(init_variable);
 7652.   4233// } else {
 7653.   4233//     init_variable(thing.names);
 7654.   4233// }
 7655.   4233
 7656.   4233                jslint_assert(
 7657.   4233                    !Array.isArray(thing.names),
 7658.   4233                    `Expected !Array.isArray(thing.names).`
 7659.   4233                );
 7660.   4233                init_variable(thing.names);
 7661.   4233            } else {
 7662.   4233                if (lvalue.id === "[" || lvalue.id === "{") {
 7663.   4233                    lvalue.expression.forEach(function (thing) {
 7664.   4233                        if (thing.variable) {
 7665.   4233                            thing.variable.init = true;
 7666.   4233                        }
 7667.   4233                    });
 7668.   4233                } else if (
 7669.   4233                    lvalue.id === "."
 7670.   4233                    && thing.expression[1].id === "undefined"
 7671.   4233                ) {
 7672.   4233
 7673.   4233// test_cause:
 7674.   4233// ["aa.aa=undefined", "post_a", "expected_a_b", "undefined", 1]
 7675.   4233
 7676.   4233                    warn(
 7677.   4233                        "expected_a_b",
 7678.   4233                        lvalue.expression,
 7679.   4233                        "delete",
 7680.   4233                        "undefined"
 7681.   4233                    );
 7682.   4233                }
 7683.   4233            }
 7684.   4233        } else {
 7685.    775            if (lvalue.arity === "variable") {
 7686.    775                if (!lvalue.variable || lvalue.variable.readonly) {
 7687.    775                    warn("bad_assignment_a", lvalue);
 7688.    775                }
 7689.    775            }
 7690.    775            right = syntax_dict[thing.expression[1].id];
 7691.    775            if (
 7692.    775                right !== undefined
 7693.    775                && (
 7694.    775                    right.id === "function"
 7695.    775                    || right.id === "=>"
 7696.    775                    || (
 7697.    775                        right.constant
 7698.    775                        && right.id !== "(number)"
 7699.    775                        && (right.id !== "(string)" || thing.id !== "+=")
 7700.    775                    )
 7701.    775                )
 7702.    775            ) {
 7703.    775
 7704.    775// test_cause:
 7705.    775// ["aa+=undefined", "post_a", "unexpected_a", "undefined", 5]
 7706.    775
 7707.    775                warn("unexpected_a", thing.expression[1]);
 7708.    775            }
 7709.    775        }
 7710.   5008    }
 7711.    516
 7712.    706    function post_a_pluseq(thing) {
 7713.    706        const right = thing.expression[1];
 7714.    396        if (right.constant) {
 7715.    396            if (
 7716.    396                right.value === ""
 7717.    396                || (right.id === "(number)" && right.value === "0")
 7718.    396                || right.id === "(boolean)"
 7719.    396                || right.id === "null"
 7720.    396                || right.id === "undefined"
 7721.    396                || Number.isNaN(right.value)
 7722.    396            ) {
 7723.    396                warn("unexpected_a", right);
 7724.    396            }
 7725.    396        }
 7726.    706    }
 7727.    516
 7728.  31874    function post_b(thing) {
 7729.  31874        let right;
 7730.   3950        if (relationop[thing.id]) {
 7731.   3950            if (
 7732.   3950                is_weird(thing.expression[0])
 7733.   3950                || is_weird(thing.expression[1])
 7734.   3950                || is_equal(thing.expression[0], thing.expression[1])
 7735.   3950                || (
 7736.   3950                    thing.expression[0].constant === true
 7737.   3950                    && thing.expression[1].constant === true
 7738.   3950                )
 7739.   3950            ) {
 7740.   3950
 7741.   3950// test_cause:
 7742.   3950// ["if(0===0){0}", "post_b", "weird_relation_a", "===", 5]
 7743.   3950
 7744.   3950                warn("weird_relation_a", thing);
 7745.   3950            }
 7746.   3950        }
 7747.   2023        if (thing.id === "+") {
 7748.   2023            if (!option_dict.convert) {
 7749.   2023                if (thing.expression[0].value === "") {
 7750.   2023
 7751.   2023// test_cause:
 7752.   2023// ["\"\"+0", "post_b", "expected_a_b", "\"\" +", 3]
 7753.   2023
 7754.   2023                    warn("expected_a_b", thing, "String(...)", "\"\" +");
 7755.   2023                } else if (thing.expression[1].value === "") {
 7756.   2023
 7757.   2023// test_cause:
 7758.   2023// ["0+\"\"", "post_b", "expected_a_b", "+ \"\"", 2]
 7759.   2023
 7760.   2023                    warn("expected_a_b", thing, "String(...)", "+ \"\"");
 7761.   2023                }
 7762.   2023            }
 7763.  29851        } else if (thing.id === "[") {
 7764.  29851            if (thing.expression[0].id === "window") {
 7765.  29851
 7766.  29851// test_cause:
 7767.  29851// ["aa=window[0]", "post_b", "weird_expression_a", "window[...]", 10]
 7768.  29851
 7769.  29851                warn("weird_expression_a", thing, "window[...]");
 7770.  29851            }
 7771.  29851            if (thing.expression[0].id === "self") {
 7772.  29851
 7773.  29851// test_cause:
 7774.  29851// ["aa=self[0]", "post_b", "weird_expression_a", "self[...]", 8]
 7775.  29851
 7776.  29851                warn("weird_expression_a", thing, "self[...]");
 7777.  29851            }
 7778.  29851        } else if (thing.id === "." || thing.id === "?.") {
 7779.  29851            if (thing.expression.id === "RegExp") {
 7780.  29851
 7781.  29851// test_cause:
 7782.  29851// ["aa=RegExp.aa", "post_b", "weird_expression_a", ".", 10]
 7783.  29851
 7784.  29851                warn("weird_expression_a", thing);
 7785.  29851            }
 7786.  29851        } else if (thing.id !== "=>" && thing.id !== "(") {
 7787.  29851            right = thing.expression[1];
 7788.  29851            if (
 7789.  29851                (thing.id === "+" || thing.id === "-")
 7790.  29851                && right.id === thing.id
 7791.  29851                && right.arity === "unary"
 7792.  29851                && !right.wrapped
 7793.  29851            ) {
 7794.  29851
 7795.  29851// test_cause:
 7796.  29851// ["0- -0", "post_b", "wrap_unary", "-", 4]
 7797.  29851
 7798.  29851                warn("wrap_unary", right);
 7799.  29851            }
 7800.  29851            if (
 7801.  29851                thing.expression[0].constant === true
 7802.  29851                && right.constant === true
 7803.  29851            ) {
 7804.  29851                thing.constant = true;
 7805.  29851            }
 7806.  29851        }
 7807.  31874    }
 7808.    516
 7809.   1201    function post_b_and(thing) {
 7810.   1201        if (
 7811.   1201            is_weird(thing.expression[0])
 7812.   1196            || is_equal(thing.expression[0], thing.expression[1])
 7813.   1182            || thing.expression[0].constant === true
 7814.   1180            || thing.expression[1].constant === true
 7815.     21        ) {
 7816.     21
 7817.     21// test_cause:
 7818.     21// ["aa=(()=>0)&&(()=>0)", "post_b_and", "weird_condition_a", "&&", 11]
 7819.     21// ["aa=(``?``:``)&&(``?``:``)", "post_b_and", "weird_condition_a", "&&", 14]
 7820.     21// ["aa=/./&&/./", "post_b_and", "weird_condition_a", "&&", 7]
 7821.     21// ["aa=0&&0", "post_b_and", "weird_condition_a", "&&", 5]
 7822.     21// ["aa=[]&&[]", "post_b_and", "weird_condition_a", "&&", 6]
 7823.     21// ["aa=`${0}`&&`${0}`", "post_b_and", "weird_condition_a", "&&", 10]
 7824.     21// ["
 7825.     21// aa=function aa(){}&&function aa(){}
 7826.     21// ", "post_b_and", "weird_condition_a", "&&", 19]
 7827.     21// ["aa={}&&{}", "post_b_and", "weird_condition_a", "&&", 6]
 7828.     21
 7829.     21            warn("weird_condition_a", thing);
 7830.     21        }
 7831.   1201    }
 7832.    516
 7833.   1465    function post_b_lbracket(thing) {
 7834.      1        if (thing.expression[0].id === "RegExp") {
 7835.      1
 7836.      1// test_cause:
 7837.      1// ["aa=RegExp[0]", "post_b_lbracket", "weird_expression_a", "[", 10]
 7838.      1
 7839.      1            warn("weird_expression_a", thing);
 7840.      1        }
 7841.      1        if (is_weird(thing.expression[1])) {
 7842.      1
 7843.      1// test_cause:
 7844.      1// ["aa[[0]]", "post_b_lbracket", "weird_expression_a", "[", 4]
 7845.      1
 7846.      1            warn("weird_expression_a", thing.expression[1]);
 7847.      1        }
 7848.   1465    }
 7849.    516
 7850.  10392    function post_b_lparen(thing) {
 7851.  10392        let arg;
 7852.  10392        let array;
 7853.  10392        let cack;
 7854.  10392        let left = thing.expression[0];
 7855.  10392        let new_date;
 7856.  10392        let paren;
 7857.  10392        let the_new;
 7858.    154        if (left.id === "new") {
 7859.    154            the_new = left;
 7860.    154            left = left.expression;
 7861.    154        }
 7862.     37        if (left.id === "function") {
 7863.     37            if (!thing.wrapped) {
 7864.     37
 7865.     37// test_cause:
 7866.     37// ["aa=function(){}()", "post_b_lparen", "wrap_immediate", "(", 16]
 7867.     37
 7868.     37                warn("wrap_immediate", thing);
 7869.     37            }
 7870.  10355        } else if (left.identifier) {
 7871.  10355            if (the_new !== undefined) {
 7872.  10355                if (
 7873.  10355                    left.id[0] > "Z"
 7874.  10355                    || left.id === "BigInt"
 7875.  10355                    || left.id === "Boolean"
 7876.  10355                    || left.id === "Number"
 7877.  10355                    || left.id === "String"
 7878.  10355                    || left.id === "Symbol"
 7879.  10355                ) {
 7880.  10355
 7881.  10355// test_cause:
 7882.  10355// ["new BigInt()", "post_b_lparen", "unexpected_a", "new", 1]
 7883.  10355// ["new Boolean()", "post_b_lparen", "unexpected_a", "new", 1]
 7884.  10355// ["new Number()", "post_b_lparen", "unexpected_a", "new", 1]
 7885.  10355// ["new String()", "post_b_lparen", "unexpected_a", "new", 1]
 7886.  10355// ["new Symbol()", "post_b_lparen", "unexpected_a", "new", 1]
 7887.  10355// ["new aa()", "post_b_lparen", "unexpected_a", "new", 1]
 7888.  10355
 7889.  10355                    warn("unexpected_a", the_new);
 7890.  10355                } else if (left.id === "Function") {
 7891.  10355                    if (!option_dict.eval) {
 7892.  10355
 7893.  10355// test_cause:
 7894.  10355// ["new Function()", "post_b_lparen", "unexpected_a", "new Function", 5]
 7895.  10355
 7896.  10355                        warn("unexpected_a", left, "new Function");
 7897.  10355                    }
 7898.  10355                } else if (left.id === "Array") {
 7899.  10355                    arg = thing.expression;
 7900.  10355                    if (arg.length !== 2 || arg[1].id === "(string)") {
 7901.  10355
 7902.  10355// test_cause:
 7903.  10355// ["new Array()", "post_b_lparen", "expected_a_b", "new Array", 5]
 7904.  10355
 7905.  10355                        warn("expected_a_b", left, "[]", "new Array");
 7906.  10355                    }
 7907.  10355                } else if (left.id === "Object") {
 7908.  10355
 7909.  10355// test_cause:
 7910.  10355// ["new Object()", "post_b_lparen", "expected_a_b", "new Object", 5]
 7911.  10355
 7912.  10355                    warn(
 7913.  10355                        "expected_a_b",
 7914.  10355                        left,
 7915.  10355                        "Object.create(null)",
 7916.  10355                        "new Object"
 7917.  10355                    );
 7918.  10355                }
 7919.  10355            } else {
 7920.  10355                if (
 7921.  10355                    left.id[0] >= "A"
 7922.  10355                    && left.id[0] <= "Z"
 7923.  10355                    && left.id !== "BigInt"
 7924.  10355                    && left.id !== "Boolean"
 7925.  10355                    && left.id !== "Number"
 7926.  10355                    && left.id !== "String"
 7927.  10355                    && left.id !== "Symbol"
 7928.  10355                ) {
 7929.  10355
 7930.  10355// test_cause:
 7931.  10355// ["let Aa=Aa()", "post_b_lparen", "expected_a_before_b", "Aa", 8]
 7932.  10355
 7933.  10355                    warn("expected_a_before_b", left, "new", artifact(left));
 7934.  10355                }
 7935.  10355            }
 7936.  10355        } else if (left.id === ".") {
 7937.  10355            cack = the_new !== undefined;
 7938.  10355            if (left.expression.id === "Date" && left.name.id === "UTC") {
 7939.  10355
 7940.  10355// test_cause:
 7941.  10355// ["new Date.UTC()", "post_b_lparen", "cack", "", 0]
 7942.  10355
 7943.  10355                test_cause("cack");
 7944.  10355                cack = !cack;
 7945.  10355            }
 7946.  10355            if (jslint_rgx_cap.test(left.name.id) !== cack) {
 7947.  10355                if (the_new !== undefined) {
 7948.  10355
 7949.  10355// test_cause:
 7950.  10355// ["new Date.UTC()", "post_b_lparen", "unexpected_a", "new", 1]
 7951.  10355
 7952.  10355                    warn("unexpected_a", the_new);
 7953.  10355                } else {
 7954.  10355
 7955.  10355// test_cause:
 7956.  10355// ["let Aa=Aa.Aa()", "post_b_lparen", "expected_a_before_b", "Aa", 8]
 7957.  10355
 7958.  10355                    warn(
 7959.  10355                        "expected_a_before_b",
 7960.  10355                        left.expression,
 7961.  10355                        "new",
 7962.  10355                        left.name.id
 7963.  10355                    );
 7964.  10355                }
 7965.  10355            }
 7966.  10355            if (left.name.id === "getTime") {
 7967.  10355                paren = left.expression;
 7968.  10355                if (paren.id === "(") {
 7969.  10355                    array = paren.expression;
 7970.  10355                    if (array.length === 1) {
 7971.  10355                        new_date = array[0];
 7972.  10355                        if (
 7973.  10355                            new_date.id === "new"
 7974.  10355                            && new_date.expression.id === "Date"
 7975.  10355                        ) {
 7976.  10355
 7977.  10355// test_cause:
 7978.  10355// ["
 7979.  10355// new Date().getTime()
 7980.  10355// ", "post_b_lparen", "expected_a_b", "new Date().getTime()", 1]
 7981.  10355
 7982.  10355                            warn(
 7983.  10355                                "expected_a_b",
 7984.  10355                                new_date,
 7985.  10355                                "Date.now()",
 7986.  10355                                "new Date().getTime()"
 7987.  10355                            );
 7988.  10355                        }
 7989.  10355                    }
 7990.  10355                }
 7991.  10355            }
 7992.  10355        }
 7993.  10392    }
 7994.    516
 7995.    963    function post_b_or(thing) {
 7996.    963        if (
 7997.    963            is_weird(thing.expression[0])
 7998.    963            || is_equal(thing.expression[0], thing.expression[1])
 7999.    962            || thing.expression[0].constant === true
 8000.      2        ) {
 8001.      2
 8002.      2// test_cause:
 8003.      2// ["aa=0||0", "post_b_or", "weird_condition_a", "||", 5]
 8004.      2
 8005.      2            warn("weird_condition_a", thing);
 8006.      2        }
 8007.    963    }
 8008.    516
 8009.     78    function post_s_export(the_thing) {
 8010.     78
 8011.     78// Some features must be at the most outermost level.
 8012.     78
 8013.      1        if (blockage !== token_global) {
 8014.      1
 8015.      1// test_cause:
 8016.      1// ["
 8017.      1// if(0){import aa from "aa";}
 8018.      1// ", "post_s_export", "misplaced_a", "import", 7]
 8019.      1
 8020.      1            warn("misplaced_a", the_thing);
 8021.      1        }
 8022.     78    }
 8023.    516
 8024.      8    function post_s_for(thing) {
 8025.      8
 8026.      8// Recurse walk_statement().
 8027.      8
 8028.      8        walk_statement(thing.inc);
 8029.      8    }
 8030.    516
 8031.   2001    function post_s_function(thing) {
 8032.   2001        delete functionage.async;
 8033.   2001        delete functionage.finally;
 8034.   2001        delete functionage.loop;
 8035.   2001        delete functionage.statement_prv;
 8036.   2001        delete functionage.switch;
 8037.   2001        delete functionage.try;
 8038.   2001        functionage = function_stack.pop();
 8039.      3        if (thing.wrapped) {
 8040.      3
 8041.      3// test_cause:
 8042.      3// ["aa=(function(){})", "post_s_function", "unexpected_parens", "function", 5]
 8043.      3
 8044.      3            warn("unexpected_parens", thing);
 8045.      3        }
 8046.   2001        return post_s_lbrace();
 8047.   2001    }
 8048.    516
 8049.     61    function post_s_import(the_thing) {
 8050.     61        const name = the_thing.name;
 8051.     60        if (name) {
 8052.     60            if (Array.isArray(name)) {
 8053.     60                name.forEach(function (name) {
 8054.     60                    name.dead = false;
 8055.     60                    name.init = true;
 8056.     60                    blockage.live.push(name);
 8057.     60                });
 8058.     60            } else {
 8059.     60                name.dead = false;
 8060.     60                name.init = true;
 8061.     60                blockage.live.push(name);
 8062.     60            }
 8063.     60            return post_s_export(the_thing);
 8064.     60        }
 8065.     61    }
 8066.    516
 8067.   7684    function post_s_lbrace() {
 8068.   2981        blockage.live.forEach(function (name) {
 8069.   2981            name.dead = true;
 8070.   2981        });
 8071.   7684        delete blockage.live;
 8072.   7684        blockage = block_stack.pop();
 8073.   7684    }
 8074.    516
 8075.     56    function post_s_try(thing) {
 8076.     54        if (thing.catch) {
 8077.     54            if (thing.catch.name) {
 8078.     54                Object.assign(catchage.context[thing.catch.name.id], {
 8079.     54                    dead: false,
 8080.     54                    init: true
 8081.     54                });
 8082.     54            }
 8083.     54
 8084.     54// Recurse walk_statement().
 8085.     54
 8086.     54            walk_statement(thing.catch.block);
 8087.     54
 8088.     54// Restore previous catch-scope after catch-block.
 8089.     54
 8090.     54            catchage = catch_stack.pop();
 8091.     54        }
 8092.     56    }
 8093.    516
 8094.   2314    function post_s_var(thing) {
 8095.   2629        thing.names.forEach(function (name) {
 8096.   2629            name.dead = false;
 8097.   1239            if (name.expression !== undefined) {
 8098.   1239                walk_expression(name.expression);
 8099.   1239
 8100.   1239// Probably deadcode.
 8101.   1239// if (name.id === "{" || name.id === "[") {
 8102.   1239//     name.names.forEach(subactivate);
 8103.   1239// } else {
 8104.   1239//     name.init = true;
 8105.   1239// }
 8106.   1239
 8107.   1239                jslint_assert(
 8108.   1239                    !(name.id === "{" || name.id === "["),
 8109.   1239                    `Expected !(name.id === "{" || name.id === "[").`
 8110.   1239                );
 8111.   1239                name.init = true;
 8112.   1239            }
 8113.   2629            blockage.live.push(name);
 8114.   2629        });
 8115.   2314    }
 8116.    516
 8117.    219    function post_t(thing) {
 8118.    219        if (
 8119.    219            is_weird(thing.expression[0])
 8120.    219            || thing.expression[0].constant === true
 8121.    212            || is_equal(thing.expression[1], thing.expression[2])
 8122.      9        ) {
 8123.      9
 8124.      9// test_cause:
 8125.      9// ["let aa=(aa?`${0}`:`${0}`);", "post_t", "unexpected_a", "?", 11]
 8126.      9// ["let aa=(aa?`0`:`0`);", "post_t", "unexpected_a", "?", 11]
 8127.      9
 8128.      9            warn("unexpected_a", thing);
 8129.    210        } else if (is_equal(thing.expression[0], thing.expression[1])) {
 8130.    210
 8131.    210// test_cause:
 8132.    210// ["aa?aa:0", "post_t", "expected_a_b", "?", 3]
 8133.    210
 8134.    210            warn("expected_a_b", thing, "||", "?");
 8135.    210        } else if (is_equal(thing.expression[0], thing.expression[2])) {
 8136.    210
 8137.    210// test_cause:
 8138.    210// ["aa?0:aa", "post_t", "expected_a_b", "?", 3]
 8139.    210
 8140.    210            warn("expected_a_b", thing, "&&", "?");
 8141.    210        } else if (
 8142.    210            thing.expression[1].id === "true"
 8143.    210            && thing.expression[2].id === "false"
 8144.    210        ) {
 8145.    210
 8146.    210// test_cause:
 8147.    210// ["aa?true:false", "post_t", "expected_a_b", "?", 3]
 8148.    210
 8149.    210            warn("expected_a_b", thing, "!!", "?");
 8150.    210        } else if (
 8151.    210            thing.expression[1].id === "false"
 8152.    210            && thing.expression[2].id === "true"
 8153.    210        ) {
 8154.    210
 8155.    210// test_cause:
 8156.    210// ["aa?false:true", "post_t", "expected_a_b", "?", 3]
 8157.    210
 8158.    210            warn("expected_a_b", thing, "!", "?");
 8159.    210        } else if (
 8160.    210            thing.expression[0].wrapped !== true
 8161.    210            && (
 8162.    210                thing.expression[0].id === "||"
 8163.    210                || thing.expression[0].id === "&&"
 8164.    210            )
 8165.    210        ) {
 8166.    210
 8167.    210// test_cause:
 8168.    210// ["(aa&&!aa?0:1)", "post_t", "wrap_condition", "&&", 4]
 8169.    210
 8170.    210            warn("wrap_condition", thing.expression[0]);
 8171.    210        }
 8172.    219    }
 8173.    516
 8174.   4106    function post_u(thing) {
 8175.    779        if (thing.id === "`") {
 8176.    779            if (thing.expression.every(function (thing) {
 8177.    779                return thing.constant;
 8178.    779            })) {
 8179.    779                thing.constant = true;
 8180.    779            }
 8181.   3327        } else if (thing.id === "!") {
 8182.   3327            if (thing.expression.constant === true) {
 8183.   3327                warn("unexpected_a", thing);
 8184.   3327            }
 8185.   3327        } else if (thing.id === "!!") {
 8186.   3327            if (!option_dict.convert) {
 8187.   3327
 8188.   3327// test_cause:
 8189.   3327// ["!!0", "post_u", "expected_a_b", "!!", 1]
 8190.   3327
 8191.   3327                warn("expected_a_b", thing, "Boolean(...)", "!!");
 8192.   3327            }
 8193.   3327        } else if (
 8194.   3327            thing.id !== "["
 8195.   3327            && thing.id !== "{"
 8196.   3327            && thing.id !== "function"
 8197.   3327            && thing.id !== "new"
 8198.   3327        ) {
 8199.   3327            if (thing.expression.constant === true) {
 8200.   3327                thing.constant = true;
 8201.   3327            }
 8202.   3327        }
 8203.   4106    }
 8204.    516
 8205.      7    function post_u_plus(thing) {
 8206.      7        const right = thing.expression;
 8207.      7        if (!option_dict.convert) {
 8208.      7
 8209.      7// test_cause:
 8210.      7// ["aa=+0", "post_u_plus", "expected_a_b", "+", 4]
 8211.      7
 8212.      7            warn("expected_a_b", thing, "Number(...)", "+");
 8213.      7        }
 8214.      1        if (right.id === "(" && right.expression[0].id === "new") {
 8215.      1            warn("unexpected_a_before_b", thing, "+", "new");
 8216.      6        } else if (
 8217.      6            right.constant
 8218.      6            || right.id === "{"
 8219.      6            || (right.id === "[" && right.arity !== "binary")
 8220.      6        ) {
 8221.      6            warn("unexpected_a", thing, "+");
 8222.      6        }
 8223.      7    }
 8224.    516
 8225.  36885    function pre_a_bitwise(thing) {
 8226.  36885
 8227.  36885// These are the bitwise operators.
 8228.  36885
 8229.  36883        switch (!option_dict.bitwise && thing.id) {
 8230.      2        case "&":
 8231.      3        case "&=":
 8232.      5        case "<<":
 8233.      6        case "<<=":
 8234.      8        case ">>":
 8235.      9        case ">>=":
 8236.     11        case ">>>":
 8237.     12        case ">>>=":
 8238.     14        case "^":
 8239.     15        case "^=":
 8240.     17        case "|":
 8241.     18        case "|=":
 8242.     21        case "~":
 8243.     21
 8244.     21// test_cause:
 8245.     21// ["0&0", "pre_a_bitwise", "unexpected_a", "&", 2]
 8246.     21// ["0&=0", "pre_a_bitwise", "unexpected_a", "&=", 2]
 8247.     21// ["0<<0", "pre_a_bitwise", "unexpected_a", "<<", 2]
 8248.     21// ["0<<=0", "pre_a_bitwise", "unexpected_a", "<<=", 2]
 8249.     21// ["0>>0", "pre_a_bitwise", "unexpected_a", ">>", 2]
 8250.     21// ["0>>=0", "pre_a_bitwise", "unexpected_a", ">>=", 2]
 8251.     21// ["0>>>0", "pre_a_bitwise", "unexpected_a", ">>>", 2]
 8252.     21// ["0>>>=0", "pre_a_bitwise", "unexpected_a", ">>>=", 2]
 8253.     21// ["0^0", "pre_a_bitwise", "unexpected_a", "^", 2]
 8254.     21// ["0^=0", "pre_a_bitwise", "unexpected_a", "^=", 2]
 8255.     21// ["0|0", "pre_a_bitwise", "unexpected_a", "|", 2]
 8256.     21// ["0|=0", "pre_a_bitwise", "unexpected_a", "|=", 2]
 8257.     21// ["~0", "pre_a_bitwise", "unexpected_a", "~", 1]
 8258.     21
 8259.     21            warn("unexpected_a", thing);
 8260.     21            break;
 8261.  36885        }
 8262.  36885        if (
 8263.  36885            thing.id !== "("
 8264.  26493            && thing.id !== "&&"
 8265.  25292            && thing.id !== "||"
 8266.  24329            && thing.id !== "="
 8267.  20096            && Array.isArray(thing.expression)
 8268.   8501            && thing.expression.length === 2
 8269.   8500            && (
 8270.   8500                relationop[thing.expression[0].id] === true
 8271.   8500                || relationop[thing.expression[1].id] === true
 8272.   8500            )
 8273.      1        ) {
 8274.      1
 8275.      1// test_cause:
 8276.      1// ["0<0<0", "pre_a_bitwise", "unexpected_a", "<", 4]
 8277.      1
 8278.      1            warn("unexpected_a", thing);
 8279.      1        }
 8280.  36885    }
 8281.    516
 8282.  31874    function pre_b(thing) {
 8283.  31874        let left;
 8284.  31874        let right;
 8285.  31874        let value;
 8286.   3950        if (relationop[thing.id] === true) {
 8287.   3950            left = thing.expression[0];
 8288.   3950            right = thing.expression[1];
 8289.   3950            if (left.id === "NaN" || right.id === "NaN") {
 8290.   3950
 8291.   3950// test_cause:
 8292.   3950// ["NaN===NaN", "pre_b", "number_isNaN", "===", 4]
 8293.   3950
 8294.   3950                warn("number_isNaN", thing);
 8295.   3950            } else if (left.id === "typeof") {
 8296.   3950                if (right.id !== "(string)") {
 8297.   3950                    if (right.id !== "typeof") {
 8298.   3950
 8299.   3950// test_cause:
 8300.   3950// ["typeof 0===0", "pre_b", "expected_string_a", "0", 12]
 8301.   3950
 8302.   3950                        warn("expected_string_a", right);
 8303.   3950                    }
 8304.   3950                } else {
 8305.   3950                    value = right.value;
 8306.   3950                    if (value === "null" || value === "undefined") {
 8307.   3950
 8308.   3950// test_cause:
 8309.   3950// ["
 8310.   3950// typeof aa==="undefined"
 8311.   3950// ", "pre_b", "unexpected_typeof_a", "undefined", 13]
 8312.   3950
 8313.   3950                        warn("unexpected_typeof_a", right, value);
 8314.   3950                    } else if (
 8315.   3950                        value !== "bigint"
 8316.   3950                        && value !== "boolean"
 8317.   3950                        && value !== "function"
 8318.   3950                        && value !== "number"
 8319.   3950                        && value !== "object"
 8320.   3950                        && value !== "string"
 8321.   3950                        && value !== "symbol"
 8322.   3950                    ) {
 8323.   3950
 8324.   3950// test_cause:
 8325.   3950// ["typeof 0===\"aa\"", "pre_b", "expected_type_string_a", "aa", 12]
 8326.   3950
 8327.   3950                        warn("expected_type_string_a", right, value);
 8328.   3950                    }
 8329.   3950                }
 8330.   3950            }
 8331.   3950        }
 8332.  31874    }
 8333.    516
 8334.      1    function pre_b_eqeq(thing) {
 8335.      1
 8336.      1// test_cause:
 8337.      1// ["0==0", "pre_b_eqeq", "expected_a_b", "==", 2]
 8338.      1
 8339.      1        warn("expected_a_b", thing, "===", "==");
 8340.      1    }
 8341.    516
 8342.      1    function pre_b_in(thing) {
 8343.      1
 8344.      1// test_cause:
 8345.      1// ["aa in aa", "pre_b_in", "infix_in", "in", 4]
 8346.      1
 8347.      1        warn("infix_in", thing);
 8348.      1    }
 8349.    516
 8350.      1    function pre_b_instanceof(thing) {
 8351.      1
 8352.      1// test_cause:
 8353.      1// ["0 instanceof 0", "pre_b_instanceof", "unexpected_a", "instanceof", 3]
 8354.      1
 8355.      1        warn("unexpected_a", thing);
 8356.      1    }
 8357.    516
 8358.  10392    function pre_b_lparen(thing) {
 8359.  10392        const left = thing.expression[0];
 8360.  10392        let left_variable;
 8361.  10392        let parent;
 8362.  10392        if (
 8363.  10392            left.identifier
 8364.   6652            && functionage.context[left.id] === undefined
 8365.   3033            && typeof functionage.name === "object"
 8366.   2395        ) {
 8367.   2395            parent = functionage.name.parent;
 8368.   2395            if (parent) {
 8369.   2395                left_variable = parent.context[left.id];
 8370.   2395                if (
 8371.   2395                    left_variable !== undefined
 8372.   2395
 8373.   2395// Probably deadcode.
 8374.   2395// && left_variable.dead
 8375.   2395
 8376.   2395                    && left_variable.parent === parent
 8377.   2395                    && left_variable.calls !== undefined
 8378.   2395                    && left_variable.calls[functionage.name.id] !== undefined
 8379.   2395                ) {
 8380.   2395                    left_variable.dead = false;
 8381.   2395                }
 8382.   2395            }
 8383.   2395        }
 8384.  10392    }
 8385.    516
 8386.      1    function pre_b_noteq(thing) {
 8387.      1
 8388.      1// test_cause:
 8389.      1// ["0!=0", "pre_b_noteq", "expected_a_b", "!=", 2]
 8390.      1
 8391.      1        warn("expected_a_b", thing, "!==", "!=");
 8392.      1    }
 8393.    516
 8394.    963    function pre_b_or(thing) {
 8395.   1926        thing.expression.forEach(function (thang) {
 8396.    177            if (thang.id === "&&" && !thang.wrapped) {
 8397.      1
 8398.      1// test_cause:
 8399.      1// ["0&&0||0", "pre_b_or", "and", "&&", 2]
 8400.      1
 8401.      1                warn("and", thang);
 8402.      1            }
 8403.   1926        });
 8404.    963    }
 8405.    516
 8406.      8    function pre_s_for(thing) {
 8407.      8        let the_variable;
 8408.      2        if (thing.name !== undefined) {
 8409.      2            thing.name.dead = false;
 8410.      2            the_variable = lookup(thing.name);
 8411.      2            if (the_variable !== undefined) {
 8412.      2                if (the_variable.init && the_variable.readonly) {
 8413.      2
 8414.      2// test_cause:
 8415.      2// ["const aa=0;for(aa in aa){}", "pre_s_for", "bad_assignment_a", "aa", 16]
 8416.      2
 8417.      2                    warn("bad_assignment_a", thing.name);
 8418.      2                }
 8419.      2                the_variable.init = true;
 8420.      2            }
 8421.      2        }
 8422.      8
 8423.      8// Recurse walk_statement().
 8424.      8
 8425.      8        walk_statement(thing.initial);
 8426.      8    }
 8427.    516
 8428.   2001    function pre_s_function(thing) {
 8429.   2001
 8430.   2001// test_cause:
 8431.   2001// ["()=>0", "pre_s_function", "", "", 0]
 8432.   2001// ["(function (){}())", "pre_s_function", "", "", 0]
 8433.   2001// ["function aa(){}", "pre_s_function", "", "", 0]
 8434.   2001
 8435.   2001        test_cause("");
 8436.   1057        if (thing.arity === "statement" && blockage.body !== true) {
 8437.      1
 8438.      1// test_cause:
 8439.      1// ["if(0){function aa(){}\n}", "pre_s_function", "unexpected_a", "function", 7]
 8440.      1
 8441.      1            warn("unexpected_a", thing);
 8442.      1        }
 8443.   2001        function_stack.push(functionage);
 8444.   2001        block_stack.push(blockage);
 8445.   2001        functionage = thing;
 8446.   2001        blockage = thing;
 8447.   2001        thing.live = [];
 8448.   1098        if (typeof thing.name === "object") {
 8449.   1098            thing.name.dead = false;
 8450.   1098            thing.name.init = true;
 8451.   1098        }
 8452.      7        if (thing.extra === "get") {
 8453.      7            if (thing.parameters.length !== 0) {
 8454.      7
 8455.      7// test_cause:
 8456.      7// ["
 8457.      7// /*jslint getset*/
 8458.      7// aa={get aa(aa){}}
 8459.      7// ", "pre_s_function", "bad_get", "function", 9]
 8460.      7
 8461.      7                warn("bad_get", thing);
 8462.      7            }
 8463.   1994        } else if (thing.extra === "set") {
 8464.   1994            if (thing.parameters.length !== 1) {
 8465.   1994
 8466.   1994// test_cause:
 8467.   1994// ["
 8468.   1994// /*jslint getset*/
 8469.   1994// aa={set aa(){}}
 8470.   1994// ", "pre_s_function", "bad_set", "function", 9]
 8471.   1994
 8472.   1994                warn("bad_set", thing);
 8473.   1994            }
 8474.   1994        }
 8475.   2063        thing.parameters.forEach(function (name) {
 8476.   2063            walk_expression(name.expression);
 8477.   1840            if (name.id === "{" || name.id === "[") {
 8478.    267                name.names.forEach(subactivate);
 8479.   1796            } else {
 8480.   1796                name.dead = false;
 8481.   1796                name.init = true;
 8482.   1796            }
 8483.   2063        });
 8484.   2001    }
 8485.    516
 8486.   5683    function pre_s_lbrace(thing) {
 8487.   5683        block_stack.push(blockage);
 8488.   5683        blockage = thing;
 8489.   5683        thing.live = [];
 8490.   5683    }
 8491.    516
 8492.     56    function pre_try(thing) {
 8493.     54        if (thing.catch !== undefined) {
 8494.     54
 8495.     54// Create new catch-scope for catch-parameter.
 8496.     54
 8497.     54            catch_stack.push(catchage);
 8498.     54            catchage = thing.catch;
 8499.     54        }
 8500.     56    }
 8501.    516
 8502.  28646    function pre_v(thing) {
 8503.  28646        const the_variable = lookup(thing);
 8504.  28572        if (the_variable !== undefined) {
 8505.  28572            thing.variable = the_variable;
 8506.  28572            the_variable.used += 1;
 8507.  28572        }
 8508.  28646    }
 8509.    516
 8510.    717    function subactivate(name) {
 8511.    717        name.init = true;
 8512.    717        name.dead = false;
 8513.    717        blockage.live.push(name);
 8514.    717    }
 8515.    516
 8516. 164313    function walk_expression(thing) {
 8517. 103647        if (thing) {
 8518. 103647            if (Array.isArray(thing)) {
 8519. 103647
 8520. 103647// test_cause:
 8521. 103647// ["(function(){}())", "walk_expression", "isArray", "", 0]
 8522. 103647// ["0&&0", "walk_expression", "isArray", "", 0]
 8523. 103647
 8524. 103647                test_cause("isArray");
 8525. 103647                thing.forEach(walk_expression);
 8526. 103647            } else {
 8527. 103647                preamble(thing);
 8528. 103647                walk_expression(thing.expression);
 8529. 103647
 8530. 103647// PR-414 - Bugfix - fix fart-body not being walked.
 8531. 103647
 8532. 103647                if (thing.id === "function" || thing.id === "=>") {
 8533. 103647
 8534. 103647// test_cause:
 8535. 103647// ["aa=()=>0", "walk_expression", "function", "=>", 0]
 8536. 103647// ["aa=function(){}", "walk_expression", "function", "function", 0]
 8537. 103647
 8538. 103647                    test_cause("function", thing.id);
 8539. 103647
 8540. 103647// Recurse walk_statement().
 8541. 103647
 8542. 103647                    walk_statement(thing.block);
 8543. 103647                }
 8544. 103647                if (
 8545. 103647                    thing.arity === "preassign" || thing.arity === "postassign"
 8546. 103647                ) {
 8547. 103647
 8548. 103647// test_cause:
 8549. 103647// ["aa=++aa", "walk_expression", "unexpected_a", "++", 4]
 8550. 103647// ["aa=--aa", "walk_expression", "unexpected_a", "--", 4]
 8551. 103647
 8552. 103647                    warn("unexpected_a", thing);
 8553. 103647                } else if (
 8554. 103647                    thing.arity === "statement"
 8555. 103647                    || thing.arity === "assignment"
 8556. 103647                ) {
 8557. 103647
 8558. 103647// test_cause:
 8559. 103647// ["aa[aa=0]", "walk_expression", "unexpected_statement_a", "=", 6]
 8560. 103647
 8561. 103647                    warn("unexpected_statement_a", thing);
 8562. 103647                }
 8563. 103647
 8564. 103647// test_cause:
 8565. 103647// ["aa=0", "walk_expression", "default", "", 0]
 8566. 103647
 8567. 103647                test_cause("default");
 8568. 103647                postamble(thing);
 8569. 103647            }
 8570. 103647        }
 8571. 164313    }
 8572.    516
 8573.  78189    function walk_statement(thing) {
 8574.  43035        if (!thing) {
 8575.  43035            return;
 8576.  43035        }
 8577.  35154        if (Array.isArray(thing)) {
 8578.   7595
 8579.   7595// test_cause:
 8580.   7595// ["+[]", "walk_statement", "isArray", "", 0]
 8581.   7595
 8582.   7595            test_cause("isArray");
 8583.   7595
 8584.   7595// Recurse walk_statement().
 8585.   7595
 8586.   7595            thing.forEach(walk_statement);
 8587.   7595            return;
 8588.  27559        }
 8589.  27559        preamble(thing);
 8590.  27559        walk_expression(thing.expression);
 8591.  27559        if (thing.arity === "binary") {
 8592.   5658            if (thing.id !== "(") {
 8593.   5658
 8594.   5658// test_cause:
 8595.   5658// ["0&&0", "walk_statement", "unexpected_expression_a", "&&", 2]
 8596.   5658
 8597.   5658                warn("unexpected_expression_a", thing);
 8598.   5658            }
 8599.  21901        } else if (
 8600.  21901            thing.arity !== "statement"
 8601.  21901            && thing.arity !== "assignment"
 8602.  21901            && thing.id !== "import"
 8603.  21901        ) {
 8604.  21901
 8605.  21901// test_cause:
 8606.  21901// ["!0", "walk_statement", "unexpected_expression_a", "!", 1]
 8607.  21901// ["+[]", "walk_statement", "unexpected_expression_a", "+", 1]
 8608.  21901// ["+new aa()", "walk_statement", "unexpected_expression_a", "+", 1]
 8609.  21901// ["0", "walk_statement", "unexpected_expression_a", "0", 1]
 8610.  21901// ["typeof 0", "walk_statement", "unexpected_expression_a", "typeof", 1]
 8611.  21901
 8612.  21901            warn("unexpected_expression_a", thing);
 8613.  27559        }
 8614.  27559
 8615.  27559// Recurse walk_statement().
 8616.  27559
 8617.  27559        walk_statement(thing.block);
 8618.  27559        walk_statement(thing.else);
 8619.  27559        postamble(thing);
 8620.  27559    }
 8621.    516
 8622.    516    postaction = action(posts);
 8623.    516    postamble = amble(posts);
 8624.    516    preaction = action(pres);
 8625.    516    preamble = amble(pres);
 8626.    516    postaction("assignment", "+=", post_a_pluseq);
 8627.    516    postaction("assignment", post_a);
 8628.    516    postaction("binary", "&&", post_b_and);
 8629.    516    postaction("binary", "(", post_b_lparen);
 8630.    516    postaction("binary", "=>", post_s_function);
 8631.    516    postaction("binary", "[", post_b_lbracket);
 8632.    516    postaction("binary", "||", post_b_or);
 8633.    516    postaction("binary", post_b);
 8634.    516    postaction("statement", "const", post_s_var);
 8635.    516    postaction("statement", "export", post_s_export);
 8636.    516    postaction("statement", "for", post_s_for);
 8637.    516    postaction("statement", "function", post_s_function);
 8638.    516    postaction("statement", "import", post_s_import);
 8639.    516    postaction("statement", "let", post_s_var);
 8640.    516    postaction("statement", "try", post_s_try);
 8641.    516    postaction("statement", "var", post_s_var);
 8642.    516    postaction("statement", "{", post_s_lbrace);
 8643.    516    postaction("ternary", post_t);
 8644.    516    postaction("unary", "+", post_u_plus);
 8645.    516    postaction("unary", "function", post_s_function);
 8646.    516    postaction("unary", post_u);
 8647.    516    preaction("assignment", pre_a_bitwise);
 8648.    516    preaction("binary", "!=", pre_b_noteq);
 8649.    516    preaction("binary", "(", pre_b_lparen);
 8650.    516    preaction("binary", "==", pre_b_eqeq);
 8651.    516    preaction("binary", "=>", pre_s_function);
 8652.    516    preaction("binary", "in", pre_b_in);
 8653.    516    preaction("binary", "instanceof", pre_b_instanceof);
 8654.    516    preaction("binary", "||", pre_b_or);
 8655.    516    preaction("binary", pre_b);
 8656.    516    preaction("binary", pre_a_bitwise);
 8657.    516    preaction("statement", "for", pre_s_for);
 8658.    516    preaction("statement", "function", pre_s_function);
 8659.    516    preaction("statement", "try", pre_try);
 8660.    516    preaction("statement", "{", pre_s_lbrace);
 8661.    516    preaction("unary", "function", pre_s_function);
 8662.    516    preaction("unary", "~", pre_a_bitwise);
 8663.    516    preaction("variable", pre_v);
 8664.    516
 8665.    516    walk_statement(state.token_tree);
 8666.    516}
 8667.      1
 8668.    208function jslint_phase5_whitage(state) {
 8669.    208
 8670.    208// PHASE 5. Check whitespace between tokens in <token_list>.
 8671.    208
 8672.    208    let {
 8673.    208        artifact,
 8674.    208        catch_list,
 8675.    208        function_list,
 8676.    208        function_stack,
 8677.    208        option_dict,
 8678.    208        test_cause,
 8679.    208        token_global,
 8680.    208        token_list,
 8681.    208        warn
 8682.    208    } = state;
 8683.    208    let closer = "(end)";
 8684.    208    let free = false;
 8685.    208
 8686.    208// free = false
 8687.    208
 8688.    208// cause:
 8689.    208// "()=>0"
 8690.    208// "aa()"
 8691.    208// "aa(0,0)"
 8692.    208// "function(){}"
 8693.    208
 8694.    208// free = true
 8695.    208
 8696.    208// cause:
 8697.    208// "(0)"
 8698.    208// "(aa)"
 8699.    208// "aa(0)"
 8700.    208// "do{}while()"
 8701.    208// "for(){}"
 8702.    208// "if(){}"
 8703.    208// "switch(){}"
 8704.    208// "while(){}"
 8705.    208
 8706.    208    let left = token_global;
 8707.    208    let margin = 0;
 8708.    208    let mode_indent = (
 8709.    208
 8710.    208// PR-330 - Allow 2-space indent.
 8711.    208
 8712.    208        option_dict.indent2
 8713.      5        ? 2
 8714.    203        : 4
 8715.    208    );
 8716.    208    let nr_comments_skipped = 0;
 8717.    208    let open = true;
 8718.    208    let opening = true;
 8719.    208    let right;
 8720.    208
 8721.    208// This is the set of infix operators that require a space on each side.
 8722.    208
 8723.    208    let spaceop = object_assign_from_list(empty(), [
 8724.    208        "!=", "!==", "%", "%=", "&", "&&", "&=", "*", "*=", "+=", "-=", "/",
 8725.    208        "/=", "<", "<<", "<<=", "<=", "=", "==", "===", "=>", ">", ">=", ">>",
 8726.    208        ">>=", ">>>", ">>>=", "^", "^=", "|", "|=", "||"
 8727.    208    ], true);
 8728.    208
 8729.  38041    function at_margin(fit) {
 8730.  38041        const at = margin + fit;
 8731.     21        if (right.from !== at) {
 8732.     21            return expected_at(at);
 8733.     21        }
 8734.  38041    }
 8735.    208
 8736.   2057    function delve(the_function) {
 8737.  13008        Object.keys(the_function.context).forEach(function (id) {
 8738.  13008            const name = the_function.context[id];
 8739.  12973            if (id !== "ignore" && name.parent === the_function) {
 8740.   6280
 8741.   6280// test_cause:
 8742.   6280// ["function aa(aa) {return aa;}", "delve", "id", "", 0]
 8743.   6280
 8744.   6280                test_cause("id");
 8745.   6280                if (
 8746.   6280                    name.used === 0
 8747.   6280
 8748.   6280// Probably deadcode.
 8749.   6280// && (
 8750.   6280//     name.role !== "function"
 8751.   6280//     || name.parent.arity !== "unary"
 8752.   6280// )
 8753.   6280
 8754.   6280                    && jslint_assert(
 8755.   6280                        name.role !== "function",
 8756.   6280                        `Expected name.role !== "function".`
 8757.   6280                    )
 8758.   6280                ) {
 8759.   6280
 8760.   6280// test_cause:
 8761.   6280// ["/*jslint node*/\nlet aa;", "delve", "unused_a", "aa", 5]
 8762.   6280// ["function aa(aa){return;}", "delve", "unused_a", "aa", 13]
 8763.   6280// ["let aa=0;try{aa();}catch(bb){aa();}", "delve", "unused_a", "bb", 26]
 8764.   6280
 8765.   6280                    warn("unused_a", name);
 8766.   6280                } else if (!name.init) {
 8767.   6280
 8768.   6280// test_cause:
 8769.   6280// ["/*jslint node*/\nlet aa;aa();", "delve", "uninitialized_a", "aa", 5]
 8770.   6280
 8771.   6280                    warn("uninitialized_a", name);
 8772.   6280                }
 8773.   6280            }
 8774.  13008        });
 8775.   2057    }
 8776.    208
 8777.     25    function expected_at(at) {
 8778.     25
 8779.     25// Probably deadcode.
 8780.     25// if (right === undefined) {
 8781.     25//     right = token_nxt;
 8782.     25// }
 8783.     25
 8784.     25        jslint_assert(
 8785.     25            !(right === undefined),
 8786.     25            `Expected !(right === undefined).`
 8787.     25        );
 8788.     25        warn(
 8789.     25            "expected_a_at_b_c",
 8790.     25            right,
 8791.     25            artifact(right),
 8792.     25
 8793.     25// Fudge column numbers in warning message.
 8794.     25
 8795.     25            at + jslint_fudge,
 8796.     25            right.from + jslint_fudge
 8797.     25        );
 8798.     25    }
 8799.    208
 8800.   3094    function no_space() {
 8801.   3093        if (left.line === right.line) {
 8802.   3093
 8803.   3093// from:
 8804.   3093// if (left.line === right.line) {
 8805.   3093//     no_space();
 8806.   3093// } else {
 8807.   3093
 8808.   3093            if (left.thru !== right.from && nr_comments_skipped === 0) {
 8809.   3093
 8810.   3093// test_cause:
 8811.   3093// ["let aa = aa( );", "no_space", "unexpected_space_a_b", ")", 14]
 8812.   3093
 8813.   3093                warn(
 8814.   3093                    "unexpected_space_a_b",
 8815.   3093                    right,
 8816.   3093                    artifact(left),
 8817.   3093                    artifact(right)
 8818.   3093                );
 8819.   3093            }
 8820.   3093        } else {
 8821.      1
 8822.      1// from:
 8823.      1// } else if (
 8824.      1//     right.arity === "binary"
 8825.      1//     && right.id === "("
 8826.      1//     && free
 8827.      1// ) {
 8828.      1//     no_space();
 8829.      1// } else if (
 8830.      1
 8831.      1// Probably deadcode.
 8832.      1// if (open) {
 8833.      1//     const at = (
 8834.      1//         free
 8835.      1//         ? margin
 8836.      1//         : margin + 8
 8837.      1//     );
 8838.      1//     if (right.from < at) {
 8839.      1//         expected_at(at);
 8840.      1//     }
 8841.      1// } else {
 8842.      1//     if (right.from !== margin + 8) {
 8843.      1//         expected_at(margin + 8);
 8844.      1//     }
 8845.      1// }
 8846.      1
 8847.      1            jslint_assert(open, `Expected open.`);
 8848.      1            jslint_assert(free, `Expected free.`);
 8849.      1            if (right.from < margin) {
 8850.      1
 8851.      1// test_cause:
 8852.      1// ["let aa = aa(\naa\n()\n);", "expected_at", "expected_a_at_b_c", "5", 1]
 8853.      1
 8854.      1                expected_at(margin);
 8855.      1            }
 8856.      1        }
 8857.   3094    }
 8858.    208
 8859.  95940    function no_space_only() {
 8860.  95940        if (
 8861.  95940            left.id !== "(global)"
 8862.  95938            && left.nr + 1 === right.nr
 8863.  95938            && (
 8864.  95938                left.line !== right.line
 8865.  95938                || left.thru !== right.from
 8866.  95938            )
 8867.      5        ) {
 8868.      5            warn(
 8869.      5                "unexpected_space_a_b",
 8870.      5                right,
 8871.      5                artifact(left),
 8872.      5                artifact(right)
 8873.      5            );
 8874.      5        }
 8875.  95940    }
 8876.    208
 8877.  46137    function one_space() {
 8878.  44240        if (left.line === right.line || !open) {
 8879.  44240            if (left.thru + 1 !== right.from && nr_comments_skipped === 0) {
 8880.  44240                warn(
 8881.  44240                    "expected_space_a_b",
 8882.  44240                    right,
 8883.  44240                    artifact(left),
 8884.  44240                    artifact(right)
 8885.  44240                );
 8886.  44240            }
 8887.  44240        } else {
 8888.   1897            if (right.from !== margin) {
 8889.   1897                expected_at(margin);
 8890.   1897            }
 8891.   1897        }
 8892.  46137    }
 8893.    208
 8894.   9345    function one_space_only() {
 8895.      8        if (left.line !== right.line || left.thru + 1 !== right.from) {
 8896.      8            warn("expected_space_a_b", right, artifact(left), artifact(right));
 8897.      8        }
 8898.   9345    }
 8899.    208
 8900.  24634    function pop() {
 8901.  24634        const previous = function_stack.pop();
 8902.  24634        closer = previous.closer;
 8903.  24634        free = previous.free;
 8904.  24634        margin = previous.margin;
 8905.  24634        open = previous.open;
 8906.  24634        opening = previous.opening;
 8907.  24634    }
 8908.    208
 8909.  24634    function push() {
 8910.  24634        function_stack.push({
 8911.  24634            closer,
 8912.  24634            free,
 8913.  24634            margin,
 8914.  24634            open,
 8915.  24634            opening
 8916.  24634        });
 8917.  24634    }
 8918.    208
 8919.    208// uninitialized_and_unused();
 8920.    208// Delve into the functions looking for variables that were not initialized
 8921.    208// or used. If the file imports or exports, then its global object is also
 8922.    208// delved.
 8923.    208
 8924.    174    if (state.mode_module === true || option_dict.node) {
 8925.     51        delve(token_global);
 8926.     51    }
 8927.    208    catch_list.forEach(delve);
 8928.    208    function_list.forEach(delve);
 8929.    208
 8930.      2    if (option_dict.white) {
 8931.      2        return;
 8932.    206    }
 8933.    206
 8934.    206// whitage();
 8935.    206// Go through the token list, looking at usage of whitespace.
 8936.    206
 8937. 206858    token_list.forEach(function whitage(the_token) {
 8938. 206858        right = the_token;
 8939. 195699        if (right.id === "(comment)" || right.id === "(end)") {
 8940.  11367            nr_comments_skipped += 1;
 8941. 195491        } else {
 8942. 195491
 8943. 195491// If left is an opener and right is not the closer, then push the previous
 8944. 195491// state. If the token following the opener is on the next line, then this is
 8945. 195491// an open form. If the tokens are on the same line, then it is a closed form.
 8946. 195491// Open form is more readable, with each item (statement, argument, parameter,
 8947. 195491// etc) starting on its own line. Closed form is more compact. Statement blocks
 8948. 195491// are always in open form.
 8949. 195491
 8950. 195491// The open and close pairs.
 8951. 195491
 8952. 195491            switch (left.id) {
 8953. 195491            case "${":
 8954. 195491            case "(":
 8955. 195491            case "[":
 8956. 195491            case "{":
 8957. 195491
 8958. 195491// test_cause:
 8959. 195491// ["let aa=[];", "whitage", "opener", "", 0]
 8960. 195491// ["let aa=`${0}`;", "whitage", "opener", "", 0]
 8961. 195491// ["let aa=aa();", "whitage", "opener", "", 0]
 8962. 195491// ["let aa={};", "whitage", "opener", "", 0]
 8963. 195491
 8964. 195491                test_cause("opener");
 8965. 195491
 8966. 195491// Probably deadcode.
 8967. 195491// case "${}":
 8968. 195491
 8969. 195491                jslint_assert(
 8970. 195491                    !(left.id + right.id === "${}"),
 8971. 195491                    "Expected !(left.id + right.id === \"${}\")."
 8972. 195491                );
 8973. 195491                switch (left.id + right.id) {
 8974. 195491                case "()":
 8975. 195491                case "[]":
 8976. 195491                case "{}":
 8977. 195491
 8978. 195491// If left and right are opener and closer, then the placement of right depends
 8979. 195491// on the openness. Illegal pairs (like '{]') have already been detected.
 8980. 195491
 8981. 195491// test_cause:
 8982. 195491// ["let aa=[];", "whitage", "opener_closer", "", 0]
 8983. 195491// ["let aa=aa();", "whitage", "opener_closer", "", 0]
 8984. 195491// ["let aa={};", "whitage", "opener_closer", "", 0]
 8985. 195491
 8986. 195491                    test_cause("opener_closer");
 8987. 195491                    if (left.line === right.line) {
 8988. 195491
 8989. 195491// test_cause:
 8990. 195491// ["let aa = aa( );", "no_space", "unexpected_space_a_b", ")", 14]
 8991. 195491
 8992. 195491                        no_space();
 8993. 195491                    } else {
 8994. 195491
 8995. 195491// test_cause:
 8996. 195491// ["let aa = aa(\n );", "expected_at", "expected_a_at_b_c", "1", 2]
 8997. 195491
 8998. 195491                        at_margin(0);
 8999. 195491                    }
 9000. 195491                    break;
 9001. 195491                default:
 9002. 195491
 9003. 195491// test_cause:
 9004. 195491// ["let aa=(0);", "whitage", "opener_operand", "", 0]
 9005. 195491// ["let aa=[0];", "whitage", "opener_operand", "", 0]
 9006. 195491// ["let aa=`${0}`;", "whitage", "opener_operand", "", 0]
 9007. 195491// ["let aa=aa(0);", "whitage", "opener_operand", "", 0]
 9008. 195491// ["let aa={aa:0};", "whitage", "opener_operand", "", 0]
 9009. 195491
 9010. 195491                    test_cause("opener_operand");
 9011. 195491                    opening = left.open || (left.line !== right.line);
 9012. 195491                    push();
 9013. 195491                    switch (left.id) {
 9014. 195491                    case "${":
 9015. 195491                        closer = "}";
 9016. 195491                        break;
 9017. 195491                    case "(":
 9018. 195491                        closer = ")";
 9019. 195491                        break;
 9020. 195491                    case "[":
 9021. 195491                        closer = "]";
 9022. 195491                        break;
 9023. 195491                    case "{":
 9024. 195491                        closer = "}";
 9025. 195491                        break;
 9026. 195491                    }
 9027. 195491                    if (opening) {
 9028. 195491
 9029. 195491// test_cause:
 9030. 195491// ["function aa(){\nreturn;\n}", "whitage", "opening", "", 0]
 9031. 195491// ["let aa=(\n0\n);", "whitage", "opening", "", 0]
 9032. 195491// ["let aa=[\n0\n];", "whitage", "opening", "", 0]
 9033. 195491// ["let aa=`${\n0\n}`;", "whitage", "opening", "", 0]
 9034. 195491// ["let aa={\naa:0\n};", "whitage", "opening", "", 0]
 9035. 195491
 9036. 195491                        test_cause("opening");
 9037. 195491                        free = closer === ")" && left.free;
 9038. 195491                        open = true;
 9039. 195491                        margin += mode_indent;
 9040. 195491                        if (right.role === "label") {
 9041. 195491                            if (right.from !== 0) {
 9042. 195491
 9043. 195491// test_cause:
 9044. 195491// ["
 9045. 195491// function aa() {
 9046. 195491//  bb:
 9047. 195491//     while (aa) {
 9048. 195491//         if (aa) {
 9049. 195491//             break bb;
 9050. 195491//         }
 9051. 195491//     }
 9052. 195491// }
 9053. 195491// ", "expected_at", "expected_a_at_b_c", "1", 2]
 9054. 195491
 9055. 195491                                expected_at(0);
 9056. 195491                            }
 9057. 195491                        } else if (right.switch) {
 9058. 195491                            at_margin(-mode_indent);
 9059. 195491                        } else {
 9060. 195491                            at_margin(0);
 9061. 195491                        }
 9062. 195491                    } else {
 9063. 195491                        if (right.statement || right.role === "label") {
 9064. 195491
 9065. 195491// test_cause:
 9066. 195491// ["
 9067. 195491// function aa() {bb:
 9068. 195491//     while (aa) {
 9069. 195491//         aa();
 9070. 195491//     }
 9071. 195491// }
 9072. 195491// ", "whitage", "expected_line_break_a_b", "bb", 16]
 9073. 195491
 9074. 195491                            warn(
 9075. 195491                                "expected_line_break_a_b",
 9076. 195491                                right,
 9077. 195491                                artifact(left),
 9078. 195491                                artifact(right)
 9079. 195491                            );
 9080. 195491                        }
 9081. 195491
 9082. 195491// test_cause:
 9083. 195491// ["let aa=(0);", "whitage", "not_free", "", 0]
 9084. 195491// ["let aa=[0];", "whitage", "not_free", "", 0]
 9085. 195491// ["let aa=`${0}`;", "whitage", "not_free", "", 0]
 9086. 195491// ["let aa={aa:0};", "whitage", "not_free", "", 0]
 9087. 195491
 9088. 195491                        test_cause("not_free");
 9089. 195491                        free = false;
 9090. 195491                        open = false;
 9091. 195491
 9092. 195491// test_cause:
 9093. 195491// ["let aa = ( 0 );", "no_space_only", "unexpected_space_a_b", "0", 12]
 9094. 195491
 9095. 195491                        no_space_only();
 9096. 195491                    }
 9097. 195491                }
 9098. 195491                break;
 9099. 195491            default:
 9100. 195491                if (right.statement === true) {
 9101. 195491                    if (left.id === "else") {
 9102. 195491
 9103. 195491// test_cause:
 9104. 195491// ["
 9105. 195491// let aa = 0;
 9106. 195491// if (aa) {
 9107. 195491//     aa();
 9108. 195491// } else  if (aa) {
 9109. 195491//     aa();
 9110. 195491// }
 9111. 195491// ", "one_space_only", "expected_space_a_b", "if", 9]
 9112. 195491
 9113. 195491                        one_space_only();
 9114. 195491                    } else {
 9115. 195491
 9116. 195491// test_cause:
 9117. 195491// [" let aa = 0;", "expected_at", "expected_a_at_b_c", "1", 2]
 9118. 195491
 9119. 195491                        at_margin(0);
 9120. 195491                        open = false;
 9121. 195491                    }
 9122. 195491
 9123. 195491// If right is a closer, then pop the previous state.
 9124. 195491
 9125. 195491                } else if (right.id === closer) {
 9126. 195491                    pop();
 9127. 195491                    if (opening && right.id !== ";") {
 9128. 195491                        at_margin(0);
 9129. 195491                    } else {
 9130. 195491                        no_space_only();
 9131. 195491                    }
 9132. 195491                } else {
 9133. 195491
 9134. 195491// Left is not an opener, and right is not a closer.
 9135. 195491// The nature of left and right will determine the space between them.
 9136. 195491
 9137. 195491// If left is ',' or ';' or right is a statement then if open,
 9138. 195491// right must go at the margin, or if closed, a space between.
 9139. 195491
 9140. 195491                    if (right.switch) {
 9141. 195491                        at_margin(-mode_indent);
 9142. 195491                    } else if (right.role === "label") {
 9143. 195491                        if (right.from !== 0) {
 9144. 195491
 9145. 195491// test_cause:
 9146. 195491// ["
 9147. 195491// function aa() {
 9148. 195491//     aa();cc:
 9149. 195491//     while (aa) {
 9150. 195491//         if (aa) {
 9151. 195491//             break cc;
 9152. 195491//         }
 9153. 195491//     }
 9154. 195491// }
 9155. 195491// ", "expected_at", "expected_a_at_b_c", "1", 10]
 9156. 195491
 9157. 195491                            expected_at(0);
 9158. 195491                        }
 9159. 195491                    } else if (left.id === ",") {
 9160. 195491                        if (!open || (
 9161. 195491                            (free || closer === "]")
 9162. 195491                            && left.line === right.line
 9163. 195491                        )) {
 9164. 195491
 9165. 195491// test_cause:
 9166. 195491// ["let {aa,bb} = 0;", "one_space", "expected_space_a_b", "bb", 9]
 9167. 195491
 9168. 195491                            one_space();
 9169. 195491                        } else {
 9170. 195491
 9171. 195491// test_cause:
 9172. 195491// ["
 9173. 195491// function aa() {
 9174. 195491//     aa(
 9175. 195491//         0,0
 9176. 195491//     );
 9177. 195491// }
 9178. 195491// ", "expected_at", "expected_a_at_b_c", "9", 11]
 9179. 195491
 9180. 195491                            at_margin(0);
 9181. 195491                        }
 9182. 195491
 9183. 195491// If right is a ternary operator, line it up on the margin.
 9184. 195491
 9185. 195491                    } else if (right.arity === "ternary") {
 9186. 195491                        if (open) {
 9187. 195491
 9188. 195491// test_cause:
 9189. 195491// ["
 9190. 195491// let aa = (
 9191. 195491//     aa
 9192. 195491//     ? 0
 9193. 195491// : 1
 9194. 195491// );
 9195. 195491// ", "expected_at", "expected_a_at_b_c", "5", 1]
 9196. 195491
 9197. 195491                            at_margin(0);
 9198. 195491                        } else {
 9199. 195491
 9200. 195491// test_cause:
 9201. 195491// ["let aa = (aa ? 0 : 1);", "whitage", "use_open", "?", 14]
 9202. 195491
 9203. 195491                            warn("use_open", right);
 9204. 195491                        }
 9205. 195491                    } else if (
 9206. 195491                        right.arity === "binary"
 9207. 195491                        && right.id === "("
 9208. 195491                        && free
 9209. 195491                    ) {
 9210. 195491
 9211. 195491// test_cause:
 9212. 195491// ["let aa = aa(\naa ()\n);", "no_space", "unexpected_space_a_b", "(", 4]
 9213. 195491
 9214. 195491                        no_space();
 9215. 195491                    } else if (
 9216. 195491                        left.id === "."
 9217. 195491                        || left.id === "?."
 9218. 195491                        || left.id === "..."
 9219. 195491                        || right.id === ","
 9220. 195491                        || right.id === ";"
 9221. 195491                        || right.id === ":"
 9222. 195491                        || (
 9223. 195491                            right.arity === "binary"
 9224. 195491                            && (right.id === "(" || right.id === "[")
 9225. 195491                        )
 9226. 195491                        || (
 9227. 195491                            right.arity === "function"
 9228. 195491                            && left.id !== "function"
 9229. 195491                        )
 9230. 195491                        || (right.id === "." || right.id === "?.")
 9231. 195491                    ) {
 9232. 195491
 9233. 195491// test_cause:
 9234. 195491// ["let aa = 0 ;", "no_space_only", "unexpected_space_a_b", ";", 12]
 9235. 195491// ["let aa = aa ?.aa;", "no_space_only", "unexpected_space_a_b", "?.", 13]
 9236. 195491
 9237. 195491                        no_space_only();
 9238. 195491                    } else if (left.id === ";") {
 9239. 195491
 9240. 195491// test_cause:
 9241. 195491// ["
 9242. 195491// /*jslint for*/
 9243. 195491// function aa() {
 9244. 195491//     for (
 9245. 195491//         aa();
 9246. 195491// aa;
 9247. 195491//         aa()
 9248. 195491//     ) {
 9249. 195491//         aa();
 9250. 195491//     }
 9251. 195491// }
 9252. 195491// ", "expected_at", "expected_a_at_b_c", "9", 1]
 9253. 195491
 9254. 195491                        if (open) {
 9255. 195491                            at_margin(0);
 9256. 195491                        }
 9257. 195491                    } else if (
 9258. 195491                        left.arity === "ternary"
 9259. 195491                        || left.id === "case"
 9260. 195491                        || left.id === "catch"
 9261. 195491                        || left.id === "else"
 9262. 195491                        || left.id === "finally"
 9263. 195491                        || left.id === "while"
 9264. 195491                        || left.id === "await"
 9265. 195491                        || right.id === "catch"
 9266. 195491                        || right.id === "else"
 9267. 195491                        || right.id === "finally"
 9268. 195491                        || (right.id === "while" && !right.statement)
 9269. 195491                        || (left.id === ")" && right.id === "{")
 9270. 195491                    ) {
 9271. 195491
 9272. 195491// test_cause:
 9273. 195491// ["
 9274. 195491// function aa() {
 9275. 195491//     do {
 9276. 195491//         aa();
 9277. 195491//     } while(aa());
 9278. 195491// }
 9279. 195491// ", "one_space_only", "expected_space_a_b", "(", 12]
 9280. 195491
 9281. 195491                        one_space_only();
 9282. 195491                    } else if (
 9283. 195491
 9284. 195491// There is a space between left and right.
 9285. 195491
 9286. 195491                        spaceop[left.id] === true
 9287. 195491                        || spaceop[right.id] === true
 9288. 195491                        || (
 9289. 195491                            left.arity === "binary"
 9290. 195491                            && (left.id === "+" || left.id === "-")
 9291. 195491                        )
 9292. 195491                        || (
 9293. 195491                            right.arity === "binary"
 9294. 195491                            && (right.id === "+" || right.id === "-")
 9295. 195491                        )
 9296. 195491                        || left.id === "function"
 9297. 195491                        || left.id === ":"
 9298. 195491                        || left.id === "async"
 9299. 195491                        || (
 9300. 195491                            (
 9301. 195491                                left.identifier
 9302. 195491                                || left.id === "(string)"
 9303. 195491                                || left.id === "(number)"
 9304. 195491                            )
 9305. 195491                            && (
 9306. 195491                                right.identifier
 9307. 195491                                || right.id === "(string)"
 9308. 195491                                || right.id === "(number)"
 9309. 195491                            )
 9310. 195491                        )
 9311. 195491                        || (left.arity === "statement" && right.id !== ";")
 9312. 195491                    ) {
 9313. 195491
 9314. 195491// test_cause:
 9315. 195491// ["let aa=0;", "one_space", "expected_space_a_b", "0", 8]
 9316. 195491// ["let aa={\naa:\n0\n};", "expected_at", "expected_a_at_b_c", "5", 1]
 9317. 195491
 9318. 195491                        one_space();
 9319. 195491                    } else if (left.arity === "unary" && left.id !== "`") {
 9320. 195491                        no_space_only();
 9321. 195491                    }
 9322. 195491                }
 9323. 195491            }
 9324. 195491            nr_comments_skipped = 0;
 9325. 195491            delete left.calls;
 9326. 195491            delete left.dead;
 9327. 195491            delete left.free;
 9328. 195491            delete left.init;
 9329. 195491            delete left.open;
 9330. 195491            delete left.used;
 9331. 195491            left = right;
 9332. 195491        }
 9333. 206858    });
 9334.    206}
 9335.      1
 9336.      6function jslint_report({
 9337.      6    exports,
 9338.      6    froms,
 9339.      6    functions,
 9340.      6    global,
 9341.      6    json,
 9342.      6    module,
 9343.      6    property,
 9344.      6    stop,
 9345.      6    warnings
 9346.      6}) {
 9347.      6
 9348.      6// This function will create human-readable, html-report
 9349.      6// for warnings, properties, and functions from jslint-result-object.
 9350.      6//
 9351.      6// Example usage:
 9352.      6//  let result = jslint("console.log('hello world')");
 9353.      6//  let html = jslint_report(result);
 9354.      6
 9355.      6    let html = "";
 9356.      6    let length_80 = 1111;
 9357.      6
 9358.    328    function address(line = 1, column = 1) {
 9359.    328
 9360.    328// This function will create HTML address element from <line> and <column>
 9361.    328
 9362.    328        return `<address>${Number(line)}: ${Number(column)}</address>`;
 9363.    328
 9364.    328    }
 9365.      6
 9366.   2256    function detail(title, list) {
 9367.   2256        return (
 9368.   2256            (Array.isArray(list) && list.length > 0)
 9369.    780            ? (
 9370.    780
 9371.    780// Google Lighthouse Accessibility - <dl>'s do not contain only properly-ordered
 9372.    780// <dt> and <dd> groups, <script>, <template> or <div> elements.
 9373.    780
 9374.    780                "<dl>"
 9375.    780                + "<dt>" + htmlEscape(title) + "</dt>"
 9376.    780                + "<dd>" + list.join(", ") + "</dd>"
 9377.    780                + "</dl>"
 9378.    780            )
 9379.   1476            : ""
 9380.   2256        );
 9381.   2256    }
 9382.      6
 9383.      6    html += String(`
 9384.      6<style class="JSLINT_REPORT_STYLE">
 9385.      6/* jslint utility2:true */
 9386.      6/*csslint box-model: false, ids:false */
 9387.      6/*csslint ignore:start*/
 9388.      6@font-face {
 9389.      6    font-display: swap;
 9390.      6    font-family: "Daley";
 9391.      6    src: url(
 9392.      6"data:font/woff2;base64,d09GMgABAAAAABy4AA4AAAAAThwAABxiAAEAAAAAAAAAAAAA\
 9393.      6AAAAAAAAAAAAAAAABmAAgiQINAmcDBEICuc41DEBNgIkA4R2C4I+AAQgBYkuByAMgScfYUIF\
 9394.      67NgjsHGAbcDVFkXZ5Jwd+P96IGPc9rl9ETBEaCzCJkvY2UpziRZ7zftZWk8052U9+NqX6vXL\
 9395.      6KDflSQnlJ0bP+QnPQAy744n9mup6H9PaCDFwM5zjf8exB89bZ1cdrYOP0NgnuRDRWlk9u/fE\
 9396.      6llkxqmfH8lmRQ/DAmER9opk9wR6suc1LvTiXNEe1vbhUCH2USgnEwH3vUm05JQqejGvZvOtz\
 9397.      67sIKEGgLdDNl/IrfqWVZG/wr42ekomEm91VA1p4LhHBuFzHF8//u7vvbREHMQqGtNLmiOOD/\
 9398.      6X7WWiwqyCE98qt0jk5JJmgR5WJJElBmzRb1F7a66MmSLTNWZ2XSHfKBSKHoVteSEJ6EOdvVw\
 9399.      6fNZOtXKDe39jXdRlkmMnOWIOFBgeEK/b0mFsgffnPyyAitNyutKky7J8a8MSEkAKGLgfptnS\
 9400.      6/gDRSo7vwdNUmQDB7oP6pK7QF5d9SrY8M/tkrXcurSIQAmX7tz7pd33LIB7GQkBQ/k81s/0D\
 9401.      6gpt4gbw7x0Cn/PocitK5KIGPGQIzQzAMuCeC2ERAidx9TySVqX06goT0SFFOOV9Kuxdi5Rg7\
 9402.      6l6n3c+nKRemidOm2dtFV1jXMk4rP2m6RJ8xEdPYONLTbeMgaJ1nwS2W4su3MHwqkkvJ2PdDU\
 9403.      6r7pgAnVRt4Kh789FXlD0r3p6jUtNO19O1s74U9pnIxqFpw+mBgF+8y30PAyw1dzlknLLVcSB\
 9404.      6J2OuCr9eV5Efew6cOGd47ZEfhrW7HXI+FBNFvWgWnugUU4UvlrV63niv2ZPeKu8M76y/HQaG\
 9405.      6weU+4Gzp+Y+cfb9R9djDWcd1Svr1xG7l+j/yf3eM996548qlC+dOzOqQ8//Lo0uaSEQCFuLD\
 9406.      6/bXyWhJ6aPmyaRonVPxGABFL4/0slcKI6f+PmT0M+QRsplmWnv4F49VT+JsPifoa6aeyr2Hz\
 9407.      6EeLdP1FEOV/ZN+c9sAuoNh0BRS0xgCCc9wME5s0HOKj/wc0fWYsTbFQpsZL5SayJPkL45kDo\
 9408.      6DcJJ10MvD0ZSq7FEIr1TfqZ7NC6s75zSp8viaNO5/PczYCV9z6NTa0KBdnGBg6kbdeBkRLfU\
 9409.      6qRd3D9Pqw5jWCc5WM/i95OE8731MBd1u2EmsXIa5dCvavY32U1Ytza4nfbERg6OVRZka7jq0\
 9410.      6r2FcXNDyEhXheaHtaU1o1kvO9MuBOHqugLUEzN+4jznu0oK9wZPur1lWVFfxl8lZzn2XwcjZ\
 9411.      6Csg/RJy0mAMMmgnqXS8ELhOCRUSLzvsM5gAPudEh2lVoRxGgyUVnArZMruE0YS1PqFMD3upb\
 9412.      6jVoecGj1KpWl6/ZysuyzkG4SGA4bps6FBQSg4e4IxNUgdmosmoDn0TpIex/s1BFau6GBNO4z\
 9413.      6cvWXypm4hEg5k3llelySFqNmUtRZ3PHBA7p4MBX1nK4awwAV6kWzIVbUA67A55QKYbMsgVaH\
 9414.      6c1ZxKuZ0DCyqxCsJjLyCEY36gf0wjAu3t0zemc87PmBCJbU9Lso0YAaYJUx8wsR02hYz5hGy\
 9415.      6Js0+A4uHGZgfuf5SOR9iBQuLhpOExaIFrHj6JlXanebzGHp2ELDh6av09PVE1fmdsj2oHRWs\
 9416.      6fOtYrV6wRCyx7XogHqvpnZiPBBdNcL6kIoS9UI/DOIlumlveSgv9oqMBYp7WZ2fGxAXmZmaG\
 9417.      6OCyJG6+wAszZFCQw/EXVjx+YA2uVyN6bhNWiZhgtYjAwR5U/7uV1scghiTGiAPZbA5ZqHw5u\
 9418.      6Yu1cDjhRwREBFyq2wa0R8GgceDUKPo2BX+MhoAkQ1EQIaZqVHMwH3xM+P32TTA34tmOMNZ4n\
 9419.      6mHXqn49fmE3qX1+wMNYoYetOsPx6wxKzkURImERJIjGSSJwkkiCJJEkiKZJImiSSIYlkSYqK\
 9420.      6UBu0UOopuLMmasiJW0PMFOO2UgbDif2NaQUqkBbyaGjdTUvuyamEQwCq9DWsxsG9qPt+VFqV\
 9421.      66cIsXcyWujWIEtNFdeia9ssNrJUpe3IDMPQZOReC8x+qvt17drPWdcHeL0gTarWwoQ6o828o\
 9422.      60EJzrA20yZsgVyVHdlCJOF3NaACxHbP38TA+MGx3St9c5t2CxbGtunB4J9AF4Px2rSr1wyK9\
 9423.      69KoXBR13vw9Fk9qhTX0ivZoanrvhLa5oiJO8cqR0lX7QtJ2c1a62V3PMtutaaoit+hxtXuC5\
 9424.      6ZUXJePSR6btQlt5g7PqPQ822g7F8D123pc4kaGXz7qYztJxDXCxJr7foKqxwy4rikI/NvINx\
 9425.      6bkArRTTnnMWy6YA8J39LfTweThKsqlt7Mz078NDSOPOGgtGTpeG8ZRBF+xKBjdSoNe8gE6uC\
 9426.      6ucOH98jE4+cv1JEjI555TFjYj4+0KdFlojzJGWp2wc1tCaYGSeO8dBfT0u3lpDY3tazzu4wn\
 9427.      6lF9wzy2nK+sTr/qEVdANoZ0ToBdD+MY4ewOHNnkXPBvKVXLSbEGfGVD0Nzr0Fs3HID3Y1Kqx\
 9428.      6mzJ6p1C1/R6Xneyw/q9YRDLahbnsI1u76XzMLPqsK0yvQDeQ4TMR41709sIssmEgs0XH1lcj\
 9429.      67HLnUG6u2Xpy5vbOowIGqrR6cwF0TLGI5PF7pkbzIVYQU0sIaoNgul3LGAH2B1nREFYXUMia\
 9430.      6prCeAzggGxrC5gIK2dK0exs/AIRKdlIIuxkUspdSsU+rqXagqXaooXakqTiWS/a0E7zA6QIK\
 9431.      6OdMUznMAh+RCQ7hcQCFXmspr3ciuds/6gPsZFPIgpfJhwUIepRAeZ1DIk5Tue4oKfSfKZyNV\
 9432.      6pKU/J7J4Abx1EMV5mXSRDl6lMfU6jfBmBww4k7f6gLzTB+J9od/kA/uGj2mET2nkn7+zQ/JF\
 9433.      6H5Kv+pB804fkOyvwI43wM438V5sdkd/6iPzRR+SvPiL/WIH/aYRxGqMb/Oqe3d54+LWR1vr2\
 9434.      6knnnc467iD247eXBA3YYBAiFfierClXz/8jyL3Qh/zP8y+Y/1eN8jq+SKZAML/lIidjwZ8N4\
 9435.      6aLthvhxGUkGPo+p0eHKZ0sT5FsqJcQCy9UhHIvcJFIlIvANTPFWUTUhSiVdsNRnvwEQxm5uc\
 9436.      6ksjdv5evJfpOgI6c7juH8pnG2RKwlXaDYe9g8rMwYfML3A2SMWeBDopJJsmS5dUE2KttnmQa\
 9437.      6JZlMspvEpJioiEDFNpPUTbwqG3Zjhx2VCeJrIf60s2mI6blZMZVyAyYzI+1a2Y0AIqcbLUgR\
 9438.      66iRbNtnp82GrImXW0YbcbczDgqQDWNdTenvtTAlT9iPHenluV+d3eed1/5MjMBrX2LgrK2ml\
 9439.      6FuoDOz036n/kaHbAeszR3jHoI4NWB3lusTfuVgkMUkLQaH0F6+pSCS11fXRwT421vs9s7axd\
 9440.      6nvtF7/eeIeq9s1aCLsLWdh+w7sXz3IYdEsSQ0LVsebmES/vXDU9k653W4MiNq8bMj5nLioCY\
 9441.      6edGgOT6tmYwqiOW1ugiEmew6iwjvvYb3SaeZJb7XNufOo9oH8FTneWGL+BLiclptpnhPwcui\
 9442.      6T+rzcF34+ycsL7p3AveuML9i9h13beylyg8CzEz5HppadqmmDxKrAquG9L3ztedRoWxEsAYt\
 9443.      6OM1Eu0G0gyTHkxf7cSkHJQRbA4xmlqHWkv1C0KhFhBq1z81Wq1CZoWic8TJ570WfSj5qsM+Q\
 9444.      6nl4k3H5+P+P3zlv9ltQrzv41qyiSwV/gOadyQBchsmwDGu/JI8tXflE8jqUVA0Zw0SKbdDC9\
 9445.      6c4FR+fak95SdF7uqpoRe9z6YRv+85YUzF4qJy6Q8GOVNwUn/ymyjNNbmcuVfXYeH2osLdCte\
 9446.      6ebmZRyUfQQZA1BSCLK4PWA/z1kBvDZm0t+i3or1LkMD6en95pGG0UOa8ZJXgS9TdEA1I2mZw\
 9447.      61JOWWxDu0NEh4rM19H55rvueMBUZV1RjkmB3oxkXhAckpa5gzzxUDA2VLOrWFAXx+4gmfU17\
 9448.      65o3v9H7EYdvGFuM+tDB3TA4ITjVUKduO/R4bXRAcPXZusWkN+t59sFz7Hyi0FkSdzrHXQVFq\
 9449.      6b8c9k9eLRjVlBbNvt4172CanYg/F3Rket1zCTc77UZ61Gq/Be9J8hrKrxbDZMEotf5o8zHDc\
 9450.      6/UJaEtdhgwHEcBEQKM+6NBWIewLmI1sHuWYAedZCw8U1hJfSWcld+2tv3jpCFc5FnosLWC0+\
 9451.      6DnAlnOXUXLoMXrmCVerNQkZHvRm8YtE12vG8+N/vOnPcu3vM1uOnzE3u3VP2ppmLZawm2NuO\
 9452.      6tPa7xwHFCgVKpox5PVrOmaDHrThk1tX864a2+/qhJd3nCFRQ+bfUKI4O+Wgk5byB3saMcUfV\
 9453.      6C8G137yMd16zRm3ZSq+UrDlk5ha3TiAj0b74prWO/vYG+RC+ronP1/McDtefBtY1XhZE0PIB\
 9454.      6wTe7CBTte2U6KPbYd5GffApQlDGssdfmxYGSlnHrQt7++KEwUg3ikkoQyKPixgUDB6Lozjv5\
 9455.      6vM5PBnllt+UzMnP6DStFsOfossbXOefWhQApACCNpkTYGAONIowDfndqDKRFuzn685nthZPe\
 9456.      6vEL7TIWkXAG2yxKBH90+yMzuRzWn3KMmyKGwZWnIErlJ9Vwt8OtR6+4TKad5y9+ViBtTzVG+\
 9457.      6tpv/xiLrcGKJRtYvCUlGeL4Dwy1jo1CSQe0X71EXK1YG44ztxTONjIslL8SwY0Cki0k0vsX/\
 9458.      6/xz7CxkAc9dEdJZhMy/JCGzD2FAGtUcag0tc2e2miJkp477V2qTKB+nFnDl/noxpXJ+yqVdO\
 9459.      6wNjbplmeiuburg9ii1Z1zwtG8QjcJAiVPSOV2mHzq1Qt7p2+YCcIKPmFusE5O+m8s+Wd8o3t\
 9460.      6qO1b1IZF8N0tx6RQnZ9Ux3gXijHlolixst6vhJV6ao0ZFzSprfAc3x0MLvxU0OsmXEVddMVK\
 9461.      629CC6mPgPtXTUW7tVnZxwm0DTJwNOeVRV4axMSPlpgyv1Va1MQhQqWwUOb0s+gVLOecos4Nf\
 9462.      6eqlFW3fLQrlP86R4XRxrDHF0VIx6ArM5/sTWtObY6U2aosgxbN6FUa1iNTUpMThk1sUfJOC6\
 9463.      6s1SKo9D0g1NfiVmavyful/K7nZdDgutV1A26i7FR3r16bv3zz1cGw+ta17IX/+ripyutix3C\
 9464.      6xNmCxs7uiqKu9/Zjjn06tblXpJxlaLF5Od0d5W9QhQrs2u6UN0trQlCyEK2j9VYgCEIDrhQN\
 9465.      6c00rxg/FOfZ1N+nLV7RXDsYP+p0EzqKcuPujzuzEQsu2mFf4nYvf3Yp32rq/RYLetDLuOOTc\
 9466.      60WXBtgoech7AHUxAxPBg81qWCsYlzTofRU5/MpuyNoegR6mCJO5ckrLOhWbG7xo/VGwGgpRb\
 9467.      6+Ch+TmlcuY6Qct/2x3gxzeDUU9u+ltexrjelJ0VRR9KXH/AqrbYxHa0vmQ/kBnE5EORBK1ZH\
 9468.      6mTSy7A8DJMgzzqDsu9ML5J3ufkuUNDCfN5UKAjBgw2I/QlS8MQ6o/ll9dTAdoM7HYtV4cNWE\
 9469.      6U4pOl5Y4SIzdMbNSjXFmsBV1uXXf7GaBZZslpFGFiIpokSzxWj4hjlGl4VKJDACo7ScxQf29\
 9470.      6kM8gHD3nUJkwkN2aW2TGttqwOrygJ7r9nYX2tYqy7Z3TQV5ocWzUI8l871y3LsQLoTgEO76B\
 9471.      6Upp69hy6VKRpZvpvgfQ2T06qgXjxh38eatREitX6bzKggIYmN4sAkA3a5oeJZDK3ahQrVJwa\
 9472.      6AD65cEGBkS/tKH9TtybiREEWCMcKD0HH0gELtjB+KNSk7bspmpr6eb0CscIiFyZpmXu8+gxw\
 9473.      6O7pJNbAK2h9q2c5dMHBaoi5DylbNGdweVVdN3Jm9u6YXXlmx4nYY2vIPfSkrE/vyv9gn/Z+j\
 9474.      6R3HKExaUhdV0Az77YWbQPhNfjw+F0vTteSMin+wIfxyPe0DEoI4uz6o2IXwsZC7sg8MicQ3o\
 9475.      6wys+NJYKVW72YiVQ5LKDVwrEg2jNVM6XdNjbsHlRDcAkD08o5iWtFB2dVoydRmmDRLalE+4t\
 9476.      63gBbAPa7n7qXXXbTZTJXZKy5+1W0K7dgYEcIlu90ovC0C+5gxXiKtZisT14qDJ7f2ksyK59U\
 9477.      6r3QeHtBb24mPz7YDB3rgMTyUZ/fxM8h2i1Z21B8/VA5+9l7BKaOJZ15lWsyPv/z6CjU32ZKq\
 9478.      6+QFeyUywxYnUxUmcQfGc1Sp69oE2n6zFL8BXf5rc3cJMM6S97gagTT1bi7cmAV4MibkC4rz/\
 9479.      6icmmFtMlo5aN1Wp3uxsBfd4+9T42xmxvd79FV/hfuviBcrIaX092PrY5rle9FR4wTnDzrwj4\
 9480.      67frD2d0KsMcdcADQ1Yu1LECg9Wj3yOS8OhrJdQBqXqsam17vmt2wjjjouHE/EO9sGPdqt23v\
 9481.      6j8rL6wid6ulagtNK5p1hjRkFtUxTIaZnIXk63Zb3P0t5MQ+3vxHIFrmgAdWwiDuA67tbVIF6\
 9482.      6wJ53z0uhyhsfH9bgF0kPT9v2hrT3HKIBgUXIYoxsVU+uryemiUiQEwh+BfxP//qLShlumR26\
 9483.      6I8OqjD+x3hHDj/IrEWmvyL6ioG/atfxe+5GzIqRgfaoayWOiTk+YixO15KDO6Os3XACDjboe\
 9484.      6ryXXOuEmTpDsc7czk+H04Kw1PNJazW32CAURHwBldqK0/nqYHtcrtLyyTYmoD8hbcnJUfa3U\
 9485.      63FxWNus7uic3Qm1BzEecJW0MAz+W2CyN9FLIy+EpSy6CjkXsllZw1uBs1SxrQWM97/vnHu7m\
 9486.      6OtrkRl8AtBN3RDxI/fg7dZLLtDFYuCYYPMwXiO6ZIpwJ1GGydI9oUYYgnQQKDKoMTcwsjrfe\
 9487.      6Tcht6y18bLcpNfX41WE27447vLNzHuF+j15co5N7Py8vKUpTCoghHMEYKkM6y02lvX+9XiFg\
 9488.      6xBKMRNiwX69+LJb2Xa5WGqo7Rlk0cxsLVd0l2UXAW5jORg31sFMKYWXsDcRUKRDP8Q87OjiM\
 9489.      6dI1hNEt43netf8rOyfp+L58fq3holY9gxXwRJLY6gahgLQi4hS8w9LS+rFcJtdSCBrQLWsMs\
 9490.      6aDg/n8/P8/N+fcyoLepYr3W/CIUT7HsRQTtkduddbVfbo6Twt6fyJVPRrUGqRkWp3rdry65v\
 9491.      6sPYInyq1mPHrQDrqGJYI/LzA/QAzAXLnx+lu9uxHTEka9xgWgRvqEioskh+UWgD4nDvTAxaz\
 9492.      63v9BqqmFuQwy1wSXye1Df1NXVF7G8bUFxUE4F9axG5fm+vFQJvP8iuYjrFveB6++AqmJTQJ0\
 9493.      69GHjbPhzdSzkZGxokQzONVs0R0FCPJz1hJKbvDKsaj9hT0vp/gH5oiT8pAbWsBChwAbxHgDd\
 9494.      659iJVZE3bAzPRN1RuG+MT7th+J3i6KFwVJvPvsGRDIZW4P2rVfiKjDVBM2Va+w6PgI0c5u3K\
 9495.      6O7MrWryPhXFFdBoAwi2JCaW9sZ3fTagQ4Tld6u4djwcWzeCdiYoeNbfalsRYo740afYQ1Rid\
 9496.      6Bp/E9mbcTemEjoWWXIU7I5nK5H/BEqmZnPMyhDV234BTLQKCe6nhU+frwQo1gNFWf+eQGN62\
 9497.      6aeF7BuzaN/94W2xlKd8t8KMA/3uoxymFt19OlCjYZeaMWbTKM9Yog9zDhptYMOzIQAoO7kn6\
 9498.      6nTao8CxjrRRgjKe7mKa+tzuufhAAZtgjA92THkulWvIzEi0++j1DvXMnupDUS8aVusWain+c\
 9499.      6CcvmR5orC+RcJs3wVahLYyEcqbvAS2e0QJ6BlU36R/IEd9Aol9q+M+UGvlo8EyRzISvqusNS\
 9500.      67ePQ6cQzG1s725db4jNYNHAfF3KFG8wHqDwZDpWDsJ5qRLXR1ulFx85GhkypPubYaCiOQ5DR\
 9501.      6PQUiNpgk4fLJHenSMLMiswXsqW4Cpln1rFoHzpOoBbuZIixmVyhKajeqlFmp8zNAEsbEJz0g\
 9502.      6X0qlQuykZhf82pkhq2hWtCtYUdBODn6iPTBJT5Zk8IqFxqfBeFKjXk/sMeumhT8muOtq2Bgn\
 9503.      6dR4fj6RoOi0zI25kajAXlDZhUhS39jipk39h/69AfDPBLmOxhDj7Lg/WUTbOwJiJ3p7WtOpm\
 9504.      6ypARmhorQifINNm1CNS99GfDcLbD8sn8Fvlmvn7CmW65Pdmu6bKtuE0tn7NglIX1e/JAJP+G\
 9505.      6gB3At7cSOp92rl0lp0pp0xVb5YaQedwGgcJA1pT4cy24lS+jvzDw86YTfb2igJm5MysHmejW\
 9506.      6ZTGXpoAoLBLucUGEz/DwbjqOdzGAl5jy5VoCQws5zNYl4SVt030aZulYMgpDBPZd+kL0wV+w\
 9507.      6nob2LPRDQGEbdUoeFm4fEKio9c/ferVlpSO8Bx7OFZyHip1PIizvoqFe02kpmS17TvIOty42\
 9508.      6+Q0QaCnOpeLsPwwo+vixIeIeUjucUsKejVlez35qyuC0mm5pJJJLEVP2JAe/LTOwUUfKJkNy\
 9509.      6lEe3Kdth241ZNQmkVcAIh6DZJBzvQov5fn3JZA0phBWdNq5iTsm5N2D8gyve3V3X2o3zF3VY\
 9510.      6OqEBgTIADAbC69z7vOKJjGOzHRmUUwLU66iabtIbqR6SPOHCL+fCTfvpKcB/oG2p3wRKErEJ\
 9511.      6v1YOfu9iaKEMLXS3ptdH8fwN2Rdww9bZ7rFa2bwrzcyux3o+hPV6bJZpb71j7lLAdzge3VX7\
 9512.      69uSCdz6f/FDb7+wzWnbbDSPj9R20+PybDUm/lVAsTuF0aycFQwJfPCUwcBvCGWEq6xoTIEOy\
 9513.      6b0bLta20+LYRYdyEceX7ypfezQKIy5OvJTAHCJy/WyOYaDVyPucMsHnZ0GCH75Cd//te1Bv2\
 9514.      6RkMykqYurBiNbuH3Xfuprirr4Dd453O6abAYGb5tw1d6wrBL8p1J1Sx9Lgw7yxqYn0FTrc0y\
 9515.      659yLlV+4zIkLfZlPFRVnanHpTyrIlpn4lGkt269+JXnIWhEQWNvuVsrt531jr+8AHkVZfQU8\
 9516.      68U/4AUZMuOj5iliigFrof/usmloYEI1f8erhJku75snYW7YmFmUcoC7UtG/KfJRuz6j0tWPa\
 9517.      656J5QA0rJHwSIhNT4GWvez19HT2lia+Pz7/+MVEWlvjY6+9P85a0y9qWkTzQ7nF0wDXpQpw3\
 9518.      6K4xnfK2L08b5MrxdeI+DDfVDeV2JY0Fp6KH602tj2MbxxKM8oG+wTkE/dr8jyo4Sfs/IV6uf\
 9519.      6+IIXpH2Nca1+WCJV5qEv193bcUELLR4iFu83xUedKy9353tn+3o01dF2bNEQ3fK9Q5tCXrCi\
 9520.      6La+woCuvEeYrr+PiN2+i2V/eDJck580pyra8BV5ZIZbpe3kr5vJD3pqoGsnbcl/d+ndvR23b\
 9521.      6K41M4dKwaAwDaMA1gZGBoQWAcYE9mYkmQOnAjkaG41FkGkIP2BAIgKvUvzhpE5JbA6lze2iL\
 9522.      65Nr+AwiDo2W4BStvK30dKy0JGNbzAY5akexsrV0xo5K8rY50LOTLvDyukIZNbRLKOCk18mD3\
 9523.      6WxmZGlsCMxNdGFYGNJnetUWyCPgo4BONEL4I9b8UeEBGYXuCdCd+DkctrqVLYXGSfE46kvAu\
 9524.      6+ltK5SRxQPnjUqyJXsSYs6VY6WPKfns9+IXjHhd5wQvGipgFdMwVEQ+A7a2AAS0clQwH7KHW\
 9525.      6SEGjhnklSVRghMtPy6gEtJRIKJeYkpQyQiequQunFOOU4BLdK1yp55olZS6npyPhMnvK7xIa\
 9526.      6pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
 9527.      61R8uVi8Zu9nRFqk/t0gR6wmWOlzuKRqk33HpO8qQ+nbGoEZLL/0Va156SJ+u+t86/os7ic49\
 9528.      6/7xoEqvL+2E8VOyCTuT/7j269Zy4jUtN+g4="
 9529.      6    ) format("woff2");
 9530.      6}
 9531.      6.JSLINT_,
 9532.      6.JSLINT_ address,
 9533.      6.JSLINT_ button,
 9534.      6.JSLINT_ cite,
 9535.      6.JSLINT_ dd,
 9536.      6.JSLINT_ dfn,
 9537.      6.JSLINT_ dl,
 9538.      6.JSLINT_ dt,
 9539.      6.JSLINT_ fieldset,
 9540.      6.JSLINT_ fieldset > div,
 9541.      6.JSLINT_ input,
 9542.      6.JSLINT_ label,
 9543.      6.JSLINT_ legend,
 9544.      6.JSLINT_ ol,
 9545.      6.JSLINT_ samp,
 9546.      6.JSLINT_ style,
 9547.      6.JSLINT_ textarea,
 9548.      6.JSLINT_ ul {
 9549.      6    border: 0;
 9550.      6    box-sizing: border-box;
 9551.      6    margin: 0;
 9552.      6    padding: 0;
 9553.      6}
 9554.      6/* disable text inflation algorithm used on some smartphones and tablets */
 9555.      6.JSLINT_ {
 9556.      6    -ms-text-size-adjust: none;
 9557.      6    -webkit-text-size-adjust: none;
 9558.      6    text-size-adjust: none;
 9559.      6}
 9560.      6.JSLINT_REPORT_ div {
 9561.      6    box-sizing: border-box;
 9562.      6}
 9563.      6/*csslint ignore:end*/
 9564.      6
 9565.      6/* css - jslint_report - font */
 9566.      6.JSLINT_,
 9567.      6.JSLINT_ fieldset legend,
 9568.      6.JSLINT_ .center {
 9569.      6    font-family: daley, sans-serif;
 9570.      6    font-size: 14px;
 9571.      6}
 9572.      6.JSLINT_ fieldset textarea,
 9573.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS dt,
 9574.      6.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
 9575.      6    font-size: 12px;
 9576.      6}
 9577.      6.JSLINT_ fieldset textarea,
 9578.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS > div {
 9579.      6    font-family: monospace;
 9580.      6}
 9581.      6.JSLINT_ fieldset > div {
 9582.      6    font-family: sans-serif;
 9583.      6}
 9584.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dfn {
 9585.      6    font-style: normal;
 9586.      6    font-weight: bold;
 9587.      6}
 9588.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dt {
 9589.      6    font-style: italic;
 9590.      6}
 9591.      6.JSLINT_ #JSLINT_REPORT_TITLE {
 9592.      6    font-size: 32px;
 9593.      6}
 9594.      6
 9595.      6/* css - jslint_report - general */
 9596.      6.JSLINT_ {
 9597.      6    background: antiquewhite;
 9598.      6}
 9599.      6.JSLINT_ fieldset {
 9600.      6    background: gainsboro;
 9601.      6    clear: both;
 9602.      6    margin: 16px 40px;
 9603.      6    width: auto;
 9604.      6}
 9605.      6.JSLINT_ fieldset address {
 9606.      6    float: right;
 9607.      6}
 9608.      6.JSLINT_ fieldset legend,
 9609.      6.JSLINT_ .center {
 9610.      6    text-align: center;
 9611.      6}
 9612.      6.JSLINT_ fieldset legend {
 9613.      6    background: darkslategray;
 9614.      6    color: white;
 9615.      6    padding: 4px 0;
 9616.      6    width: 100%;
 9617.      6}
 9618.      6.JSLINT_ fieldset textarea {
 9619.      6    padding: 4px;
 9620.      6    resize: none;
 9621.      6    white-space: pre;
 9622.      6    width: 100%;
 9623.      6}
 9624.      6.JSLINT_ fieldset textarea::selection {
 9625.      6    background: wheat;
 9626.      6}
 9627.      6.JSLINT_ fieldset > div {
 9628.      6    padding: 16px;
 9629.      6    width: 100%;
 9630.      6    word-wrap: break-word;
 9631.      6}
 9632.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level {
 9633.      6    background: cornsilk;
 9634.      6    padding: 8px 16px;
 9635.      6}
 9636.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dd {
 9637.      6    line-height: 20px;
 9638.      6    padding-left: 120px;
 9639.      6}
 9640.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dfn {
 9641.      6    display: block;
 9642.      6    line-height: 20px;
 9643.      6}
 9644.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dl {
 9645.      6    position: relative
 9646.      6}
 9647.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dt {
 9648.      6    line-height: 20px;
 9649.      6    position: absolute;
 9650.      6    text-align: right;
 9651.      6    width: 100px;
 9652.      6}
 9653.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level0 {
 9654.      6    background: white;
 9655.      6}
 9656.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level1 {
 9657.      6    /* yellow */
 9658.      6    background: #ffffe0;
 9659.      6    margin-left: 16px;
 9660.      6}
 9661.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level2 {
 9662.      6    /* green */
 9663.      6    background: #e0ffe0;
 9664.      6    margin-left: 32px;
 9665.      6}
 9666.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level3 {
 9667.      6    /* blue */
 9668.      6    background: #D0D0ff;
 9669.      6    margin-left: 48px;
 9670.      6}
 9671.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level4 {
 9672.      6    /* purple */
 9673.      6    background: #ffe0ff;
 9674.      6    margin-left: 64px;
 9675.      6}
 9676.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level5 {
 9677.      6    /* red */
 9678.      6    background: #ffe0e0;
 9679.      6    margin-left: 80px;
 9680.      6}
 9681.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level6 {
 9682.      6    /* orange */
 9683.      6    background: #ffe390;
 9684.      6    margin-left: 96px;
 9685.      6}
 9686.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level7 {
 9687.      6    /* gray */
 9688.      6    background: #e0e0e0;
 9689.      6    margin-left: 112px;
 9690.      6}
 9691.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level8 {
 9692.      6    margin-left: 128px;
 9693.      6}
 9694.      6.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level9 {
 9695.      6    margin-left: 144px;
 9696.      6}
 9697.      6.JSLINT_ #JSLINT_REPORT_PROPERTIES {
 9698.      6    background: transparent;
 9699.      6}
 9700.      6.JSLINT_ #JSLINT_REPORT_PROPERTIES textarea {
 9701.      6    background: honeydew;
 9702.      6    height: 100px;
 9703.      6}
 9704.      6.JSLINT_ #JSLINT_REPORT_TITLE {
 9705.      6    color: darkslategray;
 9706.      6    padding-top: 16px;
 9707.      6}
 9708.      6.JSLINT_ #JSLINT_REPORT_WARNINGS cite {
 9709.      6    display: block;
 9710.      6    margin: 16px 0 4px 0;
 9711.      6    overflow-x: hidden;
 9712.      6    white-space: pre-line;
 9713.      6}
 9714.      6.JSLINT_ #JSLINT_REPORT_WARNINGS cite:nth-child(1) {
 9715.      6    margin-top: 0;
 9716.      6}
 9717.      6.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
 9718.      6    background: lavenderblush;
 9719.      6    display: block;
 9720.      6    padding: 4px;
 9721.      6    white-space: pre-wrap;
 9722.      6}
 9723.      6.JSLINT_ #JSLINT_REPORT_WARNINGS > div {
 9724.      6    background: pink;
 9725.      6    max-height: 400px;
 9726.      6    overflow-y: auto;
 9727.      6}
 9728.      6.JSLINT_ #JSLINT_REPORT_WARNINGS > legend {
 9729.      6/* Google Lighthouse Accessibility - Background and foreground colors do not */
 9730.      6/* have a sufficient contrast ratio. */
 9731.      6    /* background: indianred; */
 9732.      6    background: #b44;
 9733.      6}
 9734.      6</style>
 9735.      6            `).trim() + "\n";
 9736.      6
 9737.      6// Produce the Title.
 9738.      6
 9739.      6    html += "<div class=\"center\" id=\"JSLINT_REPORT_TITLE\">\n";
 9740.      6    html += "JSLint Report\n";
 9741.      6    html += "</div>\n";
 9742.      6
 9743.      6// Produce the HTML Error Report.
 9744.      6// <cite>
 9745.      6//     <address>LINE_NUMBER</address>
 9746.      6//     MESSAGE
 9747.      6// </cite>
 9748.      6// <samp>EVIDENCE</samp>
 9749.      6
 9750.      6    html += "<fieldset id=\"JSLINT_REPORT_WARNINGS\">\n";
 9751.      6    html += "<legend>Report: Warnings (" + warnings.length + ")</legend>\n";
 9752.      6    html += "<div>\n";
 9753.      1    if (stop) {
 9754.      1        html += "<div class=\"center\">JSLint was unable to finish.</div>\n";
 9755.      1    }
 9756.      7    warnings.forEach(function ({
 9757.      7        column,
 9758.      7        line,
 9759.      7        line_source,
 9760.      7        message,
 9761.      7        stack_trace = ""
 9762.      7    }, ii) {
 9763.      7        html += (
 9764.      7            "<cite>"
 9765.      7            + address(line, column)
 9766.      7            + htmlEscape((ii + 1) + ". " + message)
 9767.      7            + "</cite>"
 9768.      7            + "<samp>"
 9769.      7            + htmlEscape(line_source.slice(0, 400) + "\n" + stack_trace)
 9770.      7            + "</samp>\n"
 9771.      7        );
 9772.      7    });
 9773.      3    if (warnings.length === 0) {
 9774.      3        html += "<div class=\"center\">There are no warnings.</div>\n";
 9775.      3    }
 9776.      6    html += "</div>\n";
 9777.      6    html += "</fieldset>\n";
 9778.      6
 9779.      6// Produce the /*property*/ directive.
 9780.      6
 9781.      6    html += "<fieldset id=\"JSLINT_REPORT_PROPERTIES\">\n";
 9782.      6    html += (
 9783.      6        "<legend>Report: Properties ("
 9784.      6        + Object.keys(property).length
 9785.      6        + ")</legend>\n"
 9786.      6    );
 9787.      6    html += "<label>\n";
 9788.      6    html += "<textarea readonly>";
 9789.      6    html += "/*property";
 9790.    300    Object.keys(property).sort().forEach(function (key, ii) {
 9791.    299        if (ii !== 0) {
 9792.    299            html += ",";
 9793.    299            length_80 += 2;
 9794.    299        }
 9795.     42        if (length_80 + key.length >= 80) {
 9796.     42            length_80 = 4;
 9797.     42            html += "\n   ";
 9798.     42        }
 9799.    300        html += " " + key;
 9800.    300        length_80 += key.length;
 9801.    300    });
 9802.      6    html += "\n*/\n";
 9803.      6    html += "</textarea>\n";
 9804.      6    html += "</label>\n";
 9805.      6    html += "</fieldset>\n";
 9806.      6
 9807.      6// Produce the HTML Function Report.
 9808.      6// <div class=LEVEL>
 9809.      6//     <address>LINE_NUMBER</address>
 9810.      6//     <dfn>FUNCTION_NAME_AND_SIGNATURE</dfn>
 9811.      6//     <dl>
 9812.      6//         <dt>DETAIL</dt>
 9813.      6//         <dd>NAMES</dd>
 9814.      6//     </dl>
 9815.      6// </div>
 9816.      6
 9817.      6    html += "<fieldset id=\"JSLINT_REPORT_FUNCTIONS\">\n";
 9818.      6    html += "<legend>Report: Functions (" + functions.length + ")</legend>\n";
 9819.      6    html += "<div>\n";
 9820.      2    if (json) {
 9821.      2
 9822.      2// Bugfix - fix website crashing when linting pure json-object.
 9823.      2// return (
 9824.      2
 9825.      2        html += (
 9826.      2            warnings.length === 0
 9827.      2            ? "<div class=\"center\">JSON: good.</div>\n"
 9828.      2            : "<div class=\"center\">JSON: bad.</div>\n"
 9829.      2        );
 9830.      4    } else if (functions.length === 0) {
 9831.      4        html += "<div class=\"center\">There are no functions.</div>\n";
 9832.      4    }
 9833.      6    exports = Object.keys(exports).sort();
 9834.      6    froms.sort();
 9835.      6    global = Object.keys(global.context).sort();
 9836.      6    module = (
 9837.      6        module
 9838.      1        ? "module"
 9839.      5        : "global"
 9840.      6    );
 9841.      3    if (global.length + froms.length + exports.length > 0) {
 9842.      3        if (functions.length === 0) {
 9843.      3            html += "<br>\n";
 9844.      3        }
 9845.      3        html += "<div class=\"level level0\">\n";
 9846.      3        html += detail(module, global);
 9847.      3        html += detail("import from", froms);
 9848.      3        html += detail("export", exports);
 9849.      3        html += "</div>\n";
 9850.      3    }
 9851.    321    functions.forEach(function (the_function) {
 9852.    321        let {
 9853.    321            context,
 9854.    321            from,
 9855.    321            id,
 9856.    321            level,
 9857.    321            line,
 9858.    321            name,
 9859.    321
 9860.    321// Bugfix - fix html-report from crashing if parameters is undefined.
 9861.    321
 9862.    321            parameters = [],
 9863.    321            signature
 9864.    321        } = the_function;
 9865.    321        let list = Object.keys(context);
 9866.    321        let params;
 9867.    321        html += (
 9868.    321            "<div class=\"level level" + htmlEscape(level) + "\">"
 9869.    321            + address(line, from + 1)
 9870.    321            + "<dfn>"
 9871.    321            + (
 9872.    321                id === "=>"
 9873.      1                ? (
 9874.      1                    "\u00ab" + htmlEscape(name) + "\u00bb"
 9875.      1                    + htmlEscape(signature)
 9876.      1                    + " =>"
 9877.      1                )
 9878.    320                : (
 9879.    320                    typeof name === "string"
 9880.    320                    ? "\u00ab" + htmlEscape(name) + "\u00bb"
 9881.    320                    : htmlEscape(name.id)
 9882.    320                ) + htmlEscape(signature)
 9883.    321            )
 9884.    321            + "</dfn>"
 9885.    321        );
 9886.    321        params = [];
 9887.    470        parameters.forEach(function extract({
 9888.    470            id,
 9889.    470            names
 9890.    470        }) {
 9891.    470            switch (id) {
 9892.      6            case "[":
 9893.     42            case "{":
 9894.     42
 9895.     42// Recurse extract().
 9896.     42
 9897.     42                names.forEach(extract);
 9898.     42                break;
 9899.      4            case "ignore":
 9900.      4                break;
 9901.    424            default:
 9902.    424                params.push(id);
 9903.    470            }
 9904.    470        });
 9905.    321        html += detail("parameter", params.sort());
 9906.    321        list.sort();
 9907.   2202        html += detail("variable", list.filter(function (id) {
 9908.   2202            return (
 9909.   2202                context[id].role === "variable"
 9910.   1692                && context[id].parent === the_function
 9911.   2202            );
 9912.   2202        }));
 9913.   2202        html += detail("exception", list.filter(function (id) {
 9914.   2202            return context[id].role === "exception";
 9915.   2202        }));
 9916.   2202        html += detail("closure", list.filter(function (id) {
 9917.   2202            return (
 9918.   2202                context[id].closure === true
 9919.   1494                && context[id].parent === the_function
 9920.   2202            );
 9921.   2202        }));
 9922.   2202        html += detail("outer", list.filter(function (id) {
 9923.   2202            return (
 9924.   2202                context[id].parent !== the_function
 9925.   1190                && context[id].parent.id !== "(global)"
 9926.   2202            );
 9927.   2202        }));
 9928.   2202        html += detail(module, list.filter(function (id) {
 9929.   2202            return context[id].parent.id === "(global)";
 9930.   2202        }));
 9931.   2202        html += detail("label", list.filter(function (id) {
 9932.   2202            return context[id].role === "label";
 9933.   2202        }));
 9934.    321        html += "</div>\n";
 9935.    321    });
 9936.      6    html += "</div>\n";
 9937.      6    html += "</fieldset>\n";
 9938.      6    return html;
 9939.      6}
 9940.      1
 9941.     10async function jstestDescribe(description, testFunction) {
 9942.     10
 9943.     10// This function will create-and-run test-group <testFunction>
 9944.     10// with given <description>.
 9945.     10
 9946.     10    let message;
 9947.     10    let result;
 9948.     10    let timerTimeout;
 9949.     10
 9950.     10// Init jstestTimeStart.
 9951.     10
 9952.      1    if (jstestTimeStart === undefined) {
 9953.      1        jstestTimeStart = jstestTimeStart || Date.now();
 9954.      1        process.on("exit", jstestOnExit);
 9955.      1    }
 9956.     10
 9957.     10// PR-457 - Wait awhile for imports to initialize.
 9958.     10
 9959.     10    await new Promise(function (resolve) {
 9960.     10        setTimeout(resolve);
 9961.     10    });
 9962.     10
 9963.     10// Init jstestItList.
 9964.     10
 9965.     10    jstestItList = [];
 9966.     10    testFunction();
 9967.     10
 9968.     10// Wait for jstestItList to resolve.
 9969.     10
 9970.     10    timerTimeout = setTimeout(noop, 0x7fffffff);
 9971.     10    result = await Promise.all(jstestItList);
 9972.     10    clearTimeout(timerTimeout);
 9973.     10
 9974.     10// Print test results.
 9975.     10
 9976.     10    message = (
 9977.     10        "\n  " + (Date.now() - jstestTimeStart) + "ms"
 9978.     10        + " - test describe - " + description + "\n"
 9979.     66        + result.map(function ([
 9980.     66            err, description, mode
 9981.     66        ]) {
 9982.     66            jstestItCount += 1;
 9983.      1            if (err) {
 9984.      1                jstestCountFailed += 1;
 9985.      1                err = (
 9986.      1                    "    \u001b[31m\u2718 " + jstestItCount + ". test it - "
 9987.      1                    + description + "\n" + err.stack + "\u001b[39m"
 9988.      1                );
 9989.      1                if (mode === "pass") {
 9990.      1                    jstestCountFailed -= 1;
 9991.      1                    err = "";
 9992.      1                }
 9993.      1            }
 9994.     66            return err || (
 9995.     66                "    \u001b[32m\u2714 " + jstestItCount + ". test it - "
 9996.     66                + description + "\u001b[39m"
 9997.     66            );
 9998.     66        }).join("\n")
 9999.     10    );
10000.     10    console.error(message);
10001.     10}
10002.      1
10003.     66function jstestIt(description, testFunction, mode) {
10004.     66
10005.     66// This function will create-and-run test-case <testFunction>
10006.     66// inside current test-group with given <description>.
10007.     66
10008.     66    jstestCountTotal += 1;
10009.     66    jstestItList.push(new Promise(async function (resolve) {
10010.     66        let err;
10011.     66        try {
10012.     65            await testFunction();
10013.     65        } catch (errCaught) {
10014.      1            err = errCaught;
10015.      1        }
10016.     66        resolve([err, description, mode]);
10017.     66    }));
10018.     66}
10019.      1
10020.      2function jstestOnExit(exitCode, mode) {
10021.      2
10022.      2// This function will on process-exit, print test-report
10023.      2// and exit with non-zero exit-code if any test failed.
10024.      2
10025.      2    let message = (
10026.      2        (
10027.      2            (jstestCountFailed || mode === "testsFailed")
10028.      1            ? "\n\u001b[31m"
10029.      1            : "\n\u001b[32m"
10030.      2        )
10031.      2        + "  tests total  - " + jstestCountTotal + "\n"
10032.      2        + "  tests failed - " + jstestCountFailed + "\n"
10033.      2        + "\n"
10034.      2        + "  time finished - "
10035.      2        + Number(Date.now() - jstestTimeStart).toLocaleString()
10036.      2        + " ms\n"
10037.      2        + "\u001b[39m"
10038.      2    );
10039.      1    if (mode !== "testsFailed") {
10040.      1        console.error(message);
10041.      1    }
10042.      2    process.exitCode = exitCode || jstestCountFailed;
10043.      2    return message;
10044.      2}
10045.      1
10046.    107async function moduleFsInit() {
10047.    107
10048.    107// This function will import nodejs builtin-modules if they have not yet been
10049.    107// imported.
10050.    107
10051.    107// State 3 - Modules already imported.
10052.    107
10053.    104    if (moduleFs !== undefined) {
10054.    104        return;
10055.    104    }
10056.      3
10057.      3// State 2 - Wait while modules are importing.
10058.      3
10059.      3    if (moduleFsInitResolveList !== undefined) {
10060.      2        return new Promise(function (resolve) {
10061.      2            moduleFsInitResolveList.push(resolve);
10062.      2        });
10063.      2    }
10064.      1
10065.      1// State 1 - Start importing modules.
10066.      1
10067.      1    moduleFsInitResolveList = [];
10068.      1    [
10069.      1        moduleChildProcess,
10070.      1        moduleFs,
10071.      1        modulePath,
10072.      1        moduleUrl
10073.      1    ] = await Promise.all([
10074.      1        import("child_process"),
10075.      1        import("fs"),
10076.      1        import("path"),
10077.      1        import("url")
10078.      1    ]);
10079.      2    while (moduleFsInitResolveList.length > 0) {
10080.      2        moduleFsInitResolveList.shift()();
10081.      2    }
10082.    107}
10083.      1
10084.   2728function noop(val) {
10085.   2728
10086.   2728// This function will do nothing except return <val>.
10087.   2728
10088.   2728    return val;
10089.   2728}
10090.      1
10091.  12919function objectDeepCopyWithKeysSorted(obj) {
10092.  12919
10093.  12919// This function will recursively deep-copy <obj> with keys sorted.
10094.  12919
10095.  12919    let sorted;
10096.   8995    if (typeof obj !== "object" || !obj) {
10097.   8995        return obj;
10098.   8995    }
10099.   3924
10100.   3924// Recursively deep-copy list with child-keys sorted.
10101.   3924
10102.   3924    if (Array.isArray(obj)) {
10103.   1338        return obj.map(objectDeepCopyWithKeysSorted);
10104.   2586    }
10105.   2586
10106.   2586// Recursively deep-copy obj with keys sorted.
10107.   2586
10108.   2586    sorted = Object.create(null);
10109.   7457    Object.keys(obj).sort().forEach(function (key) {
10110.   7457        sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
10111.   7457    });
10112.   2586    return sorted;
10113.   2586}
10114.      1
10115.   2783function object_assign_from_list(dict, list, val) {
10116.   2783
10117.   2783// Assign each property-name from <list> to <dict>.
10118.   2783
10119.  89614    list.forEach(function (key) {
10120.  89614        dict[key] = val;
10121.  89614    });
10122.   2783    return dict;
10123.   2783}
10124.      1
10125.     97function v8CoverageListMerge(processCovs) {
10126.     97
10127.     97// This function is derived from MIT Licensed v8-coverage at
10128.     97// https://github.com/demurgos/v8-coverage/tree/master/ts
10129.     97// https://github.com/demurgos/v8-coverage/blob/master/ts/LICENSE.md
10130.     97//
10131.     97// Merges a list of v8 process coverages.
10132.     97// The result is normalized.
10133.     97// The input values may be mutated, it is not safe to use them after passing
10134.     97// them to this function.
10135.     97// The computation is synchronous.
10136.     97// @param processCovs Process coverages to merge.
10137.     97// @return Merged process coverage.
10138.     97
10139.     97    let resultMerged = [];      // List of merged scripts from processCovs.
10140.     97    let urlToScriptDict = new Map();    // Map scriptCov.url to scriptCovs.
10141.     97
10142.   1094    function compareRangeList(aa, bb) {
10143.   1094
10144.   1094// Compares two range coverages.
10145.   1094// The ranges are first ordered by ascending `startOffset` and then by
10146.   1094// descending `endOffset`.
10147.   1094// This corresponds to a pre-order tree traversal.
10148.   1094
10149.   1065        if (aa.startOffset !== bb.startOffset) {
10150.   1065            return aa.startOffset - bb.startOffset;
10151.   1065        }
10152.     29        return bb.endOffset - aa.endOffset;
10153.     29    }
10154.     97
10155.   1707    function dictKeyValueAppend(dict, key, val) {
10156.   1707
10157.   1707// This function will append <val> to list <dict>[<key>].
10158.   1707
10159.   1707        let list = dict.get(key);
10160.   1165        if (list === undefined) {
10161.   1165            list = [];
10162.   1165            dict.set(key, list);
10163.   1165        }
10164.   1707        list.push(val);
10165.   1707    }
10166.     97
10167.    384    function mergeTreeList(parentTrees) {
10168.    384
10169.    384// This function will return RangeTree object with <parentTrees> merged into
10170.    384// property-children.
10171.    384// @precondition Same `start` and `end` for all the parentTrees
10172.    384
10173.    119        if (parentTrees.length <= 1) {
10174.    119            return parentTrees[0];
10175.    265        }
10176.    265
10177.    265// new RangeTree().
10178.    265
10179.    265        return {
10180.    265
10181.    265// Merge parentTrees into property-children.
10182.    265
10183.    265            children: mergeTreeListToChildren(parentTrees),
10184.    669            delta: parentTrees.reduce(function (aa, bb) {
10185.    669                return aa + bb.delta;
10186.    669            }, 0),
10187.    265            end: parentTrees[0].end,
10188.    265            start: parentTrees[0].start
10189.    265        };
10190.    265    }
10191.     97
10192.    265    function mergeTreeListToChildren(parentTrees) {
10193.    265
10194.    265// This function will return <resultChildren> with <parentTrees> merged.
10195.    265
10196.    265        let openRange;
10197.    265        let parentToChildDict = new Map();      // Map parent to child.
10198.    265        let queueList;
10199.    265        let queueListIi = 0;
10200.    265        let queueOffset;
10201.    265        let queueTrees;
10202.    265        let resultChildren = [];
10203.    265        let startToTreeDict = new Map();        // Map tree.start to tree.
10204.    639        function nextXxx() {
10205.    639
10206.    639// Increment nextOffset, nextTrees.
10207.    639
10208.    639            let [
10209.    639                nextOffset, nextTrees
10210.    300            ] = queueList[queueListIi] || [];
10211.    639            let openRangeEnd;
10212.    583            if (queueTrees === undefined) {
10213.    583                queueListIi += 1;
10214.    583
10215.    583// Increment nextOffset, nextTrees.
10216.    583
10217.    583            } else if (nextOffset === undefined || nextOffset > queueOffset) {
10218.     56                nextOffset = queueOffset;
10219.     56                nextTrees = queueTrees;
10220.     56                queueTrees = undefined;
10221.     56
10222.     56// Concat queueTrees to nextTrees.
10223.     56
10224.     56            } else {
10225.     56                if (nextOffset === queueOffset) {
10226.     56                    queueTrees.forEach(function (tree) {
10227.     56                        nextTrees.push(tree);
10228.     56                    });
10229.     56                    queueTrees = undefined;
10230.     56                }
10231.     56                queueListIi += 1;
10232.     56            }
10233.    639
10234.    639// Reached end of queueList.
10235.    639
10236.    265            if (nextOffset === undefined) {
10237.    265                if (openRange !== undefined) {
10238.    265
10239.    265// Append nested-children from parentToChildDict (within openRange) to
10240.    265// resultChildren.
10241.    265
10242.    265                    resultAppendNextChild();
10243.    265                }
10244.    265                return true;
10245.    374            }
10246.    374            if (openRange !== undefined && openRange.end <= nextOffset) {
10247.    129
10248.    129// Append nested-children from parentToChildDict (within openRange) to
10249.    129// resultChildren.
10250.    129
10251.    129                resultAppendNextChild();
10252.    129                openRange = undefined;
10253.    374            }
10254.    374            if (openRange === undefined) {
10255.    292                openRangeEnd = nextOffset + 1;
10256.    502                nextTrees.forEach(function ({
10257.    502                    parentIi,
10258.    502                    tree
10259.    502                }) {
10260.    502                    openRangeEnd = Math.max(openRangeEnd, tree.end);
10261.    502
10262.    502// Append children from nextTrees to parentToChildDict.
10263.    502
10264.    502                    dictKeyValueAppend(parentToChildDict, parentIi, tree);
10265.    502                });
10266.    292                queueOffset = openRangeEnd;
10267.    292                openRange = {
10268.    292                    end: openRangeEnd,
10269.    292                    start: nextOffset
10270.    292                };
10271.    292            } else {
10272.    114                nextTrees.forEach(function ({
10273.    114                    parentIi,
10274.    114                    tree
10275.    114                }) {
10276.    114                    let right;
10277.     82                    if (tree.end > openRange.end) {
10278.     82                        right = treeSplit(tree, openRange.end);
10279.     82                        if (queueTrees === undefined) {
10280.     82                            queueTrees = [];
10281.     82                        }
10282.     82
10283.     82// new RangeTreeWithParent().
10284.     82
10285.     82                        queueTrees.push({
10286.     82                            parentIi,
10287.     82                            tree: right
10288.     82                        });
10289.     82                    }
10290.    114
10291.    114// Append children from nextTrees to parentToChildDict.
10292.    114
10293.    114                    dictKeyValueAppend(parentToChildDict, parentIi, tree);
10294.    114                });
10295.     82            }
10296.    639        }
10297.    292        function resultAppendNextChild() {
10298.    292
10299.    292// This function will append next child to <resultChildren>.
10300.    292
10301.    292            let treesMatching = [];
10302.    589            parentToChildDict.forEach(function (nested) {
10303.    589                if (
10304.    589                    nested.length === 1
10305.    563                    && nested[0].start === openRange.start
10306.    480                    && nested[0].end === openRange.end
10307.    468                ) {
10308.    468                    treesMatching.push(nested[0]);
10309.    468                } else {
10310.    121
10311.    121// new rangeTreeCreate().
10312.    121
10313.    121                    treesMatching.push({
10314.    121                        children: nested,
10315.    121                        delta: 0,
10316.    121                        end: openRange.end,
10317.    121                        start: openRange.start
10318.    121                    });
10319.    121                }
10320.    589            });
10321.    292            parentToChildDict.clear();
10322.    292
10323.    292// Recurse mergeTreeList().
10324.    292
10325.    292            resultChildren.push(mergeTreeList(treesMatching));
10326.    292        }
10327.     75        function treeSplit(tree, offset) {
10328.     75
10329.     75// This function will split <tree> along <offset> and return the right-side.
10330.     75// @precondition `tree.start < offset && offset < tree.end`
10331.     75// @return RangeTree Right part
10332.     75
10333.     75            let child;
10334.     75            let ii = 0;
10335.     75            let leftChildLen = tree.children.length;
10336.     75            let mid;
10337.     75            let resultTree;
10338.     75            let rightChildren;
10339.     75
10340.     75// TODO(perf): Binary search (check overhead) //jslint-ignore-line
10341.     75
10342.     19            while (ii < tree.children.length) {
10343.     19                child = tree.children[ii];
10344.     19                if (child.start < offset && offset < child.end) {
10345.     19
10346.     19// Recurse treeSplit().
10347.     19
10348.     19                    mid = treeSplit(child, offset);
10349.     19                    leftChildLen = ii + 1;
10350.     19                    break;
10351.     19                }
10352.     19                if (child.start >= offset) {
10353.     19                    leftChildLen = ii;
10354.     19                    break;
10355.     19                }
10356.     19                ii += 1;
10357.     19            }
10358.     75            rightChildren = tree.children.splice(
10359.     75                leftChildLen,
10360.     75                tree.children.length - leftChildLen
10361.     75            );
10362.      4            if (mid !== undefined) {
10363.      4                rightChildren.unshift(mid);
10364.      4            }
10365.     75
10366.     75// new rangeTreeCreate().
10367.     75
10368.     75            resultTree = {
10369.     75                children: rightChildren,
10370.     75                delta: tree.delta,
10371.     75                end: tree.end,
10372.     75                start: offset
10373.     75            };
10374.     75            tree.end = offset;
10375.     75            return resultTree;
10376.     75        }
10377.    265
10378.    265// Init startToTreeDict.
10379.    265
10380.    669        parentTrees.forEach(function (parentTree, parentIi) {
10381.    545            parentTree.children.forEach(function (child) {
10382.    545
10383.    545// Append child with child.start to startToTreeDict.
10384.    545
10385.    545                dictKeyValueAppend(startToTreeDict, child.start, {
10386.    545                    parentIi,
10387.    545                    tree: child
10388.    545                });
10389.    545            });
10390.    669        });
10391.    265
10392.    265// init queueList.
10393.    265
10394.    335        queueList = Array.from(startToTreeDict).map(function ([
10395.    335            startOffset, trees
10396.    335        ]) {
10397.    335
10398.    335// new StartEvent().
10399.    335
10400.    335            return [
10401.    335                startOffset, trees
10402.    335            ];
10403.    217        }).sort(function (aa, bb) {
10404.    217            return aa[0] - bb[0];
10405.    217        });
10406.    639        while (true) {
10407.    639            if (nextXxx()) {
10408.    639                break;
10409.    639            }
10410.    639        }
10411.    265        return resultChildren;
10412.    265    }
10413.     97
10414.    689    function sortFunc(funcCov) {
10415.    689
10416.    689// This function will normalize-and-sort <funcCov>.ranges.
10417.    689// Sorts the ranges (pre-order sort).
10418.    689// TODO: Tree-based normalization of the ranges. //jslint-ignore-line
10419.    689// @param funcCov Function coverage to normalize.
10420.    689
10421.    689        funcCov.ranges = treeToRanges(treeFromSortedRanges(
10422.    689            funcCov.ranges.sort(compareRangeList)
10423.    689        ));
10424.    689        return funcCov;
10425.    689    }
10426.     97
10427.    129    function sortScript(scriptCov) {
10428.    129
10429.    129// This function will normalize-and-sort <scriptCov>.functions.
10430.    129
10431.    129// Normalize-and-sort functions[xxx].ranges.
10432.    129
10433.    688        scriptCov.functions.forEach(function (funcCov) {
10434.    688            sortFunc(funcCov);
10435.    688        });
10436.    129
10437.    129// Sort functions by root range (pre-order sort).
10438.    129
10439.    559        scriptCov.functions.sort(function (aa, bb) {
10440.    559            return compareRangeList(aa.ranges[0], bb.ranges[0]);
10441.    559        });
10442.    129        return scriptCov;
10443.    129    }
10444.     97
10445.    888    function treeFromSortedRanges(ranges) {
10446.    888
10447.    888// @precondition `ranges` are well-formed and pre-order sorted
10448.    888
10449.    888        let root;
10450.    888        let stack = [];   // Stack of parent trees and parent counts.
10451.   1856        ranges.forEach(function (range) {
10452.   1856
10453.   1856// new rangeTreeCreate().
10454.   1856
10455.   1856            let node = {
10456.   1856                children: [],
10457.   1856                delta: range.count,
10458.   1856                end: range.endOffset,
10459.   1856                start: range.startOffset
10460.   1856            };
10461.   1856            let parent;
10462.   1856            let parentCount;
10463.    888            if (root === undefined) {
10464.    888                root = node;
10465.    888                stack.push([
10466.    888                    node, range.count
10467.    888                ]);
10468.    888                return;
10469.    968            }
10470.   1565            while (true) {
10471.   1565                [
10472.   1565                    parent, parentCount
10473.   1565                ] = stack[stack.length - 1];
10474.   1565
10475.   1565// assert: `top !== undefined` (the ranges are sorted)
10476.   1565
10477.   1565                if (range.startOffset < parent.end) {
10478.   1565                    break;
10479.   1565                }
10480.   1565                stack.pop();
10481.   1565            }
10482.    968            node.delta -= parentCount;
10483.    968            parent.children.push(node);
10484.    968            stack.push([
10485.    968                node, range.count
10486.    968            ]);
10487.    968        });
10488.    888        return root;
10489.    888    }
10490.     97
10491.    781    function treeToRanges(tree) {
10492.    781
10493.    781// Get the range coverages corresponding to the tree.
10494.    781// The ranges are pre-order sorted.
10495.    781
10496.    781        let count;
10497.    781        let cur;
10498.    781        let ii;
10499.    781        let parentCount;
10500.    781        let ranges = [];
10501.    781        let stack = [           // Stack of parent trees and counts.
10502.    781            [
10503.    781                tree, 0
10504.    781            ]
10505.    781        ];
10506.   1630        function normalizeRange(tree) {
10507.   1630
10508.   1630// @internal
10509.   1630
10510.   1630            let children = [];
10511.   1630            let curEnd;
10512.   1630            let head;
10513.   1630            let tail = [];
10514.    849            function endChain() {
10515.     18                if (tail.length !== 0) {
10516.     18                    head.end = tail[tail.length - 1].end;
10517.     18                    tail.forEach(function (tailTree) {
10518.     18                        tailTree.children.forEach(function (subChild) {
10519.     18                            subChild.delta += tailTree.delta - head.delta;
10520.     18                            head.children.push(subChild);
10521.     18                        });
10522.     18                    });
10523.     18                    tail.length = 0;
10524.     18                }
10525.    849
10526.    849// Recurse normalizeRange().
10527.    849
10528.    849                normalizeRange(head);
10529.    849                children.push(head);
10530.    849            }
10531.    867            tree.children.forEach(function (child) {
10532.    432                if (head === undefined) {
10533.    432                    head = child;
10534.    435                } else if (
10535.    435                    child.delta === head.delta && child.start === curEnd
10536.    435                ) {
10537.    435                    tail.push(child);
10538.    435                } else {
10539.    435                    endChain();
10540.    435                    head = child;
10541.    435                }
10542.    867                curEnd = child.end;
10543.    867            });
10544.    432            if (head !== undefined) {
10545.    432                endChain();
10546.    432            }
10547.    238            if (children.length === 1) {
10548.    238                if (
10549.    238                    children[0].start === tree.start
10550.    238                    && children[0].end === tree.end
10551.    238                ) {
10552.    238                    tree.delta += children[0].delta;
10553.    238                    tree.children = children[0].children;
10554.    238
10555.    238// `.lazyCount` is zero for both (both are after normalization)
10556.    238
10557.    238                    return;
10558.    238                }
10559.   1624            }
10560.   1624            tree.children = children;
10561.   1624        }
10562.    781        normalizeRange(tree);
10563.   1624        while (stack.length > 0) {
10564.   1624            [
10565.   1624                cur, parentCount
10566.   1624            ] = stack.pop();
10567.   1624            count = parentCount + cur.delta;
10568.   1624            ranges.push({
10569.   1624                count,
10570.   1624                endOffset: cur.end,
10571.   1624                startOffset: cur.start
10572.   1624            });
10573.   1624            ii = cur.children.length - 1;
10574.   1624            while (ii >= 0) {
10575.   1624                stack.push([
10576.   1624                    cur.children[ii], count
10577.   1624                ]);
10578.   1624                ii -= 1;
10579.   1624            }
10580.   1624        }
10581.    781        return ranges;
10582.    781    }
10583.     97
10584.      1    if (processCovs.length === 0) {
10585.      1        return {
10586.      1            result: []
10587.      1        };
10588.     96    }
10589.     96
10590.     96// Init urlToScriptDict.
10591.     96
10592.    234    processCovs.forEach(function ({
10593.    234        result
10594.    234    }) {
10595.    269        result.forEach(function (scriptCov) {
10596.    269            dictKeyValueAppend(urlToScriptDict, scriptCov.url, scriptCov);
10597.    269        });
10598.    234    });
10599.    129    urlToScriptDict.forEach(function (scriptCovs) {
10600.    129
10601.    129// assert: `scriptCovs.length > 0`
10602.    129
10603.    129// function mergeScriptList(scriptCovs) {
10604.    129// Merges a list of matching script coverages.
10605.    129// Scripts are matching if they have the same `url`.
10606.    129// The result is normalized.
10607.    129// The input values may be mutated, it is not safe to use them after passing
10608.    129// them to this function.
10609.    129// The computation is synchronous.
10610.    129// @param scriptCovs Process coverages to merge.
10611.    129// @return Merged script coverage, or `undefined` if the input list was empty.
10612.    129
10613.    129        let functions = [];
10614.    129
10615.    129// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
10616.    129
10617.    129        let rangeToFuncDict = new Map();
10618.    129
10619.    129// Probably deadcode.
10620.    129// if (scriptCovs.length === 0) {
10621.    129//     return undefined;
10622.    129// }
10623.    129
10624.     96        if (scriptCovs.length === 1) {
10625.     96            resultMerged.push(sortScript(scriptCovs[0]));
10626.     96            return;
10627.     96        }
10628.     96
10629.     96// Init rangeToFuncDict.
10630.     96// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
10631.     96
10632.    226        scriptCovs.forEach(function ({
10633.    226            functions
10634.    226        }) {
10635.    277            functions.forEach(function (funcCov) {
10636.    277                dictKeyValueAppend(
10637.    277                    rangeToFuncDict,
10638.    277
10639.    277// This string can be used to match function with same root range.
10640.    277// The string is derived from the start and end offsets of the root range of
10641.    277// the function.
10642.    277// This assumes that `ranges` is non-empty (true for valid function coverages).
10643.    277
10644.    277                    (
10645.    277                        funcCov.ranges[0].startOffset
10646.    277                        + ";" + funcCov.ranges[0].endOffset
10647.    277                    ),
10648.    277                    funcCov
10649.    277                );
10650.    277            });
10651.    226        });
10652.    112        rangeToFuncDict.forEach(function (funcCovs) {
10653.    112
10654.    112// assert: `funcCovs.length > 0`
10655.    112
10656.    112// function mergeFuncList(funcCovs) {
10657.    112// Merges a list of matching function coverages.
10658.    112// Functions are matching if their root ranges have the same span.
10659.    112// The result is normalized.
10660.    112// The input values may be mutated, it is not safe to use them after passing
10661.    112// them to this function.
10662.    112// The computation is synchronous.
10663.    112// @param funcCovs Function coverages to merge.
10664.    112// @return Merged function coverage, or `undefined` if the input list was empty.
10665.    112
10666.    112            let count = 0;
10667.    112            let isBlockCoverage;
10668.    112            let merged;
10669.    112            let ranges;
10670.    112            let trees = [];
10671.    112
10672.    112// Probably deadcode.
10673.    112// if (funcCovs.length === 0) {
10674.    112//     return undefined;
10675.    112// }
10676.    112
10677.     96            if (funcCovs.length === 1) {
10678.     96                functions.push(sortFunc(funcCovs[0]));
10679.     96                return;
10680.    111            }
10681.    111
10682.    111// assert: `funcCovs[0].ranges.length > 0`
10683.    111
10684.    276            funcCovs.forEach(function (funcCov) {
10685.    276
10686.    276// assert: `funcCov.ranges.length > 0`
10687.    276// assert: `funcCov.ranges` is sorted
10688.    276
10689.    276                count += (
10690.    276                    funcCov.count !== undefined
10691.    111                    ? funcCov.count
10692.    274                    : funcCov.ranges[0].count
10693.    276                );
10694.    199                if (funcCov.isBlockCoverage) {
10695.    199                    trees.push(treeFromSortedRanges(funcCov.ranges));
10696.    199                }
10697.    276            });
10698.    111            if (trees.length > 0) {
10699.     96                isBlockCoverage = true;
10700.     96                ranges = treeToRanges(mergeTreeList(trees));
10701.     96            } else {
10702.     96                isBlockCoverage = false;
10703.     96                ranges = [
10704.     96                    {
10705.     96                        count,
10706.     96                        endOffset: funcCovs[0].ranges[0].endOffset,
10707.     96                        startOffset: funcCovs[0].ranges[0].startOffset
10708.     96                    }
10709.     96                ];
10710.    111            }
10711.    111            merged = {
10712.    111                functionName: funcCovs[0].functionName,
10713.    111                isBlockCoverage,
10714.    111                ranges
10715.    111            };
10716.    111            if (count !== ranges[0].count) {
10717.     96                merged.count = count;
10718.    111            }
10719.    111
10720.    111// assert: `merged` is normalized
10721.    111
10722.    111            functions.push(merged);
10723.    111        });
10724.     96        resultMerged.push(sortScript({
10725.     96            functions,
10726.     96            scriptId: scriptCovs[0].scriptId,
10727.     96            url: scriptCovs[0].url
10728.     96        }));
10729.     96    });
10730.     96
10731.     96// Sorts the scripts alphabetically by `url`.
10732.     96// Reassigns script ids: the script at index `0` receives `"0"`, the script at
10733.     96// index `1` receives `"1"` etc.
10734.     96
10735.     96    Object.entries(resultMerged.sort(function (aa, bb) {
10736.     96        return (
10737.     96            aa.url > bb.url
10738.     96            ? 1
10739.     96            : -1
10740.     96        );
10741.    129    })).forEach(function ([
10742.    129        scriptId, scriptCov
10743.    129    ]) {
10744.    129        scriptCov.scriptId = scriptId.toString(10);
10745.    129    });
10746.     96    return {
10747.     96        result: resultMerged
10748.     96    };
10749.     96}
10750.      1
10751.      8async function v8CoverageReportCreate({
10752.      8    consoleError,
10753.      8    coverageDir,
10754.      8    processArgv = []
10755.      8}) {
10756.      8
10757.      8// This function will create html-coverage-reports directly from
10758.      8// v8-coverage-files in <coverageDir>.
10759.      8// 1. Spawn node.js program <processArgv> with NODE_V8_COVERAGE.
10760.      8// 2. Merge JSON v8-coverage-files in <coverageDir>.
10761.      8// 3. Create html-coverage-reports in <coverageDir>.
10762.      8
10763.      8    let cwd;
10764.      8    let excludeList = [];
10765.      8    let exitCode = 0;
10766.      8    let fileDict;
10767.      8    let includeList = [];
10768.      8    let modeIncludeNodeModules;
10769.      8    let processArgElem;
10770.      8    let promiseList = [];
10771.      8    let v8CoverageObj;
10772.      8
10773.     13    function htmlRender({
10774.     13        fileList,
10775.     13        lineList,
10776.     13        modeIndex,
10777.     13        pathname
10778.     13    }) {
10779.     13        let html;
10780.     13        let padLines;
10781.     13        let padPathname;
10782.     13        let txt;
10783.     13        let txtBorder;
10784.     13        html = "";
10785.     13        html += String(`
10786.     13<!DOCTYPE html>
10787.     13<html lang="en">
10788.     13<head>
10789.     13<title>V8 Coverage Report</title>
10790.     13<style>
10791.     13/* jslint utility2:true */
10792.     13/*csslint ignore:start*/
10793.     13.coverage,
10794.     13.coverage a,
10795.     13.coverage div,
10796.     13.coverage pre,
10797.     13.coverage span,
10798.     13.coverage table,
10799.     13.coverage tbody,
10800.     13.coverage td,
10801.     13.coverage th,
10802.     13.coverage thead,
10803.     13.coverage tr {
10804.     13    box-sizing: border-box;
10805.     13    font-family: monospace;
10806.     13}
10807.     13/*csslint ignore:end*/
10808.     13
10809.     13/* css - coverage_report - general */
10810.     13body {
10811.     13    margin: 0;
10812.     13}
10813.     13.coverage pre {
10814.     13    margin: 5px 0;
10815.     13}
10816.     13.coverage table {
10817.     13    border-collapse: collapse;
10818.     13}
10819.     13.coverage td,
10820.     13.coverage th {
10821.     13    border: 1px solid #777;
10822.     13    line-height: 20px;
10823.     13    margin: 0;
10824.     13    padding: 5px 10px;
10825.     13}
10826.     13.coverage td span {
10827.     13    display: inline-block;
10828.     13    width: 100%;
10829.     13}
10830.     13.coverage .content {
10831.     13    padding: 0 5px;
10832.     13}
10833.     13.coverage .content a {
10834.     13    text-decoration: none;
10835.     13}
10836.     13.coverage .count {
10837.     13    margin: 0 5px;
10838.     13    padding: 0 5px;
10839.     13}
10840.     13.coverage .footer,
10841.     13.coverage .header {
10842.     13    padding: 20px;
10843.     13}
10844.     13.coverage .footer {
10845.     13    text-align: center;
10846.     13}
10847.     13.coverage .percentbar {
10848.     13    height: 12px;
10849.     13    margin: 2px 0;
10850.     13    min-width: 200px;
10851.     13    position: relative;
10852.     13    width: 100%;
10853.     13}
10854.     13.coverage .percentbar div {
10855.     13    height: 100%;
10856.     13    position: absolute;
10857.     13}
10858.     13.coverage .title {
10859.     13    font-size: large;
10860.     13    font-weight: bold;
10861.     13    margin-bottom: 10px;
10862.     13}
10863.     13
10864.     13/* css - coverage_report - color */
10865.     13.coverage td,
10866.     13.coverage th {
10867.     13    background: #fff;
10868.     13}
10869.     13.coverage .count,
10870.     13.coverage .coverageHigh {
10871.     13    background: #9d9;
10872.     13}
10873.     13.coverage .count {
10874.     13    color: #666;
10875.     13}
10876.     13.coverage .coverageIgnore {
10877.     13    background: #ccc;
10878.     13}
10879.     13.coverage .coverageLow,
10880.     13.coverage .uncovered {
10881.     13    background: #ebb;
10882.     13}
10883.     13.coverage .coverageMedium {
10884.     13    background: #fd7;
10885.     13}
10886.     13.coverage .footer,
10887.     13.coverage .header,
10888.     13.coverage .lineno {
10889.     13    background: #ddd;
10890.     13}
10891.     13.coverage .percentbar {
10892.     13    background: #999;
10893.     13}
10894.     13.coverage .percentbar div {
10895.     13    background: #666;
10896.     13}
10897.     13
10898.     13/* css - coverage_report - important */
10899.     13.coverage pre:hover span,
10900.     13.coverage tr:hover td {
10901.     13    background: #7d7;
10902.     13}
10903.     13.coverage pre:hover span.uncovered,
10904.     13.coverage tr:hover td.coverageLow {
10905.     13    background: #f99;
10906.     13}
10907.     13</style>
10908.     13</head>
10909.     13<body class="coverage">
10910.     13<!-- header start -->
10911.     13<div class="header">
10912.     13<div class="title">V8 Coverage Report</div>
10913.     13<table>
10914.     13<thead>
10915.     13    <tr>
10916.     13    <th>Files covered</th>
10917.     13    <th>Lines</th>
10918.     13    <th>Remaining</th>
10919.     13    </tr>
10920.     13</thead>
10921.     13<tbody>
10922.     13        `).trim() + "\n";
10923.      7        if (modeIndex) {
10924.      7            padLines = String("(ignore) 100.00 %").length;
10925.      7            padPathname = 32;
10926.      7            fileList.unshift({
10927.      7                linesCovered: 0,
10928.      7                linesTotal: 0,
10929.      7                modeCoverageIgnoreFile: "",
10930.      7                pathname: "./"
10931.      7            });
10932.      7            fileList.slice(1).forEach(function ({
10933.      7                linesCovered,
10934.      7                linesTotal,
10935.      7                modeCoverageIgnoreFile,
10936.      7                pathname
10937.      7            }) {
10938.      7                if (!modeCoverageIgnoreFile) {
10939.      7                    fileList[0].linesCovered += linesCovered;
10940.      7                    fileList[0].linesTotal += linesTotal;
10941.      7                }
10942.      7                padPathname = Math.max(padPathname, pathname.length + 2);
10943.      7                padLines = Math.max(
10944.      7                    padLines,
10945.      7                    String(linesCovered + " / " + linesTotal).length
10946.      7                );
10947.      7            });
10948.      7        }
10949.     13        txtBorder = (
10950.     13            "+" + "-".repeat(padPathname + 2) + "+"
10951.     13            + "-".repeat(padLines + 2) + "+"
10952.     13            + "-".repeat(padLines + 2) + "+\n"
10953.     13        );
10954.     13        txt = "";
10955.     13        txt += "V8 Coverage Report\n";
10956.     13        txt += txtBorder;
10957.     13        txt += (
10958.     13            "| " + String("Files covered").padEnd(padPathname, " ") + " | "
10959.     13            + String("Lines").padStart(padLines, " ") + " | "
10960.     13            + String("Remaining").padStart(padLines, " ") + " |\n"
10961.     13        );
10962.     13        txt += txtBorder;
10963.     19        fileList.forEach(function ({
10964.     19            linesCovered,
10965.     19            linesTotal,
10966.     19            modeCoverageIgnoreFile,
10967.     19            pathname
10968.     19        }, ii) {
10969.     19            let coverageLevel;
10970.     19            let coveragePct;
10971.     19            let fill;
10972.     19            let str1;
10973.     19            let str2;
10974.     19            let xx1;
10975.     19            let xx2;
10976.      2            coveragePct = Math.floor(10000 * linesCovered / linesTotal || 0);
10977.     19            coverageLevel = (
10978.     19                modeCoverageIgnoreFile
10979.      2                ? "coverageIgnore"
10980.     17                : coveragePct >= 8000
10981.     17                ? "coverageHigh"
10982.     17                : coveragePct >= 5000
10983.     17                ? "coverageMedium"
10984.     17                : "coverageLow"
10985.     19            );
10986.     19            coveragePct = String(coveragePct).replace((
10987.     19                /..$/m
10988.     19            ), ".$&");
10989.     13            if (modeIndex && ii === 0) {
10990.      7                fill = (
10991.      7
10992.      7// Badge-color rgb-red.
10993.      7
10994.      7                    "#" + Math.round(
10995.      7                        (100 - Number(coveragePct)) * 2.21
10996.      7                    ).toString(16).padStart(2, "0")
10997.      7
10998.      7// Badge-color rgb-green.
10999.      7
11000.      7                    + Math.round(
11001.      7                        Number(coveragePct) * 2.21
11002.      7                    ).toString(16).padStart(2, "0")
11003.      7
11004.      7// Badge-color rgb-blue.
11005.      7
11006.      7                    + "00"
11007.      7                );
11008.      7                str1 = "coverage";
11009.      7                str2 = coveragePct + " %";
11010.      7                xx1 = 6 * str1.length + 20;
11011.      7                xx2 = 6 * str2.length + 20;
11012.      7
11013.      7// Fs - write coverage_badge.svg.
11014.      7
11015.      7                promiseList.push(fsWriteFileWithParents((
11016.      7                    coverageDir + "coverage_badge.svg"
11017.      7                ), String(`
11018.      7<svg height="20" width="${xx1 + xx2}" xmlns="http://www.w3.org/2000/svg">
11019.      7<rect fill="#555" height="20" width="${xx1 + xx2}"/>
11020.      7<rect fill="${fill}" height="20" width="${xx2}" x="${xx1}"/>
11021.      7<g
11022.      7    fill="#fff"
11023.      7    font-family="verdana, geneva, dejavu sans, sans-serif"
11024.      7    font-size="11"
11025.      7    font-weight="bold"
11026.      7    text-anchor="middle"
11027.      7>
11028.      7<text x="${0.5 * xx1}" y="14">${str1}</text>
11029.      7<text x="${xx1 + 0.5 * xx2}" y="14">${str2}</text>
11030.      7</g>
11031.      7</svg>
11032.      7                `).trim() + "\n"));
11033.      7                pathname = "";
11034.      7            }
11035.     19            txt += (
11036.     19                "| "
11037.     19                + String("./" + pathname).padEnd(padPathname, " ") + " | "
11038.     19                + String(
11039.     19                    modeCoverageIgnoreFile + " " + coveragePct + " %"
11040.     19                ).padStart(padLines, " ") + " | "
11041.     19                + " ".repeat(padLines) + " |\n"
11042.     19            );
11043.     19            txt += (
11044.     19                "| " + "*".repeat(
11045.     19                    Math.round(0.01 * coveragePct * padPathname)
11046.     19                ).padEnd(padPathname, "_") + " | "
11047.     19                + String(
11048.     19                    linesCovered + " / " + linesTotal
11049.     19                ).padStart(padLines, " ") + " | "
11050.     19                + String(
11051.     19                    (linesTotal - linesCovered) + " / " + linesTotal
11052.     19                ).padStart(padLines, " ") + " |\n"
11053.     19            );
11054.     19            txt += txtBorder;
11055.     19            pathname = htmlEscape(pathname);
11056.     19
11057.     19// CL-37251d17 - Bugfix - Fix incorrect http-link to index.html.
11058.     19
11059.     19            html += String(`
11060.     19    <tr>
11061.     19    <td class="${coverageLevel}">
11062.     19            ${(
11063.     19                modeIndex
11064.     13                ? (
11065.     13                    "<a href=\"" + (pathname || "index") + ".html\">. / "
11066.     13                    + pathname + "</a><br>"
11067.     13                )
11068.      6                : (
11069.      6                    "<a href=\""
11070.      6                    + "../".repeat(pathname.split("/").length - 1)
11071.      6                    + "index.html\">. / </a>"
11072.      6                    + pathname + "<br>"
11073.      6                )
11074.     19            )}
11075.     19        <div class="percentbar">
11076.     19            <div style="width: ${coveragePct}%;"></div>
11077.     19        </div>
11078.     19    </td>
11079.     19    <td style="text-align: right;">
11080.     19        ${modeCoverageIgnoreFile} ${coveragePct} %<br>
11081.     19        ${linesCovered} / ${linesTotal}
11082.     19    </td>
11083.     19    <td style="text-align: right;">
11084.     19        <br>
11085.     19        ${linesTotal - linesCovered} / ${linesTotal}
11086.     19    </td>
11087.     19    </tr>
11088.     19        `).trim() + "\n";
11089.     19        });
11090.     13        html += String(`
11091.     13</tbody>
11092.     13</table>
11093.     13</div>
11094.     13<!-- header end -->
11095.     13        `).trim() + "\n";
11096.      6        if (!modeIndex) {
11097.      6            html += String(`
11098.      6<!-- content start -->
11099.      6<div class="content">
11100.      6            `).trim() + "\n";
11101.  11829            lineList.forEach(function ({
11102.  11829                count,
11103.  11829                holeList,
11104.  11829                line,
11105.  11829                startOffset
11106.  11829            }, ii) {
11107.  11829                let chunk;
11108.  11829                let inHole;
11109.  11829                let lineHtml;
11110.  11829                let lineId;
11111.  11829                lineHtml = "";
11112.  11829                lineId = "line_" + (ii + 1);
11113.  11829                switch (count) {
11114.     32                case -1:
11115.  11195                case 0:
11116.  11195                    if (holeList.length === 0) {
11117.  11195                        lineHtml += "</span>";
11118.  11195                        lineHtml += "<span class=\"uncovered\">";
11119.  11195                        lineHtml += htmlEscape(line);
11120.  11195                        break;
11121.  11195                    }
11122.  11195                    line = line.split("").map(function (char) {
11123.  11195                        return {
11124.  11195                            char,
11125.  11195                            isHole: undefined
11126.  11195                        };
11127.  11195                    });
11128.  11195                    holeList.forEach(function ([
11129.  11195                        aa, bb
11130.  11195                    ]) {
11131.  11195                        aa = Math.max(aa - startOffset, 0);
11132.  11195                        bb = Math.min(bb - startOffset, line.length);
11133.  11195                        while (aa < bb) {
11134.  11195                            line[aa].isHole = true;
11135.  11195                            aa += 1;
11136.  11195                        }
11137.  11195                    });
11138.  11195                    chunk = "";
11139.  11195                    line.forEach(function ({
11140.  11195                        char,
11141.  11195                        isHole
11142.  11195                    }) {
11143.  11195                        if (inHole !== isHole) {
11144.  11195                            lineHtml += htmlEscape(chunk);
11145.  11195                            lineHtml += "</span><span";
11146.  11195
11147.  11195// Coverage-hack - Ugly-hack around possible deadcode where isHole is always
11148.  11195// true.
11149.  11195
11150.  11195                            if (isHole) {
11151.  11195                                lineHtml += " class=\"uncovered\"";
11152.  11195                            }
11153.  11195                            lineHtml += ">";
11154.  11195                            chunk = "";
11155.  11195                            inHole = isHole;
11156.  11195                        }
11157.  11195                        chunk += char;
11158.  11195                    });
11159.  11195                    lineHtml += htmlEscape(chunk);
11160.  11195                    break;
11161.    634                default:
11162.    634                    lineHtml += htmlEscape(line);
11163.  11829                }
11164.  11829                html += String(`
11165.  11829<pre>
11166.  11829<span class="lineno">
11167.  11829<a href="#${lineId}" id="${lineId}">${String(ii + 1).padStart(5, " ")}.</a>
11168.  11829</span>
11169.  11829<span class="count
11170.  11829                ${(
11171.  11829                    count <= 0
11172.  11195                    ? "uncovered"
11173.    634                    : ""
11174.  11829                )}"
11175.  11829>
11176.  11163${String(count || "-0").padStart(7, " ")}
11177.  11829</span>
11178.  11829<span>${lineHtml}</span>
11179.  11829</pre>
11180.  11829                `).replace((
11181.  11829                    /\n/g
11182.  11829                ), "").trim() + "\n";
11183.  11829            });
11184.      6            html += String(`
11185.      6</div>
11186.      6<!-- content end -->
11187.      6            `).trim() + "\n";
11188.      6        }
11189.     13        html += String(`
11190.     13<div class="footer">
11191.     13    [
11192.     13    This document was created with
11193.     13    <a href="https://github.com/jslint-org/jslint">JSLint</a>
11194.     13    ]
11195.     13</div>
11196.     13</body>
11197.     13</html>
11198.     13        `).trim() + "\n";
11199.     13
11200.     13// Fs - write <file>.html.
11201.     13
11202.     13        promiseList.push(fsWriteFileWithParents(pathname + ".html", html));
11203.      6        if (!modeIndex) {
11204.      6            return;
11205.      7        }
11206.      7
11207.      7// Fs - write coverage_report.txt.
11208.      7
11209.      7        consoleError("\n" + txt);
11210.      7        promiseList.push(fsWriteFileWithParents((
11211.      7            coverageDir + "coverage_report.txt"
11212.      7        ), txt));
11213.      7    }
11214.      8
11215.      8/*
11216.      8function sentinel() {}
11217.      8*/
11218.      8
11219.      8    await moduleFsInit();
11220.      1    consoleError = consoleError || console.error;
11221.      8    cwd = process.cwd().replace((
11222.      8        /\\/g
11223.      8    ), "/") + "/";
11224.      8
11225.      8// Init coverageDir.
11226.      8// Assert coverageDir is subdirectory of cwd.
11227.      8
11228.      8    assertOrThrow(coverageDir, "invalid coverageDir " + coverageDir);
11229.      8
11230.      8// CL-61b11012 - coverage - Relax requirement for coverageDir to be in cwd.
11231.      8//     assertOrThrow(
11232.      8//         pathnameRelativeCwd(coverageDir),
11233.      8//         "coverageDir " + coverageDir + " is not subdirectory of cwd " + cwd
11234.      8//     );
11235.      8
11236.      8    coverageDir = modulePath.resolve(coverageDir).replace((
11237.      8        /\\/g
11238.      8    ), "/") + "/";
11239.      8
11240.      8    processArgv = processArgv.slice();
11241.      9    while (processArgv[0] && processArgv[0][0] === "-") {
11242.      3        processArgElem = processArgv.shift().split("=");
11243.      3        processArgElem[1] = processArgElem.slice(1).join("=");
11244.      3        switch (processArgElem[0]) {
11245.      3
11246.      3// PR-371 - Add cli-option `--exclude=...`.
11247.      3
11248.      3        case "--exclude":
11249.      3            excludeList.push(processArgElem[1]);
11250.      3            break;
11251.      3
11252.      3// PR-371 - Add cli-option `--include=...`
11253.      3
11254.      3        case "--include":
11255.      3            includeList.push(processArgElem[1]);
11256.      3            break;
11257.      3
11258.      3// PR-400
11259.      3// Disable default-coverage of directory `node_modules`,
11260.      3// but allow override with cli-option `--include-node-modules=1`.
11261.      3
11262.      3        case "--include-node-modules":
11263.      3            modeIncludeNodeModules = !(
11264.      3                /0|false|null|undefined/
11265.      3            ).test(processArgElem[1]);
11266.      3            break;
11267.      3        }
11268.      7    }
11269.      7
11270.      7// 1. Spawn node.js program <processArgv> with coverage
11271.      7
11272.      7    if (processArgv.length > 0) {
11273.      6
11274.      6// Remove old coverage-files.
11275.      6
11276.      6        await fsWriteFileWithParents(coverageDir + "/touch.txt", "");
11277.      6        await Promise.all(Array.from(
11278.      6            await moduleFs.promises.readdir(coverageDir)
11279.     11        ).map(async function (file) {
11280.     11            if ((
11281.     11                /^coverage-\d+?-\d+?-\d+?\.json$/
11282.      6            ).test(file)) {
11283.      6                consoleError("rm file " + coverageDir + file);
11284.      6                await moduleFs.promises.unlink(coverageDir + file);
11285.      6            }
11286.     11        }));
11287.      6        exitCode = await new Promise(function (resolve) {
11288.      6            moduleChildProcess.spawn(
11289.      6                (
11290.      6                    processArgv[0] === "npm"
11291.      6
11292.      6// If win32 environment, then replace program npm with npm.cmd.
11293.      6// Coverage-hack - Ugly-hack to get test-coverage under both win32 and linux.
11294.      6
11295.      6                    ? process.platform.replace("win32", "npm.cmd").replace(
11296.      6                        process.platform,
11297.      6                        "npm"
11298.      6                    )
11299.      6                    : processArgv[0]
11300.      6                ),
11301.      6                processArgv.slice(1),
11302.      6                {
11303.      6                    env: Object.assign({}, process.env, {
11304.      6                        NODE_V8_COVERAGE: coverageDir
11305.      6                    }),
11306.      6                    stdio: ["ignore", 1, 2]
11307.      6                }
11308.      6            ).on("exit", resolve);
11309.      6        });
11310.      6        consoleError(
11311.      6            `v8CoverageReportCreate - program exited with exitCode=${exitCode}`
11312.      6        );
11313.      7    }
11314.      7
11315.      7// 2. Merge JSON v8-coverage-files in <coverageDir>.
11316.      7
11317.      7    consoleError("v8CoverageReportCreate - merging coverage files...");
11318.      7    v8CoverageObj = await moduleFs.promises.readdir(coverageDir);
11319.     18    v8CoverageObj = v8CoverageObj.filter(function (file) {
11320.     18        return (
11321.     18            /^coverage-\d+?-\d+?-\d+?\.json$/
11322.     18        ).test(file);
11323.     18    });
11324.      7    v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
11325.      7        let data;
11326.      7        let pathnameDict = Object.create(null);
11327.      7        data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
11328.      7        data = JSON.parse(data);
11329.    770        data.result.forEach(function (scriptCov) {
11330.    770            let pathname = scriptCov.url;
11331.    770
11332.    770// Filter out internal coverages.
11333.    770
11334.    463            if (!pathname.startsWith("file:///")) {
11335.    463                return;
11336.    463            }
11337.    307
11338.    307// Normalize pathname.
11339.    307
11340.    307            pathname = moduleUrl.fileURLToPath(pathname);
11341.    307            pathname = modulePath.resolve(pathname).replace((
11342.    307                /\\/g
11343.    307            ), "/");
11344.    307
11345.    307// Filter files outside of cwd.
11346.    307
11347.    307            if (pathname.indexOf("[") >= 0 || !pathname.startsWith(cwd)) {
11348.    301                return;
11349.    301            }
11350.      7
11351.      7// Normalize pathname relative to cwd.
11352.      7
11353.      7            pathname = pathname.slice(cwd.length);
11354.      7            scriptCov.url = pathname;
11355.      7            pathnameDict[pathname] = scriptCov;
11356.      7        });
11357.      7
11358.      7// PR-400 - Filter directory `node_modules`.
11359.      7
11360.      7        if (!modeIncludeNodeModules) {
11361.      7            excludeList.push("node_modules/");
11362.      7        }
11363.      7
11364.      7// PR-400 - Filter files by glob-patterns in excludeList, includeList.
11365.      7
11366.      7        data.result = globExclude({
11367.      7            excludeList,
11368.      7            includeList,
11369.      7            pathnameList: Object.keys(pathnameDict)
11370.      7        }).pathnameList.map(function (pathname) {
11371.      7            return pathnameDict[pathname];
11372.      7        });
11373.      7        return data;
11374.      7    }));
11375.      7
11376.      7// Merge v8CoverageObj.
11377.      7
11378.      7    v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
11379.      7
11380.      7// Debug v8CoverageObj.
11381.      7
11382.      7    await fsWriteFileWithParents(
11383.      7        coverageDir + "v8_coverage_merged.json",
11384.      7        JSON.stringify(v8CoverageObj, undefined, 1)
11385.      7    );
11386.      7
11387.      7// 3. Create html-coverage-reports in <coverageDir>.
11388.      7
11389.      7    consoleError("v8CoverageReportCreate - creating html-coverage-report...");
11390.      7    fileDict = Object.create(null);
11391.      7    await Promise.all(v8CoverageObj.result.map(async function ({
11392.      7        functions,
11393.      7        url: pathname
11394.      7    }) {
11395.      7        let lineList;
11396.      7        let linesCovered;
11397.      7        let linesTotal;
11398.      7        let source;
11399.      7        source = await moduleFs.promises.readFile(pathname, "utf8");
11400.      7        lineList = [{}];
11401.      7        source.replace((
11402.      7            /^.*$/gm
11403.  11829        ), function (line, startOffset) {
11404.  11829            lineList[lineList.length - 1].endOffset = startOffset - 1;
11405.  11829            lineList.push({
11406.  11829                count: -1,
11407.  11829                endOffset: 0,
11408.  11829                holeList: [],
11409.  11829                line,
11410.  11829                startOffset
11411.  11829            });
11412.  11829            return "";
11413.  11829        });
11414.      7        lineList.shift();
11415.      7        lineList[lineList.length - 1].endOffset = source.length;
11416.     41        functions.reverse().forEach(function ({
11417.     41            ranges
11418.     41        }) {
11419.     65            ranges.reverse().forEach(function ({
11420.     65                count,
11421.     65                endOffset,
11422.     65                startOffset
11423.     65            }, ii, list) {
11424. 578847                lineList.forEach(function (elem) {
11425. 578847                    if (!(
11426. 578847                        (
11427. 578847                            elem.startOffset <= startOffset
11428. 205552                            && startOffset <= elem.endOffset
11429. 578782                        ) || (
11430. 578782                            elem.startOffset <= endOffset
11431. 578782                            && endOffset <= elem.endOffset
11432. 578782                        ) || (
11433. 578726                            startOffset <= elem.startOffset
11434. 578726                            && elem.endOffset <= endOffset
11435. 578726                        )
11436. 555345                    )) {
11437. 555345                        return;
11438. 555345                    }
11439.  23502
11440.  23502// Handle tree-root.
11441.  23502
11442.  23502                    if (ii + 1 === list.length) {
11443.  23233                        if (elem.count === -1) {
11444.  23233                            elem.count = count;
11445.  23233                        }
11446.  23233                        return;
11447.  23233                    }
11448.    269
11449.    269// Handle tree-children.
11450.    269
11451.    269                    if (elem.count !== 0) {
11452.    170                        elem.count = Math.max(count, elem.count);
11453.    269                    }
11454.    269                    if (count === 0) {
11455.    203                        elem.count = 0;
11456.    203                        elem.holeList.push([
11457.    203                            startOffset, endOffset
11458.    203                        ]);
11459.    203                    }
11460. 578847                });
11461.     65            });
11462.     41        });
11463.      7        linesTotal = lineList.length;
11464.  11829        linesCovered = lineList.filter(function ({
11465.  11829            count
11466.  11829        }) {
11467.  11829            return count > 0;
11468.  11829        }).length;
11469.      7        await moduleFs.promises.mkdir((
11470.      7            modulePath.dirname(coverageDir + pathname)
11471.      7        ), {
11472.      7            recursive: true
11473.      7        });
11474.      7        fileDict[pathname] = {
11475.      7            lineList,
11476.      7            linesCovered,
11477.      7            linesTotal,
11478.      7            modeCoverageIgnoreFile: (
11479.      7                (
11480.      7                    /^\/\*coverage-ignore-file\*\/$/m
11481.      7                ).test(source.slice(0, 65536))
11482.      7                ? "(ignore)"
11483.      7                : ""
11484.      7            ),
11485.      7            pathname
11486.      7        };
11487.      7        htmlRender({
11488.      7            fileList: [
11489.      7                fileDict[pathname]
11490.      7            ],
11491.      7            lineList,
11492.      7            pathname: coverageDir + pathname
11493.      7        });
11494.      7    }));
11495.      7    htmlRender({
11496.      7        fileList: Object.keys(fileDict).sort().map(function (pathname) {
11497.      7            return fileDict[pathname];
11498.      7        }),
11499.      7        modeIndex: true,
11500.      7        pathname: coverageDir + "index"
11501.      7    });
11502.      7    await Promise.all(promiseList);
11503.      7    assertOrThrow(
11504.      7        exitCode === 0,
11505.      7        "v8CoverageReportCreate - nonzero exitCode " + exitCode
11506.      7    );
11507.      7}
11508.      1
11509.      1/*
11510.      1function sentinel() {}
11511.      1*/
11512.      1
11513.      1// Export jslint as cjs/esm.
11514.      1
11515.      1jslint_export = Object.freeze(Object.assign(jslint, {
11516.      1    assertErrorThrownAsync,
11517.      1    assertJsonEqual,
11518.      1    assertOrThrow,
11519.      1    debugInline,
11520.      1    fsWriteFileWithParents,
11521.      1    globExclude,
11522.      1    htmlEscape,
11523.      1    jslint,
11524.      1    jslint_apidoc,
11525.      1    jslint_assert,
11526.      1    jslint_charset_ascii,
11527.      1    jslint_cli,
11528.      1    jslint_edition,
11529.      1    jslint_phase1_split,
11530.      1    jslint_phase2_lex,
11531.      1    jslint_phase3_parse,
11532.      1    jslint_phase4_walk,
11533.      1    jslint_phase5_whitage,
11534.      1    jslint_report,
11535.      1    jstestDescribe,
11536.      1    jstestIt,
11537.      1    jstestOnExit,
11538.      1    moduleFsInit,
11539.      1    noop,
11540.      1    objectDeepCopyWithKeysSorted,
11541.      1    v8CoverageListMerge,
11542.      1    v8CoverageReportCreate
11543.      1}));
11544.      1// module.exports = jslint_export;              // Export jslint as cjs.
11545.      1export default Object.freeze(jslint_export);    // Export jslint as esm.
11546.      1jslint_import_meta_url = import.meta.url;
11547.      1
11548.      1// Run jslint_cli.
11549.      1jslint_cli({});
11550.      1