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

0 / 13977
    1.     23// #!/usr/bin/env node
    2.     23// JSLint
    3.     23
    4.     23// The Unlicense
    5.     23//
    6.     23// This is free and unencumbered software released into the public domain.
    7.     23//
    8.     23// Anyone is free to copy, modify, publish, use, compile, sell, or
    9.     23// distribute this software, either in source code form or as a compiled
   10.     23// binary, for any purpose, commercial or non-commercial, and by any
   11.     23// means.
   12.     23//
   13.     23// In jurisdictions that recognize copyright laws, the author or authors
   14.     23// of this software dedicate any and all copyright interest in the
   15.     23// software to the public domain. We make this dedication for the benefit
   16.     23// of the public at large and to the detriment of our heirs and
   17.     23// successors. We intend this dedication to be an overt act of
   18.     23// relinquishment in perpetuity of all present and future rights to this
   19.     23// software under copyright law.
   20.     23//
   21.     23// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
   22.     23// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
   23.     23// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
   24.     23// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
   25.     23// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
   26.     23// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
   27.     23// OTHER DEALINGS IN THE SOFTWARE.
   28.     23
   29.     23
   30.     23// jslint(source, option_dict, global_list) is a function that takes 3
   31.     23// arguments. The second two arguments are optional.
   32.     23
   33.     23//      source          A text to analyze.
   34.     23//      option_dict     An object whose keys correspond to option names.
   35.     23//      global_list     An array of strings containing global variables that
   36.     23//                      the file is allowed readonly access.
   37.     23
   38.     23// jslint returns an object containing its results. The object contains a lot
   39.     23// of valuable information. It can be used to generate reports. The object
   40.     23// contains:
   41.     23
   42.     23//      directives: an array of directive comment tokens.
   43.     23//      edition: the version of JSLint that did the analysis.
   44.     23//      exports: the names exported from the module.
   45.     23//      froms: an array of strings representing each of the imports.
   46.     23//      functions: an array of objects that represent all functions
   47.     23//              declared in the file.
   48.     23//      global: an object representing the global object. Its .context property
   49.     23//              is an object containing a property for each global variable.
   50.     23//      id: "(JSLint)"
   51.     23//      json: true if the file is a JSON text.
   52.     23//      lines: an array of strings, the source.
   53.     23//      module: true if an import or export statement was used.
   54.     23//      ok: true if no warnings were generated. This is what you want.
   55.     23//      option: the option argument.
   56.     23//      property: a property object.
   57.     23//      stop: true if JSLint was unable to finish. You don't want this.
   58.     23//      tokens: an array of objects representing the tokens in the file.
   59.     23//      tree: the token objects arranged in a tree.
   60.     23//      warnings: an array of warning objects. A warning object can contain:
   61.     23//          name: "JSLintError"
   62.     23//          column: A column number in the file.
   63.     23//          line: A line number in the file.
   64.     23//          code: A warning code string.
   65.     23//          message: The warning message string.
   66.     23//          a: Exhibit A.
   67.     23//          b: Exhibit B.
   68.     23//          c: Exhibit C.
   69.     23//          d: Exhibit D.
   70.     23
   71.     23// jslint works in several phases. In any of these phases, errors might be
   72.     23// found. Sometimes JSLint is able to recover from an error and continue
   73.     23// parsing. In some cases, it cannot and will stop early. If that should happen,
   74.     23// repair your code and try again.
   75.     23
   76.     23// Phases:
   77.     23
   78.     23// PHASE 1. Split <source> by newlines into <line_list>.
   79.     23// PHASE 2. Lex <line_list> into <token_list>.
   80.     23// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
   81.     23// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
   82.     23//          recursive traversal. Each node may be processed on the way down
   83.     23//          (preaction) and on the way up (postaction).
   84.     23// PHASE 5. Check whitespace between tokens in <token_list>.
   85.     23
   86.     23// jslint can also examine JSON text. It decides that a file is JSON text if
   87.     23// the first token is "[" or "{". Processing of JSON text is much simpler than
   88.     23// the processing of JavaScript programs. Only the first three phases are
   89.     23// required.
   90.     23
   91.     23// WARNING: JSLint will hurt your feelings.
   92.     23
   93.     23/*jslint beta, node, trace*/
   94.     23/*property
   95.     23    JSLINT_BETA,
   96.     23    NODE_V8_COVERAGE,
   97.     23    alive,
   98.     23    all,
   99.     23    argv,
  100.     23    arity,
  101.     23    artifact,
  102.     23    assertErrorThrownAsync,
  103.     23    assertJsonEqual,
  104.     23    assertOrThrow,
  105.     23    assign,
  106.     23    assigned,
  107.     23    assignment,
  108.     23    async,
  109.     23    at,
  110.     23    autofix,
  111.     23    autofixed,
  112.     23    beta,
  113.     23    bitwise,
  114.     23    block,
  115.     23    block_list,
  116.     23    block_stack,
  117.     23    browser,
  118.     23    catch,
  119.     23    char,
  120.     23    children,
  121.     23    clear,
  122.     23    closer,
  123.     23    closure,
  124.     23    code,
  125.     23    column,
  126.     23    concat,
  127.     23    consoleError,
  128.     23    console_error,
  129.     23    console_log,
  130.     23    constant,
  131.     23    context,
  132.     23    context_report,
  133.     23    convert,
  134.     23    count,
  135.     23    coverageDir,
  136.     23    create,
  137.     23    cwd,
  138.     23    debugInline,
  139.     23    default,
  140.     23    delta,
  141.     23    describe,
  142.     23    description,
  143.     23    devel,
  144.     23    directive,
  145.     23    directive_ignore_line,
  146.     23    directive_list,
  147.     23    directives,
  148.     23    dirname,
  149.     23    disrupt,
  150.     23    dot,
  151.     23    dot_depth,
  152.     23    edition,
  153.     23    elem_list,
  154.     23    ellipsis,
  155.     23    else,
  156.     23    end,
  157.     23    endOffset,
  158.     23    endsWith,
  159.     23    entries,
  160.     23    env,
  161.     23    err,
  162.     23    error,
  163.     23    eval,
  164.     23    every,
  165.     23    example_list,
  166.     23    excludeList,
  167.     23    exec,
  168.     23    execArgv,
  169.     23    exit,
  170.     23    exitCode,
  171.     23    export_dict,
  172.     23    exports,
  173.     23    expression,
  174.     23    extra,
  175.     23    fart,
  176.     23    file,
  177.     23    fileList,
  178.     23    fileURLToPath,
  179.     23    filter,
  180.     23    finally,
  181.     23    flag,
  182.     23    floor,
  183.     23    forEach,
  184.     23    for_init,
  185.     23    for_loop,
  186.     23    for_of,
  187.     23    for_semicolon,
  188.     23    formatted_message,
  189.     23    freeze,
  190.     23    from,
  191.     23    froms,
  192.     23    fsWriteFileWithParents,
  193.     23    fud_stmt,
  194.     23    functionName,
  195.     23    function_body,
  196.     23    function_list,
  197.     23    function_stack,
  198.     23    functions,
  199.     23    get,
  200.     23    getset,
  201.     23    github_repo,
  202.     23    globExclude,
  203.     23    global,
  204.     23    global_dict,
  205.     23    global_list,
  206.     23    holeList,
  207.     23    htmlEscape,
  208.     23    id,
  209.     23    identifier,
  210.     23    ignoreLine,
  211.     23    import,
  212.     23    import_list,
  213.     23    import_meta_url,
  214.     23    includeList,
  215.     23    includes,
  216.     23    indent2,
  217.     23    index,
  218.     23    indexOf,
  219.     23    isArray,
  220.     23    isBlockCoverage,
  221.     23    isHole,
  222.     23    isNaN,
  223.     23    is_equal,
  224.     23    is_weird,
  225.     23    itList,
  226.     23    join,
  227.     23    jslint,
  228.     23    jslint_apidoc,
  229.     23    jslint_charset_ascii,
  230.     23    jslint_cli,
  231.     23    jslint_edition,
  232.     23    jslint_phase1_split,
  233.     23    jslint_phase2_lex,
  234.     23    jslint_phase3_parse,
  235.     23    jslint_phase4_walk,
  236.     23    jslint_phase5_whitage,
  237.     23    jslint_phase6_autofix,
  238.     23    jslint_report,
  239.     23    json,
  240.     23    jstestDescribe,
  241.     23    jstestIt,
  242.     23    keys,
  243.     23    label_break,
  244.     23    label_name,
  245.     23    lbp,
  246.     23    led_infix,
  247.     23    length,
  248.     23    level,
  249.     23    line,
  250.     23    lineList,
  251.     23    line_list,
  252.     23    line_offset,
  253.     23    line_source,
  254.     23    lines,
  255.     23    linesCovered,
  256.     23    linesTotal,
  257.     23    log,
  258.     23    long,
  259.     23    loop,
  260.     23    map,
  261.     23    margin,
  262.     23    match,
  263.     23    max,
  264.     23    message,
  265.     23    meta,
  266.     23    min,
  267.     23    mkdir,
  268.     23    modeCoverageIgnoreFile,
  269.     23    modeIndex,
  270.     23    mode_cli,
  271.     23    mode_conditional,
  272.     23    mode_json,
  273.     23    mode_module,
  274.     23    mode_noop,
  275.     23    mode_property,
  276.     23    mode_shebang,
  277.     23    mode_stop,
  278.     23    module,
  279.     23    moduleFsInit,
  280.     23    moduleName,
  281.     23    module_list,
  282.     23    name,
  283.     23    name_alias,
  284.     23    name_list,
  285.     23    name_only,
  286.     23    node,
  287.     23    nomen,
  288.     23    noop,
  289.     23    now,
  290.     23    npm_config_mode_test_filter,
  291.     23    nr,
  292.     23    nud_prefix,
  293.     23    objectDeepCopyWithKeysSorted,
  294.     23    ok,
  295.     23    on,
  296.     23    open,
  297.     23    opening,
  298.     23    operator,
  299.     23    option,
  300.     23    option_dict,
  301.     23    optional,
  302.     23    order,
  303.     23    package_name,
  304.     23    padEnd,
  305.     23    padStart,
  306.     23    parameter_count,
  307.     23    parameter_rest,
  308.     23    parentIi,
  309.     23    parse,
  310.     23    parseInt,
  311.     23    pass,
  312.     23    pathname,
  313.     23    pathnameList,
  314.     23    platform,
  315.     23    pop,
  316.     23    printed,
  317.     23    processArgv,
  318.     23    process_argv,
  319.     23    process_env,
  320.     23    process_exit,
  321.     23    promises,
  322.     23    property,
  323.     23    property_dict,
  324.     23    push,
  325.     23    quote,
  326.     23    ranges,
  327.     23    readFile,
  328.     23    readdir,
  329.     23    readonly,
  330.     23    recursive,
  331.     23    reduce,
  332.     23    repeat,
  333.     23    replace,
  334.     23    resolve,
  335.     23    result,
  336.     23    reverse,
  337.     23    rgx,
  338.     23    role,
  339.     23    round,
  340.     23    scope_block,
  341.     23    scope_block_pop,
  342.     23    scope_block_push,
  343.     23    scope_declared,
  344.     23    scope_function,
  345.     23    scope_function_pop,
  346.     23    scope_function_push,
  347.     23    scope_name,
  348.     23    scope_report_push,
  349.     23    scriptId,
  350.     23    search,
  351.     23    set,
  352.     23    shebang,
  353.     23    shell,
  354.     23    shift,
  355.     23    signature,
  356.     23    single,
  357.     23    slice,
  358.     23    some,
  359.     23    sort,
  360.     23    source,
  361.     23    spawn,
  362.     23    splice,
  363.     23    split,
  364.     23    stack,
  365.     23    stack_trace,
  366.     23    start,
  367.     23    startOffset,
  368.     23    startsWith,
  369.     23    statement,
  370.     23    status,
  371.     23    stdio,
  372.     23    stop,
  373.     23    stop_at,
  374.     23    stringify,
  375.     23    subscript,
  376.     23    suffix,
  377.     23    suffix_file,
  378.     23    switch,
  379.     23    syntax_dict,
  380.     23    tenure,
  381.     23    test,
  382.     23    testFunction,
  383.     23    test_internal_error,
  384.     23    test_unknown_warning_code,
  385.     23    text,
  386.     23    this,
  387.     23    thru,
  388.     23    toFixed,
  389.     23    toLocaleString,
  390.     23    toLowerCase,
  391.     23    toString,
  392.     23    token,
  393.     23    token_global,
  394.     23    token_list,
  395.     23    token_nxt,
  396.     23    token_tree,
  397.     23    tokens,
  398.     23    trace,
  399.     23    tree,
  400.     23    trim,
  401.     23    trimEnd,
  402.     23    trimStart,
  403.     23    try,
  404.     23    type,
  405.     23    unlink,
  406.     23    unordered,
  407.     23    unshift,
  408.     23    url,
  409.     23    used,
  410.     23    v8CoverageListMerge,
  411.     23    v8CoverageReportCreate,
  412.     23    value,
  413.     23    values,
  414.     23    variable,
  415.     23    variable_prv,
  416.     23    version,
  417.     23    versions,
  418.     23    warn,
  419.     23    warn_at,
  420.     23    warning,
  421.     23    warning_list,
  422.     23    warning_list_untagged,
  423.     23    warnings,
  424.     23    white,
  425.     23    wrapped,
  426.     23    writeFile
  427.     23*/
  428.     23
  429.     23// init debugInline
  430.     23const debugInline = (function () {
  431.     23    let consoleError = Object;
  432.     23    function debug(...argList) {
  433.     23
  434.     23// This function will print <argList> to stderr and then return <argList>[0].
  435.     23
  436.     23        consoleError("\n\ndebugInline");
  437.     23        consoleError(...argList);
  438.     23        consoleError("\n");
  439.     23        if (consoleError === Object) {
  440.     23            consoleError = console.error;
  441.     23        }
  442.     23        return argList[0];
  443.     23    }
  444.     23    return debug;
  445.     23}());
  446.     23debugInline(); // coverage-hack
  447.     23
  448.     23const jslint_autofix_warning_list = [ //jslint-ignore-line
  449.     23    "expected_a_at_b_c",
  450.     23    "expected_a_at_end",
  451.     23    "expected_line_break_a_b",
  452.     23    "expected_space_a_b",
  453.     23    "unexpected_space_a_b",
  454.     23
  455.     23// PR-511 - jslint-autofix - Warning 'too_long' no longer blocks autofix.
  456.     23
  457.     23    "too_long"
  458.     23];
  459.     23const jslint_charset_ascii = (
  460.     23    "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007" +
  461.     23    "\b\t\n\u000b\f\r\u000e\u000f" +
  462.     23    "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017" +
  463.     23    "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f" +
  464.     23    " !\"#$%&'()*+,-./0123456789:;<=>?" +
  465.     23    "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_" +
  466.     23    "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"
  467.     23);
  468.     23const jslint_edition = "v2026.10.30";
  469.     23const jslint_fudge = 1;                 // Fudge starting line and starting
  470.     23                                        // ... column to 1.
  471.     23const jslint_global_dict_all = {
  472.     23/*jslint-disable*/
  473.     23
  474.     23// Assign global browser variables to global_dict.
  475.     23
  476.     23    "browser": {
  477.     23        "CharacterData": true,
  478.     23        "DocumentType": true,
  479.     23        "Element": true,
  480.     23        "FileReader": true,
  481.     23        "FontFace": true,
  482.     23        "IntersectionObserver": true,
  483.     23        "MutationObserver": true,
  484.     23        "WebAssembly": true,
  485.     23        "Worker": true,
  486.     23        "XMLHttpRequest": true,
  487.     23        "caches": false,
  488.     23        "document": true,
  489.     23        "history": false,
  490.     23        "indexedDB": true,
  491.     23        "location": true,
  492.     23        "name": false,
  493.     23        "postMessage": true,
  494.     23        "screen": false,
  495.     23        "window": true
  496.     23    },
  497.     23
  498.     23// https://docs.couchdb.org/en/stable/query-server/javascript.html#javascript
  499.     23
  500.     23    "couch": {
  501.     23        "emit": true,
  502.     23        "getRow": true,
  503.     23        "isArray": true,
  504.     23        "log": true,
  505.     23        "provides": true,
  506.     23        "registerType": true,
  507.     23        "require": true,
  508.     23        "send": true,
  509.     23        "start": true,
  510.     23        "sum": true,
  511.     23        "toJSON": true
  512.     23    },
  513.     23    "devel": {
  514.     23        "alert": true,
  515.     23        "confirm": true,
  516.     23        "console": true,
  517.     23        "prompt": true
  518.     23    },
  519.     23
  520.     23// These are the globals that are provided by the language standard.
  521.     23// Assign global ECMAScript variables to global_dict.
  522.     23
  523.     23    "ecma": {
  524.     23        "ShadowRealm": true,
  525.     23        "eval": true,
  526.     23        "import": true
  527.     23    },
  528.     23
  529.     23// Assign global Node.js variables to global_dict.
  530.     23
  531.     23    "node": {
  532.     23        "__dirname": true,
  533.     23        "__filename": true
  534.     23    },
  535.     23
  536.     23// sh jslint_ci.sh shCiJslintGlobalDictAllFetch
  537.     23
  538.     23// jslint_global_dict_all - auto-generated - start.
  539.     23
  540.     23    "ecma_auto": {
  541.     23        "AggregateError": true,
  542.     23        "Array": true,
  543.     23        "ArrayBuffer": true,
  544.     23        "AsyncDisposableStack": true,
  545.     23        "AsyncFunction": true,
  546.     23        "AsyncGenerator": true,
  547.     23        "AsyncGeneratorFunction": true,
  548.     23        "AsyncIterator": true,
  549.     23        "Atomics": true,
  550.     23        "BigInt": true,
  551.     23        "BigInt64Array": true,
  552.     23        "BigUint64Array": true,
  553.     23        "Boolean": true,
  554.     23        "DataView": true,
  555.     23        "Date": true,
  556.     23        "DisposableStack": true,
  557.     23        "Error": true,
  558.     23        "EvalError": true,
  559.     23        "FinalizationRegistry": true,
  560.     23        "Float16Array": true,
  561.     23        "Float32Array": true,
  562.     23        "Float64Array": true,
  563.     23        "Function": true,
  564.     23        "Generator": true,
  565.     23        "GeneratorFunction": true,
  566.     23        "Infinity": true,
  567.     23        "Int16Array": true,
  568.     23        "Int32Array": true,
  569.     23        "Int8Array": true,
  570.     23        "InternalError": false,
  571.     23        "Intl": true,
  572.     23        "Iterator": true,
  573.     23        "JSON": true,
  574.     23        "Map": true,
  575.     23        "Math": true,
  576.     23        "NaN": true,
  577.     23        "Number": true,
  578.     23        "Object": true,
  579.     23        "Promise": true,
  580.     23        "Proxy": true,
  581.     23        "RangeError": true,
  582.     23        "ReferenceError": true,
  583.     23        "Reflect": true,
  584.     23        "RegExp": true,
  585.     23        "Set": true,
  586.     23        "SharedArrayBuffer": true,
  587.     23        "String": true,
  588.     23        "SuppressedError": true,
  589.     23        "Symbol": true,
  590.     23        "SyntaxError": true,
  591.     23        "Temporal": true,
  592.     23        "TypeError": true,
  593.     23        "TypedArray": true,
  594.     23        "URIError": true,
  595.     23        "Uint16Array": true,
  596.     23        "Uint32Array": true,
  597.     23        "Uint8Array": true,
  598.     23        "Uint8ClampedArray": true,
  599.     23        "WeakMap": true,
  600.     23        "WeakRef": true,
  601.     23        "WeakSet": true,
  602.     23        "decodeURI": true,
  603.     23        "decodeURIComponent": true,
  604.     23        "encodeURI": true,
  605.     23        "encodeURIComponent": true,
  606.     23        "escape": false,
  607.     23        "globalThis": true,
  608.     23        "isFinite": true,
  609.     23        "isNaN": true,
  610.     23        "parseFloat": true,
  611.     23        "parseInt": true,
  612.     23        "undefined": true,
  613.     23        "unescape": false
  614.     23    },
  615.     23    "node_auto": {
  616.     23        "AbortController":              "node brow",
  617.     23        "AbortSignal":                  "node brow",
  618.     23        "Blob":                         "node brow",
  619.     23        "BroadcastChannel":             "node brow",
  620.     23        "Buffer":                       "node ----",
  621.     23        "ByteLengthQueuingStrategy":    "node brow",
  622.     23        "CloseEvent":                   "node brow",
  623.     23        "CompressionStream":            "node brow",
  624.     23        "CountQueuingStrategy":         "node brow",
  625.     23        "Crypto":                       "node brow",
  626.     23        "CryptoKey":                    "node brow",
  627.     23        "CustomEvent":                  "node brow",
  628.     23        "DOMException":                 "node brow",
  629.     23        "DecompressionStream":          "node brow",
  630.     23        "Event":                        "node brow",
  631.     23        "EventSource":                  "node brow",
  632.     23        "EventTarget":                  "node brow",
  633.     23        "File":                         "node brow",
  634.     23        "FormData":                     "node brow",
  635.     23        "Headers":                      "node brow",
  636.     23        "MessageChannel":               "node brow",
  637.     23        "MessageEvent":                 "node brow",
  638.     23        "MessagePort":                  "node brow",
  639.     23        "Navigator":                    "node brow",
  640.     23        "PerformanceEntry":             "node brow",
  641.     23        "PerformanceMark":              "node brow",
  642.     23        "PerformanceMeasure":           "node brow",
  643.     23        "PerformanceObserver":          "node brow",
  644.     23        "PerformanceObserverEntryList": "node brow",
  645.     23        "PerformanceResourceTiming":    "node brow",
  646.     23        "ReadableByteStreamController": "node brow",
  647.     23        "ReadableStream":               "node brow",
  648.     23        "ReadableStreamBYOBReader":     "node brow",
  649.     23        "ReadableStreamBYOBRequest":    "node brow",
  650.     23        "ReadableStreamDefaultController": "node brow",
  651.     23        "ReadableStreamDefaultReader":  "node brow",
  652.     23        "Request":                      "node brow",
  653.     23        "Response":                     "node brow",
  654.     23        "Storage":                      "node brow",
  655.     23        "SubtleCrypto":                 "node brow",
  656.     23        "TextDecoder":                  "node brow",
  657.     23        "TextDecoderStream":            "node brow",
  658.     23        "TextEncoder":                  "node brow",
  659.     23        "TextEncoderStream":            "node brow",
  660.     23        "TransformStream":              "node brow",
  661.     23        "TransformStreamDefaultController": "node brow",
  662.     23        "URL":                          "node brow",
  663.     23        "URLPattern":                   "node brow",
  664.     23        "URLSearchParams":              "node brow",
  665.     23        "WebAssembly":                  "node ----",
  666.     23        "WebSocket":                    "node brow",
  667.     23        "WritableStream":               "node brow",
  668.     23        "WritableStreamDefaultController": "node brow",
  669.     23        "WritableStreamDefaultWriter":  "node brow",
  670.     23        "__dirname":                    "node ----",
  671.     23        "__filename":                   "node ----",
  672.     23        "atob":                         "---- ----",
  673.     23        "btoa":                         "---- ----",
  674.     23        "clearImmediate":               "node ----",
  675.     23        "clearInterval":                "node brow",
  676.     23        "clearTimeout":                 "node brow",
  677.     23        "console":                      "node brow",
  678.     23        "crypto":                       "node brow",
  679.     23        "exports":                      "node ----",
  680.     23        "fetch":                        "node brow",
  681.     23        "global":                       "node ----",
  682.     23        "localStorage":                 "node brow",
  683.     23        "module":                       "node ----",
  684.     23        "navigator":                    "node brow",
  685.     23        "performance":                  "node brow",
  686.     23        "process":                      "node ----",
  687.     23        "queueMicrotask":               "node brow",
  688.     23        "require":                      "node ----",
  689.     23        "sessionStorage":               "node brow",
  690.     23        "setImmediate":                 "node ----",
  691.     23        "setInterval":                  "node brow",
  692.     23        "setTimeout":                   "node brow",
  693.     23        "structuredClone":              "node brow"
  694.     23    }
  695.     23
  696.     23// jslint_global_dict_all - auto-generated - end.
  697.     23
  698.     23/*jslint-enable*/
  699.     23};
  700.     23const jslint_rgx_cap = (
  701.     23    /^[A-Z]/
  702.     23);
  703.     23const jslint_rgx_crlf = (
  704.     23    /\n|\r\n?/
  705.     23);
  706.     23const jslint_rgx_digits_bits = (
  707.     23    /^[01_]*/
  708.     23);
  709.     23const jslint_rgx_digits_decimals = (
  710.     23    /^[0-9_]*/
  711.     23);
  712.     23const jslint_rgx_digits_hexs = (
  713.     23    /^[0-9A-F_]*/i
  714.     23);
  715.     23const jslint_rgx_digits_octals = (
  716.     23    /^[0-7_]*/
  717.     23);
  718.     23const jslint_rgx_directive = (
  719.     23    /^(jslint|property|global)\s+?(\S.*?)$/
  720.     23);
  721.     23const jslint_rgx_directive_part = (
  722.     23    /([a-zA-Z$_][a-zA-Z0-9$_]*)(?::\s*(true|false))?,?\s*|$/g
  723.     23);
  724.     23const jslint_rgx_identifier = (
  725.     23    /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/
  726.     23);
  727.     23const jslint_rgx_json_number = (
  728.     23
  729.     23// https://datatracker.ietf.org/doc/html/rfc7159#section-6
  730.     23// number = [ minus ] int [ frac ] [ exp ]
  731.     23
  732.     23    /^-?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][\-+]?\d+)?$/
  733.     23);
  734.     23const jslint_rgx_mega = (
  735.     23
  736.     23// Vim-hack - vim-editor has trouble parsing naked '`' in regexp
  737.     23
  738.     23    /[\u0060\\]|\$\{/
  739.     23);
  740.     23const jslint_rgx_module = (
  741.     23    /^[a-zA-Z0-9_$:.@\-\/]+$/
  742.     23);
  743.     23const jslint_rgx_numeric_separator_illegal = (
  744.     23    /__|_$|_n$/m
  745.     23);
  746.     23const jslint_rgx_slash_star_or_slash = (
  747.     23    /\/\*|\/$/
  748.     23);
  749.     23const jslint_rgx_tab = (
  750.     23    /\t/g
  751.     23);
  752.     23const jslint_rgx_todo = (
  753.     23    /\b(?:todo|TO\s?DO|HACK)\b/
  754.     23);
  755.     23const jslint_rgx_token = new RegExp(
  756.     23    "^(" +
  757.     23    "(\\s+)" +
  758.     23    "|([a-zA-Z_$][a-zA-Z0-9_$]*)" +
  759.     23    "|[(){}\\[\\],:;'\"~\\`]" +
  760.     23    "|\\?\\?=" +
  761.     23    "|\\?[?.]?" +
  762.     23    "|=(?:==?|>)?" +
  763.     23    "|\\.+" +
  764.     23
  765.     23// PR-514 - Add Exponentiation-assignment-operator '**=' support.
  766.     23
  767.     23    "|\\*(?:\\*=?|[\\/=])?" +
  768.     23    "|\\/[*\\/]?" +
  769.     23    "|\\+[=+]?" +
  770.     23    "|-[=\\-]?" +
  771.     23    "|[\\^%]=?" +
  772.     23    "|&&=" +
  773.     23    "|&[&=]?" +
  774.     23    "|\\|\\|=" +
  775.     23    "|\\|[|=]?" +
  776.     23    "|>{1,3}=?" +
  777.     23    "|<<?=?" +
  778.     23    "|!(?:!|==?)?" +
  779.     23
  780.     23// PR-351 - Add BigInt support.
  781.     23// PR-390 - Add numeric-separator support.
  782.     23
  783.     23    "|((?:0_?|[1-9][0-9_]*)n?)" +
  784.     23    ")" +
  785.     23    "(.*)$"
  786.     23);
  787.     23const jslint_rgx_url_search_window_jslint = (
  788.     23    /[&?]window_jslint=1(?:$|&)/m
  789.     23);
  790.     23const jslint_rgx_weird_property = (
  791.     23    /^_|\$|Sync$|_$/m
  792.     23);
  793.     23const jstestItRecordList = [];
  794.     23let jslint_export;                      // The jslint object to be exported.
  795.     23let jslint_import_meta_url = "";        // import.meta.url used by cli.
  796.     23let jstestDescribeNow;                  // The describe whose body is running.
  797.     23let jstestDescribePrv = "";
  798.     23let jstestItCount = 0;
  799.     23let jstestTimeStart;
  800.     23let moduleChildProcess;
  801.     23let moduleFs;
  802.     23let moduleFsInitResolveList;
  803.     23let modulePath;
  804.     23let moduleUrl;
  805.     23
  806.     11async function assertErrorThrownAsync(asyncFunc, regexp) {
  807.     11
  808.     11// This function will assert calling <asyncFunc> throws an error.
  809.     11
  810.     11    let err;
  811.     11    try {
  812.      1        await asyncFunc();
  813.     10    } catch (errCaught) {
  814.     10        err = errCaught;
  815.     10    }
  816.     11    assertOrThrow(err, "No error thrown.");
  817.     11    assertOrThrow(
  818.      4        !regexp || new RegExp(regexp).test(err.message),
  819.     11        err
  820.     11    );
  821.     11}
  822.     23
  823.    320function assertJsonEqual(aa, bb, message) {
  824.    320
  825.    320// This function will assert JSON.stringify(<aa>) === JSON.stringify(<bb>).
  826.    320
  827.    320    aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa), undefined, 1);
  828.    320    bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb), undefined, 1);
  829.      3    if (aa !== bb) {
  830.      3        throw new Error(
  831.      3            "\n" + aa + "\n!==\n" + bb +
  832.      3            (
  833.      3                typeof message === "string"
  834.      3                ? " - " + message
  835.      3                : message
  836.      3                ? " - " + JSON.stringify(message)
  837.      3                : ""
  838.      3            )
  839.      3        );
  840.      3    }
  841.    320}
  842.     23
  843.   1842function assertOrThrow(condition, message) {
  844.   1842
  845.   1842// This function will throw <message> if <condition> is falsy.
  846.   1842
  847.      4    if (!condition) {
  848.      4        throw (
  849.      4            (!message || typeof message === "string")
  850.      4            ? new Error(String(message).slice(0, 2048))
  851.      4            : message
  852.      4        );
  853.      4    }
  854.   1842}
  855.     23
  856. 155760function empty() {
  857. 155760
  858. 155760// The empty function produces a new empty object that inherits nothing. This is
  859. 155760// much better than '{}' because confusions around accidental method names like
  860. 155760// 'constructor' are completely avoided.
  861. 155760
  862. 155760    return Object.create(null);
  863. 155760}
  864.     23
  865.     95async function fsWriteFileWithParents(pathname, data) {
  866.     95
  867.     95// This function will write <data> to <pathname> and lazy-mkdirp if necessary.
  868.     95
  869.     95    await moduleFsInit();
  870.     95
  871.     95// Try writing to pathname.
  872.     95
  873.     95    try {
  874.     72        await moduleFs.promises.writeFile(pathname, data);
  875.     72    } catch (ignore) {
  876.     23
  877.     23// Lazy mkdirp.
  878.     23
  879.     23        await moduleFs.promises.mkdir(modulePath.dirname(pathname), {
  880.     23            recursive: true
  881.     23        });
  882.     23
  883.     23// Retry writing to pathname.
  884.     23
  885.     23        await moduleFs.promises.writeFile(pathname, data);
  886.     23    }
  887.     95    console.error("wrote file " + pathname);
  888.     95}
  889.     23
  890.    185function globExclude({
  891.    185    excludeList = [],
  892.    185    includeList = [],
  893.    185    pathnameList = []
  894.    185}) {
  895.    185
  896.    185// This function will
  897.    185// 1. Exclude pathnames in <pathnameList> that don't match glob-patterns in
  898.    185//    <includeList>.
  899.    185// 2. Exclude pathnames in <pathnameList> that match glob-patterns in
  900.    185//    <excludeList>.
  901.    185
  902.    555    function globAssertNotWeird(list, name) {
  903.    555
  904.    555// This function will check if <list> of strings contain weird characters.
  905.    555
  906.    555        [
  907.    555            [
  908.    555                "\n", (
  909.    555                    /^.*?([\u0000-\u0007\r]).*/gm
  910.    555                )
  911.    555            ],
  912.    555            [
  913.    555                "\r", (
  914.    555                    /^.*?([\n]).*/gm
  915.    555                )
  916.    555            ]
  917.   1108        ].forEach(function ([
  918.   1108            separator, rgx
  919.   1108        ]) {
  920.      3            list.join(separator).replace(rgx, function (match0, char) {
  921.      3                throw new Error(
  922.      3                    "Weird character " +
  923.      3                    JSON.stringify(char) +
  924.      3                    " found in " + name + " " +
  925.      3                    JSON.stringify(match0)
  926.      3                );
  927.      3            });
  928.   1108        });
  929.    555    }
  930.    185
  931.   1371    function globToRegexp(pattern) {
  932.   1371
  933.   1371// This function will translate glob <pattern> to javascript-regexp,
  934.   1371// which javascript can then use to "glob" pathnames.
  935.   1371
  936.   1371        let ii = 0;
  937.   1371        let isClass = false;
  938.   1371        let strClass = "";
  939.   1371        let strRegex = "";
  940.   1371        pattern = pattern.replace((
  941.   1371            /\/\/+/g
  942.   1371        ), "/");
  943.   1371        pattern = pattern.replace((
  944.   1371            /\*\*\*+/g
  945.   1371        ), "**");
  946.   1371        pattern.replace((
  947.   1371            /\\\\|\\\[|\\\]|\[|\]|./g
  948.  18704        ), function (match0) {
  949.  18704            switch (match0) {
  950.    310            case "[":
  951.    310                if (isClass) {
  952.    310                    strClass += "[";
  953.    310                    return;
  954.    310                }
  955.    310                strClass += "\u0000";
  956.    310                strRegex += "\u0000";
  957.    310                isClass = true;
  958.    310                return;
  959.    310            case "]":
  960.    310                if (isClass) {
  961.    310                    isClass = false;
  962.    310                    return;
  963.    310                }
  964.    310                strRegex += "]";
  965.    310                return;
  966.  18084            default:
  967.  18084                if (isClass) {
  968.  18084                    strClass += match0;
  969.  18084                    return;
  970.  18084                }
  971.  18084                strRegex += match0;
  972.  15034            }
  973.  15034            return "";
  974.  15034        });
  975.   1371        strClass += "\u0000";
  976.   1371
  977.   1371// An expression "[!...]" matches a single character, namely any character that
  978.   1371// is not matched by the expression obtained by removing the first '!' from it.
  979.   1371// (Thus, "[!a-]" matches any single character except 'a', and '-'.)
  980.   1371
  981.   1371        strClass = strClass.replace((
  982.   1371            /\u0000!/g
  983.   1371        ), "\u0000^");
  984.   1371
  985.   1371// One may include '-' in its literal meaning by making it the first or last
  986.   1371// character between the brackets.
  987.   1371
  988.   1371        strClass = strClass.replace((
  989.   1371            /\u0000-/g
  990.   1371        ), "\u0000\\-");
  991.   1371        strClass = strClass.replace((
  992.   1371            /-\u0000/g
  993.   1371        ), "\\-\u0000");
  994.   1371
  995.   1371// Escape brackets '[', ']' in character class.
  996.   1371
  997.   1371        strClass = strClass.replace((
  998.   1371            /[\[\]]/g
  999.   1371        ), "\\$&");
 1000.   1371
 1001.   1371// https://stackoverflow.com/questions/3561493
 1002.   1371// /is-there-a-regexp-escape-function-in-javascript
 1003.   1371// $()*+-./?[\]^{|}
 1004.   1371
 1005.   1371        strRegex = strRegex.replace((
 1006.   1371
 1007.   1371// Ignore [-/].
 1008.   1371
 1009.   1371            /[$()*+.?\[\\\]\^{|}]/g
 1010.   1371        ), "\\$&");
 1011.   1371
 1012.   1371// Expand wildcard '**/*'.
 1013.   1371
 1014.   1371        strRegex = strRegex.replace((
 1015.   1371            /\\\*\\\*\/(?:\\\*)+/g
 1016.   1371        ), ".*?");
 1017.   1371
 1018.   1371// Expand wildcard '**'.
 1019.   1371
 1020.   1371        strRegex = strRegex.replace((
 1021.   1371            /(^|\/)\\\*\\\*(\/|$)/gm
 1022.   1371        ), "$1.*?$2");
 1023.   1371
 1024.   1371// Expand wildcard '*'.
 1025.   1371
 1026.   1371        strRegex = strRegex.replace((
 1027.   1371            /(?:\\\*)+/g
 1028.   1371        ), "[^\\/]*?");
 1029.   1371
 1030.   1371// Expand wildcard '?'.
 1031.   1371
 1032.   1371        strRegex = strRegex.replace((
 1033.   1371            /\\\?/g
 1034.   1371        ), "[^\\/]");
 1035.   1371
 1036.   1371// Expand directory-with-trailing-slash '.../'.
 1037.   1371
 1038.   1371        strRegex = strRegex.replace((
 1039.   1371            /\/$/gm
 1040.   1371        ), "\\/.*?");
 1041.   1371
 1042.   1371// Merge strClass into strRegex.
 1043.   1371
 1044.   1371        ii = 0;
 1045.   1371        strClass = strClass.split("\u0000");
 1046.   1371        strRegex = strRegex.replace((
 1047.   1371            /\u0000/g
 1048.    306        ), function () {
 1049.    306            ii += 1;
 1050.      2            if (strClass[ii] === "") {
 1051.      2                return "";
 1052.    304            }
 1053.    304            return "[" + strClass[ii] + "]";
 1054.    304        });
 1055.   1371
 1056.   1371// Change strRegex from string to regexp.
 1057.   1371
 1058.   1371        strRegex = new RegExp("^" + strRegex + "$", "gm");
 1059.   1371        return strRegex;
 1060.   1371    }
 1061.    185
 1062.    185// Validate excludeList, includeList, pathnameList.
 1063.    185
 1064.    185    globAssertNotWeird(excludeList, "pattern");
 1065.    185    globAssertNotWeird(includeList, "pattern");
 1066.    185    globAssertNotWeird(pathnameList, "pathname");
 1067.    185
 1068.    185// Optimization
 1069.    185// Concat pathnames into a single, newline-separated string,
 1070.    185// whose pathnames can all be filtered with a single, regexp-pass.
 1071.    185
 1072.    185    pathnameList = pathnameList.join("\n");
 1073.    185
 1074.    185// 1. Exclude pathnames in <pathnameList> that don't match glob-patterns in
 1075.    185//    <includeList>.
 1076.    185
 1077.    142    if (includeList.length > 0) {
 1078.    142        includeList = includeList.map(globToRegexp);
 1079.    574        includeList.forEach(function (pattern) {
 1080.    574            pathnameList = pathnameList.replace(pattern, "\u0000$&");
 1081.    574        });
 1082.    142        pathnameList = pathnameList.replace((
 1083.    142            /^[^\u0000].*/gm
 1084.    142        ), "");
 1085.    142        pathnameList = pathnameList.replace((
 1086.    142            /^\u0000+/gm
 1087.    142        ), "");
 1088.    182    }
 1089.    182
 1090.    182// 2. Exclude pathnames in <pathnameList> that match glob-patterns in
 1091.    182//    <excludeList>.
 1092.    182
 1093.    182    excludeList = excludeList.map(globToRegexp);
 1094.    797    excludeList.forEach(function (pattern) {
 1095.    797        pathnameList = pathnameList.replace(pattern, "");
 1096.    797    });
 1097.    182
 1098.    182// Split newline-separated pathnames back to list.
 1099.    182
 1100.  10118    pathnameList = pathnameList.split("\n").filter(function (elem) {
 1101.  10118        return elem;
 1102.  10118    });
 1103.    182    return {
 1104.    182        excludeList,
 1105.    182        includeList,
 1106.    182        pathnameList
 1107.    182    };
 1108.    182}
 1109.     23
 1110.  20054function htmlEscape(str) {
 1111.  20054
 1112.  20054// This function will make <str> html-safe by escaping & < >.
 1113.  20054
 1114.  20054    return String(str)
 1115.  20054        .replace((/&/g), "&amp;")
 1116.  20054        .replace((/</g), "&lt;")
 1117.  20054        .replace((/>/g), "&gt;");
 1118.  20054}
 1119.     23
 1120.   1050function jslint(
 1121.   1050    source = "",                // A text to analyze.
 1122.   1050    option_dict = empty(),      // An object whose keys correspond to option
 1123.   1050                                // ... names.
 1124.   1050    global_list = []            // An array of strings containing global
 1125.   1050                                // ... variables that the file is allowed
 1126.   1050                                // ... readonly access.
 1127.   1050) {
 1128.   1050
 1129.   1050// The jslint function itself.
 1130.   1050
 1131.   1050    const block_list = [];      // The array containing all lexical-blocks.
 1132.   1050    const block_stack = [];     // The stack of lexical-blocks.
 1133.   1050    const directive_list = [];  // The directive comments.
 1134.   1050    const export_dict = empty();        // The exported names and values.
 1135.   1050    const function_list = [];   // The array containing all functions.
 1136.   1050    const function_stack = [];  // The stack of functions.
 1137.   1050    const global_dict = empty();        // The object containing the global
 1138.   1050                                        // ... declarations.
 1139.   1050    const import_list = [];     // The array collecting all import-from strings.
 1140.   1050    const line_list = String(   // The array containing source lines.
 1141.   1050        "\n" + source
 1142. 121465    ).split(jslint_rgx_crlf).map(function (line_source) {
 1143. 121465        return {
 1144. 121465            line_source
 1145. 121465        };
 1146. 121465    });
 1147.   1050    const mode_autofix = (
 1148.   1050        option_dict.autofix === true
 1149.     36        ? 256
 1150.   1014        : Math.max(0, Number(option_dict.autofix) || 0)
 1151.   1050    );
 1152.   1050    const property_dict = empty();      // The object containing the tallied
 1153.   1050                                        // ... property names.
 1154.   1050                                // jslint functions.
 1155.   1050    const state = empty();      // jslint state-object to be passed between
 1156.   1050    const syntax_dict = empty();        // The object containing the parser.
 1157.   1050    const tenure = empty();     // The predefined property registry.
 1158.   1050    const token_global = {      // The global object; the outermost context.
 1159.   1050        async: 0,
 1160.   1050        context: empty(),
 1161.   1050        finally: 0,
 1162.   1050        from: 0,
 1163.   1050        function_body: true,
 1164.   1050        id: "(global)",
 1165.   1050        level: 0,
 1166.   1050        line: jslint_fudge,
 1167.   1050        loop: 0,
 1168.   1050        switch: 0,
 1169.   1050        thru: 0,
 1170.   1050        try: 0
 1171.   1050    };
 1172.   1050    const token_list = [];      // The array of tokens.
 1173.   1050    const warning_list = [];    // The array collecting all generated warnings.
 1174.   1050    let autofixed;              // The <source> after one autofix pass.
 1175.   1050    let mode_stop = false;      // true if JSLint cannot finish.
 1176.   1050    let result_autofix;         // The re-lint of <autofixed>.
 1177.   1050
 1178.   1050// Error reportage functions:
 1179.   1050
 1180.   9832    function artifact(the_token) {
 1181.   9832
 1182.   9832// Return a string representing an artifact.
 1183.   9832
 1184.     41        the_token = the_token || state.token_nxt;
 1185.   9832        return (
 1186.   6598            (the_token.id === "(string)" || the_token.id === "(number)")
 1187.   3551            ? String(the_token.value)
 1188.   6281            : the_token.id
 1189.   9832        );
 1190.   9832    }
 1191.   1050
 1192.  33879    function is_equal(aa, bb) {
 1193.  33879
 1194.  33879// test_cause:
 1195.  33879// ["0&&0", "is_equal", "(live)", "", 0]
 1196.  33879
 1197.  33879// PR-510 - deadcode-confirmed - <aa> and <bb> are never the same object. Each
 1198.  33879// call below pairs a slot of <aa> with the same slot of <bb>, and the only
 1199.  33879// slot that can be undefined on both sides is <expression>[1] of a binary
 1200.  33879// token. Case "`" returns before that branch, and <aa>.id !== "(" skips it.
 1201.  33879//
 1202.  33879// deadcode-revive - Delete case '`' below and a tagged-megastring with no
 1203.  33879// substitution falls through to the binary branch again. Its <expression>
 1204.  33879// holds one element, so both sides read <expression>[1] as undefined. Any
 1205.  33879// token with fewer slots than its <arity> implies does the same.
 1206.  33879//
 1207.  33879// if (aa === bb) {
 1208.  33879//     return true;
 1209.  33879// }
 1210.  33879
 1211.  33879        jslint_assert(!(aa === bb), `Expected !(aa === bb).`);
 1212.     38        if (Array.isArray(aa)) {
 1213.     38            return (
 1214.     38                Array.isArray(bb) &&
 1215.     38                aa.length === bb.length &&
 1216.     39                aa.every(function (value, index) {
 1217.     39
 1218.     39// test_cause:
 1219.     39// ["`${0}`&&`${0}`", "is_equal", "(live)", "", 0]
 1220.     39// ["`${0}`&&`${1}`", "is_equal", "(live)", "", 0]
 1221.     39
 1222.     39                    return is_equal(value, bb[index]);
 1223.     39                })
 1224.     38            );
 1225.  33841        }
 1226.  33841
 1227.  33841// PR-510 - deadcode-confirmed - If <aa> is not an array then <bb> is not one
 1228.  33841// either. Arrays only reach <is_equal> from case "`" below, and only when
 1229.  33841// <aa>.id === <bb>.id, so they arrive in pairs and the branch above takes both.
 1230.  33841//
 1231.  33841// deadcode-revive - Recurse on a slot that holds an array for some token ids
 1232.  33841// and a single token for others, or let the backtick case run when only one
 1233.  33841// side is a backtick.
 1234.  33841//
 1235.  33841// if (Array.isArray(bb)) {
 1236.  33841//     return false;
 1237.  33841// }
 1238.  33841
 1239.  33841        jslint_assert(!Array.isArray(bb), `Expected !Array.isArray(bb).`);
 1240.  33841        switch (aa.id === bb.id && aa.id) {
 1241.     82        case "(number)":
 1242.  24192        case "(string)":
 1243.  24192            return aa.value === bb.value;
 1244.     23        case "`":
 1245.     23
 1246.     23// test_cause:
 1247.     23// ["aa=bb`${cc}${dd}`&&bb`${cc}${ee}`", "is_equal", "(live)", "", 0]
 1248.     23
 1249.     23            return (
 1250.     23
 1251.     23// PR-394 - Bugfix - Fix jslint treating megastrings bb`0` and bb`1` as equal.
 1252.     23// The untagged form always warns, because <post_b_and> fires on any constant.
 1253.     23
 1254.     23                is_equal(aa.value, bb.value) &&
 1255.     23
 1256.     23// PR-510 - Bugfix - Fix jslint treating tagged-megastrings as equal when they
 1257.     23// differ past the first substitution, which is all the binary branch compared.
 1258.     23
 1259.     23                is_equal(aa.expression, bb.expression)
 1260.     23            );
 1261.   9626        }
 1262.   9626        if (is_weird(aa) || is_weird(bb)) {
 1263.     35
 1264.     35// test_cause:
 1265.     35// ["aa(/./)||{}", "is_equal", "(live)", "", 0]
 1266.     35
 1267.     35            return false;
 1268.   9591        }
 1269.   9591        if (aa.arity === bb.arity && aa.id === bb.id) {
 1270.   2194            if (aa.id === "." || aa.id === "?.") {
 1271.   2194
 1272.   2194// test_cause:
 1273.   2194// ["aa.bb&&aa.bb", "is_equal", "(live)", "", 0]
 1274.   2194// ["aa?.bb&&aa?.bb", "is_equal", "(live)", "", 0]
 1275.   2194
 1276.   2194                return (
 1277.   2194                    is_equal(aa.expression, bb.expression) &&
 1278.   2194                    is_equal(aa.name, bb.name)
 1279.   2194                );
 1280.   2194            }
 1281.   2194            if (aa.arity === "unary") {
 1282.   2194
 1283.   2194// test_cause:
 1284.   2194// ["+0&&+0", "is_equal", "(live)", "", 0]
 1285.   2194
 1286.   2194                return is_equal(aa.expression, bb.expression);
 1287.   2194            }
 1288.   2194            if (aa.arity === "binary") {
 1289.   2194
 1290.   2194// test_cause:
 1291.   2194// ["aa[0]&&aa[0]", "is_equal", "(live)", "", 0]
 1292.   2194
 1293.   2194                return (
 1294.   2194                    aa.id !== "(" &&
 1295.   2194                    is_equal(aa.expression[0], bb.expression[0]) &&
 1296.   2194                    is_equal(aa.expression[1], bb.expression[1])
 1297.   2194                );
 1298.   2194            }
 1299.   2194            if (aa.arity === "ternary") {
 1300.   2194
 1301.   2194// test_cause:
 1302.   2194// ["aa=(``?``:``)&&(``?``:``)", "is_equal", "(live)", "", 0]
 1303.   2194
 1304.   2194                return (
 1305.   2194                    is_equal(aa.expression[0], bb.expression[0]) &&
 1306.   2194                    is_equal(aa.expression[1], bb.expression[1]) &&
 1307.   2194                    is_equal(aa.expression[2], bb.expression[2])
 1308.   2194                );
 1309.   2194            }
 1310.   2194
 1311.   2194// PR-510 - deadcode-confirmed - Nothing in this file sets <arity> to "regexp",
 1312.   2194// and <arity> "function" is set in one place, on the "(" that opens a
 1313.   2194// parameter list in <prefix_function>. That token is never stored in an
 1314.   2194// <expression>, <name> or <value> slot, so <is_equal> never sees it.
 1315.   2194//
 1316.   2194// deadcode-revive - Compare two function expressions by recursing into their
 1317.   2194// parameter lists, which puts that "(" on both sides. Giving any token
 1318.   2194// <arity> "regexp" would also do it.
 1319.   2194//
 1320.   2194// if (aa.arity === "function" || aa.arity === "regexp") {
 1321.   2194//     return false;
 1322.   2194// }
 1323.   2194
 1324.   2194            jslint_assert(
 1325.   2194                !(aa.arity === "function" || aa.arity === "regexp"),
 1326.   2194                `Expected !(aa.arity === "function" || aa.arity === "regexp").`
 1327.   2194            );
 1328.   2194
 1329.   2194// test_cause:
 1330.   2194// ["undefined&&undefined", "is_equal", "(live)", "", 0]
 1331.   2194
 1332.   2194            return true;
 1333.   7397        }
 1334.   7397
 1335.   7397// test_cause:
 1336.   7397// ["null&&undefined", "is_equal", "(live)", "", 0]
 1337.   7397
 1338.   7397        return false;
 1339.   7397    }
 1340.   1050
 1341.  32332    function is_weird(thing) {
 1342.  32332        switch (thing.id) {
 1343.      1        case "(regexp)":
 1344.      1            return true;
 1345.      1        case "=>":
 1346.      1            return true;
 1347.    601        case "[":
 1348.    601            return thing.arity === "unary";
 1349.     14        case "function":
 1350.     14            return true;
 1351.     11        case "{":
 1352.     11            return true;
 1353.  31704        default:
 1354.  31704            return false;
 1355.  32332        }
 1356.  32332    }
 1357.   1050
 1358.  22676    function scope_block_pop() {
 1359.  22676        jslint_assert(
 1360.  22676            block_stack.length > 1,
 1361.  22676            `block_stack.length=${block_stack.length}`
 1362.  22676        );
 1363.  22676        block_stack.shift();
 1364.  22676        return block_stack[0];
 1365.  22676    }
 1366.   1050
 1367.  24576    function scope_block_push(value, list_push) {
 1368.   9028        if (!value.context) {
 1369.   9028            value.context = empty();
 1370.   9028        }
 1371.  24576        block_stack.unshift(value);
 1372.  10022        if (list_push) {
 1373.  10022            block_list.push(value);
 1374.  10022        }
 1375.  24576        return value;
 1376.  24576    }
 1377.   1050
 1378.   4705    function scope_function_pop() {
 1379.   4705        jslint_assert(
 1380.   4705            function_stack.length > 1,
 1381.   4705            `function_stack.length=${function_stack.length}`
 1382.   4705        );
 1383.   4705        function_stack.shift();
 1384.   4705        return function_stack[0];
 1385.   4705    }
 1386.   1050
 1387.   6573    function scope_function_push(value, list_push) {
 1388.   6573        function_stack.unshift(value);
 1389.   2367        if (list_push) {
 1390.   2367            function_list.push(value);
 1391.   2367        }
 1392.   6573        return value;
 1393.   6573    }
 1394.   1050
 1395.  22967    function scope_report_push(the_function, name) {
 1396.  22967
 1397.  22967// PR-516 - Bugfix - This function will push <name> to what <jslint_report>
 1398.  22967// lists for <the_function>, which are the names it declares and the outer
 1399.  22967// names it uses. An own 'bb' and an outer 'bb' are two entries.
 1400.  22967
 1401.      5        if (the_function.scope_name === name.scope_declared) {
 1402.      5
 1403.      5// PR-516 - A function using its own name from <scope_name> lists it nowhere,
 1404.      5// though a nested function using it lists it as outer.
 1405.      5
 1406.      5// test_cause:
 1407.      5// ["aa=function bb(){return bb;}", "scope_report_push", "(live)", "", 0]
 1408.      5
 1409.      5            return;
 1410.  22962        }
 1411.  22962        the_function.context_report ??= [];
 1412.  22962        the_function.context_report.push(name);
 1413.  22962    }
 1414.   1050
 1415.    134    function stop(code, the_token, a, b, c, d) {
 1416.    134
 1417.    134// Similar to warn and stop_at. If the token already had a warning, that
 1418.    134// warning will be replaced with this new one. It is likely that the stopping
 1419.    134// warning will be the more meaningful.
 1420.    134
 1421.      7        the_token = the_token || state.token_nxt;
 1422.    134        delete the_token.warning;
 1423.    134        throw warn(code, the_token, a, b, c, d);
 1424.    134    }
 1425.   1050
 1426.     40    function stop_at(code, line, column, a, b, c, d) {
 1427.     40
 1428.     40// Same as warn_at, except that it stops the analysis.
 1429.     40
 1430.     40        throw warn_at(code, line, column, a, b, c, d);
 1431.     40    }
 1432.   1050
 1433.   1830    function warn(code, the_token, a, b, c, d) {
 1434.   1830
 1435.   1830// Same as warn_at, except the warning will be associated with a specific token.
 1436.   1830// If there is already a warning on this token, suppress the new one. It is
 1437.   1830// likely that the first warning will be the most meaningful.
 1438.   1830
 1439.   1830        let the_warning;
 1440.     21        the_token = the_token || state.token_nxt;
 1441.   1830        the_warning = warn_at(
 1442.   1830            code,
 1443.   1830            the_token.line,
 1444.   1830            the_token.from,
 1445.   1342            a || artifact(the_token),
 1446.   1830            b,
 1447.   1830            c,
 1448.   1830            d
 1449.   1830        );
 1450.   1830
 1451.   1830// Issue #408
 1452.   1830// Warnings that should be ignored sometimes suppress legitimate warnings.
 1453.   1830
 1454.     88        if (the_warning.directive_ignore_line) {
 1455.     88            return the_warning;
 1456.   1742        }
 1457.   1742
 1458.   1742// If there is already a warning on this token, suppress the new one. It is
 1459.   1742// likely that the first warning will be the most meaningful.
 1460.   1742
 1461.   1742        if (the_token.warning) {
 1462.    234            warning_list.pop();
 1463.    234            return the_warning;
 1464.   1508        }
 1465.   1508        the_token.warning = the_warning;
 1466.   1508        return the_warning;
 1467.   1508    }
 1468.   1050
 1469.   2389    function warn_at(code, line, column, a, b, c, d) {
 1470.   2389
 1471.   2389// Report an error at some line and column of the program. The warning object
 1472.   2389// resembles an exception.
 1473.   2389
 1474.   2389        const warning = {
 1475.   2389            a, //jslint-ignore-line
 1476.   2389            b, //jslint-ignore-line
 1477.   2389            c, //jslint-ignore-line
 1478.   2389            code,
 1479.   2389            d, //jslint-ignore-line
 1480.   2389            line,
 1481.   2389            line_source: "",
 1482.   2389            name: "JSLintError",
 1483.   2389            ...line_list[Math.min(line, line_list.length - 1)]
 1484.   2389        };
 1485.   2389        let mm;
 1486.   2389        jslint_assert(typeof column === "number", `column=${column}`);
 1487.     35        if (line >= line_list.length) {
 1488.     35
 1489.     35// Handle premature EOF.
 1490.     35
 1491.     35            warning.line = line_list.length - 1;
 1492.     35            column = warning.line_source.length - 1;
 1493.     35        }
 1494.   2389        warning.column = (
 1495.   2389
 1496.   2389// Fudge column numbers in warning message.
 1497.   2389
 1498.   2389            jslint_fudge +
 1499.   2389            Math.max(0, Math.min(column, warning.line_source.length - 1))
 1500.   2389        );
 1501.   2389        switch (code) {
 1502.   2389
 1503.   2389// The bundle contains the raw text messages that are generated by jslint. It
 1504.   2389// seems that they are all error messages and warnings. There are no "Atta
 1505.   2389// boy!" or "You are so awesome!" messages. There is no positive reinforcement
 1506.   2389// or encouragement. This relentless negativity can undermine self-esteem and
 1507.   2389// wound the inner child. But if you accept it as sound advice rather than as
 1508.   2389// personal criticism, it can make your programs better.
 1509.   2389
 1510.     18        case "bad_assignment_a":
 1511.     18            mm = `Bad assignment to '${a}'.`;
 1512.     18            break;
 1513.      2        case "bad_directive_a":
 1514.      2            mm = `Bad directive '${a}'.`;
 1515.      2            break;
 1516.      1        case "bad_get":
 1517.      1            mm = `A get function takes no parameters.`;
 1518.      1            break;
 1519.      1        case "bad_module_name_a":
 1520.      1            mm = `Bad module name '${a}'.`;
 1521.      1            break;
 1522.      3        case "bad_option_a":
 1523.      3            mm = `Bad option '${a}'.`;
 1524.      3            break;
 1525.      2        case "bad_set":
 1526.      2            mm = `A set function takes one parameter.`;
 1527.      2            break;
 1528.      5        case "duplicate_a":
 1529.      5            mm = `Duplicate '${a}'.`;
 1530.      5            break;
 1531.    140        case "empty_block":
 1532.    140            mm = `Empty block.`;
 1533.    140            break;
 1534.     44        case "expected_a":
 1535.     44            mm = `Expected '${a}'.`;
 1536.     44            break;
 1537.    404        case "expected_a_after_b":
 1538.    404            mm = `Expected '${a}' after '${b}'.`;
 1539.    404            break;
 1540.     54        case "expected_a_at_b_c":
 1541.     54            mm = (
 1542.     54                `Expected '${a}' at column ${b + jslint_fudge},` +
 1543.     54                ` not column ${c + jslint_fudge}.`
 1544.     54            );
 1545.     54            break;
 1546.     11        case "expected_a_at_end":
 1547.     11            mm = `Expected '${a}' at the end of its left operand's line.`;
 1548.     11            break;
 1549.    113        case "expected_a_b":
 1550.    113            mm = `Expected '${a}' and instead saw '${b}'.`;
 1551.    113            break;
 1552.     21        case "expected_a_b_before_c_d":
 1553.     21            mm = `Expected ${a} '${b}' to be ordered before ${c} '${d}'.`;
 1554.     21            break;
 1555.      2        case "expected_a_b_from_c_d":
 1556.      2            mm = (
 1557.      2                `Expected '${a}' to match '${b}' from line ${c}` +
 1558.      2                ` and instead saw '${d}'.`
 1559.      2            );
 1560.      2            break;
 1561.     40        case "expected_a_before_b":
 1562.     40            mm = `Expected '${a}' before '${b}'.`;
 1563.     40            break;
 1564.      4        case "expected_digits_after_a":
 1565.      4            mm = `Expected digits after '${a}'.`;
 1566.      4            break;
 1567.      4        case "expected_four_digits":
 1568.      4            mm = `Expected four digits after '\\u'.`;
 1569.      4            break;
 1570.     37        case "expected_identifier_a":
 1571.     37            mm = `Expected an identifier and instead saw '${a}'.`;
 1572.     37            break;
 1573.     35        case "expected_line_break_a_b":
 1574.     35            mm = `Expected a line break between '${a}' and '${b}'.`;
 1575.     35            break;
 1576.      5        case "expected_regexp_factor_a":
 1577.      5            mm = `Expected a regexp factor and instead saw '${a}'.`;
 1578.      5            break;
 1579.     75        case "expected_space_a_b":
 1580.     75            mm = `Expected one space between '${a}' and '${b}'.`;
 1581.     75            break;
 1582.      2        case "expected_statements_a":
 1583.      2            mm = `Expected statements before '${a}'.`;
 1584.      2            break;
 1585.      2        case "expected_string_a":
 1586.      2            mm = `Expected a string and instead saw '${a}'.`;
 1587.      2            break;
 1588.      1        case "expected_type_string_a":
 1589.      1            mm = `Expected a type string and instead saw '${a}'.`;
 1590.      1            break;
 1591.     12        case "freeze_exports":
 1592.     12            mm = (
 1593.     12                `Expected 'Object.freeze('. All export values should be frozen.`
 1594.     12            );
 1595.     12            break;
 1596.   2389
 1597.   2389// PR-378 - Relax warning "function_in_loop".
 1598.   2389//
 1599.   2389//         case "function_in_loop":
 1600.   2389//             mm = `Don't create functions within a loop.`;
 1601.   2389//             break;
 1602.   2389
 1603.   2389// PR-390 - Add numeric-separator check.
 1604.   2389
 1605.      8        case "illegal_num_separator":
 1606.      8            mm = `Illegal numeric separator '_' at column ${warning.column}.`;
 1607.      8            break;
 1608.      1        case "infix_in":
 1609.      1            mm = (
 1610.      1                `Unexpected 'in'. Compare with undefined,` +
 1611.      1                ` or use Object.hasOwn() instead.`
 1612.      1            );
 1613.      1            break;
 1614.      2        case "label_a":
 1615.      2            mm = `'${a}' is a statement label.`;
 1616.      2            break;
 1617.      1        case "misplaced_a":
 1618.      1            mm = `Place '${a}' at the outermost level.`;
 1619.      1            break;
 1620.      2        case "misplaced_directive_a":
 1621.      2            mm = `Place the '/*${a}*/' directive before the first statement.`;
 1622.      2            break;
 1623.      6        case "missing_await_statement":
 1624.      6            mm = `Expected await statement in async function.`;
 1625.      6            break;
 1626.      2        case "missing_m":
 1627.      2            mm = `Expected 'm' flag on a multiline regular expression.`;
 1628.      2            break;
 1629.      4        case "naked_block":
 1630.      4            mm = `Naked block.`;
 1631.      4            break;
 1632.      3        case "nested_comment":
 1633.      3            mm = `Nested comment.`;
 1634.      3            break;
 1635.      3        case "not_label_a":
 1636.      3            mm = `'${a}' is not a label.`;
 1637.      3            break;
 1638.      3        case "number_isNaN":
 1639.      3            mm = `Use Number.isNaN function to compare with NaN.`;
 1640.      3            break;
 1641.     27        case "redefinition_a_b":
 1642.     27            mm = `Redefinition of '${a}' from line ${b}.`;
 1643.     27            break;
 1644.      1        case "redefinition_global_a_b":
 1645.      1            mm = `Redefinition of global ${a} variable '${b}'.`;
 1646.      1            break;
 1647.      6        case "required_a_optional_b":
 1648.      6            mm = `Required parameter '${a}' after optional parameter '${b}'.`;
 1649.      6            break;
 1650.      1        case "reserved_a":
 1651.      1            mm = `Reserved name '${a}'.`;
 1652.      1            break;
 1653.      1        case "subscript_a":
 1654.      1            mm = `['${a}'] is better written in dot notation.`;
 1655.      1            break;
 1656.     29        case "temporal_dead_zone_a":
 1657.     29            mm = `'${a}' was used before it was defined.`;
 1658.     29            break;
 1659.     22        case "todo_comment":
 1660.     22            mm = `Unexpected TODO comment.`;
 1661.     22            break;
 1662.     26        case "too_long":
 1663.     26            mm = `Line is longer than 80 characters.`;
 1664.     26            break;
 1665.      4        case "too_many_digits":
 1666.      4            mm = `Too many digits.`;
 1667.      4            break;
 1668.      3        case "unassigned_var_a":
 1669.      3            mm = `Unassigned variable '${a}'.`;
 1670.      3            break;
 1671.      4        case "unclosed_comment":
 1672.      4            mm = `Unclosed comment.`;
 1673.      4            break;
 1674.      3        case "unclosed_disable":
 1675.      3            mm = (
 1676.      3                `Directive '/*jslint-disable*/' was not closed` +
 1677.      3                ` with '/*jslint-enable*/'.`
 1678.      3            );
 1679.      3            break;
 1680.      5        case "unclosed_mega":
 1681.      5            mm = `Unclosed mega literal.`;
 1682.      5            break;
 1683.      2        case "unclosed_string":
 1684.      2            mm = `Unclosed string.`;
 1685.      2            break;
 1686.    221        case "undeclared_a":
 1687.    221            mm = `Undeclared '${a}'.`;
 1688.    221            break;
 1689.    380        case "unexpected_a":
 1690.    380            mm = `Unexpected '${a}'.`;
 1691.    380            break;
 1692.      9        case "unexpected_a_after_b":
 1693.      9            mm = `Unexpected '${a}' after '${b}'.`;
 1694.      9            break;
 1695.      4        case "unexpected_a_before_b":
 1696.      4            mm = `Unexpected '${a}' before '${b}'.`;
 1697.      4            break;
 1698.     81        case "unexpected_at_top_level_a":
 1699.     81            mm = `Expected '${a}' to be in a function.`;
 1700.     81            break;
 1701.      2        case "unexpected_char_a":
 1702.      2            mm = `Unexpected character '${a}'.`;
 1703.      2            break;
 1704.      3        case "unexpected_comment":
 1705.      3            mm = `Unexpected comment.`;
 1706.      3            break;
 1707.   2389
 1708.   2389// PR-347 - Disable warning "unexpected_directive_a".
 1709.   2389//
 1710.   2389//         case "unexpected_directive_a":
 1711.   2389//             mm = `When using modules, don't use directive '/\u002a${a}'.`;
 1712.   2389//             break;
 1713.   2389
 1714.    221        case "unexpected_expression_a":
 1715.    221            mm = `Unexpected expression '${a}' in statement position.`;
 1716.    221            break;
 1717.      8        case "unexpected_label_a":
 1718.      8            mm = `Unexpected label '${a}'.`;
 1719.      8            break;
 1720.      6        case "unexpected_parens":
 1721.      6            mm = `Don't wrap function literals in parens.`;
 1722.      6            break;
 1723.     27        case "unexpected_space_a_b":
 1724.     27            mm = `Unexpected space between '${a}' and '${b}'.`;
 1725.     27            break;
 1726.      2        case "unexpected_statement_a":
 1727.      2            mm = `Unexpected statement '${a}' in expression position.`;
 1728.      2            break;
 1729.      8        case "unexpected_trailing_space":
 1730.      8            mm = `Unexpected trailing space.`;
 1731.      8            break;
 1732.      1        case "unexpected_typeof_a":
 1733.      1            mm = (
 1734.      1                `Unexpected 'typeof'. Use '===' to compare directly with ${a}.`
 1735.      1            );
 1736.      1            break;
 1737.      1        case "unopened_enable":
 1738.      1            mm = (
 1739.      1                `Directive '/*jslint-enable*/' was not opened` +
 1740.      1                ` with '/*jslint-disable*/'.`
 1741.      1            );
 1742.      1            break;
 1743.      1        case "unreachable_a":
 1744.      1            mm = `Unreachable '${a}'.`;
 1745.      1            break;
 1746.     36        case "unregistered_property_a":
 1747.     36            mm = `Unregistered property name '${a}'.`;
 1748.     36            break;
 1749.     28        case "unused_a":
 1750.     28            mm = `Unused '${a}'.`;
 1751.     28            break;
 1752.      3        case "use_double":
 1753.      3            mm = `Use double quotes, not single quotes.`;
 1754.      3            break;
 1755.   2389
 1756.   2389// PR-386 - Fix issue #382 - Make fart-related warnings more readable.
 1757.   2389
 1758.      7        case "use_function_not_fart":
 1759.      7            mm = (
 1760.      7                `Use 'function (...)', not '(...) =>' when arrow functions` +
 1761.      7                ` become too complex.`
 1762.      7            );
 1763.      7            break;
 1764.      9        case "use_open":
 1765.      9            mm = (
 1766.      9                `Wrap a ternary expression in parens,` +
 1767.      9                ` with a line break after the left paren.`
 1768.      9            );
 1769.      9            break;
 1770.      3        case "use_spaces":
 1771.      3            mm = `Use spaces, not tabs.`;
 1772.      3            break;
 1773.     21        case "var_on_top_a_b":
 1774.     21            mm = `Move ${a} declaration to top of ${b} or script.`;
 1775.     21            break;
 1776.      2        case "var_switch":
 1777.      2            mm = `Don't declare variables in a switch.`;
 1778.      2            break;
 1779.     25        case "weird_condition_a":
 1780.     25            mm = `Weird condition '${a}'.`;
 1781.     25            break;
 1782.      5        case "weird_expression_a":
 1783.      5            mm = `Weird expression '${a}'.`;
 1784.      5            break;
 1785.      9        case "weird_loop":
 1786.      9            mm = `Weird loop.`;
 1787.      9            break;
 1788.     10        case "weird_property_a":
 1789.     10            mm = `Weird property name '${a}'.`;
 1790.     10            break;
 1791.      9        case "weird_relation_a":
 1792.      9            mm = `Weird relation '${a}'.`;
 1793.      9            break;
 1794.   2389
 1795.   2389// PR-386 - Fix issue #382 - Make fart-related warnings more readable.
 1796.   2389
 1797.      3        case "wrap_fart_parameter":
 1798.      3            mm = `Wrap the parameter before '=>' in parens.`;
 1799.      3            break;
 1800.      2        case "wrap_immediate":
 1801.      2            mm = (
 1802.      2                `Wrap an immediate function invocation in parentheses to` +
 1803.      2                ` assist the reader in understanding that the expression is` +
 1804.      2                ` the result of a function, and not the function itself.`
 1805.      2            );
 1806.      2            break;
 1807.     18        case "wrap_regexp":
 1808.     18            mm = `Wrap this regexp in parens to avoid confusion.`;
 1809.     18            break;
 1810.     15        case "wrap_subexpression_a_b":
 1811.     15            mm = `Wrap the '${a}' subexpression beside '${b}' in parens.`;
 1812.     15            break;
 1813.      2        default:
 1814.      2            jslint_assert(undefined, `unknown_warning_code=${code}`);
 1815.   2387        }
 1816.   2387
 1817.   2387// Validate mm.
 1818.   2387
 1819.   2387        jslint_assert(mm, code);
 1820.   2387        warning.message = mm;
 1821.   2387
 1822.   2387// PR-242 - Include stack_trace for jslint to debug itself for errors.
 1823.   2387
 1824.   2387        if (option_dict.trace) {
 1825.   2217            warning.stack_trace = new Error().stack;
 1826.   2387        }
 1827.   2387        if (warning.directive_ignore_line) {
 1828.    109
 1829.    109// test_cause:
 1830.    109// ["0 //jslint-ignore-line", "warn_at", "(live)", "", 0]
 1831.    109
 1832.    109            return warning;
 1833.   2278        }
 1834.   2278        warning_list.push(warning);
 1835.   2278        return warning;
 1836.   2278    }
 1837.   1050
 1838.   1050    try {
 1839.   1050
 1840.   1050// tokenize takes a source and produces from it an array of token objects.
 1841.   1050// JavaScript is notoriously difficult to tokenize because of the horrible
 1842.   1050// interactions between automatic semicolon insertion, regular expression
 1843.   1050// literals, and now megastring literals. JSLint benefits from eliminating
 1844.   1050// automatic semicolon insertion and nested megastring literals, which allows
 1845.   1050// full tokenization to precede parsing.
 1846.   1050
 1847.   1050        option_dict = {
 1848.   1050            ...option_dict
 1849.   1050        };
 1850.   1050        Object.assign(
 1851.   1050            state,
 1852.   1050            {
 1853.   1050                artifact,
 1854.   1050                block_list,
 1855.   1050                block_stack,
 1856.   1050                directive_list,
 1857.   1050                export_dict,
 1858.   1050                function_list,
 1859.   1050                function_stack,
 1860.   1050                global_dict,
 1861.   1050                global_list,
 1862.   1050                import_list,
 1863.   1050                is_equal,
 1864.   1050                is_weird,
 1865.   1050                line_list,
 1866.   1050                mode_json: false,       // true if parsing JSON.
 1867.   1050                mode_module: false,     // true if import or export was used.
 1868.   1050                mode_property: false,   // true if directive /*property*/ is
 1869.   1050                                        // ... used.
 1870.   1050                mode_shebang: false,    // true if #! is seen on the first line.
 1871.   1050                option_dict,
 1872.   1050                property_dict,
 1873.   1050                scope_block_pop,
 1874.   1050                scope_block_push,
 1875.   1050                scope_function_pop,
 1876.   1050                scope_function_push,
 1877.   1050                scope_report_push,
 1878.   1050                source,
 1879.   1050                stop,
 1880.   1050                stop_at,
 1881.   1050                syntax_dict,
 1882.   1050                tenure,
 1883.   1050                token_global,
 1884.   1050                token_list,
 1885.   1050                token_nxt: token_global,
 1886.   1050                warn,
 1887.   1050                warn_at,
 1888.   1050                warning_list
 1889.   1050            }
 1890.   1050        );
 1891.   1050
 1892.   1050// PHASE 1. Split <source> by newlines into <line_list>.
 1893.   1050
 1894.   1050        jslint_phase1_split(state);
 1895.   1050
 1896.   1050// PHASE 2. Lex <line_list> into <token_list>.
 1897.   1050
 1898.   1050        jslint_phase2_lex(state);
 1899.   1050
 1900.   1050// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
 1901.   1050
 1902.   1050        jslint_phase3_parse(state);
 1903.   1050
 1904.   1050// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
 1905.   1050//          recursive traversal. Each node may be processed on the way down
 1906.   1050//          (preaction) and on the way up (postaction).
 1907.   1050
 1908.    861        if (!state.mode_json) {
 1909.    861            jslint_phase4_walk(state);
 1910.    876        }
 1911.    876
 1912.    876// PHASE 5. Check whitespace between tokens in <token_list>.
 1913.    876
 1914.    876        if (
 1915.    876            !state.mode_json &&
 1916.    861            !warning_list.some(function ({
 1917.    861                code
 1918.    861            }) {
 1919.    861                if (mode_autofix) {
 1920.    861
 1921.    861// PR-511 - jslint-autofix - Warning 'too_long' no longer blocks autofix.
 1922.    861
 1923.    861                    return !jslint_autofix_warning_list.includes(code);
 1924.    861                }
 1925.    861                return true;
 1926.    861            })
 1927.    306        ) {
 1928.    306            jslint_phase5_whitage(state);
 1929.    876        }
 1930.    876
 1931.    876// PHASE 6. Autofix whitespace-warnings in <source>, and re-lint the result.
 1932.    876
 1933.    876        if (mode_autofix) {
 1934.     67            autofixed = jslint_phase6_autofix(state) || state.source;
 1935.     67            if (autofixed !== state.source) {
 1936.     67
 1937.     67// Recurse jslint.
 1938.     67
 1939.     67                result_autofix = jslint(
 1940.     67                    autofixed,
 1941.     67                    {
 1942.     67                        ...option_dict,
 1943.     67                        autofix: mode_autofix - 1
 1944.     67                    },
 1945.     67                    global_list
 1946.     67                );
 1947.     67
 1948.     67// A stop in the re-lint can only be the fix's own doing - this pass parsed to
 1949.     67// the end, or phase 6 would have had a non-whitespace warning to block on - so
 1950.     67// discard the fix and report on <source> as-is, unfixed.
 1951.     67
 1952.     67                if (!result_autofix.stop) {
 1953.     67                    return {
 1954.     67                        autofixed,
 1955.     67                        ...result_autofix
 1956.     67                    };
 1957.     67                }
 1958.     67
 1959.     67// Name the discarded fix in this pass's own report, or a fixer defect would
 1960.     67// look exactly like an ordinary blocked file.
 1961.     67
 1962.     67                result_autofix.warnings.forEach(function (warning) {
 1963.     67                    if (warning.mode_stop) {
 1964.     67                        warning_list.push({
 1965.     67                            ...warning,
 1966.     67                            message: (
 1967.     67                                "[autofix discarded - line and column refer" +
 1968.     67                                " to the autofixed text] " + warning.message
 1969.     67                            )
 1970.     67                        });
 1971.     67                    }
 1972.     67                });
 1973.     67            }
 1974.    846        }
 1975.    846        if (option_dict.test_internal_error) {
 1976.      5            jslint_assert(undefined, "test_internal_error");
 1977.    841        }
 1978.    841        if (option_dict.test_unknown_warning_code) {
 1979.      2            warn_at("test_unknown_warning_code", jslint_fudge, 0);
 1980.      2        }
 1981.    181    } catch (err) {
 1982.    181        mode_stop = true;
 1983.    181        err.message = "[JSLint was unable to finish] " + err.message;
 1984.    181        err.mode_stop = true;
 1985.    181        if (err.name !== "JSLintError") {
 1986.    181            err.column = jslint_fudge;
 1987.    181            err.line = jslint_fudge;
 1988.    181            err.line_source = "";
 1989.    181            err.stack_trace = err.stack;
 1990.    181        }
 1991.    181        if (warning_list.indexOf(err) === -1) {
 1992.    181            warning_list.push(err);
 1993.    181        }
 1994.   1020    }
 1995.   1020
 1996.   1020// Sort warning_list by mode_stop first, line, column respectively.
 1997.   1020
 1998.   1696    warning_list.sort(function (aa, bb) {
 1999.   1696        return (
 2000.   1592            Boolean(bb.mode_stop) - Boolean(aa.mode_stop) ||
 2001.   1592            aa.line - bb.line ||
 2002.   1560            aa.column - bb.column
 2003.   1696        );
 2004.   1696
 2005.   1696// Update each warning with formatted_message ready-for-use by jslint_cli.
 2006.   1696
 2007.   1992    }).map(function ({
 2008.   1992        column,
 2009.   1992        line,
 2010.   1992        line_source,
 2011.   1992        message,
 2012.   1992        stack_trace = ""
 2013.   1992    }, ii, list) {
 2014.   1992        list[ii].formatted_message = String(
 2015.   1992            String(ii + 1).padStart(2, " ") +
 2016.   1992            ". \u001b[31m" + message + "\u001b[39m" +
 2017.   1992            " \u001b[90m\/\/ line " + line + ", column " + column +
 2018.   1992            "\u001b[39m\n" +
 2019.   1992            ("    " + line_source.trim()).slice(0, 72) + "\n" +
 2020.   1992            stack_trace
 2021.   1992        ).trimEnd();
 2022.   1992    });
 2023.   1020
 2024.   1020    return {
 2025.   1020        directives: directive_list,
 2026.   1020        edition: jslint_edition,
 2027.   1020        exports: export_dict,
 2028.   1020        froms: import_list,
 2029.   1020        functions: function_list,
 2030.   1020        global: token_global,
 2031.   1020        id: "(JSLint)",
 2032.   1020        json: state.mode_json,
 2033.   1020        lines: line_list,
 2034.   1020        module: state.mode_module === true,
 2035.   1020        ok: warning_list.length === 0 && !mode_stop,
 2036.   1050        option: option_dict,
 2037.   1050        property: property_dict,
 2038.   1050        shebang: (
 2039.   1050            state.mode_shebang
 2040.      2            ? line_list[jslint_fudge].line_source
 2041.   1018            : undefined
 2042.   1050        ),
 2043.   1050        stop: mode_stop,
 2044.   1050        tokens: token_list,
 2045.   1050        tree: state.token_tree,
 2046.   1050        warnings: warning_list
 2047.   1050    };
 2048.   1050}
 2049.     23
 2050.     23// PR-362 - Add API Doc.
 2051.     23
 2052.      1async function jslint_apidoc({
 2053.      1    example_list,
 2054.      1    github_repo,
 2055.      1    module_list,
 2056.      1    package_name,
 2057.      1    pathname,
 2058.      1    version
 2059.      1}) {
 2060.      1
 2061.      1// This function will create API Doc from <module_list>.
 2062.      1
 2063.      1    let elem_ii = 0;
 2064.      1    let html;
 2065.      1
 2066.     26    function elem_create(moduleObj, key, moduleName) {
 2067.     26
 2068.     26// This function will create a sub API Doc from elem <moduleObj>[<key>].
 2069.     26
 2070.     26        let example = "N/A";
 2071.     26        let id = encodeURIComponent("apidoc.elem." + moduleName + "." + key);
 2072.     26        let name;
 2073.     26        let signature;
 2074.     26        let source;
 2075.     26        name = htmlEscape((typeof moduleObj[key]) + " " + key);
 2076.      2        if (typeof moduleObj[key] !== "function") {
 2077.      2            return {
 2078.      2                name,
 2079.      2                signature: (`
 2080.      2<a class="apidocElementLiA" href="#${id}">
 2081.      2${name}
 2082.      2</a>
 2083.      2                `),
 2084.      2                source: (`
 2085.      2<li>
 2086.      2    <h2>
 2087.      2    <a href="#${id}" id="${id}">
 2088.      2    ${name}
 2089.      2    </a>
 2090.      2    </h2>
 2091.      2</li>
 2092.      2                `)
 2093.      2            };
 2094.     24        }
 2095.     24        // init source
 2096.     24        source = htmlEscape(trim_start(moduleObj[key].toString()));
 2097.     24        // init signature
 2098.     24        source = source.replace((
 2099.     24            /(\([\S\s]*?\)) \{/
 2100.     24        ), function (match0, match1) {
 2101.     24            signature = htmlEscape(
 2102.     24                match1
 2103.     24                    .replace((/ *?\/\*[\S\s]*?\*\/ */g), "")
 2104.     24                    .replace((/ *?\/\/.*/g), "")
 2105.     24                    .replace((/\n{2,}/g), "\n")
 2106.     24            );
 2107.     24            return match0;
 2108.     24        });
 2109.     24        // init comment
 2110.     24        source = source.replace((
 2111.     24            /\n(?:\/\/.*?\n)+\n/
 2112.     24        ), "<span class=\"apidocCodeCommentSpan\">$&</span>");
 2113.     24        // init example
 2114.     54        example_list.some(function (example2) {
 2115.     54            example2.replace(
 2116.     54                new RegExp((
 2117.     54                    "((?:\\n.*?){8}(function )?)\\b" +
 2118.     54                    key +
 2119.     54                    "(\\((?:.*?\\n){8})"
 2120.     54                ), "g"),
 2121.    247                function (ignore, header, isDeclaration, footer) {
 2122.    239                    if (!isDeclaration) {
 2123.    239                        example = "..." + trim_start(
 2124.    239                            htmlEscape(header) +
 2125.    239                            "<span class=\"apidocCodeKeywordSpan\">" +
 2126.    239                            htmlEscape(key) +
 2127.    239                            "</span>" +
 2128.    239                            htmlEscape(footer)
 2129.    239                        ).trimEnd() + "\n...";
 2130.    239                    }
 2131.    247                    return "";
 2132.    247                }
 2133.     54            );
 2134.     54            return example !== "N/A";
 2135.     54        });
 2136.     24        if (source.length > 2048) {
 2137.     13            source = source.slice(0, 2048) + "...\n}\n";
 2138.     24        }
 2139.     24        return {
 2140.     24            name,
 2141.     24            signature: (`
 2142.     24<a class="apidocElementLiA" href="#${id}">
 2143.     24${name}<span class="apidocSignatureSpan">${signature}</span>
 2144.     24</a>
 2145.     24            `),
 2146.     24            source: (`
 2147.     24<li>
 2148.     24    <h2>
 2149.     24    <a href="#${id}" id="${id}">
 2150.     24    ${name}<span class="apidocSignatureSpan">${signature}</span>
 2151.     24    </a>
 2152.     24    </h2>
 2153.     24</li>
 2154.     24<li>Description and source-code:<pre class="apidocCodePre">${source}</pre></li>
 2155.     24<li>Example usage:<pre class="apidocCodePre">${example}</pre></li>
 2156.     24            `)
 2157.     24        };
 2158.     24    }
 2159.      1
 2160.    263    function trim_start(str) {
 2161.    263
 2162.    263// This function will normalize whitespace before <str>.
 2163.    263
 2164.    263        let whitespace = "";
 2165.    263        str.trim().replace((
 2166.    263            /^ */gm
 2167.  16476        ), function (match0) {
 2168.   9991            if (whitespace === "" || match0.length < whitespace.length) {
 2169.   9096                whitespace = match0;
 2170.   9096            }
 2171.  16476            return "";
 2172.  16476        });
 2173.    263        str = str.replace(new RegExp("^" + whitespace, "gm"), "");
 2174.    263        return str;
 2175.    263    }
 2176.      1    await moduleFsInit();
 2177.      1
 2178.      1// Html-escape params.
 2179.      1
 2180.      1    github_repo = htmlEscape(github_repo);
 2181.      1    package_name = htmlEscape(package_name);
 2182.      1    version = htmlEscape(version);
 2183.      1
 2184.      1// Init example_list.
 2185.      1
 2186.      3    example_list = await Promise.all(example_list.map(async function (file) {
 2187.      3
 2188.      3// This function will read example from given file.
 2189.      3
 2190.      3        let result = await moduleFs.promises.readFile(file, "utf8");
 2191.      3        result = (
 2192.      3            "\n\n\n\n\n\n\n\n" +
 2193.      3
 2194.      3// bug-workaround - Truncate example to manageable size.
 2195.      3
 2196.      3            result.slice(0, 524288) +
 2197.      3            "\n\n\n\n\n\n\n\n"
 2198.      3        );
 2199.      3        result = result.replace((
 2200.      3            /\r\n?/g
 2201.      3        ), "\n");
 2202.      3        return result;
 2203.      3    }));
 2204.      1
 2205.      1// Init module_list.
 2206.      1
 2207.      1    module_list = await Promise.all(module_list.map(async function ({
 2208.      1        pathname
 2209.      1    }) {
 2210.      1        let moduleName = htmlEscape(JSON.stringify(pathname));
 2211.      1        let moduleObj = await import(pathname);
 2212.      1        if (moduleObj.default) {
 2213.      1            moduleObj = moduleObj.default;
 2214.      1        }
 2215.      1        return {
 2216.     26            elem_list: Object.keys(moduleObj).map(function (key) {
 2217.     26                return elem_create(moduleObj, key, moduleName);
 2218.     75            }).sort(function (aa, bb) {
 2219.     75                return (
 2220.     75                    aa.name < bb.name
 2221.     22                    ? -1
 2222.     53                    : 1
 2223.     75                );
 2224.     26            }).map(function (elem) {
 2225.     26                elem_ii += 1;
 2226.     26
 2227.     26// PR-503 - Fix codeql-warning - Incomplete string escaping or encoding.
 2228.     26
 2229.     26                elem.signature = elem.signature.replace(
 2230.     26                    (/<a[^>]*?>|">/),
 2231.     26                    `$&${elem_ii}. `
 2232.     26                );
 2233.     26                return elem;
 2234.     26            }),
 2235.      1            id: encodeURIComponent("apidoc.module." + moduleName),
 2236.      1            moduleName
 2237.      1        };
 2238.      1    }));
 2239.      1    html = (`
 2240.      1<!DOCTYPE html>
 2241.      1<html lang="en">
 2242.      1<head>
 2243.      1<meta charset="utf-8">
 2244.      1<meta name="viewport" content="width=device-width, initial-scale=1">
 2245.      1<meta name="description" content="${package_name} API Doc">
 2246.      1<title>${package_name} apidoc</title>
 2247.      1<style>
 2248.      1/* jslint utility2:true */
 2249.      1/*csslint*/
 2250.      1body {
 2251.      1    margin: 0;
 2252.      1    padding: 20px;
 2253.      1}
 2254.      1.apidocCodeCommentSpan,
 2255.      1.apidocCodeKeywordSpan {
 2256.      1    background: royalblue;
 2257.      1    color: white;
 2258.      1}
 2259.      1.apidocCodeCommentSpan {
 2260.      1    display: block;
 2261.      1}
 2262.      1.apidocCodePre {
 2263.      1    background: #eef;
 2264.      1    border: 1px solid;
 2265.      1    font-size: 14px;
 2266.      1    overflow-wrap: break-word;
 2267.      1    padding: 5px;
 2268.      1    white-space: pre-wrap;
 2269.      1}
 2270.      1.apidocDiv {
 2271.      1    color: #555;
 2272.      1    font-family: sans-serif;
 2273.      1}
 2274.      1.apidocDiv a[href] {
 2275.      1    color: royalblue;
 2276.      1    text-decoration: none;
 2277.      1}
 2278.      1.apidocDiv a[href]:hover {
 2279.      1    text-decoration: underline;
 2280.      1}
 2281.      1.apidocDiv li a {
 2282.      1    display: inline-block;
 2283.      1    padding: 8px 0;
 2284.      1}
 2285.      1.apidocDiv ul {
 2286.      1    list-style: none;
 2287.      1    padding-left: 20px;
 2288.      1}
 2289.      1.apidocFooterDiv {
 2290.      1    margin-top: 20px;
 2291.      1    text-align: center;
 2292.      1}
 2293.      1.apidocModuleA {
 2294.      1    font-size: 24px;
 2295.      1    font-weight: bold;
 2296.      1}
 2297.      1.apidocSectionDiv {
 2298.      1    border-top: 1px solid;
 2299.      1    margin-top: 20px;
 2300.      1}
 2301.      1.apidocSignatureSpan {
 2302.      1    color: #666;
 2303.      1    white-space: pre-wrap;
 2304.      1}
 2305.      1</style>
 2306.      1</head>
 2307.      1<body>
 2308.      1<div class="apidocDiv">
 2309.      1<h1>API Doc for <a href="${github_repo}">${package_name} (${version})</a></h1>
 2310.      1<div class="apidocSectionDiv">
 2311.      1    <a href="#apidocTableOfContents1" id="apidocTableOfContents1">
 2312.      1        <h1>Table of Contents</h1>
 2313.      1    </a>
 2314.      1    <ul>
 2315.      1    `) + module_list.map(function ({
 2316.      1        elem_list,
 2317.      1        id,
 2318.      1        moduleName
 2319.      1    }) {
 2320.      1        return (
 2321.      1            (`
 2322.      1        <li>
 2323.      1            <a class="apidocModuleA" href="#${id}">Module ${moduleName}</a>
 2324.      1            <ul>
 2325.      1            `) +
 2326.     26            elem_list.map(function ({
 2327.     26                signature
 2328.     26            }) {
 2329.     26                return "<li>\n" + signature + "\n</li>\n";
 2330.     26            }).join("") +
 2331.      1            (`
 2332.      1            </ul>
 2333.      1        </li>
 2334.      1            `)
 2335.      1        );
 2336.      1    }).join("") + (`
 2337.      1    </ul>
 2338.      1</div>
 2339.      1    `) + module_list.map(function ({
 2340.      1        elem_list,
 2341.      1        id,
 2342.      1        moduleName
 2343.      1    }) {
 2344.      1        return (
 2345.      1            (`
 2346.      1<div class="apidocSectionDiv">
 2347.      1    <h1><a href="#${id}" id="${id}">Module ${moduleName}</a></h1>
 2348.      1    <ul>
 2349.      1            `) +
 2350.     26            elem_list.map(function ({
 2351.     26                source
 2352.     26            }) {
 2353.     26                return source;
 2354.     26            }).join("") +
 2355.      1            (`
 2356.      1    </ul>
 2357.      1</div>
 2358.      1            `)
 2359.      1        );
 2360.      1    }).join("") + (`
 2361.      1<div class="apidocFooterDiv">
 2362.      1    [
 2363.      1    This document was created with
 2364.      1    <a href="https://github.com/jslint-org/jslint">JSLint</a>
 2365.      1    ]
 2366.      1</div>
 2367.      1</div>
 2368.      1</body>
 2369.      1</html>
 2370.      1    `);
 2371.      1
 2372.      1// PR-503 - Fix codeql-warning - Polynomial regular expression used on
 2373.      1// uncontrolled data.
 2374.      1
 2375.      1    html = html.trim().replace((/(?<! ) +$/gm), "") + "\n";
 2376.      1    await fsWriteFileWithParents(pathname, html);
 2377.      1}
 2378.     23
 2379. 139865function jslint_assert(condition, message) {
 2380. 139865
 2381. 139865// This function will throw <message> if <condition> is falsy.
 2382. 139865
 2383. 139865    let error;
 2384. 139858    if (condition) {
 2385. 139858        return;
 2386. 139858    }
 2387.      7    error = new Error(
 2388.      7        `This was caused by a bug in JSLint.
 2389.      7Please open an issue with this stack-trace (and possible example-code) at
 2390.      7https://github.com/jslint-org/jslint/issues.
 2391.      7edition = "${jslint_edition}";
 2392.      7${String(message).slice(0, 2000)}`
 2393.      7    );
 2394.      7    switch (message) {
 2395.      7    case "test_internal_error":
 2396.      7    case "unknown_warning_code=test_unknown_warning_code":
 2397.      7        error = {};
 2398.      7        break;
 2399.      7    }
 2400.      7    console.error(error);
 2401.      7    throw error;
 2402.      7}
 2403.     23
 2404.     79async function jslint_cli({
 2405.     79    console_error,
 2406.     79    console_log,
 2407.     79    file,
 2408.     79    import_meta_url,
 2409.     79    mode_cli,
 2410.     79    mode_noop,
 2411.     79    option,
 2412.     79    process_argv,
 2413.     79    process_env,
 2414.     79    process_exit,
 2415.     79    source
 2416.     79}) {
 2417.     79
 2418.     79// This function will run jslint from nodejs-cli.
 2419.     79
 2420.     79    let command;
 2421.     79    let data;
 2422.     79    let exit_code = 0;
 2423.     79    let mode_autofix;
 2424.     79    let mode_report;
 2425.     79    let mode_wrapper_vim;
 2426.     79    let result;
 2427.     79
 2428.     79// PR-509 - Add command jslint_autofix.
 2429.     79
 2430.     14    function autofix_embedded({
 2431.     14        code,
 2432.     14        file,
 2433.     14        mode_conditional,
 2434.     14        option,
 2435.     14        rgx,
 2436.     14        suffix,
 2437.     14        suffix_file
 2438.     14    }) {
 2439.     14
 2440.     14// This function will jslint each embedded block <rgx> matches, and return
 2441.     14// <code> with every autofixed block spliced back between the SAME delimiters
 2442.     14// - or undefined if no block was autofixed. <suffix> is the closing
 2443.     14// delimiter, which the capture deliberately excludes.
 2444.     14//
 2445.     14// A BLOCKED BLOCK IS LEFT AS IT WAS AND THE REST ARE STILL REPAIRED, unlike a
 2446.     14// blocked whole-file, which is not written at all.
 2447.     14
 2448.     31        const code_fixed = code.replace(rgx, function (match0, match1, ii) {
 2449.     31            const result_embedded = jslint_from_file({
 2450.     31                code: match1,
 2451.     31                file: file + suffix_file,
 2452.     31                line_offset: (
 2453.     31                    jslint_fudge +
 2454.     31
 2455.     31// Count line-terminators the way <jslint_rgx_crlf> splits them, without
 2456.     31// materialising every preceding line.
 2457.     31
 2458.     31                    (
 2459.     31                        code
 2460.     31                            .slice(0, ii)
 2461.     31                            .match(new RegExp(jslint_rgx_crlf, "g"))
 2462.     30                            ?.length ||
 2463.      1                        0
 2464.     31                    )
 2465.     31                ),
 2466.     31                mode_conditional,
 2467.     31                option
 2468.     31            });
 2469.     31            if (
 2470.     29                result_embedded === undefined ||
 2471.     29                result_embedded.autofixed === undefined
 2472.     25            ) {
 2473.     25                return match0;
 2474.     25            }
 2475.      6            return (
 2476.      6                match0.slice(
 2477.      6                    0,
 2478.      6                    match0.length - match1.length - suffix.length
 2479.      6                ) +
 2480.      6                result_embedded.autofixed +
 2481.      6                suffix
 2482.      6            );
 2483.      6        });
 2484.     14        return (
 2485.     14            code_fixed === code
 2486.      8            ? undefined
 2487.      6            : code_fixed
 2488.     14        );
 2489.     14    }
 2490.     79
 2491.     70    function jslint_from_file({
 2492.     70        code,
 2493.     70        file,
 2494.     70        line_offset = 0,
 2495.     70        mode_conditional,
 2496.     70        option = empty()
 2497.     70    }) {
 2498.     70
 2499.     70// PR-513 - Pad with the block's OWN terminator. Phase 6 rejoins with the
 2500.     70// first one it sees, so a "\n" pad turned a CRLF block's fixed lines into LF.
 2501.     70
 2502.     70        const line_pad = String(
 2503.     63            jslint_rgx_crlf.exec(code)?.[0] || "\n"
 2504.     70        ).repeat(line_offset);
 2505.     70        let result_from_file;
 2506.     70        if (
 2507.      8            mode_conditional &&
 2508.      8            !(
 2509.      8                /^\/\*jslint\b/m
 2510.      8            ).test(code.slice(0, 65536))
 2511.      2        ) {
 2512.      2            return;
 2513.     68        }
 2514.     68        option = {
 2515.     68            ...option,
 2516.     68            file
 2517.     68        };
 2518.     68        switch ((
 2519.     68            /\.\w+?$|$/m
 2520.     68        ).exec(file)[0]) {
 2521.     68        case ".html":
 2522.      6
 2523.      6// Recursively jslint embedded "<script>\n...\n</script>".
 2524.      6
 2525.      6            return {
 2526.      6                autofixed: autofix_embedded({
 2527.      6                    code,
 2528.      6                    file,
 2529.      6                    option: {
 2530.      6                        browser: true,
 2531.      6                        ...option
 2532.      6                    },
 2533.      6                    rgx: (
 2534.      6                        /^<script\b[^>]*?>(?:\n|\r\n?)([\S\s]*?(?:\n|\r\n?))<\/script>$/gm
 2535.      6                    ),
 2536.      6                    suffix: "</script>",
 2537.      6                    suffix_file: ".<script>.js"
 2538.      6                })
 2539.      6            };
 2540.      4        case ".md":
 2541.      4
 2542.      4// Recursively jslint embedded "node --eval '\n...\n'".
 2543.      4
 2544.      4            return jslint_node_eval({
 2545.      4                code,
 2546.      4                file,
 2547.      4                mode_conditional: true,
 2548.      4                option
 2549.      4            });
 2550.      4        case ".sh":
 2551.      4
 2552.      4// Recursively jslint embedded "node --eval '\n...\n'".
 2553.      4
 2554.      4            return jslint_node_eval({
 2555.      4                code,
 2556.      4                file,
 2557.      4                option
 2558.      4            });
 2559.     54        default:
 2560.     54            result_from_file = jslint(line_pad + code, option);
 2561.     54
 2562.     54// The <line_pad> terminators prefixed above make the warnings absolute, and
 2563.     54// they ride along in <autofixed> too. Strip exactly them back off, so the
 2564.     54// caller splices the block back between its OWN delimiters.
 2565.     54
 2566.     54            if (line_offset > 0 && result_from_file.autofixed !== undefined) {
 2567.     54                result_from_file.autofixed = (
 2568.     54                    result_from_file.autofixed.slice(line_pad.length)
 2569.     54                );
 2570.     54            }
 2571.     54        }
 2572.     54
 2573.     54// Print only first 10 warnings to stderr.
 2574.     54
 2575.     54        if (result_from_file.warnings.length > 0) {
 2576.     10            exit_code = 1;
 2577.     10            console_error(
 2578.     10                mode_wrapper_vim
 2579.     10
 2580.     10// PR-349 - Print warnings in format readable by vim.
 2581.     10
 2582.     10                ? result_from_file.warnings.slice(0, 10).map(function ({
 2583.     10                    column,
 2584.     10                    line,
 2585.     10                    message
 2586.     10                }, ii) {
 2587.     10                    return (
 2588.     10                        file +
 2589.     10                        ":" + ii +
 2590.     10                        ":" + line +
 2591.     10                        ":" + column +
 2592.     10                        ":" + message
 2593.     10                    );
 2594.     10                }).join("\n")
 2595.     10
 2596.     10// Print warnings in format readable by human.
 2597.     10
 2598.     10                : "\u001b[1mjslint " + file + "\u001b[22m\n" +
 2599.     19                result_from_file.warnings.slice(0, 10).map(function ({
 2600.     19                    formatted_message
 2601.     19                }) {
 2602.     19                    return formatted_message;
 2603.     19                }).join("\n")
 2604.     10            );
 2605.     54        }
 2606.     54        return result_from_file;
 2607.     54    }
 2608.     79
 2609.      8    function jslint_node_eval({
 2610.      8        code,
 2611.      8        file,
 2612.      8        mode_conditional,
 2613.      8        option = empty()
 2614.      8    }) {
 2615.      8        return {
 2616.      8            autofixed: autofix_embedded({
 2617.      8                code,
 2618.      8                file,
 2619.      8                mode_conditional,
 2620.      8                option: {
 2621.      8                    beta: Boolean(
 2622.      6                        process_env.JSLINT_BETA &&
 2623.      6                        !(
 2624.      6                            /0|false|null|undefined/
 2625.      6                        ).test(process_env.JSLINT_BETA)
 2626.      8                    ),
 2627.      8                    node: true,
 2628.      8                    ...option
 2629.      8                },
 2630.      8                rgx: (
 2631.      8                    /\bnode\b.*? (?:--eval|-e) '(?:\n|\r\n?)([\S\s]*?(?:\n|\r\n?))'/gm
 2632.      8                ),
 2633.      8                suffix: "'",
 2634.      8                suffix_file: ".<node -e>.js"
 2635.      8            })
 2636.      8        };
 2637.      8    }
 2638.     79
 2639.     79// PR-396 - window.jslint
 2640.     79// Check import.meta.url for directive to export jslint to window-object.
 2641.     79// Useful for ES5-era browser-scripts that rely on window.jslint,
 2642.     79// like CodeMirror.
 2643.     79//
 2644.     79// Example usage:
 2645.     79// <script type="module" src="./jslint.mjs?window_jslint=1"></script>
 2646.     79
 2647.     63    import_meta_url = import_meta_url || jslint_import_meta_url;
 2648.     79    if (
 2649.      4        jslint_rgx_url_search_window_jslint.test(import_meta_url) &&
 2650.      4        (typeof globalThis === "object" && globalThis)
 2651.      4    ) {
 2652.      4        globalThis.jslint = jslint;
 2653.      4    }
 2654.     79
 2655.     79// Feature-detect nodejs.
 2656.     79
 2657.     79    if (!(
 2658.     79        (typeof process === "object" && process) &&
 2659.     79        process.versions &&
 2660.     79        typeof process.versions.node === "string" &&
 2661.     79        !mode_noop
 2662.      1    )) {
 2663.      1        return exit_code;
 2664.     78    }
 2665.     78    console_error = console_error || console.error;
 2666.     78    console_log = console_log || console.log;
 2667.     45    process_argv = process_argv || process.argv;
 2668.     71    process_env = process_env || process.env;
 2669.     47    process_exit = process_exit || process.exit;
 2670.     77    await moduleFsInit();
 2671.     77    if (
 2672.     77        !(
 2673.     77
 2674.     77// Feature-detect nodejs-cli.
 2675.     77
 2676.     77            process.execArgv.indexOf("--eval") === -1 &&
 2677.     77            process.execArgv.indexOf("-e") === -1 &&
 2678.     56            (
 2679.     56                (
 2680.     56                    /[\/|\\]jslint(?:\.[cm]?js)?$/m
 2681.     56                ).test(process_argv[1]) ||
 2682.     56                mode_cli
 2683.     56            ) &&
 2684.     39            (
 2685.     39                moduleUrl.fileURLToPath(import_meta_url) ===
 2686.     39                modulePath.resolve(process_argv[1])
 2687.     39            )
 2688.     44        ) &&
 2689.     44        !mode_cli
 2690.     78    ) {
 2691.     78        return exit_code;
 2692.     78    }
 2693.     78
 2694.     78// init commmand
 2695.     78
 2696.     78    command = String(process_argv[2]).split("=");
 2697.     78    command[1] = command.slice(1).join("=");
 2698.     78
 2699.     78    switch (command[0]) {
 2700.     78
 2701.     78// PR-362 - Add API Doc.
 2702.     78
 2703.     78    case "jslint_apidoc":
 2704.     78        await jslint_apidoc({
 2705.     78            ...JSON.parse(process_argv[3]),
 2706.     78            pathname: command[1]
 2707.     78        });
 2708.     78        return;
 2709.     79
 2710.     79// PR-509 - Add command jslint_autofix.
 2711.     79
 2712.     15    case "jslint_autofix":
 2713.     15        file = command[1];
 2714.     15        mode_autofix = true;
 2715.     15        option = {
 2716.     15            ...option,
 2717.     15            autofix: true
 2718.     15        };
 2719.     15        break;
 2720.     79
 2721.     79// PR-363 - Add command jslint_report.
 2722.     79
 2723.      7    case "jslint_report":
 2724.      7        mode_report = command[1];
 2725.      7        process_argv = process_argv.slice(1);
 2726.      7        break;
 2727.     79
 2728.     79// COMMIT-b26d6df2 - Add command jslint_wrapper_vim.
 2729.     79
 2730.      1    case "jslint_wrapper_vim":
 2731.      1        mode_wrapper_vim = true;
 2732.      1        process_argv = process_argv.slice(1);
 2733.      1        break;
 2734.     79
 2735.     79// PR-364 - Add command v8_coverage_report.
 2736.     79
 2737.      8    case "v8_coverage_report":
 2738.      8        await v8CoverageReportCreate({
 2739.      8            consoleError: console_error,
 2740.      8            coverageDir: command[1],
 2741.      8            processArgv: process_argv.slice(3)
 2742.      8        });
 2743.      8        return;
 2744.     57    }
 2745.     57
 2746.     57// Normalize file relative to process.cwd().
 2747.     57
 2748.     57    process_argv.slice(2).some(function (arg) {
 2749.     57        if (!arg.startsWith("-")) {
 2750.     57            file = file || arg;
 2751.     57            return true;
 2752.     57        }
 2753.     57    });
 2754.     57    if (!file) {
 2755.     57        return;
 2756.     57    }
 2757.     57    file = modulePath.resolve(file) + "/";
 2758.     57    if (file.startsWith(process.cwd() + "/")) {
 2759.     57        file = file.replace(process.cwd() + "/", "").slice(0, -1) || ".";
 2760.     57    }
 2761.     57    file = file.replace((
 2762.     57        /\\/g
 2763.     57    ), "/").replace((
 2764.     57        /\/$/g
 2765.     57    ), "");
 2766.     57    if (source) {
 2767.     57        data = source;
 2768.     57    } else {
 2769.     57
 2770.     57// jslint_cli - jslint directory.
 2771.     57
 2772.     57        try {
 2773.     57            data = await moduleFs.promises.readdir(file, "utf8");
 2774.     57        } catch (ignore) {}
 2775.     57        if (data) {
 2776.     57            await Promise.all(data.map(async function (file2) {
 2777.     57                let code;
 2778.     57                let result_dir;
 2779.     57                let time_start = Date.now();
 2780.     57
 2781.     57// PR-409 - Skip dotfile (e.g. .foo.js) when reading directory.
 2782.     57
 2783.     57                if ((/^\./).test(file2)) {
 2784.     57                    return;
 2785.     57                }
 2786.     57                file2 = file + "/" + file2;
 2787.     57                switch ((/\.\w+?$|$/m).exec(file2)[0]) {
 2788.     57                case ".cjs":
 2789.     57                case ".html":
 2790.     57                case ".js":
 2791.     57                case ".json":
 2792.     57                case ".md":
 2793.     57                case ".mjs":
 2794.     57                case ".sh":
 2795.     57                    break;
 2796.     57                default:
 2797.     57                    return;
 2798.     57                }
 2799.     57                try {
 2800.     57                    code = await moduleFs.promises.readFile(file2, "utf8");
 2801.     57                } catch (ignore) {
 2802.     57                    return;
 2803.     57                }
 2804.     57                if (
 2805.     57                    (/(?:\b|_)(?:lock|min|raw|rollup)(?:\b|_)/).test(file2) ||
 2806.     57                    !(code && code.length < 1048576)
 2807.     57                ) {
 2808.     57                    return;
 2809.     57                }
 2810.     57                result_dir = jslint_from_file({
 2811.     57                    code,
 2812.     57                    file: file2,
 2813.     57                    option
 2814.     57                });
 2815.     57                if (mode_autofix && result_dir.autofixed !== undefined) {
 2816.     57                    await fsWriteFileWithParents(file2, result_dir.autofixed);
 2817.     57                }
 2818.     57                console_error(
 2819.     57                    "jslint - " + (Date.now() - time_start) + "ms - " + file2
 2820.     57                );
 2821.     57            }));
 2822.     57            process_exit(exit_code);
 2823.     57            return exit_code;
 2824.     57        }
 2825.     57
 2826.     57// jslint_cli - jslint file.
 2827.     57
 2828.     57        try {
 2829.     57            data = await moduleFs.promises.readFile(file, "utf8");
 2830.     57        } catch (err) {
 2831.     57            console_error(err);
 2832.     57            exit_code = 1;
 2833.     57            process_exit(exit_code);
 2834.     57            return exit_code;
 2835.     57        }
 2836.     57    }
 2837.     57    result = jslint_from_file({
 2838.     57        code: data,
 2839.     57        file,
 2840.     57        option
 2841.     57    });
 2842.     57    if (mode_autofix && result.autofixed !== undefined) {
 2843.     57        await fsWriteFileWithParents(file, result.autofixed);
 2844.     57    }
 2845.     57    if (mode_report) {
 2846.     57
 2847.     57// A container-file - .html, .md, .sh - lints its embedded blocks one by one
 2848.     57// and returns no single lint-result, so there is nothing to report on.
 2849.     57
 2850.     57        if (result.warnings === undefined) {
 2851.     57            console_error(`jslint_report - ${file} - not javascript file`);
 2852.     57            exit_code = 1;
 2853.     57            process_exit(exit_code);
 2854.     57            return exit_code;
 2855.     57        }
 2856.     57        result = jslint.jslint_report(result);
 2857.     57        result = `<body class="JSLINT_ JSLINT_REPORT_">\n${result}</body>\n`;
 2858.     57        await fsWriteFileWithParents(mode_report, result);
 2859.     57    }
 2860.     57    process_exit(exit_code);
 2861.     57    return exit_code;
 2862.     57}
 2863.     23
 2864.   1050function jslint_phase1_split() {
 2865.   1050
 2866.   1050// PHASE 1. Split <source> by newlines into <line_list>.
 2867.   1050
 2868.   1050    return;
 2869.   1050}
 2870.     23
 2871.   1050function jslint_phase2_lex(state) {
 2872.   1050
 2873.   1050// PHASE 2. Lex <line_list> into <token_list>.
 2874.   1050
 2875.   1050    const {
 2876.   1050        artifact,
 2877.   1050        directive_list,
 2878.   1050        global_dict,
 2879.   1050        global_list,
 2880.   1050        line_list,
 2881.   1050        option_dict,
 2882.   1050        stop,
 2883.   1050        stop_at,
 2884.   1050        tenure,
 2885.   1050        token_global,
 2886.   1050        token_list,
 2887.   1050        warn,
 2888.   1050        warn_at,
 2889.   1050        warning_list
 2890.   1050    } = state;
 2891.   1050    const mode_digits_numeric_separator = 1;
 2892.   1050    const mode_digits_regexp_quantifier = 2;
 2893.   1050    const mode_digits_unicode_escape = 3;
 2894.   1050    const opener_stack = [];    // Stack of opener tokens: (, [, {, ${.
 2895.   1050    let char;                   // The current character being lexed.
 2896.   1050    let column = 0;             // The column number of the next character.
 2897.   1050    let from;                   // The starting column number of the token.
 2898.   1050    let from_mega;              // The starting column of megastring.
 2899.   1050    let line = 0;               // The line number of the next character.
 2900.   1050    let line_disable;           // The starting line of "/*jslint-disable*/".
 2901.   1050    let line_mega;              // The starting line of megastring.
 2902.   1050    let line_source = "";       // The remaining line source string.
 2903.   1050    let line_whole = "";        // The whole line source string.
 2904.   1050    let mode_directive = true;  // true if directives are still allowed.
 2905.   1050    let mode_mega = false;      // true if currently parsing a megastring
 2906.   1050                                // ... literal.
 2907.   1050    let mode_regexp;            // true if regular expression literal seen on
 2908.   1050                                // ... this line.
 2909.   1050    let opener_popped = empty();        // Last token popped from opener_stack.
 2910.   1050    let snippet = "";           // A piece of string.
 2911.   1050    let token_1;                // The first token.
 2912.   1050    let token_prv = token_global;       // The previous token including
 2913.   1050                                        // ... comments.
 2914.   1050    let token_prv_expr = token_global;  // The previous token excluding
 2915.   1050                                        // ... comments.
 2916.   1050
 2917.   1050// Most tokens, including the identifiers, operators, and punctuators, can be
 2918.   1050// found with a regular expression. Regular expressions cannot correctly match
 2919.   1050// regular expression literals, so we will match those the hard way. String
 2920.   1050// literals and number literals can be matched by regular expressions, but they
 2921.   1050// don't provide good warnings. The functions char_after, char_before,
 2922.   1050// read_digits, and char_after_escape help in the parsing of literals.
 2923.   1050
 2924. 248655    function char_after(match) {
 2925. 248655
 2926. 248655// Get the next character from the source line. Remove it from the line_source,
 2927. 248655// and append it to the snippet. Optionally check that the previous character
 2928. 248655// matched an expected value.
 2929. 248655
 2930.   7672        if (match !== undefined && char !== match) {
 2931.     14            return (
 2932.     14                char === ""
 2933.     14
 2934.     14// test_cause:
 2935.     14// ["aa=/", "char_after", "expected_a_after_b", "/", 4]
 2936.     14// ["aa=/(?-", "char_after", "expected_a_after_b", "-", 7]
 2937.     14// ["aa=/[", "char_after", "expected_a_after_b", "[", 5]
 2938.     14
 2939.     14                ? stop_at(
 2940.     14                    "expected_a_after_b",
 2941.     14                    line,
 2942.     14                    column - 1,
 2943.     14                    match,
 2944.     14
 2945.     14// At EOL, <snippet> may have been reset or trimmed, so use <line_list[line]>.
 2946.     14
 2947.     14                    line_list[line].line_source.slice(-1)
 2948.     14                )
 2949.     14
 2950.     14// test_cause:
 2951.     14// ["aa=/aa{/", "char_after", "expected_a_b", "/", 8]
 2952.     14// ["aa=/aa{/;", "char_after", "expected_a_b", "/", 8]
 2953.     14
 2954.     14                : stop_at("expected_a_b", line, column - 1, match, char)
 2955.     14            );
 2956. 248641        }
 2957. 248641        char = line_source.slice(0, 1);
 2958. 248641        snippet += char;
 2959. 248641        column += char.length;
 2960. 248641        line_source = line_source.slice(char.length);
 2961. 248641        return char;
 2962. 248641    }
 2963.   1050
 2964.   4248    function char_after_escape(escape_char_list) {
 2965.   4248
 2966.   4248// Validate char after escape "\\". <escape_char_list> lists the chars this
 2967.   4248// caller may escape beyond the shared '/\`bfnrtu', such as a string's quote, a
 2968.   4248// megastring's '${', or a regexp's metachars.
 2969.   4248
 2970.   4248        char_after("\\");
 2971.   4248        switch (char) {
 2972.    682        case "":
 2973.    682            if (escape_char_list === "${") {
 2974.    682
 2975.    682// A megastring's '\' at end of line continues the line.
 2976.    682
 2977.    682// test_cause:
 2978.    682// ["
 2979.    682// `\
 2980.    682// `
 2981.    682// ", "char_after_escape", "(live)", "", 0]
 2982.    682
 2983.    682                return;
 2984.    682            }
 2985.    682
 2986.    682// test_cause:
 2987.    682// ["\"\\", "char_after_escape", "unclosed_string", "", 2]
 2988.    682
 2989.    682            return stop_at("unclosed_string", line, column - 0);
 2990.    225        case "/":
 2991.    225            return char_after();
 2992.    384        case "\\":
 2993.    384            return char_after();
 2994.     30        case "`":
 2995.     30            return char_after();
 2996.     62        case "b":
 2997.     62            return char_after();
 2998.      7        case "f":
 2999.      7            return char_after();
 3000.   1343        case "n":
 3001.   1343            return char_after();
 3002.    104        case "r":
 3003.    104            return char_after();
 3004.     31        case "t":
 3005.     31
 3006.     31// test_cause:
 3007.     31// ["\"\\/\\\\\\`\\b\\f\\n\\r\\t\"", "char_after_escape", "(live)", "", 0]
 3008.     31// ["`\\/\\\\\\`\\b\\f\\n\\r\\t`", "char_after_escape", "(live)", "", 0]
 3009.     31
 3010.     31            return char_after();
 3011.    412        case "u":
 3012.    412            if (char_after("u") === "{") {
 3013.    412                if (state.mode_json) {
 3014.    412
 3015.    412// test_cause:
 3016.    412// ["[\"\\u{12345}\"]", "char_after_escape", "unexpected_a", "{", 5]
 3017.    412
 3018.    412                    warn_at("unexpected_a", line, column - 1, char);
 3019.    412                }
 3020.    412                read_digits("x", mode_digits_unicode_escape);
 3021.    412                if (char !== "}") {
 3022.    412
 3023.    412// test_cause:
 3024.    412// ["\"\\u{12345\"", "char_after_escape", "expected_a_before_b", "\"", 10]
 3025.    412// ["\"\\u{12345\";", "char_after_escape", "expected_a_before_b", "\"", 10]
 3026.    412// ["\"\\u{12\"", "char_after_escape", "expected_a_before_b", "\"", 7]
 3027.    412// ["`\\u{12345`", "char_after_escape", "expected_a_before_b", "`", 10]
 3028.    412// ["`\\u{12345`;", "char_after_escape", "expected_a_before_b", "`", 10]
 3029.    412// ["`\\u{12`", "char_after_escape", "expected_a_before_b", "`", 7]
 3030.    412
 3031.    412                    warn_at(
 3032.    412                        "expected_a_before_b",
 3033.    412                        line,
 3034.    412                        column - 1,
 3035.    412                        "}",
 3036.    412                        char
 3037.    412                    );
 3038.    412                    return;
 3039.    412                }
 3040.    412                return char_after();
 3041.    412            }
 3042.    412            char_before();
 3043.    412            read_digits("x", mode_digits_unicode_escape);
 3044.    412            return;
 3045.    968        default:
 3046.    968            if (escape_char_list && escape_char_list.indexOf(char) >= 0) {
 3047.    968                return char_after();
 3048.    968            }
 3049.    968
 3050.    968// test_cause:
 3051.    968// ["\"\\0\"", "char_after_escape", "unexpected_a_before_b", "0", 3]
 3052.    968// ["`\\0`", "char_after_escape", "unexpected_a_before_b", "0", 3]
 3053.    968
 3054.    968            warn_at("unexpected_a_before_b", line, column - 1, "\\", char);
 3055.   4248        }
 3056.   4248    }
 3057.   1050
 3058.  11772    function char_before() {
 3059.  11772
 3060.  11772// Back up one character by moving a character from the end of the snippet to
 3061.  11772// the front of the line_source.
 3062.  11772
 3063.  11772        line_source = char + line_source;
 3064.  11772        column -= char.length;
 3065.  11772
 3066.  11772// Remove last character from snippet. At end of line <char> is "" and nothing
 3067.  11772// was consumed, so nothing comes off column or snippet.
 3068.  11772
 3069.  11772        snippet = snippet.slice(0, snippet.length - char.length);
 3070.  11772        return char;
 3071.  11772    }
 3072.   1050
 3073.   9782    function check_numeric_separator(digits, column) {
 3074.   9782
 3075.   9782// This function will check for illegal numeric-separator in <digits>.
 3076.   9782
 3077.   9782        digits.replace((
 3078.   9782            jslint_rgx_numeric_separator_illegal
 3079.      6        ), function (ignore, ii) {
 3080.      6
 3081.      6// test_cause:
 3082.      6// ["0x0_0_", "check_numeric_separator", "illegal_num_separator", "", 6]
 3083.      6// ["0x0_0__0", "check_numeric_separator", "illegal_num_separator", "", 6]
 3084.      6// ["aa=1_2_", "check_numeric_separator", "illegal_num_separator", "", 7]
 3085.      6// ["aa=1_2__3", "check_numeric_separator", "illegal_num_separator", "", 7]
 3086.      6// ["aa=1_2_n", "check_numeric_separator", "illegal_num_separator", "", 7]
 3087.      6
 3088.      6            warn_at("illegal_num_separator", line, column - 0 + ii);
 3089.      6            return "";
 3090.      6        });
 3091.   9782    }
 3092.   1050
 3093.  15676    function lex_comment() {
 3094.  15676        let body;
 3095.  15676        let ii = 0;
 3096.  15676        let jj = 0;
 3097.  15676        let the_comment;
 3098.  15676
 3099.  15676// Create a comment object. Comments are not allowed in JSON text. Comments can
 3100.  15676// include directives and notices of incompletion.
 3101.  15676
 3102.  15676// Create token from comment //....
 3103.  15676
 3104.  15551        if (snippet === "//") {
 3105.  15551            snippet = line_source;
 3106.  15551            line_source = "";
 3107.  15551            the_comment = token_create("(comment)", snippet);
 3108.  15551            if (mode_mega) {
 3109.  15551
 3110.  15551// test_cause:
 3111.  15551// ["`${//}`", "lex_comment", "unexpected_comment", "`", 4]
 3112.  15551
 3113.  15551                warn("unexpected_comment", the_comment, "`");
 3114.  15551            }
 3115.  15551
 3116.  15551// Create token from comment /*...*/.
 3117.  15551
 3118.  15551        } else {
 3119.    125            snippet = [];
 3120.    125            if (line_source[0] === "/") {
 3121.    125
 3122.    125// test_cause:
 3123.    125// ["/*/", "lex_comment", "unexpected_a", "/", 3]
 3124.    125// ["/*/*", "lex_comment", "unexpected_a", "/", 3]
 3125.    125
 3126.    125                warn_at("unexpected_a", line, column - 0, "/");
 3127.    125            }
 3128.    125
 3129.    125// Lex/loop through each line until "*/".
 3130.    125
 3131.   1873            while (true) {
 3132.   1873                // jslint_rgx_star_slash
 3133.   1873                ii = line_source.indexOf("*/");
 3134.   1873                if (ii >= 0) {
 3135.   1873                    break;
 3136.   1873                }
 3137.   1873                // jslint_rgx_slash_star
 3138.   1873                ii = line_source.indexOf("/*");
 3139.   1873                if (ii >= 0) {
 3140.   1873
 3141.   1873// test_cause:
 3142.   1873// ["/*/*", "lex_comment", "nested_comment", "", 3]
 3143.   1873
 3144.   1873                    warn_at("nested_comment", line, column - 0 + ii);
 3145.   1873                }
 3146.   1873                snippet.push(line_source);
 3147.   1873                line_source = read_line();
 3148.   1873                if (line_source === undefined) {
 3149.   1873
 3150.   1873// test_cause:
 3151.   1873// ["/*", "lex_comment", "unclosed_comment", "", 2]
 3152.   1873
 3153.   1873                    return stop_at("unclosed_comment", line, column - 0);
 3154.   1873                }
 3155.   1873            }
 3156.    125            jj = line_source.slice(0, ii).search(
 3157.    125                jslint_rgx_slash_star_or_slash
 3158.    125            );
 3159.    125            if (jj >= 0) {
 3160.    125
 3161.    125// test_cause:
 3162.    125// ["/*/**/", "lex_comment", "nested_comment", "", 3]
 3163.    125
 3164.    125                warn_at("nested_comment", line, column - 0 + jj);
 3165.    125            }
 3166.    125            snippet.push(line_source.slice(0, ii));
 3167.    125            snippet = snippet.join(" ");
 3168.    125            column += ii + 2;
 3169.    125            line_source = line_source.slice(ii + 2);
 3170.    125            the_comment = token_create("(comment)", snippet);
 3171.  15672        }
 3172.  15672
 3173.  15672// Uncompleted work comment.
 3174.  15672
 3175.  15672        if (!option_dict.devel && jslint_rgx_todo.test(snippet)) {
 3176.     22
 3177.     22// test_cause:
 3178.     22// [" //todo", "lex_comment", "todo_comment", "(comment)", 2] //jslint-ignore-line
 3179.     22// ["//todo", "lex_comment", "todo_comment", "(comment)", 1] //jslint-ignore-line
 3180.     22
 3181.     22            warn("todo_comment", the_comment);
 3182.  15672        }
 3183.  15672
 3184.  15672// Lex directives in comment.
 3185.  15672
 3186.  15672        snippet.replace(jslint_rgx_directive, function (
 3187.  15672            ignore,
 3188.  15672            match1,
 3189.  15672            match2
 3190.  15672        ) {
 3191.  15672            the_comment.directive = match1;
 3192.  15672            body = match2;
 3193.  15672        });
 3194.  15672        if (the_comment.directive === undefined) {
 3195.  15578            return the_comment;
 3196.  15578        }
 3197.     94        directive_list.push(the_comment);
 3198.     94        if (!mode_directive) {
 3199.      2
 3200.      2// test_cause:
 3201.      2// ["0; /*global aa*/", "lex_comment", "misplaced_directive_a", "global", 4]
 3202.      2// ["0\n/*global aa*/", "lex_comment", "misplaced_directive_a", "global", 1]
 3203.      2
 3204.      2            warn_at("misplaced_directive_a", line, from, the_comment.directive);
 3205.      2            return the_comment;
 3206.     92        }
 3207.     92
 3208.     92// lex_directive();
 3209.     92// JSLint recognizes three directives that can be encoded in comments. This
 3210.     92// function processes one item, and calls itself recursively to process the
 3211.     92// next one.
 3212.     92
 3213.     92// Lex/loop through each directive in /*...*/
 3214.     92
 3215.     92        ii = 0;
 3216.   2034        body.replace(jslint_rgx_directive_part, function (
 3217.   2034            match0,
 3218.   2034            key,
 3219.   2034            value,
 3220.   2034            jj
 3221.   2034        ) {
 3222.     92            if (ii !== jj) {
 3223.     92
 3224.     92// test_cause:
 3225.     92// [" /*jslint !*/", "lex_comment", "bad_directive_a", "!", 2]
 3226.     92// ["/*jslint !*/", "lex_comment", "bad_directive_a", "!", 1]
 3227.     92
 3228.     92                warn("bad_directive_a", the_comment, body.slice(ii));
 3229.     92            }
 3230.     92            if (match0 === "") {
 3231.     92                return "";
 3232.   1942            }
 3233.   1942            ii += match0.length;
 3234.   1942            switch (the_comment.directive) {
 3235.   1942            case "global":
 3236.     92                if (value) {
 3237.     92
 3238.     92// test_cause:
 3239.     92// [" /*global aa:false*/", "lex_comment", "bad_option_a", "aa:false", 2]
 3240.     92// ["/*global aa:false*/", "lex_comment", "bad_option_a", "aa:false", 1]
 3241.     92
 3242.     92                    warn("bad_option_a", the_comment, key + ":" + value);
 3243.     92                }
 3244.     92                global_dict[key] = "user-defined";
 3245.     92
 3246.     92// PR-347 - Disable warning "unexpected_directive_a".
 3247.     92//
 3248.     92//                 state.mode_module = the_comment;
 3249.     92
 3250.     92                break;
 3251.    118            case "jslint":
 3252.    118                if (!option_set_item(key, value !== "false")) {
 3253.    118
 3254.    118// test_cause:
 3255.    118// ["/*jslint undefined*/", "lex_comment", "bad_option_a", "undefined", 1]
 3256.    118
 3257.    118                    warn("bad_option_a", the_comment, key);
 3258.    118                }
 3259.    118                break;
 3260.   1815            case "property":
 3261.   1815                state.mode_property = true;
 3262.   1815                tenure[key] = true;
 3263.   1815                break;
 3264.   1942            }
 3265.   1942            return "";
 3266.   1942        });
 3267.     92        return the_comment;
 3268.     92    }
 3269.   1050
 3270.    930    function lex_megastring() {
 3271.    930        const warning_list_untagged = [];
 3272.    930        let id;
 3273.    930        let ii;
 3274.    930        let match;
 3275.    930
 3276.    930// The token is a megastring. We don't allow any kind of mega nesting.
 3277.    930
 3278.      2        if (mode_mega) {
 3279.      2
 3280.      2// test_cause:
 3281.      2// ["`${`", "lex_megastring", "expected_a_b", "`", 4]
 3282.      2// ["`${`;", "lex_megastring", "expected_a_b", "`", 4]
 3283.      2
 3284.      2            return stop_at("expected_a_b", line, column - 1, "}", "`");
 3285.    928        }
 3286.    928        from_mega = from;
 3287.    928        line_mega = line;
 3288.    928        mode_mega = true;
 3289.    928        snippet = "";
 3290.    928
 3291.    928// Parsing a mega literal is tricky. First create a ` token.
 3292.    928
 3293.    928        token_create("`").warning_list_untagged = warning_list_untagged;
 3294.    928        from += 1;
 3295.    928
 3296.    928// Then loop, building up a string, possibly from many lines, until seeing
 3297.    928// the end of file, a closing `, or a ${ indicting an expression within the
 3298.    928// string.
 3299.    928
 3300.   7283        while (true) {
 3301.   7283            match = line_source.match(jslint_rgx_mega) || {
 3302.   7283                "0": "",
 3303.   7283                index: 0
 3304.   7283            };
 3305.   7283            snippet += line_source.slice(0, match.index);
 3306.   7283            column += match.index;
 3307.   7283            line_source = line_source.slice(match.index);
 3308.   7283            match = match[0];
 3309.   7283            switch (match) {
 3310.   7283            case "${":
 3311.   7283
 3312.   7283// if either ` or ${ was found, then the preceding joins the snippet to become
 3313.   7283// a string token.
 3314.   7283
 3315.   7283                token_create("(string)", snippet).quote = "`";
 3316.   7283                snippet = "";
 3317.   7283
 3318.   7283// If ${, then create tokens that will become part of an expression until
 3319.   7283// a } token is made.
 3320.   7283
 3321.   7283                column += 2;
 3322.   7283                line_source = line_source.slice(2);
 3323.   7283                token_create("${");
 3324.   7283
 3325.   7283// Lex/loop through each token inside megastring-expression `${...}`.
 3326.   7283
 3327.   7283                while (true) {
 3328.   7283                    id = lex_token().id;
 3329.   7283                    if (id === "{") {
 3330.   7283
 3331.   7283// test_cause:
 3332.   7283// ["`${{", "lex_megastring", "expected_a_b", "{", 4]
 3333.   7283
 3334.   7283                        return stop_at(
 3335.   7283                            "expected_a_b",
 3336.   7283                            line,
 3337.   7283                            column - 1,
 3338.   7283                            "}",
 3339.   7283                            "{"
 3340.   7283                        );
 3341.   7283                    }
 3342.   7283                    if (id === "}") {
 3343.   7283                        break;
 3344.   7283                    }
 3345.   7283                }
 3346.   7283                break;
 3347.   7283            case "\\":
 3348.   7283
 3349.   7283// PR-513 - Check the escape with <char_after_escape>, as a string does, but
 3350.   7283// move its warnings to <warning_list_untagged>, since a tagged-megastring may
 3351.   7283// hold any escape. '$' and '{' escape '${'. Push back the char it leaves in
 3352.   7283// <char>, which may be the closing '`'.
 3353.   7283
 3354.   7283                ii = warning_list.length;
 3355.   7283                char_after();
 3356.   7283                char_after_escape("${");
 3357.   7283                char_before();
 3358.   7283                warning_list_untagged.push(...warning_list.splice(ii));
 3359.   7283                break;
 3360.   7283            case "`":
 3361.   7283
 3362.   7283// if either ` or ${ was found, then the preceding joins the snippet to become
 3363.   7283// a string token.
 3364.   7283
 3365.   7283                token_create("(string)", snippet).quote = "`";
 3366.   7283                snippet = "";
 3367.   7283
 3368.   7283// Terminate megastring with `.
 3369.   7283
 3370.   7283                column += 1;
 3371.   7283                line_source = line_source.slice(1);
 3372.   7283                mode_mega = false;
 3373.   7283                return token_create("`");
 3374.   7283            default:
 3375.   7283
 3376.   7283// If neither ` nor ${ is seen, then the whole line joins the snippet.
 3377.   7283
 3378.   7283                snippet += line_source + "\n";
 3379.   7283                if (read_line() === undefined) {
 3380.   7283
 3381.   7283// test_cause:
 3382.   7283// [" `0", "lex_megastring", "unclosed_mega", "", 2]
 3383.   7283// ["`", "lex_megastring", "unclosed_mega", "", 1]
 3384.   7283
 3385.   7283                    return stop_at("unclosed_mega", line_mega, from_mega);
 3386.   7283                }
 3387.   7283            }
 3388.   7283        }
 3389.    930    }
 3390.   1050
 3391.   9697    function lex_number() {
 3392.   9697        let prefix = snippet;
 3393.   9697
 3394.   9697// PR-390 - Add numeric-separator check.
 3395.   9697
 3396.   9697        check_numeric_separator(prefix, column - prefix.length);
 3397.   9697        char_after();
 3398.   3381        switch (prefix === "0" && char.toLowerCase()) {
 3399.      6        case "b":
 3400.     12        case "o":
 3401.     42        case "x":
 3402.     42
 3403.     42// An uppercase radix prefix '0B', '0O' or '0X' is valid, so warn and read the
 3404.     42// digits as for its lowercase form.
 3405.     42
 3406.     42            if (char !== char.toLowerCase()) {
 3407.     42
 3408.     42// test_cause:
 3409.     42// ["aa=0B1", "lex_number", "expected_a_b", "B", 5]
 3410.     42// ["aa=0O7", "lex_number", "expected_a_b", "O", 5]
 3411.     42// ["aa=0X1", "lex_number", "expected_a_b", "X", 5]
 3412.     42
 3413.     42                warn_at(
 3414.     42                    "expected_a_b",
 3415.     42                    line,
 3416.     42                    column - 1,
 3417.     42                    char.toLowerCase(),
 3418.     42                    char
 3419.     42                );
 3420.     42            }
 3421.     42
 3422.     42// test_cause:
 3423.     42// ["aa=0b1", "lex_number", "(live)", "", 0]
 3424.     42// ["aa=0o7", "lex_number", "(live)", "", 0]
 3425.     42// ["aa=0x1", "lex_number", "(live)", "", 0]
 3426.     42
 3427.     42            read_digits(char.toLowerCase(), mode_digits_numeric_separator);
 3428.     42
 3429.     42// PR-351 - Ignore BigInt suffix 'n'.
 3430.     42
 3431.     42            if (char === "n") {
 3432.     42
 3433.     42// test_cause:
 3434.     42// ["aa=0x1fn", "lex_number", "(live)", "", 0]
 3435.     42
 3436.     42                char_after("n");
 3437.     42            }
 3438.     42            break;
 3439.   9655        default:
 3440.   9655            if (char === ".") {
 3441.   9655                read_digits("d", mode_digits_numeric_separator);
 3442.   9655            }
 3443.   9655            if (char === "E" || char === "e") {
 3444.   9655
 3445.   9655// test_cause:
 3446.   9655// ["aa=1e+5", "lex_number", "(live)", "", 0]
 3447.   9655// ["aa=1e5", "lex_number", "(live)", "", 0]
 3448.   9655
 3449.   9655                char_after(char);
 3450.   9655                if (char !== "+" && char !== "-") {
 3451.   9655
 3452.   9655// test_cause:
 3453.   9655// ["aa=1e5", "lex_number", "(live)", "", 0]
 3454.   9655
 3455.   9655                    char_before();
 3456.   9655                }
 3457.   9655                read_digits("d", mode_digits_numeric_separator);
 3458.   9655            }
 3459.   9697        }
 3460.   9697
 3461.   9697// If the next character after a number is a digit or letter, then something
 3462.   9697// unexpected is going on.
 3463.   9697
 3464.   9697        if (
 3465.   1823            (char >= "0" && char <= "9") ||
 3466.   9695            (char >= "a" && char <= "z") ||
 3467.   9695            (char >= "A" && char <= "Z")
 3468.      2        ) {
 3469.      2
 3470.      2// test_cause:
 3471.      2// [" 0a", "lex_number", "unexpected_a_after_b", "0", 3]
 3472.      2// [" 0a;", "lex_number", "unexpected_a_after_b", "0", 3]
 3473.      2
 3474.      2            return stop_at(
 3475.      2                "unexpected_a_after_b",
 3476.      2                line,
 3477.      2                column - 1,
 3478.      2                snippet.slice(-1),
 3479.      2                snippet.slice(0, -1)
 3480.      2            );
 3481.   9695        }
 3482.   9695        char_before();
 3483.   9695        return token_create("(number)", snippet);
 3484.   9695    }
 3485.   1050
 3486.    633    function lex_regexp() {
 3487.    633
 3488.    633// Regexp
 3489.    633// Lex a regular expression literal.
 3490.    633
 3491.    633        let flag;
 3492.    633        let mode_regexp_multiline;
 3493.    633        let result;
 3494.    633        let value;
 3495.    633        mode_regexp = true;
 3496.    633
 3497.    242        function lex_regexp_bracketed() {
 3498.    242            let mode_regexp_range;
 3499.    242
 3500.    242// RegExp
 3501.    242// Match a class.
 3502.    242
 3503.    242            char_after("[");
 3504.     56            if (char === "^") {
 3505.     56                char_after("^");
 3506.     56            }
 3507.    994            while (true) {
 3508.    994
 3509.    994// RegExp
 3510.    994// Match a character in a character class.
 3511.    994
 3512.    994                switch (char) {
 3513.    994                case "":
 3514.    994                case "]":
 3515.    994
 3516.    994// test_cause:
 3517.    994// ["aa=/[", "lex_regexp_bracketed", "(live)", "", 0]
 3518.    994// ["aa=/[]/", "lex_regexp_bracketed", "(live)", "", 0]
 3519.    994
 3520.    994                    if (mode_regexp_range) {
 3521.    994
 3522.    994// test_cause:
 3523.    994// ["aa=/[0-]/", "lex_regexp_bracketed", "unexpected_a", "-", 7]
 3524.    994
 3525.    994                        warn_at("unexpected_a", line, column - 2, "-");
 3526.    994                    }
 3527.    994                    return char_after("]");
 3528.    994
 3529.    994// PR-362 - Relax regexp-warning against using <space>.
 3530.    994//
 3531.    994//                 case " ":
 3532.    994//
 3533.    994// // test_cause:
 3534.    994// // ["aa=/[ ]/", "lex_regexp_bracketed", "expected_a_b", " ", 6]
 3535.    994//
 3536.    994//                     warn_at("expected_a_b", line, column, "\\u0020", " ");
 3537.    994//                     break;
 3538.    994
 3539.    994                case "-":
 3540.    994                case "/":
 3541.    994                case "[":
 3542.    994                case "^":
 3543.    994
 3544.    994// test_cause:
 3545.    994// ["aa=/[-]/", "lex_regexp_bracketed", "expected_a_before_b", "-", 6]
 3546.    994// ["aa=/[.^]/", "lex_regexp_bracketed", "expected_a_before_b", "^", 7]
 3547.    994// ["aa=/[/", "lex_regexp_bracketed", "expected_a_before_b", "/", 6]
 3548.    994// ["aa=/[\\\\/]/", "lex_regexp_bracketed", "expected_a_before_b", "/", 8]
 3549.    994// ["aa=/[\\\\[]/", "lex_regexp_bracketed", "expected_a_before_b", "[", 8]
 3550.    994
 3551.    994                    warn_at(
 3552.    994                        "expected_a_before_b",
 3553.    994                        line,
 3554.    994                        column - 1,
 3555.    994                        "\\",
 3556.    994                        char
 3557.    994                    );
 3558.    994                    break;
 3559.    994                case "\\":
 3560.    994                    char_after_escape("BbDdSsWw-[]^");
 3561.    994                    char_before();
 3562.    994                    break;
 3563.    994                case "`":
 3564.    994                    if (mode_mega) {
 3565.    994
 3566.    994// test_cause:
 3567.    994// ["`${/[`]/}`", "lex_regexp_bracketed", "unexpected_a", "`", 6]
 3568.    994
 3569.    994                        warn_at("unexpected_a", line, column - 1, "`");
 3570.    994                    }
 3571.    994                    break;
 3572.    994                }
 3573.    994                char_after();
 3574.    994                mode_regexp_range = false;
 3575.    994                if (char === "-") {
 3576.    994
 3577.    994// RegExp
 3578.    994// Match a range of subclasses.
 3579.    994
 3580.    994                    mode_regexp_range = true;
 3581.    994                    char_after("-");
 3582.    994                }
 3583.    994            }
 3584.    242        }
 3585.    633
 3586.    883        function lex_regexp_group() {
 3587.    883
 3588.    883// RegExp
 3589.    883// Lex sequence of characters in regexp.
 3590.    883
 3591.    883            let modifier_seen = "";
 3592.    883            switch (char) {
 3593.      2            case "":
 3594.      2
 3595.      2// test_cause:
 3596.      2// ["/ /", "lex_regexp_group", "expected_regexp_factor_a", "", 3]
 3597.      2
 3598.      2                warn_at("expected_regexp_factor_a", line, column - 0, char);
 3599.      2                break;
 3600.      2            case ")":
 3601.      2
 3602.      2// test_cause:
 3603.      2// ["aa=/)", "lex_regexp_group", "expected_regexp_factor_a", ")", 5]
 3604.      2// ["aa=/);", "lex_regexp_group", "expected_regexp_factor_a", ")", 5]
 3605.      2
 3606.      2                warn_at("expected_regexp_factor_a", line, column - 1, char);
 3607.      2                break;
 3608.      1            case "]":
 3609.      1
 3610.      1// test_cause:
 3611.      1// ["aa=/]", "lex_regexp_group", "expected_regexp_factor_a", "]", 5]
 3612.      1
 3613.      1                warn_at("expected_regexp_factor_a", line, column - 1, char);
 3614.      1                break;
 3615.    883            }
 3616.   6440            while (true) {
 3617.   6440                switch (char) {
 3618.   6440                case "":
 3619.   6440                case ")":
 3620.   6440                case "/":
 3621.   6440                case "]":
 3622.   6440                    return;
 3623.   6440
 3624.   6440// PR-362 - Relax regexp-warning against using <space>.
 3625.   6440//
 3626.   6440//                 case " ":
 3627.   6440//
 3628.   6440// // test_cause:
 3629.   6440// // ["aa=/ /", "lex_regexp_group", "expected_a_b", " ", 5]
 3630.   6440//
 3631.   6440//                     warn_at("expected_a_b", line, column, "\\s", " ");
 3632.   6440//                     char_after();
 3633.   6440//                     break;
 3634.   6440
 3635.   6440                case "$":
 3636.   6440                    if (line_source[0] !== "/") {
 3637.   6440                        mode_regexp_multiline = true;
 3638.   6440                    }
 3639.   6440                    char_after();
 3640.   6440                    break;
 3641.   6440                case "(":
 3642.   6440
 3643.   6440// RegExp
 3644.   6440// Match a group that starts with left paren.
 3645.   6440
 3646.   6440                    char_after("(");
 3647.   6440                    switch (char) {
 3648.   6440                    case ":":
 3649.   6440
 3650.   6440// test_cause:
 3651.   6440// ["aa=/(:)/", "lex_regexp_group", "expected_a_before_b", ":", 6]
 3652.   6440
 3653.   6440                        warn_at(
 3654.   6440                            "expected_a_before_b",
 3655.   6440                            line,
 3656.   6440                            column - 1,
 3657.   6440                            "?",
 3658.   6440                            ":"
 3659.   6440                        );
 3660.   6440                        break;
 3661.   6440                    case "?":
 3662.   6440                        char_after("?");
 3663.   6440                        switch (char) {
 3664.   6440
 3665.   6440// ES1999-feature Negative lookahead assertion.
 3666.   6440
 3667.   6440                        case "!":
 3668.   6440
 3669.   6440// PR-437 - Add grammar for regexp-named-capture-group.
 3670.   6440
 3671.   6440                        case "<":
 3672.   6440
 3673.   6440// ES1999-feature Positive lookahead assertion.
 3674.   6440
 3675.   6440                        case "=":
 3676.   6440                            char_after();
 3677.   6440                            break;
 3678.   6440
 3679.   6440// PR-499 - Add ES2025-feature RegExp Modifiers.
 3680.   6440
 3681.   6440                        case "-":
 3682.   6440                        case "i":
 3683.   6440                        case "m":
 3684.   6440                        case "s":
 3685.   6440                            modifier_seen = char;
 3686.   6440                            char_after();
 3687.   6440                            while (true) {
 3688.   6440
 3689.   6440// A lone "-" adds and removes nothing, which v8 rejects - unlike "(?i-:".
 3690.   6440
 3691.   6440                                if (char === ":" && modifier_seen !== "-") {
 3692.   6440                                    char_after();
 3693.   6440                                    break;
 3694.   6440                                }
 3695.   6440                                switch (char) {
 3696.   6440                                case "-":
 3697.   6440                                case "i":
 3698.   6440                                case "m":
 3699.   6440                                case "s":
 3700.   6440                                    if (modifier_seen.includes(char)) {
 3701.   6440
 3702.   6440// test_cause:
 3703.   6440// ["aa=/(?--:x)/", "lex_regexp_group", "unexpected_a_after_b", "(?-", 8]
 3704.   6440// ["aa=/(?ii:x)/", "lex_regexp_group", "unexpected_a_after_b", "(?i", 8]
 3705.   6440
 3706.   6440                                        warn_at(
 3707.   6440                                            "unexpected_a_after_b",
 3708.   6440                                            line,
 3709.   6440                                            column - 1,
 3710.   6440                                            snippet.slice(-1),
 3711.   6440                                            snippet.slice(0, -1)
 3712.   6440                                        );
 3713.   6440                                    }
 3714.   6440                                    modifier_seen += char;
 3715.   6440                                    char_after();
 3716.   6440                                    break;
 3717.   6440                                default:
 3718.   6440
 3719.   6440// End of line inside (?flags - report the missing ":" the way char_after does.
 3720.   6440
 3721.   6440                                    if (char === "") {
 3722.   6440                                        return char_after(":");
 3723.   6440                                    }
 3724.   6440
 3725.   6440// test_cause:
 3726.   6440// ["aa=/(?-.", "lex_regexp_group", "unexpected_a_after_b", "(?-", 8]
 3727.   6440// ["aa=/(?-.)/", "lex_regexp_group", "unexpected_a_after_b", "(?-", 8]
 3728.   6440// ["aa=/(?-:x)/", "lex_regexp_group", "unexpected_a_after_b", "(?-", 8]
 3729.   6440
 3730.   6440                                    return stop_at(
 3731.   6440                                        "unexpected_a_after_b",
 3732.   6440                                        line,
 3733.   6440                                        column - 1,
 3734.   6440                                        snippet.slice(-1),
 3735.   6440                                        snippet.slice(0, -1)
 3736.   6440                                    );
 3737.   6440                                }
 3738.   6440                            }
 3739.   6440                            break;
 3740.   6440                        default:
 3741.   6440                            char_after(":");
 3742.   6440                        }
 3743.   6440                        break;
 3744.   6440                    }
 3745.   6440
 3746.   6440// RegExp
 3747.   6440// Recurse lex_regexp_group.
 3748.   6440
 3749.   6440                    lex_regexp_group();
 3750.   6440                    char_after(")");
 3751.   6440                    break;
 3752.   6440                case "*":
 3753.   6440                case "+":
 3754.   6440                case "?":
 3755.   6440                case "{":
 3756.   6440                case "}":
 3757.   6440
 3758.   6440// test_cause:
 3759.   6440// ["aa=/+/", "lex_regexp_group", "expected_a_before_b", "+", 5]
 3760.   6440// ["aa=/.**/", "lex_regexp_group", "expected_a_before_b", "*", 7]
 3761.   6440// ["aa=/?/", "lex_regexp_group", "expected_a_before_b", "?", 5]
 3762.   6440// ["aa=/{/", "lex_regexp_group", "expected_a_before_b", "{", 5]
 3763.   6440// ["aa=/}/", "lex_regexp_group", "expected_a_before_b", "}", 5]
 3764.   6440
 3765.   6440                    warn_at(
 3766.   6440                        "expected_a_before_b",
 3767.   6440                        line, column - 1,
 3768.   6440                        "\\",
 3769.   6440                        char
 3770.   6440                    );
 3771.   6440                    char_after();
 3772.   6440                    break;
 3773.   6440                case "[":
 3774.   6440                    lex_regexp_bracketed();
 3775.   6440                    break;
 3776.   6440                case "\\":
 3777.   6440
 3778.   6440// test_cause:
 3779.   6440// ["aa=/\\/", "lex_regexp_group", "(live)", "", 0]
 3780.   6440
 3781.   6440// PR-437 - Add grammar for regexp-named-backreference.
 3782.   6440
 3783.   6440                    char_after_escape("BbDdSsWw^${}[]():=!.|*+?k");
 3784.   6440                    break;
 3785.   6440                case "^":
 3786.   6440                    if (snippet !== "^") {
 3787.   6440                        mode_regexp_multiline = true;
 3788.   6440                    }
 3789.   6440                    char_after();
 3790.   6440                    break;
 3791.   6440                case "`":
 3792.   6440                    if (mode_mega) {
 3793.   6440
 3794.   6440// test_cause:
 3795.   6440// ["`${/`/}`", "lex_regexp_group", "unexpected_a", "`", 5]
 3796.   6440
 3797.   6440                        warn_at("unexpected_a", line, column - 1, "`");
 3798.   6440                    }
 3799.   6440                    char_after();
 3800.   6440                    break;
 3801.   6440                default:
 3802.   6440                    char_after();
 3803.   6440                }
 3804.   6440
 3805.   6440// RegExp
 3806.   6440// Match an optional quantifier.
 3807.   6440
 3808.   6440                switch (char) {
 3809.   6440                case "*":
 3810.   6440                case "+":
 3811.   6440                    if (char_after(char) === "?") {
 3812.   6440
 3813.   6440// test_cause:
 3814.   6440// ["aa=/.*?/", "lex_regexp_group", "(live)", "", 0]
 3815.   6440// ["aa=/.+?/", "lex_regexp_group", "(live)", "", 0]
 3816.   6440
 3817.   6440                        char_after("?");
 3818.   6440                    }
 3819.   6440                    break;
 3820.   6440                case "?":
 3821.   6440                    if (char_after("?") === "?") {
 3822.   6440
 3823.   6440// test_cause:
 3824.   6440// ["aa=/.??/", "lex_regexp_group", "unexpected_a", "?", 7]
 3825.   6440
 3826.   6440                        warn_at("unexpected_a", line, column - 1, char);
 3827.   6440                        char_after("?");
 3828.   6440                    }
 3829.   6440                    break;
 3830.   6440                case "{":
 3831.   6440                    read_digits("d", mode_digits_regexp_quantifier);
 3832.   6440                    if (char_after("}") === "?") {
 3833.   6440
 3834.   6440// test_cause:
 3835.   6440// ["aa=/.{0}?/", "lex_regexp_group", "unexpected_a", "?", 9]
 3836.   6440
 3837.   6440                        warn_at("unexpected_a", line, column - 1, char);
 3838.   6440                        char_after("?");
 3839.   6440                    }
 3840.   6440                    break;
 3841.   6440                }
 3842.   6440            }
 3843.    883        }
 3844.    633
 3845.    633// RegExp
 3846.    633// Scan the regexp literal. Give a warning if the first character is = because
 3847.    633// /= looks like a division assignment operator.
 3848.    633
 3849.    633        snippet = "";
 3850.    633        char_after();
 3851.      1        if (char === "=") {
 3852.      1
 3853.      1// test_cause:
 3854.      1// ["aa=/=/", "lex_regexp", "expected_a_before_b", "=", 5]
 3855.      1
 3856.      1            warn_at("expected_a_before_b", line, column - 1, "\\", "=");
 3857.      1        }
 3858.    633        lex_regexp_group();
 3859.    633
 3860.    633// RegExp
 3861.    633// Remove last character from snippet.
 3862.    633
 3863.    633        snippet = snippet.slice(0, -1);
 3864.    633
 3865.    633// RegExp
 3866.    633// Make sure there is a closing slash.
 3867.    633
 3868.    633        value = snippet;
 3869.    633        char_after("/");
 3870.    633
 3871.    633// RegExp
 3872.    633// Create flag.
 3873.    633
 3874.    633        flag = empty();
 3875.    633        while (
 3876.    633
 3877.    633// Regexp
 3878.    633// char is a letter.
 3879.    633
 3880.    616            (char >= "a" && char <= "z\uffff") ||
 3881.    616            (char >= "A" && char <= "Z\uffff")
 3882.    512        ) {
 3883.    512
 3884.    512// RegExp
 3885.    512// Process dangling flag letters.
 3886.    512
 3887.    512            switch (!flag[char] && char) {
 3888.    512
 3889.    512// PR-499 - Add ES2022-feature RegExp Match Indices.
 3890.    512
 3891.    512            case "d":
 3892.    512
 3893.    512// test_cause:
 3894.    512// ["aa=/./d", "lex_regexp", "(live)", "", 0]
 3895.    512
 3896.    512                break;
 3897.    512            case "g":
 3898.    512                break;
 3899.    512            case "i":
 3900.    512                break;
 3901.    512            case "m":
 3902.    512                break;
 3903.    512
 3904.    512// PR-499 - Add ES2018-feature s (dotall) flag for regular expressions.
 3905.    512
 3906.    512            case "s":
 3907.    512
 3908.    512// test_cause:
 3909.    512// ["aa=/./s", "lex_regexp", "(live)", "", 0]
 3910.    512
 3911.    512                break;
 3912.    512            case "u":
 3913.    512                if (
 3914.    512                    flag.v //jslint-ignore-line
 3915.    512                ) {
 3916.    512
 3917.    512// test_cause:
 3918.    512// ["aa=/./vu", "lex_regexp", "unexpected_a", "u", 8]
 3919.    512// ["aa=/./vu;", "lex_regexp", "unexpected_a", "u", 8]
 3920.    512
 3921.    512                    warn_at("unexpected_a", line, column - 1, char);
 3922.    512                }
 3923.    512                break;
 3924.    512
 3925.    512// PR-499 - Add ES2024-feature RegExp v flag with set-notation + str-properties.
 3926.    512
 3927.    512            case "v":
 3928.    512
 3929.    512// "u" and "v" select different grammars, so v8 rejects the pair.
 3930.    512
 3931.    512                if (
 3932.    512                    flag.u //jslint-ignore-line
 3933.    512                ) {
 3934.    512
 3935.    512// test_cause:
 3936.    512// ["aa=/./uv", "lex_regexp", "unexpected_a", "v", 8]
 3937.    512
 3938.    512                    warn_at("unexpected_a", line, column - 1, char);
 3939.    512                }
 3940.    512                break;
 3941.    512            case "y":
 3942.    512
 3943.    512// test_cause:
 3944.    512// ["aa=/./gimuy", "lex_regexp", "(live)", "", 0]
 3945.    512
 3946.    512                break;
 3947.    512            default:
 3948.    512
 3949.    512// test_cause:
 3950.    512// ["aa=/./gg", "lex_regexp", "unexpected_a", "g", 8]
 3951.    512// ["aa=/./z", "lex_regexp", "unexpected_a", "z", 7]
 3952.    512
 3953.    512                warn_at("unexpected_a", line, column - 1, char);
 3954.    512            }
 3955.    512            flag[char] = true;
 3956.    512            char_after();
 3957.    616        }
 3958.    616        char_before();
 3959.    616        if (char === "/" || char === "*") {
 3960.      1
 3961.      1// test_cause:
 3962.      1// ["aa=/.//", "lex_regexp", "unexpected_a", "/", 7]
 3963.      1
 3964.      1            return stop_at("unexpected_a", line, column - 0, char);
 3965.    615        }
 3966.    615        result = token_create("(regexp)", char);
 3967.    615        result.flag = flag;
 3968.    615        result.value = value;
 3969.    615        if (
 3970.    615            mode_regexp_multiline &&
 3971.     46            !flag.m //jslint-ignore-line
 3972.      2        ) {
 3973.      2
 3974.      2// test_cause:
 3975.      2// ["aa=/$^/", "lex_regexp", "missing_m", "", 7]
 3976.      2// ["aa=/$^/;", "lex_regexp", "missing_m", "", 7]
 3977.      2
 3978.      2            warn_at("missing_m", line, column - 1);
 3979.    615        }
 3980.    615        return result;
 3981.    615    }
 3982.   1050
 3983.    655    function lex_slash_or_regexp() {
 3984.    655
 3985.    655// The / can be a division operator or the beginning of a regular expression
 3986.    655// literal. It is not possible to know which without doing a complete parse.
 3987.    655// We want to complete the tokenization before we begin to parse, so we will
 3988.    655// estimate. This estimator can fail in some cases. For example, it cannot
 3989.    655// know if "}" is ending a block or ending an object literal, so it can
 3990.    655// behave incorrectly in that case; it is not meaningful to divide an
 3991.    655// object, so it is likely that we can get away with it. We avoided the worst
 3992.    655// cases by eliminating automatic semicolon insertion.
 3993.    655
 3994.    655        let the_token;
 3995.    655        switch (
 3996.     24            token_prv_expr.identifier &&
 3997.     24            !token_prv_expr.dot &&
 3998.     22            token_prv_expr.id
 3999.    655        ) {
 4000.      1        case "case":
 4001.      2        case "delete":
 4002.      3        case "in":
 4003.      4        case "instanceof":
 4004.      5        case "new":
 4005.      6        case "typeof":
 4006.      7        case "void":
 4007.      8        case "yield":
 4008.      8            the_token = lex_regexp();
 4009.      8
 4010.      8// test_cause:
 4011.      8// ["case /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
 4012.      8// ["delete /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
 4013.      8// ["in /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 4]
 4014.      8// ["instanceof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 12]
 4015.      8// ["new /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 5]
 4016.      8// ["typeof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
 4017.      8// ["void /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
 4018.      8// ["yield /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 7]
 4019.      8
 4020.      8            return stop("unexpected_a", the_token);
 4021.      2        case "return":
 4022.      2
 4023.      2// test_cause:
 4024.      2// ["function aa(){return /./;}", "lex_slash_or_regexp", "(live)", "", 0]
 4025.      2
 4026.      2            return lex_regexp();
 4027.    645        }
 4028.    645        switch (!token_prv_expr.identifier && token_prv_expr.id.slice(-1)) {
 4029.      1        case "!":
 4030.      2        case "%":
 4031.      4        case "&":
 4032.      5        case "*":
 4033.      6        case "+":
 4034.      7        case "-":
 4035.      9        case "/":
 4036.     10        case ";":
 4037.     11        case "<":
 4038.     12        case ">":
 4039.     13        case "^":
 4040.     16        case "{":
 4041.     17        case "|":
 4042.     18        case "}":
 4043.     19        case "~":
 4044.     19            the_token = lex_regexp();
 4045.     19
 4046.     19// test_cause:
 4047.     19// ["!/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4048.     19// ["%/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4049.     19// ["&/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4050.     19// ["+/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4051.     19// ["-/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4052.     19// ["0 * /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
 4053.     19// ["0 / /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
 4054.     19// [";/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4055.     19// ["</./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4056.     19// [">/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4057.     19// ["^/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4058.     19// ["{/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4059.     19// ["|/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4060.     19// ["}/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4061.     19// ["~/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
 4062.     19
 4063.     19            warn("wrap_regexp", the_token);
 4064.     19            return the_token;
 4065.    534        case "(":
 4066.    550        case ",":
 4067.    551        case ":":
 4068.    602        case "=":
 4069.    603        case "?":
 4070.    604        case "[":
 4071.    604
 4072.    604// test_cause:
 4073.    604// ["(/./", "lex_slash_or_regexp", "(live)", "", 0]
 4074.    604// [",/./", "lex_slash_or_regexp", "(live)", "", 0]
 4075.    604// [":/./", "lex_slash_or_regexp", "(live)", "", 0]
 4076.    604// ["=/./", "lex_slash_or_regexp", "(live)", "", 0]
 4077.    604// ["?/./", "lex_slash_or_regexp", "(live)", "", 0]
 4078.    604// ["aa[/./", "lex_slash_or_regexp", "(live)", "", 0]
 4079.    604
 4080.    604            return lex_regexp();
 4081.     22        }
 4082.     22        if (line_source[0] === "=") {
 4083.      3            snippet = "/=";
 4084.      3            column += 1;
 4085.      3            line_source = line_source.slice(1);
 4086.      3
 4087.      3// test_cause:
 4088.      3// ["0/=0", "lex_slash_or_regexp", "unexpected_a", "/=", 2]
 4089.      3
 4090.      3            warn_at("unexpected_a", line, column - 2, "/=");
 4091.     22        }
 4092.     22        return token_create(snippet);
 4093.     22    }
 4094.   1050
 4095.  24695    function lex_string(quote) {
 4096.  24695
 4097.  24695// Create a string token.
 4098.  24695
 4099.  24695        let the_token;
 4100.  24693        if (!option_dict.single && quote === "'") {
 4101.      3
 4102.      3// test_cause:
 4103.      3// [" ''", "lex_string", "use_double", "", 2]
 4104.      3// ["''", "lex_string", "use_double", "", 1]
 4105.      3
 4106.      3            warn_at("use_double", line, column - 1);
 4107.      3        }
 4108.  24695        snippet = "";
 4109.  24695        char_after();
 4110.  24695
 4111.  24695// Lex/loop through each character in "...".
 4112.  24695
 4113. 223136        while (true) {
 4114. 223136            switch (char) {
 4115. 223136            case "":
 4116. 223136
 4117. 223136// test_cause:
 4118. 223136// ["\"", "lex_string", "unclosed_string", "", 1]
 4119. 223136
 4120. 223136                return stop_at("unclosed_string", line, column - 0);
 4121. 223136            case "\\":
 4122. 223136                char_after_escape(quote);
 4123. 223136                break;
 4124. 223136            case "`":
 4125. 223136                if (mode_mega) {
 4126. 223136
 4127. 223136// test_cause:
 4128. 223136// ["`${\"`\"}`", "lex_string", "unexpected_a", "`", 5]
 4129. 223136
 4130. 223136                    warn_at("unexpected_a", line, column - 1, "`");
 4131. 223136                }
 4132. 223136                char_after("`");
 4133. 223136                break;
 4134. 223136            case quote:
 4135. 223136
 4136. 223136// Remove last character from snippet.
 4137. 223136
 4138. 223136                snippet = snippet.slice(0, -1);
 4139. 223136                the_token = token_create("(string)", snippet);
 4140. 223136                the_token.quote = quote;
 4141. 223136                return the_token;
 4142. 223136            default:
 4143. 223136                char_after();
 4144. 223136            }
 4145. 223136        }
 4146.  24695    }
 4147.   1050
 4148. 282479    function lex_token() {
 4149. 282479        let match;
 4150. 282479
 4151. 282479// Lex/loop through each whitespace.
 4152. 282479
 4153. 415959        while (true) {
 4154. 415959
 4155. 415959// Lex/loop through each blank-line.
 4156. 415959
 4157. 415959            while (!line_source) {
 4158. 415959                line_source = read_line();
 4159. 415959                from = 0;
 4160. 415959                if (line_source === undefined) {
 4161. 415959                    return (
 4162. 415959                        mode_mega
 4163. 415959
 4164. 415959// test_cause:
 4165. 415959// [" `${//}`", "lex_token", "unclosed_mega", "", 2]
 4166. 415959// ["`${//}`", "lex_token", "unclosed_mega", "", 1]
 4167. 415959
 4168. 415959                        ? stop_at("unclosed_mega", line_mega, from_mega)
 4169. 415959                        : line_disable !== undefined
 4170. 415959
 4171. 415959// test_cause:
 4172. 415959// ["/*jslint-disable*/", "lex_token", "unclosed_disable", "", 1]
 4173. 415959
 4174. 415959                        ? stop_at("unclosed_disable", line_disable, column - 0)
 4175. 415959                        : token_create("(end)")
 4176. 415959                    );
 4177. 415959                }
 4178. 415959            }
 4179. 415959            from = column;
 4180. 415959            match = line_source.match(jslint_rgx_token);
 4181. 415959
 4182. 415959// match[1] token
 4183. 415959// match[2] whitespace
 4184. 415959// match[3] identifier
 4185. 415959// match[4] number
 4186. 415959// match[5] rest
 4187. 415959
 4188. 415959            if (!match) {
 4189. 415959
 4190. 415959// test_cause:
 4191. 415959// ["#", "lex_token", "unexpected_char_a", "#", 1]
 4192. 415959// ["aa=#0", "lex_token", "unexpected_char_a", "#", 4]
 4193. 415959
 4194. 415959                return stop_at(
 4195. 415959                    "unexpected_char_a",
 4196. 415959                    line,
 4197. 415959                    column - 0,
 4198. 415959                    line_source[0]
 4199. 415959                );
 4200. 415959            }
 4201. 415959            snippet = match[1];
 4202. 415959            column += snippet.length;
 4203. 415959            line_source = line_source.slice(snippet.length);
 4204. 415959            if (!match[2]) {
 4205. 415959                break;
 4206. 415959            }
 4207. 415959        }
 4208. 281462
 4209. 281462// The token is an identifier.
 4210. 281462
 4211. 281462        if (match[3]) {
 4212.  77109            return token_create(snippet, undefined, true);
 4213. 204353        }
 4214. 204353
 4215. 204353// Create token from number.
 4216. 204353
 4217. 204353        if (match[4]) {
 4218.   9697            return lex_number();
 4219. 194656        }
 4220. 194656
 4221. 194656// Create token from string "..." or '...'.
 4222. 194656
 4223. 194656        if (snippet === "\"" || snippet === "'") {
 4224.  24695            return lex_string(snippet);
 4225. 169961        }
 4226. 169961
 4227. 169961// Create token from megastring `...`.
 4228. 169961
 4229. 169961        if (snippet === "`") {
 4230.    930            return lex_megastring();
 4231. 169031        }
 4232. 169031
 4233. 169031// Create token from comment /*...*/ or //....
 4234. 169031
 4235. 169031        if (snippet === "/*" || snippet === "//") {
 4236.  15676            return lex_comment();
 4237. 153355        }
 4238. 153355
 4239. 153355// Create token from slash /.
 4240. 153355
 4241. 153355        if (snippet === "/") {
 4242.    655            return lex_slash_or_regexp();
 4243. 152700        }
 4244. 152700        return token_create(snippet);
 4245. 152700    }
 4246.   1050
 4247.   4146    function option_set_item(key, value) {
 4248.   4146
 4249.   4146// These are the options that are recognized in the option object or that may
 4250.   4146// appear in a /*jslint*/ directive. Most options will have a boolean value,
 4251.   4146// usually true. Some options will also predefine some number of global
 4252.   4146// variables.
 4253.   4146
 4254.   4146        switch (key) {
 4255.    960        case "beta":            // Enable experimental warnings.
 4256.    963        case "bitwise":         // Allow bitwise operator.
 4257.    980        case "browser":         // Assume browser environment.
 4258.    986        case "convert":         // Allow conversion operator.
 4259.    989        case "couch":           // Assume CouchDb environment.
 4260.    996        case "devel":           // Allow console.log() and friends.
 4261.   3096        case "ecma":            // Assume ECMAScript environment.
 4262.   3103        case "eval":            // Allow eval().
 4263.   3106        case "fart":            // Allow complex fat-arrow.
 4264.   3107        case "for":             // Allow for-statement (deprecated).
 4265.   3119        case "getset":          // Allow get() and set().
 4266.   3123        case "indent2":         // Use 2-space indent.
 4267.   3125        case "long":            // Allow long lines.
 4268.   3199        case "node":            // Assume Node.js environment.
 4269.   3204        case "nomen":           // Allow weird property name.
 4270.   3206        case "single":          // Allow single-quote strings.
 4271.   3208        case "subscript":       // Allow identifier in subscript-notation.
 4272.   3213        case "test_internal_error":     // Test jslint's internal-error
 4273.   4146                                        // ... handling-ability.
 4274.   3215        case "test_unknown_warning_code": // Test jslint's unknown-warning-code
 4275.   4146                                        // ... handling-ability.
 4276.   3217        case "this":            // Allow 'this'.
 4277.   3990        case "trace":           // Include jslint stack-trace in warnings.
 4278.   3994        case "unordered":       // Allow unordered cases, params, properties,
 4279.   4146                                // ... variables, and exports.
 4280.   3998        case "variable":        // Allow unordered const and let declarations
 4281.   4146                                // ... not at top of function-scope.
 4282.   4001        case "white":           // Allow messy whitespace.
 4283.   4001            option_dict[key] = value;
 4284.   4001            break;
 4285.   4146
 4286.   4146// PR-404 - Alias "evil" to sub-directive "eval" for backwards-compat.
 4287.   4146
 4288.      3        case "evil":
 4289.      3
 4290.      3// test_cause:
 4291.      3// ["/*jslint evil*/", "option_set_item", "(live)", "", 0]
 4292.      3
 4293.      3            return option_set_item("eval", value);
 4294.   4146
 4295.   4146// PR-404 - Alias "nomen" to sub-directive "name" for backwards-compat.
 4296.   4146
 4297.      3        case "name":
 4298.      3
 4299.      3// test_cause:
 4300.      3// ["/*jslint name*/", "option_set_item", "(live)", "", 0]
 4301.      3
 4302.      3            return option_set_item("nomen", value);
 4303.    139        default:
 4304.    139            return false;
 4305.   4001        }
 4306.   4001
 4307.   4001// Initialize global-variables.
 4308.   4001
 4309.   4001        switch (value && key) {
 4310.     16        case "browser":
 4311.     19        case "couch":
 4312.     26        case "devel":
 4313.   2126        case "ecma":
 4314.   2200        case "node":
 4315.  15400            Object.entries(jslint_global_dict_all).forEach(function ([
 4316.  15400                dict_name, dict
 4317.  15400            ]) {
 4318.  15400                if (
 4319.  11026                    dict_name.startsWith(key) ||
 4320.  11026                    (key === "browser" && dict_name === "node_auto")
 4321.   4390                ) {
 4322. 167133                    Object.entries(dict).forEach(function ([name, is_global]) {
 4323.   7020                        if (dict_name === "node_auto") {
 4324.   7020                            switch (dict_name === "node_auto" && key) {
 4325.   7020                            case "browser":
 4326.   7020                                if (is_global.includes("brow")) {
 4327.   7020                                    global_dict[name] = "browser";
 4328.   7020                                }
 4329.   7020                                break;
 4330.   7020                            case "node":
 4331.   7020                                if (is_global.includes("node")) {
 4332.   7020                                    global_dict[name] = "Node.js";
 4333.   7020                                }
 4334.   7020                                break;
 4335.   7020                            }
 4336. 160113                        } else {
 4337. 160113                            if (is_global) {
 4338. 160113                                global_dict[name] = (
 4339. 160113                                    dict_name.startsWith("browser")
 4340. 160113                                    ? "browser"
 4341. 160113                                    : dict_name.startsWith("couch")
 4342. 160113
 4343. 160113// test_cause:
 4344. 160113// ["/*jslint couch*/", "option_set_item", "(live)", "", 0]
 4345. 160113
 4346. 160113                                    ? "CouchDb"
 4347. 160113                                    : dict_name.startsWith("devel")
 4348. 160113                                    ? "development"
 4349. 160113                                    : dict_name.startsWith("ecma")
 4350. 160113                                    ? "ECMAScript"
 4351. 160113                                    : "Node.js"
 4352. 160113                                );
 4353. 160113                            }
 4354. 160113                        }
 4355. 167133                    });
 4356.   4390                }
 4357.  15400            });
 4358.   2200            break;
 4359.   4001        }
 4360.   4001        return true;
 4361.   4001    }
 4362.   1050
 4363.    541    function read_digits(base, mode) {
 4364.    541        let digits = line_source.match(
 4365.    541            base === "b"
 4366.    541
 4367.    541// test_cause:
 4368.    541// ["aa=0b1", "read_digits", "(live)", "", 0]
 4369.    541
 4370.      6            ? jslint_rgx_digits_bits
 4371.    535            : base === "o"
 4372.    535
 4373.    535// test_cause:
 4374.    535// ["aa=0o7", "read_digits", "(live)", "", 0]
 4375.    535
 4376.    535            ? jslint_rgx_digits_octals
 4377.    535            : base === "x"
 4378.    535            ? jslint_rgx_digits_hexs
 4379.    535            : jslint_rgx_digits_decimals
 4380.    541        )[0];
 4381.    541        if (
 4382.    541            (
 4383.     16                digits.length === 0 &&
 4384.     16                (
 4385.     16                    mode === mode_digits_numeric_separator ||
 4386.     16                    (mode === mode_digits_unicode_escape && char === "{")
 4387.     16                )
 4388.    538            ) ||
 4389.    538            digits[0] === "_"
 4390.      4        ) {
 4391.      4
 4392.      4// test_cause:
 4393.      4// ["0x", "read_digits", "expected_digits_after_a", "0x", 2]
 4394.      4// ["0x_", "read_digits", "expected_digits_after_a", "0x", 2]
 4395.      4// ["\"\\u{}\"", "read_digits", "expected_digits_after_a", "\\u{", 4]
 4396.      4// ["`\\u{}`", "read_digits", "expected_digits_after_a", "\\u{", 4]
 4397.      4
 4398.      4            warn_at("expected_digits_after_a", line, column - 1, snippet);
 4399.      4        }
 4400.    541
 4401.    541// PR-390 - Add numeric-separator check.
 4402.    541
 4403.     85        if (mode === mode_digits_numeric_separator) {
 4404.     85            check_numeric_separator(digits, column);
 4405.    456        } else if (digits.indexOf("_") >= 0) {
 4406.    456
 4407.    456// test_cause:
 4408.    456// ["\"\\u{1_2}\"", "read_digits", "illegal_num_separator", "", 6]
 4409.    456// ["`\\u{1_2}`", "read_digits", "illegal_num_separator", "", 6]
 4410.    456
 4411.    456            warn_at(
 4412.    456                "illegal_num_separator",
 4413.    456                line,
 4414.    456                column + digits.indexOf("_")
 4415.    456            );
 4416.    456        }
 4417.    541        snippet += digits;
 4418.    541        column += digits.length;
 4419.    541        line_source = line_source.slice(digits.length);
 4420.    541        switch (mode) {
 4421.     35        case mode_digits_regexp_quantifier:
 4422.     35            if (digits.length === 0) {
 4423.     35
 4424.     35// test_cause:
 4425.     35// ["aa=/aa{/", "read_digits", "expected_a_before_b", ",", 8]
 4426.     35
 4427.     35                warn_at("expected_a_before_b", line, column - 0, "0", ",");
 4428.     35            }
 4429.     35            if (line_source[0] === ",") {
 4430.     35
 4431.     35// test_cause:
 4432.     35// ["aa=/.{,/", "read_digits", "(live)", "", 0]
 4433.     35
 4434.     35                char_after();
 4435.     35
 4436.     35// Recurse read_digits.
 4437.     35
 4438.     35                read_digits("d", undefined);
 4439.     35                return;
 4440.     35            }
 4441.     35            break;
 4442.    541
 4443.    412        case mode_digits_unicode_escape:
 4444.    412
 4445.    412// PR-513 - Check the code point's value, not its digit count. '\u{10FFFF}' and
 4446.    412// '\u{000041}' are legal. Above 10FFFF a string is a SyntaxError, and a regexp
 4447.    412// without flag 'u' reads '\u{110000}' as 'u' repeated. Both lint on, so warn.
 4448.    412// A megastring's '\u' gets here too. <char> is '{' only for '\u{...}'.
 4449.    412
 4450.    412            if (char !== "{") {
 4451.    412                if (digits.length < 4) {
 4452.    412
 4453.    412// test_cause:
 4454.    412// ["\"\\u0\"", "read_digits", "expected_four_digits", "", 5]
 4455.    412// ["\"\\u0\";", "read_digits", "expected_four_digits", "", 5]
 4456.    412// ["`\\u0`", "read_digits", "expected_four_digits", "", 5]
 4457.    412
 4458.    412                    warn_at("expected_four_digits", line, column - 0);
 4459.    412                }
 4460.    412            } else if (Number.parseInt(digits, 16) > 0x10ffff) {
 4461.    412
 4462.    412// test_cause:
 4463.    412// ["\"\\u{110000}\"", "read_digits", "too_many_digits", "", 11]
 4464.    412// ["`\\u{110000}`", "read_digits", "too_many_digits", "", 11]
 4465.    412// ["aa=/\\u{110000}/", "read_digits", "too_many_digits", "", 14]
 4466.    412
 4467.    412                warn_at("too_many_digits", line, column - 0);
 4468.    412            }
 4469.    412            break;
 4470.    532        }
 4471.    532        char_after();
 4472.    532    }
 4473.   1050
 4474. 121433    function read_line() {
 4475. 121433
 4476. 121433// Put the next line of source in line_source. If the line contains tabs,
 4477. 121433// replace them with spaces and give a warning. Also warn if the line contains
 4478. 121433// unsafe characters or is too damn long.
 4479. 121433
 4480. 121433        if (
 4481. 121429            !option_dict.long &&
 4482. 121429            line_whole.length > 80 &&
 4483.     81            line_disable === undefined &&
 4484.     81            !state.mode_json &&
 4485.     48            token_1 &&
 4486.     48            !mode_regexp
 4487.     26        ) {
 4488.     26
 4489.     26// test_cause:
 4490.     26// ["/////////////////////////////////////////////////////////////////////////////////", "read_line", "too_long", "", 1] //jslint-ignore-line
 4491.     26
 4492.     26            warn_at("too_long", line, 0);
 4493.     26        }
 4494. 121433        column = 0;
 4495. 121433        line += 1;
 4496. 121433        mode_regexp = false;
 4497. 121433        line_source = undefined;
 4498. 121433        line_whole = "";
 4499.   1020        if (line_list[line] === undefined) {
 4500.   1020            return line_source;
 4501. 120413        }
 4502. 120413        line_source = line_list[line].line_source;
 4503. 120413        line_whole = line_source;
 4504. 120413
 4505. 120413// Scan each line for following ignore-directives:
 4506. 120413// "/*jslint-disable*/"
 4507. 120413// "/*jslint-enable*/"
 4508. 120413// "//jslint-ignore-line"
 4509. 120413
 4510. 120413        if (line_source === "/*jslint-disable*/") {
 4511.     10
 4512.     10// test_cause:
 4513.     10// ["/*jslint-disable*/", "read_line", "(live)", "", 0]
 4514.     10
 4515.     10            line_disable = line;
 4516. 120403        } else if (line_source === "/*jslint-enable*/") {
 4517. 120403            if (line_disable === undefined) {
 4518. 120403
 4519. 120403// test_cause:
 4520. 120403// ["/*jslint-enable*/", "read_line", "unopened_enable", "", 1]
 4521. 120403
 4522. 120403                return stop_at("unopened_enable", line, column - 0);
 4523. 120403            }
 4524. 120403            line_disable = undefined;
 4525. 120403        } else if (
 4526. 120403            line_source.endsWith(" //jslint-ignore-line") ||
 4527. 120403            line_source.endsWith(" //jslint-quiet")
 4528. 120403        ) {
 4529. 120403
 4530. 120403// test_cause:
 4531. 120403// ["0 //jslint-ignore-line", "read_line", "(live)", "", 0]
 4532. 120403
 4533. 120403            line_list[line].directive_ignore_line = true;
 4534. 120412        }
 4535. 120412        if (line_disable !== undefined) {
 4536.   1139
 4537.   1139// test_cause:
 4538.   1139// ["
 4539.   1139// /*jslint-disable*/
 4540.   1139// 0
 4541.   1139// ", "read_line", "(live)", "", 0]
 4542.   1139
 4543.   1139            line_source = "";
 4544. 120412        }
 4545. 120412        // jslint_rgx_tab
 4546. 120412        if (line_source.indexOf("\t") >= 0) {
 4547.      3            if (!option_dict.white) {
 4548.      3
 4549.      3// test_cause:
 4550.      3// [" \t0", "read_line", "use_spaces", "", 2]
 4551.      3// ["\t", "read_line", "use_spaces", "", 1]
 4552.      3
 4553.      3                warn_at("use_spaces", line, line_source.indexOf("\t"));
 4554.      3            }
 4555.      3            line_source = line_source.replace(jslint_rgx_tab, " ");
 4556. 120412        }
 4557. 120412        if (!option_dict.white && line_source.endsWith(" ")) {
 4558.      8
 4559.      8// test_cause:
 4560.      8// [" ", "read_line", "unexpected_trailing_space", "", 1]
 4561.      8// ["0 ", "read_line", "unexpected_trailing_space", "", 2]
 4562.      8
 4563.      8            warn_at("unexpected_trailing_space", line, line_source.length - 1);
 4564. 120412        }
 4565. 120412        return line_source;
 4566. 120412    }
 4567.   1050
 4568. 286028    function token_create(id, value, identifier) {
 4569. 286028
 4570. 286028// Create the token object and append it to token_list.
 4571. 286028
 4572. 286028        const the_token = {
 4573. 286028            from,
 4574. 286028            id,
 4575. 286028            identifier: Boolean(identifier),
 4576. 286028            line,
 4577. 286028            nr: token_list.length,
 4578. 286028            thru: column,
 4579. 286028            value
 4580. 286028        };
 4581. 286028        token_list.push(the_token);
 4582. 286028
 4583. 286028// Directives must appear before the first statement.
 4584. 286028
 4585. 270356        if (id !== "(comment)" && id !== ";") {
 4586. 252917            mode_directive = false;
 4587. 252917        }
 4588. 286028
 4589. 286028// If this token is an identifier that touches a preceding number, or
 4590. 286028// a "/", comment, or regular expression literal that touches a preceding
 4591. 286028// comment or regular expression literal, then give a missing space warning.
 4592. 286028// This warning is not suppressed by option_dict.white.
 4593. 286028
 4594. 286028        if (
 4595. 206909            token_prv.line === line &&
 4596. 206909            token_prv.thru === from &&
 4597. 133073            (id === "(comment)" || id === "(regexp)" || id === "/") &&
 4598.    252            (token_prv.id === "(comment)" || token_prv.id === "(regexp)")
 4599.      1        ) {
 4600.      1
 4601.      1// test_cause:
 4602.      1// ["/**//**/", "token_create", "expected_space_a_b", "(comment)", 5]
 4603.      1
 4604.      1            warn(
 4605.      1                "expected_space_a_b",
 4606.      1                the_token,
 4607.      1                artifact(token_prv),
 4608.      1                artifact(the_token)
 4609.      1            );
 4610.      1        }
 4611.  12912        if (token_prv.id === "." && id === "(number)") {
 4612.      5
 4613.      5// test_cause:
 4614.      5// [" .0", "token_create", "expected_a_before_b", ".", 2]
 4615.      5// [".0", "token_create", "expected_a_before_b", ".", 1]
 4616.      5
 4617.      5            warn("expected_a_before_b", token_prv, "0", ".");
 4618.      5        }
 4619.  12912        if (token_prv_expr.id === "." && the_token.identifier) {
 4620.  12906            the_token.dot = true;
 4621.  12906        }
 4622. 286028
 4623. 286028// PR-385 - Bugfix - Fixes issue #382 - failure to detect destructured fart.
 4624. 286028// Farts are now detected by keeping a list of most recent "(" tokens at any
 4625. 286028// given depth. When a "=>" token is encountered, the most recent "(" token at
 4626. 286028// current depth is marked as a fart.
 4627. 286028
 4628. 286028        switch (id) {
 4629. 286028
 4630. 286028// PR-514 - Bugfix - Push '{' and '${', so a ';' in a function-body inside
 4631. 286028// a for-loop-head 'for (const aa of function () {...}())' is not mistaken for
 4632. 286028// a for-loop-semicolon.
 4633. 286028
 4634.    873        case "${":
 4635.  20822        case "(":
 4636.  25087        case "[":
 4637.  36300        case "{":
 4638.  36300            opener_stack.unshift(the_token);
 4639.  36300            break;
 4640.  19950        case ")":
 4641.  24213        case "]":
 4642.  24213
 4643.  24213// PR-503 - Fix jslint crashing before warning about dangling ')' or ']'.
 4644.  24213
 4645.  24213            opener_popped = opener_stack.shift() || empty();
 4646.  24213            if (
 4647.  24213                (id === ")" && opener_popped.id !== "(") ||
 4648.  24213                (id === "]" && opener_popped.id !== "[")
 4649.  24213            ) {
 4650.  24213
 4651.  24213// test_cause:
 4652.  24213// [" );", "token_create", "unexpected_a", ")", 2]
 4653.  24213// [")", "token_create", "unexpected_a", ")", 1]
 4654.  24213// [";(]", "token_create", "unexpected_a", "]", 3]
 4655.  24213// [";[)", "token_create", "unexpected_a", ")", 3]
 4656.  24213// ["]", "token_create", "unexpected_a", "]", 1]
 4657.  24213
 4658.  24213                return stop("unexpected_a", the_token);
 4659.  24213            }
 4660.  24213            break;
 4661.  17439        case ";":
 4662.  17439            if (opener_stack[0]?.for_loop) {
 4663.  17439                opener_stack[0].for_loop.for_semicolon = [
 4664.  17439                    undefined,
 4665.  17439                    undefined,
 4666.  17439                    undefined
 4667.  17439                ];
 4668.  17439            }
 4669.  17439            break;
 4670. 286028
 4671. 286028// PR-503 - Fix jslint unable to continue parsing 'async aa => 0'.
 4672. 286028
 4673.     33        case "=>":
 4674.     33
 4675.     33// PR-511 - Stop on line-break before '=>', which is a SyntaxError.
 4676.     33
 4677.     33            if (token_prv_expr.line !== the_token.line) {
 4678.     33
 4679.     33// test_cause:
 4680.     33// ["()//\n =>0", "token_create", "unexpected_a", "=>", 2]
 4681.     33// ["()\n =>0", "token_create", "unexpected_a", "=>", 2]
 4682.     33// ["aa\n =>0", "token_create", "unexpected_a", "=>", 2]
 4683.     33
 4684.     33                return stop("unexpected_a", the_token);
 4685.     33            }
 4686.     33            if (token_prv_expr.identifier) {
 4687.     33                token_prv_expr.fart = the_token;
 4688.     33            }
 4689.     33            break;
 4690.  12078        case "}":
 4691.  12078            if (opener_stack[0]?.id === "{" || opener_stack[0]?.id === "${") {
 4692.  12078                opener_stack.shift();
 4693.  12078            }
 4694.  12078            break;
 4695. 286020        }
 4696. 286020        switch (token_prv_expr.id + " " + id) {
 4697. 286020        case ") =>":
 4698.     23            opener_popped.fart = the_token;
 4699.     23            break;
 4700.    241        case "] =":
 4701.    241            opener_popped.assignment = the_token;
 4702.    241            break;
 4703. 286028
 4704. 286028// PR-508 - Add ES2018-feature Asynchronous Iteration - for await...of.
 4705. 286028
 4706.      8        case "await (":
 4707.      8            if (token_prv_expr.for_loop) {
 4708.      8                the_token.for_loop = token_prv_expr.for_loop;
 4709.      8                delete token_prv_expr.for_loop;
 4710.      8            }
 4711.      8            break;
 4712.     90        case "for (":
 4713. 286028
 4714. 286028// PR-508 - Add ES2018-feature Asynchronous Iteration - for await...of.
 4715. 286028
 4716.     96        case "for await":
 4717.     96            the_token.for_loop = token_prv_expr;
 4718.     96            break;
 4719. 286020        }
 4720. 286020
 4721. 286020// The previous token is used to detect adjacency problems.
 4722. 286020
 4723. 286020        token_prv = the_token;
 4724. 286020
 4725. 286020// The token_prv_expr token is a previous token that was not a comment.
 4726. 286020// The token_prv_expr token
 4727. 286020// is used to disambiguate "/", which can mean division or regular expression
 4728. 286020// literal.
 4729. 286020
 4730. 286020        if (token_prv.id !== "(comment)") {
 4731. 270348            token_prv_expr = token_prv;
 4732. 286020        }
 4733. 286020        return the_token;
 4734. 286020    }
 4735.   1050
 4736.   1050// Init global_dict and option_dict.
 4737.   1050
 4738.   1050    option_set_item("ecma", true);
 4739.   2972    Object.keys(option_dict).sort().forEach(function (key) {
 4740.   2972        option_set_item(key, option_dict[key] === true);
 4741.   2972    });
 4742.   1050    object_assign_from_list(global_dict, global_list, "user-defined");
 4743.   1050
 4744.   1050// Scan first line for "#!" and ignore it.
 4745.   1050
 4746.      2    if (line_list[jslint_fudge].line_source.startsWith("#!")) {
 4747.      2
 4748.      2// test_cause:
 4749.      2// ["#!/usr/bin/env node", "jslint_phase2_lex", "(live)", "", 0]
 4750.      2
 4751.      2        line += 1;
 4752.      2        state.mode_shebang = true;
 4753.      2    }
 4754.   1050    token_1 = lex_token();
 4755.   1015    state.mode_json = token_1.id === "{" || token_1.id === "[";
 4756.   1050
 4757.   1050// Lex/loop through each token until (end).
 4758.   1050
 4759. 278715    while (true) {
 4760. 278715        if (lex_token().id === "(end)") {
 4761. 278715            break;
 4762. 278715        }
 4763. 278715    }
 4764.   1050}
 4765.     23
 4766.    994function jslint_phase3_parse(state) {
 4767.    994
 4768.    994// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
 4769.    994
 4770.    994// Parsing:
 4771.    994
 4772.    994// Parsing weaves the tokens into an abstract syntax tree. During that process,
 4773.    994// a token may be given any of these properties:
 4774.    994
 4775.    994//      arity       string
 4776.    994//      name        identifier
 4777.    994//      name_alias  identifier
 4778.    994//      expression  expressions
 4779.    994//      block       statements
 4780.    994//      else        statements (else, default, catch)
 4781.    994
 4782.    994// Specialized tokens may have additional properties.
 4783.    994
 4784.    994    const {
 4785.    994        artifact,
 4786.    994        block_stack,
 4787.    994        export_dict,
 4788.    994        function_list,
 4789.    994        function_stack,
 4790.    994        global_dict,
 4791.    994        import_list,
 4792.    994        is_equal,
 4793.    994        line_list,
 4794.    994        option_dict,
 4795.    994        property_dict,
 4796.    994        scope_block_pop,
 4797.    994        scope_block_push,
 4798.    994        scope_function_pop,
 4799.    994        scope_function_push,
 4800.    994        scope_report_push,
 4801.    994        stop,
 4802.    994        syntax_dict,
 4803.    994        tenure,
 4804.    994        token_global,
 4805.    994        token_list,
 4806.    994        warn,
 4807.    994        warn_at,
 4808.    994        warning_list
 4809.    994    } = state;
 4810.    994    let anon = "anonymous";     // The guessed name for anonymous functions.
 4811.    994    let mode_var;               // "var" if using var; "let" if using let.
 4812.    994    let scope_block;            // The current block-scope.
 4813.    994    let scope_function;         // The current function-scope.
 4814.    994    let token_ii = 0;           // The index of the next token in <token_list>.
 4815.    994    let token_now = token_global;       // The current token being examined in
 4816.    994                                        // ... the parse.
 4817.    994    let token_nxt = token_global;       // The next token to be examined in
 4818.    994                                        // ... <token_list>.
 4819.    994    let token_prv = token_global;       // The previous token examined.
 4820.    994
 4821. 270949    function advance(id, match) {
 4822. 270949
 4823. 270949// Produce the next token.
 4824. 270949
 4825. 270949// Attempt to give helpful names to anonymous functions.
 4826. 270949
 4827. 270949        if (
 4828.  77046            token_now.identifier &&
 4829.  77046            token_now.id !== "function" &&
 4830.  74725            token_now.id !== "async"
 4831.  74511        ) {
 4832.  74511
 4833.  74511// PR-516 - Bugfix - A keyword such as 'return' names no function, so reset
 4834.  74511// <anon>, else it would keep an earlier identifier. Keep 'default', the name
 4835.  74511// the spec gives 'export default function () {}', and a property name such as
 4836.  74511// 'catch' in 'aa.catch' or '{catch: ...}', but not 'null' in 'aa ? null : ...'.
 4837.  74511
 4838.  74511            anon = (
 4839.  74511                (
 4840.  74511                    syntax_dict[token_now.id] === undefined ||
 4841.  74511                    token_now.id === "default" ||
 4842.  74511                    token_prv.id === "." ||
 4843.  74511                    token_prv.id === "?." ||
 4844.  74511                    (
 4845.  74511                        token_nxt.id === ":" &&
 4846.  74511                        (token_prv.id === "{" || token_prv.id === ",")
 4847.  74511                    )
 4848.  74511                )
 4849.  74511                ? token_now.id
 4850.  74511                : "anonymous"
 4851.  74511            );
 4852. 196438        } else if (
 4853. 196438            token_now.id === "(string)" &&
 4854. 196438            jslint_rgx_identifier.test(token_now.value)
 4855. 196438        ) {
 4856. 196438            anon = token_now.value;
 4857. 196438        }
 4858. 270949
 4859. 270949// Attempt to match token_nxt with an expected id.
 4860. 270949
 4861. 134217        if (id !== undefined && token_nxt.id !== id) {
 4862.     28            return (
 4863.     28                match === undefined
 4864.     28
 4865.     28// test_cause:
 4866.     28// ["{0:0}", "advance", "expected_a_b", "0", 2]
 4867.     28
 4868.     28                ? stop("expected_a_b", token_nxt, id, artifact())
 4869.     28
 4870.     28// test_cause:
 4871.     28// ["{\"aa\":0", "advance", "expected_a_b_from_c_d", "{", 7]
 4872.     28
 4873.     28                : stop(
 4874.     28                    "expected_a_b_from_c_d",
 4875.     28                    token_nxt,
 4876.     28                    id,
 4877.     28                    artifact(match),
 4878.     28                    match.line,
 4879.     28                    artifact()
 4880.     28                )
 4881.     28            );
 4882. 270921        }
 4883. 270921
 4884. 270921// Promote the tokens, skipping comments.
 4885. 270921
 4886. 270921        token_prv = token_now;
 4887. 270921        token_now = token_nxt;
 4888. 286589        while (true) {
 4889. 286589            token_nxt = token_list[token_ii];
 4890. 286589            state.token_nxt = token_nxt;
 4891. 286589            token_ii += 1;
 4892. 286589            if (token_nxt.id !== "(comment)") {
 4893. 286589                if (token_nxt.id === "(end)") {
 4894. 286589                    token_ii -= 1;
 4895. 286589                }
 4896. 286589                break;
 4897. 286589            }
 4898. 286589            if (state.mode_json) {
 4899. 286589
 4900. 286589// test_cause:
 4901. 286589// ["[//]", "advance", "unexpected_a", "(comment)", 2]
 4902. 286589
 4903. 286589                warn("unexpected_a");
 4904. 286589            }
 4905. 286589        }
 4906. 270949    }
 4907.    994
 4908.  15904    function assignment(id) {
 4909.  15904
 4910.  15904// Create an assignment operator. The one true assignment is different because
 4911.  15904// its left side, when it is a variable, is not treated as an expression.
 4912.  15904// That case is special because that is when a variable gets initialized. The
 4913.  15904// other assignment operators can modify, but they cannot initialize.
 4914.  15904
 4915.  15904        const the_symbol = symbol(id, 20);
 4916.   5338        the_symbol.led_infix = function parse_assignment_led(left) {
 4917.   5338            const the_token = token_now;
 4918.   5338            let right;
 4919.   5338            the_token.arity = "assignment";
 4920.   5338            right = parse_expression(20 - 1);
 4921.   4562            if (id === "=" && left.arity === "variable") {
 4922.   3037                the_token.expression = right;
 4923.   3037                the_token.name_list = [];       // 1. name_list for "aa = ..."
 4924.   3037                name_declare(
 4925.   3037                    undefined,          // scope_declared
 4926.   3037                    "variable",         // role
 4927.   3037                    false,              // readonly
 4928.   3037                    the_token.name_list,        // name_list
 4929.   3037                    left,               // name
 4930.   3037                    false               // assigned
 4931.   3037                );
 4932.   3037            } else {
 4933.   2297                the_token.expression = [left, right];
 4934.   5334            }
 4935.   5334            if (
 4936.   5334                right.arity === "assignment" ||
 4937.   5334                right.arity === "preassign" ||
 4938.   5334                right.arity === "postassign"
 4939.      1            ) {
 4940.      1
 4941.      1// test_cause:
 4942.      1// ["aa=aa++", "parse_assignment_led", "unexpected_a", "++", 6]
 4943.      1
 4944.      1                warn("unexpected_a", right);
 4945.   5334            }
 4946.   5334            check_mutation(left);
 4947.   5334            return the_token;
 4948.   5334        };
 4949.  15904        return the_symbol;
 4950.  15904    }
 4951.    994
 4952.   6478    function block(special) {
 4953.   6478
 4954.   6478// Parse a block, a sequence of statements wrapped in braces.
 4955.   6478//  special "body"      The block is a function body.
 4956.   6478//          "ignore"    No warning on an empty block '{}'.
 4957.   6478//          "naked"     No advance '{'.
 4958.   6478//          undefined   An ordinary block.
 4959.   6478
 4960.   6478        const implicit = (      // No advance '{'. No advance '}'.
 4961.     30            token_nxt.id !== "{" && special !== "body" && special !== "naked"
 4962.   6478        );
 4963.   6478        let parsed_block;
 4964.   6478        let the_block;
 4965.     25        if (implicit) {
 4966.     25
 4967.     25// PR-504 - Add implicit scope_block for:
 4968.     25// - if-else
 4969.     25// - for-loop
 4970.     25// - while-loop
 4971.     25// - do-while
 4972.     25
 4973.     25// test_cause:
 4974.     25// ["do;while(0)", "block", "expected_a", "{", 3]
 4975.     25// ["for(;;);", "block", "expected_a", "{", 8]
 4976.     25// ["if(0);else if(0);else;", "block", "expected_a", "{", 17]
 4977.     25// ["if(0);else if(0);else;", "block", "expected_a", "{", 22]
 4978.     25// ["if(0);else if(0);else;", "block", "expected_a", "{", 6]
 4979.     25// ["while(0);", "block", "expected_a", "{", 9]
 4980.     25
 4981.     25            warn("expected_a", token_nxt, "{");
 4982.     25        }
 4983.   6453        if (!implicit && special !== "naked") {
 4984.   6449            advance("{");
 4985.   6477        }
 4986.   6477        the_block = token_now;
 4987.   6477        the_block.scope_block = true;
 4988.   6477        scope_block = scope_block_push(the_block, true);
 4989.   6477        if (special !== "body") {
 4990.   4139            check_ordered_var(the_block);
 4991.   6477        }
 4992.   6477        the_block.arity = "statement";
 4993.   6477        the_block.function_body = special === "body";
 4994.   6477
 4995.   6477// Top level function bodies may include the "use strict" pragma.
 4996.   6477
 4997.   6477        if (
 4998.   6477            special === "body" &&
 4999.   2338            function_stack.length === 2 &&
 5000.    437            token_nxt.value === "use strict"
 5001.      4        ) {
 5002.      4            token_nxt.statement = true;
 5003.      4            advance("(string)");
 5004.      4            semicolon();
 5005.   6477        }
 5006.   6477        parsed_block = parse_statement_block();
 5007.   6477        the_block.block = parsed_block;
 5008.   6477        if (parsed_block.length === 0) {
 5009.    148            if (!option_dict.devel && special !== "ignore") {
 5010.    148
 5011.    148// test_cause:
 5012.    148// ["function aa(){}", "block", "empty_block", "{", 14]
 5013.    148
 5014.    148                warn("empty_block", the_block);
 5015.    148            }
 5016.    148            the_block.disrupt = false;
 5017.   6326        } else {
 5018.   6326            the_block.disrupt = parsed_block[parsed_block.length - 1].disrupt;
 5019.   6474        }
 5020.   6474        scope_block = scope_block_pop();
 5021.   6474        if (!implicit) {
 5022.   6449            advance("}");
 5023.   6474        }
 5024.   6474        return the_block;
 5025.   6474    }
 5026.    994
 5027.  25785    function check_left(left, right) {
 5028.  25785
 5029.  25785// Warn if the left is not one of these:
 5030.  25785//      ?.
 5031.  25785//      ?:
 5032.  25785//      e()
 5033.  25785//      e.b
 5034.  25785//      e[b]
 5035.  25785//      identifier
 5036.  25785
 5037.  25785        const id = left.id;
 5038.  25785        if (
 5039.   6987            !left.identifier &&
 5040.   6987            (
 5041.   6987                left.arity !== "ternary" ||
 5042.   6987                (
 5043.   6987                    !check_left(left.expression[1]) &&
 5044.   6987                    !check_left(left.expression[2])
 5045.   6987                )
 5046.   6987            ) &&
 5047.   6987            (
 5048.   6987                left.arity !== "binary" ||
 5049.   6987                (id !== "." && id !== "?." && id !== "(" && id !== "[")
 5050.   6987            )
 5051.     16        ) {
 5052.     16            warn("unexpected_a", right || token_nxt);
 5053.     16            return false;
 5054.  25769        }
 5055.  25769        return true;
 5056.  25769    }
 5057.    994
 5058.   5344    function check_mutation(the_thing) {
 5059.   5344
 5060.   5344// The only expressions that may be assigned to are
 5061.   5344//      e.b
 5062.   5344//      e[b]
 5063.   5344//      v
 5064.   5344//      [destructure]
 5065.   5344//      {destructure}
 5066.   5344
 5067.   5344        const the_optional = optional_chain(the_thing);
 5068.   5344        if (
 5069.   1638            the_thing.arity !== "variable" &&
 5070.   1638            the_thing.id !== "." &&
 5071.    221            the_thing.id !== "[" &&
 5072.     10            the_thing.id !== "{"
 5073.     10        ) {
 5074.     10
 5075.     10// test_cause:
 5076.     10// [" 0=0", "check_mutation", "bad_assignment_a", "0", 2]
 5077.     10// ["0=0", "check_mutation", "bad_assignment_a", "0", 1]
 5078.     10
 5079.     10            warn("bad_assignment_a", the_thing);
 5080.     10            return false;
 5081.   5334        }
 5082.   5334        if (the_optional) {
 5083.      2
 5084.      2// PR-514 - Bugfix - An optional-chain is never an assignment target, so
 5085.      2// 'aa?.bb.cc = 0' and 'aa?.[bb] = 0' are SyntaxErrors too.
 5086.      2
 5087.      2// test_cause:
 5088.      2// ["aa?.[aa]=0", "check_mutation", "bad_assignment_a", "?.", 5]
 5089.      2// ["aa?.aa.aa=0", "check_mutation", "bad_assignment_a", "?.", 3]
 5090.      2
 5091.      2            warn("bad_assignment_a", the_optional, "?.");
 5092.      2            return false;
 5093.   5332        }
 5094.   5332        return true;
 5095.   5332    }
 5096.    994
 5097.   3107    function check_not_top_level(thing) {
 5098.   3107
 5099.   3107// Some features should not be at the outermost level.
 5100.   3107
 5101.     81        if (scope_function === token_global) {
 5102.     81
 5103.     81// test_cause:
 5104.     81// [" for(;;){}", "check_not_top_level", "unexpected_at_top_level_a", "for", 2]
 5105.     81// ["
 5106.     81// while(0){}
 5107.     81// ", "check_not_top_level", "unexpected_at_top_level_a", "while", 1]
 5108.     81
 5109.     81            warn("unexpected_at_top_level_a", thing);
 5110.     81        }
 5111.   3107    }
 5112.    994
 5113.   4245    function check_ordered(type, token_list) {
 5114.   4245
 5115.   4245// This function will warn if <token_list> is unordered.
 5116.   4245
 5117.   4245        token_list
 5118.   4555            .filter(function (token) {
 5119.   4555
 5120.   4555// Issue #401 - Regression - Ignore tokens prefixed by ellipsis for sorting.
 5121.   4555
 5122.   4490                return token && !token.ellipsis;
 5123.   4555            })
 5124.   4483            .reduce(function (aa, token) {
 5125.   4483                const bb = artifact(token);
 5126.   4469                if (!option_dict.unordered && aa > bb) {
 5127.      8                    warn("expected_a_b_before_c_d", token, type, bb, type, aa);
 5128.      8                }
 5129.   4483                return bb;
 5130.   4483            }, "");
 5131.   4245    }
 5132.    994
 5133.   1591    function check_ordered_case(case_list) {
 5134.   1591
 5135.   1591// This function will warn if <case_list> is unordered.
 5136.   1591
 5137.   3235        case_list.filter(noop).map(function (token) {
 5138.   3167            switch (token.identifier || token.id) {
 5139.     46            case "(number)":
 5140.     46                return {
 5141.     46                    order: 1,
 5142.     46                    token,
 5143.     46                    type: "number",
 5144.     46                    value: Number(artifact(token))
 5145.     46                };
 5146.   3109            case "(string)":
 5147.   3109                return {
 5148.   3109                    order: 2,
 5149.   3109                    token,
 5150.   3109                    type: "string",
 5151.   3109                    value: artifact(token)
 5152.   3109                };
 5153.     68            case true:
 5154.     68                return {
 5155.     68                    order: 3,
 5156.     68                    token,
 5157.     68                    type: "identifier",
 5158.     68                    value: artifact(token)
 5159.     68                };
 5160.   3235            }
 5161.   3235        }).reduce(function (aa, bb) {
 5162.   3235            if (
 5163.   3235
 5164.   3235// PR-419 - Hide warning about unordered case-statements behind beta-flag.
 5165.   3235
 5166.   3235                option_dict.beta &&
 5167.   3227                !option_dict.unordered &&
 5168.   3227                aa && bb &&
 5169.   1638                (
 5170.   1638                    aa.order > bb.order ||
 5171.   1638                    (aa.order === bb.order && aa.value > bb.value)
 5172.   1638                )
 5173.     10            ) {
 5174.     10                warn(
 5175.     10                    "expected_a_b_before_c_d",
 5176.     10                    bb.token,
 5177.     10                    `case-${bb.type}`,
 5178.     10                    bb.value,
 5179.     10                    `case-${aa.type}`,
 5180.     10                    aa.value
 5181.     10                );
 5182.     10            }
 5183.   3235            return bb;
 5184.   3235        }, undefined);
 5185.   1591    }
 5186.    994
 5187.  27371    function check_ordered_var(the_variable) {
 5188.  27371
 5189.  27371// This function will check:
 5190.  27371// - const and let declarations are on top of scope_block.
 5191.  27371// - const and let declarations are ordered within scope_block
 5192.  27371// - var declarations are on top of scope_function.
 5193.  27371// - var declarations are ordered within scope_function
 5194.  27371
 5195.   2662        function check(variable_prv, bb) {
 5196.   2662            switch (
 5197.   1664                Boolean(variable_prv) &&
 5198.   1664                !variable_prv.for_init &&
 5199.   1663                variable_prv.id
 5200.   2662            ) {
 5201.    547            case "const":
 5202.   1604            case "let":
 5203.   1605            case "var":
 5204.   1605                if (
 5205.   1605                    option_dict.beta &&
 5206.   1605                    !option_dict.unordered &&
 5207.   1605                    !option_dict.variable &&
 5208.   1605                    variable_prv &&
 5209.   1605                    (
 5210.   1605                        variable_prv.id + " " + variable_prv.name_list[0].id >
 5211.   1605                        the_variable.id + " " + the_variable.name_list[0].id
 5212.   1605                    )
 5213.   1605                ) {
 5214.   1605
 5215.   1605// test_cause:
 5216.   1605// ["const bb=0;const aa=0", "check", "expected_a_b_before_c_d", "aa", 12]
 5217.   1605// ["let bb;let aa", "check", "expected_a_b_before_c_d", "aa", 8]
 5218.   1605// ["var bb;var aa", "check", "expected_a_b_before_c_d", "aa", 8]
 5219.   1605
 5220.   1605                    warn(
 5221.   1605                        "expected_a_b_before_c_d",
 5222.   1605                        the_variable,
 5223.   1605                        the_variable.id,
 5224.   1605                        the_variable.name_list[0].id,
 5225.   1605                        variable_prv.id,
 5226.   1605                        variable_prv.name_list[0].id
 5227.   1605                    );
 5228.   1605                }
 5229.   1605                break;
 5230.      4            case "import":
 5231.   1003            case false:
 5232.   1003
 5233.   1003// test_cause:
 5234.   1003// ["import \"aa\";let aa", "check", "(live)", "", 0]
 5235.   1003
 5236.   1003                break;
 5237.     54            default:
 5238.     54                if (
 5239.     54                    (variable_prv.id !== "{" || the_variable.id === "var") &&
 5240.     54                    option_dict.beta &&
 5241.     54                    !option_dict.variable
 5242.     54                ) {
 5243.     54
 5244.     54// test_cause:
 5245.     54// ["String();const aa=0", "check", "var_on_top_a_b", "block", 10]
 5246.     54// ["String();let aa", "check", "var_on_top_a_b", "block", 10]
 5247.     54// ["String();var aa", "check", "var_on_top_a_b", "function", 10]
 5248.     54// ["try{}catch{var aa}", "check", "var_on_top_a_b", "function", 12]
 5249.     54// ["while(0){var aa}", "check", "var_on_top_a_b", "function", 10]
 5250.     54
 5251.     54                    warn("var_on_top_a_b", the_variable, the_variable.id, bb);
 5252.     54                }
 5253.   2662            }
 5254.   2662        }
 5255.  27371        switch (the_variable.id) {
 5256.    877        case "const":
 5257.   2636        case "let":
 5258.   2636            check(scope_block.variable_prv, "block");
 5259.   2636            scope_block.variable_prv = the_variable;
 5260.   2636            break;
 5261.     26        case "var":
 5262.     26            check(scope_function.variable_prv, "function");
 5263.     26            scope_function.variable_prv = the_variable;
 5264.     26            break;
 5265.  24709        default:
 5266.  24709            scope_block.variable_prv = the_variable;
 5267.  24709            scope_function.variable_prv = the_variable;
 5268.  27371        }
 5269.  27371    }
 5270.    994
 5271.   3673    function condition() {
 5272.   3673
 5273.   3673// Parse the condition part of a do, if, while.
 5274.   3673
 5275.   3673        const the_paren = token_nxt;
 5276.   3673        let the_value;
 5277.   3673
 5278.   3673// test_cause:
 5279.   3673// ["do{}while()", "condition", "(live)", "", 0]
 5280.   3673// ["if(){}", "condition", "(live)", "", 0]
 5281.   3673// ["while(){}", "condition", "(live)", "", 0]
 5282.   3673
 5283.   3673        advance("(");
 5284.   3673        the_value = parse_expression(0);
 5285.   3673        advance(")");
 5286.      1        if (the_value.wrapped === true) {
 5287.      1
 5288.      1// test_cause:
 5289.      1// ["while((0)){}", "condition", "unexpected_a", "(", 6]
 5290.      1
 5291.      1            warn("unexpected_a", the_paren);
 5292.   3669        }
 5293.   3669
 5294.   3669// Check for anticondition.
 5295.   3669
 5296.   3669        switch (the_value.id) {
 5297.   3669        case "%":
 5298.     11
 5299.     11// test_cause:
 5300.     11// ["if(0%0){}", "condition", "unexpected_a", "%", 5]
 5301.     11
 5302.     11            warn("unexpected_a", the_value);
 5303.     11            break;
 5304.      2        case "&":
 5305.      2
 5306.      2// test_cause:
 5307.      2// ["if(0&0){}", "condition", "unexpected_a", "&", 5]
 5308.      2
 5309.      2            warn("unexpected_a", the_value);
 5310.      2            break;
 5311.     44        case "(number)":
 5312.     44
 5313.     44// test_cause:
 5314.     44// ["if(0){}", "condition", "unexpected_a", "0", 4]
 5315.     44
 5316.     44            warn("unexpected_a", the_value);
 5317.     44            break;
 5318.      1        case "(string)":
 5319.      1
 5320.      1// test_cause:
 5321.      1// ["if(\"aa\"){}", "condition", "unexpected_a", "aa", 4]
 5322.      1
 5323.      1            warn("unexpected_a", the_value);
 5324.      1            break;
 5325.      1        case "*":
 5326.      1
 5327.      1// test_cause:
 5328.      1// ["if(0*0){}", "condition", "unexpected_a", "*", 5]
 5329.      1
 5330.      1            warn("unexpected_a", the_value);
 5331.      1            break;
 5332.      1        case "+":
 5333.      1
 5334.      1// test_cause:
 5335.      1// ["if(0+0){}", "condition", "unexpected_a", "+", 5]
 5336.      1
 5337.      1            warn("unexpected_a", the_value);
 5338.      1            break;
 5339.      1        case "-":
 5340.      1
 5341.      1// test_cause:
 5342.      1// ["if(0-0){}", "condition", "unexpected_a", "-", 5]
 5343.      1
 5344.      1            warn("unexpected_a", the_value);
 5345.      1            break;
 5346.      1        case "/":
 5347.      1
 5348.      1// test_cause:
 5349.      1// ["if(0/0){}", "condition", "unexpected_a", "/", 5]
 5350.      1
 5351.      1            warn("unexpected_a", the_value);
 5352.      1            break;
 5353.      1        case "<<":
 5354.      1
 5355.      1// test_cause:
 5356.      1// ["if(0<<0){}", "condition", "unexpected_a", "<<", 5]
 5357.      1
 5358.      1            warn("unexpected_a", the_value);
 5359.      1            break;
 5360.      1        case ">>":
 5361.      1
 5362.      1// test_cause:
 5363.      1// ["if(0>>0){}", "condition", "unexpected_a", ">>", 5]
 5364.      1
 5365.      1            warn("unexpected_a", the_value);
 5366.      1            break;
 5367.      1        case ">>>":
 5368.      1
 5369.      1// test_cause:
 5370.      1// ["if(0>>>0){}", "condition", "unexpected_a", ">>>", 5]
 5371.      1
 5372.      1            warn("unexpected_a", the_value);
 5373.      1            break;
 5374.      1        case "?":
 5375.      1
 5376.      1// test_cause:
 5377.      1// ["if(0?0:0){}", "condition", "unexpected_a", "?", 5]
 5378.      1
 5379.      1            warn("unexpected_a", the_value);
 5380.      1            break;
 5381.      1        case "^":
 5382.      1
 5383.      1// test_cause:
 5384.      1// ["if(0^0){}", "condition", "unexpected_a", "^", 5]
 5385.      1
 5386.      1            warn("unexpected_a", the_value);
 5387.      1            break;
 5388.      1        case "typeof":
 5389.      1
 5390.      1// test_cause:
 5391.      1// ["if(typeof 0){}", "condition", "unexpected_a", "typeof", 4]
 5392.      1
 5393.      1            warn("unexpected_a", the_value);
 5394.      1            break;
 5395.      1        case "|":
 5396.      1
 5397.      1// test_cause:
 5398.      1// ["if(0|0){}", "condition", "unexpected_a", "|", 5]
 5399.      1
 5400.      1            warn("unexpected_a", the_value);
 5401.      1            break;
 5402.      1        case "~":
 5403.      1
 5404.      1// test_cause:
 5405.      1// ["if(~0){}", "condition", "unexpected_a", "~", 4]
 5406.      1
 5407.      1            warn("unexpected_a", the_value);
 5408.      1            break;
 5409.   3669        }
 5410.   3669        return the_value;
 5411.   3669    }
 5412.    994
 5413.  15904    function constant(id, type, value) {
 5414.  15904
 5415.  15904// Create a constant symbol.
 5416.  15904
 5417.  15904        const the_symbol = symbol(id);
 5418.  15904        the_symbol.constant = true;
 5419.  15904        the_symbol.nud_prefix = (
 5420.  15904            typeof value === "function"
 5421.   6958            ? value
 5422.  20190            : function () {
 5423.  20190                token_now.constant = true;
 5424.   8946                if (value !== undefined) {
 5425.   8946                    token_now.value = value;
 5426.   8946                }
 5427.  20190                return token_now;
 5428.  20190            }
 5429.  15904        );
 5430.  15904        the_symbol.type = type;
 5431.  15904        the_symbol.value = value;
 5432.  15904        return the_symbol;
 5433.  15904    }
 5434.    994
 5435.      5    function constant_Function() {
 5436.      2        if (!option_dict.eval) {
 5437.      2
 5438.      2// test_cause:
 5439.      2// [" Function", "constant_Function", "unexpected_a", "Function", 2]
 5440.      2// ["Function", "constant_Function", "unexpected_a", "Function", 1]
 5441.      2
 5442.      2            warn("unexpected_a", token_now);
 5443.      3        } else if (token_nxt.id !== "(") {
 5444.      3
 5445.      3// test_cause:
 5446.      3// ["
 5447.      3// /*jslint eval*/
 5448.      3// Function
 5449.      3// ", "constant_Function", "expected_a_before_b", "(end)", 8]
 5450.      3
 5451.      3            warn("expected_a_before_b", token_nxt, "(", artifact());
 5452.      3        }
 5453.      5        return token_now;
 5454.      5    }
 5455.    994
 5456.      2    function constant_arguments() {
 5457.      2
 5458.      2// test_cause:
 5459.      2// [" arguments", "constant_arguments", "unexpected_a", "arguments", 2]
 5460.      2// ["arguments", "constant_arguments", "unexpected_a", "arguments", 1]
 5461.      2
 5462.      2        warn("unexpected_a", token_now);
 5463.      2        return token_now;
 5464.      2    }
 5465.    994
 5466.      5    function constant_eval() {
 5467.      2        if (!option_dict.eval) {
 5468.      2
 5469.      2// test_cause:
 5470.      2// [" eval", "constant_eval", "unexpected_a", "eval", 2]
 5471.      2// ["eval", "constant_eval", "unexpected_a", "eval", 1]
 5472.      2
 5473.      2            warn("unexpected_a", token_now);
 5474.      3        } else if (token_nxt.id !== "(") {
 5475.      3
 5476.      3// test_cause:
 5477.      3// ["/*jslint eval*/\neval", "constant_eval", "expected_a_before_b", "(end)", 4]
 5478.      3
 5479.      3            warn("expected_a_before_b", token_nxt, "(", artifact());
 5480.      3        }
 5481.      5        return token_now;
 5482.      5    }
 5483.    994
 5484.      2    function constant_ignore() {
 5485.      2
 5486.      2// test_cause:
 5487.      2// [" ignore", "constant_ignore", "unexpected_a", "ignore", 2]
 5488.      2// ["ignore", "constant_ignore", "unexpected_a", "ignore", 1]
 5489.      2
 5490.      2        warn("unexpected_a", token_now);
 5491.      2        return token_now;
 5492.      2    }
 5493.    994
 5494.      2    function constant_isInfinite() {
 5495.      2
 5496.      2// test_cause:
 5497.      2// [" isFinite", "constant_isInfinite", "expected_a_b", "isFinite", 2]
 5498.      2// ["isFinite", "constant_isInfinite", "expected_a_b", "isFinite", 1]
 5499.      2
 5500.      2        warn("expected_a_b", token_now, "Number.isFinite", "isFinite");
 5501.      2        return token_now;
 5502.      2    }
 5503.    994
 5504.      2    function constant_isNaN() {
 5505.      2
 5506.      2// test_cause:
 5507.      2// [" isNaN(0)", "constant_isNaN", "number_isNaN", "isNaN", 2]
 5508.      2// ["isNaN(0)", "constant_isNaN", "number_isNaN", "isNaN", 1]
 5509.      2
 5510.      2        warn("number_isNaN", token_now);
 5511.      2        return token_now;
 5512.      2    }
 5513.    994
 5514.      4    function constant_this() {
 5515.      2        if (!option_dict.this) {
 5516.      2
 5517.      2// test_cause:
 5518.      2// [" this", "constant_this", "unexpected_a", "this", 2]
 5519.      2// ["this", "constant_this", "unexpected_a", "this", 1]
 5520.      2
 5521.      2            warn("unexpected_a", token_now);
 5522.      2        }
 5523.      4        return token_now;
 5524.      4    }
 5525.    994
 5526.  30814    function infix(bp, id, f) {
 5527.  30814
 5528.  30814// Create an infix operator.
 5529.  30814
 5530.  30814        const the_symbol = symbol(id, bp);
 5531.  35729        the_symbol.led_infix = function (left) {
 5532.  35729            const the_token = token_now;
 5533.  35729            the_token.arity = "binary";
 5534.  26047            if (f) {
 5535.  26047                return f(left);
 5536.  26047            }
 5537.   9682            the_token.expression = [left, parse_expression(bp)];
 5538.   9682            return the_token;
 5539.   9682        };
 5540.  30814        return the_symbol;
 5541.  30814    }
 5542.    994
 5543.  12985    function infix_dot(left) {
 5544.  12985        const the_token = token_now;
 5545.  12985        let name = token_nxt;
 5546.  12985        if (
 5547.  12985            (
 5548.     60                left.id !== "(string)" ||
 5549.     60                (
 5550.     60                    name.id !== "at" &&
 5551.     60                    name.id !== "charCodeAt" &&
 5552.     60                    name.id !== "includes" &&
 5553.     60                    name.id !== "indexOf" &&
 5554.     60                    name.id !== "isWellFormed" &&
 5555.     60                    name.id !== "match" &&
 5556.     60                    name.id !== "repeat" &&
 5557.     60                    name.id !== "replace" &&
 5558.     60                    name.id !== "toLowerCase" &&
 5559.     60                    name.id !== "toUpperCase" &&
 5560.     60                    name.id !== "toWellFormed"
 5561.     60                )
 5562.  12928            ) &&
 5563.  12928            (
 5564.  12928                left.id !== "[" ||
 5565.  12928                (
 5566.  12928                    name.id !== "at" &&
 5567.  12928                    name.id !== "concat" &&
 5568.  12928                    name.id !== "every" &&
 5569.  12928                    name.id !== "filter" &&
 5570.  12928                    name.id !== "find" &&
 5571.  12928                    name.id !== "findIndex" &&
 5572.  12928                    name.id !== "flat" &&
 5573.  12928                    name.id !== "flatMap" &&
 5574.  12928                    name.id !== "forEach" &&
 5575.  12928                    name.id !== "includes" &&
 5576.  12928                    name.id !== "join" &&
 5577.  12928                    name.id !== "map" &&
 5578.  12928                    name.id !== "reduce" &&
 5579.  12928                    name.id !== "some" &&
 5580.  12928                    name.id !== "toReversed" &&
 5581.  12928                    name.id !== "toSorted"
 5582.  12928                )
 5583.  12928            ) &&
 5584.  12842            (left.id !== "+" || name.id !== "slice") &&
 5585.  12837            (
 5586.  12837                left.id !== "(regexp)" ||
 5587.  12837                (name.id !== "exec" && name.id !== "test")
 5588.  12837            )
 5589.  12762        ) {
 5590.  12762
 5591.  12762// test_cause:
 5592.  12762// ["(/./)?.0", "check_left", "unexpected_a", "?.", 6]
 5593.  12762// ["\"\".aa", "check_left", "unexpected_a", ".", 3]
 5594.  12762// ["\"aa\"?.0", "check_left", "unexpected_a", "?.", 5]
 5595.  12762// ["aa=[]?.aa", "check_left", "unexpected_a", "?.", 6]
 5596.  12762// ["new aa``.aa()", "check_left", "unexpected_a", ".", 9]
 5597.  12762// ["new aa``?.aa()", "check_left", "unexpected_a", "?.", 9]
 5598.  12762
 5599.  12762            check_left(left, the_token);
 5600.  12762        }
 5601.  12985
 5602.  12985// Issue #468 - Fix optional dynamic-property/function-call not recognized.
 5603.  12985
 5604.  12985        if (
 5605.     81            the_token.id === "?." &&
 5606.     81            (name.id === "[" || name.id === "(")
 5607.     18        ) {
 5608.     18
 5609.     18// test_cause:
 5610.     18// ["aa?.(bb)", "infix_dot", "(live)", "", 0]
 5611.     18// ["aa?.[bb]", "infix_dot", "(live)", "", 0]
 5612.     18
 5613.     18// PR-514 - Bugfix - The '?.' token leaves the tree here, so mark the '[' or '('
 5614.     18// that follows it, for <optional_chain>.
 5615.     18
 5616.     18            name.optional = true;
 5617.     18            return left;
 5618.  12967        }
 5619.  12967        if (!name.identifier) {
 5620.      6
 5621.      6// test_cause:
 5622.      6// ["(0+0)?.0", "infix_dot", "expected_identifier_a", "0", 8]
 5623.      6// ["(0+0)?.0;", "infix_dot", "expected_identifier_a", "0", 8]
 5624.      6// ["aa.0", "infix_dot", "expected_identifier_a", "0", 4]
 5625.      6// ["aa?.0", "infix_dot", "expected_identifier_a", "0", 5]
 5626.      6
 5627.      6            return stop("expected_identifier_a", name);
 5628.  12961        }
 5629.  12961        advance();
 5630.  12961        survey(name);
 5631.  12961
 5632.  12961// The property name is not an expression.
 5633.  12961
 5634.  12961        the_token.name = name;
 5635.  12961        the_token.expression = left;
 5636.  12961        return the_token;
 5637.  12961    }
 5638.    994
 5639.      4    function infix_fart_unwrapped() {
 5640.      2        if (!token_prv.identifier) {
 5641.      2
 5642.      2// test_cause:
 5643.      2// [" 0=>0", "infix_fart_unwrapped", "expected_identifier_a", "0", 2]
 5644.      2// ["0=>0", "infix_fart_unwrapped", "expected_identifier_a", "0", 1]
 5645.      2
 5646.      2            return stop("expected_identifier_a", token_prv);
 5647.      2        }
 5648.      2
 5649.      2// PR-499 - Update ES2015-feature arrow, to continue parsing unwrapped-form
 5650.      2// with warning, instead of stopping.
 5651.      2
 5652.      2        return prefix_function(token_now, true, true);
 5653.      2    }
 5654.    994
 5655.     13    function infix_grave(left) {
 5656.     13        const the_optional = optional_chain(left);
 5657.     13        const the_tick = prefix_tick(true);
 5658.      1        if (the_optional) {
 5659.      1
 5660.      1// test_cause:
 5661.      1// ["aa?.aa``", "infix_grave", "unexpected_a", "?.", 3]
 5662.      1
 5663.      1            warn("unexpected_a", the_optional, "?.");
 5664.      1        }
 5665.     13
 5666.     13// test_cause:
 5667.     13// ["0``", "check_left", "unexpected_a", "`", 2]
 5668.     13
 5669.     13        check_left(left, the_tick);
 5670.     13        the_tick.expression = [left].concat(the_tick.expression);
 5671.     13        return the_tick;
 5672.     13    }
 5673.    994
 5674.   1540    function infix_lbracket(left) {
 5675.   1540        const the_token = token_now;
 5676.   1540        let name;
 5677.   1540        let the_subscript = parse_expression(0);
 5678.   1518        if (the_subscript.id === "(string)" || the_subscript.id === "`") {
 5679.     24            name = survey(the_subscript);
 5680.     24
 5681.     24// PR-404 - Add new sub-directive "subscript" to play nice with Google Closure.
 5682.     24
 5683.     24            if (!option_dict.subscript && jslint_rgx_identifier.test(name)) {
 5684.     24
 5685.     24// test_cause:
 5686.     24// ["aa[`aa`]", "infix_lbracket", "subscript_a", "aa", 4]
 5687.     24
 5688.     24                warn("subscript_a", the_subscript, name);
 5689.     24            }
 5690.     24        }
 5691.   1540
 5692.   1540// test_cause:
 5693.   1540// ["0[0]", "check_left", "unexpected_a", "[", 2]
 5694.   1540
 5695.   1540        check_left(left, the_token);
 5696.   1540        the_token.expression = [left, the_subscript];
 5697.   1540        advance("]");
 5698.   1540        return the_token;
 5699.   1540    }
 5700.    994
 5701.  11508    function infix_lparen(left) {
 5702.  11508        const the_paren = token_now;
 5703.  11508        let the_argument;
 5704.  11469        if (left.id !== "function" && left.id !== "=>") {
 5705.  11468
 5706.  11468// test_cause:
 5707.  11468// ["(0?0:0)()", "check_left", "unexpected_a", "(", 8]
 5708.  11468// ["0()", "check_left", "unexpected_a", "(", 2]
 5709.  11468
 5710.  11468            check_left(left, the_paren);
 5711.  11468        }
 5712.  11508        the_paren.expression = [left];
 5713.   9757        if (token_nxt.id !== ")") {
 5714.   9757
 5715.   9757// Parse/loop through each token in expression (...).
 5716.   9757
 5717.  16162            while (true) {
 5718.  16162                if (token_nxt.id === "...") {
 5719.  16162
 5720.  16162// test_cause:
 5721.  16162// ["aa(...aa)", "infix_lparen", "(live)", "", 0]
 5722.  16162
 5723.  16162                    the_argument = prefix_ellipsis();
 5724.  16162                } else {
 5725.  16162                    the_argument = parse_expression(10);
 5726.  16162                }
 5727.  16162                the_paren.expression.push(the_argument);
 5728.  16162                if (token_nxt.id !== ",") {
 5729.  16162                    break;
 5730.  16162                }
 5731.  16162                advance(",");
 5732.  16162            }
 5733.  11507        }
 5734.  11507        advance(")", the_paren);
 5735.  11507        if (the_paren.expression.length === 2) {
 5736.   5558            if (
 5737.   5558                the_argument.wrapped === true &&
 5738.   5558
 5739.   5558// PR-483 - Allow parenthesis after ellipsis inside a function call.
 5740.   5558
 5741.   5558                the_argument.ellipsis !== true
 5742.   5558            ) {
 5743.   5558
 5744.   5558// test_cause:
 5745.   5558// ["aa((0))", "infix_lparen", "unexpected_a", "(", 3]
 5746.   5558
 5747.   5558                warn("unexpected_a", the_paren);
 5748.   5558            }
 5749.   5558            if (the_argument.id === "(") {
 5750.   5558                the_argument.wrapped = true;
 5751.   5558            }
 5752.  11507        }
 5753.  11507        return the_paren;
 5754.  11507    }
 5755.    994
 5756.    994    function infixr(bp, id) {
 5757.    994
 5758.    994// Create a right associative infix operator.
 5759.    994
 5760.    994        const the_symbol = symbol(id, bp);
 5761.     15        the_symbol.led_infix = function parse_infixr_led(left) {
 5762.     15            const the_token = token_now;
 5763.     15
 5764.     15// test_cause:
 5765.     15// ["0**0", "parse_infixr_led", "(live)", "", 0]
 5766.     15
 5767.     15            the_token.arity = "binary";
 5768.     15            the_token.expression = [left, parse_expression(bp - 1)];
 5769.     15            return the_token;
 5770.     15        };
 5771.    994        return the_symbol;
 5772.    994    }
 5773.    994
 5774.    994// PR-502 - Unify name_list.push() logic with helper-function name_declare().
 5775.    994
 5776.  10585    function name_declare(
 5777.  10585        scope_declared,
 5778.  10585        role,
 5779.  10585        readonly,
 5780.  10585        name_list,
 5781.  10585        name,
 5782.  10585        assigned
 5783.  10585    ) {
 5784.  10585
 5785.  10585// This function will:
 5786.  10585// 1. Push <name> to <name_list>.
 5787.  10585// 2. Set <name>.assigned, <name>.readonly and <name>.role from the arguments.
 5788.  10585//    An existing variable given a new value is marked by <post_a_assignment>.
 5789.  10585// 3. Declare <name> in <scope_declared>.context, unless <scope_declared> is
 5790.  10585//    undefined, as for the plain assignment 'aa = 0'.
 5791.  10585//
 5792.  10585// Most calls to name_declare() are commented regarding thing being declared,
 5793.  10585// and its lifecycle. Below is a copy of all such comments.
 5794.  10585//
 5795.  10585// 1.imp.1 - Mark 'declared', the import-name, during import-statement.
 5796.  10585// 1.imp.2 - Mark 'alive', the import-name, after import-statement.
 5797.  10585// 1.imp.3 - Mark 'assigned', the import-name, during import-statement.
 5798.  10585// 1.imp.4 - Mark 'readonly', the import-name, during import-statement.
 5799.  10585//
 5800.  10585// 2.fun.1 - Mark 'declared', the function-name, during function-declaration.
 5801.  10585// 2.fun.2 - Mark 'alive', the function-name, during function-declaration.
 5802.  10585// 2.fun.3 - Mark 'assigned', the function-name, during function-declaration.
 5803.  10585// 2.fun.4 - Mark 'readonly', the function-name, during function-declaration.
 5804.  10585//
 5805.  10585// 3.cat.1 - Mark 'declared', the catch-variable, before catch-block.
 5806.  10585// 3.cat.2 - Mark 'alive', the catch-variable, before catch-block.
 5807.  10585// 3.cat.3 - Mark 'assigned', the catch-variable, before catch-block.
 5808.  10585// 3.cat.4 - Mark 'readonly', the catch-variable, before catch-block.
 5809.  10585//
 5810.  10585// 3.glo.1 - Mark 'declared', the global-variable, immediately.
 5811.  10585// 3.glo.2 - Mark 'alive', the global-variable, immediately.
 5812.  10585// 3.glo.3 - Mark 'assigned', the global-variable, immediately.
 5813.  10585// 3.glo.4 - Mark 'readonly', the global-variable, immediately.
 5814.  10585//
 5815.  10585// 3.var.1 - Mark 'declared', the variable, during variable-declaration.
 5816.  10585// 3.var.2 - Mark 'alive', the variable, after variable-declaration.
 5817.  10585// 3.var.3 - Mark 'assigned', the variable, after assignment.
 5818.  10585// 3.var.3 - Mark 'assigned', the variable, during destructuring.
 5819.  10585// 3.var.3 - Mark 'assigned', the variable, during variable-declaration.
 5820.  10585// 3.var.4 - Mark 'readonly', the variable, if const.
 5821.  10585//
 5822.  10585// 4.par.1 - Mark 'declared', the function-parameter, during destructuring.
 5823.  10585// 4.par.1 - Mark 'declared', the function-parameter, if unwrapped.
 5824.  10585// 4.par.2 - Mark 'alive', the function-parameter, after destructuring.
 5825.  10585// 4.par.3 - Mark 'assigned', the function-parameter, during destructuring.
 5826.  10585// 4.par.3 - Mark 'assigned', the function-parameter, if unwrapped.
 5827.  10585//
 5828.  10585// 5.lab.1 - Mark 'declared', the label-name, before control-flow-block.
 5829.  10585// 5.lab.2 - Mark 'alive', the label-name, before control-flow-block.
 5830.  10585// 5.lab.3 - Mark 'assigned', the label-name, before control-flow-block.
 5831.  10585// 5.lab.4 - Mark 'readonly', the label-name, before control-flow-block.
 5832.  10585//
 5833.  10585// The 2.fun tags also cover a named function-expression, whose name is
 5834.  10585// declared in <scope_name>, a scope outside its function.
 5835.  10585//
 5836.  10585// PR-514 - Deviations from the spec, reviewed 2026-09-29, each kept. A fixed
 5837.  10585// one is commented at its site, and a Todo is in CHANGELOG.md.
 5838.  10585//
 5839.  10585// - 1.imp.2 - Kept. An import used above its import-statement warns
 5840.  10585//   temporal_dead_zone_a, though imports are hoisted.
 5841.  10585// - 2.fun.1 - Kept. 'let aa;(function aa(){})' warns redefinition_a_b, but
 5842.  10585//   the reverse order does not. ESLint no-shadow is off by default.
 5843.  10585// - 2.fun.4 - Kept. Reassigning a function warns, as ESLint no-func-assign.
 5844.  10585// - 3.cat.4 - Kept. Reassigning a catch-variable warns, as ESLint no-ex-assign.
 5845.  10585// - 3.glo.4 - Kept. Reassigning a global warns, as ESLint no-global-assign.
 5846.  10585// - 3.var.1 - Kept. Unlike the spec, jslint gives a switch no block scope, so a
 5847.  10585//   'let' in a case is seen after the switch. It is moot, since var_switch
 5848.  10585//   warns that 'let'.
 5849.  10585// - 3.var.2 - Kept. A 'var' read above its declaration warns
 5850.  10585//   temporal_dead_zone_a, though its hoisted value 'undefined' is valid.
 5851.  10585// - 3.var.2 - Kept. A function reading a 'let' declared below it warns. See
 5852.  10585//   the note in <name_lookup>.
 5853.  10585// - 3.var.3 - Kept. '&&=' and '+=' do not assign an unassigned variable, which
 5854.  10585//   stays undefined or becomes NaN, so it warns unassigned_var_a. ESLint
 5855.  10585//   no-unassigned-vars counts every compound assignment as a write.
 5856.  10585// - 4.par.1 - Kept. A parameter-default reading a body 'var' warns
 5857.  10585//   temporal_dead_zone_a, where the spec makes it undeclared. It still warns,
 5858.  10585//   and ESLint no-use-before-define likely does the same.
 5859.  10585// - 5.lab.1 - Kept. A label shares the variable namespace, so a same-named
 5860.  10585//   variable warns redefinition_a_b, as ESLint no-label-var.
 5861.  10585// - 5.lab.1 - Kept. A label is allowed only on do, for, switch and while.
 5862.  10585// - 5.lab.1 - Kept. A label read as a variable warns label_a and counts as a
 5863.  10585//   use of the label, so it warns no unused_a as well.
 5864.  10585
 5865.  10585        const id = name.id;
 5866.  10585        let earlier;
 5867.  10585        name_list.push(name);
 5868.  10585        name.assigned = assigned;
 5869.  10585        name.readonly = readonly;
 5870.  10585        name.role = role;
 5871.   7534        if (role === "variable") {
 5872.   7534            name.arity = "variable";
 5873.   7534        }
 5874.   3100        if (!scope_declared) {
 5875.   3100            return;
 5876.   7485        }
 5877.   7485
 5878.   7485// Declare a name into the current scope_declared's context. The role can be
 5879.   7485// exception, label, parameter, or variable. We look for variable
 5880.   7485// redefinition because it causes confusion.
 5881.   7485
 5882.   7485// Reserved words may not be declared.
 5883.   7485
 5884.   7485        if (syntax_dict[id] !== undefined && id !== "ignore") {
 5885.      1
 5886.      1// test_cause:
 5887.      1// ["let undefined", "name_declare", "reserved_a", "undefined", 5]
 5888.      1
 5889.      1            warn("reserved_a", name);
 5890.      1            return;
 5891.   7484        }
 5892.   7484
 5893.   7484// Has the name been declared in this context?
 5894.   7484
 5895.   7484// PR-514 - Bugfix - Check <scope_declared>, which differs from <scope_block>
 5896.   7484// for a var in a nested block. Else 'var bb' in an if-block replaced an
 5897.   7484// earlier 'var bb', and a use between them warned temporal_dead_zone_a.
 5898.   7484
 5899.   7484        earlier = scope_block.context[id] || scope_declared.context[id];
 5900.      6        if (earlier) {
 5901.      6
 5902.      6// test_cause:
 5903.      6// ["let aa;(function aa(){})", "name_declare", "redefinition_a_b", "1", 18]
 5904.      6// ["let aa;function aa(){}", "name_declare", "redefinition_a_b", "1", 17]
 5905.      6// ["let aa;let aa", "name_declare", "redefinition_a_b", "1", 12]
 5906.      6// ["var aa;if(0){var aa}", "name_declare", "redefinition_a_b", "1", 18]
 5907.      6
 5908.      6            warn("redefinition_a_b", name, id, earlier.line);
 5909.      6            return;
 5910.   7478        }
 5911.   7478
 5912.   7478// Has the name been declared in an outer context?
 5913.   7478
 5914.  34930        block_stack.slice(1).some(function (scope_block) {
 5915.  34930            earlier = scope_block.context[id];
 5916.   7478            switch (Boolean(earlier) && role) {
 5917.   7478            case "label":
 5918.   7478                if (earlier.role !== "label") {
 5919.   7478
 5920.   7478// test_cause:
 5921.   7478// ["let aa;aa:while(0){}", "name_declare", "redefinition_a_b", "1", 8]
 5922.   7478
 5923.   7478                    warn("redefinition_a_b", name, id, earlier.line);
 5924.   7478                    earlier = undefined;
 5925.   7478                }
 5926.   7478                break;
 5927.  34767            case false:
 5928.  34767                break;
 5929.   7478            default:
 5930.   7478                if (earlier.role === "label") {
 5931.   7478
 5932.   7478// test_cause:
 5933.   7478// ["aa:while(0){let aa}", "name_declare", "redefinition_a_b", "1", 17]
 5934.   7478
 5935.   7478                    warn("redefinition_a_b", name, id, earlier.line);
 5936.   7478                    earlier = undefined;
 5937.   7478                }
 5938.  34930            }
 5939.  34930            return earlier;
 5940.  34930        });
 5941.   7478
 5942.   7478// Declare it.
 5943.   7478
 5944.   7478        scope_declared.context[id] = name;
 5945.   7478        name.scope_declared = scope_declared;
 5946.   7478
 5947.   7478// PR-516 - Bugfix - Record the function that owns <name>, since a let/const
 5948.   7478// <scope_declared> may be a block inside it.
 5949.   7478
 5950.   7478        name.scope_function = scope_function;
 5951.   7478        if (!scope_declared.name_only) {
 5952.   7446
 5953.   7446// PR-516 - Omit a named function expression's name from its declaring
 5954.   7446// function. It sits in <scope_name>, a scope outside its own function.
 5955.   7446
 5956.   7446            scope_report_push(scope_function, name);
 5957.   7478        }
 5958.   7478
 5959.   7478// Warn about variable redefinition.
 5960.   7478
 5961.   7478        if (earlier && id === "ignore") {
 5962.      4            if (earlier.role === "variable") {
 5963.      4
 5964.      4// test_cause:
 5965.      4// ["let ignore;(ignore)=>0", "name_declare", "redefinition_a_b", "1", 13]
 5966.      4
 5967.      4                warn("redefinition_a_b", name, id, earlier.line);
 5968.      4            }
 5969.      4            return;
 5970.   7474        }
 5971.   7474        if (
 5972.   7474            earlier &&
 5973.    156            role !== "parameter" &&
 5974.     16            (role !== "exception" || earlier.role !== "exception")
 5975.     16        ) {
 5976.     16
 5977.     16// test_cause:
 5978.     16// ["for(let aa;;)let aa", "name_declare", "redefinition_a_b", "1", 18]
 5979.     16// ["
 5980.     16// function aa(){try{aa();}catch(aa){aa();}}
 5981.     16// ", "name_declare", "redefinition_a_b", "1", 31]
 5982.     16// ["function aa(){var aa}", "name_declare", "redefinition_a_b", "1", 19]
 5983.     16// ["let aa;do let aa;while(0)", "name_declare", "redefinition_a_b", "1", 15]
 5984.     16// ["let aa;do;while(0)let aa", "name_declare", "redefinition_a_b", "1", 23]
 5985.     16// ["let aa;for(let aa;;){}", "name_declare", "redefinition_a_b", "1", 16]
 5986.     16// ["
 5987.     16// let aa;if(0);else if(0)let aa
 5988.     16// ", "name_declare", "redefinition_a_b", "1", 28]
 5989.     16// ["let aa;if(0);else let aa", "name_declare", "redefinition_a_b", "1", 23]
 5990.     16// ["let aa;if(0)let aa", "name_declare", "redefinition_a_b", "1", 17]
 5991.     16// ["let aa;while(0)let aa", "name_declare", "redefinition_a_b", "1", 20]
 5992.     16
 5993.     16            warn("redefinition_a_b", name, id, earlier.line);
 5994.     16            return;
 5995.   7458        }
 5996.   7458        if (
 5997.   7458            option_dict.beta &&
 5998.   7270            global_dict[id] &&
 5999.     17            role !== "parameter"
 6000.      1        ) {
 6001.      1
 6002.      1// test_cause:
 6003.      1// ["let Array", "name_declare", "redefinition_global_a_b", "Array", 5]
 6004.      1
 6005.      1            warn("redefinition_global_a_b", name, global_dict[id], id);
 6006.      1            return;
 6007.      1        }
 6008.  10585    }
 6009.    994
 6010.   5529    function optional_chain(thing) {
 6011.   5529
 6012.   5529// PR-514 - This function will return the '?.' token, or the '[' or '(' token
 6013.   5529// marked <optional> after a '?.', of an unwrapped optional-chain ending at
 6014.   5529// <thing>. The spec forbids such a chain as an assignment target, the callee
 6015.   5529// of 'new' and the tag of a template.
 6016.   5529
 6017.   7259        while (thing && !thing.wrapped) {
 6018.   7259            if (thing.id === "?." || thing.optional === true) {
 6019.   7259                return thing;
 6020.   7259            }
 6021.   7259            if (thing.arity !== "binary") {
 6022.   7259                return;
 6023.   7259            }
 6024.   7259            switch (thing.id) {
 6025.   7259            case "(":
 6026.   7259            case "[":
 6027.   7259                thing = thing.expression[0];
 6028.   7259                break;
 6029.   7259            case ".":
 6030.   7259                thing = thing.expression;
 6031.   7259                break;
 6032.   7259            default:
 6033.   7259
 6034.   7259// test_cause:
 6035.   7259// ["aa+aa=0", "optional_chain", "(live)", "", 0]
 6036.   7259
 6037.   7259                return;
 6038.   7259            }
 6039.   7259        }
 6040.   5529    }
 6041.    994
 6042.  62622    function parse_expression(rbp, initial) {
 6043.  62622
 6044.  62622// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
 6045.  62622// is looking for ad hoc lint patterns. We add .fud_stmt to Pratt's model, which
 6046.  62622// is like .nud_prefix except that it is only used on the first token of a
 6047.  62622// statement. Having .fud_stmt makes it much easier to define statement-oriented
 6048.  62622// languages like JavaScript. I retained Pratt's nomenclature.
 6049.  62622// They are elements of the parsing method called Top Down Operator Precedence.
 6050.  62622
 6051.  62622// .nud_prefix  Null denotation. The prefix handler.
 6052.  62622// .fud_stmt    First null denotation. The statement handler.
 6053.  62622// .led_infix   Left denotation. The infix/postfix handler.
 6054.  62622//  lbp         Left binding power of infix operator. It tells us how strongly
 6055.  62622//              the operator binds to the argument at its left.
 6056.  62622//  rbp         Right binding power. Parser will continue consuming tokens while
 6057.  62622//              next token's lbp > rbp.
 6058.  62622//  initial     Whether first token has already been advanced. If falsy,
 6059.  62622//              immediately calls advance().
 6060.  62622
 6061.  62622// It processes a nud_prefix (variable, constant, prefix operator). It will then
 6062.  62622// process leds (infix operators) until the bind powers cause it to stop (it
 6063.  62622// consumes tokens until it meets a token whose lbp <= rbp). Specifically, it
 6064.  62622// means that it collects all tokens that bind together before returning to the
 6065.  62622// operator that called it. It returns the expression's parse tree.
 6066.  62622
 6067.  62622// For example, "3 + 1 * 2 * 4 + 5"
 6068.  62622// parses into
 6069.  62622// {
 6070.  62622//     "id": "+",
 6071.  62622//     "expression": [
 6072.  62622//         {
 6073.  62622//             "id": "+",
 6074.  62622//             "expression": [
 6075.  62622//                 {
 6076.  62622//                     "id": "(number)",
 6077.  62622//                     "value": "3"
 6078.  62622//                 },
 6079.  62622//                 {
 6080.  62622//                     "id": "*",
 6081.  62622//                     "expression": [
 6082.  62622//                         {
 6083.  62622//                             "id": "*",
 6084.  62622//                             "expression": [
 6085.  62622//                                 {
 6086.  62622//                                     "id": "(number)",
 6087.  62622//                                     "value": "1"
 6088.  62622//                                 },
 6089.  62622//                                 {
 6090.  62622//                                     "id": "(number)",
 6091.  62622//                                     "value": "2"
 6092.  62622//                                 }
 6093.  62622//                             ]
 6094.  62622//                         },
 6095.  62622//                         {
 6096.  62622//                             "id": "(number)",
 6097.  62622//                             "value": "4"
 6098.  62622//                         }
 6099.  62622//                     ]
 6100.  62622//                 }
 6101.  62622//             ]
 6102.  62622//         },
 6103.  62622//         {
 6104.  62622//             "id": "(number)",
 6105.  62622//             "value": "5"
 6106.  62622//         }
 6107.  62622//     ]
 6108.  62622// }
 6109.  62622
 6110.  62622        let left;
 6111.  62622        let the_symbol;
 6112.  62622
 6113.  62622// Statements will have already advanced, so advance now only if the token is
 6114.  62622// not the first of a statement.
 6115.  62622
 6116.  50823        if (!initial) {
 6117.  50823            advance();
 6118.  50823        }
 6119.  62622        the_symbol = syntax_dict[token_now.id];
 6120.  27182        if (the_symbol !== undefined && the_symbol.nud_prefix !== undefined) {
 6121.  27117
 6122.  27117// test_cause:
 6123.  27117// ["0", "parse_expression", "(live)", "", 0]
 6124.  27117
 6125.  27117            left = the_symbol.nud_prefix();
 6126.  35505        } else if (token_now.identifier) {
 6127.  35505
 6128.  35505// test_cause:
 6129.  35505// ["aa", "parse_expression", "(live)", "", 0]
 6130.  35505
 6131.  35505            left = token_now;
 6132.  35505            left.arity = "variable";
 6133.  35505        } else {
 6134.  35505
 6135.  35505// test_cause:
 6136.  35505// ["!", "parse_expression", "unexpected_a", "(end)", 1]
 6137.  35505// ["/./", "parse_expression", "unexpected_a", "/", 1]
 6138.  35505// ["let aa=`${}`", "parse_expression", "unexpected_a", "}", 11]
 6139.  35505
 6140.  35505            return stop("unexpected_a", token_now);
 6141.  62579        }
 6142.  62579
 6143.  62579// Parse/loop through each symbol in expression.
 6144.  62579
 6145. 103965        while (true) {
 6146. 103965            the_symbol = syntax_dict[token_nxt.id];
 6147. 103965            if (
 6148. 103965                the_symbol === undefined ||
 6149. 103965                the_symbol.led_infix === undefined ||
 6150. 103965                the_symbol.lbp <= rbp
 6151. 103965            ) {
 6152. 103965                break;
 6153. 103965            }
 6154. 103965
 6155. 103965// PR-514 - Bugfix - A line break before a postfix '++' or '--' ends the
 6156. 103965// expression, since the spec forbids one there and inserts a ';'. So 'aa' then
 6157. 103965// '++bb' on the next line is 'aa; ++bb', not 'aa++; bb'.
 6158. 103965
 6159. 103965            if (
 6160. 103965                (token_nxt.id === "++" || token_nxt.id === "--") &&
 6161. 103965                token_nxt.line !== token_now.line
 6162. 103965            ) {
 6163. 103965
 6164. 103965// test_cause:
 6165. 103965// ["
 6166. 103965// aa
 6167. 103965// ++aa
 6168. 103965// ", "parse_expression", "(live)", "", 0]
 6169. 103965
 6170. 103965                break;
 6171. 103965            }
 6172. 103965            advance();
 6173. 103965            left = the_symbol.led_infix(left);
 6174. 103965        }
 6175.  62565        return left;
 6176.  62565    }
 6177.    994
 6178.  12961    function parse_json() {
 6179.  12961        let container;
 6180.  12961        let is_dup;
 6181.  12961        let name;
 6182.  12961        let negative;
 6183.  12961        switch (token_nxt.id) {
 6184.   5260        case "(number)":
 6185.   5260            if (!jslint_rgx_json_number.test(token_nxt.value)) {
 6186.   5260
 6187.   5260// test_cause:
 6188.   5260// ["[-0x0]", "parse_json", "unexpected_a", "0x0", 3]
 6189.   5260// ["[0x0]", "parse_json", "unexpected_a", "0x0", 2]
 6190.   5260
 6191.   5260                warn("unexpected_a");
 6192.   5260            }
 6193.   5260            advance("(number)");
 6194.   5260            return token_now;
 6195.   1767        case "(string)":
 6196.   1767            if (token_nxt.quote !== "\"") {
 6197.   1767
 6198.   1767// test_cause:
 6199.   1767// ["['']", "parse_json", "unexpected_a", "'", 2]
 6200.   1767
 6201.   1767                warn("unexpected_a", token_nxt, token_nxt.quote);
 6202.   1767            }
 6203.   1767            advance("(string)");
 6204.   1767            return token_now;
 6205.      3        case "-":
 6206.      3            negative = token_nxt;
 6207.      3            negative.arity = "unary";
 6208.      3            advance("-");
 6209.      3
 6210.      3// Recurse parse_json.
 6211.      3
 6212.      3            negative.expression = parse_json();
 6213.      3            return negative;
 6214.   1649        case "[":
 6215.   1649
 6216.   1649// test_cause:
 6217.   1649// ["[]", "parse_json", "(live)", "", 0]
 6218.   1649
 6219.   1649            container = token_nxt;
 6220.   1649            container.expression = [];
 6221.   1649            advance("[");
 6222.   1649            if (token_nxt.id !== "]") {
 6223.   3299                while (true) {
 6224.   3299
 6225.   3299// Recurse parse_json.
 6226.   3299
 6227.   3299                    container.expression.push(parse_json());
 6228.   3299                    if (token_nxt.id !== ",") {
 6229.   3299                        break;
 6230.   3299                    }
 6231.   3299                    advance(",");
 6232.   3299                }
 6233.   1649            }
 6234.   1649            advance("]", container);
 6235.   1649            return container;
 6236.    509        case "false":
 6237.    511        case "null":
 6238.    896        case "true":
 6239.    896
 6240.    896// test_cause:
 6241.    896// ["[false]", "parse_json", "(live)", "", 0]
 6242.    896// ["[null]", "parse_json", "(live)", "", 0]
 6243.    896// ["[true]", "parse_json", "(live)", "", 0]
 6244.    896
 6245.    896            advance();
 6246.    896            return token_now;
 6247.   3380        case "{":
 6248.   3380
 6249.   3380// test_cause:
 6250.   3380// ["{}", "parse_json", "(live)", "", 0]
 6251.   3380
 6252.   3380            container = token_nxt;
 6253.   3380
 6254.   3380// Explicit empty-object required to detect "__proto__".
 6255.   3380
 6256.   3380            is_dup = empty();
 6257.   3380            container.expression = [];
 6258.   3380            advance("{");
 6259.   3380            if (token_nxt.id !== "}") {
 6260.   3380
 6261.   3380// JSON
 6262.   3380// Parse/loop through each property in {...}.
 6263.   3380
 6264.   9637                while (true) {
 6265.   9637                    if (token_nxt.quote !== "\"") {
 6266.   9637
 6267.   9637// test_cause:
 6268.   9637// ["{...}", "parse_json", "unexpected_a", "...", 2]
 6269.   9637// ["{0:0}", "parse_json", "unexpected_a", "0", 2]
 6270.   9637
 6271.   9637                        warn(
 6272.   9637                            "unexpected_a",
 6273.   9637                            token_nxt,
 6274.   9637                            token_nxt.quote
 6275.   9637                        );
 6276.   9637                    }
 6277.   9637                    name = token_nxt;
 6278.   9637                    advance("(string)");
 6279.   9637                    if (is_dup[token_now.value] !== undefined) {
 6280.   9637
 6281.   9637// test_cause:
 6282.   9637// ["{\"aa\":0,\"aa\":0}", "parse_json", "duplicate_a", "aa", 9]
 6283.   9637
 6284.   9637                        warn("duplicate_a", token_now);
 6285.   9637                    } else if (token_now.value === "__proto__") {
 6286.   9637
 6287.   9637// test_cause:
 6288.   9637// ["{\"__proto__\":0}", "parse_json", "weird_property_a", "__proto__", 2]
 6289.   9637
 6290.   9637                        warn("weird_property_a", token_now);
 6291.   9637                    } else {
 6292.   9637                        is_dup[token_now.value] = token_now;
 6293.   9637                    }
 6294.   9637                    advance(":");
 6295.   9637                    container.expression.push(
 6296.   9637                        Object.assign(
 6297.   9637
 6298.   9637// Recurse parse_json.
 6299.   9637
 6300.   9637                            parse_json(),
 6301.   9637                            {
 6302.   9637                                name_alias: name
 6303.   9637                            }
 6304.   9637                        )
 6305.   9637                    );
 6306.   9637                    if (token_nxt.id !== ",") {
 6307.   9637                        break;
 6308.   9637                    }
 6309.   9637                    advance(",");
 6310.   9637                }
 6311.   3380            }
 6312.   3380            advance("}", container);
 6313.   3380            return container;
 6314.      6        default:
 6315.      6
 6316.      6// test_cause:
 6317.      6// ["[-.0]", "parse_json", "unexpected_a", ".", 3]
 6318.      6// ["[...]", "parse_json", "unexpected_a", "...", 2]
 6319.      6// ["[.0]", "parse_json", "unexpected_a", ".", 2]
 6320.      6// ["[undefined]", "parse_json", "unexpected_a", "undefined", 2]
 6321.      6
 6322.      6            return stop("unexpected_a");
 6323.  12961        }
 6324.  12961    }
 6325.    994
 6326.   8883    function parse_statement_block() {
 6327.   8883
 6328.   8883// Parse a list of statements. Give a warning if an unreachable statement
 6329.   8883// follows a disruptive statement.
 6330.   8883
 6331.   8883        const statement_list = [];
 6332.   8883        let a_statement;
 6333.   8883        let disrupt = false;
 6334.   8883
 6335.   8883// Parse/loop each statement until a statement-terminator is reached.
 6336.   8883
 6337.  31816        while (true) {
 6338.  31816            switch (token_nxt.id) {
 6339.  31816            case "(end)":
 6340.  31816            case "case":
 6341.  31816            case "default":
 6342.  31816            case "else":
 6343.  31816            case "}":
 6344.  31816
 6345.  31816// test_cause:
 6346.  31816// [";", "parse_statement_block", "(live)", "", 0]
 6347.  31816// ["case", "parse_statement_block", "(live)", "", 0]
 6348.  31816// ["default", "parse_statement_block", "(live)", "", 0]
 6349.  31816// ["else", "parse_statement_block", "(live)", "", 0]
 6350.  31816// ["}", "parse_statement_block", "(live)", "", 0]
 6351.  31816
 6352.  31816                return statement_list;
 6353.  31816            }
 6354.  31816            a_statement = parse_statement_single();
 6355.  31816            statement_list.push(a_statement);
 6356.  31816            if (disrupt) {
 6357.  31816
 6358.  31816// test_cause:
 6359.  31816// ["while(0){break;0}", "parse_statement_block", "unreachable_a", "0", 16]
 6360.  31816
 6361.  31816                warn("unreachable_a", a_statement);
 6362.  31816            }
 6363.  31816            disrupt = a_statement.disrupt;
 6364.  31816        }
 6365.   8883    }
 6366.    994
 6367.  23377    function parse_statement_single() {
 6368.  23377
 6369.  23377// Parse a statement. Any statement may have a label, but only four statements
 6370.  23377// have use for one. A statement can be one of the standard statements, or
 6371.  23377// an assignment expression, or an invocation expression.
 6372.  23377
 6373.  23377        let first;
 6374.  23377        let the_statement;
 6375.  23377        let the_symbol;
 6376.     32        if (token_nxt.id === ";") {
 6377.     32            semicolon();
 6378.     32            return stmt_semicolon();
 6379.  23345        }
 6380.  23345        advance();
 6381.  23345        if (token_now.identifier && token_nxt.id === ":") {
 6382.     30            the_statement = stmt_label();
 6383.     30            if (the_statement) {
 6384.     30                return the_statement;
 6385.     30            }
 6386.  23323        }
 6387.  23323
 6388.  23323// Parse the statement.
 6389.  23323
 6390.  23323        first = token_now;
 6391.  23323        first.statement = true;
 6392.  23323        the_symbol = syntax_dict[first.id];
 6393.  23323        if (
 6394.  23323            the_symbol !== undefined &&
 6395.  12480            the_symbol.fud_stmt !== undefined &&
 6396.  12203
 6397.  12203// PR-318 - Bugfix - Fixes issues #316, #317 - dynamic-import().
 6398.  12203
 6399.  12203            !(the_symbol.id === "import" && token_nxt.id === "(")
 6400.  12202        ) {
 6401.  12202            the_symbol.disrupt = false;
 6402.  12202            the_symbol.statement = true;
 6403.  12202            token_now.arity = "statement";
 6404.  12202            the_statement = the_symbol.fud_stmt();
 6405.  12202        } else {
 6406.  11121
 6407.  11121// It is an expression statement.
 6408.  11121
 6409.  11121            the_statement = parse_expression(0, true);
 6410.  11121            if (the_statement.wrapped && the_statement.id !== "(") {
 6411.  11121
 6412.  11121// test_cause:
 6413.  11121// [" (0)", "parse_statement_single", "unexpected_a", "(", 2]
 6414.  11121// ["(0)", "parse_statement_single", "unexpected_a", "(", 1]
 6415.  11121
 6416.  11121                warn("unexpected_a", first);
 6417.  11121            }
 6418.  11121            semicolon();
 6419.  23214        }
 6420.  23214        check_ordered_var(the_statement);
 6421.  23214        return the_statement;
 6422.  23214    }
 6423.    994
 6424.   1988    function postassign(id) {
 6425.   1988
 6426.   1988// Create one of the postassign operators.
 6427.   1988
 6428.   1988        const the_symbol = symbol(id, 155);
 6429.      5        the_symbol.led_infix = function (left) {
 6430.      5            token_now.expression = left;
 6431.      5            token_now.arity = "postassign";
 6432.      5            check_mutation(token_now.expression);
 6433.      5            return token_now;
 6434.      5        };
 6435.   1988        return the_symbol;
 6436.   1988    }
 6437.    994
 6438.   1988    function preassign(id) {
 6439.   1988
 6440.   1988// Create one of the preassign operators.
 6441.   1988
 6442.   1988        const the_symbol = symbol(id);
 6443.      5        the_symbol.nud_prefix = function () {
 6444.      5            const the_token = token_now;
 6445.      5            the_token.arity = "preassign";
 6446.      5            the_token.expression = parse_expression(150);
 6447.      5            check_mutation(the_token.expression);
 6448.      5            return the_token;
 6449.      5        };
 6450.   1988        return the_symbol;
 6451.   1988    }
 6452.    994
 6453.  16898    function prefix(id, f) {
 6454.  16898
 6455.  16898// Create a prefix operator.
 6456.  16898
 6457.  16898        const the_symbol = symbol(id);
 6458.   6900        the_symbol.nud_prefix = function () {
 6459.   6900            const the_token = token_now;
 6460.   6900            the_token.arity = "unary";
 6461.   5870            if (f) {
 6462.   5870                return f();
 6463.   5870            }
 6464.   1030            the_token.expression = parse_expression(150);
 6465.   1030            return the_token;
 6466.   1030        };
 6467.  16898        return the_symbol;
 6468.  16898    }
 6469.    994
 6470.      2    function prefix_assign_divide() {
 6471.      2
 6472.      2// test_cause:
 6473.      2// [" /=", "prefix_assign_divide", "expected_a_b", "/=", 2]
 6474.      2// ["/=", "prefix_assign_divide", "expected_a_b", "/=", 1]
 6475.      2
 6476.      2        return stop("expected_a_b", token_now, "/\\=", "/=");
 6477.      2    }
 6478.    994
 6479.    154    function prefix_async() {
 6480.    154        const the_async = token_now;
 6481.    150        const the_function = token_nxt.fart || token_nxt;
 6482.    154        the_function.async = 1;
 6483.    154        token_nxt.arity = the_async.arity;
 6484.      4        if (token_nxt.fart && token_nxt.identifier) {
 6485.      1
 6486.      1// PR-503 - Parse async fart (unwrapped).
 6487.      1
 6488.      1            advance();
 6489.      1            advance("=>");
 6490.      1
 6491.      1// test_cause:
 6492.      1// ["async aa=>0", "prefix_async", "(live)", "", 0]
 6493.      1
 6494.      1            prefix_function(the_function, true, true);
 6495.    153        } else if (token_nxt.fart) {
 6496.    153
 6497.    153// PR-414 - Parse async fart.
 6498.    153
 6499.    153// test_cause:
 6500.    153// ["aa=async(bb)=>bb", "prefix_async", "(live)", "", 0]
 6501.    153
 6502.    153            advance("(");
 6503.    153            prefix_function(the_function, true, false);
 6504.    153        } else {
 6505.    153
 6506.    153// Parse async function.
 6507.    153
 6508.    153            advance("function");
 6509.    153            prefix_function(the_function, false, false);
 6510.    153        }
 6511.      6        if (the_function.async === 1) {
 6512.      6
 6513.      6// test_cause:
 6514.      6// ["
 6515.      6// async function aa(){}
 6516.      6// ", "prefix_async", "missing_await_statement", "function", 7]
 6517.      6
 6518.      6            warn("missing_await_statement", the_function);
 6519.      6        }
 6520.    154        return the_function;
 6521.    154    }
 6522.    994
 6523.    366    function prefix_await() {
 6524.    366        const the_await = token_now;
 6525.    366
 6526.    366// PR-370 - Add top-level-await support.
 6527.    366
 6528.     10        if (scope_function.async === 0 && scope_function !== token_global) {
 6529.      2
 6530.      2// test_cause:
 6531.      2// ["function aa(){aa=await 0}", "prefix_await", "unexpected_a", "await", 18]
 6532.      2// ["function aa(){await 0}", "prefix_await", "unexpected_a", "await", 15]
 6533.      2
 6534.      2            warn("unexpected_a", the_await);
 6535.      2        }
 6536.    146        if (scope_function.async === 1) {
 6537.    146            scope_function.async = 2;
 6538.    146        }
 6539.    366        the_await.expression = parse_expression(150);
 6540.    232        if (the_await.arity === "statement") {
 6541.    232
 6542.    232// PR-405 - Bugfix - Fix expression after "await" mis-identified as statement.
 6543.    232
 6544.    232            semicolon();
 6545.    232        }
 6546.    366        return the_await;
 6547.    366    }
 6548.    994
 6549.   2235    function prefix_destructure(
 6550.   2235        scope_declared,
 6551.   2235        role,
 6552.   2235        readonly,
 6553.   2235        name_list,
 6554.   2235        the_function,
 6555.   2235        the_function_toplevel
 6556.   2235    ) {
 6557.   2235        const is_assignment = scope_declared === undefined;
 6558.   2235        const is_lbrace = token_now.id === "{";
 6559.   2235        const sub_list = [];
 6560.   2235        const the_destructure = token_now;
 6561.   2235        let optional;
 6562.   4017        function name_parse() {
 6563.   4017            let name = token_nxt;
 6564.   4017            switch (name.id) {
 6565.     27            case "...":
 6566.     27                advance("...");
 6567.     27                name = token_nxt;
 6568.     27                name.ellipsis = true;
 6569.     27                if (name.id === "...") {
 6570.     27
 6571.     27// test_cause:
 6572.     27// ["let[... ...]=0", "name_parse", "unexpected_a_after_b", "...", 9]
 6573.     27
 6574.     27                    return stop("unexpected_a_after_b", name, name.id, "...");
 6575.     27                }
 6576.     27                if (optional) {
 6577.     27
 6578.     27// test_cause:
 6579.     27// ["function aa(aa=0,...){}", "name_parse", "required_a_optional_b", "aa", 21]
 6580.     27
 6581.     27                    warn("required_a_optional_b", name, name.id, optional.id);
 6582.     27                }
 6583.     27
 6584.     27// test_cause:
 6585.     27// ["let[...aa]=0", "name_parse", "(live)", "", 0]
 6586.     27// ["let{...aa}=0", "name_parse", "(live)", "", 0]
 6587.     27
 6588.     27                name_parse();
 6589.     27                return true;
 6590.     90            case "[":
 6591.    380            case "{":
 6592.    380                if (the_function?.id === "=>" && !option_dict.fart) {
 6593.    380
 6594.    380// test_cause:
 6595.    380// ["([aa])=>0", "name_parse", "use_function_not_fart", "=>", 7]
 6596.    380// ["({aa})=>0", "name_parse", "use_function_not_fart", "=>", 7]
 6597.    380
 6598.    380                    warn("use_function_not_fart", the_function);
 6599.    380                }
 6600.    380                if (optional) {
 6601.    380
 6602.    380// test_cause:
 6603.    380// ["function aa(aa=0,[]){}", "name_parse", "required_a_optional_b", "aa", 18]
 6604.    380// ["function aa(aa=0,{}){}", "name_parse", "required_a_optional_b", "aa", 18]
 6605.    380
 6606.    380                    warn("required_a_optional_b", name, name.id, optional.id);
 6607.    380                }
 6608.    380
 6609.    380// test_cause:
 6610.    380// ["let[[aa]]=0", "name_parse", "(live)", "", 0]
 6611.    380// ["let[{aa}]=0", "name_parse", "(live)", "", 0]
 6612.    380
 6613.    380                advance(token_nxt.id);
 6614.    380                prefix_destructure(
 6615.    380                    scope_declared,     // scope_declared
 6616.    380                    role,               // role
 6617.    380                    readonly,           // readonly
 6618.    380                    name_list,          // name_list
 6619.    380                    the_function,       // the_function
 6620.    380                    false               // the_function_toplevel
 6621.    380                );
 6622.    380                return;
 6623.   3610            }
 6624.   3610            if (!name.identifier) {
 6625.     13
 6626.     13// test_cause:
 6627.     13// ["function aa(...0){}", "name_parse", "expected_identifier_a", "0", 16]
 6628.     13// ["function aa(0){}", "name_parse", "expected_identifier_a", "0", 13]
 6629.     13// ["function aa([0]){}", "name_parse", "expected_identifier_a", "0", 14]
 6630.     13// ["function aa({0}){}", "name_parse", "expected_identifier_a", "0", 14]
 6631.     13// ["function aa({aa:0}){}", "name_parse", "expected_identifier_a", "0", 17]
 6632.     13// ["let[...0]=0", "name_parse", "expected_identifier_a", "0", 8]
 6633.     13// ["let[0]=0", "name_parse", "expected_identifier_a", "0", 5]
 6634.     13// ["let{0}=0", "name_parse", "expected_identifier_a", "0", 5]
 6635.     13
 6636.     13                return stop("expected_identifier_a", name);
 6637.   3597            }
 6638.   3597            if (is_lbrace) {
 6639.   1208                survey(name);
 6640.   3597            }
 6641.   3597            advance(token_nxt.id);
 6642.   3597            if (is_lbrace && token_nxt.id === ":") {
 6643.     22                advance(":");
 6644.     22                if (!the_function_toplevel) {
 6645.     22                    the_destructure.open = true;
 6646.     22                }
 6647.     22                if (token_nxt.id === "...") {
 6648.     22
 6649.     22// test_cause:
 6650.     22// ["let{aa:...aa}=0", "name_parse", "unexpected_a", "...", 8]
 6651.     22
 6652.     22                    return stop("unexpected_a", token_nxt);
 6653.     22                }
 6654.     22                if (!token_nxt.identifier) {
 6655.     22
 6656.     22// test_cause:
 6657.     22// ["let{aa:[aa]}=0", "name_parse", "(live)", "", 0]
 6658.     22// ["let{aa:{aa}}=0", "name_parse", "(live)", "", 0]
 6659.     22
 6660.     22                    name_parse();
 6661.     22                    return;
 6662.     22                }
 6663.     22                token_nxt.name_alias = name;
 6664.     22                name = token_nxt;
 6665.     22                name_declare(
 6666.     22                    scope_declared,     // scope_declared
 6667.     22                    role,               // role
 6668.     22                    readonly,           // readonly
 6669.     22                    sub_list,           // name_list
 6670.     22                    name,               // name
 6671.     22
 6672.     22// 3.var.3 - Mark 'assigned', the variable, during destructuring.
 6673.     22// 4.par.3 - Mark 'assigned', the function-parameter, during destructuring.
 6674.     22
 6675.     22                    true                // assigned
 6676.     22                );
 6677.     22                advance(token_nxt.id);
 6678.     22                return;
 6679.   3575            }
 6680.   3575            name_declare(
 6681.   3575                scope_declared,         // scope_declared
 6682.   3575                role,                   // role
 6683.   3575                readonly,               // readonly
 6684.   3575                sub_list,               // name_list
 6685.   3575                name,                   // name
 6686.   3575
 6687.   3575// 3.var.3 - Mark 'assigned', the variable, during destructuring.
 6688.   3575// 4.par.3 - Mark 'assigned', the function-parameter, during destructuring.
 6689.   3575
 6690.   3575                true                    // assigned
 6691.   3575            );
 6692.   3575            if (token_nxt.id === "=") {
 6693.    131                optional = the_function_toplevel && token_now;
 6694.    131                advance("=");
 6695.    131                if (!the_function_toplevel) {
 6696.    131                    the_destructure.open = true;
 6697.    131                }
 6698.    131                name.expression = parse_expression(0);
 6699.    131                if (is_assignment) {
 6700.    131
 6701.    131// PR-514 - Bugfix - No <post_s_var> walks a default in '[aa = bb] = ...', so
 6702.    131// 'bb' was never used. It is pushed wrapped in an array, which has no <arity>,
 6703.    131// so <prefix_lbracket> walks it and never looks it up as a target.
 6704.    131
 6705.    131// test_cause:
 6706.    131// [";[aa=0]=0", "name_parse", "(live)", "", 0]
 6707.    131
 6708.    131                    name_list.push([name.expression]);
 6709.    131                }
 6710.    131
 6711.    131// test_cause:
 6712.    131// ["function aa([aa=aa]){}", "name_parse", "(live)", "", 0]
 6713.    131// ["function aa({aa=aa}){}", "name_parse", "(live)", "", 0]
 6714.    131// ["let[aa=bb]=0;let bb", "name_parse", "(live)", "", 0]
 6715.    131// ["let{aa=bb}=0;let bb", "name_parse", "(live)", "", 0]
 6716.    131
 6717.    131                return;
 6718.   3444            }
 6719.   3444            if (optional) {
 6720.      2
 6721.      2// test_cause:
 6722.      2// ["function aa(aa=0,bb){}", "name_parse", "required_a_optional_b", "aa", 18]
 6723.      2
 6724.      2                warn("required_a_optional_b", name, name.id, optional.id);
 6725.      2            }
 6726.   4017        }
 6727.   3982        while (true) {
 6728.   3982            if (!is_lbrace && !the_function_toplevel && token_nxt.id === ",") {
 6729.   3982
 6730.   3982// test_cause:
 6731.   3982// ["([,aa])=>0", "prefix_destructure", "(live)", "", 0]
 6732.   3982// [";[,aa]=0", "prefix_destructure", "(live)", "", 0]
 6733.   3982// ["let[,aa]=0", "prefix_destructure", "(live)", "", 0]
 6734.   3982
 6735.   3982                advance(",");
 6736.   3982            }
 6737.   3982            if (the_function_toplevel) {
 6738.   3982                the_function.parameter_count += 1;
 6739.   3982            }
 6740.   3982
 6741.   3982// test_cause:
 6742.   3982// ["(,aa)=>0", "name_parse", "expected_identifier_a", ",", 2]
 6743.   3982
 6744.   3982            if (name_parse()) {
 6745.   3982
 6746.   3982// Break early from ellipsis.
 6747.   3982
 6748.   3982                if (the_function_toplevel) {
 6749.   3982                    the_function.parameter_rest = true;
 6750.   3982                }
 6751.   3982                break;
 6752.   3982            }
 6753.   3982            if (token_nxt.id !== ",") {
 6754.   3982                break;
 6755.   3982            }
 6756.   3982            advance(",");
 6757.   3982        }
 6758.   2215        name_list.push(...sub_list);
 6759.   2215        if (the_function_toplevel) {
 6760.   1715            return the_destructure;
 6761.   1715        }
 6762.    500        if (is_lbrace) {
 6763.    342
 6764.    342// test_cause:
 6765.    342// ["
 6766.    342// function aa({bb,aa}){}
 6767.    342// ", "check_ordered", "expected_a_b_before_c_d", "aa", 17]
 6768.    342// ["let{bb,aa}=0", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
 6769.    342
 6770.    342// PR-501 - Fix false-warning about ordering in nested-object-destructuring.
 6771.    342
 6772.    342            check_ordered(role, sub_list);
 6773.    342            advance("}");
 6774.    342            return the_destructure;
 6775.    342        }
 6776.    158        advance("]");
 6777.    158        return the_destructure;
 6778.    158    }
 6779.    994
 6780.    104    function prefix_ellipsis() {
 6781.    104        let after_ellipsis;
 6782.    104        advance("...");
 6783.    104        after_ellipsis = parse_expression(0);
 6784.    104        after_ellipsis.ellipsis = true;
 6785.    104        return after_ellipsis;
 6786.    104    }
 6787.    994
 6788.      2    function prefix_fart() {
 6789.      2
 6790.      2// test_cause:
 6791.      2// [" =>0", "prefix_fart", "expected_a_before_b", "=>", 2]
 6792.      2// ["=>0", "prefix_fart", "expected_a_before_b", "=>", 1]
 6793.      2
 6794.      2        return stop("expected_a_before_b", token_now, "()", "=>");
 6795.      2    }
 6796.    994
 6797.   2368    function prefix_function(the_function, mode_fart, mode_fart_unwrapped) {
 6798.   2342        const name = !mode_fart && token_nxt.identifier && token_nxt;
 6799.   2368
 6800.   2368// PR-504 - Change scope from scope_function to scope_block:
 6801.   2368// - function-declaration
 6802.   2368
 6803.   2368        let scope_declared = scope_block;
 6804.   2172        the_function = the_function || token_now;
 6805.   2368        the_function.scope_name = {
 6806.   2368            context: empty(),
 6807.   2368            name_only: true
 6808.   2368        };
 6809.     26        if (mode_fart) {
 6810.     26            the_function.arity = "binary";
 6811.     26        }
 6812.   1249        if (the_function.arity === "statement") {
 6813.   1249
 6814.   1249// A function statement must have a name that will be in the parent's scope.
 6815.   1249
 6816.   1249            if (!token_nxt.identifier) {
 6817.   1249
 6818.   1249// test_cause:
 6819.   1249// ["function(){}", "prefix_function", "expected_identifier_a", "(", 9]
 6820.   1249
 6821.   1249                return stop("expected_identifier_a", token_nxt);
 6822.   1249            }
 6823.   1249
 6824.   1249            if (scope_function.switch > 0 && scope_block.function_body) {
 6825.   1249
 6826.   1249// PR-514 - Warn a function-declaration directly in a case, as ESLint
 6827.   1249// no-case-declarations does. One nested in a block of the case already warns
 6828.   1249// unexpected_a in <pre_s_function>.
 6829.   1249
 6830.   1249// test_cause:
 6831.   1249// ["
 6832.   1249// switch(0){case 0:function aa(){}}
 6833.   1249// ", "prefix_function", "var_switch", "function", 18]
 6834.   1249
 6835.   1249                warn("var_switch", the_function);
 6836.   1249            }
 6837.   1249        } else {
 6838.   1119
 6839.   1119// A function expression may have an optional name.
 6840.   1119
 6841.   1119// PR-514 - Bugfix - Declare the name in <scope_name>, outside the function as
 6842.   1119// in the spec, so a 'var' of that name in the body is a new binding.
 6843.   1119
 6844.   1119            scope_declared = the_function.scope_name;
 6845.   2367        }
 6846.   2367        if (name) {
 6847.   1281            advance();
 6848.   1281            name_declare(
 6849.   1281
 6850.   1281// 2.fun.1 - Mark 'declared', the function-name, during function-declaration.
 6851.   1281
 6852.   1281                scope_declared,         // scope_declared
 6853.   1281                "variable",             // role
 6854.   1281
 6855.   1281// 2.fun.4 - Mark 'readonly', the function-name, during function-declaration.
 6856.   1281
 6857.   1281                true,                   // readonly
 6858.   1281                [],                     // name_list
 6859.   1281                name,                   // name
 6860.   1281
 6861.   1281// 2.fun.3 - Mark 'assigned', the function-name, during function-declaration.
 6862.   1281
 6863.   1281                true                    // assigned
 6864.   1281            );
 6865.   1281
 6866.   1281// 2.fun.2 - Mark 'alive', the function-name, during function-declaration.
 6867.   1281
 6868.   1281            name.alive = true;
 6869.   2367        }
 6870.   2367
 6871.   2367// Give the function properties for storing its names and for observing the
 6872.   2367// depth of loops and switches.
 6873.   2367
 6874.   2367        the_function.async = the_function.async || 0;
 6875.   2368        the_function.finally = 0;
 6876.   2368        the_function.level = scope_function.level + 1;
 6877.   2368        the_function.loop = 0;
 6878.   2368
 6879.   2368// PR-516 - Bugfix - Keep the name <property_parse> gives a method or accessor,
 6880.   2368// 'aa' or 'get aa'. Else <anon> named it after the previous identifier.
 6881.   2368
 6882.   2368        the_function.name = (
 6883.   1086            name ||
 6884.   1086            the_function.name ||
 6885.   1066            (
 6886.   1066                mode_fart_unwrapped
 6887.   1066                ? "anonymous"
 6888.   1066                : anon
 6889.   1066            )
 6890.   2368        );
 6891.   2368        the_function.parameter_count = Number(Boolean(mode_fart_unwrapped));
 6892.   2368        the_function.signature = (
 6893.   2368            mode_fart_unwrapped
 6894.      3            ? token_prv.id
 6895.   2364            : "("
 6896.   2368        );
 6897.   2368        the_function.switch = 0;
 6898.   2368        the_function.try = 0;
 6899.   2368
 6900.   2368// PR-384 - Relax warning "function_in_loop".
 6901.   2368//
 6902.   2368//         if (scope_function.loop > 0) {
 6903.   2368
 6904.   2368// // test_cause:
 6905.   2368// // ["while(0){aa.map(()=>0);}", "parse_fart", "function_in_loop", "=>", 19]
 6906.   2368//
 6907.   2368//             warn("function_in_loop", the_function);
 6908.   2368//         }
 6909.   2368
 6910.   2368// PR-504 - Add hidden scope_block for:
 6911.   2368// - function-parameter
 6912.   2368
 6913.   2368// Push the current function context and establish a new one.
 6914.   2368
 6915.   2368        scope_block = scope_block_push(the_function.scope_name, false);
 6916.   2368        scope_block = scope_block_push(the_function, true);
 6917.   2368        scope_function = scope_function_push(the_function, true);
 6918.   2368
 6919.   2368// Parse the parameter list.
 6920.   2368
 6921.   2341        if (!mode_fart) {
 6922.   2341            advance("(");
 6923.   2341            token_now.arity = "function";
 6924.   2367        }
 6925.   2367        the_function.name_list = [];    // 2. name_list for "function (aa)"
 6926.   2367        if (mode_fart_unwrapped) {
 6927.      3
 6928.      3// test_cause:
 6929.      3// [" aa=>0", "prefix_function", "wrap_fart_parameter", "aa", 2]
 6930.      3// ["aa=>0", "prefix_function", "wrap_fart_parameter", "aa", 1]
 6931.      3
 6932.      3            warn("wrap_fart_parameter", token_prv);
 6933.      3            name_declare(
 6934.      3
 6935.      3// 4.par.1 - Mark 'declared', the function-parameter, if unwrapped.
 6936.      3
 6937.      3                scope_function,         // scope_declared
 6938.      3                "parameter",            // role
 6939.      3                false,                  // readonly
 6940.      3                the_function.name_list, // name_list
 6941.      3                token_prv,              // name
 6942.      3
 6943.      3// 4.par.3 - Mark 'assigned', the function-parameter, if unwrapped.
 6944.      3
 6945.      3                true                    // assigned
 6946.      3            );
 6947.   2364        } else {
 6948.   2364            const lparen = token_now;
 6949.   2364            let default_depth;
 6950.   2364            let default_from;
 6951.   2364            let default_megastring = false;
 6952.   2364            let depth = 0;
 6953.   2364            let signature = "";
 6954.   2364            let token_before;
 6955.   2364            if (token_nxt.id !== ")" && token_nxt.id !== "(end)") {
 6956.   2364
 6957.   2364// PR-500 - Unify ES2015-destructure-logic. - function ([aa]) {...}
 6958.   2364
 6959.   2364                prefix_destructure(
 6960.   2364
 6961.   2364// 4.par.1 - Mark 'declared', the function-parameter, during destructuring.
 6962.   2364
 6963.   2364                    scope_function,     // scope_declared
 6964.   2364                    "parameter",        // role
 6965.   2364                    false,              // readonly
 6966.   2364                    the_function.name_list,     // name_list
 6967.   2364                    the_function,       // the_function
 6968.   2364                    true                // the_function_toplevel
 6969.   2364                );
 6970.   2364            }
 6971.   2364            advance(")");
 6972.   2364
 6973.   2364// PR-516 - Bugfix - Copy <signature> from the source text of each token but
 6974.   2364// comments, so it keeps default values. A space joins tokens apart in the
 6975.   2364// source, except after an opener or before a comma or closer. A default value
 6976.   2364// over 40 characters shows as an ellipsis, and so does one holding a
 6977.   2364// megastring, whose tokens carry columns that do not match the source.
 6978.   2364
 6979.  10033            for (const token of token_list.slice(lparen.nr, token_now.nr + 1)) {
 6980.  10033                if (token.id !== "(comment)") {
 6981.  10033                    const piece = (
 6982.  10033                        (
 6983.  10033                            token_before !== undefined &&
 6984.  10033                            (
 6985.  10033                                token_before.line !== token.line ||
 6986.  10033                                token_before.thru < token.from
 6987.  10033                            ) &&
 6988.  10033                            !["(", "[", "{"].includes(token_before.id) &&
 6989.  10033                            ![")", ",", "]", "}"].includes(token.id)
 6990.  10033                        )
 6991.  10033                        ? " "
 6992.  10033                        : ""
 6993.  10033                    ) + line_list[token.line].line_source.slice(
 6994.  10033                        token.from,
 6995.  10033                        token.thru
 6996.  10033                    );
 6997.  10033                    if ([")", "]", "}"].includes(token.id)) {
 6998.  10033                        depth -= 1;
 6999.  10033                    }
 7000.  10033
 7001.  10033// A default value ends at a comma or a closer of its own depth.
 7002.  10033
 7003.  10033                    if (
 7004.  10033                        default_from !== undefined &&
 7005.  10033                        (
 7006.  10033                            depth < default_depth ||
 7007.  10033                            (depth === default_depth && token.id === ",")
 7008.  10033                        )
 7009.  10033                    ) {
 7010.  10033                        if (
 7011.  10033                            default_megastring ||
 7012.  10033                            signature.slice(default_from).trim().length > 40
 7013.  10033                        ) {
 7014.  10033
 7015.  10033// test_cause:
 7016.  10033// ["function aa(bb=`cc`){return bb;}", "prefix_function", "(live)", "", 0]
 7017.  10033
 7018.  10033                            signature = (
 7019.  10033                                signature.slice(0, default_from) + " \u2026"
 7020.  10033                            );
 7021.  10033                        }
 7022.  10033                        default_from = undefined;
 7023.  10033                        default_megastring = false;
 7024.  10033                    }
 7025.  10033                    signature += piece;
 7026.  10033                    if (token.id === "=" && default_from === undefined) {
 7027.  10033                        default_depth = depth;
 7028.  10033                        default_from = signature.length;
 7029.  10033                    }
 7030.  10033                    if (token.id === "`" && default_from !== undefined) {
 7031.  10033
 7032.  10033// test_cause:
 7033.  10033// ["function aa(bb=`cc`){return bb;}", "prefix_function", "(live)", "", 0]
 7034.  10033
 7035.  10033                        default_megastring = true;
 7036.  10033                    }
 7037.  10033                    if (["${", "(", "[", "{"].includes(token.id)) {
 7038.  10033                        depth += 1;
 7039.  10033                    }
 7040.  10033                    token_before = token;
 7041.  10033                }
 7042.  10033            }
 7043.   2364            the_function.signature = signature;
 7044.   2364        }
 7045.   2357        if (mode_fart && !mode_fart_unwrapped) {
 7046.     22            advance("=>");
 7047.   2357        }
 7048.   2357        if (mode_fart && token_nxt.id !== "{") {
 7049.     18
 7050.     18// The function's body is an expression.
 7051.     18
 7052.     18// PR-384 - Bugfix - Fixes issue #379 - warn against naked-statement in fart.
 7053.     18
 7054.     18            if (
 7055.     18                syntax_dict[token_nxt.id] &&
 7056.     18                syntax_dict[token_nxt.id].fud_stmt
 7057.     18            ) {
 7058.     18
 7059.     18// test_cause:
 7060.     18// ["()=>delete aa", "prefix_function", "unexpected_a_after_b", "=>", 5]
 7061.     18
 7062.     18                return stop(
 7063.     18                    "unexpected_a_after_b",
 7064.     18                    token_nxt,
 7065.     18                    token_nxt.id,
 7066.     18                    "=>"
 7067.     18                );
 7068.     18            }
 7069.     18            the_function.expression = parse_expression(0);
 7070.   2339        } else if (mode_fart) {
 7071.   2339
 7072.   2339// The function's body is a block.
 7073.   2339
 7074.   2339            if (!option_dict.fart) {
 7075.   2339
 7076.   2339// test_cause:
 7077.   2339// ["()=>{}", "prefix_function", "use_function_not_fart", "=>", 3]
 7078.   2339
 7079.   2339                warn("use_function_not_fart", the_function);
 7080.   2339            }
 7081.   2339            the_function.block = block("body");
 7082.   2339        } else {
 7083.   2339            the_function.block = block("body");
 7084.   2339            if (
 7085.   2339                the_function.arity === "statement" &&
 7086.   2339                token_nxt.line === token_now.line &&
 7087.   2339                !option_dict.white
 7088.   2339            ) {
 7089.   2339
 7090.   2339// PR-503 - Fix jslint unable to continue parsing 'function aa(){}0'.
 7091.   2339
 7092.   2339// test_cause:
 7093.   2339// ["function aa(){}0", "prefix_function", "expected_line_break_a_b", "0", 16]
 7094.   2339// ["function aa(){}0;", "prefix_function", "expected_line_break_a_b", "0", 16]
 7095.   2339
 7096.   2339                warn(
 7097.   2339                    "expected_line_break_a_b",
 7098.   2339                    token_nxt,
 7099.   2339                    artifact(token_now),
 7100.   2339                    artifact(token_nxt)
 7101.   2339                );
 7102.   2339            }
 7103.   2339            if (
 7104.   2339                token_nxt.id === "." ||
 7105.   2339                token_nxt.id === "?."
 7106.   2339
 7107.   2339// PR-459 - Allow destructuring-assignment after function-definition.
 7108.   2339
 7109.   2339                // || token_nxt.id === "["
 7110.   2339            ) {
 7111.   2339
 7112.   2339// test_cause:
 7113.   2339// [" function aa(){}\n .aa", "prefix_function", "unexpected_a", ".", 2]
 7114.   2339// ["function aa(){}\n.aa", "prefix_function", "unexpected_a", ".", 1]
 7115.   2339// ["function aa(){}\n?.aa", "prefix_function", "unexpected_a", "?.", 1]
 7116.   2339
 7117.   2339                warn("unexpected_a");
 7118.   2339            }
 7119.   2354        }
 7120.   2354
 7121.   2354// Check functions are ordered.
 7122.   2354
 7123.   2354// PR-514 - Bugfix - Check only function-declarations, since a named
 7124.   2354// function-expression is not hoisted. Check an arrow-function's block-body too.
 7125.   2354
 7126.   2354// test_cause:
 7127.   2354// ["
 7128.   2354// ()=>{function bb(){}function aa(){}}
 7129.   2354// ", "check_ordered", "expected_a_b_before_c_d", "aa", 30]
 7130.   2354
 7131.   2354        check_ordered(
 7132.   2354            "function",
 7133.   2354            function_list.slice(
 7134.   2354                function_list.indexOf(the_function) + 1
 7135.   2841            ).map(function ({
 7136.   2841                arity,
 7137.   2841                level,
 7138.   2841                name
 7139.   2841            }) {
 7140.   2841                return (
 7141.   2354                    arity === "statement" &&
 7142.   2354                    level === the_function.level + 1 &&
 7143.   2354                    name
 7144.   2841                );
 7145.   2841            }).filter(function (name) {
 7146.   2827                return option_dict.beta && name && name.id;
 7147.   2841            })
 7148.   2354        );
 7149.   2354
 7150.   2354// Restore the previous context.
 7151.   2354
 7152.   2354        scope_block = scope_block_pop();
 7153.   2354        scope_block = scope_block_pop();
 7154.   2354        scope_function = scope_function_pop();
 7155.   2354        return the_function;
 7156.   2354    }
 7157.    994
 7158.    690    function prefix_lbrace() {
 7159.    690
 7160.    690// PR-514 - Bugfix - <seen> maps a property-name to true, or to false if only
 7161.    690// an accessor has it. Accessor-keys like 'get aa' live apart in
 7162.    690// <seen_getset>, so a string-key named get aa cannot collide with them.
 7163.    690
 7164.    690        const seen = empty();
 7165.    690        const seen_getset = empty();
 7166.    690        const the_brace = token_now;
 7167.   2182        function property_parse() {
 7168.   2182            let extra;
 7169.   2182            let full;
 7170.   2182            let id;
 7171.   2182            let name = token_nxt;
 7172.   2182            let the_colon;
 7173.   2182            let value;
 7174.    157            if (!name.identifier && name.id === "`") {
 7175.      1
 7176.      1// test_cause:
 7177.      1// ["aa={`aa`:0}", "property_parse", "unexpected_a", "`", 5]
 7178.      1
 7179.      1                return stop("unexpected_a", name);
 7180.   2181            }
 7181.   2181
 7182.   2181// Issue #401 - Add ES2018-syntax for object-literal-spread-operator.
 7183.   2181
 7184.   2181            if (!name.identifier && token_nxt.id === "...") {
 7185.     65
 7186.     65// test_cause:
 7187.     65// ["aa={...aa}", "property_parse", "(live)", "", 0]
 7188.     65
 7189.     65                value = prefix_ellipsis();
 7190.     65                return value;
 7191.   2116            }
 7192.   2116            advance();
 7193.   2116            if (
 7194.   2116                (name.id === "get" || name.id === "set") &&
 7195.     19                token_nxt.identifier
 7196.     18            ) {
 7197.     18                if (!option_dict.getset) {
 7198.     18
 7199.     18// test_cause:
 7200.     18// ["aa={get aa(){}}", "property_parse", "unexpected_a", "get", 5]
 7201.     18
 7202.     18                    warn("unexpected_a", name);
 7203.     18                }
 7204.     18                extra = name.id;
 7205.     18                full = extra + " " + token_nxt.id;
 7206.     18                name.getset = true;
 7207.     18                name = token_nxt;
 7208.     18                advance();
 7209.     18                id = survey(name);
 7210.     18                if (seen_getset[full] === true || seen[id] === true) {
 7211.     18
 7212.     18// test_cause:
 7213.     18// ["aa={get aa(){},get aa(){}}", "property_parse", "duplicate_a", "aa", 20]
 7214.     18
 7215.     18                    warn("duplicate_a", name);
 7216.     18                }
 7217.     18                seen[id] = false;
 7218.     18                seen_getset[full] = true;
 7219.   2098            } else {
 7220.   2098                id = survey(name);
 7221.   2098                if (typeof seen[id] === "boolean") {
 7222.   2098
 7223.   2098// test_cause:
 7224.   2098// ["aa={aa,aa}", "property_parse", "duplicate_a", "aa", 8]
 7225.   2098
 7226.   2098                    warn("duplicate_a", name);
 7227.   2098                }
 7228.   2098                seen[id] = true;
 7229.   2115            }
 7230.   2115            if (!name.identifier) {
 7231.     90
 7232.     90// test_cause:
 7233.     90// ["aa={\"aa\":0}", "property_parse", "(live)", "", 0]
 7234.     90
 7235.     90                advance(":");
 7236.     90                value = parse_expression(0);
 7237.     90                value.name_alias = name;
 7238.     90                return value;
 7239.   2025            }
 7240.   2025            if (token_nxt.id === "}" || token_nxt.id === ",") {
 7241.    679                if (typeof extra === "string") {
 7242.    679
 7243.    679// test_cause:
 7244.    679// ["aa={get aa}", "property_parse", "(live)", "", 0]
 7245.    679
 7246.    679                    advance("(");
 7247.    679                }
 7248.    679                value = parse_expression(Infinity, true);
 7249.   1346            } else if (token_nxt.id === "(") {
 7250.   1346
 7251.   1346// test_cause:
 7252.   1346// ["aa={aa()}", "property_parse", "(live)", "", 0]
 7253.   1346// ["aa={get aa(){}}", "property_parse", "(live)", "", 0]
 7254.   1346
 7255.   1346// PR-516 - Bugfix - Name an accessor 'get aa' in the report, not 'get'.
 7256.   1346
 7257.   1346                value = prefix_function(
 7258.   1346                    {
 7259.   1346                        arity: "unary",
 7260.   1346                        from: name.from,
 7261.   1346                        id: "function",
 7262.   1346                        line: name.line,
 7263.   1346                        name: (
 7264.   1346                            typeof extra === "string"
 7265.   1346                            ? full
 7266.   1346                            : id
 7267.   1346                        ),
 7268.   1346                        thru: name.from
 7269.   1346                    },
 7270.   1346                    false,
 7271.   1346                    false
 7272.   1346                );
 7273.   1346            } else {
 7274.   1346                if (typeof extra === "string") {
 7275.   1346
 7276.   1346// test_cause:
 7277.   1346// ["aa={get aa.aa}", "property_parse", "(live)", "", 0]
 7278.   1346
 7279.   1346                    advance("(");
 7280.   1346                }
 7281.   1346                the_colon = token_nxt;
 7282.   1346                advance(":");
 7283.   1346                value = parse_expression(0);
 7284.   1346                if (
 7285.   1346                    value.id === name.id &&
 7286.   1346                    value.id !== "function"
 7287.   1346                ) {
 7288.   1346
 7289.   1346// test_cause:
 7290.   1346// ["aa={aa:aa}", "property_parse", "unexpected_a", ": aa", 7]
 7291.   1346
 7292.   1346                    warn("unexpected_a", the_colon, ": " + name.id);
 7293.   1346                }
 7294.   2022            }
 7295.   2022            value.name_alias = name;
 7296.   2022            if (typeof extra === "string") {
 7297.     16                value.extra = extra;
 7298.   2022            }
 7299.   2022            return value;
 7300.   2022        }
 7301.    690        the_brace.expression = [];
 7302.    625        if (token_nxt.id !== "}") {
 7303.    625
 7304.    625// Parse/loop through each property in {...}.
 7305.    625
 7306.   2182            while (true) {
 7307.   2182                the_brace.expression.push(property_parse());
 7308.   2182                if (token_nxt.id !== ",") {
 7309.   2182                    break;
 7310.   2182                }
 7311.   2182                advance(",");
 7312.   2182                if (token_nxt.id === "}") {
 7313.   2182
 7314.   2182// test_cause:
 7315.   2182// ["aa={aa:0,}", "prefix_lbrace", "unexpected_a", ",", 9]
 7316.   2182
 7317.   2182                    warn("unexpected_a", token_now);
 7318.   2182                    break;
 7319.   2182                }
 7320.   2182            }
 7321.    685        }
 7322.    685
 7323.    685// test_cause:
 7324.    685// ["aa={bb,aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
 7325.    685
 7326.    685        check_ordered(
 7327.    685            "property",
 7328.   2177            the_brace.expression.map(function ({
 7329.   2177                name_alias
 7330.   2177            }) {
 7331.   2177                return name_alias;
 7332.   2177            })
 7333.    685        );
 7334.    685        advance("}");
 7335.    685        return the_brace;
 7336.    685    }
 7337.    994
 7338.    936    function prefix_lbracket() {
 7339.    936        let element;
 7340.    936        let the_token = token_now;
 7341.    936        the_token.expression = [];
 7342.     24        if (the_token.assignment) {
 7343.     24            the_token = token_now.assignment;
 7344.     24            the_token.name_list = [];   // 3. name_list for "[aa] = ..."
 7345.     24
 7346.     24// PR-500 - Unify ES2015-destructure-logic. - [aa] = ...;
 7347.     24
 7348.     24            element = prefix_destructure(
 7349.     24                undefined,              // scope_declared
 7350.     24                "variable",             // role
 7351.     24                false,                  // readonly
 7352.     24                the_token.name_list,    // name_list
 7353.     24                undefined,              // the_function
 7354.     24                false                   // the_function_toplevel
 7355.     24            );
 7356.     24
 7357.     24// PR-514 - Walk defaults as expressions, and leave only variables in
 7358.     24// <name_list> for <post_a_assignment> to look up.
 7359.     24
 7360.     66            element.expression = the_token.name_list.filter(function (name) {
 7361.     66                return name.arity !== "variable";
 7362.     66            });
 7363.     66            the_token.name_list = the_token.name_list.filter(function (name) {
 7364.     66                return name.arity === "variable";
 7365.     66            });
 7366.     24            advance("=");
 7367.     24            symbol("=").led_infix(element);
 7368.     24            return the_token;
 7369.    912        }
 7370.    912        if (token_nxt.id !== "]") {
 7371.    537
 7372.    537// Parse/loop through each element in [...].
 7373.    537
 7374.   1755            while (true) {
 7375.   1755                if (!state.mode_json && token_nxt.id === "...") {
 7376.   1755
 7377.   1755// test_cause:
 7378.   1755// ["aa=[...aa]", "prefix_lbracket", "(live)", "", 0]
 7379.   1755
 7380.   1755                    the_token.expression.push(prefix_ellipsis());
 7381.   1755
 7382.   1755// Issue #401 - Regression - Allow multiple-ellipsis in array-literal.
 7383.   1755
 7384.   1755                } else {
 7385.   1755                    the_token.expression.push(parse_expression(10));
 7386.   1755                }
 7387.   1755                if (token_nxt.id !== ",") {
 7388.   1755                    break;
 7389.   1755                }
 7390.   1755                advance(",");
 7391.   1755                if (token_nxt.id === "]") {
 7392.   1755
 7393.   1755// test_cause:
 7394.   1755// ["aa=[0,]", "prefix_lbracket", "unexpected_a", ",", 6]
 7395.   1755
 7396.   1755                    warn("unexpected_a", token_now);
 7397.   1755                    break;
 7398.   1755                }
 7399.   1755            }
 7400.    912        }
 7401.    912        advance("]");
 7402.    912        return the_token;
 7403.    912    }
 7404.    994
 7405.   1952    function prefix_lparen() {
 7406.   1952        let the_paren = token_now;
 7407.   1952        let the_value;
 7408.   1952
 7409.   1952// PR-385 - Bugfix - Fixes issue #382 - failure to detect destructured fart.
 7410.   1952
 7411.     20        if (token_now.fart) {
 7412.     20            return prefix_function(token_now.fart, true, false);
 7413.   1932        }
 7414.   1932
 7415.   1932// test_cause:
 7416.   1932// ["(0)", "prefix_lparen", "(live)", "", 0]
 7417.   1932
 7418.   1932        the_value = parse_expression(0);
 7419.   1932        if (the_value.wrapped === true) {
 7420.      2
 7421.      2// test_cause:
 7422.      2// [" ((0))", "prefix_lparen", "unexpected_a", "(", 2]
 7423.      2// ["((0))", "prefix_lparen", "unexpected_a", "(", 1]
 7424.      2
 7425.      2            warn("unexpected_a", the_paren);
 7426.   1932        }
 7427.   1932        the_value.wrapped = true;
 7428.   1932        advance(")", the_paren);
 7429.   1932        return the_value;
 7430.   1932    }
 7431.    994
 7432.    170    function prefix_new() {
 7433.    170        const the_new = token_now;
 7434.    170        let right;
 7435.    170        right = parse_expression(160);
 7436.    170
 7437.    170// PR-514 - Bugfix - In 'new aa`bb`()' the tagged-megastring belongs to the
 7438.    170// callee, 'new (aa`bb`)()', but '`' shares lbp 160 with the call's '(', so rbp
 7439.    170// 160 stops before it. Parse it, and any member after it, into the callee.
 7440.    170
 7441.      3        while (token_nxt.id === "`") {
 7442.      3            advance("`");
 7443.      3            right = infix_grave(right);
 7444.      3            while ([".", "?.", "["].includes(token_nxt.id)) {
 7445.      3                advance();
 7446.      3                right = syntax_dict[token_now.id].led_infix(right);
 7447.      3            }
 7448.      3        }
 7449.      2        if (optional_chain(right)) {
 7450.      2
 7451.      2// PR-514 - Bugfix - Rbp 160 lets an optional-chain into the callee, since '?.'
 7452.      2// binds at 170.
 7453.      2
 7454.      2// test_cause:
 7455.      2// ["new aa?.aa()", "prefix_new", "unexpected_a", "?.", 7]
 7456.      2
 7457.      2            warn("unexpected_a", optional_chain(right), "?.");
 7458.      2        }
 7459.      2        if (token_nxt.id !== "(") {
 7460.      2
 7461.      2// test_cause:
 7462.      2// ["new aa", "prefix_new", "expected_a_before_b", "(end)", 6]
 7463.      2
 7464.      2            warn("expected_a_before_b", token_nxt, "()", artifact());
 7465.      2        }
 7466.    170        the_new.expression = right;
 7467.    170        return the_new;
 7468.    170    }
 7469.    994
 7470.    919    function prefix_tick(mode_tagged) {
 7471.    919        const the_tick = token_now;
 7472.    906        if (!mode_tagged) {
 7473.    906            warning_list.push(...the_tick.warning_list_untagged);
 7474.    906        }
 7475.    919        the_tick.value = [];
 7476.    919        the_tick.expression = [];
 7477.    919        if (token_nxt.id !== "`") {
 7478.    919
 7479.    919// Parse/loop through each token in `${...}`.
 7480.    919
 7481.   1784            while (true) {
 7482.   1784                advance("(string)");
 7483.   1784                the_tick.value.push(token_now);
 7484.   1784                if (token_nxt.id !== "${") {
 7485.   1784                    break;
 7486.   1784                }
 7487.   1784                advance("${");
 7488.   1784
 7489.   1784// test_cause:
 7490.   1784// ["let aa=`${}`", "prefix_tick", "(live)", "", 0]
 7491.   1784
 7492.   1784                the_tick.expression.push(parse_expression(0));
 7493.   1784                advance("}");
 7494.   1784            }
 7495.    917        }
 7496.    917        advance("`");
 7497.    917        return the_tick;
 7498.    917    }
 7499.    994
 7500.      4    function prefix_void() {
 7501.      4        const the_void = token_now;
 7502.      4
 7503.      4// test_cause:
 7504.      4// [" void 0", "prefix_void", "unexpected_a", "void", 2]
 7505.      4// ["void 0", "prefix_void", "unexpected_a", "void", 1]
 7506.      4// ["void", "prefix_void", "unexpected_a", "void", 1]
 7507.      4
 7508.      4        warn("unexpected_a", the_void);
 7509.      4
 7510.      4// PR-514 - Bugfix - Parse the operand at rbp 150, like every unary operator,
 7511.      4// since the spec reads 'void UnaryExpression'. At rbp 0, 'void aa ** 2', a
 7512.      4// SyntaxError, parsed as 'void (aa ** 2)'.
 7513.      4
 7514.      4        the_void.expression = parse_expression(150);
 7515.      4        return the_void;
 7516.      4    }
 7517.    994
 7518.  17805    function semicolon() {
 7519.  17805
 7520.  17805// Try to match a semicolon.
 7521.  17805
 7522.  17408        if (token_nxt.id === ";") {
 7523.  17408            advance(";");
 7524.  17408        } else {
 7525.    397
 7526.    397// test_cause:
 7527.    397// [" 0//c", "semicolon", "expected_a_after_b", "0", 2]
 7528.    397// ["0", "semicolon", "expected_a_after_b", "0", 1]
 7529.    397
 7530.    397            warn_at(
 7531.    397                "expected_a_after_b",
 7532.    397                token_now.line,
 7533.    397
 7534.    397// <thru> is EXCLUSIVE - one past the token's last char - so it marked the
 7535.    397// character AFTER <b>. At end of line the clamp pulled it back onto <b> and
 7536.    397// hid that; off end of line it did not. <expected_a_after_b> exists so the
 7537.    397// message names the character the marker covers, so mark <b> itself.
 7538.    397
 7539.    397                token_now.thru - 1,
 7540.    397                ";",
 7541.    397                artifact(token_now)
 7542.    397            );
 7543.    397        }
 7544.  17805        anon = "anonymous";
 7545.  17805    }
 7546.    994
 7547.  22862    function stmt(id, fud_stmt) {
 7548.  22862
 7549.  22862// Create a statement.
 7550.  22862
 7551.  22862        const the_symbol = symbol(id);
 7552.  22862        the_symbol.fud_stmt = fud_stmt;
 7553.  22862        return the_symbol;
 7554.  22862    }
 7555.    994
 7556.   1199    function stmt_break() {
 7557.   1199        const the_break = token_now;
 7558.   1199        let the_label;
 7559.   1199        if (
 7560.   1192            (scope_function.loop < 1 && scope_function.switch < 1) ||
 7561.   1192            scope_function.finally > 0
 7562.      7        ) {
 7563.      7
 7564.      7// test_cause:
 7565.      7// [" break", "stmt_break", "unexpected_a", "break", 2]
 7566.      7// ["break", "stmt_break", "unexpected_a", "break", 1]
 7567.      7
 7568.      7            warn("unexpected_a", the_break);
 7569.      7        }
 7570.   1199        the_break.disrupt = true;
 7571.     11        if (token_nxt.identifier && token_now.line === token_nxt.line) {
 7572.     28            block_stack.some(function (scope_block) {
 7573.     28
 7574.     28// PR-514 - Bugfix - Stop at the function boundary, since 'break aa' cannot
 7575.     28// reach a label in an enclosing function, which is a SyntaxError.
 7576.     28
 7577.     11                if (scope_block === scope_function) {
 7578.     11                    return true;
 7579.     25                }
 7580.     25                the_label = scope_block.context[token_nxt.id];
 7581.     25                if (the_label?.role !== "label") {
 7582.     17                    the_label = undefined;
 7583.     25                }
 7584.     25                if (the_label) {
 7585.     11                    the_label.used = true;
 7586.     11                    return true;
 7587.     11                }
 7588.     28            });
 7589.     11            if (!the_label) {
 7590.     11
 7591.     11// test_cause:
 7592.     11// ["
 7593.     11// aa:while(0){(function(){while(0){break aa}}())}
 7594.     11// ", "stmt_break", "not_label_a", "aa", 40]
 7595.     11// ["aa:while(0){}break aa", "stmt_break", "not_label_a", "aa", 20]
 7596.     11// ["break aa", "stmt_break", "not_label_a", "aa", 7]
 7597.     11
 7598.     11                warn("not_label_a", token_nxt);
 7599.     11            }
 7600.     11            the_break.label_break = token_nxt;
 7601.     11            advance();
 7602.     11        }
 7603.   1199        semicolon();
 7604.   1199        return the_break;
 7605.   1199    }
 7606.    994
 7607.      3    function stmt_continue() {
 7608.      3        const the_continue = token_now;
 7609.      2        if (scope_function.loop < 1 || scope_function.finally > 0) {
 7610.      2
 7611.      2// test_cause:
 7612.      2// ["continue", "stmt_continue", "unexpected_a", "continue", 1]
 7613.      2// ["
 7614.      2// while(0){try{}finally{continue}}
 7615.      2// ", "stmt_continue", "unexpected_a", "continue", 23]
 7616.      2
 7617.      2            warn("unexpected_a", the_continue);
 7618.      2        }
 7619.      3        check_not_top_level(the_continue);
 7620.      3        the_continue.disrupt = true;
 7621.      3
 7622.      3// test_cause:
 7623.      3// ["
 7624.      3// function aa(){while(aa){continue;}}
 7625.      3// ", "stmt_continue", "unexpected_a", "continue", 25]
 7626.      3
 7627.      3        warn("unexpected_a", the_continue);
 7628.      3        semicolon();
 7629.      3        return the_continue;
 7630.      3    }
 7631.    994
 7632.      4    function stmt_debugger() {
 7633.      4        const the_debug = token_now;
 7634.      2        if (!option_dict.devel) {
 7635.      2
 7636.      2// test_cause:
 7637.      2// [" debugger", "stmt_debugger", "unexpected_a", "debugger", 2]
 7638.      2// ["debugger", "stmt_debugger", "unexpected_a", "debugger", 1]
 7639.      2
 7640.      2            warn("unexpected_a", the_debug);
 7641.      2        }
 7642.      4        semicolon();
 7643.      4        return the_debug;
 7644.      4    }
 7645.    994
 7646.     64    function stmt_delete() {
 7647.     64        const the_token = token_now;
 7648.     64        const the_value = parse_expression(0);
 7649.     64
 7650.     64// PR-514 - Bugfix - In 'delete aa[bb] || cc', the parse at rbp 0 swallows the
 7651.     64// '||'. Warn on the operator, not on a missing '.'. Rbp 150 would stop the
 7652.     64// lint on the leftover '|| cc'.
 7653.     64
 7654.     64        if (
 7655.      3            ["&&", "??", "||"].includes(the_value.id) &&
 7656.      3            [".", "?.", "["].includes(the_value.expression[0].id) &&
 7657.      3            the_value.expression[0].arity === "binary"
 7658.      3        ) {
 7659.      3
 7660.      3// test_cause:
 7661.      3// ["delete aa[aa]&&aa", "stmt_delete", "unexpected_a", "&&", 14]
 7662.      3// ["delete aa[aa]??aa", "stmt_delete", "unexpected_a", "??", 14]
 7663.      3// ["delete aa[aa]||aa", "stmt_delete", "unexpected_a", "||", 14]
 7664.      3
 7665.      3            warn("unexpected_a", the_value);
 7666.     61        } else if (
 7667.     61            ![".", "?.", "["].includes(the_value.id) ||
 7668.     61            the_value.arity !== "binary"
 7669.     61        ) {
 7670.     61
 7671.     61// test_cause:
 7672.     61// ["delete 0", "stmt_delete", "expected_a_b", "0", 8]
 7673.     61// ["delete 0;", "stmt_delete", "expected_a_b", "0", 8]
 7674.     61
 7675.     61            warn("expected_a_b", the_value, ".", artifact(the_value));
 7676.     61        }
 7677.     64        the_token.expression = the_value;
 7678.     64        semicolon();
 7679.     64        return the_token;
 7680.     64    }
 7681.    994
 7682.      9    function stmt_do() {
 7683.      9        const the_do = token_now;
 7684.      9        check_not_top_level(the_do);
 7685.      9        scope_function.loop += 1;
 7686.      9        the_do.block = block();
 7687.      9        advance("while");
 7688.      9        the_do.expression = condition();
 7689.      9        semicolon();
 7690.      2        if (the_do.block.disrupt === true) {
 7691.      2
 7692.      2// test_cause:
 7693.      2// ["function aa(){ do{break}while(0)}", "stmt_do", "weird_loop", "do", 16]
 7694.      2// ["function aa(){do{break}while(0)}", "stmt_do", "weird_loop", "do", 15]
 7695.      2
 7696.      2            warn("weird_loop", the_do);
 7697.      4        }
 7698.      4        scope_function.loop -= 1;
 7699.      4        return the_do;
 7700.      4    }
 7701.    994
 7702.     48    function stmt_export() {
 7703.     48        let export_list = [];
 7704.     48        let the_export = token_now;
 7705.     48        let the_id;
 7706.     48        let the_name;
 7707.     48        let the_thing;
 7708.     48
 7709.     48        the_export.expression = [];
 7710.     31        if (token_nxt.id === "default") {
 7711.     31            if (export_dict.default !== undefined) {
 7712.     31
 7713.     31// test_cause:
 7714.     31// ["
 7715.     31// export default 0;export default 0
 7716.     31// ", "stmt_export", "duplicate_a", "default", 25]
 7717.     31
 7718.     31                warn("duplicate_a");
 7719.     31            }
 7720.     31            advance("default");
 7721.     31            the_thing = parse_expression(0);
 7722.     31            if (
 7723.     31                the_thing.id !== "(" ||
 7724.     31                the_thing.expression[0].id !== "." ||
 7725.     31                the_thing.expression[0].expression.id !== "Object" ||
 7726.     31                the_thing.expression[0].name.id !== "freeze"
 7727.     31            ) {
 7728.     31
 7729.     31// test_cause:
 7730.     31// ["export default {}", "stmt_export", "freeze_exports", "{", 16]
 7731.     31
 7732.     31                warn("freeze_exports", the_thing);
 7733.     31
 7734.     31// PR-301 - Bugfix - Fixes issues #282 - optional-semicolon.
 7735.     31
 7736.     31            } else {
 7737.     31
 7738.     31// test_cause:
 7739.     31// ["
 7740.     31// export default Object.freeze({})
 7741.     31// ", "semicolon", "expected_a_after_b", ")", 32]
 7742.     31
 7743.     31                semicolon();
 7744.     31            }
 7745.     31            export_dict.default = the_thing;
 7746.     31            the_export.expression.push(the_thing);
 7747.     31        } else {
 7748.     17
 7749.     17// PR-439 - Add grammar for "export async function ...".
 7750.     17
 7751.     17            if (token_nxt.id === "function" || token_nxt.id === "async") {
 7752.     17
 7753.     17// test_cause:
 7754.     17// ["export async function aa(){}", "stmt_export", "freeze_exports", "async", 8]
 7755.     17// ["export function aa(){}", "stmt_export", "freeze_exports", "function", 8]
 7756.     17
 7757.     17                warn("freeze_exports");
 7758.     17                the_thing = parse_statement_single();
 7759.     17                the_name = the_thing.name;
 7760.     17                the_id = the_name.id;
 7761.     17                the_name.used = true;
 7762.     17
 7763.     17// PR-517 - deadcode-confirmed - This duplicate is never shown. An earlier
 7764.     17// export of <the_id> needs it declared at top level, so declaring it again
 7765.     17// above warns redefinition_a_b on the same token first, and <warn> drops a
 7766.     17// second warning on one token.
 7767.     17//
 7768.     17// deadcode-revive - Check for the duplicate before <parse_statement_single>
 7769.     17// declares the name, or let a token carry more than one warning.
 7770.     17//
 7771.     17// if (export_dict[the_id] !== undefined) {
 7772.     17//     warn("duplicate_a", the_name);
 7773.     17// }
 7774.     17
 7775.     17                export_dict[the_id] = the_thing;
 7776.     17                the_export.expression.push(the_thing);
 7777.     17                the_thing.statement = false;
 7778.     17                the_thing.arity = "unary";
 7779.     17            } else if (
 7780.     17                token_nxt.id === "var" ||
 7781.     17                token_nxt.id === "let" ||
 7782.     17                token_nxt.id === "const"
 7783.     17            ) {
 7784.     17
 7785.     17// test_cause:
 7786.     17// ["export const", "stmt_export", "unexpected_a", "const", 8]
 7787.     17// ["export let", "stmt_export", "unexpected_a", "let", 8]
 7788.     17// ["export var", "stmt_export", "unexpected_a", "var", 8]
 7789.     17
 7790.     17                warn("unexpected_a");
 7791.     17                parse_statement_single();
 7792.     17            } else if (token_nxt.id === "{") {
 7793.     17
 7794.     17// test_cause:
 7795.     17// ["export {}", "stmt_export", "(live)", "", 0]
 7796.     17
 7797.     17                advance("{");
 7798.     17                while (true) {
 7799.     17                    if (!token_nxt.identifier) {
 7800.     17
 7801.     17// test_cause:
 7802.     17// ["export {}", "stmt_export", "expected_identifier_a", "}", 9]
 7803.     17// ["export {};", "stmt_export", "expected_identifier_a", "}", 9]
 7804.     17
 7805.     17                        return stop("expected_identifier_a", token_nxt);
 7806.     17                    }
 7807.     17                    the_id = token_nxt.id;
 7808.     17                    export_list.push(token_nxt);
 7809.     17                    the_name = token_global.context[the_id];
 7810.     17                    if (the_name === undefined) {
 7811.     17
 7812.     17// test_cause:
 7813.     17// ["export {aa}", "stmt_export", "unexpected_a", "aa", 9]
 7814.     17
 7815.     17                        warn("unexpected_a");
 7816.     17                    } else {
 7817.     17                        the_name.used = true;
 7818.     17                        if (export_dict[the_id] !== undefined) {
 7819.     17
 7820.     17// test_cause:
 7821.     17// ["let aa;export{aa,aa}", "stmt_export", "duplicate_a", "aa", 18]
 7822.     17
 7823.     17                            warn("duplicate_a");
 7824.     17                        }
 7825.     17                        export_dict[the_id] = the_name;
 7826.     17                    }
 7827.     17                    advance();
 7828.     17                    the_export.expression.push(the_thing);
 7829.     17                    if (token_nxt.id !== ",") {
 7830.     17                        break;
 7831.     17                    }
 7832.     17                    advance(",");
 7833.     17                }
 7834.     17
 7835.     17// PR-439 - Check exported properties are ordered.
 7836.     17
 7837.     17// test_cause:
 7838.     17// ["
 7839.     17// let aa;let bb;export {bb, aa};
 7840.     17// ", "check_ordered", "expected_a_b_before_c_d", "aa", 27]
 7841.     17
 7842.     17                check_ordered("export", export_list);
 7843.     17                advance("}");
 7844.     17                semicolon();
 7845.     17            } else {
 7846.     17
 7847.     17// test_cause:
 7848.     17// ["export", "stmt_export", "unexpected_a", "(end)", 6]
 7849.     17
 7850.     17                return stop("unexpected_a");
 7851.     17            }
 7852.     41        }
 7853.     41        state.mode_module = true;
 7854.     41        return the_export;
 7855.     41    }
 7856.    994
 7857.     97    function stmt_for() {
 7858.     97        const for_await = token_nxt.id === "await";
 7859.     97        const the_for = token_now;
 7860.     97        let the_operator;
 7861.     97        let the_variable;
 7862.     97        check_not_top_level(the_for);
 7863.     97        scope_function.loop += 1;
 7864.     97
 7865.     97// PR-504 - Add hidden scope_block for:
 7866.     97// - for-variable
 7867.     97
 7868.     97        scope_block = scope_block_push(the_for, true);
 7869.     97
 7870.     97// PR-508 - Add ES2018-feature Asynchronous Iteration - for await...of.
 7871.     97
 7872.      6        if (for_await) {
 7873.      6            if (the_for.for_semicolon) {
 7874.      6
 7875.      6// test_cause:
 7876.      6// ["
 7877.      6// function aa(){for await(;;){}}
 7878.      6// ", "stmt_for", "expected_a", "for await...of", 15]
 7879.      6
 7880.      6                warn("expected_a", the_for, "for await...of");
 7881.      6            }
 7882.      6            if (scope_function.async === 0 && scope_function !== token_global) {
 7883.      6
 7884.      6// test_cause:
 7885.      6// ["()=>{for await(aa of aa){}}", "stmt_for", "unexpected_a", "await", 10]
 7886.      6
 7887.      6                warn("unexpected_a", token_nxt);
 7888.      6            }
 7889.      6            if (scope_function.async === 1) {
 7890.      6
 7891.      6// test_cause:
 7892.      6// ["async function aa(bb){for await(aa of bb){}}", "stmt_for", "(live)", "", 0]
 7893.      6
 7894.      6                scope_function.async = 2;
 7895.      6            }
 7896.      6            advance("await");
 7897.      6        }
 7898.     97        advance("(");
 7899.     19        if (the_for.for_semicolon) {
 7900.     19            switch (token_nxt.id) {
 7901.     19            case ";":
 7902.     19
 7903.     19// test_cause:
 7904.     19// ["for(;;){}", "stmt_for", "expected_a_b", "for (;", 5]
 7905.     19
 7906.     19                warn("expected_a_b", token_nxt, "while (", "for (;");
 7907.     19                break;
 7908.     19            case "const":
 7909.     19            case "var":
 7910.     19
 7911.     19// test_cause:
 7912.     19// ["for(const aa;;){}", "stmt_for", "expected_a_b", "const", 5]
 7913.     19// ["for(var aa;;){}", "stmt_for", "expected_a_b", "var", 5]
 7914.     19
 7915.     19                warn("expected_a_b", token_nxt, "let", token_nxt.id);
 7916.     19                break;
 7917.     19            case "let":
 7918.     19
 7919.     19// test_cause:
 7920.     19// ["for(let aa;;){}", "stmt_for", "(live)", "", 0]
 7921.     19
 7922.     19                break;
 7923.     19            default:
 7924.     19
 7925.     19// test_cause:
 7926.     19// ["for(aa;;){}", "stmt_for", "expected_a", "let", 5]
 7927.     19
 7928.     19                warn("expected_a", token_nxt, "let");
 7929.     19            }
 7930.     19            token_nxt.for_init = true;
 7931.     19            the_for.for_semicolon[0] = parse_statement_single();
 7932.     19
 7933.     19// PR-409 - jquery - Tolerate comma-expression in for_init `for(ii=0,jj=0;;)`.
 7934.     19
 7935.     19            while (token_nxt.id === ",") {
 7936.     19
 7937.     19// test_cause:
 7938.     19// ["for(aa=0,bb=0;;){}", "stmt_for", "(live)", "", 0]
 7939.     19
 7940.     19                advance(",");
 7941.     19                parse_expression(0);
 7942.     19                semicolon();
 7943.     19            }
 7944.     19            token_nxt.for_init = true;
 7945.     19            if (token_nxt.id === ";") {
 7946.     19
 7947.     19// test_cause:
 7948.     19// ["for(;;){}", "stmt_for", "unexpected_a", ";", 6]
 7949.     19
 7950.     19                warn("unexpected_a", token_nxt);
 7951.     19            } else {
 7952.     19                the_for.for_semicolon[1] = parse_expression(0);
 7953.     19            }
 7954.     19            advance(";");
 7955.     19            token_nxt.for_init = true;
 7956.     19            if (token_nxt.id === ")") {
 7957.     19
 7958.     19// test_cause:
 7959.     19// ["for(;;){}", "stmt_for", "unexpected_a", ")", 7]
 7960.     19
 7961.     19                warn("unexpected_a", token_nxt);
 7962.     19            } else {
 7963.     19                the_for.for_semicolon[2] = parse_expression(0);
 7964.     19            }
 7965.     77        } else {
 7966.     77            switch (token_nxt.id) {
 7967.     77            case "const":
 7968.     77            case "let":
 7969.     77
 7970.     77// test_cause:
 7971.     77// ["for(const aa in aa){}", "stmt_for", "(live)", "", 0]
 7972.     77// ["for(const aa of aa){}", "stmt_for", "(live)", "", 0]
 7973.     77// ["for(let aa in aa){}", "stmt_for", "(live)", "", 0]
 7974.     77// ["for(let aa of aa){}", "stmt_for", "(live)", "", 0]
 7975.     77
 7976.     77                break;
 7977.     77            case "var":
 7978.     77
 7979.     77// test_cause:
 7980.     77// ["for(var aa in aa){}", "stmt_for", "expected_a_b", "var", 5]
 7981.     77// ["for(var aa of aa){}", "stmt_for", "expected_a_b", "var", 5]
 7982.     77
 7983.     77                warn("expected_a_b", token_nxt, "const or let", "var");
 7984.     77                break;
 7985.     77            default:
 7986.     77
 7987.     77// test_cause:
 7988.     77// ["for(aa in aa){}", "stmt_for", "expected_a", "const or let", 5]
 7989.     77// ["for(aa of aa){}", "stmt_for", "expected_a", "const or let", 5]
 7990.     77
 7991.     77                warn("expected_a", token_nxt, "const or let");
 7992.     77            }
 7993.     77            token_nxt.for_init = true;
 7994.     77            switch (token_nxt.id) {
 7995.     77            case "const":
 7996.     77            case "let":
 7997.     77            case "var":
 7998.     77                the_variable = parse_statement_single();
 7999.     77                the_for.for_of = the_variable;
 8000.     77                the_operator = the_variable.operator;
 8001.     77                break;
 8002.     77            default:
 8003.     77
 8004.     77// PR-514 - Bugfix - Parse the target at rbp 110, which stops before 'in' and
 8005.     77// 'of', then their right side at rbp 0, as the spec does. Parsing the whole
 8006.     77// head at rbp 0 let a looser operator like '||' in 'for (aa in bb || cc)'
 8007.     77// wrap the 'in' node, and the lint stopped.
 8008.     77
 8009.     77                the_variable = parse_expression(110);
 8010.     77                if (token_nxt.id !== "in" && token_nxt.id !== "of") {
 8011.     77
 8012.     77// test_cause:
 8013.     77// ["for(aa 0){}", "stmt_for", "expected_a_b", "0", 8]
 8014.     77// ["for(aa=aa){}", "stmt_for", "expected_a_b", "=", 7]
 8015.     77
 8016.     77                    return stop(
 8017.     77                        "expected_a_b",
 8018.     77                        token_nxt,
 8019.     77                        "of",
 8020.     77                        artifact(token_nxt)
 8021.     77                    );
 8022.     77                }
 8023.     77                advance();
 8024.     77                the_operator = token_now;
 8025.     77                the_operator.arity = "binary";
 8026.     77                the_operator.expression = [the_variable, parse_expression(0)];
 8027.     77                the_variable = the_operator;
 8028.     77                the_for.for_of = the_variable;
 8029.     77            }
 8030.     77            the_variable.for_init = true;
 8031.     77            switch (the_operator.id) {
 8032.     77            case "in":
 8033.     77                if (for_await) {
 8034.     77
 8035.     77// test_cause:
 8036.     77// ["for await(aa in aa){}", "stmt_for", "expected_a_b", "in", 14]
 8037.     77
 8038.     77                    warn("expected_a_b", the_operator, "of", "in");
 8039.     77                }
 8040.     77
 8041.     77// PR-514 - Suggest 'for...of Object.keys', since a plain object is not
 8042.     77// iterable, so a bare 'for...of' would throw a TypeError.
 8043.     77
 8044.     77// test_cause:
 8045.     77// ["function aa(){for(aa in aa){}}", "stmt_for", "expected_a_b", "for in", 15]
 8046.     77// ["
 8047.     77// function aa(){for(const aa in aa){}}
 8048.     77// ", "stmt_for", "expected_a_b", "for in", 15]
 8049.     77// ["
 8050.     77// function aa(){for(let aa in aa){}}
 8051.     77// ", "stmt_for", "expected_a_b", "for in", 15]
 8052.     77// ["
 8053.     77// function aa(){for(var aa in aa){}}
 8054.     77// ", "stmt_for", "expected_a_b", "for in", 15]
 8055.     77
 8056.     77                warn("expected_a_b", the_for, "for...of Object.keys", "for in");
 8057.     77                break;
 8058.     77
 8059.     77// PR-504 - Add ES2015-feature for..of.
 8060.     77
 8061.     77            case "of":
 8062.     77
 8063.     77// test_cause:
 8064.     77// ["for(aa of aa){}", "stmt_for", "(live)", "", 0]
 8065.     77// ["for(aa of aa||aa){}", "stmt_for", "(live)", "", 0]
 8066.     77// ["for(const aa of aa){}", "stmt_for", "(live)", "", 0]
 8067.     77// ["for(let aa of aa){}", "stmt_for", "(live)", "", 0]
 8068.     77// ["for(var aa of aa){}", "stmt_for", "(live)", "", 0]
 8069.     77
 8070.     77                the_operator.for_init = true;
 8071.     77                break;
 8072.     77            default:
 8073.     77
 8074.     77// test_cause:
 8075.     77// ["for(const aa=aa){}", "stmt_for", "expected_a_b", "=", 13]
 8076.     77// ["for(let aa=aa){}", "stmt_for", "expected_a_b", "=", 11]
 8077.     77// ["for(var aa=aa){}", "stmt_for", "expected_a_b", "=", 11]
 8078.     77
 8079.     77                return stop(
 8080.     77                    "expected_a_b",
 8081.     77                    the_operator,
 8082.     77                    "of",
 8083.     77                    the_operator.id
 8084.     77                );
 8085.     77            }
 8086.     90        }
 8087.     90        advance(")");
 8088.     90        the_for.block = block();
 8089.     90        if (the_for.block.disrupt === true) {
 8090.      1
 8091.      1// test_cause:
 8092.      1// ["
 8093.      1// /*jslint for*/
 8094.      1// function aa(bb,cc){for(0;0;0){break;}}
 8095.      1// ", "stmt_for", "weird_loop", "for", 20]
 8096.      1
 8097.      1            warn("weird_loop", the_for);
 8098.     90        }
 8099.     90        scope_block = scope_block_pop();
 8100.     90        scope_function.loop -= 1;
 8101.     90        return the_for;
 8102.     90    }
 8103.    994
 8104.   3428    function stmt_if() {
 8105.   3428        const the_if = token_now;
 8106.   3428        let the_else;
 8107.   3428        the_if.expression = condition();
 8108.   3428        the_if.block = block();
 8109.    447        if (token_nxt.id === "else") {
 8110.    447            advance("else");
 8111.    447            the_else = token_now;
 8112.    447            the_if.else = (
 8113.    447                token_nxt.id === "if"
 8114.    447                ? parse_statement_single()
 8115.    447                : block()
 8116.    447            );
 8117.    447
 8118.    447// test_cause:
 8119.    447// ["if(0){0}else if(0){0}", "stmt_if", "(live)", "", 0]
 8120.    447// ["if(0){0}else{0}", "stmt_if", "(live)", "", 0]
 8121.    447
 8122.    447            if (the_if.block.disrupt === true) {
 8123.    447                if (the_if.else.disrupt === true) {
 8124.    447
 8125.    447// test_cause:
 8126.    447// ["if(0){break}else{break}", "stmt_if", "(live)", "", 0]
 8127.    447
 8128.    447                    the_if.disrupt = true;
 8129.    447                } else {
 8130.    447
 8131.    447// test_cause:
 8132.    447// ["if(0){break;}else{}", "stmt_if", "unexpected_a", "else", 14]
 8133.    447
 8134.    447                    warn("unexpected_a", the_else);
 8135.    447                }
 8136.    447            }
 8137.   3427        }
 8138.   3427        return the_if;
 8139.   3427    }
 8140.    994
 8141.     61    function stmt_import() {
 8142.     61        const the_import = token_now;
 8143.     61        let name;
 8144.     61        the_import.name_list = [];      // 4. name_list for "import ..."
 8145.     61        state.mode_module = true;
 8146.     63        while (true) {
 8147.     63
 8148.     63// PR-436 - Add grammar for side-effect import-statement.
 8149.     63
 8150.     63            if (token_nxt.id === "(string)") {
 8151.     63
 8152.     63// test_cause:
 8153.     63// ["import \"aa\"", "stmt_import", "expected_a_b", "aa", 8]
 8154.     63
 8155.     63                warn("expected_a_b", token_nxt, "{", artifact());
 8156.     63                advance();
 8157.     63                semicolon();
 8158.     63                return the_import;
 8159.     63            }
 8160.     63            if (token_nxt.id === "*") {
 8161.     63                advance("*");
 8162.     63                advance("as");
 8163.     63                if (!token_nxt.identifier) {
 8164.     63
 8165.     63// test_cause:
 8166.     63// ["import * as", "stmt_import", "expected_identifier_a", "(end)", 11]
 8167.     63
 8168.     63                    return stop("expected_identifier_a", token_nxt);
 8169.     63                }
 8170.     63            }
 8171.     63            if (token_nxt.identifier) {
 8172.     63                name = token_nxt;
 8173.     63                advance();
 8174.     63                if (name.id === "ignore") {
 8175.     63
 8176.     63// test_cause:
 8177.     63// ["import ignore from \"aa\"", "stmt_import", "unexpected_a", "ignore", 8]
 8178.     63
 8179.     63                    warn("unexpected_a", name);
 8180.     63                }
 8181.     63                name_declare(
 8182.     63
 8183.     63// 1.imp.1 - Mark 'declared', the import-name, during import-statement.
 8184.     63
 8185.     63                    scope_function,     // scope_declared
 8186.     63                    "variable",         // role
 8187.     63
 8188.     63// 1.imp.4 - Mark 'readonly', the import-name, during import-statement.
 8189.     63
 8190.     63                    true,               // readonly
 8191.     63                    the_import.name_list,       // name_list
 8192.     63                    name,               // name
 8193.     63
 8194.     63// 1.imp.3 - Mark 'assigned', the import-name, during import-statement.
 8195.     63
 8196.     63                    true                // assigned
 8197.     63                );
 8198.     63            } else {
 8199.     63                advance("{");
 8200.     63                if (token_nxt.id !== "}") {
 8201.     63                    while (true) {
 8202.     63                        if (!token_nxt.identifier) {
 8203.     63
 8204.     63// test_cause:
 8205.     63// ["import {", "stmt_import", "expected_identifier_a", "(end)", 8]
 8206.     63
 8207.     63                            return stop("expected_identifier_a", token_nxt);
 8208.     63                        }
 8209.     63                        name = token_nxt;
 8210.     63                        advance();
 8211.     63                        if (token_nxt.id === "as") {
 8212.     63                            advance("as");
 8213.     63                            if (!token_nxt.identifier) {
 8214.     63
 8215.     63// test_cause:
 8216.     63// ["import {aa as 0}", "stmt_import", "expected_identifier_a", "0", 15]
 8217.     63
 8218.     63                                return stop("expected_identifier_a", token_nxt);
 8219.     63                            }
 8220.     63                            name = token_nxt;
 8221.     63                            advance();
 8222.     63                        }
 8223.     63                        if (name.id === "ignore") {
 8224.     63
 8225.     63// test_cause:
 8226.     63// ["import {ignore} from \"aa\"", "stmt_import", "unexpected_a", "ignore", 9]
 8227.     63
 8228.     63                            warn("unexpected_a", name);
 8229.     63                        }
 8230.     63                        name_declare(
 8231.     63
 8232.     63// 1.imp.1 - Mark 'declared', the import-name, during import-statement.
 8233.     63
 8234.     63                            scope_function,     // scope_declared
 8235.     63                            "variable", // role
 8236.     63
 8237.     63// 1.imp.4 - Mark 'readonly', the import-name, during import-statement.
 8238.     63
 8239.     63                            true,       // readonly
 8240.     63                            the_import.name_list,       // name_list
 8241.     63                            name,       // name
 8242.     63
 8243.     63// 1.imp.3 - Mark 'assigned', the import-name, during import-statement.
 8244.     63
 8245.     63                            true        // assigned
 8246.     63                        );
 8247.     63                        if (token_nxt.id !== ",") {
 8248.     63                            break;
 8249.     63                        }
 8250.     63
 8251.     63// test_cause:
 8252.     63// ["import {aa,bb} from \"aa\"", "stmt_import", "(live)", "", 0]
 8253.     63
 8254.     63                        advance(",");
 8255.     63                    }
 8256.     63                }
 8257.     63                advance("}");
 8258.     63            }
 8259.     63
 8260.     63// PR-347 - Disable warning "unexpected_directive_a".
 8261.     63//
 8262.     63//         if (typeof state.mode_module === "object") {
 8263.     63//
 8264.     63// // test_cause:
 8265.     63// // ["
 8266.     63// // /*global aa*/
 8267.     63// // import aa from "aa"
 8268.     63// // ", "stmt_import", "unexpected_directive_a", "global", 1]
 8269.     63//
 8270.     63//             warn(
 8271.     63//                 "unexpected_directive_a",
 8272.     63//                 state.mode_module,
 8273.     63//                 state.mode_module.directive
 8274.     63//             );
 8275.     63//         }
 8276.     63
 8277.     63            if (token_nxt.id !== ",") {
 8278.     63                break;
 8279.     63            }
 8280.     63
 8281.     63// test_cause:
 8282.     63// ["import aa,{bb} from \"aa\"", "stmt_import", "(live)", "", 0]
 8283.     63
 8284.     63            advance(",");
 8285.     63        }
 8286.     56        advance("from");
 8287.     56        advance("(string)");
 8288.     56        the_import.import = token_now;
 8289.     56        if (!jslint_rgx_module.test(token_now.value)) {
 8290.      1
 8291.      1// test_cause:
 8292.      1// ["import aa from \"!aa\"", "stmt_import", "bad_module_name_a", "!aa", 16]
 8293.      1
 8294.      1            warn("bad_module_name_a", token_now);
 8295.     56        }
 8296.     56        import_list.push(token_now.value);
 8297.     56
 8298.     56// Issue #495 - Add ES2025-syntax "import ... with {...}".
 8299.     56
 8300.     56        if (token_nxt.id === "with") {
 8301.      2
 8302.      2// test_cause:
 8303.      2// ["import aa from \"aa\" with {}", "stmt_import", "(live)", "", 0]
 8304.      2
 8305.      2            advance("with");
 8306.      2            advance("{");
 8307.      2            prefix_lbrace();
 8308.     56        }
 8309.     56        semicolon();
 8310.     56        return the_import;
 8311.     56    }
 8312.    994
 8313.     30    function stmt_label() {
 8314.     30        const the_label = token_now;
 8315.     30        let the_statement;
 8316.      2        if (the_label.id === "ignore") {
 8317.      2
 8318.      2// test_cause:
 8319.      2// [" ignore:", "stmt_label", "unexpected_a", "ignore", 2]
 8320.      2// ["ignore:", "stmt_label", "unexpected_a", "ignore", 1]
 8321.      2
 8322.      2            warn("unexpected_a", the_label);
 8323.      2        }
 8324.     30        advance(":");
 8325.     30        switch (token_nxt.id) {
 8326.      2        case "do":
 8327.      5        case "for":
 8328.      7        case "switch":
 8329.     22        case "while":
 8330.     22
 8331.     22// test_cause:
 8332.     22// ["aa:do", "stmt_label", "(live)", "", 0]
 8333.     22// ["aa:for", "stmt_label", "(live)", "", 0]
 8334.     22// ["aa:switch", "stmt_label", "(live)", "", 0]
 8335.     22// ["aa:while", "stmt_label", "(live)", "", 0]
 8336.     22
 8337.     22            break;
 8338.      8        default:
 8339.      8
 8340.      8// test_cause:
 8341.      8// ["()=>{aa:0}", "stmt_label", "unexpected_label_a", "aa", 6]
 8342.      8// [";{aa:0}", "stmt_label", "unexpected_label_a", "aa", 3]
 8343.      8// ["aa:", "stmt_label", "unexpected_label_a", "aa", 1]
 8344.      8// ["aa:0", "stmt_label", "unexpected_label_a", "aa", 1]
 8345.      8// ["aa:0?0:0", "stmt_label", "unexpected_label_a", "aa", 1]
 8346.      8// ["aa:bb:0", "stmt_label", "unexpected_label_a", "aa", 1]
 8347.      8
 8348.      8            warn("unexpected_label_a", the_label);
 8349.      8            advance();
 8350.      8            return;
 8351.     22        }
 8352.     22
 8353.     22// PR-504 - Add hidden scope_block for:
 8354.     22// - label-name
 8355.     22
 8356.     22        scope_block = scope_block_push(the_label, true);
 8357.     22        name_declare(
 8358.     22
 8359.     22// 5.lab.1 - Mark 'declared', the label-name, before control-flow-block.
 8360.     22
 8361.     22            scope_block,        // scope_declared
 8362.     22            "label",            // role
 8363.     22
 8364.     22// 5.lab.4 - Mark 'readonly', the label-name, before control-flow-block.
 8365.     22
 8366.     22            true,               // readonly
 8367.     22            [],                 // name_list
 8368.     22            the_label,          // name
 8369.     22
 8370.     22// 5.lab.3 - Mark 'assigned', the label-name, before control-flow-block.
 8371.     22
 8372.     22            true                // assigned
 8373.     22        );
 8374.     22
 8375.     22// 5.lab.2 - Mark 'alive', the label-name, before control-flow-block.
 8376.     22
 8377.     22        the_label.alive = true;
 8378.     22        the_statement = parse_statement_single();
 8379.     22        the_statement.label_name = the_label;
 8380.     22        check_ordered_var(the_statement);
 8381.     22        scope_block = scope_block_pop();
 8382.     22        return the_statement;
 8383.     22    }
 8384.    994
 8385.      4    function stmt_lbrace() {
 8386.      4
 8387.      4// test_cause:
 8388.      4// [";{}", "stmt_lbrace", "naked_block", "{", 2]
 8389.      4// ["class aa{}", "stmt_lbrace", "naked_block", "{", 9]
 8390.      4
 8391.      4        warn("naked_block", token_now);
 8392.      4        return block("naked");
 8393.      4    }
 8394.    994
 8395.   2449    function stmt_return() {
 8396.   2449        const the_return = token_now;
 8397.   2449        check_not_top_level(the_return);
 8398.      1        if (scope_function.finally > 0) {
 8399.      1
 8400.      1// test_cause:
 8401.      1// ["
 8402.      1// function aa(){try{}finally{return;}}
 8403.      1// ", "stmt_return", "unexpected_a", "return", 28]
 8404.      1
 8405.      1            warn("unexpected_a", the_return);
 8406.      1        }
 8407.   2449        the_return.disrupt = true;
 8408.   1961        if (token_nxt.id !== ";" && the_return.line === token_nxt.line) {
 8409.   1961            the_return.expression = parse_expression(10);
 8410.   1961        }
 8411.   2449        semicolon();
 8412.   2449        return the_return;
 8413.   2449    }
 8414.    994
 8415.     32    function stmt_semicolon() {
 8416.     32
 8417.     32// test_cause:
 8418.     32// [" ;0", "stmt_semicolon", "unexpected_a", ";", 2]
 8419.     32// [";", "stmt_semicolon", "unexpected_a", ";", 1]
 8420.     32
 8421.     32        warn("unexpected_a", token_now);
 8422.     32        return token_now;
 8423.     32    }
 8424.    994
 8425.    309    function stmt_switch() {
 8426.    309        const the_cases = [];
 8427.    309        const the_switch = token_now;
 8428.    309        let dups = [];
 8429.    309        let exp;
 8430.    309        let last;
 8431.    309        let parsed_block;
 8432.    309        let the_case;
 8433.    309        let the_default;
 8434.    309        let the_disrupt = true;
 8435.    309        let the_last;
 8436.  23808        function is_dup(thing) {
 8437.  23808            return is_equal(thing, exp);
 8438.  23808        }
 8439.    309        check_not_top_level(the_switch);
 8440.      1        if (scope_function.finally > 0) {
 8441.      1
 8442.      1// test_cause:
 8443.      1// ["
 8444.      1// function aa(){try{}finally{switch(0){}}}
 8445.      1// ", "stmt_switch", "unexpected_a", "switch", 28]
 8446.      1
 8447.      1            warn("unexpected_a", the_switch);
 8448.      1        }
 8449.    309        scope_function.switch += 1;
 8450.    309        advance("(");
 8451.    309        the_switch.expression = parse_expression(0);
 8452.    309        the_switch.block = the_cases;
 8453.    309        advance(")");
 8454.    309        advance("{");
 8455.   1285        while (true) {
 8456.   1285
 8457.   1285// Loop through cases with breaks.
 8458.   1285
 8459.   1285            the_case = token_nxt;
 8460.   1285            the_case.arity = "statement";
 8461.   1285            the_case.expression = [];
 8462.   1954            while (true) {
 8463.   1954
 8464.   1954// Loop through fallthrough cases.
 8465.   1954
 8466.   1954                advance("case");
 8467.   1954                token_now.switch = true;
 8468.   1954                exp = parse_expression(0);
 8469.   1954                if (dups.some(is_dup)) {
 8470.   1954
 8471.   1954// test_cause:
 8472.   1954// ["
 8473.   1954// switch(0){case 0:break;case 0:break}
 8474.   1954// ", "stmt_switch", "unexpected_a", "0", 29]
 8475.   1954
 8476.   1954                    warn("unexpected_a", exp);
 8477.   1954                }
 8478.   1954                dups.push(exp);
 8479.   1954                the_case.expression.push(exp);
 8480.   1954                advance(":");
 8481.   1954                if (token_nxt.id !== "case") {
 8482.   1954                    break;
 8483.   1954                }
 8484.   1954            }
 8485.   1285
 8486.   1285// test_cause:
 8487.   1285// ["
 8488.   1285// switch(0){case 1:case 0:break;}
 8489.   1285// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 23]
 8490.   1285// ["
 8491.   1285// switch(0){case "aa":case 0:break;}
 8492.   1285// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 26]
 8493.   1285// ["
 8494.   1285// switch(0){case "bb":case "aa":break;}
 8495.   1285// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 26]
 8496.   1285// ["
 8497.   1285// switch(0){case aa:case "aa":break;}
 8498.   1285// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
 8499.   1285// ["
 8500.   1285// switch(0){case bb:case aa:break;}
 8501.   1285// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
 8502.   1285
 8503.   1285            check_ordered_case(the_case.expression);
 8504.   1285            parsed_block = parse_statement_block();
 8505.   1285            if (parsed_block.length < 1) {
 8506.   1285
 8507.   1285// test_cause:
 8508.   1285// ["
 8509.   1285// switch(0){case 0:default:}
 8510.   1285// ", "stmt_switch", "expected_statements_a", "default", 18]
 8511.   1285// ["switch(0){case 0:}", "stmt_switch", "expected_statements_a", "}", 18]
 8512.   1285
 8513.   1285                warn("expected_statements_a");
 8514.   1285
 8515.   1285// PR-359 - Bugfix - Fixes issue #358 - switch-statement crashes jslint.
 8516.   1285
 8517.   1285                break;
 8518.   1285            }
 8519.   1285            the_case.block = parsed_block;
 8520.   1285            the_cases.push(the_case);
 8521.   1285            last = parsed_block[parsed_block.length - 1];
 8522.   1285            if (last.disrupt) {
 8523.   1285                if (last.id === "break" && last.label_break === undefined) {
 8524.   1285                    the_disrupt = false;
 8525.   1285                }
 8526.   1285            } else {
 8527.   1285
 8528.   1285// test_cause:
 8529.   1285// ["switch(0){case 0:;}", "stmt_switch", "expected_a_before_b", "}", 19]
 8530.   1285
 8531.   1285                warn("expected_a_before_b", token_nxt, "break;", artifact());
 8532.   1285            }
 8533.   1285            if (token_nxt.id !== "case") {
 8534.   1285                break;
 8535.   1285            }
 8536.   1285        }
 8537.    307
 8538.    307// test_cause:
 8539.    307// ["
 8540.    307// switch(0){case 1:break;case 0:break;}
 8541.    307// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 29]
 8542.    307// ["
 8543.    307// switch(0){case "aa":break;case 0:break;}
 8544.    307// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 32]
 8545.    307// ["
 8546.    307// switch(0){case "bb":break;case "aa":break;}
 8547.    307// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 32]
 8548.    307// ["
 8549.    307// switch(0){case aa:break;case "aa":break;}
 8550.    307// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
 8551.    307// ["
 8552.    307// switch(0){case bb:break;case aa:break;}
 8553.    307// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
 8554.    307
 8555.   1282        check_ordered_case(the_cases.map(function ({
 8556.   1282            expression
 8557.   1282        }) {
 8558.   1282            return expression[0];
 8559.   1282        }));
 8560.    307        dups = undefined;
 8561.    307        if (token_nxt.id === "default") {
 8562.    154            the_default = token_nxt;
 8563.    154            advance("default");
 8564.    154            token_now.switch = true;
 8565.    154            advance(":");
 8566.    154            the_switch.else = parse_statement_block();
 8567.    154            if (the_switch.else.length < 1) {
 8568.    154
 8569.    154// test_cause:
 8570.    154// ["
 8571.    154// switch(0){case 0:break;default:}
 8572.    154// ", "stmt_switch", "unexpected_a", "default", 24]
 8573.    154
 8574.    154                warn("unexpected_a", the_default);
 8575.    154                the_disrupt = false;
 8576.    154            } else {
 8577.    154                the_last = the_switch.else[
 8578.    154                    the_switch.else.length - 1
 8579.    154                ];
 8580.    154                if (
 8581.    154                    the_last.id === "break" &&
 8582.    154                    the_last.label_break === undefined
 8583.    154                ) {
 8584.    154
 8585.    154// test_cause:
 8586.    154// ["
 8587.    154// switch(0){case 0:break;default:break;}
 8588.    154// ", "stmt_switch", "unexpected_a", "break", 32]
 8589.    154
 8590.    154                    warn("unexpected_a", the_last);
 8591.    154                    the_last.disrupt = false;
 8592.    154                }
 8593.    154                the_disrupt = the_disrupt && the_last.disrupt;
 8594.    154            }
 8595.    154        } else {
 8596.    153            the_disrupt = false;
 8597.    307        }
 8598.    307        advance("}", the_switch);
 8599.    307        scope_function.switch -= 1;
 8600.    307        the_switch.disrupt = the_disrupt;
 8601.    307        return the_switch;
 8602.    307    }
 8603.    994
 8604.     46    function stmt_throw() {
 8605.     46        const the_throw = token_now;
 8606.     46        the_throw.disrupt = true;
 8607.     46        the_throw.expression = parse_expression(10);
 8608.     46        semicolon();
 8609.      1        if (scope_function.try > 0) {
 8610.      1
 8611.      1// test_cause:
 8612.      1// ["try{throw 0}catch(){}", "stmt_throw", "unexpected_a", "throw", 5]
 8613.      1
 8614.      1            warn("unexpected_a", the_throw);
 8615.      1        }
 8616.     46        return the_throw;
 8617.     46    }
 8618.    994
 8619.     78    function stmt_try() {
 8620.     78        const the_try = token_now;
 8621.     78        let ignored;
 8622.     78        let the_catch;
 8623.     78        let the_disrupt;
 8624.      1        if (scope_function.try > 0) {
 8625.      1
 8626.      1// test_cause:
 8627.      1// ["try{try{}catch(){}}catch(){}", "stmt_try", "unexpected_a", "try", 5]
 8628.      1
 8629.      1            warn("unexpected_a", the_try);
 8630.      1        }
 8631.     78        scope_function.try += 1;
 8632.      1        if (token_nxt.id !== "{") {
 8633.      1
 8634.      1// test_cause:
 8635.      1// ["try", "stmt_try", "expected_a_b", "(end)", 3]
 8636.      1
 8637.      1            return stop("expected_a_b", token_nxt, "{", artifact());
 8638.     77        }
 8639.     77        the_try.block = block();
 8640.     77        the_disrupt = the_try.block.disrupt;
 8641.     77        if (token_nxt.id === "catch") {
 8642.     65            ignored = "ignore";
 8643.     65            the_catch = token_nxt;
 8644.     65            the_try.catch = the_catch;
 8645.     65            advance("catch");
 8646.     65
 8647.     65// PR-504 - Add hidden scope_block for:
 8648.     65// - catch-variable
 8649.     65
 8650.     65            scope_block = scope_block_push(the_catch, true);
 8651.     65            if (token_nxt.id === "(") {
 8652.     65                advance("(");
 8653.     65                if (!token_nxt.identifier) {
 8654.     65
 8655.     65// test_cause:
 8656.     65// ["try{}catch(){}", "stmt_try", "expected_identifier_a", ")", 12]
 8657.     65
 8658.     65                    return stop("expected_identifier_a", token_nxt);
 8659.     65                }
 8660.     65                if (token_nxt.id !== "ignore") {
 8661.     65                    ignored = undefined;
 8662.     65                    the_catch.name = token_nxt;
 8663.     65                    name_declare(
 8664.     65
 8665.     65// 3.cat.1 - Mark 'declared', the catch-variable, before catch-block.
 8666.     65
 8667.     65                        scope_block,    // scope_declared
 8668.     65                        "exception",    // role
 8669.     65
 8670.     65// 3.cat.4 - Mark 'readonly', the catch-variable, before catch-block.
 8671.     65
 8672.     65                        true,           // readonly
 8673.     65                        [],             // name_list
 8674.     65                        token_nxt,      // name
 8675.     65
 8676.     65// 3.cat.3 - Mark 'assigned', the catch-variable, before catch-block.
 8677.     65
 8678.     65                        true            // assigned
 8679.     65                    );
 8680.     65
 8681.     65// 3.cat.2 - Mark 'alive', the catch-variable, before catch-block.
 8682.     65
 8683.     65                    token_nxt.alive = true;
 8684.     65                }
 8685.     65                advance();
 8686.     65                advance(")");
 8687.     65            }
 8688.     65
 8689.     65            if (token_nxt.id !== "{") {
 8690.     65
 8691.     65// test_cause:
 8692.     65// ["try{}catch(aa);", "stmt_try", "expected_a_b", ";", 15]
 8693.     65// ["try{}catch(aa);;", "stmt_try", "expected_a_b", ";", 15]
 8694.     65
 8695.     65                return stop("expected_a_b", token_nxt, "{", artifact());
 8696.     65            }
 8697.     65            the_catch.block = block(ignored);
 8698.     65            if (the_catch.block.disrupt !== true) {
 8699.     65                the_disrupt = false;
 8700.     65            }
 8701.     65
 8702.     65// Restore previous catch-scope after catch-block.
 8703.     65
 8704.     65            scope_block = scope_block_pop();
 8705.     65
 8706.     65// PR-404 - Relax warning about missing `catch` in `try...finally` statement.
 8707.     65//
 8708.     65//         } else {
 8709.     65//
 8710.     65// // test_cause:
 8711.     65// // ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
 8712.     65//
 8713.     65//             warn("expected_a_before_b", token_nxt, "catch", artifact());
 8714.     65
 8715.     71        }
 8716.     71        if (token_nxt.id === "finally") {
 8717.     13            scope_function.finally += 1;
 8718.     13            advance("finally");
 8719.     13
 8720.     13            if (token_nxt.id !== "{") {
 8721.     13
 8722.     13// test_cause:
 8723.     13// ["try{}finally;", "stmt_try", "expected_a_b", ";", 13]
 8724.     13
 8725.     13                return stop("expected_a_b", token_nxt, "{", artifact());
 8726.     13            }
 8727.     13            the_try.finally = block();
 8728.     13            the_disrupt = the_try.finally.disrupt;
 8729.     13            scope_function.finally -= 1;
 8730.     69        }
 8731.     69        the_try.disrupt = the_disrupt;
 8732.     69        scope_function.try -= 1;
 8733.     69        return the_try;
 8734.     69    }
 8735.    994
 8736.   2679    function stmt_var() {
 8737.   2679        const for_init = token_now.for_init;
 8738.   2679        const readonly = token_now.id === "const";
 8739.   2679        const scope_declared = (
 8740.   2679            token_now.id === "var"
 8741.     27            ? scope_function
 8742.   2679
 8743.   2679// PR-504 - Change scope from scope_function to scope_block:
 8744.   2679// - const-declaration
 8745.   2679// - let-declaration
 8746.   2679
 8747.   2652            : scope_block
 8748.   2679        );
 8749.   2679        const the_variable = token_now;
 8750.   2679        let name;
 8751.   2679        let the_operator;
 8752.   2670        function advance_operator() {
 8753.   2670            switch (the_operator.id) {
 8754.   1517            case "=":
 8755.   1517                the_variable.operator = the_operator;
 8756.   1517                advance("=");
 8757.   1517                break;
 8758.     13            case "in":
 8759.     64            case "of":
 8760.     64                if (for_init) {
 8761.     64
 8762.     64// test_cause:
 8763.     64// ["for(let aa in 0){}", "advance_operator", "(live)", "", 0]
 8764.     64// ["for(let aa of 0){}", "advance_operator", "(live)", "", 0]
 8765.     64// ["for(let {aa} in 0){}", "advance_operator", "(live)", "", 0]
 8766.     64// ["for(let {aa} of 0){}", "advance_operator", "(live)", "", 0]
 8767.     64
 8768.     64                    the_variable.operator = the_operator;
 8769.     64                    advance();
 8770.     64                    break;
 8771.     64                }
 8772.     64
 8773.     64// test_cause:
 8774.     64// ["let aa in 0", "advance_operator", "(live)", "", 0]
 8775.     64// ["let aa of 0", "advance_operator", "(live)", "", 0]
 8776.     64// ["let {aa} in 0", "advance_operator", "(live)", "", 0]
 8777.     64// ["let {aa} of 0", "advance_operator", "(live)", "", 0]
 8778.     64
 8779.     64                the_variable.operator = the_operator;
 8780.     64                advance("=");
 8781.     64                break;
 8782.   1089            default:
 8783.   1089                if (readonly) {
 8784.   1089                    the_variable.operator = the_operator;
 8785.   1089                    advance("=");
 8786.   1089                }
 8787.   2670            }
 8788.   2670        }
 8789.   2679        the_variable.name_list = [];    // 5. name_list for "let [aa] = ..."
 8790.   2679
 8791.   2679// A program may use var or let, but not both.
 8792.   2679
 8793.   1800        if (!readonly) {
 8794.   1800            if (mode_var === undefined) {
 8795.   1800                mode_var = the_variable.id;
 8796.   1800            } else if (the_variable.id !== mode_var) {
 8797.   1800
 8798.   1800// test_cause:
 8799.   1800// ["let aa;var aa", "stmt_var", "expected_a_b", "var", 8]
 8800.   1800
 8801.   1800                warn("expected_a_b", the_variable, mode_var, the_variable.id);
 8802.   1800            }
 8803.   1800        }
 8804.   2679
 8805.   2679// We don't expect to see variables created in switch statements.
 8806.   2679
 8807.   2679// PR-514 - Kept 2026-09-29, broader than ESLint no-case-declarations. This
 8808.   2679// also warns a 'var', a braced 'case 0: {let aa}' and a 'let' nested in a
 8809.   2679// block of the case, all of which ESLint allows.
 8810.   2679
 8811.      1        if (scope_function.switch > 0) {
 8812.      1
 8813.      1// test_cause:
 8814.      1// ["switch(0){case 0:var aa}", "stmt_var", "var_switch", "var", 18]
 8815.      1
 8816.      1            warn("var_switch", the_variable);
 8817.      1        }
 8818.   2680        while (true) {
 8819.   2680            if (token_nxt.id === "{" || token_nxt.id === "[") {
 8820.   2680                if (the_variable.id === "var") {
 8821.   2680
 8822.   2680// test_cause:
 8823.   2680// ["var[aa]=0", "stmt_var", "unexpected_a", "var", 1]
 8824.   2680// ["var{aa}=0", "stmt_var", "unexpected_a", "var", 1]
 8825.   2680
 8826.   2680                    warn("unexpected_a", the_variable);
 8827.   2680                }
 8828.   2680                advance();
 8829.   2680
 8830.   2680// PR-500 - Unify ES2015-destructure-logic. - let [aa] = ...;
 8831.   2680
 8832.   2680                prefix_destructure(
 8833.   2680                    scope_declared,     // scope_declared
 8834.   2680                    "variable",         // role
 8835.   2680                    readonly,           // readonly
 8836.   2680                    the_variable.name_list,     // name_list
 8837.   2680                    undefined,          // the_function
 8838.   2680                    false               // the_function_toplevel
 8839.   2680                );
 8840.   2680                the_operator = token_nxt;
 8841.   2680                advance_operator();
 8842.   2680                the_variable.expression = parse_expression(0);
 8843.   2680            } else if (token_nxt.identifier) {
 8844.   2680                name = token_nxt;
 8845.   2680                advance();
 8846.   2680                if (name.id === "ignore") {
 8847.   2680
 8848.   2680// test_cause:
 8849.   2680// ["
 8850.   2680// let ignore;function aa(ignore) {}
 8851.   2680// ", "stmt_var", "unexpected_a", "ignore", 5]
 8852.   2680
 8853.   2680                    warn("unexpected_a", name);
 8854.   2680                }
 8855.   2680                the_operator = token_nxt;
 8856.   2680                advance_operator();
 8857.   2680                switch (the_operator.id) {
 8858.   2680                case "=":
 8859.   2680                case "in":
 8860.   2680                case "of":
 8861.   2680                    name.expression = parse_expression(0);
 8862.   2680                    break;
 8863.   2680                }
 8864.   2680                name_declare(
 8865.   2680
 8866.   2680// 3.var.1 - Mark 'declared', the variable, during variable-declaration.
 8867.   2680
 8868.   2680                    scope_declared,     // scope_declared
 8869.   2680                    "variable",         // role
 8870.   2680
 8871.   2680// 3.var.4 - Mark 'readonly', the variable, if const.
 8872.   2680
 8873.   2680                    readonly,           // readonly
 8874.   2680                    the_variable.name_list,     // name_list
 8875.   2680                    name,               // name
 8876.   2680
 8877.   2680// 3.var.3 - Mark 'assigned', the variable, during variable-declaration.
 8878.   2680
 8879.   2680                    Boolean(name.expression)    // assigned
 8880.   2680                );
 8881.   2680            } else {
 8882.   2680
 8883.   2680// test_cause:
 8884.   2680// ["let 0", "stmt_var", "expected_identifier_a", "0", 5]
 8885.   2680// ["let 0;", "stmt_var", "expected_identifier_a", "0", 5]
 8886.   2680
 8887.   2680                return stop("expected_identifier_a", token_nxt);
 8888.   2680            }
 8889.   2680            if (token_nxt.id !== ",") {
 8890.   2680                break;
 8891.   2680            }
 8892.   2680
 8893.   2680// test_cause:
 8894.   2680// ["let aa,bb", "stmt_var", "expected_a_b", ",", 7]
 8895.   2680
 8896.   2680            warn("expected_a_b", token_nxt, ";", ",");
 8897.   2680            advance(",");
 8898.   2680        }
 8899.   2662        if (!for_init || token_nxt.id === ";") {
 8900.   2599            semicolon();
 8901.   2662        }
 8902.   2662        return the_variable;
 8903.   2662    }
 8904.    994
 8905.    240    function stmt_while() {
 8906.    240        const the_while = token_now;
 8907.    240        check_not_top_level(the_while);
 8908.    240        scope_function.loop += 1;
 8909.    240        the_while.expression = condition();
 8910.    240        the_while.block = block();
 8911.      6        if (the_while.block.disrupt === true) {
 8912.      6
 8913.      6// test_cause:
 8914.      6// ["function aa(){ while(0){break}}", "stmt_while", "weird_loop", "while", 16]
 8915.      6// ["function aa(){while(0){break}}", "stmt_while", "weird_loop", "while", 15]
 8916.      6
 8917.      6            warn("weird_loop", the_while);
 8918.    238        }
 8919.    238        scope_function.loop -= 1;
 8920.    238        return the_while;
 8921.    238    }
 8922.    994
 8923.      2    function stmt_with() {
 8924.      2
 8925.      2// test_cause:
 8926.      2// [" with", "stmt_with", "unexpected_a", "with", 2]
 8927.      2// ["with", "stmt_with", "unexpected_a", "with", 1]
 8928.      2
 8929.      2        return stop("unexpected_a", token_now);
 8930.      2    }
 8931.    994
 8932.  16309    function survey(name) {
 8933.  16309        let id = name.id;
 8934.  16309
 8935.  16309// Tally the property name. If it is a string, only tally strings that conform
 8936.  16309// to the identifier rules.
 8937.  16309
 8938.  16309        switch (id) {
 8939.      1        case "(number)":
 8940.      1
 8941.      1// PR-409 - jquery - Tolerate numeric object-key `{0: 200}` - warn, do not stop.
 8942.      1// Like a non-identifier string-key, it is not tallied for /*property*/.
 8943.      1
 8944.      1// test_cause:
 8945.      1// ["String({0:0})", "survey", "unexpected_a", "0", 9]
 8946.      1
 8947.      1            warn("unexpected_a", name);
 8948.      1            return name.value;
 8949.    111        case "(string)":
 8950.    111            id = name.value;
 8951.    111            if (!jslint_rgx_identifier.test(id)) {
 8952.    111                return id;
 8953.    111            }
 8954.    111            break;
 8955.      2        case "`":
 8956.      2            if (name.value.length === 1) {
 8957.      2                id = name.value[0].value;
 8958.      2                if (!jslint_rgx_identifier.test(id)) {
 8959.      2                    return id;
 8960.      2                }
 8961.      2            }
 8962.      2            break;
 8963.  16195        default:
 8964.  16195            if (!name.identifier) {
 8965.  16195
 8966.  16195// test_cause:
 8967.  16195// ["String({+:0})", "survey", "expected_identifier_a", "+", 9]
 8968.  16195
 8969.  16195                return stop("expected_identifier_a", name);
 8970.  16195            }
 8971.  16221        }
 8972.  16221
 8973.  16221// If we have seen this name before, increment its count.
 8974.  16221
 8975.  16221        if (typeof property_dict[id] === "number") {
 8976.  13488            property_dict[id] += 1;
 8977.  13488            return id;
 8978.  13488        }
 8979.   2733
 8980.   2733// If this is the first time seeing this property name, and if there is a
 8981.   2733// tenure list, then it must be on the list. Otherwise, it must conform to
 8982.   2733// the rules for good property names.
 8983.   2733
 8984.   2733        if (state.mode_property) {
 8985.   1845            if (tenure[id] !== true) {
 8986.   1845
 8987.   1845// test_cause:
 8988.   1845// ["/*property aa*/\naa.bb", "survey", "unregistered_property_a", "bb", 4]
 8989.   1845
 8990.   1845                warn("unregistered_property_a", name);
 8991.   1845            }
 8992.   1845        } else if (
 8993.    888            !option_dict.nomen &&
 8994.    888            name.identifier &&
 8995.    888            jslint_rgx_weird_property.test(id)
 8996.    888        ) {
 8997.    888
 8998.    888// test_cause:
 8999.    888// ["aa.$", "survey", "weird_property_a", "$", 4]
 9000.    888// ["aa._", "survey", "weird_property_a", "_", 4]
 9001.    888// ["aa._aa", "survey", "weird_property_a", "_aa", 4]
 9002.    888// ["aa.aaSync", "survey", "weird_property_a", "aaSync", 4]
 9003.    888// ["aa.aa_", "survey", "weird_property_a", "aa_", 4]
 9004.    888
 9005.    888            warn("weird_property_a", name);
 9006.   2733        }
 9007.   2733        property_dict[id] = 1;
 9008.   2733        return id;
 9009.   2733    }
 9010.    994
 9011.    994// These functions are used to specify the grammar of our language:
 9012.    994
 9013. 132226    function symbol(id, bp) {
 9014. 132226
 9015. 132226// Create a symbol if it does not already exist in the language's syntax.
 9016. 132226
 9017. 132226        let the_symbol = syntax_dict[id];
 9018. 117292        if (the_symbol === undefined) {
 9019. 117292            the_symbol = empty();
 9020. 117292            the_symbol.id = id;
 9021. 117292            the_symbol.lbp = bp || 0;
 9022. 117292            syntax_dict[id] = the_symbol;
 9023. 117292        }
 9024. 132226        return the_symbol;
 9025. 132226    }
 9026.    994
 9027.    994    function ternary(id1, id2) {
 9028.    994
 9029.    994// Create a ternary operator.
 9030.    994
 9031.    994        const the_symbol = symbol(id1, 30);
 9032.    339        the_symbol.led_infix = function parse_ternary_led(left) {
 9033.    339            const the_token = token_now;
 9034.    339            let second;
 9035.    339
 9036.    339// PR-514 - Bugfix - Both branches are an AssignmentExpression in the spec, so
 9037.    339// parse the second like the third. 'aa ? bb = 0 : cc' used to stop at '='.
 9038.    339
 9039.    339            second = parse_expression(10);
 9040.    339            advance(id2);
 9041.    339            token_now.arity = "ternary";
 9042.    339            the_token.arity = "ternary";
 9043.    339            the_token.expression = [left, second, parse_expression(10)];
 9044.      3            if (token_nxt.id !== ")") {
 9045.      3
 9046.      3// test_cause:
 9047.      3// ["0?0:0", "parse_ternary_led", "use_open", "?", 2]
 9048.      3// ["aa=0?aa=0:0", "parse_ternary_led", "use_open", "?", 5]
 9049.      3
 9050.      3                warn("use_open", the_token);
 9051.      3            }
 9052.    339            return the_token;
 9053.    339        };
 9054.    994        return the_symbol;
 9055.    994    }
 9056.    994
 9057.    994// Now we parse JavaScript.
 9058.    994// Begin defining the language.
 9059.    994
 9060.    994    assignment("%=");
 9061.    994    assignment("&&=");
 9062.    994    assignment("&=");
 9063.    994    assignment("**=");
 9064.    994    assignment("*=");
 9065.    994    assignment("+=");
 9066.    994    assignment("-=");
 9067.    994    assignment("/=");
 9068.    994    assignment("<<=");
 9069.    994    assignment("=");
 9070.    994    assignment(">>=");
 9071.    994    assignment(">>>=");
 9072.    994    assignment("??=");
 9073.    994    assignment("^=");
 9074.    994    assignment("|=");
 9075.    994    assignment("||=");
 9076.    994    constant("(number)", "number");
 9077.    994    constant("(regexp)", "regexp");
 9078.    994    constant("(string)", "string");
 9079.    994    constant("Function", "function", constant_Function);
 9080.    994    constant("Infinity", "number", Infinity);
 9081.    994    constant("NaN", "number", NaN);
 9082.    994    constant("arguments", "object", constant_arguments);
 9083.    994    constant("eval", "function", constant_eval);
 9084.    994    constant("false", "boolean", false);
 9085.    994    constant("ignore", "undefined", constant_ignore);
 9086.    994    constant("isFinite", "function", constant_isInfinite);
 9087.    994    constant("isNaN", "function", constant_isNaN);
 9088.    994    constant("null", "null", null);
 9089.    994    constant("this", "object", constant_this);
 9090.    994    constant("true", "boolean", true);
 9091.    994    constant("undefined", "undefined");
 9092.    994    infix(100, "!=");
 9093.    994    infix(100, "!==");
 9094.    994    infix(100, "==");
 9095.    994    infix(100, "===");
 9096.    994    infix(110, "<");
 9097.    994    infix(110, "<=");
 9098.    994    infix(110, ">");
 9099.    994    infix(110, ">=");
 9100.    994    infix(110, "in");
 9101.    994    infix(110, "instanceof");
 9102.    994
 9103.    994// PR-504 - Add ES2015-feature for..of.
 9104.    994
 9105.    994    infix(110, "of");
 9106.    994    infix(120, "<<");
 9107.    994    infix(120, ">>");
 9108.    994    infix(120, ">>>");
 9109.    994    infix(130, "+");
 9110.    994    infix(130, "-");
 9111.    994    infix(140, "%");
 9112.    994    infix(140, "*");
 9113.    994    infix(140, "/");
 9114.    994    infix(160, "(", infix_lparen);
 9115.    994    infix(160, "`", infix_grave);
 9116.    994    infix(170, ".", infix_dot);
 9117.    994    infix(170, "=>", infix_fart_unwrapped);
 9118.    994    infix(170, "?.", infix_dot);
 9119.    994    infix(170, "[", infix_lbracket);
 9120.    994    infix(35, "??");
 9121.    994    infix(40, "||");
 9122.    994    infix(50, "&&");
 9123.    994    infix(70, "|");
 9124.    994    infix(80, "^");
 9125.    994    infix(90, "&");
 9126.    994    infixr(150, "**");
 9127.    994    postassign("++");
 9128.    994    postassign("--");
 9129.    994    preassign("++");
 9130.    994    preassign("--");
 9131.    994    prefix("!!");
 9132.    994    prefix("!");
 9133.    994    prefix("(", prefix_lparen);
 9134.    994    prefix("+");
 9135.    994    prefix("-");
 9136.    994    prefix("/=", prefix_assign_divide);
 9137.    994    prefix("=>", prefix_fart);
 9138.    994    prefix("[", prefix_lbracket);
 9139.    994    prefix("`", prefix_tick);
 9140.    994    prefix("async", prefix_async);
 9141.    994    prefix("await", prefix_await);
 9142.    994    prefix("function", prefix_function);
 9143.    994    prefix("new", prefix_new);
 9144.    994    prefix("typeof");
 9145.    994    prefix("void", prefix_void);
 9146.    994    prefix("{", prefix_lbrace);
 9147.    994    prefix("~");
 9148.    994    stmt(";", stmt_semicolon);
 9149.    994    stmt("async", prefix_async);
 9150.    994    stmt("await", prefix_await);
 9151.    994    stmt("break", stmt_break);
 9152.    994    stmt("const", stmt_var);
 9153.    994    stmt("continue", stmt_continue);
 9154.    994    stmt("debugger", stmt_debugger);
 9155.    994    stmt("delete", stmt_delete);
 9156.    994    stmt("do", stmt_do);
 9157.    994    stmt("export", stmt_export);
 9158.    994    stmt("for", stmt_for);
 9159.    994    stmt("function", prefix_function);
 9160.    994    stmt("if", stmt_if);
 9161.    994    stmt("import", stmt_import);
 9162.    994    stmt("let", stmt_var);
 9163.    994    stmt("return", stmt_return);
 9164.    994    stmt("switch", stmt_switch);
 9165.    994    stmt("throw", stmt_throw);
 9166.    994    stmt("try", stmt_try);
 9167.    994    stmt("var", stmt_var);
 9168.    994    stmt("while", stmt_while);
 9169.    994    stmt("with", stmt_with);
 9170.    994    stmt("{", stmt_lbrace);
 9171.    994    symbol(")");
 9172.    994    symbol("*/");
 9173.    994    symbol(",");
 9174.    994    symbol(":");
 9175.    994    symbol(";");
 9176.    994    symbol("]");
 9177.    994    symbol("case");
 9178.    994    symbol("catch");
 9179.    994    symbol("class");
 9180.    994    symbol("default");
 9181.    994    symbol("else");
 9182.    994    symbol("enum");
 9183.    994    symbol("finally");
 9184.    994    symbol("implements");
 9185.    994    symbol("interface");
 9186.    994    symbol("package");
 9187.    994    symbol("private");
 9188.    994    symbol("protected");
 9189.    994    symbol("public");
 9190.    994    symbol("static");
 9191.    994    symbol("super");
 9192.    994    symbol("void");
 9193.    994    symbol("yield");
 9194.    994    symbol("}");
 9195.    994    ternary("?", ":");
 9196.    994
 9197.    994// Init block_stack, function_stack.
 9198.    994
 9199.    994    block_stack.length = 0;
 9200.    994    function_stack.length = 0;
 9201.    994    scope_block = scope_block_push(token_global, true);
 9202.    994    scope_function = scope_function_push(token_global, false);
 9203.    994
 9204.    994// Init token_nxt.
 9205.    994
 9206.    994    advance();
 9207.    994
 9208.    994// Parsing of JSON is simple:
 9209.    994
 9210.     26    if (state.mode_json) {
 9211.     26        state.token_tree = parse_json();
 9212.     26        advance("(end)");
 9213.     26        return;
 9214.    968    }
 9215.    968
 9216.    968// Because browsers encourage combining of script files, the first token might
 9217.    968// be a semicolon to defend against a missing semicolon in the preceding file.
 9218.    968
 9219.    968    if (option_dict.browser) {
 9220.     10        if (token_nxt.id === ";") {
 9221.     10            advance(";");
 9222.     10        }
 9223.     10
 9224.     10// If we are not in a browser, then the file form of strict pragma may be used.
 9225.     10
 9226.    958    } else if (token_nxt.value === "use strict") {
 9227.    958        advance("(string)");
 9228.    958        semicolon();
 9229.    968    }
 9230.    968    state.token_tree = parse_statement_block();
 9231.    968    advance("(end)");
 9232.    968
 9233.    968// Check top-level functions are ordered.
 9234.    968
 9235.    968// PR-514 - Bugfix - Also check an exported function-declaration, which is
 9236.    968// hoisted too, though <stmt_export> resets its arity to 'unary'.
 9237.    968
 9238.    968// test_cause:
 9239.    968// ["
 9240.    968// export async function bb(){}export async function aa(){}
 9241.    968// ", "check_ordered", "expected_a_b_before_c_d", "aa", 51]
 9242.    968// ["
 9243.    968// export function bb(){}export default function aa(){}
 9244.    968// ", "check_ordered", "expected_a_b_before_c_d", "aa", 47]
 9245.    968// ["
 9246.    968// export function bb(){}export function aa(){}
 9247.    968// ", "check_ordered", "expected_a_b_before_c_d", "aa", 39]
 9248.    968
 9249.    968    check_ordered(
 9250.    968        "function",
 9251.   2351        function_list.map(function (the_function) {
 9252.   2351            const {
 9253.   2351                arity,
 9254.   2351                level,
 9255.   2351                name
 9256.   2351            } = the_function;
 9257.   2351            return (
 9258.   2351                (
 9259.   1123                    arity === "statement" ||
 9260.   1123                    Object.values(export_dict).includes(the_function)
 9261.   1237                ) &&
 9262.   1237                level === 1 &&
 9263.    968                name
 9264.   2351            );
 9265.   2351        }).filter(function (name) {
 9266.   2265            return option_dict.beta && name && name.id;
 9267.   2351        })
 9268.    968    );
 9269.    968
 9270.    968// Cleanup block_stack, function_stack.
 9271.    968
 9272.    968    jslint_assert(
 9273.    968        block_stack.length === 1,
 9274.    968        `block_stack.length=${block_stack.length}.`
 9275.    968    );
 9276.    968    jslint_assert(
 9277.    968        function_stack.length === 1,
 9278.    968        `function_stack.length=${function_stack.length}.`
 9279.    968    );
 9280.    968    block_stack.length = 0;
 9281.    968    function_stack.length = 0;
 9282.    968}
 9283.     23
 9284.    861function jslint_phase4_walk(state) {
 9285.    861
 9286.    861// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
 9287.    861//          recursive traversal. Each node may be processed on the way down
 9288.    861//          (preaction) and on the way up (postaction).
 9289.    861
 9290.    861    const {
 9291.    861        artifact,
 9292.    861        block_stack,
 9293.    861        function_stack,
 9294.    861        global_dict,
 9295.    861        is_equal,
 9296.    861        is_weird,
 9297.    861        option_dict,
 9298.    861        scope_block_pop,
 9299.    861        scope_block_push,
 9300.    861        scope_function_pop,
 9301.    861        scope_function_push,
 9302.    861        scope_report_push,
 9303.    861        syntax_dict,
 9304.    861        token_global,
 9305.    861        warn
 9306.    861    } = state;
 9307.    861    let postaction;
 9308.    861    let postamble;
 9309.    861    let posts = empty();
 9310.    861    let preaction;
 9311.    861    let preamble;
 9312.    861    let pres = empty();
 9313.    861
 9314.    861// The relational operators.
 9315.    861
 9316.    861    let relationop = object_assign_from_list(empty(), [
 9317.    861        "!=", "!==", "<", "<=", "==", "===", ">", ">="
 9318.    861    ], true);
 9319.    861    let scope_block;            // The current block-scope.
 9320.    861    let scope_function;         // The current function-scope.
 9321.    861
 9322.    861// Ambulation of the parse tree.
 9323.    861
 9324.   1722    function action(when) {
 9325.   1722
 9326.   1722// Produce a function that will register task functions that will be called as
 9327.   1722// the tree is traversed.
 9328.   1722
 9329.  31857        return function (arity, id, task) {
 9330.  31857            let a_set = when[arity];
 9331.  31857            let i_set;
 9332.  31857
 9333.  31857// If this arity has no registrations yet, then create a set object to hold
 9334.  31857// them.
 9335.  31857
 9336.  10332            if (a_set === undefined) {
 9337.  10332                a_set = empty();
 9338.  10332                when[arity] = a_set;
 9339.  10332            }
 9340.  31857
 9341.  31857// If this id has no registrations yet, then create a set array to hold them.
 9342.  31857
 9343.  31857            i_set = a_set[id];
 9344.  30996            if (i_set === undefined) {
 9345.  30996                i_set = [];
 9346.  30996                a_set[id] = i_set;
 9347.  30996            }
 9348.  31857
 9349.  31857// Register the task with the arity and the id.
 9350.  31857
 9351.  31857            i_set.push(task);
 9352.  31857        };
 9353.   1722    }
 9354.    861
 9355.   1722    function amble(when) {
 9356.   1722
 9357.   1722// Produce a function that will act on the tasks registered by an action
 9358.   1722// function while walking the tree.
 9359.   1722
 9360. 237648        return function (the_token) {
 9361. 237648
 9362. 237648// Given a task set that was built by an action function, run all
 9363. 237648// relevant tasks on the token.
 9364. 237648
 9365. 237648            let a_set = when[the_token.arity];
 9366. 237648            let i_set;
 9367. 237648
 9368. 237648// If there are tasks associated with the token's arity...
 9369. 237648
 9370. 164428            if (a_set !== undefined) {
 9371. 164428
 9372. 164428// If there are tasks associated with the token's id...
 9373. 164428
 9374. 164428                i_set = a_set[the_token.id];
 9375. 164428                if (i_set !== undefined) {
 9376. 164428                    i_set.forEach(function (task) {
 9377. 164428                        task(the_token);
 9378. 164428                    });
 9379. 164428                }
 9380. 164428
 9381. 164428// If there are tasks for all ids.
 9382. 164428
 9383. 164428                i_set = a_set["(all)"];
 9384. 164428                if (i_set !== undefined) {
 9385. 164428                    i_set.forEach(function (task) {
 9386. 164428                        task(the_token);
 9387. 164428                    });
 9388. 164428                }
 9389. 164428            }
 9390. 237648        };
 9391.   1722    }
 9392.    861
 9393.   3768    function check_assignable(name, the_variable) {
 9394.   3768
 9395.   3768// PR-514 - This function will warn bad_assignment_a when <name> has a readonly
 9396.   3768// binding, such as a const, an import, a catch variable or a function name,
 9397.   3768// and return false for that or for no binding.
 9398.   3768
 9399.    104        if (!the_variable) {
 9400.    104
 9401.    104// PR-514 - An undeclared <name> returns false with no warning, since
 9402.    104// <name_lookup> already warned undeclared_a on this token, and <warn> keeps
 9403.    104// only the first warning of a token.
 9404.    104
 9405.    104// test_cause:
 9406.    104// ["aa+=0", "check_assignable", "(live)", "", 0]
 9407.    104// ["aa=0", "check_assignable", "(live)", "", 0]
 9408.    104
 9409.    104            return false;
 9410.   3664        }
 9411.   3664        if (the_variable.readonly) {
 9412.      6
 9413.      6// test_cause:
 9414.      6// ["const aa=0;++aa", "check_assignable", "bad_assignment_a", "aa", 14]
 9415.      6// ["const aa=0;aa++", "check_assignable", "bad_assignment_a", "aa", 12]
 9416.      6// ["const aa=0;aa+=0", "check_assignable", "bad_assignment_a", "aa", 12]
 9417.      6// ["const aa=0;aa=0", "check_assignable", "bad_assignment_a", "aa", 12]
 9418.      6// ["
 9419.      6// function aa(){}
 9420.      6// aa=0
 9421.      6// ", "check_assignable", "bad_assignment_a", "aa", 1]
 9422.      6
 9423.      6            warn("bad_assignment_a", name);
 9424.      6            return false;
 9425.   3658        }
 9426.   3658        return true;
 9427.   3658    }
 9428.    861
 9429.  35524    function name_lookup(thing) {
 9430.  35524
 9431.  35524// This function will look up <thing>.id from the current scope outward, and
 9432.  35524// return its variable, parameter, label or global, or undefined if undeclared.
 9433.  35524
 9434.  35524        const id = thing.id;
 9435.  35524        const ii_function = block_stack.indexOf(scope_function);
 9436.  35524        let the_label;
 9437.  35524        let the_variable;
 9438.  35524
 9439.  35524// PR-510 - deadcode-confirmed - Both callers pass a token already known to be
 9440.  35524// a variable. <pre_v_var> is registered as a preaction on arity "variable",
 9441.  35524// and <post_a_assignment> walks an assignment token's <name_list>, which only
 9442.  35524// <name_declare> calls with role "variable" fill. That role sets <arity>.
 9443.  35524//
 9444.  35524// deadcode-revive - <name_declare> pushes into the list it is given before
 9445.  35524// it checks the role, so a list built under another role holds names with no
 9446.  35524// <arity>. <the_function>.name_list collects "parameter" names that way. Pass
 9447.  35524// one here and the lookup below resolves the wrong name, with no error.
 9448.  35524//
 9449.  35524// if (thing.arity !== "variable") {
 9450.  35524//     return;
 9451.  35524// }
 9452.  35524
 9453.  35524        jslint_assert(
 9454.  35524            !(thing.arity !== "variable"),
 9455.  35524            `Expected !(thing.arity !== "variable").`
 9456.  35524        );
 9457.  35524
 9458.  35524// Look up the variable, from current-scope, moving up the scope-chain.
 9459.  35524
 9460. 121328        block_stack.some(function (scope_block, ii) {
 9461. 121328            the_variable = scope_block.context[id];
 9462. 121328
 9463. 121328// PR-514 - Bugfix - Skip a label, so a same-named variable, function or global
 9464. 121328// in an outer scope is still found.
 9465. 121328
 9466.  34906            if (the_variable?.role === "label") {
 9467.      3
 9468.      3// test_cause:
 9469.      3// ["aa:while(0){aa}", "name_lookup", "(live)", "", 0]
 9470.      3// ["function aa(){aa:while(aa){break aa;}}", "name_lookup", "(live)", "", 0]
 9471.      3
 9472.      3                the_label = the_variable;
 9473.      3                the_variable = undefined;
 9474.      3            }
 9475.  34903            if (the_variable && ii > ii_function) {
 9476.  15123
 9477.  15123// PR-516 - Bugfix - Mark closure only if found outside the current function,
 9478.  15123// not merely outside the current scope_block, and record it for the report.
 9479.  15123
 9480.  15123                the_variable.closure = true;
 9481.  15123                scope_report_push(scope_function, the_variable);
 9482.  15123            }
 9483. 121328            return the_variable;
 9484. 121328        });
 9485.    621        if (!the_variable && global_dict[id] === undefined) {
 9486.    223            if (the_label) {
 9487.    223
 9488.    223// test_cause:
 9489.    223// ["aa:while(0){aa}", "name_lookup", "label_a", "aa", 13]
 9490.    223
 9491.    223                warn("label_a", thing);
 9492.    223                return the_label;
 9493.    223            }
 9494.    223
 9495.    223// test_cause:
 9496.    223// ["(function aa(){})aa", "name_lookup", "undeclared_a", "aa", 18]
 9497.    223// ["aa", "name_lookup", "undeclared_a", "aa", 1]
 9498.    223// ["class aa{}", "name_lookup", "undeclared_a", "aa", 7]
 9499.    223// ["
 9500.    223// function aa(){function bb(){}}
 9501.    223// bb
 9502.    223// ", "name_lookup", "undeclared_a", "bb", 1]
 9503.    223// ["
 9504.    223// function aa(){var bb}
 9505.    223// bb
 9506.    223// ", "name_lookup", "undeclared_a", "bb", 1]
 9507.    223// ["if(0){const aa=0}aa", "name_lookup", "undeclared_a", "aa", 18]
 9508.    223// ["if(0){function aa(){}}aa", "name_lookup", "undeclared_a", "aa", 23]
 9509.    223// ["if(0){let aa}aa", "name_lookup", "undeclared_a", "aa", 14]
 9510.    223// ["try{}catch(aa){}aa", "name_lookup", "undeclared_a", "aa", 17]
 9511.    223// ["try{}finally{aa}", "name_lookup", "undeclared_a", "aa", 14]
 9512.    223
 9513.    223            warn("undeclared_a", thing);
 9514.    223            return;
 9515.  35301        }
 9516.  35301
 9517.  35301// If it isn't in any of those either, perhaps it is a predefined global.
 9518.  35301// If so, add it to the global context.
 9519.  35301
 9520.  35301        if (!the_variable) {
 9521.    398            the_variable = {
 9522.    398
 9523.    398// 3.glo.2 - Mark 'alive', the global-variable, immediately.
 9524.    398
 9525.    398                alive: true,
 9526.    398
 9527.    398// 3.glo.3 - Mark 'assigned', the global-variable, immediately.
 9528.    398
 9529.    398                assigned: true,
 9530.    398                id,
 9531.    398
 9532.    398// 3.glo.4 - Mark 'readonly', the global-variable, immediately.
 9533.    398
 9534.    398                readonly: true,
 9535.    398                role: "variable",
 9536.    398                scope_declared: token_global
 9537.    398            };
 9538.    398
 9539.    398// 3.glo.1 - Mark 'declared', the global-variable, immediately.
 9540.    398
 9541.    398            token_global.context[id] = the_variable;
 9542.    398            scope_report_push(scope_function, the_variable);
 9543.  35301        }
 9544.  35301        if (!the_variable.alive) {
 9545.     29
 9546.     29// PR-514 - Deviation kept 2026-09-29. A function reading a 'let' declared
 9547.     29// below it warns, though valid when called later. This matches ESLint
 9548.     29// no-use-before-define.
 9549.     29
 9550.     29// test_cause:
 9551.     29// ["(aa=aa)=>0", "name_lookup", "temporal_dead_zone_a", "aa", 5]
 9552.     29// ["
 9553.     29// (function aa(){aa();var aa})
 9554.     29// ", "name_lookup", "temporal_dead_zone_a", "aa", 16]
 9555.     29// ["for(const [aa] of aa){}", "name_lookup", "temporal_dead_zone_a", "aa", 19]
 9556.     29// ["let [aa]=aa", "name_lookup", "temporal_dead_zone_a", "aa", 10]
 9557.     29// ["let aa=()=>aa", "name_lookup", "temporal_dead_zone_a", "aa", 12]
 9558.     29// ["let aa=aa", "name_lookup", "temporal_dead_zone_a", "aa", 8]
 9559.     29// ["let aa=bb;let bb", "name_lookup", "temporal_dead_zone_a", "bb", 8]
 9560.     29
 9561.     29            warn("temporal_dead_zone_a", thing);
 9562.  35301        }
 9563.  35301        return the_variable;
 9564.  35301    }
 9565.    861
 9566.   5333    function post_a_assignment(thing) {
 9567.   5333
 9568.   5333// Assignment using = sets the assigned property of a variable, and so do '??='
 9569.   5333// and '||=' below. A = token keeps that variable, or the variables of a
 9570.   5333// destructuring, in its name_list property.
 9571.   5333
 9572.   5333        const lvalue = thing.expression[0];
 9573.   5333        let right;
 9574.    772        if (thing.id !== "=") {
 9575.    772            if (
 9576.    772                lvalue.arity === "variable" &&
 9577.    772                check_assignable(lvalue, lvalue.variable) &&
 9578.    772                (thing.id === "??=" || thing.id === "||=")
 9579.    772            ) {
 9580.    772
 9581.    772// PR-514 - Bugfix - '??=' and '||=' assign an unassigned variable, since its
 9582.    772// 'undefined' is nullish and falsy, so it counts as assigned. '&&=' does not
 9583.    772// assign it, and still warns unassigned_var_a.
 9584.    772
 9585.    772// test_cause:
 9586.    772// ["let aa;aa??=0", "post_a_assignment", "(live)", "", 0]
 9587.    772// ["let aa;aa||=0", "post_a_assignment", "(live)", "", 0]
 9588.    772
 9589.    772                lvalue.variable.assigned = true;
 9590.    772            }
 9591.    772            right = syntax_dict[thing.expression[1].id];
 9592.    772            if (
 9593.    772                right &&
 9594.    772                (
 9595.    772                    right.id === "function" ||
 9596.    772                    right.id === "=>" ||
 9597.    772                    (
 9598.    772                        right.constant &&
 9599.    772                        right.id !== "(number)" &&
 9600.    772                        (right.id !== "(string)" || thing.id !== "+=")
 9601.    772                    )
 9602.    772                )
 9603.    772            ) {
 9604.    772
 9605.    772// test_cause:
 9606.    772// ["aa-=undefined", "post_a_assignment", "unexpected_a", "undefined", 5]
 9607.    772
 9608.    772                warn("unexpected_a", thing.expression[1]);
 9609.    772            }
 9610.    772            return;
 9611.   4561        }
 9612.   4561        if (thing.name_list) {
 9613.   3099            for (const name of thing.name_list) {
 9614.   3099                const the_variable = name_lookup(name);
 9615.   3099                if (check_assignable(name, the_variable)) {
 9616.   3099
 9617.   3099// 3.var.3 - Mark 'assigned', the variable, after assignment.
 9618.   3099
 9619.   3099                    the_variable.assigned = true;
 9620.   3099                }
 9621.   3099            }
 9622.   3060            return;
 9623.   3060        }
 9624.   1501        if (lvalue.id === "." && thing.expression[1].id === "undefined") {
 9625.      2
 9626.      2// test_cause:
 9627.      2// ["
 9628.      2// let aa; aa.aa=undefined;
 9629.      2// ", "post_a_assignment", "expected_a_b", "undefined", 9]
 9630.      2// ["
 9631.      2// let aa;aa.aa=undefined;
 9632.      2// ", "post_a_assignment", "expected_a_b", "undefined", 8]
 9633.      2
 9634.      2            warn("expected_a_b", lvalue.expression, "delete", "undefined");
 9635.      2            return;
 9636.      2        }
 9637.   5333    }
 9638.    861
 9639.    682    function post_a_pluseq(thing) {
 9640.    682        const right = thing.expression[1];
 9641.    340        if (right.constant) {
 9642.    340            if (
 9643.    340                right.value === "" ||
 9644.    340                (right.id === "(number)" && right.value === "0") ||
 9645.    340                right.id === "(boolean)" ||
 9646.    340                right.id === "null" ||
 9647.    340                right.id === "undefined" ||
 9648.    340                Number.isNaN(right.value)
 9649.    340            ) {
 9650.    340
 9651.    340// test_cause:
 9652.    340// ["let aa=0;aa+=0;", "post_a_pluseq", "unexpected_a", "0", 14]
 9653.    340
 9654.    340                warn("unexpected_a", right);
 9655.    340            }
 9656.    340        }
 9657.    682    }
 9658.    861
 9659.   1532    function post_b_and(thing) {
 9660.   1532        if (
 9661.   1527            is_weird(thing.expression[0]) ||
 9662.   1527            is_equal(thing.expression[0], thing.expression[1]) ||
 9663.   1512            thing.expression[0].constant === true ||
 9664.   1510            thing.expression[1].constant === true
 9665.     22        ) {
 9666.     22
 9667.     22// test_cause:
 9668.     22// ["aa=(()=>0)&&(()=>0)", "post_b_and", "weird_condition_a", "&&", 11]
 9669.     22// ["aa=(``?``:``)&&(``?``:``)", "post_b_and", "weird_condition_a", "&&", 14]
 9670.     22// ["aa=/./&&/./", "post_b_and", "weird_condition_a", "&&", 7]
 9671.     22// ["aa=0&&0", "post_b_and", "weird_condition_a", "&&", 5]
 9672.     22// ["aa=[]&&[]", "post_b_and", "weird_condition_a", "&&", 6]
 9673.     22// ["aa=`${0}`&&`${0}`", "post_b_and", "weird_condition_a", "&&", 10]
 9674.     22// ["aa=bb``&&bb``", "post_b_and", "weird_condition_a", "&&", 8]
 9675.     22// ["
 9676.     22// aa=function aa(){}&&function aa(){}
 9677.     22// ", "post_b_and", "weird_condition_a", "&&", 19]
 9678.     22// ["aa={}&&{}", "post_b_and", "weird_condition_a", "&&", 6]
 9679.     22
 9680.     22            warn("weird_condition_a", thing);
 9681.     22        }
 9682.   1532    }
 9683.    861
 9684.  35748    function post_b_binary(thing) {
 9685.  35748        let right;
 9686.   4312        if (relationop[thing.id]) {
 9687.   4312            if (
 9688.   4312                is_weird(thing.expression[0]) ||
 9689.   4312                is_weird(thing.expression[1]) ||
 9690.   4312                is_equal(thing.expression[0], thing.expression[1]) ||
 9691.   4312                (
 9692.   4312                    thing.expression[0].constant === true &&
 9693.   4312                    thing.expression[1].constant === true
 9694.   4312                )
 9695.   4312            ) {
 9696.   4312
 9697.   4312// test_cause:
 9698.   4312// ["if(0===0){0}", "post_b_binary", "weird_relation_a", "===", 5]
 9699.   4312
 9700.   4312                warn("weird_relation_a", thing);
 9701.   4312            }
 9702.   4312        }
 9703.  35748        switch (thing.id) {
 9704.  11507        case "(":
 9705.  11531        case "=>":
 9706.  35748
 9707.  35748// Tagged-megastring is infix at same binding-power as "(" and is a call,
 9708.  35748// not binary-operator.
 9709.  35748
 9710.  11541        case "`":
 9711.  11541            break;
 9712.   2159        case "+":
 9713.   2159            if (!option_dict.convert) {
 9714.   2159                if (thing.expression[0].value === "") {
 9715.   2159
 9716.   2159// test_cause:
 9717.   2159// ["let aa=\"\"+0;", "post_b_binary", "expected_a_b", "\"\" +", 10]
 9718.   2159
 9719.   2159                    warn("expected_a_b", thing, "String(...)", "\"\" +");
 9720.   2159                } else if (thing.expression[1].value === "") {
 9721.   2159
 9722.   2159// test_cause:
 9723.   2159// ["let aa=0+\"\";", "post_b_binary", "expected_a_b", "+ \"\"", 9]
 9724.   2159
 9725.   2159                    warn("expected_a_b", thing, "String(...)", "+ \"\"");
 9726.   2159                }
 9727.   2159            }
 9728.   2159            break;
 9729.  12903        case ".":
 9730.  12961        case "?.":
 9731.  12961            if (thing.expression.id === "RegExp") {
 9732.  12961
 9733.  12961// PR-499 - Relax warning for ES2025-feature RegExp.escape().
 9734.  12961
 9735.  12961                if (!thing.name || thing.name.id !== "escape") {
 9736.  12961
 9737.  12961// test_cause:
 9738.  12961// ["aa=RegExp.aa", "post_b_binary", "weird_expression_a", ".", 10]
 9739.  12961
 9740.  12961                    warn("weird_expression_a", thing);
 9741.  12961                }
 9742.  12961            }
 9743.  12961            break;
 9744.   1539        case "[":
 9745.   1539            if (thing.expression[0].id === "window") {
 9746.   1539
 9747.   1539// test_cause:
 9748.   1539// ["aa=window[0]", "post_b_binary", "weird_expression_a", "window[...]", 10]
 9749.   1539
 9750.   1539                warn("weird_expression_a", thing, "window[...]");
 9751.   1539            }
 9752.   1539            if (thing.expression[0].id === "self") {
 9753.   1539
 9754.   1539// test_cause:
 9755.   1539// ["aa=self[0]", "post_b_binary", "weird_expression_a", "self[...]", 8]
 9756.   1539
 9757.   1539                warn("weird_expression_a", thing, "self[...]");
 9758.   1539            }
 9759.   1539            break;
 9760.   7548        default:
 9761.   7548            right = thing.expression[1];
 9762.   7548            if (
 9763.   7548                (thing.id === "+" || thing.id === "-") &&
 9764.   7548                right.id === thing.id &&
 9765.   7548                right.arity === "unary" &&
 9766.   7548                !right.wrapped
 9767.   7548            ) {
 9768.   7548
 9769.   7548// test_cause:
 9770.   7548// ["0- -0", "post_b_binary", "wrap_subexpression_a_b", "-", 4]
 9771.   7548
 9772.   7548                warn("wrap_subexpression_a_b", right, right.id, thing.id);
 9773.   7548            }
 9774.   7548
 9775.   7548            if (
 9776.   7548                thing.id === "**" &&
 9777.   7548                thing.expression[0].arity === "unary" &&
 9778.   7548                !thing.expression[0].wrapped &&
 9779.   7548
 9780.   7548// PR-517 - deadcode-confirmed - A 'void' here never showed its warning, since
 9781.   7548// <prefix_void> has already warned on the same token, and <warn> drops a
 9782.   7548// second warning on one token.
 9783.   7548//
 9784.   7548// deadcode-revive - Let a token carry more than one warning, and list "void".
 9785.   7548
 9786.   7548                [
 9787.   7548                    "!", "!!", "+", "-", "await", "typeof", "~"
 9788.   7548                ].includes(thing.expression[0].id)
 9789.   7548            ) {
 9790.   7548
 9791.   7548// PR-514 - Bugfix - A unary operator before '**' is a SyntaxError, since the
 9792.   7548// spec's ExponentiationExpression takes an UpdateExpression on its left. So
 9793.   7548// '-aa ** 2' needs parens, while '[aa] ** 2' and '++aa ** 2' do not.
 9794.   7548
 9795.   7548// test_cause:
 9796.   7548// ["
 9797.   7548// /*jslint bitwise*/
 9798.   7548// let aa;aa=~aa**aa;
 9799.   7548// ", "post_b_binary", "wrap_subexpression_a_b", "**", 11]
 9800.   7548// ["
 9801.   7548// /*jslint convert*/
 9802.   7548// let aa;aa=!!aa**aa;
 9803.   7548// ", "post_b_binary", "wrap_subexpression_a_b", "**", 11]
 9804.   7548// ["
 9805.   7548// /*jslint convert*/
 9806.   7548// let aa;aa=+aa**aa;
 9807.   7548// ", "post_b_binary", "wrap_subexpression_a_b", "**", 11]
 9808.   7548// ["aa=-0**0", "post_b_binary", "wrap_subexpression_a_b", "**", 4]
 9809.   7548// ["
 9810.   7548// async function aa(){return await aa**0;}
 9811.   7548// ", "post_b_binary", "wrap_subexpression_a_b", "**", 28]
 9812.   7548// ["let aa;aa=!aa**aa;", "post_b_binary", "wrap_subexpression_a_b", "**", 11]
 9813.   7548
 9814.   7548                warn(
 9815.   7548                    "wrap_subexpression_a_b",
 9816.   7548                    thing.expression[0],
 9817.   7548                    thing.expression[0].id,
 9818.   7548                    "**"
 9819.   7548                );
 9820.   7548            }
 9821.   7548
 9822.   7548            if (thing.id === "??") {
 9823.   7548
 9824.   7548// PR-514 - Bugfix - An unwrapped '&&' or '||' operand of '??' is a SyntaxError,
 9825.   7548// since the spec's CoalesceExpression takes a BitwiseORExpression on each side.
 9826.   7548// '??' binds loosest of the three, so only a '??' node can hold one.
 9827.   7548
 9828.   7548                thing.expression.forEach(function (thang) {
 9829.   7548                    if (
 9830.   7548                        (thang.id === "&&" || thang.id === "||") &&
 9831.   7548                        !thang.wrapped
 9832.   7548                    ) {
 9833.   7548
 9834.   7548// test_cause:
 9835.   7548// ["aa&&bb??cc", "post_b_binary", "wrap_subexpression_a_b", "??", 3]
 9836.   7548// ["aa??bb||cc", "post_b_binary", "wrap_subexpression_a_b", "??", 7]
 9837.   7548
 9838.   7548                        warn("wrap_subexpression_a_b", thang, thang.id, "??");
 9839.   7548                    }
 9840.   7548                });
 9841.   7548            }
 9842.   7548            if (
 9843.   7548                thing.expression[0].constant === true &&
 9844.   7548                right.constant === true
 9845.   7548            ) {
 9846.   7548                thing.constant = true;
 9847.   7548            }
 9848.  35748        }
 9849.  35748    }
 9850.    861
 9851.   1539    function post_b_lbracket(thing) {
 9852.      1        if (thing.expression[0].id === "RegExp") {
 9853.      1
 9854.      1// test_cause:
 9855.      1// ["aa=RegExp[0]", "post_b_lbracket", "weird_expression_a", "[", 10]
 9856.      1
 9857.      1            warn("weird_expression_a", thing);
 9858.      1        }
 9859.      1        if (is_weird(thing.expression[1])) {
 9860.      1
 9861.      1// test_cause:
 9862.      1// ["aa[[0]]", "post_b_lbracket", "weird_expression_a", "[", 4]
 9863.      1
 9864.      1            warn("weird_expression_a", thing.expression[1]);
 9865.      1        }
 9866.   1539    }
 9867.    861
 9868.  11507    function post_b_lparen(thing) {
 9869.  11507        let arg;
 9870.  11507        let array;
 9871.  11507        let cack;
 9872.  11507        let left = thing.expression[0];
 9873.  11507        let new_date;
 9874.  11507        let paren;
 9875.  11507        let the_new;
 9876.    168        if (left.id === "new") {
 9877.    168            the_new = left;
 9878.    168            left = left.expression;
 9879.    168        }
 9880.     39        if (left.id === "function") {
 9881.     39            if (!thing.wrapped) {
 9882.     39
 9883.     39// test_cause:
 9884.     39// ["aa=function(){}()", "post_b_lparen", "wrap_immediate", "(", 16]
 9885.     39
 9886.     39                warn("wrap_immediate", thing);
 9887.     39            }
 9888.  11468        } else if (left.identifier) {
 9889.  11468            if (the_new !== undefined) {
 9890.  11468
 9891.  11468// PR-517 - deadcode-confirmed - A branch for 'new Function' never showed its
 9892.  11468// warning. Without option eval, <constant_Function> has already warned on the
 9893.  11468// same 'Function' token, and <warn> drops a second warning on one token.
 9894.  11468//
 9895.  11468// deadcode-revive - Let a token carry more than one warning.
 9896.  11468//
 9897.  11468// } else if (left.id === "Function") {
 9898.  11468//     if (!option_dict.eval) {
 9899.  11468//         warn("unexpected_a", left, "new Function");
 9900.  11468//     }
 9901.  11468
 9902.  11468                if (
 9903.  11468                    left.id[0] > "Z" ||
 9904.  11468                    left.id === "BigInt" ||
 9905.  11468                    left.id === "Boolean" ||
 9906.  11468                    left.id === "Number" ||
 9907.  11468                    left.id === "String" ||
 9908.  11468                    left.id === "Symbol"
 9909.  11468                ) {
 9910.  11468
 9911.  11468// test_cause:
 9912.  11468// ["new BigInt()", "post_b_lparen", "unexpected_a", "new", 1]
 9913.  11468// ["new Boolean()", "post_b_lparen", "unexpected_a", "new", 1]
 9914.  11468// ["new Number()", "post_b_lparen", "unexpected_a", "new", 1]
 9915.  11468// ["new String()", "post_b_lparen", "unexpected_a", "new", 1]
 9916.  11468// ["new Symbol()", "post_b_lparen", "unexpected_a", "new", 1]
 9917.  11468// ["new aa()", "post_b_lparen", "unexpected_a", "new", 1]
 9918.  11468
 9919.  11468                    warn("unexpected_a", the_new);
 9920.  11468                } else if (left.id === "Array") {
 9921.  11468                    arg = thing.expression;
 9922.  11468                    if (arg.length !== 2 || arg[1].id === "(string)") {
 9923.  11468
 9924.  11468// test_cause:
 9925.  11468// ["new Array()", "post_b_lparen", "expected_a_b", "new Array", 5]
 9926.  11468// ["new Array(0,\"bb\")", "post_b_lparen", "expected_a_b", "new Array", 5]
 9927.  11468
 9928.  11468                        warn("expected_a_b", left, "[]", "new Array");
 9929.  11468                    }
 9930.  11468                } else if (left.id === "Object") {
 9931.  11468
 9932.  11468// test_cause:
 9933.  11468// ["new Object()", "post_b_lparen", "expected_a_b", "new Object", 5]
 9934.  11468
 9935.  11468                    warn(
 9936.  11468                        "expected_a_b",
 9937.  11468                        left,
 9938.  11468                        "Object.create(null)",
 9939.  11468                        "new Object"
 9940.  11468                    );
 9941.  11468                }
 9942.  11468            } else {
 9943.  11468                if (
 9944.  11468                    left.id[0] >= "A" &&
 9945.  11468                    left.id[0] <= "Z" &&
 9946.  11468                    left.id !== "BigInt" &&
 9947.  11468                    left.id !== "Boolean" &&
 9948.  11468                    left.id !== "Number" &&
 9949.  11468                    left.id !== "String" &&
 9950.  11468                    left.id !== "Symbol"
 9951.  11468                ) {
 9952.  11468
 9953.  11468// test_cause:
 9954.  11468// ["let Aa;let bb=Aa();", "post_b_lparen", "expected_a_before_b", "Aa", 15]
 9955.  11468
 9956.  11468                    warn("expected_a_before_b", left, "new", artifact(left));
 9957.  11468                }
 9958.  11468            }
 9959.  11468        } else if (left.id === ".") {
 9960.  11468            cack = the_new !== undefined;
 9961.  11468            if (left.expression.id === "Date" && left.name.id === "UTC") {
 9962.  11468
 9963.  11468// test_cause:
 9964.  11468// ["new Date.UTC()", "post_b_lparen", "(live)", "", 0]
 9965.  11468
 9966.  11468                cack = !cack;
 9967.  11468            }
 9968.  11468            if (jslint_rgx_cap.test(left.name.id) !== cack) {
 9969.  11468                if (the_new !== undefined) {
 9970.  11468
 9971.  11468// test_cause:
 9972.  11468// ["new Date.UTC()", "post_b_lparen", "unexpected_a", "new", 1]
 9973.  11468
 9974.  11468                    warn("unexpected_a", the_new);
 9975.  11468                } else {
 9976.  11468
 9977.  11468// test_cause:
 9978.  11468// ["let Aa;let bb=Aa.Aa();", "post_b_lparen", "expected_a_before_b", "Aa", 15]
 9979.  11468
 9980.  11468                    warn(
 9981.  11468                        "expected_a_before_b",
 9982.  11468                        left.expression,
 9983.  11468                        "new",
 9984.  11468                        left.name.id
 9985.  11468                    );
 9986.  11468                }
 9987.  11468            }
 9988.  11468            if (left.name.id === "getTime") {
 9989.  11468                paren = left.expression;
 9990.  11468                if (paren.id === "(") {
 9991.  11468                    array = paren.expression;
 9992.  11468                    if (array.length === 1) {
 9993.  11468                        new_date = array[0];
 9994.  11468                        if (
 9995.  11468                            new_date.id === "new" &&
 9996.  11468                            new_date.expression.id === "Date"
 9997.  11468                        ) {
 9998.  11468
 9999.  11468// test_cause:
10000.  11468// ["
10001.  11468// new Date().getTime()
10002.  11468// ", "post_b_lparen", "expected_a_b", "new Date().getTime()", 1]
10003.  11468
10004.  11468                            warn(
10005.  11468                                "expected_a_b",
10006.  11468                                new_date,
10007.  11468                                "Date.now()",
10008.  11468                                "new Date().getTime()"
10009.  11468                            );
10010.  11468                        }
10011.  11468                    }
10012.  11468                }
10013.  11468            }
10014.  11468        }
10015.  11507    }
10016.    861
10017.   1049    function post_b_or(thing) {
10018.   1049        if (
10019.   1049            is_weird(thing.expression[0]) ||
10020.   1047            is_equal(thing.expression[0], thing.expression[1]) ||
10021.   1047            thing.expression[0].constant === true
10022.      3        ) {
10023.      3
10024.      3// test_cause:
10025.      3// ["aa=0||0", "post_b_or", "weird_condition_a", "||", 5]
10026.      3
10027.      3            warn("weird_condition_a", thing);
10028.      3        }
10029.   1049    }
10030.    861
10031.     10    function post_p_update(thing) {
10032.     10        if (thing.expression.arity === "variable") {
10033.     10            check_assignable(thing.expression, thing.expression.variable);
10034.     10        }
10035.     10    }
10036.    861
10037.     99    function post_s_export_toplevel(the_thing) {
10038.     99
10039.     99// Some features must be at the most outermost level.
10040.     99
10041.      1        if (scope_block !== token_global) {
10042.      1
10043.      1// test_cause:
10044.      1// ["
10045.      1// if(0){import aa from "aa";}
10046.      1// ", "post_s_export_toplevel", "misplaced_a", "import", 7]
10047.      1
10048.      1            warn("misplaced_a", the_thing);
10049.      1        }
10050.     99    }
10051.    861
10052.     90    function post_s_for(thing) {
10053.     18        if (thing.for_semicolon) {
10054.     18
10055.     18// Recurse walk_statement.
10056.     18
10057.     18            walk_statement(thing.for_semicolon[2]);
10058.     18        }
10059.     90        scope_block = scope_block_pop();
10060.     90    }
10061.    861
10062.   2351    function post_s_function(thing) {
10063.   2351        delete scope_function.async;
10064.   2351        delete scope_function.finally;
10065.   2351        delete scope_function.loop;
10066.   2351        delete scope_function.switch;
10067.   2351        delete scope_function.try;
10068.      6        if (thing.wrapped) {
10069.      6
10070.      6// test_cause:
10071.      6// ["aa=(function(){})", "post_s_function", "unexpected_parens", "function", 5]
10072.      6
10073.      6            warn("unexpected_parens", thing);
10074.      6        }
10075.   2351        scope_block = scope_block_pop();
10076.   2351        scope_block = scope_block_pop();
10077.   2351        scope_function = scope_function_pop();
10078.   2351    }
10079.    861
10080.     58    function post_s_import(the_thing) {
10081.     58
10082.     58// 1.imp.2 - Mark 'alive', the import-name, after import-statement.
10083.     58
10084.     58        post_s_var(the_thing);
10085.     58        post_s_export_toplevel(the_thing);
10086.     58    }
10087.    861
10088.     69    function post_s_try(thing) {
10089.     60        if (thing.catch !== undefined) {
10090.     60
10091.     60// PR-504 - Add hidden scope_block for:
10092.     60// - catch-variable
10093.     60
10094.     60            scope_block = scope_block_push(thing.catch, false);
10095.     60
10096.     60// Recurse walk_statement.
10097.     60
10098.     60            walk_statement(thing.catch.block);
10099.     60
10100.     60// Restore previous catch-scope after catch-block.
10101.     60
10102.     60            scope_block = scope_block_pop();
10103.     60        }
10104.     69
10105.     69// PR-514 - Bugfix - Walk the finally-block after the catch-block, as parsed.
10106.     69// Else a 'var' from the catch-block warned temporal_dead_zone_a in it.
10107.     69
10108.     69// Recurse walk_statement.
10109.     69
10110.     69        walk_statement(thing.finally);
10111.     69    }
10112.    861
10113.   5064    function post_s_var(thing) {
10114.   6137        thing.name_list.forEach(function (name) {
10115.   1598            if (name.expression) {
10116.   1598
10117.   1598// test_cause:
10118.   1598// ["function aa([aa=aa]){}", "name_lookup", "temporal_dead_zone_a", "aa", 17]
10119.   1598// ["function aa({aa=aa}){}", "name_lookup", "temporal_dead_zone_a", "aa", 17]
10120.   1598// ["let aa=0", "post_s_var", "(live)", "", 0]
10121.   1598// ["let[aa=bb]=0;let bb", "name_lookup", "temporal_dead_zone_a", "bb", 8]
10122.   1598// ["let{aa=bb}=0;let bb", "name_lookup", "temporal_dead_zone_a", "bb", 8]
10123.   1598
10124.   1598                walk_expression(name.expression);
10125.   1598            }
10126.   6137
10127.   6137// PR-502 - Fix long-running regression where 'let x = x;'
10128.   6137// doesn't warn about temporal-dead-zone.
10129.   6137
10130.   6137// 3.var.2 - Mark 'alive', the variable, after variable-declaration.
10131.   6137
10132.   6137            name.alive = true;
10133.   6137        });
10134.   5064    }
10135.    861
10136.    339    function post_t_ternary(thing) {
10137.    339        if (
10138.    339            is_weird(thing.expression[0]) ||
10139.    330            thing.expression[0].constant === true ||
10140.    330            is_equal(thing.expression[1], thing.expression[2])
10141.     11        ) {
10142.     11
10143.     11// test_cause:
10144.     11// ["let aa=(aa?`${0}`:`${0}`)", "post_t_ternary", "unexpected_a", "?", 11]
10145.     11// ["let aa=(aa?`0`:`0`)", "post_t_ternary", "unexpected_a", "?", 11]
10146.     11
10147.     11            warn("unexpected_a", thing);
10148.    328        } else if (is_equal(thing.expression[0], thing.expression[1])) {
10149.    328
10150.    328// test_cause:
10151.    328// ["let aa;let bb=(aa?aa:0);", "post_t_ternary", "expected_a_b", "?", 18]
10152.    328
10153.    328            warn("expected_a_b", thing, "||", "?");
10154.    328        } else if (is_equal(thing.expression[0], thing.expression[2])) {
10155.    328
10156.    328// test_cause:
10157.    328// ["let aa;let bb=(aa?0:aa);", "post_t_ternary", "expected_a_b", "?", 18]
10158.    328
10159.    328            warn("expected_a_b", thing, "&&", "?");
10160.    328        } else if (
10161.    328            thing.expression[1].id === "true" &&
10162.    328            thing.expression[2].id === "false"
10163.    328        ) {
10164.    328
10165.    328// test_cause:
10166.    328// ["let aa;let bb=(aa?true:false);", "post_t_ternary", "expected_a_b", "?", 18]
10167.    328
10168.    328            warn("expected_a_b", thing, "Boolean(...)", "?");
10169.    328        } else if (
10170.    328            thing.expression[1].id === "false" &&
10171.    328            thing.expression[2].id === "true"
10172.    328        ) {
10173.    328
10174.    328// test_cause:
10175.    328// ["let aa;let bb=(aa?false:true);", "post_t_ternary", "expected_a_b", "?", 18]
10176.    328
10177.    328            warn("expected_a_b", thing, "!", "?");
10178.    328        } else if (
10179.    328            thing.expression[0].wrapped !== true &&
10180.    328            (
10181.    328                thing.expression[0].id === "||" ||
10182.    328                thing.expression[0].id === "&&"
10183.    328            )
10184.    328        ) {
10185.    328
10186.    328// test_cause:
10187.    328// ["(aa&&!aa?0:1)", "post_t_ternary", "wrap_subexpression_a_b", "?", 4]
10188.    328
10189.    328            warn(
10190.    328                "wrap_subexpression_a_b",
10191.    328                thing.expression[0],
10192.    328                thing.expression[0].id,
10193.    328                "?"
10194.    328            );
10195.    328        }
10196.    339    }
10197.    861
10198.     10    function post_u_plus(thing) {
10199.     10        const right = thing.expression;
10200.      7        if (!option_dict.convert) {
10201.      7
10202.      7// test_cause:
10203.      7// ["aa=+0", "post_u_plus", "expected_a_b", "+", 4]
10204.      7
10205.      7            warn("expected_a_b", thing, "Number(...)", "+");
10206.      7        }
10207.      2        if (right.id === "(" && right.expression[0].id === "new") {
10208.      2
10209.      2// test_cause:
10210.      2// ["
10211.      2// /*jslint convert*/let aa=+new Date();
10212.      2// ", "post_u_plus", "unexpected_a_before_b", "new", 26]
10213.      2
10214.      2            warn("unexpected_a_before_b", thing, "+", "new");
10215.      8        } else if (
10216.      8            right.constant ||
10217.      8            right.id === "{" ||
10218.      8            (right.id === "[" && right.arity !== "binary")
10219.      8        ) {
10220.      8
10221.      8// test_cause:
10222.      8// ["/*jslint convert*/aa=+{};", "post_u_plus", "unexpected_a", "+", 22]
10223.      8
10224.      8            warn("unexpected_a", thing, "+");
10225.      8        }
10226.     10    }
10227.    861
10228.   4958    function post_u_unary(thing) {
10229.    904        if (thing.id === "`") {
10230.    904            if (thing.expression.every(function (thing) {
10231.    904                return thing.constant;
10232.    904            })) {
10233.    904                thing.constant = true;
10234.    904            }
10235.   4054        } else if (thing.id === "!") {
10236.   4054            if (thing.expression.constant === true) {
10237.   4054
10238.   4054// test_cause:
10239.   4054// ["let aa=!0;", "post_u_unary", "unexpected_a", "!", 8]
10240.   4054
10241.   4054                warn("unexpected_a", thing);
10242.   4054            }
10243.   4054        } else if (thing.id === "!!") {
10244.   4054            if (!option_dict.convert) {
10245.   4054
10246.   4054// test_cause:
10247.   4054// ["let aa= !!0;", "post_u_unary", "expected_a_b", "!!", 9]
10248.   4054// ["let aa=!!0;", "post_u_unary", "expected_a_b", "!!", 8]
10249.   4054
10250.   4054                warn("expected_a_b", thing, "Boolean(...)", "!!");
10251.   4054            }
10252.   4054        } else if (
10253.   4054            thing.id !== "[" &&
10254.   4054            thing.id !== "{" &&
10255.   4054            thing.id !== "function" &&
10256.   4054            thing.id !== "new"
10257.   4054        ) {
10258.   4054            if (thing.expression.constant === true) {
10259.   4054                thing.constant = true;
10260.   4054            }
10261.   4054        }
10262.   4958    }
10263.    861
10264.  41085    function pre_a_bitwise(thing) {
10265.  41085
10266.  41085// These are the bitwise operators.
10267.  41085
10268.  41078        switch (!option_dict.bitwise && thing.id) {
10269.      3        case "&":
10270.      4        case "&=":
10271.      6        case "<<":
10272.      7        case "<<=":
10273.      9        case ">>":
10274.     10        case ">>=":
10275.     12        case ">>>":
10276.     13        case ">>>=":
10277.     15        case "^":
10278.     16        case "^=":
10279.     18        case "|":
10280.     19        case "|=":
10281.     22        case "~":
10282.     22
10283.     22// test_cause:
10284.     22// ["0&0", "pre_a_bitwise", "unexpected_a", "&", 2]
10285.     22// ["0&=0", "pre_a_bitwise", "unexpected_a", "&=", 2]
10286.     22// ["0<<0", "pre_a_bitwise", "unexpected_a", "<<", 2]
10287.     22// ["0<<=0", "pre_a_bitwise", "unexpected_a", "<<=", 2]
10288.     22// ["0>>0", "pre_a_bitwise", "unexpected_a", ">>", 2]
10289.     22// ["0>>=0", "pre_a_bitwise", "unexpected_a", ">>=", 2]
10290.     22// ["0>>>0", "pre_a_bitwise", "unexpected_a", ">>>", 2]
10291.     22// ["0>>>=0", "pre_a_bitwise", "unexpected_a", ">>>=", 2]
10292.     22// ["0^0", "pre_a_bitwise", "unexpected_a", "^", 2]
10293.     22// ["0^=0", "pre_a_bitwise", "unexpected_a", "^=", 2]
10294.     22// ["0|0", "pre_a_bitwise", "unexpected_a", "|", 2]
10295.     22// ["0|=0", "pre_a_bitwise", "unexpected_a", "|=", 2]
10296.     22// ["~0", "pre_a_bitwise", "unexpected_a", "~", 1]
10297.     22
10298.     22            warn("unexpected_a", thing);
10299.     22            break;
10300.  41085        }
10301.  41085        if (
10302.  29578            thing.id !== "(" &&
10303.  29578            thing.id !== "&&" &&
10304.  28046            thing.id !== "||" &&
10305.  26997            thing.id !== "=" &&
10306.  22436
10307.  22436// PR-514 - Bugfix - Skip the 'of' or 'in' node of a for-loop-head, so
10308.  22436// 'for (aa of bb < cc)' does not warn on its own 'of', like the const form.
10309.  22436
10310.  22436            thing.for_init !== true &&
10311.  22424            Array.isArray(thing.expression) &&
10312.   9435            thing.expression.length === 2 &&
10313.   9427            (
10314.   9427                relationop[thing.expression[0].id] === true ||
10315.   9427                relationop[thing.expression[1].id] === true
10316.   9427            )
10317.      1        ) {
10318.      1
10319.      1// test_cause:
10320.      1// ["0<0<0", "pre_a_bitwise", "unexpected_a", "<", 4]
10321.      1
10322.      1            warn("unexpected_a", thing);
10323.      1        }
10324.  41085    }
10325.    861
10326.  35748    function pre_b_binary(thing) {
10327.  35748        let left;
10328.  35748        let right;
10329.  35748        let value;
10330.   4312        if (relationop[thing.id] === true) {
10331.   4312            left = thing.expression[0];
10332.   4312            right = thing.expression[1];
10333.   4312            if (left.id === "NaN" || right.id === "NaN") {
10334.   4312
10335.   4312// test_cause:
10336.   4312// ["NaN===NaN", "pre_b_binary", "number_isNaN", "===", 4]
10337.   4312
10338.   4312                warn("number_isNaN", thing);
10339.   4312            } else if (left.id === "typeof") {
10340.   4312                if (right.id !== "(string)") {
10341.   4312                    if (right.id !== "typeof") {
10342.   4312
10343.   4312// test_cause:
10344.   4312// ["typeof 0===0", "pre_b_binary", "expected_string_a", "0", 12]
10345.   4312// ["typeof 0===0;", "pre_b_binary", "expected_string_a", "0", 12]
10346.   4312
10347.   4312                        warn("expected_string_a", right);
10348.   4312                    }
10349.   4312                } else {
10350.   4312                    value = right.value;
10351.   4312                    if (value === "null" || value === "undefined") {
10352.   4312
10353.   4312// test_cause:
10354.   4312// ["
10355.   4312// typeof aa==="undefined"
10356.   4312// ", "pre_b_binary", "unexpected_typeof_a", "undefined", 13]
10357.   4312
10358.   4312                        warn("unexpected_typeof_a", right, value);
10359.   4312                    } else if (
10360.   4312                        value !== "bigint" &&
10361.   4312                        value !== "boolean" &&
10362.   4312                        value !== "function" &&
10363.   4312                        value !== "number" &&
10364.   4312                        value !== "object" &&
10365.   4312                        value !== "string" &&
10366.   4312                        value !== "symbol"
10367.   4312                    ) {
10368.   4312
10369.   4312// test_cause:
10370.   4312// ["typeof 0===\"aa\"", "pre_b_binary", "expected_type_string_a", "aa", 12]
10371.   4312
10372.   4312                        warn("expected_type_string_a", right, value);
10373.   4312                    }
10374.   4312                }
10375.   4312            }
10376.   4312        }
10377.  35748    }
10378.    861
10379.      1    function pre_b_eqeq(thing) {
10380.      1
10381.      1// test_cause:
10382.      1// ["0==0", "pre_b_eqeq", "expected_a_b", "==", 2]
10383.      1
10384.      1        warn("expected_a_b", thing, "===", "==");
10385.      1    }
10386.    861
10387.      6    function pre_b_in(thing) {
10388.      1        if (!thing.for_init) {
10389.      1
10390.      1// test_cause:
10391.      1// ["aa in aa", "pre_b_in", "infix_in", "in", 4]
10392.      1
10393.      1            warn("infix_in", thing);
10394.      1        }
10395.      6    }
10396.    861
10397.      1    function pre_b_instanceof(thing) {
10398.      1
10399.      1// test_cause:
10400.      1// ["0 instanceof 0", "pre_b_instanceof", "unexpected_a", "instanceof", 3]
10401.      1
10402.      1        warn("unexpected_a", thing);
10403.      1    }
10404.    861
10405.      1    function pre_b_noteq(thing) {
10406.      1
10407.      1// test_cause:
10408.      1// ["0!=0", "pre_b_noteq", "expected_a_b", "!=", 2]
10409.      1
10410.      1        warn("expected_a_b", thing, "!==", "!=");
10411.      1    }
10412.    861
10413.      8    function pre_b_of(thing) {
10414.      1        if (!thing.for_init) {
10415.      1
10416.      1// test_cause:
10417.      1// ["0 of 0", "pre_b_of", "unexpected_a", "of", 3]
10418.      1
10419.      1            warn("unexpected_a", thing);
10420.      1        }
10421.      8    }
10422.    861
10423.   1049    function pre_b_or(thing) {
10424.   2098        thing.expression.forEach(function (thang) {
10425.    182            if (thang.id === "&&" && !thang.wrapped) {
10426.      1
10427.      1// test_cause:
10428.      1// ["0&&0||0", "pre_b_or", "wrap_subexpression_a_b", "||", 2]
10429.      1
10430.      1                warn("wrap_subexpression_a_b", thang, "&&", "||");
10431.      1            }
10432.   2098        });
10433.   1049    }
10434.    861
10435.     90    function pre_s_for(thing) {
10436.     90
10437.     90// PR-504 - Add hidden scope_block for:
10438.     90// - for-variable
10439.     90
10440.     90        scope_block = scope_block_push(thing, false);
10441.     18        if (thing.for_semicolon) {
10442.     18            walk_statement(thing.for_semicolon[0]);
10443.     18            walk_expression(thing.for_semicolon[1]);
10444.     18        }
10445.     72        if (thing.for_of) {
10446.     72            switch (thing.for_of.id) {
10447.     72            case "const":
10448.     72            case "let":
10449.     72            case "var":
10450.     72
10451.     72// PR-514 - Bugfix - Walk the iterable of destructured 'for (const [aa] of bb)',
10452.     72// which <stmt_var> keeps in <expression>, and <post_s_var> does not walk. Walk
10453.     72// it before <post_s_var> marks the names alive, to catch temporal_dead_zone_a.
10454.     72
10455.     72                walk_expression(thing.for_of.expression);
10456.     72                post_s_var(thing.for_of);
10457.     72                break;
10458.     72            default:
10459.     72                walk_expression(thing.for_of);
10460.     72            }
10461.     72        }
10462.     90    }
10463.    861
10464.   2351    function pre_s_function(thing) {
10465.   2351
10466.   2351// test_cause:
10467.   2351// ["()=>0", "pre_s_function", "(live)", "", 0]
10468.   2351// ["(function (){}())", "pre_s_function", "(live)", "", 0]
10469.   2351// ["function aa(){}", "pre_s_function", "(live)", "", 0]
10470.   2351
10471.   1228        if (thing.arity === "statement" && !scope_block.function_body) {
10472.      2
10473.      2// test_cause:
10474.      2// ["if(0){function aa(){}}", "pre_s_function", "unexpected_a", "function", 7]
10475.      2
10476.      2            warn("unexpected_a", thing);
10477.      2        }
10478.   2351
10479.   2351// PR-504 - Add hidden scope_block for:
10480.   2351// - function-parameter
10481.   2351
10482.   2351        scope_block = scope_block_push(thing.scope_name, false);
10483.   2351        scope_block = scope_block_push(thing, false);
10484.   2351        scope_function = scope_function_push(thing, false);
10485.     12        if (thing.extra === "get") {
10486.     12            if (thing.parameter_count !== 0) {
10487.     12
10488.     12// test_cause:
10489.     12// ["
10490.     12// /*jslint getset*/
10491.     12// aa={get aa(aa){}}
10492.     12// ", "pre_s_function", "bad_get", "function", 9]
10493.     12
10494.     12                warn("bad_get", thing);
10495.     12            }
10496.   2339        } else if (thing.extra === "set") {
10497.   2339
10498.   2339// PR-514 - Bugfix - A setter's one parameter cannot be a rest-parameter, a
10499.   2339// SyntaxError. Read <parameter_rest>, since <name_list> flattens destructuring
10500.   2339// and cannot tell a rest-parameter from a valid rest-element inside one.
10501.   2339
10502.   2339            if (thing.parameter_count !== 1 || thing.parameter_rest) {
10503.   2339
10504.   2339// test_cause:
10505.   2339// ["
10506.   2339// /*jslint getset*/
10507.   2339// aa={set aa(){}}
10508.   2339// ", "pre_s_function", "bad_set", "function", 9]
10509.   2339// ["
10510.   2339// /*jslint getset*/
10511.   2339// aa={set aa(...aa){}}
10512.   2339// ", "pre_s_function", "bad_set", "function", 9]
10513.   2339
10514.   2339                warn("bad_set", thing);
10515.   2339            }
10516.   2339        }
10517.   2351
10518.   2351// 4.par.2 - Mark 'alive', the function-parameter, after destructuring.
10519.   2351
10520.   2351        post_s_var(thing);
10521.   2351    }
10522.    861
10523.  32425    function pre_v_var(thing) {
10524.  32425        const the_variable = name_lookup(thing);
10525.  32299        if (the_variable !== undefined) {
10526.  32299            thing.variable = the_variable;
10527.  32299            the_variable.used = true;
10528.  32299        }
10529.  32425    }
10530.    861
10531. 183092    function walk_expression(thing) {
10532. 117173        if (thing) {
10533. 117173            if (Array.isArray(thing)) {
10534. 117173
10535. 117173// test_cause:
10536. 117173// ["(function(){}())", "walk_expression", "(live)", "", 0]
10537. 117173// ["0&&0", "walk_expression", "(live)", "", 0]
10538. 117173
10539. 117173                thing.forEach(walk_expression);
10540. 117173            } else {
10541. 117173                preamble(thing);
10542. 117173                walk_expression(thing.expression);
10543. 117173
10544. 117173// PR-414 - Bugfix - Fix fart-body not being walked.
10545. 117173
10546. 117173                if (thing.id === "function" || thing.id === "=>") {
10547. 117173
10548. 117173// test_cause:
10549. 117173// ["aa=()=>0", "walk_expression", "(live)", "", 0]
10550. 117173// ["aa=function(){}", "walk_expression", "(live)", "", 0]
10551. 117173
10552. 117173// Recurse walk_statement.
10553. 117173
10554. 117173                    walk_statement(thing.block);
10555. 117173                }
10556. 117173                if (
10557. 117173                    thing.arity === "preassign" || thing.arity === "postassign"
10558. 117173                ) {
10559. 117173
10560. 117173// test_cause:
10561. 117173// ["if(++aa){}", "walk_expression", "unexpected_a", "++", 4]
10562. 117173// ["if(--aa){}", "walk_expression", "unexpected_a", "--", 4]
10563. 117173// ["if(aa++){}", "walk_expression", "unexpected_a", "++", 6]
10564. 117173// ["if(aa--){}", "walk_expression", "unexpected_a", "--", 6]
10565. 117173
10566. 117173                    warn("unexpected_a", thing);
10567. 117173                } else if (
10568. 117173                    thing.arity === "statement" ||
10569. 117173                    thing.arity === "assignment"
10570. 117173                ) {
10571. 117173
10572. 117173// test_cause:
10573. 117173// ["aa[aa=0]", "walk_expression", "unexpected_statement_a", "=", 6]
10574. 117173
10575. 117173                    warn("unexpected_statement_a", thing);
10576. 117173                }
10577. 117173
10578. 117173// test_cause:
10579. 117173// ["aa=0", "walk_expression", "(live)", "", 0]
10580. 117173
10581. 117173                postamble(thing);
10582. 117173            }
10583. 117173        }
10584. 183092    }
10585.    861
10586.  88137    function walk_statement(thing) {
10587.  48175        if (!thing) {
10588.  48175            return;
10589.  48175        }
10590.  39962        if (Array.isArray(thing)) {
10591.   9060
10592.   9060// test_cause:
10593.   9060// ["+[]", "walk_statement", "(live)", "", 0]
10594.   9060
10595.   9060// Recurse walk_statement.
10596.   9060
10597.   9060            thing.forEach(walk_statement);
10598.   9060            return;
10599.  30902        }
10600.  30902
10601.  30902// PR-504 - Add hidden scope_block for:
10602.  30902// - label-name
10603.  30902
10604.  30902        if (thing.label_name) {
10605.     18            scope_block = scope_block_push(thing.label_name, false);
10606.  30902        }
10607.  30902        if (thing.scope_block) {
10608.   6456            scope_block = scope_block_push(thing, false);
10609.  30902        }
10610.  30902        preamble(thing);
10611.  30902        walk_expression(thing.expression);
10612.  30902        if (thing.arity === "binary") {
10613.   5628            if (thing.id !== "(") {
10614.   5628
10615.   5628// test_cause:
10616.   5628// ["0&&0", "walk_statement", "unexpected_expression_a", "&&", 2]
10617.   5628
10618.   5628                warn("unexpected_expression_a", thing);
10619.   5628            }
10620.  25274        } else if (
10621.  25274            thing.arity !== "statement" &&
10622.  25274            thing.arity !== "assignment" &&
10623.  25274            thing.id !== "import"
10624.  25274        ) {
10625.  25274
10626.  25274// test_cause:
10627.  25274// ["!0", "walk_statement", "unexpected_expression_a", "!", 1]
10628.  25274// ["+[]", "walk_statement", "unexpected_expression_a", "+", 1]
10629.  25274// ["+new aa()", "walk_statement", "unexpected_expression_a", "+", 1]
10630.  25274// ["0", "walk_statement", "unexpected_expression_a", "0", 1]
10631.  25274// ["typeof 0", "walk_statement", "unexpected_expression_a", "typeof", 1]
10632.  25274
10633.  25274            warn("unexpected_expression_a", thing);
10634.  30902        }
10635.  30902
10636.  30902// Recurse walk_statement.
10637.  30902
10638.  30902        walk_statement(thing.block);
10639.  30902        walk_statement(thing.else);
10640.  30902        postamble(thing);
10641.  30902        if (thing.scope_block) {
10642.   6456            scope_block = scope_block_pop();
10643.  30902        }
10644.  30902        if (thing.label_name) {
10645.     18            scope_block = scope_block_pop();
10646.     18        }
10647.  88137    }
10648.    861
10649.    861    postaction = action(posts);
10650.    861    postamble = amble(posts);
10651.    861    preaction = action(pres);
10652.    861    preamble = amble(pres);
10653.    861    postaction("assignment", "(all)", post_a_assignment);
10654.    861    postaction("assignment", "+=", post_a_pluseq);
10655.    861    postaction("binary", "&&", post_b_and);
10656.    861    postaction("binary", "(", post_b_lparen);
10657.    861    postaction("binary", "(all)", post_b_binary);
10658.    861    postaction("binary", "=>", post_s_function);
10659.    861    postaction("binary", "[", post_b_lbracket);
10660.    861    postaction("binary", "||", post_b_or);
10661.    861    postaction("postassign", "(all)", post_p_update);
10662.    861    postaction("preassign", "(all)", post_p_update);
10663.    861    postaction("statement", "const", post_s_var);
10664.    861    postaction("statement", "export", post_s_export_toplevel);
10665.    861    postaction("statement", "for", post_s_for);
10666.    861    postaction("statement", "function", post_s_function);
10667.    861    postaction("statement", "import", post_s_import);
10668.    861    postaction("statement", "let", post_s_var);
10669.    861    postaction("statement", "try", post_s_try);
10670.    861    postaction("statement", "var", post_s_var);
10671.    861    postaction("ternary", "(all)", post_t_ternary);
10672.    861    postaction("unary", "(all)", post_u_unary);
10673.    861    postaction("unary", "+", post_u_plus);
10674.    861    postaction("unary", "function", post_s_function);
10675.    861    preaction("assignment", "(all)", pre_a_bitwise);
10676.    861    preaction("binary", "!=", pre_b_noteq);
10677.    861    preaction("binary", "(all)", pre_a_bitwise);
10678.    861    preaction("binary", "(all)", pre_b_binary);
10679.    861    preaction("binary", "==", pre_b_eqeq);
10680.    861    preaction("binary", "=>", pre_s_function);
10681.    861    preaction("binary", "in", pre_b_in);
10682.    861    preaction("binary", "instanceof", pre_b_instanceof);
10683.    861    preaction("binary", "of", pre_b_of);
10684.    861    preaction("binary", "||", pre_b_or);
10685.    861    preaction("statement", "for", pre_s_for);
10686.    861    preaction("statement", "function", pre_s_function);
10687.    861    preaction("unary", "function", pre_s_function);
10688.    861    preaction("unary", "~", pre_a_bitwise);
10689.    861    preaction("variable", "(all)", pre_v_var);
10690.    861
10691.    861// Init block_stack, function_stack.
10692.    861
10693.    861    block_stack.length = 0;
10694.    861    function_stack.length = 0;
10695.    861    scope_block = scope_block_push(token_global, false);
10696.    861    scope_function = scope_function_push(token_global, false);
10697.    861
10698.    861// Walk the token_tree.
10699.    861
10700.    861    walk_statement(state.token_tree);
10701.    861
10702.    861// Cleanup block_stack, function_stack.
10703.    861
10704.    861    jslint_assert(
10705.    861        block_stack.length === 1,
10706.    861        `block_stack.length=${block_stack.length}.`
10707.    861    );
10708.    861    jslint_assert(
10709.    861        function_stack.length === 1,
10710.    861        `function_stack.length=${function_stack.length}.`
10711.    861    );
10712.    861    block_stack.length = 0;
10713.    861    function_stack.length = 0;
10714.    861}
10715.     23
10716.    306function jslint_phase5_whitage(state) {
10717.    306
10718.    306// PHASE 5. Check whitespace between tokens in <token_list>.
10719.    306
10720.    306    const {
10721.    306        artifact,
10722.    306        block_list,
10723.    306        option_dict,
10724.    306        token_global,
10725.    306        token_list,
10726.    306        warn
10727.    306    } = state;
10728.    306    const indent_stack = [];
10729.    306    let closer = "(end)";
10730.    306    let dot_depth = 0;
10731.    306    let indentage;
10732.    306    let left = token_global;
10733.    306    let margin = 0;
10734.    306    let mode_indent = (
10735.    306
10736.    306// PR-330 - Allow 2-space indent.
10737.    306
10738.    306        option_dict.indent2
10739.      4        ? 2
10740.    302        : 4
10741.    306    );
10742.    306    let nr_comments_skipped = 0;
10743.    306    let open = true;
10744.    306    let opening = true;
10745.    306    let right;
10746.    306
10747.    306// This is the set of infix operators that require a space on each side.
10748.    306
10749.    306    let spaceop = object_assign_from_list(empty(), [
10750.    306        "!=", "!==",
10751.    306        "%", "%=",
10752.    306        "&", "&&", "&&=", "&=",
10753.    306        "*", "**", "**=", "*=",
10754.    306        "+=",
10755.    306        "-=",
10756.    306        "/", "/=",
10757.    306        "<", "<<", "<<=", "<=",
10758.    306        "=", "==", "===", "=>",
10759.    306        ">", ">=", ">>", ">>=", ">>>", ">>>=",
10760.    306        "??", "??=",
10761.    306        "^", "^=",
10762.    306        "|", "|=", "||", "||="
10763.    306    ], true);
10764.    306
10765.  37811    function at_margin(fit) {
10766.  37811        const at = margin + fit;
10767.     45        if (right.from !== at) {
10768.     45            return expected_at(at);
10769.     45        }
10770.  37811    }
10771.    306
10772.   8880    function delve(the_block) {
10773.   7517        Object.keys(the_block.context).forEach(function (id) {
10774.   7517            const name = the_block.context[id];
10775.   7483            if (id !== "ignore" && name.scope_declared === the_block) {
10776.   7483
10777.   7483// test_cause:
10778.   7483// ["function aa(aa) {return aa;}", "delve", "(live)", "", 0]
10779.   7483
10780.   7483                if (!name.used) {
10781.   7483
10782.   7483// test_cause:
10783.   7483// ["function aa(){bb:while(aa){aa();}}", "delve", "unused_a", "bb", 15]
10784.   7483// ["function aa(bb){return;}", "delve", "unused_a", "bb", 13]
10785.   7483// ["let aa;", "delve", "unused_a", "aa", 5]
10786.   7483// ["let aa=0;try{aa();}catch(bb){aa();}", "delve", "unused_a", "bb", 26]
10787.   7483
10788.   7483                    warn("unused_a", name);
10789.   7483                } else if (!name.assigned) {
10790.   7483
10791.   7483// test_cause:
10792.   7483// ["let aa;aa&&=0;aa();", "delve", "unassigned_var_a", "aa", 5]
10793.   7483// ["let aa;aa();", "delve", "unassigned_var_a", "aa", 5]
10794.   7483
10795.   7483                    warn("unassigned_var_a", name);
10796.   7483                }
10797.   7483            }
10798.   7517        });
10799.   8880    }
10800.    306
10801.     54    function expected_at(at) {
10802.     54
10803.     54// PR-510 - deadcode-confirmed - <right> is always assigned first. The whitage
10804.     54// walk starts in one place, the <token_list>.forEach whose first statement is
10805.     54// <right> = <the_token>, and every route to <expected_at> runs inside it.
10806.     54//
10807.     54// deadcode-revive - Call <expected_at>, or anything that reaches it, from
10808.     54// outside that forEach. A pre-pass or post-pass indent check would do it, and
10809.     54// <right> would hold whatever the last token left there, or undefined.
10810.     54//
10811.     54// if (right === undefined) {
10812.     54//     right = token_nxt;
10813.     54// }
10814.     54
10815.     54        jslint_assert(
10816.     54            !(right === undefined),
10817.     54            `Expected !(right === undefined).`
10818.     54        );
10819.     54
10820.     54// test_cause:
10821.     54// ["
10822.     54// let aa;
10823.     54//   aa();
10824.     54// ", "expected_at", "expected_a_at_b_c", "aa", 3]
10825.     54
10826.     54        warn(
10827.     54            "expected_a_at_b_c",
10828.     54            right,
10829.     54            artifact(right),
10830.     54            at,
10831.     54            right.from
10832.     54        );
10833.     54    }
10834.    306
10835. 107590    function no_space_only() {
10836. 107590        if (
10837. 107588            left.id !== "(global)" &&
10838. 107588            left.nr + 1 === right.nr &&
10839. 107587            (
10840. 107587                left.line !== right.line ||
10841. 107587                left.thru !== right.from
10842. 107587            )
10843.     27        ) {
10844.     27
10845.     27// test_cause:
10846.     27// ["String( 0);", "no_space_only", "unexpected_space_a_b", "0", 9]
10847.     27
10848.     27            warn(
10849.     27                "unexpected_space_a_b",
10850.     27                right,
10851.     27                artifact(left),
10852.     27                artifact(right)
10853.     27            );
10854.     27        }
10855. 107590    }
10856.    306
10857.  50566    function one_space() {
10858.  48427        if (left.line === right.line || !open) {
10859.  48427            if (left.thru + 1 !== right.from && nr_comments_skipped === 0) {
10860.  48427
10861.  48427// test_cause:
10862.  48427// ["String(0,0);", "one_space", "expected_space_a_b", "0", 10]
10863.  48427
10864.  48427                warn(
10865.  48427                    "expected_space_a_b",
10866.  48427                    right,
10867.  48427                    artifact(left),
10868.  48427                    artifact(right)
10869.  48427                );
10870.  48427            }
10871.  48427            return;
10872.  48427        }
10873.   2139        if (right.from !== margin) {
10874.      6
10875.      6// test_cause:
10876.      6// ["
10877.      6// let aa={
10878.      6// aa:
10879.      6// 0};
10880.      6// ", "one_space", "(live)", "", 0]
10881.      6
10882.      6            expected_at(margin);
10883.      6        }
10884.  50566    }
10885.    306
10886.  10217    function one_space_only() {
10887.  10216        if (left.line !== right.line || left.thru + 1 !== right.from) {
10888.     28            warn("expected_space_a_b", right, artifact(left), artifact(right));
10889.     28        }
10890.  10217    }
10891.    306
10892.  29637    function whitage_closer() {
10893.  29637
10894.  29637// test_cause:
10895.  29637// ["String(0);", "whitage_closer", "(live)", "", 0]
10896.  29637// ["let aa=[0];", "whitage_closer", "(live)", "", 0]
10897.  29637// ["let aa=`${0}`;", "whitage_closer", "(live)", "", 0]
10898.  29637// ["let aa={String};", "whitage_closer", "(live)", "", 0]
10899.  29637
10900.  29637// If right is a closer, then pop the previous state.
10901.  29637
10902.  29637        indentage = indent_stack.pop();
10903.  29637        closer = indentage.closer;
10904.  29637        margin = indentage.margin;
10905.  29637        open = indentage.open;
10906.  29637        opening = indentage.opening;
10907.  29637
10908.  29637// Commit 3903449a - Cleanup indent for multiline-method-chaining.
10909.  29637
10910.    108        if (dot_depth > 1) {
10911.    108            dot_depth -= 1;
10912.    108        }
10913.   9884        if (opening && right.id !== ";") {
10914.   9884
10915.   9884// test_cause:
10916.   9884// ["
10917.   9884// String(
10918.   9884// 0);
10919.   9884// ", "whitage_closer", "(live)", "", 0]
10920.   9884
10921.   9884            at_margin(
10922.   9884                indentage.dot_depth === 1
10923.   9884
10924.   9884// Commit 3903449a - Cleanup indent for multiline-method-chaining.
10925.   9884
10926.   9884                ? mode_indent
10927.   9884                : 0
10928.   9884            );
10929.   9884            return;
10930.  19753        }
10931.  19753
10932.  19753// test_cause:
10933.  19753// ["String( );", "whitage_closer", "(live)", "", 0]
10934.  19753
10935.  19753        no_space_only();
10936.  19753    }
10937.    306
10938. 213888    function whitage_default() {
10939. 213888
10940. 213888// The open and close pairs.
10941. 213888
10942. 213888        switch (left.id) {
10943.    824        case "${":
10944.  19875        case "(":
10945.  22331        case "[":
10946.  29637        case "{":
10947.  29637            whitage_opener();
10948.  29637            return;
10949. 184251        }
10950. 184251        if (right.id === closer) {
10951.  26993            whitage_closer();
10952.  26993            return;
10953. 157258        }
10954. 157258
10955. 157258// Left is not an opener, and right is not a closer.
10956. 157258// The nature of left and right will determine the space between them.
10957. 157258
10958. 157258        if (right.statement === true) {
10959.  15792            if (left.id === "else") {
10960.  15792
10961.  15792// test_cause:
10962.  15792// ["
10963.  15792// let aa=0;if(aa){aa();}else if(aa){aa();}
10964.  15792// ", "whitage_default", "(live)", "", 0]
10965.  15792
10966.  15792                one_space_only();
10967.  15792                return;
10968.  15792            }
10969.  15792
10970.  15792// test_cause:
10971.  15792// ["let aa;", "whitage_default", "(live)", "", 0]
10972.  15792
10973.  15792            at_margin(0);
10974.  15792            open = false;
10975.  15792            return;
10976. 141466        }
10977. 141466
10978. 141466// If left is ',' or ';' or right is a statement, then if open,
10979. 141466// right must go at the margin, or if closed, a space between.
10980. 141466
10981. 141466        if (right.switch) {
10982.   1780            at_margin(-mode_indent);
10983.   1780            return;
10984. 139686        }
10985. 139686        if (right.role === "label") {
10986.      3            if (right.from !== 0) {
10987.      3
10988.      3// test_cause:
10989.      3// ["
10990.      3// function aa(){
10991.      3//     aa();bb:while(aa){aa();}}
10992.      3// ", "whitage_default", "(live)", "", 0]
10993.      3
10994.      3                expected_at(0);
10995.      3            }
10996.      3            return;
10997. 139683        }
10998. 139683        if (left.id === ",") {
10999.  10664            if (
11000.  10664                !open ||
11001.  10664                (closer === "]" && left.line === right.line)
11002.  10664            ) {
11003.  10664
11004.  10664// test_cause:
11005.  10664// ["String(0,0);", "whitage_default", "(live)", "", 0]
11006.  10664
11007.  10664                one_space();
11008.  10664                return;
11009.  10664            }
11010.  10664
11011.  10664// test_cause:
11012.  10664// ["
11013.  10664// String(
11014.  10664// 0,0);
11015.  10664// ", "whitage_default", "(live)", "", 0]
11016.  10664
11017.  10664            return;
11018. 129019        }
11019. 129019
11020. 129019// If right is a ternary operator, line it up on the margin.
11021. 129019
11022. 129019        if (right.arity === "ternary") {
11023.    622            if (open) {
11024.    622
11025.    622// test_cause:
11026.    622// ["
11027.    622// String(
11028.    622// String?0:1);
11029.    622// ", "whitage_default", "(live)", "", 0]
11030.    622
11031.    622                at_margin(0);
11032.    622                return;
11033.    622            }
11034.    622
11035.    622// test_cause:
11036.    622// ["String(String?0:1);", "whitage_default", "use_open", "?", 14]
11037.    622
11038.    622            warn("use_open", right);
11039.    622            return;
11040. 128397        }
11041. 128397        if (
11042. 128397            left.id === "." ||
11043. 115903            left.id === "?." ||
11044. 115837            left.id === "..." ||
11045. 115718            right.id === "," ||
11046. 105055            right.id === ";" ||
11047.  88262            right.id === ":" ||
11048.  84810            (
11049.  84810                right.arity === "binary" &&
11050.  84810                (right.id === "(" || right.id === "[")
11051.  84810            ) ||
11052.  72217            (
11053.  72217                right.arity === "function" &&
11054.  72217                left.id !== "function"
11055.  72217            )
11056.  57363        ) {
11057.  57363
11058.  57363// test_cause:
11059.  57363// ["String(...String);", "whitage_default", "(live)", "", 0]
11060.  57363
11061.  57363            no_space_only();
11062.  57363            return;
11063.  71034        }
11064.  71034        if (right.id === "." || right.id === "?.") {
11065.  12560            if (left.line === right.line) {
11066.  12560
11067.  12560// test_cause:
11068.  12560// ["String?.aa();", "whitage_default", "(live)", "", 0]
11069.  12560
11070.  12560                no_space_only();
11071.  12560                return;
11072.  12560            }
11073.  12560            at_margin(mode_indent);
11074.  12560            return;
11075.  58474        }
11076.  58474        if (left.id === ";") {
11077.     10            if (open) {
11078.     10
11079.     10// test_cause:
11080.     10// ["
11081.     10// function aa() {
11082.     10//     for (
11083.     10//         let bb = 0;
11084.     10// bb < 0;
11085.     10//         bb += 1
11086.     10//     ) {
11087.     10//         aa(bb);
11088.     10//     }
11089.     10// }
11090.     10// ", "whitage_default", "(live)", "", 0]
11091.     10
11092.     10                at_margin(0);
11093.     10            }
11094.     10            return;
11095.  58464        }
11096.  58464        if (left.getset === true) {
11097.      9
11098.      9// PR-514 - Bugfix - On one line, <one_space> still lets a comment sit between
11099.      9// the 'get' or 'set' and its name.
11100.      9
11101.      9            if (left.line === right.line) {
11102.      9
11103.      9// test_cause:
11104.      9// ["
11105.      9// /*jslint getset*/
11106.      9// String({get aa() {
11107.      9//     return;
11108.      9// }});
11109.      9// ", "whitage_default", "(live)", "", 0]
11110.      9
11111.      9                one_space();
11112.      9            } else {
11113.      9
11114.      9// test_cause:
11115.      9// ["
11116.      9// /*jslint getset*/
11117.      9// String({
11118.      9//     get
11119.      9//     aa() {
11120.      9//         return;
11121.      9//     }
11122.      9// });
11123.      9// ", "one_space_only", "expected_space_a_b", "aa", 5]
11124.      9
11125.      9                one_space_only();
11126.      9            }
11127.      9            return;
11128.  58455        }
11129.  58455        if (
11130.  58455            left.arity === "ternary" ||
11131.  57833            left.id === "case" ||
11132.  55916            left.id === "catch" ||
11133.  55849            left.id === "else" ||
11134.  55629            left.id === "finally" ||
11135.  55580            left.id === "while" ||
11136.  55369            left.id === "await" ||
11137.  55023            right.id === "catch" ||
11138.  54967            right.id === "else" ||
11139.  54539            right.id === "finally" ||
11140.  54531            (right.id === "while" && !right.statement) ||
11141.  54529            (left.id === ")" && right.id === "{")
11142.   9998        ) {
11143.   9998
11144.   9998// test_cause:
11145.   9998// ["if(String()){String();}", "whitage_default", "(live)", "", 0]
11146.   9998
11147.   9998            one_space_only();
11148.   9998            return;
11149.  48457        }
11150.  48457        if (
11151.  48457
11152.  48457// There is a space between left and right.
11153.  48457
11154.  48457            spaceop[left.id] === true ||
11155.  35055            spaceop[right.id] === true ||
11156.  21715            (
11157.  21715                left.arity === "binary" &&
11158.  21715                (left.id === "+" || left.id === "-")
11159.  21715            ) ||
11160.  19169            (
11161.  19169                right.arity === "binary" &&
11162.  19169                (right.id === "+" || right.id === "-")
11163.  19169            ) ||
11164.  16623            left.id === "function" ||
11165.  14475            left.id === ":" ||
11166.  13100            left.id === "async" ||
11167.  12960            (
11168.  12960                (
11169.  12960                    left.identifier ||
11170.  12960                    left.id === "(string)" ||
11171.  12960                    left.id === "(number)"
11172.  12960                ) &&
11173.  12960                (
11174.  12960                    right.identifier ||
11175.  12960                    right.id === "(string)" ||
11176.  12960                    right.id === "(number)"
11177.  12960                )
11178.  12960            ) ||
11179.   8377            (left.arity === "statement" && right.id !== ";")
11180.  44165        ) {
11181.  44165
11182.  44165// test_cause:
11183.  44165// ["let aa=0;", "whitage_default", "(live)", "", 0]
11184.  44165
11185.  44165            one_space();
11186.  44165            return;
11187.  44165        }
11188.   4292        if (left.arity === "unary" && left.id !== "`") {
11189.    882            no_space_only();
11190.    882            return;
11191.    882        }
11192. 213888    }
11193.    306
11194.  29637    function whitage_opener() {
11195.  29637
11196.  29637// test_cause:
11197.  29637// ["String();", "whitage_opener", "(live)", "", 0]
11198.  29637// ["String(0);", "whitage_opener", "(live)", "", 0]
11199.  29637// ["let aa=[0];", "whitage_opener", "(live)", "", 0]
11200.  29637// ["let aa=[];", "whitage_opener", "(live)", "", 0]
11201.  29637// ["let aa=`${0}`;", "whitage_opener", "(live)", "", 0]
11202.  29637// ["let aa={String};", "whitage_opener", "(live)", "", 0]
11203.  29637// ["let aa={};", "whitage_opener", "(live)", "", 0]
11204.  29637
11205.  29586        opening = left.open || (left.line !== right.line);
11206.  29637        indentage = {
11207.  29637            closer,
11208.  29637            dot_depth,
11209.  29637            margin,
11210.  29637            open,
11211.  29637            opening
11212.  29637        };
11213.  29637        indent_stack.push(indentage);
11214.  29637
11215.  29637// Commit 3903449a - Cleanup indent for multiline-method-chaining.
11216.  29637
11217.    138        if (dot_depth >= 1) {
11218.    138            dot_depth += 1;
11219.    138            if (dot_depth === 2) {
11220.    138                margin += mode_indent;
11221.    138            }
11222.    138        }
11223.  29637        switch (left.id) {
11224.    824        case "${":
11225.    824            closer = "}";
11226.    824            break;
11227.  19051        case "(":
11228.  19051            closer = ")";
11229.  19051            break;
11230.   2456        case "[":
11231.   2456            closer = "]";
11232.   2456            break;
11233.   7306        case "{":
11234.   7306            closer = "}";
11235.   7306            break;
11236.  29637        }
11237.   2644        if (right.id === closer) {
11238.   2644            whitage_closer();
11239.   2644            return;
11240.  26993        }
11241.  26993        if (opening) {
11242.   9878
11243.   9878// test_cause:
11244.   9878// ["
11245.   9878// String(
11246.   9878// 0);
11247.   9878// ", "whitage_opener", "(live)", "", 0]
11248.   9878
11249.   9878            open = true;
11250.   9878            margin += mode_indent;
11251.   9878            if (right.role === "label") {
11252.   9878                if (right.from !== 0) {
11253.   9878
11254.   9878// test_cause:
11255.   9878// ["
11256.   9878// function aa(){
11257.   9878//  bb:while(aa){aa();}}
11258.   9878// ", "whitage_opener", "(live)", "", 0]
11259.   9878
11260.   9878                    expected_at(0);
11261.   9878                }
11262.   9878            } else if (right.switch) {
11263.   9878                at_margin(-mode_indent);
11264.   9878            } else {
11265.   9878                at_margin(0);
11266.   9878            }
11267.   9878            return;
11268.  17115        }
11269.  17115        if (
11270.  17115            (right.statement || right.role === "label") &&
11271.     68            (!right.for_init || left.line !== right.line)
11272.     23        ) {
11273.     23
11274.     23// test_cause:
11275.     23// ["
11276.     23// function aa(){bb:while(aa){aa();}}
11277.     23// ", "whitage_opener", "expected_line_break_a_b", "aa", 28]
11278.     23
11279.     23            warn(
11280.     23                "expected_line_break_a_b",
11281.     23                right,
11282.     23                artifact(left),
11283.     23                artifact(right)
11284.     23            );
11285.  17115        }
11286.  17115        open = false;
11287.  17115
11288.  17115// test_cause:
11289.  17115// ["String(0);", "whitage_opener", "(live)", "", 0]
11290.  17115
11291.  17115        no_space_only();
11292.  17115    }
11293.    306
11294.    306// unassigned_or_unused();
11295.    306// Delve into the functions looking for variables that were not assigned or
11296.    306// used. If the file imports or exports, then its global object is also delved.
11297.    306
11298.    306// PR-502 - Tighten warning of unused variables to be always on.
11299.    306
11300.    306    block_list.forEach(delve);
11301.      3    if (option_dict.white) {
11302.      3        return;
11303.    303    }
11304.    303
11305.    303// whitage();
11306.    303// Go through the token list, looking at usage of whitespace.
11307.    303
11308. 229826    token_list.forEach(function (the_token) {
11309. 229826        right = the_token;
11310. 214198        if (right.id === "(comment)" || right.id === "(end)") {
11311.  15938            nr_comments_skipped += 1;
11312.  15938            return;
11313. 213888        }
11314. 213888
11315. 213888// If left is an opener and right is not the closer, then push the previous
11316. 213888// state. If the token following the opener is on the next line, then this is
11317. 213888// an open form. If the tokens are on the same line, then it is a closed form.
11318. 213888// Open form is more readable, with each item (statement, argument, parameter,
11319. 213888// etc) starting on its own line. Closed form is more compact. Statement blocks
11320. 213888// are always in open form.
11321. 213888
11322. 213888        whitage_default();
11323. 213888
11324. 213888// Commit 3903449a - Cleanup indent for multiline-method-chaining.
11325. 213888
11326. 213888        if (left.line !== right.line) {
11327.  44373
11328.  44373// PR-511 - Binary operators at end-of-line - A tagged-megastring is a binary
11329.  44373// '`' whose right side is the megastring. Moving its backtick up would put the
11330.  44373// line break INSIDE the megastring and change its value, so it is excluded.
11331.  44373
11332.  44373            if (
11333.  44373                option_dict.beta &&
11334.  44373                right.arity === "binary" &&
11335.  44373                right.id !== "." &&
11336.  44373                right.id !== "?." &&
11337.  44373                right.id !== "`"
11338.  44373            ) {
11339.  44373
11340.  44373// test_cause:
11341.  44373// ["
11342.  44373// let aa = [
11343.  44373//     0
11344.  44373//     + 0
11345.  44373// ];
11346.  44373// ", "jslint_phase5_whitage", "expected_a_at_end", "+", 5]
11347.  44373
11348.  44373                warn(
11349.  44373                    "expected_a_at_end",
11350.  44373                    right,
11351.  44373                    artifact(right),
11352.  44373                    undefined,
11353.  44373                    left.line,
11354.  44373                    left.thru
11355.  44373                );
11356.  44373            }
11357.  44373            dot_depth = 0;
11358.  44373            switch (right.id) {
11359.  44373            case ".":
11360.  44373            case "?.":
11361.  44373                dot_depth = dot_depth || 1;
11362.  44373                break;
11363.  44373            }
11364. 213888        }
11365. 213888        nr_comments_skipped = 0;
11366. 213888        delete left.alive;
11367. 213888        delete left.assigned;
11368. 213888        delete left.open;
11369. 213888        delete left.used;
11370. 213888        left = right;
11371. 213888    });
11372.    303    jslint_assert(
11373.    303        indent_stack.length === 0,
11374.    303        `indent_stack.length=${indent_stack.length}.`
11375.    303    );
11376.    303}
11377.     23
11378.     23// PR-509 - Add function jslint_phase6_autofix.
11379.     23
11380.     67function jslint_phase6_autofix(state) {
11381.     67
11382.     67// PHASE 6. Autofix whitespace-warnings in <source>, and return the result.
11383.     67
11384.     62    const line_crlf = jslint_rgx_crlf.exec(state.source)?.[0] || "\n";
11385.    445    const line_list = state.line_list.map(function ({
11386.    445        line_source
11387.    445    }) {
11388.    445        return line_source;
11389.    445    });
11390.     67    const warning_list = state.warning_list;
11391.     25    if (warning_list.length === 0) {
11392.     25        return;
11393.     42    }
11394.     70    for (const {code} of warning_list) {
11395.     70        if (!jslint_autofix_warning_list.includes(code)) {
11396.     70            return;
11397.     70        }
11398.     70    }
11399.     35
11400.     35// Apply each fix RIGHT-TO-LEFT within a line, so an earlier fix cannot
11401.     35// invalidate a later fix's column, and BOTTOM-UP across lines, so every line
11402.     35// a splice shifts has already been visited.
11403.     35
11404.     36    warning_list.slice().sort(function (aa, bb) {
11405.     35        return bb.line - aa.line || bb.column - aa.column;
11406.     63    }).forEach(function ({
11407.     63        a,
11408.     63        b,
11409.     63        c,
11410.     63        code,
11411.     63        column,
11412.     63        d,
11413.     63        line
11414.     63    }) {
11415.     63        const ii = column - 1;
11416.     63        const line_source = line_list[line];
11417.     63        let indentage_at;
11418.     63        let jj = ii;
11419.     63        switch (code) {
11420.     35        case "expected_a_at_b_c":
11421.     35
11422.     35// expected_a_at_b_c is indentation. <at_margin>, <one_space> and the two label
11423.     35// callers of <expected_at> warn a token that belongs at a margin, and a label
11424.     35// can be mid-line, such as 'cc:' after 'bb();'. Unless a warning such as
11425.     35// weird_loop blocks autofix, that reaches here, so keep the mid-line branch.
11426.     35
11427.     35            indentage_at = line_source.length - line_source.trimStart().length;
11428.     35
11429.     35// A MID-LINE token cannot be re-indented, but it does not need to be skipped,
11430.     35// since all four callers warn a token that belongs AT a margin and therefore
11431.     35// on its OWN line. So split first and indent the remainder, which also lands a
11432.     35// trailing closer correctly, and is what line-breaks a single-line ternary.
11433.     35
11434.     35            if (ii !== indentage_at) {
11435.     35                line_list.splice(
11436.     35                    line,
11437.     35                    1,
11438.     35                    line_source.slice(0, ii).replace((/ +$/), ""),
11439.     35                    " ".repeat(b) + line_source.slice(ii)
11440.     35                );
11441.     35                return;
11442.     35            }
11443.     35            line_list[line] = " ".repeat(b) + line_source.trimStart();
11444.     35            return;
11445.     35        case "expected_a_at_end":
11446.     35
11447.     35// PR-511 - Move the line-leading operator to just after its left operand, which
11448.     35// ends at line <c>, column <d>, and before any trailing comment there.
11449.     35
11450.     35            line_list[c] = (
11451.     35                line_list[c].slice(0, d) + " " + a +
11452.     35                line_list[c].slice(d).replace((/ +$/), "")
11453.     35            );
11454.     35            line_list[line] = (
11455.     35                line_source.slice(0, ii) +
11456.     35                line_source.slice(ii + a.length).replace((/^ /), "")
11457.     35            );
11458.     35
11459.     35// An operator left ALONE on its line would leave a blank line behind.
11460.     35
11461.     35            if (line_list[line].trim() === "") {
11462.     35                line_list.splice(line, 1);
11463.     35            }
11464.     35            return;
11465.     35        case "expected_line_break_a_b":
11466.     35
11467.     35// Split the line at the token. The new line lands unindented and the
11468.     35// expected_a_at_b_c pass re-indents it on the NEXT recursion - that division
11469.     35// of labour is why autofix iterates rather than trying to be complete in one
11470.     35// pass.
11471.     35
11472.     35            line_list.splice(
11473.     35                line,
11474.     35                1,
11475.     35                line_source.slice(0, ii).replace((/ +$/), ""),
11476.     35                line_source.slice(ii)
11477.     35            );
11478.     35            return;
11479.     35        }
11480.     35
11481.     35// Walk back over the whitespace-run immediately before the token.
11482.     35
11483.     35        while (
11484.     38            jj > 0 &&
11485.     38            (line_source[jj - 1] === " " || line_source[jj - 1] === "\t")
11486.     35        ) {
11487.     35            jj -= 1;
11488.     35        }
11489.     35
11490.     35// A run reaching column 0 is INDENTATION or a line-join, not a gap between
11491.     35// two tokens on one line. Leave it to a future jslint_autofix_warning_list
11492.     35// entry.
11493.     35
11494.     35        if (jj === 0) {
11495.     35            return;
11496.     35        }
11497.     35        line_list[line] = (
11498.     35            line_source.slice(0, jj) +
11499.     35            (
11500.     35                code === "expected_space_a_b"
11501.     35                ? " "
11502.     35                : ""
11503.     63            ) +
11504.     63            line_source.slice(ii)
11505.     63        );
11506.     63    });
11507.     35
11508.     35// PR-511 - jslint-autofix - Append <line_crlf> to end of code, if missing.
11509.     35
11510.     35    if (line_list[line_list.length - 1] !== "") {
11511.      2        line_list.push("");
11512.     35    }
11513.     35    return line_list.slice(jslint_fudge).join(line_crlf);
11514.     35}
11515.     23
11516.     13function jslint_report({
11517.     13    autofix,
11518.     13    exports,
11519.     13    froms,
11520.     13    functions,
11521.     13    global,
11522.     13    json,
11523.     13    module,
11524.     13    property,
11525.     13    stop,
11526.     13    warnings
11527.     13}) {
11528.     13
11529.     13// This function will create human-readable, html-report
11530.     13// for warnings, properties, and functions from jslint-result-object.
11531.     13//
11532.     13// Example usage:
11533.     13//  let result = jslint("console.log('hello world')");
11534.     13//  let html = jslint_report(result);
11535.     13
11536.      4    const autofix_blocked = autofix && warnings.some(function ({
11537.      4        code
11538.      4    }) {
11539.      4        return !jslint_autofix_warning_list.includes(code);
11540.      4    });
11541.     13    let html = "";
11542.     13    let length_80 = 1111;
11543.     13
11544.    368    function address(line = 1, column = 1) {
11545.    368
11546.    368// This function will create HTML address element from <line> and <column>
11547.    368
11548.    368        return `<address>${Number(line)}: ${Number(column)}</address>`;
11549.    368
11550.    368    }
11551.     13
11552.   2516    function detail(title, list) {
11553.   2516        return (
11554.   2516            (Array.isArray(list) && list.length > 0)
11555.    859            ? (
11556.    859
11557.    859// Google Lighthouse Accessibility - <dl>'s do not contain only properly-ordered
11558.    859// <dt> and <dd> groups, <script>, <template> or <div> elements.
11559.    859
11560.    859                "<dl>" +
11561.    859                "<dt>" + htmlEscape(title) + "</dt>" +
11562.    859                "<dd>" + list.map(htmlEscape).join(", ") + "</dd>" +
11563.    859                "</dl>"
11564.    859            )
11565.   1657            : ""
11566.   2516        );
11567.   2516    }
11568.     13
11569.     13    html += String(`
11570.     13<style class="JSLINT_REPORT_STYLE">
11571.     13/* jslint utility2:true */
11572.     13/*csslint box-model: false, ids:false */
11573.     13/*csslint ignore:start*/
11574.     13@font-face {
11575.     13    font-display: swap;
11576.     13    font-family: "Daley";
11577.     13    src: url(
11578.     13"data:font/woff2;base64,d09GMgABAAAAABy4AA4AAAAAThwAABxiAAEAAAAAAAAAAAAA\
11579.     13AAAAAAAAAAAAAAAABmAAgiQINAmcDBEICuc41DEBNgIkA4R2C4I+AAQgBYkuByAMgScfYUIF\
11580.     137NgjsHGAbcDVFkXZ5Jwd+P96IGPc9rl9ETBEaCzCJkvY2UpziRZ7zftZWk8052U9+NqX6vXL\
11581.     13KDflSQnlJ0bP+QnPQAy744n9mup6H9PaCDFwM5zjf8exB89bZ1cdrYOP0NgnuRDRWlk9u/fE\
11582.     13llkxqmfH8lmRQ/DAmER9opk9wR6suc1LvTiXNEe1vbhUCH2USgnEwH3vUm05JQqejGvZvOtz\
11583.     137sIKEGgLdDNl/IrfqWVZG/wr42ekomEm91VA1p4LhHBuFzHF8//u7vvbREHMQqGtNLmiOOD/\
11584.     13X7WWiwqyCE98qt0jk5JJmgR5WJJElBmzRb1F7a66MmSLTNWZ2XSHfKBSKHoVteSEJ6EOdvVw\
11585.     13fNZOtXKDe39jXdRlkmMnOWIOFBgeEK/b0mFsgffnPyyAitNyutKky7J8a8MSEkAKGLgfptnS\
11586.     13/gDRSo7vwdNUmQDB7oP6pK7QF5d9SrY8M/tkrXcurSIQAmX7tz7pd33LIB7GQkBQ/k81s/0D\
11587.     13gpt4gbw7x0Cn/PocitK5KIGPGQIzQzAMuCeC2ERAidx9TySVqX06goT0SFFOOV9Kuxdi5Rg7\
11588.     13l6n3c+nKRemidOm2dtFV1jXMk4rP2m6RJ8xEdPYONLTbeMgaJ1nwS2W4su3MHwqkkvJ2PdDU\
11589.     13r7pgAnVRt4Kh789FXlD0r3p6jUtNO19O1s74U9pnIxqFpw+mBgF+8y30PAyw1dzlknLLVcSB\
11590.     13J2OuCr9eV5Efew6cOGd47ZEfhrW7HXI+FBNFvWgWnugUU4UvlrV63niv2ZPeKu8M76y/HQaG\
11591.     13weU+4Gzp+Y+cfb9R9djDWcd1Svr1xG7l+j/yf3eM996548qlC+dOzOqQ8//Lo0uaSEQCFuLD\
11592.     13/bXyWhJ6aPmyaRonVPxGABFL4/0slcKI6f+PmT0M+QRsplmWnv4F49VT+JsPifoa6aeyr2Hz\
11593.     13EeLdP1FEOV/ZN+c9sAuoNh0BRS0xgCCc9wME5s0HOKj/wc0fWYsTbFQpsZL5SayJPkL45kDo\
11594.     13DcJJ10MvD0ZSq7FEIr1TfqZ7NC6s75zSp8viaNO5/PczYCV9z6NTa0KBdnGBg6kbdeBkRLfU\
11595.     13qRd3D9Pqw5jWCc5WM/i95OE8731MBd1u2EmsXIa5dCvavY32U1Ytza4nfbERg6OVRZka7jq0\
11596.     13r2FcXNDyEhXheaHtaU1o1kvO9MuBOHqugLUEzN+4jznu0oK9wZPur1lWVFfxl8lZzn2XwcjZ\
11597.     13Csg/RJy0mAMMmgnqXS8ELhOCRUSLzvsM5gAPudEh2lVoRxGgyUVnArZMruE0YS1PqFMD3upb\
11598.     13jVoecGj1KpWl6/ZysuyzkG4SGA4bps6FBQSg4e4IxNUgdmosmoDn0TpIex/s1BFau6GBNO4z\
11599.     13cvWXypm4hEg5k3llelySFqNmUtRZ3PHBA7p4MBX1nK4awwAV6kWzIVbUA67A55QKYbMsgVaH\
11600.     13c1ZxKuZ0DCyqxCsJjLyCEY36gf0wjAu3t0zemc87PmBCJbU9Lso0YAaYJUx8wsR02hYz5hGy\
11601.     13Js0+A4uHGZgfuf5SOR9iBQuLhpOExaIFrHj6JlXanebzGHp2ELDh6av09PVE1fmdsj2oHRWs\
11602.     13fOtYrV6wRCyx7XogHqvpnZiPBBdNcL6kIoS9UI/DOIlumlveSgv9oqMBYp7WZ2fGxAXmZmaG\
11603.     13OCyJG6+wAszZFCQw/EXVjx+YA2uVyN6bhNWiZhgtYjAwR5U/7uV1scghiTGiAPZbA5ZqHw5u\
11604.     13Yu1cDjhRwREBFyq2wa0R8GgceDUKPo2BX+MhoAkQ1EQIaZqVHMwH3xM+P32TTA34tmOMNZ4n\
11605.     13mHXqn49fmE3qX1+wMNYoYetOsPx6wxKzkURImERJIjGSSJwkkiCJJEkiKZJImiSSIYlkSYqK\
11606.     13UBu0UOopuLMmasiJW0PMFOO2UgbDif2NaQUqkBbyaGjdTUvuyamEQwCq9DWsxsG9qPt+VFqV\
11607.     136cIsXcyWujWIEtNFdeia9ssNrJUpe3IDMPQZOReC8x+qvt17drPWdcHeL0gTarWwoQ6o828o\
11608.     130EJzrA20yZsgVyVHdlCJOF3NaACxHbP38TA+MGx3St9c5t2CxbGtunB4J9AF4Px2rSr1wyK9\
11609.     139KoXBR13vw9Fk9qhTX0ivZoanrvhLa5oiJO8cqR0lX7QtJ2c1a62V3PMtutaaoit+hxtXuC5\
11610.     13ZUXJePSR6btQlt5g7PqPQ822g7F8D123pc4kaGXz7qYztJxDXCxJr7foKqxwy4rikI/NvINx\
11611.     13bkArRTTnnMWy6YA8J39LfTweThKsqlt7Mz078NDSOPOGgtGTpeG8ZRBF+xKBjdSoNe8gE6uC\
11612.     13ucOH98jE4+cv1JEjI555TFjYj4+0KdFlojzJGWp2wc1tCaYGSeO8dBfT0u3lpDY3tazzu4wn\
11613.     13lF9wzy2nK+sTr/qEVdANoZ0ToBdD+MY4ewOHNnkXPBvKVXLSbEGfGVD0Nzr0Fs3HID3Y1Kqx\
11614.     13mzJ6p1C1/R6Xneyw/q9YRDLahbnsI1u76XzMLPqsK0yvQDeQ4TMR41709sIssmEgs0XH1lcj\
11615.     137HLnUG6u2Xpy5vbOowIGqrR6cwF0TLGI5PF7pkbzIVYQU0sIaoNgul3LGAH2B1nREFYXUMia\
11616.     13prCeAzggGxrC5gIK2dK0exs/AIRKdlIIuxkUspdSsU+rqXagqXaooXakqTiWS/a0E7zA6QIK\
11617.     13OdMUznMAh+RCQ7hcQCFXmspr3ciuds/6gPsZFPIgpfJhwUIepRAeZ1DIk5Tue4oKfSfKZyNV\
11618.     13pKU/J7J4Abx1EMV5mXSRDl6lMfU6jfBmBww4k7f6gLzTB+J9od/kA/uGj2mET2nkn7+zQ/JF\
11619.     13H5Kv+pB804fkOyvwI43wM438V5sdkd/6iPzRR+SvPiL/WIH/aYRxGqMb/Oqe3d54+LWR1vr2\
11620.     13knnnc467iD247eXBA3YYBAiFfierClXz/8jyL3Qh/zP8y+Y/1eN8jq+SKZAML/lIidjwZ8N4\
11621.     13aLthvhxGUkGPo+p0eHKZ0sT5FsqJcQCy9UhHIvcJFIlIvANTPFWUTUhSiVdsNRnvwEQxm5uc\
11622.     13ksjdv5evJfpOgI6c7juH8pnG2RKwlXaDYe9g8rMwYfML3A2SMWeBDopJJsmS5dUE2KttnmQa\
11623.     13JZlMspvEpJioiEDFNpPUTbwqG3Zjhx2VCeJrIf60s2mI6blZMZVyAyYzI+1a2Y0AIqcbLUgR\
11624.     136iRbNtnp82GrImXW0YbcbczDgqQDWNdTenvtTAlT9iPHenluV+d3eed1/5MjMBrX2LgrK2ml\
11625.     13FuoDOz036n/kaHbAeszR3jHoI4NWB3lusTfuVgkMUkLQaH0F6+pSCS11fXRwT421vs9s7axd\
11626.     13nvtF7/eeIeq9s1aCLsLWdh+w7sXz3IYdEsSQ0LVsebmES/vXDU9k653W4MiNq8bMj5nLioCY\
11627.     13edGgOT6tmYwqiOW1ugiEmew6iwjvvYb3SaeZJb7XNufOo9oH8FTneWGL+BLiclptpnhPwcui\
11628.     13T+rzcF34+ycsL7p3AveuML9i9h13beylyg8CzEz5HppadqmmDxKrAquG9L3ztedRoWxEsAYt\
11629.     13OM1Eu0G0gyTHkxf7cSkHJQRbA4xmlqHWkv1C0KhFhBq1z81Wq1CZoWic8TJ570WfSj5qsM+Q\
11630.     13nl4k3H5+P+P3zlv9ltQrzv41qyiSwV/gOadyQBchsmwDGu/JI8tXflE8jqUVA0Zw0SKbdDC9\
11631.     13c4FR+fak95SdF7uqpoRe9z6YRv+85YUzF4qJy6Q8GOVNwUn/ymyjNNbmcuVfXYeH2osLdCte\
11632.     13ebmZRyUfQQZA1BSCLK4PWA/z1kBvDZm0t+i3or1LkMD6en95pGG0UOa8ZJXgS9TdEA1I2mZw\
11633.     131JOWWxDu0NEh4rM19H55rvueMBUZV1RjkmB3oxkXhAckpa5gzzxUDA2VLOrWFAXx+4gmfU17\
11634.     135o3v9H7EYdvGFuM+tDB3TA4ITjVUKduO/R4bXRAcPXZusWkN+t59sFz7Hyi0FkSdzrHXQVFq\
11635.     13b8c9k9eLRjVlBbNvt4172CanYg/F3Rket1zCTc77UZ61Gq/Be9J8hrKrxbDZMEotf5o8zHDc\
11636.     13/UJaEtdhgwHEcBEQKM+6NBWIewLmI1sHuWYAedZCw8U1hJfSWcld+2tv3jpCFc5FnosLWC0+\
11637.     13DnAlnOXUXLoMXrmCVerNQkZHvRm8YtE12vG8+N/vOnPcu3vM1uOnzE3u3VP2ppmLZawm2NuO\
11638.     13tPa7xwHFCgVKpox5PVrOmaDHrThk1tX864a2+/qhJd3nCFRQ+bfUKI4O+Wgk5byB3saMcUfV\
11639.     13C8G137yMd16zRm3ZSq+UrDlk5ha3TiAj0b74prWO/vYG+RC+ronP1/McDtefBtY1XhZE0PIB\
11640.     13wTe7CBTte2U6KPbYd5GffApQlDGssdfmxYGSlnHrQt7++KEwUg3ikkoQyKPixgUDB6Lozjv5\
11641.     13vM5PBnllt+UzMnP6DStFsOfossbXOefWhQApACCNpkTYGAONIowDfndqDKRFuzn685nthZPe\
11642.     13vEL7TIWkXAG2yxKBH90+yMzuRzWn3KMmyKGwZWnIErlJ9Vwt8OtR6+4TKad5y9+ViBtTzVG+\
11643.     13tpv/xiLrcGKJRtYvCUlGeL4Dwy1jo1CSQe0X71EXK1YG44ztxTONjIslL8SwY0Cki0k0vsX/\
11644.     13/xz7CxkAc9dEdJZhMy/JCGzD2FAGtUcag0tc2e2miJkp477V2qTKB+nFnDl/noxpXJ+yqVdO\
11645.     13wNjbplmeiuburg9ii1Z1zwtG8QjcJAiVPSOV2mHzq1Qt7p2+YCcIKPmFusE5O+m8s+Wd8o3t\
11646.     13qO1b1IZF8N0tx6RQnZ9Ux3gXijHlolixst6vhJV6ao0ZFzSprfAc3x0MLvxU0OsmXEVddMVK\
11647.     1329CC6mPgPtXTUW7tVnZxwm0DTJwNOeVRV4axMSPlpgyv1Va1MQhQqWwUOb0s+gVLOecos4Nf\
11648.     13eqlFW3fLQrlP86R4XRxrDHF0VIx6ArM5/sTWtObY6U2aosgxbN6FUa1iNTUpMThk1sUfJOC6\
11649.     13s1SKo9D0g1NfiVmavyful/K7nZdDgutV1A26i7FR3r16bv3zz1cGw+ta17IX/+ripyutix3C\
11650.     13xNmCxs7uiqKu9/Zjjn06tblXpJxlaLF5Od0d5W9QhQrs2u6UN0trQlCyEK2j9VYgCEIDrhQN\
11651.     13c00rxg/FOfZ1N+nLV7RXDsYP+p0EzqKcuPujzuzEQsu2mFf4nYvf3Yp32rq/RYLetDLuOOTc\
11652.     130WXBtgoech7AHUxAxPBg81qWCsYlzTofRU5/MpuyNoegR6mCJO5ckrLOhWbG7xo/VGwGgpRb\
11653.     13+Ch+TmlcuY6Qct/2x3gxzeDUU9u+ltexrjelJ0VRR9KXH/AqrbYxHa0vmQ/kBnE5EORBK1ZH\
11654.     13mTSy7A8DJMgzzqDsu9ML5J3ufkuUNDCfN5UKAjBgw2I/QlS8MQ6o/ll9dTAdoM7HYtV4cNWE\
11655.     13U4pOl5Y4SIzdMbNSjXFmsBV1uXXf7GaBZZslpFGFiIpokSzxWj4hjlGl4VKJDACo7ScxQf29\
11656.     13kM8gHD3nUJkwkN2aW2TGttqwOrygJ7r9nYX2tYqy7Z3TQV5ocWzUI8l871y3LsQLoTgEO76B\
11657.     13Upp69hy6VKRpZvpvgfQ2T06qgXjxh38eatREitX6bzKggIYmN4sAkA3a5oeJZDK3ahQrVJwa\
11658.     13AD65cEGBkS/tKH9TtybiREEWCMcKD0HH0gELtjB+KNSk7bspmpr6eb0CscIiFyZpmXu8+gxw\
11659.     13O7pJNbAK2h9q2c5dMHBaoi5DylbNGdweVVdN3Jm9u6YXXlmx4nYY2vIPfSkrE/vyv9gn/Z+j\
11660.     13R3HKExaUhdV0Az77YWbQPhNfjw+F0vTteSMin+wIfxyPe0DEoI4uz6o2IXwsZC7sg8MicQ3o\
11661.     13wys+NJYKVW72YiVQ5LKDVwrEg2jNVM6XdNjbsHlRDcAkD08o5iWtFB2dVoydRmmDRLalE+4t\
11662.     133gBbAPa7n7qXXXbTZTJXZKy5+1W0K7dgYEcIlu90ovC0C+5gxXiKtZisT14qDJ7f2ksyK59U\
11663.     13r3QeHtBb24mPz7YDB3rgMTyUZ/fxM8h2i1Z21B8/VA5+9l7BKaOJZ15lWsyPv/z6CjU32ZKq\
11664.     13+QFeyUywxYnUxUmcQfGc1Sp69oE2n6zFL8BXf5rc3cJMM6S97gagTT1bi7cmAV4MibkC4rz/\
11665.     13icmmFtMlo5aN1Wp3uxsBfd4+9T42xmxvd79FV/hfuviBcrIaX092PrY5rle9FR4wTnDzrwj4\
11666.     137frD2d0KsMcdcADQ1Yu1LECg9Wj3yOS8OhrJdQBqXqsam17vmt2wjjjouHE/EO9sGPdqt23v\
11667.     13j8rL6wid6ulagtNK5p1hjRkFtUxTIaZnIXk63Zb3P0t5MQ+3vxHIFrmgAdWwiDuA67tbVIF6\
11668.     13wJ53z0uhyhsfH9bgF0kPT9v2hrT3HKIBgUXIYoxsVU+uryemiUiQEwh+BfxP//qLShlumR26\
11669.     13I8OqjD+x3hHDj/IrEWmvyL6ioG/atfxe+5GzIqRgfaoayWOiTk+YixO15KDO6Os3XACDjboe\
11670.     13ryXXOuEmTpDsc7czk+H04Kw1PNJazW32CAURHwBldqK0/nqYHtcrtLyyTYmoD8hbcnJUfa3U\
11671.     133FxWNus7uic3Qm1BzEecJW0MAz+W2CyN9FLIy+EpSy6CjkXsllZw1uBs1SxrQWM97/vnHu7m\
11672.     13OtrkRl8AtBN3RDxI/fg7dZLLtDFYuCYYPMwXiO6ZIpwJ1GGydI9oUYYgnQQKDKoMTcwsjrfe\
11673.     13Tcht6y18bLcpNfX41WE27447vLNzHuF+j15co5N7Py8vKUpTCoghHMEYKkM6y02lvX+9XiFg\
11674.     13xBKMRNiwX69+LJb2Xa5WGqo7Rlk0cxsLVd0l2UXAW5jORg31sFMKYWXsDcRUKRDP8Q87OjiM\
11675.     13dI1hNEt43netf8rOyfp+L58fq3holY9gxXwRJLY6gahgLQi4hS8w9LS+rFcJtdSCBrQLWsMs\
11676.     13aDg/n8/P8/N+fcyoLepYr3W/CIUT7HsRQTtkduddbVfbo6Twt6fyJVPRrUGqRkWp3rdry65v\
11677.     13sPYInyq1mPHrQDrqGJYI/LzA/QAzAXLnx+lu9uxHTEka9xgWgRvqEioskh+UWgD4nDvTAxaz\
11678.     133v9BqqmFuQwy1wSXye1Df1NXVF7G8bUFxUE4F9axG5fm+vFQJvP8iuYjrFveB6++AqmJTQJ0\
11679.     139GHjbPhzdSzkZGxokQzONVs0R0FCPJz1hJKbvDKsaj9hT0vp/gH5oiT8pAbWsBChwAbxHgDd\
11680.     1359iJVZE3bAzPRN1RuG+MT7th+J3i6KFwVJvPvsGRDIZW4P2rVfiKjDVBM2Va+w6PgI0c5u3K\
11681.     13O7MrWryPhXFFdBoAwi2JCaW9sZ3fTagQ4Tld6u4djwcWzeCdiYoeNbfalsRYo740afYQ1Rid\
11682.     13Bp/E9mbcTemEjoWWXIU7I5nK5H/BEqmZnPMyhDV234BTLQKCe6nhU+frwQo1gNFWf+eQGN62\
11683.     13aeF7BuzaN/94W2xlKd8t8KMA/3uoxymFt19OlCjYZeaMWbTKM9Yog9zDhptYMOzIQAoO7kn6\
11684.     13nTao8CxjrRRgjKe7mKa+tzuufhAAZtgjA92THkulWvIzEi0++j1DvXMnupDUS8aVusWain+c\
11685.     13CcvmR5orC+RcJs3wVahLYyEcqbvAS2e0QJ6BlU36R/IEd9Aol9q+M+UGvlo8EyRzISvqusNS\
11686.     137ePQ6cQzG1s725db4jNYNHAfF3KFG8wHqDwZDpWDsJ5qRLXR1ulFx85GhkypPubYaCiOQ5DR\
11687.     13PQUiNpgk4fLJHenSMLMiswXsqW4Cpln1rFoHzpOoBbuZIixmVyhKajeqlFmp8zNAEsbEJz0g\
11688.     13X0qlQuykZhf82pkhq2hWtCtYUdBODn6iPTBJT5Zk8IqFxqfBeFKjXk/sMeumhT8muOtq2Bgn\
11689.     13dR4fj6RoOi0zI25kajAXlDZhUhS39jipk39h/69AfDPBLmOxhDj7Lg/WUTbOwJiJ3p7WtOpm\
11690.     13ypARmhorQifINNm1CNS99GfDcLbD8sn8Fvlmvn7CmW65Pdmu6bKtuE0tn7NglIX1e/JAJP+G\
11691.     13gB3At7cSOp92rl0lp0pp0xVb5YaQedwGgcJA1pT4cy24lS+jvzDw86YTfb2igJm5MysHmejW\
11692.     13ZTGXpoAoLBLucUGEz/DwbjqOdzGAl5jy5VoCQws5zNYl4SVt030aZulYMgpDBPZd+kL0wV+w\
11693.     13nob2LPRDQGEbdUoeFm4fEKio9c/ferVlpSO8Bx7OFZyHip1PIizvoqFe02kpmS17TvIOty42\
11694.     13+Q0QaCnOpeLsPwwo+vixIeIeUjucUsKejVlez35qyuC0mm5pJJJLEVP2JAe/LTOwUUfKJkNy\
11695.     13lEe3Kdth241ZNQmkVcAIh6DZJBzvQov5fn3JZA0phBWdNq5iTsm5N2D8gyve3V3X2o3zF3VY\
11696.     13OqEBgTIADAbC69z7vOKJjGOzHRmUUwLU66iabtIbqR6SPOHCL+fCTfvpKcB/oG2p3wRKErEJ\
11697.     13v1YOfu9iaKEMLXS3ptdH8fwN2Rdww9bZ7rFa2bwrzcyux3o+hPV6bJZpb71j7lLAdzge3VX7\
11698.     139uSCdz6f/FDb7+wzWnbbDSPj9R20+PybDUm/lVAsTuF0aycFQwJfPCUwcBvCGWEq6xoTIEOy\
11699.     13b0bLta20+LYRYdyEceX7ypfezQKIy5OvJTAHCJy/WyOYaDVyPucMsHnZ0GCH75Cd//te1Bv2\
11700.     13RkMykqYurBiNbuH3Xfuprirr4Dd453O6abAYGb5tw1d6wrBL8p1J1Sx9Lgw7yxqYn0FTrc0y\
11701.     1359yLlV+4zIkLfZlPFRVnanHpTyrIlpn4lGkt269+JXnIWhEQWNvuVsrt531jr+8AHkVZfQU8\
11702.     138U/4AUZMuOj5iliigFrof/usmloYEI1f8erhJku75snYW7YmFmUcoC7UtG/KfJRuz6j0tWPa\
11703.     1356J5QA0rJHwSIhNT4GWvez19HT2lia+Pz7/+MVEWlvjY6+9P85a0y9qWkTzQ7nF0wDXpQpw3\
11704.     13K4xnfK2L08b5MrxdeI+DDfVDeV2JY0Fp6KH602tj2MbxxKM8oG+wTkE/dr8jyo4Sfs/IV6uf\
11705.     13+IIXpH2Nca1+WCJV5qEv193bcUELLR4iFu83xUedKy9353tn+3o01dF2bNEQ3fK9Q5tCXrCi\
11706.     13La+woCuvEeYrr+PiN2+i2V/eDJck580pyra8BV5ZIZbpe3kr5vJD3pqoGsnbcl/d+ndvR23b\
11707.     13K41M4dKwaAwDaMA1gZGBoQWAcYE9mYkmQOnAjkaG41FkGkIP2BAIgKvUvzhpE5JbA6lze2iL\
11708.     135Nr+AwiDo2W4BStvK30dKy0JGNbzAY5akexsrV0xo5K8rY50LOTLvDyukIZNbRLKOCk18mD3\
11709.     13WxmZGlsCMxNdGFYGNJnetUWyCPgo4BONEL4I9b8UeEBGYXuCdCd+DkctrqVLYXGSfE46kvAu\
11710.     13+ltK5SRxQPnjUqyJXsSYs6VY6WPKfns9+IXjHhd5wQvGipgFdMwVEQ+A7a2AAS0clQwH7KHW\
11711.     13SEGjhnklSVRghMtPy6gEtJRIKJeYkpQyQiequQunFOOU4BLdK1yp55olZS6npyPhMnvK7xIa\
11712.     13pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
11713.     131R8uVi8Zu9nRFqk/t0gR6wmWOlzuKRqk33HpO8qQ+nbGoEZLL/0Va156SJ+u+t86/os7ic49\
11714.     13/7xoEqvL+2E8VOyCTuT/7j269Zy4jUtN+g4="
11715.     13    ) format("woff2");
11716.     13}
11717.     13.JSLINT_,
11718.     13.JSLINT_ address,
11719.     13.JSLINT_ button,
11720.     13.JSLINT_ cite,
11721.     13.JSLINT_ dd,
11722.     13.JSLINT_ dfn,
11723.     13.JSLINT_ dl,
11724.     13.JSLINT_ dt,
11725.     13.JSLINT_ fieldset,
11726.     13.JSLINT_ fieldset > div,
11727.     13.JSLINT_ input,
11728.     13.JSLINT_ label,
11729.     13.JSLINT_ legend,
11730.     13.JSLINT_ ol,
11731.     13.JSLINT_ samp,
11732.     13.JSLINT_ style,
11733.     13.JSLINT_ textarea,
11734.     13.JSLINT_ ul {
11735.     13    border: 0;
11736.     13    box-sizing: border-box;
11737.     13    margin: 0;
11738.     13    padding: 0;
11739.     13}
11740.     13/* disable text inflation algorithm used on some smartphones and tablets */
11741.     13.JSLINT_ {
11742.     13    -ms-text-size-adjust: none;
11743.     13    -webkit-text-size-adjust: none;
11744.     13    text-size-adjust: none;
11745.     13}
11746.     13.JSLINT_REPORT_ div {
11747.     13    box-sizing: border-box;
11748.     13}
11749.     13/*csslint ignore:end*/
11750.     13
11751.     13/* css - jslint_report - font */
11752.     13.JSLINT_,
11753.     13.JSLINT_ fieldset legend,
11754.     13.JSLINT_ .center {
11755.     13    font-family: daley, sans-serif;
11756.     13    font-size: 14px;
11757.     13}
11758.     13.JSLINT_ fieldset textarea,
11759.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS dt,
11760.     13.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
11761.     13    font-size: 12px;
11762.     13}
11763.     13.JSLINT_ fieldset textarea,
11764.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS > div {
11765.     13    font-family: monospace;
11766.     13}
11767.     13.JSLINT_ fieldset > div {
11768.     13    font-family: sans-serif;
11769.     13}
11770.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dfn {
11771.     13    font-style: normal;
11772.     13    font-weight: bold;
11773.     13}
11774.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dt {
11775.     13    font-style: italic;
11776.     13}
11777.     13.JSLINT_ #JSLINT_REPORT_TITLE {
11778.     13    font-size: 32px;
11779.     13}
11780.     13
11781.     13/* css - jslint_report - general */
11782.     13.JSLINT_ {
11783.     13    background: antiquewhite;
11784.     13}
11785.     13.JSLINT_ fieldset {
11786.     13    background: gainsboro;
11787.     13    clear: both;
11788.     13    margin: 16px 40px;
11789.     13    width: auto;
11790.     13}
11791.     13.JSLINT_ fieldset address {
11792.     13    float: right;
11793.     13}
11794.     13.JSLINT_ fieldset legend,
11795.     13.JSLINT_ .center {
11796.     13    text-align: center;
11797.     13}
11798.     13.JSLINT_ fieldset legend {
11799.     13    background: darkslategray;
11800.     13    color: white;
11801.     13    padding: 4px 0;
11802.     13    width: 100%;
11803.     13}
11804.     13.JSLINT_ fieldset textarea {
11805.     13    padding: 4px;
11806.     13    resize: none;
11807.     13    white-space: pre;
11808.     13    width: 100%;
11809.     13}
11810.     13.JSLINT_ fieldset textarea::selection {
11811.     13    background: wheat;
11812.     13}
11813.     13.JSLINT_ fieldset > div {
11814.     13    padding: 16px;
11815.     13    width: 100%;
11816.     13    word-wrap: break-word;
11817.     13}
11818.     13.JSLINT_ #JSLINT_REPORT_AUTOFIX > div {
11819.     13    background: honeydew;
11820.     13}
11821.     13.JSLINT_ #JSLINT_REPORT_AUTOFIX.blocked > div {
11822.     13    background: pink;
11823.     13}
11824.     13.JSLINT_ #JSLINT_REPORT_AUTOFIX.blocked > legend {
11825.     13    background: #b44;
11826.     13}
11827.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level {
11828.     13    background: cornsilk;
11829.     13    padding: 8px 16px;
11830.     13}
11831.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dd {
11832.     13    line-height: 20px;
11833.     13    padding-left: 120px;
11834.     13}
11835.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dfn {
11836.     13    display: block;
11837.     13    line-height: 20px;
11838.     13}
11839.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dl {
11840.     13    position: relative
11841.     13}
11842.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dt {
11843.     13    line-height: 20px;
11844.     13    position: absolute;
11845.     13    text-align: right;
11846.     13    width: 100px;
11847.     13}
11848.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level0 {
11849.     13    background: white;
11850.     13}
11851.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level1 {
11852.     13    /* yellow */
11853.     13    background: #ffffe0;
11854.     13    margin-left: 16px;
11855.     13}
11856.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level2 {
11857.     13    /* green */
11858.     13    background: #e0ffe0;
11859.     13    margin-left: 32px;
11860.     13}
11861.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level3 {
11862.     13    /* blue */
11863.     13    background: #D0D0ff;
11864.     13    margin-left: 48px;
11865.     13}
11866.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level4 {
11867.     13    /* purple */
11868.     13    background: #ffe0ff;
11869.     13    margin-left: 64px;
11870.     13}
11871.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level5 {
11872.     13    /* red */
11873.     13    background: #ffe0e0;
11874.     13    margin-left: 80px;
11875.     13}
11876.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level6 {
11877.     13    /* orange */
11878.     13    background: #ffe390;
11879.     13    margin-left: 96px;
11880.     13}
11881.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level7 {
11882.     13    /* gray */
11883.     13    background: #e0e0e0;
11884.     13    margin-left: 112px;
11885.     13}
11886.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level8 {
11887.     13    margin-left: 128px;
11888.     13}
11889.     13.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level9 {
11890.     13    margin-left: 144px;
11891.     13}
11892.     13.JSLINT_ #JSLINT_REPORT_PROPERTIES {
11893.     13    background: transparent;
11894.     13}
11895.     13.JSLINT_ #JSLINT_REPORT_PROPERTIES textarea {
11896.     13    background: honeydew;
11897.     13    height: 100px;
11898.     13}
11899.     13.JSLINT_ #JSLINT_REPORT_TITLE {
11900.     13    color: darkslategray;
11901.     13    padding-top: 16px;
11902.     13}
11903.     13.JSLINT_ #JSLINT_REPORT_WARNINGS cite {
11904.     13    display: block;
11905.     13    margin: 16px 0 4px 0;
11906.     13    overflow-x: hidden;
11907.     13    white-space: pre-line;
11908.     13}
11909.     13.JSLINT_ #JSLINT_REPORT_WARNINGS cite:nth-child(1) {
11910.     13    margin-top: 0;
11911.     13}
11912.     13.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
11913.     13    background: lavenderblush;
11914.     13    display: block;
11915.     13    padding: 4px;
11916.     13    white-space: pre-wrap;
11917.     13}
11918.     13.JSLINT_ #JSLINT_REPORT_WARNINGS > div {
11919.     13    background: pink;
11920.     13    max-height: 400px;
11921.     13    overflow-y: auto;
11922.     13}
11923.     13.JSLINT_ #JSLINT_REPORT_WARNINGS > legend {
11924.     13/* Google Lighthouse Accessibility - Background and foreground colors do not */
11925.     13/* have a sufficient contrast ratio. */
11926.     13    /* background: indianred; */
11927.     13    background: #b44;
11928.     13}
11929.     13</style>
11930.     13    `).trim() + "\n";
11931.     13
11932.     13// Produce the Title.
11933.     13
11934.     13    html += "<div class=\"center\" id=\"JSLINT_REPORT_TITLE\">\n";
11935.     13    html += "JSLint Report\n";
11936.     13    html += "</div>\n";
11937.     13
11938.     13// PR-509 - Produce the Autofix Report.
11939.     13
11940.     13    html += String(`
11941.     13<fieldset
11942.     13    class="
11943.     13    ${(
11944.     13        autofix_blocked
11945.      1        ? "blocked"
11946.     12        : ""
11947.     13    )}
11948.     13    "
11949.     13    id="JSLINT_REPORT_AUTOFIX"
11950.     13>
11951.     13<legend>Report: Autofix</legend>
11952.     13<div class="center">
11953.     13    ${(
11954.     13        autofix_blocked
11955.      1        ? "Autofix blocked. Fix non-whitespace warnings below."
11956.     12        : autofix
11957.     12        ? "Autofix successful."
11958.     12        : ""
11959.     13    )}
11960.     13</div>
11961.     13</fieldset>
11962.     13    `).trim() + "\n";
11963.     13
11964.     13// Produce the HTML Error Report.
11965.     13// <cite>
11966.     13//     <address>LINE_NUMBER</address>
11967.     13//     MESSAGE
11968.     13// </cite>
11969.     13// <samp>EVIDENCE</samp>
11970.     13
11971.     13    html += "<fieldset id=\"JSLINT_REPORT_WARNINGS\">\n";
11972.     13    html += "<legend>Report: Warnings (" + warnings.length + ")</legend>\n";
11973.     13    html += "<div>\n";
11974.      1    if (stop) {
11975.      1        html += "<div class=\"center\">JSLint was unable to finish.</div>\n";
11976.      1    }
11977.     12    warnings.forEach(function ({
11978.     12        column,
11979.     12        line,
11980.     12        line_source,
11981.     12        message,
11982.     12        stack_trace = ""
11983.     12    }, ii) {
11984.     12        html += (
11985.     12            "<cite>" +
11986.     12            address(line, column) +
11987.     12            htmlEscape((ii + 1) + ". " + message) +
11988.     12            "</cite>" +
11989.     12            "<samp>" +
11990.     12            htmlEscape(line_source.slice(0, 400) + "\n" + stack_trace) +
11991.     12            "</samp>\n"
11992.     12        );
11993.     12    });
11994.      5    if (warnings.length === 0) {
11995.      5        html += "<div class=\"center\">There are no warnings.</div>\n";
11996.      5    }
11997.     13    html += "</div>\n";
11998.     13    html += "</fieldset>\n";
11999.     13
12000.     13// Produce the /*property*/ directive.
12001.     13
12002.     13    html += "<fieldset id=\"JSLINT_REPORT_PROPERTIES\">\n";
12003.     13    html += (
12004.     13        "<legend>Report: Properties (" +
12005.     13        Object.keys(property).length +
12006.     13        ")</legend>\n"
12007.     13    );
12008.     13    html += "<label>\n";
12009.     13    html += "<textarea readonly>";
12010.     13    html += "/*property";
12011.    340    Object.keys(property).sort().forEach(function (key, ii) {
12012.    337        if (ii !== 0) {
12013.    337            html += ",";
12014.    337            length_80 += 2;
12015.    337        }
12016.     51        if (length_80 + key.length >= 80) {
12017.     51            length_80 = 4;
12018.     51            html += "\n   ";
12019.     51        }
12020.    340        html += " " + key;
12021.    340        length_80 += key.length;
12022.    340    });
12023.     13    html += "\n*/\n";
12024.     13    html += "</textarea>\n";
12025.     13    html += "</label>\n";
12026.     13    html += "</fieldset>\n";
12027.     13
12028.     13// Produce the HTML Function Report.
12029.     13// <div class=LEVEL>
12030.     13//     <address>LINE_NUMBER</address>
12031.     13//     <dfn>FUNCTION_NAME_AND_SIGNATURE</dfn>
12032.     13//     <dl>
12033.     13//         <dt>DETAIL</dt>
12034.     13//         <dd>NAMES</dd>
12035.     13//     </dl>
12036.     13// </div>
12037.     13
12038.     13// A function's name is a best guess, since most functions have none in the
12039.     13// source. A wrong name in an odd case goes in the CHANGELOG Todo list, and is
12040.     13// fixed only when a user reports it [owner 2026-10-22].
12041.     13
12042.     13    html += "<fieldset id=\"JSLINT_REPORT_FUNCTIONS\">\n";
12043.     13    html += "<legend>Report: Functions (" + functions.length + ")</legend>\n";
12044.     13    html += "<div>\n";
12045.      2    if (json) {
12046.      2
12047.      2// Bugfix - Fix website crashing when linting pure json-object.
12048.      2// return (
12049.      2
12050.      2        html += (
12051.      2            warnings.length === 0
12052.      2            ? "<div class=\"center\">JSON: good.</div>\n"
12053.      2            : "<div class=\"center\">JSON: bad.</div>\n"
12054.      2        );
12055.     11    } else if (functions.length === 0) {
12056.     11        html += "<div class=\"center\">There are no functions.</div>\n";
12057.     11    }
12058.     13    exports = Object.keys(exports).sort();
12059.     13    froms.sort();
12060.     13    global = Object.keys(global.context).sort();
12061.     13    module = (
12062.     13        module
12063.      1        ? "module"
12064.     12        : "global"
12065.     13    );
12066.      8    if (global.length + froms.length + exports.length > 0) {
12067.      8        if (functions.length === 0) {
12068.      8            html += "<br>\n";
12069.      8        }
12070.      8        html += "<div class=\"level level0\">\n";
12071.      8        html += detail(module, global);
12072.      8        html += detail("import from", froms);
12073.      8        html += detail("export", exports);
12074.      8        html += "</div>\n";
12075.      8    }
12076.    356    functions.forEach(function (the_function) {
12077.    356        const {
12078.    356            context_report = [],
12079.    356            from,
12080.    356            id,
12081.    356            level,
12082.    356            line,
12083.    356            name,
12084.    356            name_list = [],
12085.    356            signature
12086.    356        } = the_function;
12087.    356
12088.    356// PR-516 - Bugfix - <context_report> mixes own and outer names, so each row
12089.    356// checks <scope_function>.
12090.    356
12091.   2136        function id_list(filter) {
12092.   2136            return Array.from(
12093.   3785                new Set(context_report.filter(filter).map(function ({id}) {
12094.   3785                    return id;
12095.   3785                }))
12096.   2136            ).sort();
12097.   2136        }
12098.  23562        function is_own({scope_function}) {
12099.  23562            return scope_function === the_function;
12100.  23562        }
12101.    356        html += (
12102.    356            "<div class=\"level level" + htmlEscape(level) + "\">" +
12103.    356            address(line, from + 1) +
12104.    356            "<dfn>" +
12105.    356            (
12106.    356                id === "=>"
12107.      1                ? (
12108.      1                    "\u00ab" + htmlEscape(name) + "\u00bb" +
12109.      1                    htmlEscape(signature) +
12110.      1                    " =>"
12111.      1                )
12112.    355                : (
12113.    355                    typeof name === "string"
12114.    355                    ? "\u00ab" + htmlEscape(name) + "\u00bb"
12115.    355                    : htmlEscape(name.id)
12116.    355                ) + htmlEscape(signature)
12117.    356            ) +
12118.    356            "</dfn>"
12119.    356        );
12120.    486        html += detail("parameter", name_list.map(function ({id}) {
12121.    486            return id;
12122.    486        }).sort());
12123.   3927        html += detail("variable", id_list(function (entry) {
12124.   1132            return is_own(entry) && entry.role === "variable";
12125.   3927        }));
12126.   3927        html += detail("exception", id_list(function (entry) {
12127.   1132            return is_own(entry) && entry.role === "exception";
12128.   3927        }));
12129.   3927        html += detail("closure", id_list(function (entry) {
12130.   1132            return is_own(entry) && entry.closure === true;
12131.   3927        }));
12132.   3927        html += detail("outer", id_list(function (entry) {
12133.   2795            return !is_own(entry) && entry.scope_declared.id !== "(global)";
12134.   3927        }));
12135.   3927        html += detail(module, id_list(function (entry) {
12136.   2795            return !is_own(entry) && entry.scope_declared.id === "(global)";
12137.   3927        }));
12138.   3927        html += detail("label", id_list(function (entry) {
12139.   1132            return is_own(entry) && entry.role === "label";
12140.   3927        }));
12141.    356        html += "</div>\n";
12142.    356    });
12143.     13    html += "</div>\n";
12144.     13    html += "</fieldset>\n";
12145.     13    return html;
12146.     13}
12147.     23
12148.     37async function jstestDescribe(description, testFunction) {
12149.     37
12150.     37// This function will collect test-group <testFunction>'s tests with given
12151.     37// <description>, then run them.
12152.     37
12153.     37    const describe = {
12154.     37        description,
12155.     37        itList: []
12156.     37    };
12157.     37    const describePrv = jstestDescribePrv;
12158.     37    const recordBody = {
12159.     37        describe: description,
12160.     37        description: "jstestDescribe body",
12161.     37        status: "pending"
12162.     37    };
12163.     37    let message;
12164.     37    let result;
12165.     37
12166.     37// Record <description> before the first await, since describes then
12167.     37// interleave and finish out of source order.
12168.     37
12169.     37    jstestDescribePrv = description;
12170.     37
12171.     37// Init jstestTimeStart.
12172.     37
12173.     22    if (jstestTimeStart === undefined) {
12174.     22        jstestTimeStart = Date.now();
12175.     22        process.on("exit", jstestOnExit);
12176.     22    }
12177.     37
12178.     37// PR-517 - Collect, then run. Record the body as pending, then await it, so a
12179.     37// body that hangs before registering fails at exit instead of passing with 0
12180.     37// tests. A body that throws crashes node as an unhandled rejection, leaving its
12181.     37// record pending. A body that settles clean leaves no record.
12182.     37
12183.     37    jstestItRecordList.push(recordBody);
12184.     32    await jstestDescribeRun(describe, testFunction);
12185.     32    jstestItRecordList.splice(jstestItRecordList.indexOf(recordBody), 1);
12186.     32
12187.     32// PR-517 - Assert this describe's tests, then this describe, are in ASCII
12188.     32// order. Record them before any test runs, so a hung sibling cannot hide them
12189.     32// at exit.
12190.     32
12191.     32    result = [
12192.    363        jstestOrderCheck(describe.itList.map(function (record) {
12193.    363            return record.description;
12194.    363        })),
12195.     32        jstestOrderCheck([describePrv, description])
12196.     32    ].filter(Boolean).map(function ([err, descriptionIt]) {
12197.     32        return {
12198.     32            describe: description,
12199.     32            description: descriptionIt,
12200.     32            err,
12201.     32            status: "failed"
12202.     32        };
12203.     32    });
12204.     32    jstestItRecordList.push(...result);
12205.    363    await Promise.all(describe.itList.map(async function (record) {
12206.    363        try {
12207.    360            await record.testFunction();
12208.    360            record.status = "passed";
12209.    360        } catch (err) {
12210.    360            record.err = err;
12211.    360            record.status = "failed";
12212.    360        }
12213.    363    }));
12214.     32    result.unshift(...describe.itList);
12215.     32
12216.     32// PR-517 - Print nothing for a describe whose tests the filter all skipped.
12217.     32
12218.     32    if (result.length === 0) {
12219.     32        return;
12220.     32    }
12221.     32
12222.     32// Print test results.
12223.     32
12224.     32    message = (
12225.     32        "\n  " + (Date.now() - jstestTimeStart) + "ms" +
12226.     32        " - test describe - " + description + "\n" +
12227.    358        result.map(function (record) {
12228.    358            jstestItCount += 1;
12229.    358            record.printed = true;
12230.    358            return (
12231.    358                (record.status === "passed")
12232.     92                ? (
12233.     92                    "    \u001b[32m\u2714 " + jstestItCount + ". test it - " +
12234.     92                    record.description + "\u001b[39m"
12235.     92                )
12236.    266                : (
12237.    266                    "    \u001b[31m\u2718 " + jstestItCount + ". test it - " +
12238.    266                    record.description + "\n" +
12239.    266                    jstestErrText(record.err) + "\u001b[39m"
12240.    266                )
12241.    358            );
12242.    358        }).join("\n")
12243.     32    );
12244.     32    console.error(message);
12245.     32}
12246.     23
12247.     37function jstestDescribeRun(describe, testFunction) {
12248.     37
12249.     37// This function will run describe-body <testFunction> with <describe> current
12250.     37// only while it runs synchronously, so <jstestIt> registers there alone and a
12251.     37// call after an await throws.
12252.     37
12253.     37    jstestDescribeNow = describe;
12254.     37    try {
12255.     37        return testFunction();
12256.     37    } finally {
12257.     37        jstestDescribeNow = undefined;
12258.     37    }
12259.     37}
12260.     23
12261.    269function jstestErrText(err) {
12262.    269
12263.    269// This function will return the stack of thrown <err>, else <err> as text,
12264.    269// for any thrown value, even a falsy one or a null-prototype object.
12265.    269
12266.    269    try {
12267.    267        return String(err?.stack ?? err);
12268.      1    } catch (ignore) {
12269.      1        return "[" + typeof err + "]";
12270.      1    }
12271.    269}
12272.     23
12273.    374function jstestIt(description, testFunction) {
12274.    374
12275.    374// This function will register test-case <testFunction> with given
12276.    374// <description> in the current describe, to run once its body settles.
12277.    374
12278.    374    const describe = jstestDescribeNow;
12279.    374
12280.    374// PR-517 - Throw outside a describe body's synchronous part, since no describe
12281.    374// would run or report this test.
12282.    374
12283.    372    if (!describe) {
12284.    372        throw new Error(
12285.    372            "jstestIt " + JSON.stringify(description) +
12286.    372            " called outside a jstestDescribe body, or after an await"
12287.    372        );
12288.    372    }
12289.    372
12290.    372// PR-517 - Run only a test whose "<describe> - <it>" matches opt-in regexp
12291.    372// npm_config_mode_test_filter, e.g.
12292.    372// npm_config_mode_test_filter="jstestXxx.*pending" npm test
12293.    372// Prefer the env form, since npm 11 warns the flag form --mode-test-filter
12294.    372// stops working in npm 12.
12295.    372
12296.    372    if (!new RegExp(
12297.    372        process.env.npm_config_mode_test_filter || ""
12298.    372    ).test(describe.description + " - " + description)) {
12299.    372        return;
12300.    372    }
12301.    372
12302.    372// PR-517 - Record this test as pending from registration, so <jstestReport>
12303.    372// sees it even if its describe never runs or prints.
12304.    372
12305.    372    jstestItRecordList.push({
12306.    372        describe: describe.description,
12307.    372        description,
12308.    372        status: "pending",
12309.    372        testFunction
12310.    372    });
12311.    372    describe.itList.push(jstestItRecordList.at(-1));
12312.    372}
12313.     23
12314.     22function jstestOnExit(exitCode) {
12315.     22
12316.     22// This function will on process-exit, print test-report
12317.     22// and exit with non-zero exit-code if any test failed.
12318.     22
12319.     22    const report = jstestReport();
12320.     22    console.error(report.text);
12321.     16    process.exitCode = exitCode || report.exitCode;
12322.     22}
12323.     23
12324.     64function jstestOrderCheck(descriptionList) {
12325.     64
12326.     64// This function will return a failed result for the first description in
12327.     64// <descriptionList> not strictly after the one before it, else undefined.
12328.     64// Strict means a duplicate fails too, as two identical lines cannot be told
12329.     64// apart in the output. Not '>=', which is false for a non-string name such as
12330.     64// undefined, so that name would pass.
12331.     64
12332.    426    for (const [ii, description] of descriptionList.entries()) {
12333.    426        if (ii > 0 && !(descriptionList[ii - 1] < description)) {
12334.    426            const now = JSON.stringify(description);
12335.    426            const prv = JSON.stringify(descriptionList[ii - 1]);
12336.    426            return [
12337.    426                new Error(
12338.    426                    (prv === now)
12339.    426                    ? `duplicate description ${now}`
12340.    426                    : `${now} must sort before ${prv}`
12341.    426                ),
12342.    426                "jstestDescribe and jstestIt descriptions in ASCII order"
12343.    426            ];
12344.    426        }
12345.    426    }
12346.     59}
12347.     23
12348.     22function jstestReport() {
12349.     22
12350.     22// This function will return the test-report <text> and its <exitCode>,
12351.     22// without side effects.
12352.     22
12353.     22// PR-517 - List and count as failed each test its describe never printed: one
12354.     22// still pending, e.g. hung until a watchdog ended the process, or one that
12355.     22// failed while a sibling hung, whose error was otherwise never shown.
12356.     22
12357.    376    const countFailed = jstestItRecordList.filter(function ({status}) {
12358.    376        return status !== "passed";
12359.    376    }).length;
12360.     22    const filter = process.env.npm_config_mode_test_filter;
12361.     22
12362.     22// PR-517 - Fail a run whose filter matched no test, so a stray or mistyped
12363.     22// filter, e.g. a mode_test_filter line left in .npmrc, cannot skip the whole
12364.     22// suite and pass green.
12365.     22
12366.      4    const filterEmpty = Boolean(filter) && jstestItRecordList.length === 0;
12367.    376    const unprintedList = jstestItRecordList.filter(function (record) {
12368.     18        return !record.printed && record.status !== "passed";
12369.    376    });
12370.     22    return {
12371.     22
12372.     22// PR-517 - Exit 1, not the failed count, since an exit status keeps only 8
12373.     22// bits, so 256 failed tests would exit 0.
12374.     22
12375.      4        exitCode: Number(countFailed > 0 || filterEmpty),
12376.     22        text: (
12377.      4            (countFailed > 0 || filterEmpty)
12378.     19            ? "\n\u001b[31m"
12379.      3            : "\n\u001b[32m"
12380.     22        ) +
12381.     17        unprintedList.map(function ({
12382.     17            describe,
12383.     17            description,
12384.     17            err,
12385.     17            status
12386.     17        }, ii) {
12387.     17            return (
12388.     17                "  \u2718 " + (jstestItCount + ii + 1) + ". test it " + status +
12389.     17                " - " + describe + " - " + description + "\n" + (
12390.     17                    (status === "pending")
12391.     14                    ? ""
12392.      3                    : jstestErrText(err) + "\n"
12393.     17                )
12394.     17            );
12395.     17        }).join("") + (
12396.     22            filterEmpty
12397.      1            ? (
12398.      1                "  \u2718 no test matched npm_config_mode_test_filter=" +
12399.      1                JSON.stringify(filter) + "\n"
12400.      1            )
12401.     21            : ""
12402.     22        ) +
12403.     22        "  tests total  - " + jstestItRecordList.length + "\n" +
12404.     22        "  tests failed - " + countFailed + "\n" +
12405.     22        "\n" +
12406.     22        "  time finished - " +
12407.     22        Number(Date.now() - jstestTimeStart).toLocaleString() +
12408.     22        " ms\n" +
12409.     22        "\u001b[39m"
12410.     22    };
12411.     22}
12412.     23
12413.    185async function moduleFsInit() {
12414.    185
12415.    185// This function will import nodejs builtin-modules if they have not yet been
12416.    185// imported.
12417.    185
12418.    185// State 3 - Modules already imported.
12419.    185
12420.    160    if (moduleFs !== undefined) {
12421.    160        return;
12422.    160    }
12423.     25
12424.     25// State 2 - Wait while modules are importing.
12425.     25
12426.     25    if (moduleFsInitResolveList !== undefined) {
12427.      2        return new Promise(function (resolve) {
12428.      2            moduleFsInitResolveList.push(resolve);
12429.      2        });
12430.     23    }
12431.     23
12432.     23// State 1 - Start importing modules.
12433.     23
12434.     23    moduleFsInitResolveList = [];
12435.     23    [
12436.     23        moduleChildProcess,
12437.     23        moduleFs,
12438.     23        modulePath,
12439.     23        moduleUrl
12440.     23    ] = await Promise.all([
12441.     23        import("child_process"),
12442.     23        import("fs"),
12443.     23        import("path"),
12444.     23        import("url")
12445.     23    ]);
12446.     23    while (moduleFsInitResolveList.length > 0) {
12447.      2        moduleFsInitResolveList.shift()();
12448.      2    }
12449.    185}
12450.     23
12451.   3314function noop(value) {
12452.   3314
12453.   3314// This function will do nothing except return <value>.
12454.   3314
12455.   3314    return value;
12456.   3314}
12457.     23
12458.  13201function objectDeepCopyWithKeysSorted(obj) {
12459.  13201
12460.  13201// This function will recursively deep-copy <obj> with keys sorted.
12461.  13201
12462.  13201    let sorted;
12463.   9187    if (typeof obj !== "object" || !obj) {
12464.   9187        return obj;
12465.   9187    }
12466.   4014
12467.   4014// Recursively deep-copy list with child-keys sorted.
12468.   4014
12469.   4014    if (Array.isArray(obj)) {
12470.   1428        return obj.map(objectDeepCopyWithKeysSorted);
12471.   2586    }
12472.   2586
12473.   2586// Recursively deep-copy obj with keys sorted.
12474.   2586
12475.   2586    sorted = Object.create(null);
12476.   7457    Object.keys(obj).sort().forEach(function (key) {
12477.   7457        sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
12478.   7457    });
12479.   2586    return sorted;
12480.   2586}
12481.     23
12482.   2217function object_assign_from_list(dict, list, value) {
12483.   2217
12484.   2217// Assign each property-name from <list> to <dict>.
12485.   2217
12486.  18516    list.forEach(function (key) {
12487.  18516        dict[key] = value;
12488.  18516    });
12489.   2217    return dict;
12490.   2217}
12491.     23
12492.     98function v8CoverageListMerge(processCovs) {
12493.     98
12494.     98// This function is derived from MIT Licensed v8-coverage at
12495.     98// https://github.com/demurgos/v8-coverage/tree/master/ts
12496.     98// https://github.com/demurgos/v8-coverage/blob/master/ts/LICENSE.md
12497.     98//
12498.     98// Merges a list of v8 process coverages.
12499.     98// The result is normalized.
12500.     98// The input values may be mutated, it is not safe to use them after passing
12501.     98// them to this function.
12502.     98// The computation is synchronous.
12503.     98// @param processCovs Process coverages to merge.
12504.     98// @return Merged process coverage.
12505.     98
12506.     98    let resultMerged = [];      // List of merged scripts from processCovs.
12507.     98    let urlToScriptDict = new Map();    // Map scriptCov.url to scriptCovs.
12508.     98
12509.   1198    function compareRangeList(aa, bb) {
12510.   1198
12511.   1198// Compares two range coverages.
12512.   1198// The ranges are first ordered by ascending `startOffset` and then by
12513.   1198// descending `endOffset`.
12514.   1198// This corresponds to a pre-order tree traversal.
12515.   1198
12516.   1168        if (aa.startOffset !== bb.startOffset) {
12517.   1168            return aa.startOffset - bb.startOffset;
12518.   1168        }
12519.     30        return bb.endOffset - aa.endOffset;
12520.     30    }
12521.     98
12522.   1708    function dictKeyValueAppend(dict, key, value) {
12523.   1708
12524.   1708// This function will append <value> to list <dict>[<key>].
12525.   1708
12526.   1708        let list = dict.get(key);
12527.   1166        if (list === undefined) {
12528.   1166            list = [];
12529.   1166            dict.set(key, list);
12530.   1166        }
12531.   1708        list.push(value);
12532.   1708    }
12533.     98
12534.    384    function mergeTreeList(parentTrees) {
12535.    384
12536.    384// This function will return RangeTree object with <parentTrees> merged into
12537.    384// property-children.
12538.    384// @precondition Same `start` and `end` for all the parentTrees
12539.    384
12540.    119        if (parentTrees.length <= 1) {
12541.    119            return parentTrees[0];
12542.    265        }
12543.    265
12544.    265// new RangeTree().
12545.    265
12546.    265        return {
12547.    265
12548.    265// Merge parentTrees into property-children.
12549.    265
12550.    265            children: mergeTreeListToChildren(parentTrees),
12551.    669            delta: parentTrees.reduce(function (aa, bb) {
12552.    669                return aa + bb.delta;
12553.    669            }, 0),
12554.    265            end: parentTrees[0].end,
12555.    265            start: parentTrees[0].start
12556.    265        };
12557.    265    }
12558.     98
12559.    265    function mergeTreeListToChildren(parentTrees) {
12560.    265
12561.    265// This function will return <resultChildren> with <parentTrees> merged.
12562.    265
12563.    265        let openRange;
12564.    265        let parentToChildDict = new Map();      // Map parent to child.
12565.    265        let queueList;
12566.    265        let queueListIi = 0;
12567.    265        let queueOffset;
12568.    265        let queueTrees;
12569.    265        let resultChildren = [];
12570.    265        let startToTreeDict = new Map();        // Map tree.start to tree.
12571.    639        function nextXxx() {
12572.    639
12573.    639// Increment nextOffset, nextTrees.
12574.    639
12575.    639            let [
12576.    639                nextOffset, nextTrees
12577.    300            ] = queueList[queueListIi] || [];
12578.    639            let openRangeEnd;
12579.    583            if (queueTrees === undefined) {
12580.    583                queueListIi += 1;
12581.    583
12582.    583// Increment nextOffset, nextTrees.
12583.    583
12584.    583            } else if (nextOffset === undefined || nextOffset > queueOffset) {
12585.     56                nextOffset = queueOffset;
12586.     56                nextTrees = queueTrees;
12587.     56                queueTrees = undefined;
12588.     56
12589.     56// Concat queueTrees to nextTrees.
12590.     56
12591.     56            } else {
12592.     56                if (nextOffset === queueOffset) {
12593.     56                    queueTrees.forEach(function (tree) {
12594.     56                        nextTrees.push(tree);
12595.     56                    });
12596.     56                    queueTrees = undefined;
12597.     56                }
12598.     56                queueListIi += 1;
12599.     56            }
12600.    639
12601.    639// Reached end of queueList.
12602.    639
12603.    265            if (nextOffset === undefined) {
12604.    265                if (openRange !== undefined) {
12605.    265
12606.    265// Append nested-children from parentToChildDict (within openRange) to
12607.    265// resultChildren.
12608.    265
12609.    265                    resultAppendNextChild();
12610.    265                }
12611.    265                return true;
12612.    374            }
12613.    374            if (openRange !== undefined && openRange.end <= nextOffset) {
12614.    129
12615.    129// Append nested-children from parentToChildDict (within openRange) to
12616.    129// resultChildren.
12617.    129
12618.    129                resultAppendNextChild();
12619.    129                openRange = undefined;
12620.    374            }
12621.    374            if (openRange === undefined) {
12622.    292                openRangeEnd = nextOffset + 1;
12623.    502                nextTrees.forEach(function ({
12624.    502                    parentIi,
12625.    502                    tree
12626.    502                }) {
12627.    502                    openRangeEnd = Math.max(openRangeEnd, tree.end);
12628.    502
12629.    502// Append children from nextTrees to parentToChildDict.
12630.    502
12631.    502                    dictKeyValueAppend(parentToChildDict, parentIi, tree);
12632.    502                });
12633.    292                queueOffset = openRangeEnd;
12634.    292                openRange = {
12635.    292                    end: openRangeEnd,
12636.    292                    start: nextOffset
12637.    292                };
12638.    292            } else {
12639.    114                nextTrees.forEach(function ({
12640.    114                    parentIi,
12641.    114                    tree
12642.    114                }) {
12643.    114                    let right;
12644.     82                    if (tree.end > openRange.end) {
12645.     82                        right = treeSplit(tree, openRange.end);
12646.     82                        if (queueTrees === undefined) {
12647.     82                            queueTrees = [];
12648.     82                        }
12649.     82
12650.     82// new RangeTreeWithParent().
12651.     82
12652.     82                        queueTrees.push({
12653.     82                            parentIi,
12654.     82                            tree: right
12655.     82                        });
12656.     82                    }
12657.    114
12658.    114// Append children from nextTrees to parentToChildDict.
12659.    114
12660.    114                    dictKeyValueAppend(parentToChildDict, parentIi, tree);
12661.    114                });
12662.     82            }
12663.    639        }
12664.    292        function resultAppendNextChild() {
12665.    292
12666.    292// This function will append next child to <resultChildren>.
12667.    292
12668.    292            let treesMatching = [];
12669.    589            parentToChildDict.forEach(function (nested) {
12670.    589                if (
12671.    563                    nested.length === 1 &&
12672.    563                    nested[0].start === openRange.start &&
12673.    480                    nested[0].end === openRange.end
12674.    468                ) {
12675.    468                    treesMatching.push(nested[0]);
12676.    468                } else {
12677.    121
12678.    121// new rangeTreeCreate().
12679.    121
12680.    121                    treesMatching.push({
12681.    121                        children: nested,
12682.    121                        delta: 0,
12683.    121                        end: openRange.end,
12684.    121                        start: openRange.start
12685.    121                    });
12686.    121                }
12687.    589            });
12688.    292            parentToChildDict.clear();
12689.    292
12690.    292// Recurse mergeTreeList.
12691.    292
12692.    292            resultChildren.push(mergeTreeList(treesMatching));
12693.    292        }
12694.     75        function treeSplit(tree, offset) {
12695.     75
12696.     75// This function will split <tree> along <offset> and return the right-side.
12697.     75// @precondition `tree.start < offset && offset < tree.end`
12698.     75// @return RangeTree Right part
12699.     75
12700.     75            let child;
12701.     75            let ii = 0;
12702.     75            let leftChildLen = tree.children.length;
12703.     75            let mid;
12704.     75            let resultTree;
12705.     75            let rightChildren;
12706.     75
12707.     75// TODO(perf): Binary search (check overhead) //jslint-ignore-line
12708.     75
12709.     19            while (ii < tree.children.length) {
12710.     19                child = tree.children[ii];
12711.     19                if (child.start < offset && offset < child.end) {
12712.     19
12713.     19// Recurse treeSplit.
12714.     19
12715.     19                    mid = treeSplit(child, offset);
12716.     19                    leftChildLen = ii + 1;
12717.     19                    break;
12718.     19                }
12719.     19                if (child.start >= offset) {
12720.     19                    leftChildLen = ii;
12721.     19                    break;
12722.     19                }
12723.     19                ii += 1;
12724.     19            }
12725.     75            rightChildren = tree.children.splice(
12726.     75                leftChildLen,
12727.     75                tree.children.length - leftChildLen
12728.     75            );
12729.      4            if (mid !== undefined) {
12730.      4                rightChildren.unshift(mid);
12731.      4            }
12732.     75
12733.     75// new rangeTreeCreate().
12734.     75
12735.     75            resultTree = {
12736.     75                children: rightChildren,
12737.     75                delta: tree.delta,
12738.     75                end: tree.end,
12739.     75                start: offset
12740.     75            };
12741.     75            tree.end = offset;
12742.     75            return resultTree;
12743.     75        }
12744.    265
12745.    265// Init startToTreeDict.
12746.    265
12747.    669        parentTrees.forEach(function (parentTree, parentIi) {
12748.    545            parentTree.children.forEach(function (child) {
12749.    545
12750.    545// Append child with child.start to startToTreeDict.
12751.    545
12752.    545                dictKeyValueAppend(startToTreeDict, child.start, {
12753.    545                    parentIi,
12754.    545                    tree: child
12755.    545                });
12756.    545            });
12757.    669        });
12758.    265
12759.    265// init queueList.
12760.    265
12761.    335        queueList = Array.from(startToTreeDict).map(function ([
12762.    335            startOffset, trees
12763.    335        ]) {
12764.    335
12765.    335// new StartEvent().
12766.    335
12767.    335            return [
12768.    335                startOffset, trees
12769.    335            ];
12770.    222        }).sort(function (aa, bb) {
12771.    222            return aa[0] - bb[0];
12772.    222        });
12773.    639        while (true) {
12774.    639            if (nextXxx()) {
12775.    639                break;
12776.    639            }
12777.    639        }
12778.    265        return resultChildren;
12779.    265    }
12780.     98
12781.    696    function sortFunc(funcCov) {
12782.    696
12783.    696// This function will normalize-and-sort <funcCov>.ranges.
12784.    696// Sorts the ranges (pre-order sort).
12785.    696// TODO: Tree-based normalization of the ranges. //jslint-ignore-line
12786.    696// @param funcCov Function coverage to normalize.
12787.    696
12788.    696        funcCov.ranges = treeToRanges(treeFromSortedRanges(
12789.    696            funcCov.ranges.sort(compareRangeList)
12790.    696        ));
12791.    696        return funcCov;
12792.    696    }
12793.     98
12794.    130    function sortScript(scriptCov) {
12795.    130
12796.    130// This function will normalize-and-sort <scriptCov>.functions.
12797.    130
12798.    130// Normalize-and-sort functions[xxx].ranges.
12799.    130
12800.    695        scriptCov.functions.forEach(function (funcCov) {
12801.    695            sortFunc(funcCov);
12802.    695        });
12803.    130
12804.    130// Sort functions by root range (pre-order sort).
12805.    130
12806.    583        scriptCov.functions.sort(function (aa, bb) {
12807.    583            return compareRangeList(aa.ranges[0], bb.ranges[0]);
12808.    583        });
12809.    130        return scriptCov;
12810.    130    }
12811.     98
12812.    895    function treeFromSortedRanges(ranges) {
12813.    895
12814.    895// @precondition `ranges` are well-formed and pre-order sorted
12815.    895
12816.    895        let root;
12817.    895        let stack = [];   // Stack of parent trees and parent counts.
12818.   1869        ranges.forEach(function (range) {
12819.   1869
12820.   1869// new rangeTreeCreate().
12821.   1869
12822.   1869            let node = {
12823.   1869                children: [],
12824.   1869                delta: range.count,
12825.   1869                end: range.endOffset,
12826.   1869                start: range.startOffset
12827.   1869            };
12828.   1869            let parent;
12829.   1869            let parentCount;
12830.    895            if (root === undefined) {
12831.    895                root = node;
12832.    895                stack.push([
12833.    895                    node, range.count
12834.    895                ]);
12835.    895                return;
12836.    974            }
12837.   1574            while (true) {
12838.   1574                [
12839.   1574                    parent, parentCount
12840.   1574                ] = stack[stack.length - 1];
12841.   1574
12842.   1574// assert: `top !== undefined` (the ranges are sorted)
12843.   1574
12844.   1574                if (range.startOffset < parent.end) {
12845.   1574                    break;
12846.   1574                }
12847.   1574                stack.pop();
12848.   1574            }
12849.    974            node.delta -= parentCount;
12850.    974            parent.children.push(node);
12851.    974            stack.push([
12852.    974                node, range.count
12853.    974            ]);
12854.    974        });
12855.    895        return root;
12856.    895    }
12857.     98
12858.    788    function treeToRanges(tree) {
12859.    788
12860.    788// Get the range coverages corresponding to the tree.
12861.    788// The ranges are pre-order sorted.
12862.    788
12863.    788        let count;
12864.    788        let cur;
12865.    788        let ii;
12866.    788        let parentCount;
12867.    788        let ranges = [];
12868.    788        let stack = [           // Stack of parent trees and counts.
12869.    788            [
12870.    788                tree, 0
12871.    788            ]
12872.    788        ];
12873.   1643        function normalizeRange(tree) {
12874.   1643
12875.   1643// @internal
12876.   1643
12877.   1643            let children = [];
12878.   1643            let curEnd;
12879.   1643            let head;
12880.   1643            let tail = [];
12881.    855            function endChain() {
12882.     18                if (tail.length !== 0) {
12883.     18                    head.end = tail[tail.length - 1].end;
12884.     18                    tail.forEach(function (tailTree) {
12885.     18                        tailTree.children.forEach(function (subChild) {
12886.     18                            subChild.delta += tailTree.delta - head.delta;
12887.     18                            head.children.push(subChild);
12888.     18                        });
12889.     18                    });
12890.     18                    tail.length = 0;
12891.     18                }
12892.    855
12893.    855// Recurse normalizeRange.
12894.    855
12895.    855                normalizeRange(head);
12896.    855                children.push(head);
12897.    855            }
12898.    873            tree.children.forEach(function (child) {
12899.    435                if (head === undefined) {
12900.    435                    head = child;
12901.    438                } else if (
12902.    438                    child.delta === head.delta && child.start === curEnd
12903.    438                ) {
12904.    438                    tail.push(child);
12905.    438                } else {
12906.    438                    endChain();
12907.    438                    head = child;
12908.    438                }
12909.    873                curEnd = child.end;
12910.    873            });
12911.    435            if (head !== undefined) {
12912.    435                endChain();
12913.    435            }
12914.    240            if (children.length === 1) {
12915.    240                if (
12916.    240                    children[0].start === tree.start &&
12917.    240                    children[0].end === tree.end
12918.    240                ) {
12919.    240                    tree.delta += children[0].delta;
12920.    240                    tree.children = children[0].children;
12921.    240
12922.    240// `.lazyCount` is zero for both (both are after normalization)
12923.    240
12924.    240                    return;
12925.    240                }
12926.   1637            }
12927.   1637            tree.children = children;
12928.   1637        }
12929.    788        normalizeRange(tree);
12930.   1637        while (stack.length > 0) {
12931.   1637            [
12932.   1637                cur, parentCount
12933.   1637            ] = stack.pop();
12934.   1637            count = parentCount + cur.delta;
12935.   1637            ranges.push({
12936.   1637                count,
12937.   1637                endOffset: cur.end,
12938.   1637                startOffset: cur.start
12939.   1637            });
12940.   1637            ii = cur.children.length - 1;
12941.   1637            while (ii >= 0) {
12942.   1637                stack.push([
12943.   1637                    cur.children[ii], count
12944.   1637                ]);
12945.   1637                ii -= 1;
12946.   1637            }
12947.   1637        }
12948.    788        return ranges;
12949.    788    }
12950.     98
12951.      1    if (processCovs.length === 0) {
12952.      1        return {
12953.      1            result: []
12954.      1        };
12955.     97    }
12956.     97
12957.     97// Init urlToScriptDict.
12958.     97
12959.    235    processCovs.forEach(function ({
12960.    235        result
12961.    235    }) {
12962.    270        result.forEach(function (scriptCov) {
12963.    270            dictKeyValueAppend(urlToScriptDict, scriptCov.url, scriptCov);
12964.    270        });
12965.    235    });
12966.    130    urlToScriptDict.forEach(function (scriptCovs) {
12967.    130
12968.    130// assert: `scriptCovs.length > 0`
12969.    130
12970.    130// function mergeScriptList(scriptCovs) {
12971.    130// Merges a list of matching script coverages.
12972.    130// Scripts are matching if they have the same `url`.
12973.    130// The result is normalized.
12974.    130// The input values may be mutated, it is not safe to use them after passing
12975.    130// them to this function.
12976.    130// The computation is synchronous.
12977.    130// @param scriptCovs Process coverages to merge.
12978.    130// @return Merged script coverage, or `undefined` if the input list was empty.
12979.    130
12980.    130        let functions = [];
12981.    130
12982.    130// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
12983.    130
12984.    130        let rangeToFuncDict = new Map();
12985.    130
12986.    130// PR-510 - deadcode-confirmed - Every list in <urlToScriptDict> has at least
12987.    130// one element. <dictKeyValueAppend> is the only writer and pushes in the same
12988.    130// call that creates the list, and nothing pops, splices or filters it.
12989.    130//
12990.    130// deadcode-revive - Restore <mergeScriptList>, whose signature is commented
12991.    130// out above. It took its list from any caller, which is why it needed this
12992.    130// guard. Adding a second writer or a filter to the map would also do it.
12993.    130//
12994.    130// if (scriptCovs.length === 0) {
12995.    130//     return undefined;
12996.    130// }
12997.    130
12998.     97        if (scriptCovs.length === 1) {
12999.     97            resultMerged.push(sortScript(scriptCovs[0]));
13000.     97            return;
13001.     97        }
13002.     97
13003.     97// Init rangeToFuncDict.
13004.     97// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
13005.     97
13006.    226        scriptCovs.forEach(function ({
13007.    226            functions
13008.    226        }) {
13009.    277            functions.forEach(function (funcCov) {
13010.    277                dictKeyValueAppend(
13011.    277                    rangeToFuncDict,
13012.    277
13013.    277// This string can be used to match function with same root range.
13014.    277// The string is derived from the start and end offsets of the root range of
13015.    277// the function.
13016.    277// This assumes that `ranges` is non-empty (true for valid function coverages).
13017.    277
13018.    277                    (
13019.    277                        funcCov.ranges[0].startOffset +
13020.    277                        ";" + funcCov.ranges[0].endOffset
13021.    277                    ),
13022.    277                    funcCov
13023.    277                );
13024.    277            });
13025.    226        });
13026.    112        rangeToFuncDict.forEach(function (funcCovs) {
13027.    112
13028.    112// assert: `funcCovs.length > 0`
13029.    112
13030.    112// function mergeFuncList(funcCovs) {
13031.    112// Merges a list of matching function coverages.
13032.    112// Functions are matching if their root ranges have the same span.
13033.    112// The result is normalized.
13034.    112// The input values may be mutated, it is not safe to use them after passing
13035.    112// them to this function.
13036.    112// The computation is synchronous.
13037.    112// @param funcCovs Function coverages to merge.
13038.    112// @return Merged function coverage, or `undefined` if the input list was empty.
13039.    112
13040.    112            let count = 0;
13041.    112            let isBlockCoverage;
13042.    112            let merged;
13043.    112            let ranges;
13044.    112            let trees = [];
13045.    112
13046.    112// PR-510 - deadcode-confirmed - Same as <scriptCovs> above, but with
13047.    112// <rangeToFuncDict>. <dictKeyValueAppend> is its only writer and pushes as it
13048.    112// creates each list.
13049.    112//
13050.    112// deadcode-revive - Restore <mergeFuncList>, commented out above, or give the
13051.    112// map a second writer.
13052.    112//
13053.    112// if (funcCovs.length === 0) {
13054.    112//     return undefined;
13055.    112// }
13056.    112
13057.     97            if (funcCovs.length === 1) {
13058.     97                functions.push(sortFunc(funcCovs[0]));
13059.     97                return;
13060.    111            }
13061.    111
13062.    111// assert: `funcCovs[0].ranges.length > 0`
13063.    111
13064.    276            funcCovs.forEach(function (funcCov) {
13065.    276
13066.    276// assert: `funcCov.ranges.length > 0`
13067.    276// assert: `funcCov.ranges` is sorted
13068.    276
13069.    276                count += (
13070.    276                    funcCov.count !== undefined
13071.    111                    ? funcCov.count
13072.    274                    : funcCov.ranges[0].count
13073.    276                );
13074.    199                if (funcCov.isBlockCoverage) {
13075.    199                    trees.push(treeFromSortedRanges(funcCov.ranges));
13076.    199                }
13077.    276            });
13078.    111            if (trees.length > 0) {
13079.     97                isBlockCoverage = true;
13080.     97                ranges = treeToRanges(mergeTreeList(trees));
13081.     97            } else {
13082.     97                isBlockCoverage = false;
13083.     97                ranges = [
13084.     97                    {
13085.     97                        count,
13086.     97                        endOffset: funcCovs[0].ranges[0].endOffset,
13087.     97                        startOffset: funcCovs[0].ranges[0].startOffset
13088.     97                    }
13089.     97                ];
13090.    111            }
13091.    111            merged = {
13092.    111                functionName: funcCovs[0].functionName,
13093.    111                isBlockCoverage,
13094.    111                ranges
13095.    111            };
13096.    111            if (count !== ranges[0].count) {
13097.     97                merged.count = count;
13098.    111            }
13099.    111
13100.    111// assert: `merged` is normalized
13101.    111
13102.    111            functions.push(merged);
13103.    111        });
13104.     97        resultMerged.push(sortScript({
13105.     97            functions,
13106.     97            scriptId: scriptCovs[0].scriptId,
13107.     97            url: scriptCovs[0].url
13108.     97        }));
13109.     97    });
13110.     97
13111.     97// Sorts the scripts alphabetically by `url`.
13112.     97// Reassigns script ids: the script at index `0` receives `"0"`, the script at
13113.     97// index `1` receives `"1"` etc.
13114.     97
13115.     97    Object.entries(resultMerged.sort(function (aa, bb) {
13116.     97        return (
13117.     97            aa.url > bb.url
13118.     97            ? 1
13119.     97            : -1
13120.     97        );
13121.    130    })).forEach(function ([
13122.    130        scriptId, scriptCov
13123.    130    ]) {
13124.    130        scriptCov.scriptId = scriptId.toString(10);
13125.    130    });
13126.     97    return {
13127.     97        result: resultMerged
13128.     97    };
13129.     97}
13130.     23
13131.      9async function v8CoverageReportCreate({
13132.      9    consoleError,
13133.      9    coverageDir,
13134.      9    processArgv = []
13135.      9}) {
13136.      9
13137.      9// This function will create html-coverage-reports directly from
13138.      9// v8-coverage-files in <coverageDir>.
13139.      9// 1. Spawn node.js program <processArgv> with NODE_V8_COVERAGE.
13140.      9// 2. Merge JSON v8-coverage-files in <coverageDir>.
13141.      9// 3. Create html-coverage-reports in <coverageDir>.
13142.      9
13143.      9    let cwd;
13144.      9    let excludeList = [];
13145.      9    let exitCode = 0;
13146.      9    let fileDict;
13147.      9    let includeList = [];
13148.      9    let modeIncludeNodeModules;
13149.      9    let processArgElem;
13150.      9    let promiseList = [];
13151.      9    let v8CoverageObj;
13152.      9
13153.     15    function htmlRender({
13154.     15        fileList,
13155.     15        lineList,
13156.     15        modeIndex,
13157.     15        pathname
13158.     15    }) {
13159.     15        let html;
13160.     15        let padLines;
13161.     15        let padPathname;
13162.     15        let txt;
13163.     15        let txtBorder;
13164.     15        html = "";
13165.     15        html += String(`
13166.     15<!DOCTYPE html>
13167.     15<html lang="en">
13168.     15<head>
13169.     15<title>V8 Coverage Report</title>
13170.     15<style>
13171.     15/* jslint utility2:true */
13172.     15/*csslint ignore:start*/
13173.     15.coverage,
13174.     15.coverage a,
13175.     15.coverage div,
13176.     15.coverage pre,
13177.     15.coverage span,
13178.     15.coverage table,
13179.     15.coverage tbody,
13180.     15.coverage td,
13181.     15.coverage th,
13182.     15.coverage thead,
13183.     15.coverage tr {
13184.     15    box-sizing: border-box;
13185.     15    font-family: monospace;
13186.     15}
13187.     15/*csslint ignore:end*/
13188.     15
13189.     15/* css - coverage_report - general */
13190.     15body {
13191.     15    margin: 0;
13192.     15}
13193.     15.coverage pre {
13194.     15    margin: 5px 0;
13195.     15}
13196.     15.coverage table {
13197.     15    border-collapse: collapse;
13198.     15}
13199.     15.coverage td,
13200.     15.coverage th {
13201.     15    border: 1px solid #777;
13202.     15    line-height: 20px;
13203.     15    margin: 0;
13204.     15    padding: 5px 10px;
13205.     15}
13206.     15.coverage td span {
13207.     15    display: inline-block;
13208.     15    width: 100%;
13209.     15}
13210.     15.coverage .content {
13211.     15    padding: 0 5px;
13212.     15}
13213.     15.coverage .content a {
13214.     15    text-decoration: none;
13215.     15}
13216.     15.coverage .count {
13217.     15    margin: 0 5px;
13218.     15    padding: 0 5px;
13219.     15}
13220.     15.coverage .footer,
13221.     15.coverage .header {
13222.     15    padding: 20px;
13223.     15}
13224.     15.coverage .footer {
13225.     15    text-align: center;
13226.     15}
13227.     15.coverage .percentbar {
13228.     15    height: 12px;
13229.     15    margin: 2px 0;
13230.     15    min-width: 200px;
13231.     15    position: relative;
13232.     15    width: 100%;
13233.     15}
13234.     15.coverage .percentbar div {
13235.     15    height: 100%;
13236.     15    position: absolute;
13237.     15}
13238.     15.coverage .title {
13239.     15    font-size: large;
13240.     15    font-weight: bold;
13241.     15    margin-bottom: 10px;
13242.     15}
13243.     15
13244.     15/* css - coverage_report - color */
13245.     15.coverage td,
13246.     15.coverage th {
13247.     15    background: #fff;
13248.     15}
13249.     15.coverage .count,
13250.     15.coverage .coverageHigh {
13251.     15    background: #9d9;
13252.     15}
13253.     15.coverage .count {
13254.     15    color: #333;
13255.     15}
13256.     15.coverage .coverageIgnore {
13257.     15    background: #ccc;
13258.     15}
13259.     15.coverage .coverageLow,
13260.     15.coverage .ignore {
13261.     15    background: #ccc;
13262.     15}
13263.     15.coverage .uncovered {
13264.     15    background: #ebb;
13265.     15}
13266.     15.coverage .coverageMedium {
13267.     15    background: #fd7;
13268.     15}
13269.     15.coverage .footer,
13270.     15.coverage .header,
13271.     15.coverage .lineno {
13272.     15    background: #ddd;
13273.     15}
13274.     15.coverage .percentbar {
13275.     15    background: #999;
13276.     15}
13277.     15.coverage .percentbar div {
13278.     15    background: #666;
13279.     15}
13280.     15
13281.     15/* css - coverage_report - important */
13282.     15.coverage pre:hover span,
13283.     15.coverage tr:hover td {
13284.     15    background: #7d7;
13285.     15}
13286.     15.coverage pre:hover span.ignore,
13287.     15.coverage tr:hover td.coverageIgnore {
13288.     15    background: #ccc;
13289.     15}
13290.     15.coverage pre:hover span.uncovered,
13291.     15.coverage tr:hover td.coverageLow {
13292.     15    background: #f99;
13293.     15}
13294.     15</style>
13295.     15</head>
13296.     15<body class="coverage">
13297.     15<!-- header start -->
13298.     15<div class="header">
13299.     15<div class="title">V8 Coverage Report</div>
13300.     15<table>
13301.     15<thead>
13302.     15    <tr>
13303.     15    <th>Files covered</th>
13304.     15    <th>Lines</th>
13305.     15    <th>Remaining</th>
13306.     15    </tr>
13307.     15</thead>
13308.     15<tbody>
13309.     15        `).trim() + "\n";
13310.      8        if (modeIndex) {
13311.      8            padLines = String("(ignore) 100.00 %").length;
13312.      8            padPathname = 32;
13313.      8            fileList.unshift({
13314.      8                linesCovered: 0,
13315.      8                linesTotal: 0,
13316.      8                modeCoverageIgnoreFile: "",
13317.      8                pathname: "./"
13318.      8            });
13319.      8            fileList.slice(1).forEach(function ({
13320.      8                linesCovered,
13321.      8                linesTotal,
13322.      8                modeCoverageIgnoreFile,
13323.      8                pathname
13324.      8            }) {
13325.      8                if (!modeCoverageIgnoreFile) {
13326.      8                    fileList[0].linesCovered += linesCovered;
13327.      8                    fileList[0].linesTotal += linesTotal;
13328.      8                }
13329.      8                padPathname = Math.max(padPathname, pathname.length + 2);
13330.      8                padLines = Math.max(
13331.      8                    padLines,
13332.      8                    String(linesCovered + " / " + linesTotal).length
13333.      8                );
13334.      8            });
13335.      8        }
13336.     15        txtBorder = (
13337.     15            "+" + "-".repeat(padPathname + 2) + "+" +
13338.     15            "-".repeat(padLines + 2) + "+" +
13339.     15            "-".repeat(padLines + 2) + "+\n"
13340.     15        );
13341.     15        txt = "";
13342.     15        txt += "V8 Coverage Report\n";
13343.     15        txt += txtBorder;
13344.     15        txt += (
13345.     15            "| " + String("Files covered").padEnd(padPathname, " ") + " | " +
13346.     15            String("Lines").padStart(padLines, " ") + " | " +
13347.     15            String("Remaining").padStart(padLines, " ") + " |\n"
13348.     15        );
13349.     15        txt += txtBorder;
13350.     22        fileList.forEach(function ({
13351.     22            linesCovered,
13352.     22            linesTotal,
13353.     22            modeCoverageIgnoreFile,
13354.     22            pathname
13355.     22        }, ii) {
13356.     22            let coverageLevel;
13357.     22            let coveragePct;
13358.     22            let fill;
13359.     22            let str1;
13360.     22            let str2;
13361.     22            let xx1;
13362.     22            let xx2;
13363.      2            coveragePct = Math.floor(10000 * linesCovered / linesTotal || 0);
13364.     22            coverageLevel = (
13365.     22                modeCoverageIgnoreFile
13366.      2                ? "coverageIgnore"
13367.     20                : coveragePct >= 8000
13368.     20                ? "coverageHigh"
13369.     20                : coveragePct >= 5000
13370.     20                ? "coverageMedium"
13371.     20                : "coverageLow"
13372.     22            );
13373.     22            coveragePct = Number(coveragePct / 100).toFixed(2);
13374.     15            if (modeIndex && ii === 0) {
13375.      8                fill = (
13376.      8
13377.      8// Badge-color rgb-red.
13378.      8
13379.      8                    "#" + Math.round(
13380.      8                        (100 - Number(coveragePct)) * 2.21
13381.      8                    ).toString(16).padStart(2, "0") +
13382.      8
13383.      8// Badge-color rgb-green.
13384.      8
13385.      8                    Math.round(
13386.      8                        Number(coveragePct) * 2.21
13387.      8                    ).toString(16).padStart(2, "0") +
13388.      8
13389.      8// Badge-color rgb-blue.
13390.      8
13391.      8                    "00"
13392.      8                );
13393.      8                str1 = "coverage";
13394.      8                str2 = coveragePct + " %";
13395.      8                xx1 = 6 * str1.length + 20;
13396.      8                xx2 = 6 * str2.length + 20;
13397.      8
13398.      8// Fs - write coverage_badge.svg.
13399.      8
13400.      8                promiseList.push(fsWriteFileWithParents((
13401.      8                    coverageDir + "coverage_badge.svg"
13402.      8                ), String(`
13403.      8<svg height="20" width="${xx1 + xx2}" xmlns="http://www.w3.org/2000/svg">
13404.      8<rect fill="#555" height="20" width="${xx1 + xx2}"/>
13405.      8<rect fill="${fill}" height="20" width="${xx2}" x="${xx1}"/>
13406.      8<g
13407.      8    fill="#fff"
13408.      8    font-family="verdana, geneva, dejavu sans, sans-serif"
13409.      8    font-size="11"
13410.      8    font-weight="bold"
13411.      8    text-anchor="middle"
13412.      8>
13413.      8<text x="${0.5 * xx1}" y="14">${str1}</text>
13414.      8<text x="${xx1 + 0.5 * xx2}" y="14">${str2}</text>
13415.      8</g>
13416.      8</svg>
13417.      8                `).trim() + "\n"));
13418.      8                pathname = "";
13419.      8            }
13420.     22            txt += (
13421.     22                "| " +
13422.     22                String("./" + pathname).padEnd(padPathname, " ") + " | " +
13423.     22                String(
13424.     22                    modeCoverageIgnoreFile + " " + coveragePct + " %"
13425.     22                ).padStart(padLines, " ") + " | " +
13426.     22                " ".repeat(padLines) + " |\n"
13427.     22            );
13428.     22            txt += (
13429.     22                "| " + "*".repeat(
13430.     22                    Math.round(0.01 * coveragePct * padPathname)
13431.     22                ).padEnd(padPathname, "_") + " | " +
13432.     22                String(
13433.     22                    linesCovered + " / " + linesTotal
13434.     22                ).padStart(padLines, " ") + " | " +
13435.     22                String(
13436.     22                    (linesTotal - linesCovered) + " / " + linesTotal
13437.     22                ).padStart(padLines, " ") + " |\n"
13438.     22            );
13439.     22            txt += txtBorder;
13440.     22            pathname = htmlEscape(pathname);
13441.     22
13442.     22// CL-37251d17 - Bugfix - Fix incorrect http-link to index.html.
13443.     22
13444.     22            html += String(`
13445.     22    <tr>
13446.     22    <td class="${coverageLevel}">
13447.     22            ${(
13448.     22                modeIndex
13449.     15                ? (
13450.     15                    "<a href=\"" + (pathname || "index") + ".html\">. / " +
13451.     15                    pathname + "</a><br>"
13452.     15                )
13453.      7                : (
13454.      7                    "<a href=\"" +
13455.      7                    "../".repeat(pathname.split("/").length - 1) +
13456.      7                    "index.html\">. / </a>" +
13457.      7                    pathname + "<br>"
13458.      7                )
13459.     22            )}
13460.     22        <div class="percentbar">
13461.     22            <div style="width: ${coveragePct}%;"></div>
13462.     22        </div>
13463.     22    </td>
13464.     22    <td style="text-align: right;">
13465.     22        ${modeCoverageIgnoreFile} ${coveragePct} %<br>
13466.     22        ${linesCovered} / ${linesTotal}
13467.     22    </td>
13468.     22    <td style="text-align: right;">
13469.     22        <br>
13470.     22        ${linesTotal - linesCovered} / ${linesTotal}
13471.     22    </td>
13472.     22    </tr>
13473.     22        `).trim() + "\n";
13474.     22        });
13475.     15        html += String(`
13476.     15</tbody>
13477.     15</table>
13478.     15</div>
13479.     15<!-- header end -->
13480.     15        `).trim() + "\n";
13481.      7        if (!modeIndex) {
13482.      7            html += String(`
13483.      7<!-- content start -->
13484.      7<div class="content">
13485.      7            `).trim() + "\n";
13486.  14269            lineList.forEach(function ({
13487.  14269                count,
13488.  14269                holeList,
13489.  14269                ignoreLine,
13490.  14269                line,
13491.  14269                startOffset
13492.  14269            }, ii) {
13493.  14269                let chunk;
13494.  14269                let inHole;
13495.  14269                let lineHtml;
13496.  14269                let lineId;
13497.  14269                lineHtml = "";
13498.  14269                lineId = "line_" + (ii + 1);
13499.  14269                switch (count) {
13500.     32                case -1:
13501.  13077                case 0:
13502.  13077                    if (holeList.length === 0) {
13503.  13077                        lineHtml += "</span>";
13504.  13077                        lineHtml += "<span class=\"uncovered\">";
13505.  13077                        lineHtml += htmlEscape(line);
13506.  13077                        break;
13507.  13077                    }
13508.  13077                    line = line.split("").map(function (char) {
13509.  13077                        return {
13510.  13077                            char,
13511.  13077                            isHole: undefined
13512.  13077                        };
13513.  13077                    });
13514.  13077                    holeList.forEach(function ([
13515.  13077                        aa, bb
13516.  13077                    ]) {
13517.  13077                        aa = Math.max(aa - startOffset, 0);
13518.  13077                        bb = Math.min(bb - startOffset, line.length);
13519.  13077                        while (aa < bb) {
13520.  13077                            line[aa].isHole = true;
13521.  13077                            aa += 1;
13522.  13077                        }
13523.  13077                    });
13524.  13077                    chunk = "";
13525.  13077                    line.forEach(function ({
13526.  13077                        char,
13527.  13077                        isHole
13528.  13077                    }) {
13529.  13077                        if (inHole !== isHole) {
13530.  13077                            lineHtml += htmlEscape(chunk);
13531.  13077                            lineHtml += (
13532.  13077                                (isHole && ignoreLine)
13533.  13077                                ? "</span><span class=\"ignore\">"
13534.  13077                                : isHole
13535.  13077                                ? "</span><span class=\"uncovered\">"
13536.  13077
13537.  13077// PR-510 - deadcode-dispelled - The branch below is live: a hole ending before
13538.  13077// end-of-line re-enters with <isHole> undefined, and that bare span closes it.
13539.  13077// Line coverage hides this, the condition above running either way:
13540.  13077//
13541.  13077// function aa(bb) {
13542.  13077//     return bb && bb.cc;
13543.  13077//               ^^^^^^^^ this hole ends at the ";", not at end-of-line
13544.  13077// }
13545.  13077// aa(0);
13546.  13077
13547.  13077                                : "</span><span>"
13548.  13077                            );
13549.  13077                            chunk = "";
13550.  13077                            inHole = isHole;
13551.  13077                        }
13552.  13077                        chunk += char;
13553.  13077                    });
13554.  13077                    lineHtml += htmlEscape(chunk);
13555.  13077                    break;
13556.   1192                default:
13557.   1192                    lineHtml += htmlEscape(line);
13558.  14269                }
13559.  14269                html += String(`
13560.  14269<pre>
13561.  14269<span class="lineno">
13562.  14269<a href="#${lineId}" id="${lineId}">${String(ii + 1).padStart(5, " ")}.</a>
13563.  14269</span>
13564.  14269<span class="count
13565.  14269                ${(
13566.  13077                    (count <= 0 && ignoreLine)
13567.      7                    ? "ignore"
13568.  14266                    : count <= 0
13569.  14266                    ? "uncovered"
13570.  14266                    : ""
13571.  14269                )}"
13572.  14269>
13573.  13045${String(count || "-0").padStart(7, " ")}
13574.  14269</span>
13575.  14269<span>${lineHtml}</span>
13576.  14269</pre>
13577.  14269                `).replace((
13578.  14269                    /\n/g
13579.  14269                ), "").trim() + "\n";
13580.  14269            });
13581.      7            html += String(`
13582.      7</div>
13583.      7<!-- content end -->
13584.      7            `).trim() + "\n";
13585.      7        }
13586.     15        html += String(`
13587.     15<div class="footer">
13588.     15    [
13589.     15    This document was created with
13590.     15    <a href="https://github.com/jslint-org/jslint">JSLint</a>
13591.     15    ]
13592.     15</div>
13593.     15</body>
13594.     15</html>
13595.     15        `).trim() + "\n";
13596.     15
13597.     15// Fs - write <file>.html.
13598.     15
13599.     15        promiseList.push(fsWriteFileWithParents(pathname + ".html", html));
13600.      7        if (!modeIndex) {
13601.      7            return;
13602.      8        }
13603.      8
13604.      8// Fs - write coverage_report.txt.
13605.      8
13606.      8        consoleError("\n" + txt);
13607.      8        promiseList.push(fsWriteFileWithParents((
13608.      8            coverageDir + "coverage_report.txt"
13609.      8        ), txt));
13610.      8    }
13611.      9
13612.      9/*
13613.      9function sentinel() {}
13614.      9*/
13615.      9
13616.      9    await moduleFsInit();
13617.      1    consoleError = consoleError || console.error;
13618.      9    cwd = process.cwd().replace((
13619.      9        /\\/g
13620.      9    ), "/") + "/";
13621.      9
13622.      9// Init coverageDir.
13623.      9// Assert coverageDir is subdirectory of cwd.
13624.      9
13625.      9    assertOrThrow(coverageDir, "invalid coverageDir " + coverageDir);
13626.      9
13627.      9// CL-61b11012 - coverage - Relax requirement for coverageDir to be in cwd.
13628.      9//     assertOrThrow(
13629.      9//         pathnameRelativeCwd(coverageDir),
13630.      9//         "coverageDir " + coverageDir + " is not subdirectory of cwd " + cwd
13631.      9//     );
13632.      9
13633.      9    coverageDir = modulePath.resolve(coverageDir).replace((
13634.      9        /\\/g
13635.      9    ), "/") + "/";
13636.      9
13637.      9    processArgv = processArgv.slice();
13638.     10    while (processArgv[0] && processArgv[0][0] === "-") {
13639.      3        processArgElem = processArgv.shift().split("=");
13640.      3        processArgElem[1] = processArgElem.slice(1).join("=");
13641.      3        switch (processArgElem[0]) {
13642.      3
13643.      3// PR-371 - Add cli-option `--exclude=...`.
13644.      3
13645.      3        case "--exclude":
13646.      3            excludeList.push(processArgElem[1]);
13647.      3            break;
13648.      3
13649.      3// PR-371 - Add cli-option `--include=...`
13650.      3
13651.      3        case "--include":
13652.      3            includeList.push(processArgElem[1]);
13653.      3            break;
13654.      3
13655.      3// PR-400
13656.      3// Disable default-coverage of directory `node_modules`,
13657.      3// but allow override with cli-option `--include-node-modules=1`.
13658.      3
13659.      3        case "--include-node-modules":
13660.      3            modeIncludeNodeModules = !(
13661.      3                /0|false|null|undefined/
13662.      3            ).test(processArgElem[1]);
13663.      3            break;
13664.      3        }
13665.      8    }
13666.      8
13667.      8// 1. Spawn node.js program <processArgv> with coverage
13668.      8
13669.      8    if (processArgv.length > 0) {
13670.      7
13671.      7// Remove old coverage-files.
13672.      7
13673.      7        await fsWriteFileWithParents(coverageDir + "/touch.txt", "");
13674.      7        await Promise.all(Array.from(
13675.      7            await moduleFs.promises.readdir(coverageDir)
13676.     13        ).map(async function (file) {
13677.     13            if ((
13678.     13                /^coverage-\d+?-\d+?-\d+?\.json$/
13679.      7            ).test(file)) {
13680.      7                consoleError("rm file " + coverageDir + file);
13681.      7                await moduleFs.promises.unlink(coverageDir + file);
13682.      7            }
13683.     13        }));
13684.      7        exitCode = await new Promise(function (resolve) {
13685.      7            let processArgv0 = processArgv[0];
13686.      7
13687.      7// If win32 environment, then replace program npm with npm.cmd.
13688.      7// Coverage-hack - Ugly-hack to get test-coverage under both win32 and linux.
13689.      7
13690.      7            if (processArgv0 === "npm") {
13691.      7                processArgv0 = process.platform
13692.      7                    .replace("win32", "npm.cmd")
13693.      7                    .replace(process.platform, "npm");
13694.      7            }
13695.      7            moduleChildProcess.spawn(
13696.      7                processArgv0,
13697.      7                processArgv.slice(1),
13698.      7                {
13699.      7                    env: {
13700.      7                        ...process.env,
13701.      7                        NODE_V8_COVERAGE: coverageDir
13702.      7                    },
13703.      7
13704.      7// PR-465
13705.      7// https://nodejs.org/en/blog/vulnerability/april-2024-security-releases-2
13706.      7// Node.js will now error with EINVAL if a .bat or .cmd file is passed to
13707.      7// child_process.spawn and child_process.spawnSync without the shell option set.
13708.      7
13709.      7                    shell: (
13710.      7                        processArgv0.endsWith(".bat") ||
13711.      7                        processArgv0.endsWith(".cmd")
13712.      7                    ),
13713.      7                    stdio: ["ignore", 1, 2]
13714.      7                }
13715.      7            ).on("exit", resolve);
13716.      7        });
13717.      7        consoleError(
13718.      7            `v8CoverageReportCreate - program exited with exitCode=${exitCode}`
13719.      7        );
13720.      8    }
13721.      8
13722.      8// 2. Merge JSON v8-coverage-files in <coverageDir>.
13723.      8
13724.      8    consoleError("v8CoverageReportCreate - merging coverage files...");
13725.      8    v8CoverageObj = await moduleFs.promises.readdir(coverageDir);
13726.     21    v8CoverageObj = v8CoverageObj.filter(function (file) {
13727.     21        return (
13728.     21            /^coverage-\d+?-\d+?-\d+?\.json$/
13729.     21        ).test(file);
13730.     21    });
13731.      8    v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
13732.      8        let data;
13733.      8        let pathnameDict = Object.create(null);
13734.      8        data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
13735.      8        data = JSON.parse(data);
13736.    478        data.result.forEach(function (scriptCov) {
13737.    478            let pathname = scriptCov.url;
13738.    478
13739.    478// Filter out internal coverages.
13740.    478
13741.    399            if (!pathname.startsWith("file:///")) {
13742.    399                return;
13743.    399            }
13744.     79
13745.     79// Normalize pathname.
13746.     79
13747.     79            pathname = moduleUrl.fileURLToPath(pathname);
13748.     79            pathname = modulePath.resolve(pathname).replace((
13749.     79                /\\/g
13750.     79            ), "/");
13751.     79
13752.     79// Filter files outside of cwd.
13753.     79
13754.     79            if (pathname.indexOf("[") >= 0 || !pathname.startsWith(cwd)) {
13755.     72                return;
13756.     72            }
13757.      8
13758.      8// Normalize pathname relative to cwd.
13759.      8
13760.      8            pathname = pathname.slice(cwd.length);
13761.      8            scriptCov.url = pathname;
13762.      8            pathnameDict[pathname] = scriptCov;
13763.      8        });
13764.      8
13765.      8// PR-400 - Filter directory `node_modules`.
13766.      8
13767.      8        if (!modeIncludeNodeModules) {
13768.      8            excludeList.push("node_modules/");
13769.      8        }
13770.      8
13771.      8// PR-400 - Filter files by glob-patterns in excludeList, includeList.
13772.      8
13773.      8        data.result = globExclude({
13774.      8            excludeList,
13775.      8            includeList,
13776.      8            pathnameList: Object.keys(pathnameDict)
13777.      8        }).pathnameList.map(function (pathname) {
13778.      8            return pathnameDict[pathname];
13779.      8        });
13780.      8        return data;
13781.      8    }));
13782.      8
13783.      8// Merge v8CoverageObj.
13784.      8
13785.      8    v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
13786.      8
13787.      8// Debug v8CoverageObj.
13788.      8
13789.      8    await fsWriteFileWithParents(
13790.      8        coverageDir + "v8_coverage_merged.json",
13791.      8        JSON.stringify(v8CoverageObj, undefined, 1)
13792.      8    );
13793.      8
13794.      8// 3. Create html-coverage-reports in <coverageDir>.
13795.      8
13796.      8    consoleError("v8CoverageReportCreate - creating html-coverage-report...");
13797.      8    fileDict = Object.create(null);
13798.      8    await Promise.all(v8CoverageObj.result.map(async function ({
13799.      8        functions,
13800.      8        url: pathname
13801.      8    }) {
13802.      8        let ignoreBlock = false;
13803.      8        let lineList;
13804.      8        let linesCovered;
13805.      8        let linesTotal;
13806.      8        let source;
13807.      8        source = await moduleFs.promises.readFile(pathname, "utf8");
13808.      8        lineList = [{}];
13809.      8
13810.      8// PR-513 - One entry per line, "\r\n" being ONE terminator: /^.*$/gm also ends
13811.      8// a line at "\r", so a crlf file got an empty entry after every line.
13812.      8
13813.      8        source.replace((
13814.      8            /(?<![^\n\r])(?!(?<=\r)\n)[^\n\r]*/g
13815.  14269        ), function (line, startOffset) {
13816.      8            if (line === "/*coverage-disable*/") {
13817.      8                ignoreBlock = true;
13818.      8            }
13819.  14269            lineList[lineList.length - 1].endOffset = startOffset - 1;
13820.  14269            lineList.push({
13821.  14269                count: -1,
13822.  14269                endOffset: 0,
13823.  14269                holeList: [],
13824.  14269                ignoreLine: (
13825.  14266                    ignoreBlock || line.endsWith("//coverage-ignore-line")
13826.  14269                ),
13827.  14269                line,
13828.  14269                startOffset
13829.  14269            });
13830.      8            if (line === "/*coverage-enable*/") {
13831.      8                ignoreBlock = false;
13832.      8            }
13833.  14269            return "";
13834.  14269        });
13835.      8        lineList.shift();
13836.      8        lineList[lineList.length - 1].endOffset = source.length;
13837.     48        functions.reverse().forEach(function ({
13838.     48            ranges
13839.     48        }) {
13840.     78            ranges.reverse().forEach(function ({
13841.     78                count,
13842.     78                endOffset,
13843.     78                startOffset
13844.     78            }, ii, list) {
13845. 784126                lineList.forEach(function (elem) {
13846. 784126                    if (!(
13847. 784126                        (
13848. 328082                            elem.startOffset <= startOffset &&
13849. 328082                            startOffset <= elem.endOffset
13850. 784048                        ) || (
13851. 784048                            elem.startOffset <= endOffset &&
13852. 784048                            endOffset <= elem.endOffset
13853. 784048                        ) || (
13854. 783980                            startOffset <= elem.startOffset &&
13855. 783980                            elem.endOffset <= endOffset
13856. 783980                        )
13857. 756198                    )) {
13858. 756198                        return;
13859. 756198                    }
13860.  27928
13861.  27928// Handle tree-root.
13862.  27928
13863.  27928                    if (ii + 1 === list.length) {
13864.  27623                        if (elem.count === -1) {
13865.  27623                            elem.count = count;
13866.  27623                        }
13867.  27623                        return;
13868.  27623                    }
13869.    305
13870.    305// Handle tree-children.
13871.    305
13872.    305                    if (elem.count !== 0) {
13873.    199                        elem.count = Math.max(count, elem.count);
13874.    305                    }
13875.    305                    if (count === 0) {
13876.    239                        elem.count = 0;
13877.    239                        elem.holeList.push([
13878.    239                            startOffset, endOffset
13879.    239                        ]);
13880.    239                    }
13881. 784126                });
13882.     78            });
13883.     48        });
13884.      8        linesTotal = lineList.length;
13885.      8        linesCovered = 0;
13886.  14269        lineList.forEach(function ({
13887.  14269            count,
13888.  14269            ignoreLine
13889.  14269        }) {
13890.  13077            linesCovered += count > 0 || ignoreLine;
13891.  14269        });
13892.      8        await moduleFs.promises.mkdir((
13893.      8            modulePath.dirname(coverageDir + pathname)
13894.      8        ), {
13895.      8            recursive: true
13896.      8        });
13897.      8        fileDict[pathname] = {
13898.      8            lineList,
13899.      8            linesCovered,
13900.      8            linesTotal,
13901.      8            modeCoverageIgnoreFile: (
13902.      8                (
13903.      8                    /^\/\*coverage-ignore-file\*\/$/m
13904.      8                ).test(source.slice(0, 65536))
13905.      8                ? "(ignore)"
13906.      8                : ""
13907.      8            ),
13908.      8            pathname
13909.      8        };
13910.      8        htmlRender({
13911.      8            fileList: [
13912.      8                fileDict[pathname]
13913.      8            ],
13914.      8            lineList,
13915.      8            pathname: coverageDir + pathname
13916.      8        });
13917.      8    }));
13918.      8    htmlRender({
13919.      8        fileList: Object.keys(fileDict).sort().map(function (pathname) {
13920.      8            return fileDict[pathname];
13921.      8        }),
13922.      8        modeIndex: true,
13923.      8        pathname: coverageDir + "index"
13924.      8    });
13925.      8    await Promise.all(promiseList);
13926.      8    assertOrThrow(
13927.      8        exitCode === 0,
13928.      8        "v8CoverageReportCreate - nonzero exitCode " + exitCode
13929.      8    );
13930.      8}
13931.     23
13932.     23/*
13933.     23function sentinel() {}
13934.     23*/
13935.     23
13936.     23// Export jslint as cjs/esm.
13937.     23
13938.     23jslint_export = Object.freeze(
13939.     23    Object.assign(
13940.     23        jslint,
13941.     23        {
13942.     23            assertErrorThrownAsync,
13943.     23            assertJsonEqual,
13944.     23            assertOrThrow,
13945.     23            debugInline,
13946.     23            fsWriteFileWithParents,
13947.     23            globExclude,
13948.     23            htmlEscape,
13949.     23            jslint,
13950.     23            jslint_apidoc,
13951.     23            jslint_charset_ascii,
13952.     23            jslint_cli,
13953.     23            jslint_edition,
13954.     23            jslint_phase1_split,
13955.     23            jslint_phase2_lex,
13956.     23            jslint_phase3_parse,
13957.     23            jslint_phase4_walk,
13958.     23            jslint_phase5_whitage,
13959.     23            jslint_phase6_autofix,
13960.     23            jslint_report,
13961.     23            jstestDescribe,
13962.     23            jstestIt,
13963.     23            moduleFsInit,
13964.     23            noop,
13965.     23            objectDeepCopyWithKeysSorted,
13966.     23            v8CoverageListMerge,
13967.     23            v8CoverageReportCreate
13968.     23        }
13969.     23    )
13970.     23);
13971.     23// module.exports = jslint_export;              // Export jslint as cjs.
13972.     23export default Object.freeze(jslint_export);    // Export jslint as esm.
13973.     23jslint_import_meta_url = import.meta.url;
13974.     23
13975.     23// Run jslint_cli.
13976.     23jslint_cli({});
13977.     23