@jslint-org/jslint 2022.2.20 → 2022.6.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/jslint.mjs CHANGED
@@ -1,14 +1,15 @@
1
1
  // #!/usr/bin/env node
2
2
  // JSLint
3
- // Original Author: Douglas Crockford (https://www.jslint.com).
4
3
 
4
+ // The Unlicense
5
+ //
5
6
  // This is free and unencumbered software released into the public domain.
6
-
7
+ //
7
8
  // Anyone is free to copy, modify, publish, use, compile, sell, or
8
9
  // distribute this software, either in source code form or as a compiled
9
10
  // binary, for any purpose, commercial or non-commercial, and by any
10
11
  // means.
11
-
12
+ //
12
13
  // In jurisdictions that recognize copyright laws, the author or authors
13
14
  // of this software dedicate any and all copyright interest in the
14
15
  // software to the public domain. We make this dedication for the benefit
@@ -16,7 +17,7 @@
16
17
  // successors. We intend this dedication to be an overt act of
17
18
  // relinquishment in perpetuity of all present and future rights to this
18
19
  // software under copyright law.
19
-
20
+ //
20
21
  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21
22
  // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22
23
  // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
@@ -24,7 +25,7 @@
24
25
  // OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25
26
  // ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26
27
  // OTHER DEALINGS IN THE SOFTWARE.
27
-
28
+ //
28
29
  // For more information, please refer to <https://unlicense.org/>
29
30
 
30
31
 
@@ -92,49 +93,46 @@
92
93
  // WARNING: JSLint will hurt your feelings.
93
94
 
94
95
  /*jslint beta, node*/
95
-
96
96
  /*property
97
- fud_stmt,
98
- is_fart,
99
- mode_conditional,
100
97
  JSLINT_BETA, NODE_V8_COVERAGE, a, all, argv, arity, artifact,
101
98
  assertErrorThrownAsync, assertJsonEqual, assertOrThrow, assign, async, b,
102
99
  beta, bitwise, block, body, browser, c, calls, catch, catch_list,
103
- catch_stack, causes, char, children, clear, closer,
104
- closure, code, column, concat, consoleError, console_error, console_log,
105
- constant, context, convert, count, coverageDir, create, cwd, d, dead,
106
- debugInline, default, delta, devel, directive, directive_list,
107
- directive_quiet, directives, dirname, disrupt, dot, edition, elem_list,
108
- ellipsis, else, end, endOffset, endsWith, entries, env, error, eval, every,
109
- example_list, exec, execArgv, exit, export_dict, exports, expression, extra,
110
- file, fileList, fileURLToPath, filter, finally, flag, floor, for, forEach,
111
- formatted_message, free, freeze, from, froms,
112
- fsWriteFileWithParents, functionName, function_list, function_stack,
113
- functions, get, getset, github_repo, global, global_dict, global_list,
114
- holeList, htmlEscape, id, identifier, import, import_list, inc, indent2,
115
- index, indexOf, init, initial, isArray, isBlockCoverage, isHole, isNaN,
116
- is_equal, is_weird, join, jslint, jslint_apidoc, jslint_assert,
117
- jslint_charset_ascii, jslint_cli, jslint_edition, jslint_phase1_split,
118
- jslint_phase2_lex, jslint_phase3_parse, jslint_phase4_walk,
119
- jslint_phase5_whitage, jslint_report, json, jstestDescribe, jstestIt,
120
- jstestOnExit, keys, label, lbp, led_infix, length, level, line, lineList,
121
- line_list, line_offset, line_source, lines, linesCovered, linesTotal, live,
122
- log, long, loop, m, main, map, margin, match, max, message, meta, min,
123
- mkdir, modeCoverageIgnoreFile, modeIndex, mode_cli, mode_json, mode_module,
124
- mode_noop, mode_property, mode_shebang, mode_stop, module, moduleFsInit,
125
- moduleName, module_list, name, names, node, noop, now,
126
- nr, nud_prefix, objectDeepCopyWithKeysSorted, ok, on, open, opening, option,
127
- option_dict, order, package_name, padEnd, padStart, parameters, parent,
128
- parentIi, parse, pathname, platform, pop, processArgv, process_argv,
129
- process_env, process_exit, process_version, promises, property,
130
- property_dict, push, quote, ranges, readFile, readdir, readonly, recursive,
131
- reduce, repeat, replace, resolve, result, reverse, rm, rmdir, role, round,
132
- scriptId, search, set, shebang, shift, signature, single, slice, some, sort,
133
- source, spawn, splice, split, stack, stack_trace, start, startOffset,
134
- startsWith, statement, statement_prv, stdio, stop, stop_at, stringify,
135
- switch, syntax_dict, tenure, test, test_cause, test_internal_error, this,
136
- thru, toString, token, token_global, token_list, token_nxt, token_tree,
137
- tokens, trace, tree, trim, trimEnd, trimRight, try, type, unlink, unordered,
100
+ catch_stack, causes, char, children, clear, closer, closure, code, column,
101
+ concat, consoleError, console_error, console_log, constant, context,
102
+ convert, count, coverageDir, create, cwd, d, dead, debugInline, default,
103
+ delta, devel, directive, directive_list, directive_quiet, directives,
104
+ dirname, disrupt, dot, edition, elem_list, ellipsis, else, end, endOffset,
105
+ endsWith, entries, env, error, eval, every, example_list, excludeList, exec,
106
+ execArgv, exit, exitCode, export_dict, exports, expression, extra, file,
107
+ fileList, fileURLToPath, filter, finally, flag, floor, for, forEach,
108
+ formatted_message, free, freeze, from, froms, fsWriteFileWithParents,
109
+ fud_stmt, functionName, function_list, function_stack, functions, get,
110
+ getset, github_repo, globExclude, global, global_dict, global_list,
111
+ holeList, htmlEscape, id, identifier, import, import_list, import_meta_url,
112
+ inc, includeList, indent2, index, indexOf, init, initial, isArray,
113
+ isBlockCoverage, isHole, isNaN, is_equal, is_fart, is_weird, join, jslint,
114
+ jslint_apidoc, jslint_assert, jslint_charset_ascii, jslint_cli,
115
+ jslint_edition, jslint_phase1_split, jslint_phase2_lex, jslint_phase3_parse,
116
+ jslint_phase4_walk, jslint_phase5_whitage, jslint_report, json,
117
+ jstestDescribe, jstestIt, jstestOnExit, keys, label, lbp, led_infix, length,
118
+ level, line, lineList, line_list, line_offset, line_source, lines,
119
+ linesCovered, linesTotal, live, log, long, loop, m, map, margin, match, max,
120
+ message, meta, min, mkdir, modeCoverageIgnoreFile, modeIndex, mode_cli,
121
+ mode_conditional, mode_json, mode_module, mode_noop, mode_property,
122
+ mode_shebang, mode_stop, module, moduleFsInit, moduleName, module_list,
123
+ name, names, node, nomen, noop, now, nr, nud_prefix,
124
+ objectDeepCopyWithKeysSorted, ok, on, open, opening, option, option_dict,
125
+ order, package_name, padEnd, padStart, parameters, parent, parentIi, parse,
126
+ pathname, pathnameList, platform, pop, processArgv, process_argv,
127
+ process_env, process_exit, promises, property, property_dict, push, quote,
128
+ ranges, readFile, readdir, readonly, recursive, reduce, repeat, replace,
129
+ resolve, result, reverse, role, round, scriptId, search, set, shebang,
130
+ shift, signature, single, slice, some, sort, source, spawn, splice, split,
131
+ stack, stack_trace, start, startOffset, startsWith, statement,
132
+ statement_prv, stdio, stop, stop_at, stringify, subscript, switch,
133
+ syntax_dict, tenure, test, test_cause, test_internal_error, this, thru,
134
+ toString, token, token_global, token_list, token_nxt, token_tree, tokens,
135
+ trace, tree, trim, trimEnd, trimRight, try, type, unlink, unordered,
138
136
  unshift, url, used, v8CoverageListMerge, v8CoverageReportCreate, value,
139
137
  variable, version, versions, warn, warn_at, warning, warning_list, warnings,
140
138
  white, wrapped, writeFile
@@ -142,20 +140,20 @@
142
140
 
143
141
  // init debugInline
144
142
  let debugInline = (function () {
145
- let consoleError = function () {
143
+ let __consoleError = function () {
146
144
  return;
147
145
  };
148
146
  function debug(...argv) {
149
147
 
150
148
  // This function will print <argv> to stderr and then return <argv>[0].
151
149
 
152
- consoleError("\n\ndebugInline");
153
- consoleError(...argv);
154
- consoleError("\n");
150
+ __consoleError("\n\ndebugInline");
151
+ __consoleError(...argv);
152
+ __consoleError("\n");
155
153
  return argv[0];
156
154
  }
157
155
  debug(); // Coverage-hack.
158
- consoleError = console.error;
156
+ __consoleError = console.error;
159
157
  return debug;
160
158
  }());
161
159
  let jslint_charset_ascii = (
@@ -167,11 +165,99 @@ let jslint_charset_ascii = (
167
165
  + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
168
166
  + "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"
169
167
  );
170
- let jslint_edition = "v2022.2.20";
168
+ let jslint_edition = "v2022.6.21";
171
169
  let jslint_export; // The jslint object to be exported.
172
170
  let jslint_fudge = 1; // Fudge starting line and starting
173
171
  // ... column to 1.
174
172
  let jslint_import_meta_url = ""; // import.meta.url used by cli.
173
+ let jslint_rgx_cap = (
174
+ /^[A-Z]/
175
+ );
176
+ let jslint_rgx_crlf = (
177
+ /\n|\r\n?/
178
+ );
179
+ let jslint_rgx_digits_bits = (
180
+ /^[01_]*/
181
+ );
182
+ let jslint_rgx_digits_decimals = (
183
+ /^[0-9_]*/
184
+ );
185
+ let jslint_rgx_digits_hexs = (
186
+ /^[0-9A-F_]*/i
187
+ );
188
+ let jslint_rgx_digits_octals = (
189
+ /^[0-7_]*/
190
+ );
191
+ let jslint_rgx_directive = (
192
+ /^(jslint|property|global)\s+(.*)$/
193
+ );
194
+ let jslint_rgx_directive_part = (
195
+ /([a-zA-Z$_][a-zA-Z0-9$_]*)(?::\s*(true|false))?,?\s*|$/g
196
+ );
197
+ let jslint_rgx_identifier = (
198
+ /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/
199
+ );
200
+ let jslint_rgx_json_number = (
201
+
202
+ // https://datatracker.ietf.org/doc/html/rfc7159#section-6
203
+ // number = [ minus ] int [ frac ] [ exp ]
204
+
205
+ /^-?(?:0|[1-9]\d*)(?:\.\d*)?(?:[eE][\-+]?\d+)?$/
206
+ );
207
+ let jslint_rgx_mega = (
208
+
209
+ // Vim-hack - vim-editor has trouble parsing naked '`' in regexp
210
+
211
+ /[\u0060\\]|\$\{/
212
+ );
213
+ let jslint_rgx_module = (
214
+ /^[a-zA-Z0-9_$:.@\-\/]+$/
215
+ );
216
+ let jslint_rgx_numeric_separator_illegal = (
217
+ /__|_$|_n$/m
218
+ );
219
+ let jslint_rgx_slash_star_or_slash = (
220
+ /\/\*|\/$/
221
+ );
222
+ let jslint_rgx_tab = (
223
+ /\t/g
224
+ );
225
+ let jslint_rgx_todo = (
226
+ /\b(?:todo|TO\s?DO|HACK)\b/
227
+ );
228
+ let jslint_rgx_token = new RegExp(
229
+ "^("
230
+ + "(\\s+)"
231
+ + "|([a-zA-Z_$][a-zA-Z0-9_$]*)"
232
+ + "|[(){}\\[\\],:;'\"~\\`]"
233
+ + "|\\?[?.]?"
234
+ + "|=(?:==?|>)?"
235
+ + "|\\.+"
236
+ + "|\\*[*\\/=]?"
237
+ + "|\\/[*\\/]?"
238
+ + "|\\+[=+]?"
239
+ + "|-[=\\-]?"
240
+ + "|[\\^%]=?"
241
+ + "|&[&=]?"
242
+ + "|\\"
243
+ + "|[|=]?"
244
+ + "|>{1,3}=?"
245
+ + "|<<?=?"
246
+ + "|!(?:!|==?)?"
247
+
248
+ // PR-351 - Add BigInt support.
249
+ // PR-390 - Add numeric-separator support.
250
+
251
+ + "|((?:0_?|[1-9][0-9_]*)n?)"
252
+ + ")"
253
+ + "(.*)$"
254
+ );
255
+ let jslint_rgx_url_search_window_jslint = (
256
+ /[&?]window_jslint=1(?:$|&)/m
257
+ );
258
+ let jslint_rgx_weird_property = (
259
+ /^_|\$|Sync$|_$/m
260
+ );
175
261
  let jstestCountFailed = 0;
176
262
  let jstestCountTotal = 0;
177
263
  let jstestItCount = 0;
@@ -267,6 +353,226 @@ async function fsWriteFileWithParents(pathname, data) {
267
353
  console.error("wrote file " + pathname);
268
354
  }
269
355
 
356
+ function globExclude({
357
+ excludeList = [],
358
+ includeList = [],
359
+ pathnameList = []
360
+ }) {
361
+
362
+ // This function will
363
+ // 1. Exclude pathnames in <pathnameList> that don't match glob-patterns in
364
+ // <includeList>.
365
+ // 2. Exclude pathnames in <pathnameList> that match glob-patterns in
366
+ // <excludeList>.
367
+
368
+ function globAssertNotWeird(list, name) {
369
+
370
+ // This function will check if <list> of strings contain weird characters.
371
+
372
+ [
373
+ [
374
+ "\n", (
375
+ /^.*?([\u0000-\u0007\r]).*/gm
376
+ )
377
+ ],
378
+ [
379
+ "\r", (
380
+ /^.*?([\n]).*/gm
381
+ )
382
+ ]
383
+ ].forEach(function ([
384
+ separator, rgx
385
+ ]) {
386
+ list.join(separator).replace(rgx, function (match0, char) {
387
+ throw new Error(
388
+ "Weird character "
389
+ + JSON.stringify(char)
390
+ + " found in " + name + " "
391
+ + JSON.stringify(match0)
392
+ );
393
+ });
394
+ });
395
+ }
396
+
397
+ function globToRegexp(pattern) {
398
+
399
+ // This function will translate glob <pattern> to javascript-regexp,
400
+ // which javascript can then use to "glob" pathnames.
401
+
402
+ let ii = 0;
403
+ let isClass = false;
404
+ let strClass = "";
405
+ let strRegex = "";
406
+ pattern = pattern.replace((
407
+ /\/\/+/g
408
+ ), "/");
409
+ pattern = pattern.replace((
410
+ /\*\*\*+/g
411
+ ), "**");
412
+ pattern.replace((
413
+ /\\\\|\\\[|\\\]|\[|\]|./g
414
+ ), function (match0) {
415
+ switch (match0) {
416
+ case "[":
417
+ if (isClass) {
418
+ strClass += "[";
419
+ return;
420
+ }
421
+ strClass += "\u0000";
422
+ strRegex += "\u0000";
423
+ isClass = true;
424
+ return;
425
+ case "]":
426
+ if (isClass) {
427
+ isClass = false;
428
+ return;
429
+ }
430
+ strRegex += "]";
431
+ return;
432
+ default:
433
+ if (isClass) {
434
+ strClass += match0;
435
+ return;
436
+ }
437
+ strRegex += match0;
438
+ }
439
+ return "";
440
+ });
441
+ strClass += "\u0000";
442
+
443
+ // An expression "[!...]" matches a single character, namely any character that
444
+ // is not matched by the expression obtained by removing the first '!' from it.
445
+ // (Thus, "[!a-]" matches any single character except 'a', and '-'.)
446
+
447
+ strClass = strClass.replace((
448
+ /\u0000!/g
449
+ ), "\u0000^");
450
+
451
+ // One may include '-' in its literal meaning by making it the first or last
452
+ // character between the brackets.
453
+
454
+ strClass = strClass.replace((
455
+ /\u0000-/g
456
+ ), "\u0000\\-");
457
+ strClass = strClass.replace((
458
+ /-\u0000/g
459
+ ), "\\-\u0000");
460
+
461
+ // Escape brackets '[', ']' in character class.
462
+
463
+ strClass = strClass.replace((
464
+ /[\[\]]/g
465
+ ), "\\$&");
466
+
467
+ // https://stackoverflow.com/questions/3561493
468
+ // /is-there-a-regexp-escape-function-in-javascript
469
+ // $()*+-./?[\]^{|}
470
+
471
+ strRegex = strRegex.replace((
472
+
473
+ // Ignore [-/].
474
+
475
+ /[$()*+.?\[\\\]\^{|}]/g
476
+ ), "\\$&");
477
+
478
+ // Expand wildcard '**/*'.
479
+
480
+ strRegex = strRegex.replace((
481
+ /\\\*\\\*\/(?:\\\*)+/g
482
+ ), ".*?");
483
+
484
+ // Expand wildcard '**'.
485
+
486
+ strRegex = strRegex.replace((
487
+ /(^|\/)\\\*\\\*(\/|$)/gm
488
+ ), "$1.*?$2");
489
+
490
+ // Expand wildcard '*'.
491
+
492
+ strRegex = strRegex.replace((
493
+ /(?:\\\*)+/g
494
+ ), "[^\\/]*?");
495
+
496
+ // Expand wildcard '?'.
497
+
498
+ strRegex = strRegex.replace((
499
+ /\\\?/g
500
+ ), "[^\\/]");
501
+
502
+ // Expand directory-with-trailing-slash '.../'.
503
+
504
+ strRegex = strRegex.replace((
505
+ /\/$/gm
506
+ ), "\\/.*?");
507
+
508
+ // Merge strClass into strRegex.
509
+
510
+ ii = 0;
511
+ strClass = strClass.split("\u0000");
512
+ strRegex = strRegex.replace((
513
+ /\u0000/g
514
+ ), function () {
515
+ ii += 1;
516
+ if (strClass[ii] === "") {
517
+ return "";
518
+ }
519
+ return "[" + strClass[ii] + "]";
520
+ });
521
+
522
+ // Change strRegex from string to regexp.
523
+
524
+ strRegex = new RegExp("^" + strRegex + "$", "gm");
525
+ return strRegex;
526
+ }
527
+
528
+ // Validate excludeList, includeList, pathnameList.
529
+
530
+ globAssertNotWeird(excludeList, "pattern");
531
+ globAssertNotWeird(includeList, "pattern");
532
+ globAssertNotWeird(pathnameList, "pathname");
533
+
534
+ // Optimization
535
+ // Concat pathnames into a single, newline-separated string,
536
+ // whose pathnames can all be filtered with a single, regexp-pass.
537
+
538
+ pathnameList = pathnameList.join("\n");
539
+
540
+ // 1. Exclude pathnames in <pathnameList> that don't match glob-patterns in
541
+ // <includeList>.
542
+
543
+ if (includeList.length > 0) {
544
+ includeList = includeList.map(globToRegexp);
545
+ includeList.forEach(function (pattern) {
546
+ pathnameList = pathnameList.replace(pattern, "\u0000$&");
547
+ });
548
+ pathnameList = pathnameList.replace((
549
+ /^[^\u0000].*/gm
550
+ ), "");
551
+ pathnameList = pathnameList.replace((
552
+ /^\u0000+/gm
553
+ ), "");
554
+ }
555
+
556
+ // 2. Exclude pathnames in <pathnameList> that match glob-patterns in
557
+ // <excludeList>.
558
+
559
+ excludeList = excludeList.map(globToRegexp);
560
+ excludeList.forEach(function (pattern) {
561
+ pathnameList = pathnameList.replace(pattern, "");
562
+ });
563
+
564
+ // Split newline-separated pathnames back to list.
565
+
566
+ pathnameList = pathnameList.split("\n").filter(function (elem) {
567
+ return elem;
568
+ });
569
+ return {
570
+ excludeList,
571
+ includeList,
572
+ pathnameList
573
+ };
574
+ }
575
+
270
576
  function htmlEscape(str) {
271
577
 
272
578
  // This function will make <str> html-safe by escaping & < >.
@@ -307,10 +613,7 @@ function jslint(
307
613
  let import_list = []; // The array collecting all import-from strings.
308
614
  let line_list = String( // The array containing source lines.
309
615
  "\n" + source
310
- ).split(
311
- // rx_crlf
312
- /\n|\r\n?/
313
- ).map(function (line_source) {
616
+ ).split(jslint_rgx_crlf).map(function (line_source) {
314
617
  return {
315
618
  line_source
316
619
  };
@@ -355,8 +658,6 @@ function jslint(
355
658
  }
356
659
 
357
660
  function is_equal(aa, bb) {
358
- let aa_value;
359
- let bb_value;
360
661
 
361
662
  // test_cause:
362
663
  // ["0&&0", "is_equal", "", "", 0]
@@ -377,6 +678,7 @@ function jslint(
377
678
 
378
679
  // test_cause:
379
680
  // ["`${0}`&&`${0}`", "is_equal", "recurse_isArray", "", 0]
681
+ // ["`${0}`&&`${1}`", "is_equal", "recurse_isArray", "", 0]
380
682
 
381
683
  test_cause("recurse_isArray");
382
684
  return is_equal(value, bb[index]);
@@ -390,21 +692,19 @@ function jslint(
390
692
  // }
391
693
 
392
694
  jslint_assert(!Array.isArray(bb), `Expected !Array.isArray(bb).`);
393
- if (aa.id === "(number)" && bb.id === "(number)") {
695
+ switch (aa.id === bb.id && aa.id) {
696
+ case "(number)":
697
+ case "(string)":
394
698
  return aa.value === bb.value;
395
- }
396
- if (aa.id === "(string)") {
397
- aa_value = aa.value;
398
- } else if (aa.id === "`" && aa.constant) {
399
- aa_value = aa.value[0];
400
- }
401
- if (bb.id === "(string)") {
402
- bb_value = bb.value;
403
- } else if (bb.id === "`" && bb.constant) {
404
- bb_value = bb.value[0];
405
- }
406
- if (typeof aa_value === "string") {
407
- return aa_value === bb_value;
699
+
700
+ // PR-394 - Bugfix
701
+ // Fix jslint falsely believing megastring literals `0` and `1` are similar.
702
+
703
+ case "`":
704
+ if (!is_equal(aa.value, bb.value)) {
705
+ return false;
706
+ }
707
+ break;
408
708
  }
409
709
  if (is_weird(aa) || is_weird(bb)) {
410
710
 
@@ -415,10 +715,11 @@ function jslint(
415
715
  return false;
416
716
  }
417
717
  if (aa.arity === bb.arity && aa.id === bb.id) {
418
- if (aa.id === ".") {
718
+ if (aa.id === "." || aa.id === "?.") {
419
719
 
420
720
  // test_cause:
421
721
  // ["aa.bb&&aa.bb", "is_equal", "recurse_arity_id", "", 0]
722
+ // ["aa?.bb&&aa?.bb", "is_equal", "recurse_arity_id", "", 0]
422
723
 
423
724
  test_cause("recurse_arity_id");
424
725
  return (
@@ -687,6 +988,12 @@ function jslint(
687
988
  // case "function_in_loop":
688
989
  // mm = `Don't create functions within a loop.`;
689
990
  // break;
991
+
992
+ // PR-390 - Add numeric-separator check.
993
+
994
+ case "illegal_num_separator":
995
+ mm = `Illegal numeric separator '_' at column ${column}.`;
996
+ break;
690
997
  case "infix_in":
691
998
  mm = (
692
999
  `Unexpected 'in'. Compare with undefined,`
@@ -951,7 +1258,7 @@ function jslint(
951
1258
  mode_json: false, // true if parsing JSON.
952
1259
  mode_module: false, // true if import or export was used.
953
1260
  mode_property: false, // true if directive /*property*/ is
954
- // used.
1261
+ // ... used.
955
1262
  mode_shebang: false, // true if #! is seen on the first line.
956
1263
  option_dict,
957
1264
  property_dict,
@@ -1455,6 +1762,7 @@ async function jslint_cli({
1455
1762
  console_error,
1456
1763
  console_log,
1457
1764
  file,
1765
+ import_meta_url,
1458
1766
  mode_cli,
1459
1767
  mode_noop,
1460
1768
  option,
@@ -1623,11 +1931,26 @@ async function jslint_cli({
1623
1931
  return count;
1624
1932
  }
1625
1933
 
1934
+ // PR-396 - window.jslint
1935
+ // Check import.meta.url for directive to export jslint to window-object.
1936
+ // Useful for ES5-era browser-scripts that rely on window.jslint,
1937
+ // like CodeMirror.
1938
+ //
1939
+ // Example usage:
1940
+ // <script type="module" src="./jslint.mjs?window_jslint=1"></script>
1941
+
1942
+ import_meta_url = import_meta_url || jslint_import_meta_url;
1943
+ if (
1944
+ jslint_rgx_url_search_window_jslint.test(import_meta_url)
1945
+ && (typeof globalThis === "object" && globalThis)
1946
+ ) {
1947
+ globalThis.jslint = jslint;
1948
+ }
1949
+
1626
1950
  // Feature-detect nodejs.
1627
1951
 
1628
1952
  if (!(
1629
- typeof process === "object"
1630
- && process
1953
+ (typeof process === "object" && process)
1631
1954
  && process.versions
1632
1955
  && typeof process.versions.node === "string"
1633
1956
  && !mode_noop
@@ -1653,7 +1976,7 @@ async function jslint_cli({
1653
1976
  ).test(process_argv[1])
1654
1977
  || mode_cli
1655
1978
  )
1656
- && moduleUrl.fileURLToPath(jslint_import_meta_url)
1979
+ && moduleUrl.fileURLToPath(import_meta_url)
1657
1980
  === modulePath.resolve(process_argv[1])
1658
1981
  )
1659
1982
  && !mode_cli
@@ -1799,7 +2122,9 @@ async function jslint_cli({
1799
2122
  option
1800
2123
  });
1801
2124
  if (mode_report) {
1802
- await fsWriteFileWithParents(mode_report, jslint_report(result));
2125
+ result = jslint.jslint_report(result);
2126
+ result = `<body class="JSLINT_ JSLINT_REPORT_">\n${result}</body>\n`;
2127
+ await fsWriteFileWithParents(mode_report, result);
1803
2128
  }
1804
2129
  process_exit(exit_code);
1805
2130
  return exit_code;
@@ -1841,6 +2166,8 @@ function jslint_phase2_lex(state) {
1841
2166
  let line_mega; // The starting line of megastring.
1842
2167
  let line_source = ""; // The remaining line source string.
1843
2168
  let line_whole = ""; // The whole line source string.
2169
+ let mode_digits_empty_string = 1;
2170
+ let mode_digits_numeric_separator = 2;
1844
2171
  let mode_directive = true; // true if directives are still allowed.
1845
2172
  let mode_mega = false; // true if currently parsing a megastring
1846
2173
  // ... literal.
@@ -1848,33 +2175,7 @@ function jslint_phase2_lex(state) {
1848
2175
  // ... this line.
1849
2176
  let paren_backtrack_list = []; // List of most recent "(" tokens at any
1850
2177
  // ... paren-depth.
1851
- let paren_depth = 0; // Keeps track of current paren-depth.
1852
- let rx_token = new RegExp(
1853
- "^("
1854
- + "(\\s+)"
1855
- + "|([a-zA-Z_$][a-zA-Z0-9_$]*)"
1856
- + "|[(){}\\[\\],:;'\"~\\`]"
1857
- + "|\\?[?.]?"
1858
- + "|=(?:==?|>)?"
1859
- + "|\\.+"
1860
- + "|\\*[*\\/=]?"
1861
- + "|\\/[*\\/]?"
1862
- + "|\\+[=+]?"
1863
- + "|-[=\\-]?"
1864
- + "|[\\^%]=?"
1865
- + "|&[&=]?"
1866
- + "|\\"
1867
- + "|[|=]?"
1868
- + "|>{1,3}=?"
1869
- + "|<<?=?"
1870
- + "|!(?:!|==?)?"
1871
-
1872
- // PR-351 - Add BigInt support.
1873
-
1874
- + "|(0n?|[1-9][0-9]*n?)"
1875
- + ")"
1876
- + "(.*)$"
1877
- );
2178
+ let paren_depth = 0; // Keeps track of current paren-depth.
1878
2179
  let snippet = ""; // A piece of string.
1879
2180
  let token_1; // The first token.
1880
2181
  let token_prv = token_global; // The previous token including
@@ -1956,7 +2257,7 @@ function jslint_phase2_lex(state) {
1956
2257
 
1957
2258
  warn_at("unexpected_a", line, column, char);
1958
2259
  }
1959
- if (read_digits("x") > 5) {
2260
+ if (read_digits("x", undefined) > 5) {
1960
2261
 
1961
2262
  // test_cause:
1962
2263
  // ["\"\\u{123456}\"", "char_after_escape", "too_many_digits", "", 11]
@@ -1973,7 +2274,7 @@ function jslint_phase2_lex(state) {
1973
2274
  return char_after();
1974
2275
  }
1975
2276
  char_before();
1976
- if (read_digits("x", true) < 4) {
2277
+ if (read_digits("x", mode_digits_empty_string) < 4) {
1977
2278
 
1978
2279
  // test_cause:
1979
2280
  // ["\"\\u0\"", "char_after_escape", "expected_four_digits", "", 5]
@@ -2008,6 +2309,26 @@ function jslint_phase2_lex(state) {
2008
2309
  return char;
2009
2310
  }
2010
2311
 
2312
+ function check_numeric_separator(digits, column) {
2313
+
2314
+ // This function will check for illegal numeric-separator in <digits>.
2315
+
2316
+ digits.replace((
2317
+ jslint_rgx_numeric_separator_illegal
2318
+ ), function (ignore, ii) {
2319
+
2320
+ // test_cause:
2321
+ // ["0x0_0_;", "check_numeric_separator", "illegal_num_separator", "", 6]
2322
+ // ["0x0_0__0;", "check_numeric_separator", "illegal_num_separator", "", 6]
2323
+ // ["aa=1_2_;", "check_numeric_separator", "illegal_num_separator", "", 7]
2324
+ // ["aa=1_2__3;", "check_numeric_separator", "illegal_num_separator", "", 7]
2325
+ // ["aa=1_2_n;", "check_numeric_separator", "illegal_num_separator", "", 7]
2326
+
2327
+ warn_at("illegal_num_separator", line, column + ii + 1);
2328
+ return "";
2329
+ });
2330
+ }
2331
+
2011
2332
  function lex_comment() {
2012
2333
  let body;
2013
2334
  let ii = 0;
@@ -2046,12 +2367,12 @@ function jslint_phase2_lex(state) {
2046
2367
  // Lex/loop through each line until "*/".
2047
2368
 
2048
2369
  while (true) {
2049
- // rx_star_slash
2370
+ // jslint_rgx_star_slash
2050
2371
  ii = line_source.indexOf("*/");
2051
2372
  if (ii >= 0) {
2052
2373
  break;
2053
2374
  }
2054
- // rx_slash_star
2375
+ // jslint_rgx_slash_star
2055
2376
  ii = line_source.indexOf("/*");
2056
2377
  if (ii >= 0) {
2057
2378
 
@@ -2071,8 +2392,7 @@ function jslint_phase2_lex(state) {
2071
2392
  }
2072
2393
  }
2073
2394
  jj = line_source.slice(0, ii).search(
2074
- // rx_slash_star_or_slash
2075
- /\/\*|\/$/
2395
+ jslint_rgx_slash_star_or_slash
2076
2396
  );
2077
2397
  if (jj >= 0) {
2078
2398
 
@@ -2090,13 +2410,7 @@ function jslint_phase2_lex(state) {
2090
2410
 
2091
2411
  // Uncompleted work comment.
2092
2412
 
2093
- if (
2094
- !option_dict.devel
2095
- && (
2096
- // rx_todo
2097
- /\b(?:todo|TO\s?DO|HACK)\b/
2098
- ).test(snippet)
2099
- ) {
2413
+ if (!option_dict.devel && jslint_rgx_todo.test(snippet)) {
2100
2414
 
2101
2415
  // test_cause:
2102
2416
  // ["//todo", "lex_comment", "todo_comment", "(comment)", 1] //jslint-quiet
@@ -2108,10 +2422,7 @@ function jslint_phase2_lex(state) {
2108
2422
 
2109
2423
  [
2110
2424
  the_comment.directive, body
2111
- ] = Array.from(snippet.match(
2112
- // rx_directive
2113
- /^(jslint|property|global)\s+(.*)$/
2114
- ) || []).slice(1);
2425
+ ] = Array.from(snippet.match(jslint_rgx_directive) || []).slice(1);
2115
2426
  if (the_comment.directive === undefined) {
2116
2427
  return the_comment;
2117
2428
  }
@@ -2133,10 +2444,12 @@ function jslint_phase2_lex(state) {
2133
2444
  // Lex/loop through each directive in /*...*/
2134
2445
 
2135
2446
  ii = 0;
2136
- body.replace((
2137
- // rx_directive_part
2138
- /([a-zA-Z$_][a-zA-Z0-9$_]*)(?::\s*(true|false))?,?\s*|$/g
2139
- ), function (match0, key, val, jj) {
2447
+ body.replace(jslint_rgx_directive_part, function (
2448
+ match0,
2449
+ key,
2450
+ val,
2451
+ jj
2452
+ ) {
2140
2453
  if (ii !== jj) {
2141
2454
 
2142
2455
  // test_cause:
@@ -2160,6 +2473,7 @@ function jslint_phase2_lex(state) {
2160
2473
  global_dict[key] = "user-defined";
2161
2474
 
2162
2475
  // PR-347 - Disable warning "unexpected_directive_a".
2476
+ //
2163
2477
  // state.mode_module = the_comment;
2164
2478
 
2165
2479
  break;
@@ -2210,13 +2524,7 @@ function jslint_phase2_lex(state) {
2210
2524
  // string.
2211
2525
 
2212
2526
  while (true) {
2213
- match = line_source.match(
2214
-
2215
- // Vim-hack - vim-editor has trouble parsing '`' in regexp
2216
-
2217
- // rx_mega
2218
- /[\u0060\\]|\$\{/
2219
- ) || {
2527
+ match = line_source.match(jslint_rgx_mega) || {
2220
2528
  "0": "",
2221
2529
  index: 0
2222
2530
  };
@@ -2293,12 +2601,16 @@ function jslint_phase2_lex(state) {
2293
2601
 
2294
2602
  function lex_number() {
2295
2603
  let prefix = snippet;
2604
+
2605
+ // PR-390 - Add numeric-separator check.
2606
+
2607
+ check_numeric_separator(prefix, column - prefix.length);
2296
2608
  char_after();
2297
2609
  switch (prefix === "0" && char) {
2298
2610
  case "b":
2299
2611
  case "o":
2300
2612
  case "x":
2301
- read_digits(char);
2613
+ read_digits(char, mode_digits_numeric_separator);
2302
2614
 
2303
2615
  // PR-351 - Ignore BigInt suffix 'n'.
2304
2616
 
@@ -2308,14 +2620,14 @@ function jslint_phase2_lex(state) {
2308
2620
  break;
2309
2621
  default:
2310
2622
  if (char === ".") {
2311
- read_digits("d");
2623
+ read_digits("d", mode_digits_numeric_separator);
2312
2624
  }
2313
2625
  if (char === "E" || char === "e") {
2314
2626
  char_after(char);
2315
2627
  if (char !== "+" && char !== "-") {
2316
2628
  char_before();
2317
2629
  }
2318
- read_digits("d");
2630
+ read_digits("d", mode_digits_numeric_separator);
2319
2631
  }
2320
2632
  }
2321
2633
 
@@ -2585,7 +2897,7 @@ function jslint_phase2_lex(state) {
2585
2897
  }
2586
2898
  break;
2587
2899
  case "{":
2588
- if (read_digits("d", true) === 0) {
2900
+ if (read_digits("d", mode_digits_empty_string) === 0) {
2589
2901
 
2590
2902
  // test_cause:
2591
2903
  // ["aa=/aa{/", "lex_regexp_group", "expected_a_before_b", ",", 8]
@@ -2598,7 +2910,7 @@ function jslint_phase2_lex(state) {
2598
2910
  // ["aa=/.{,/", "lex_regexp_group", "comma", "", 0]
2599
2911
 
2600
2912
  test_cause("comma");
2601
- read_digits("d", true);
2913
+ read_digits("d", mode_digits_empty_string);
2602
2914
  }
2603
2915
  if (char_after("}") === "?") {
2604
2916
 
@@ -2891,7 +3203,7 @@ function jslint_phase2_lex(state) {
2891
3203
  }
2892
3204
  }
2893
3205
  from = column;
2894
- match = line_source.match(rx_token);
3206
+ match = line_source.match(jslint_rgx_token);
2895
3207
 
2896
3208
  // match[1] token
2897
3209
  // match[2] whitespace
@@ -2977,9 +3289,10 @@ function jslint_phase2_lex(state) {
2977
3289
  case "getset": // Allow get() and set().
2978
3290
  case "indent2": // Use 2-space indent.
2979
3291
  case "long": // Allow long lines.
2980
- case "name": // Allow weird property names.
2981
3292
  case "node": // Assume Node.js environment.
3293
+ case "nomen": // Allow weird property names.
2982
3294
  case "single": // Allow single-quote strings.
3295
+ case "subscript": // Allow identifier in subscript-notation.
2983
3296
  case "test_cause": // Test jslint's causes.
2984
3297
  case "test_internal_error": // Test jslint's internal-error
2985
3298
  // ... handling-ability.
@@ -2992,6 +3305,16 @@ function jslint_phase2_lex(state) {
2992
3305
  case "white": // Allow messy whitespace.
2993
3306
  option_dict[key] = val;
2994
3307
  break;
3308
+
3309
+ // PR-404 - Alias "evil" to jslint-directive "eval" for backwards-compat.
3310
+
3311
+ case "evil":
3312
+ return option_set_item("eval", val);
3313
+
3314
+ // PR-404 - Alias "nomen" to jslint-directive "name" for backwards-compat.
3315
+
3316
+ case "name":
3317
+ return option_set_item("nomen", val);
2995
3318
  default:
2996
3319
  return false;
2997
3320
  }
@@ -3080,6 +3403,7 @@ console.log(JSON.stringify(Object.keys(window).sort(), undefined, 4));
3080
3403
  "location",
3081
3404
  // "name",
3082
3405
  "navigator",
3406
+ "postMessage",
3083
3407
  // "screen",
3084
3408
  "sessionStorage",
3085
3409
  // "setInterval",
@@ -3274,41 +3598,48 @@ import moduleHttps from "https";
3274
3598
  return true;
3275
3599
  }
3276
3600
 
3277
- function read_digits(base, quiet) {
3601
+ function read_digits(base, mode) {
3278
3602
  let digits = line_source.match(
3279
3603
  base === "b"
3280
- ? (
3281
- // rx_bits
3282
- /^[01]*/
3283
- )
3604
+ ? jslint_rgx_digits_bits
3284
3605
  : base === "o"
3285
- ? (
3286
- // rx_octals
3287
- /^[0-7]*/
3288
- )
3606
+ ? jslint_rgx_digits_octals
3289
3607
  : base === "x"
3290
- ? (
3291
- // rx_hexs
3292
- /^[0-9A-F]*/i
3293
- )
3294
- : (
3295
- // rx_digits
3296
- /^[0-9]*/
3297
- )
3608
+ ? jslint_rgx_digits_hexs
3609
+ : jslint_rgx_digits_decimals
3298
3610
  )[0];
3299
- let length = digits.length;
3300
- if (!quiet && length === 0) {
3611
+ if (
3612
+ (mode !== mode_digits_empty_string && digits.length === 0)
3613
+ || digits[0] === "_"
3614
+ ) {
3301
3615
 
3302
3616
  // test_cause:
3303
3617
  // ["0x", "read_digits", "expected_digits_after_a", "0x", 2]
3618
+ // ["0x_", "read_digits", "expected_digits_after_a", "0x", 2]
3304
3619
 
3305
3620
  warn_at("expected_digits_after_a", line, column, snippet);
3306
3621
  }
3307
- column += length;
3308
- line_source = line_source.slice(length);
3622
+
3623
+ // PR-390 - Add numeric-separator check.
3624
+
3625
+ if (mode === mode_digits_numeric_separator) {
3626
+ check_numeric_separator(digits, column);
3627
+ } else if (digits.indexOf("_") >= 0) {
3628
+
3629
+ // test_cause:
3630
+ // ["\"\\u{1_2}\"", "read_digits", "illegal_num_separator", "", 6]
3631
+
3632
+ warn_at(
3633
+ "illegal_num_separator",
3634
+ line,
3635
+ column + digits.indexOf("_") + 1
3636
+ );
3637
+ }
3638
+ column += digits.length;
3639
+ line_source = line_source.slice(digits.length);
3309
3640
  snippet += digits;
3310
3641
  char_after();
3311
- return length;
3642
+ return digits.length;
3312
3643
  }
3313
3644
 
3314
3645
  function read_line() {
@@ -3379,6 +3710,7 @@ import moduleHttps from "https";
3379
3710
  test_cause("line_disable");
3380
3711
  line_source = "";
3381
3712
  }
3713
+ // jslint_rgx_tab
3382
3714
  if (line_source.indexOf("\t") >= 0) {
3383
3715
  if (!option_dict.white) {
3384
3716
 
@@ -3387,10 +3719,7 @@ import moduleHttps from "https";
3387
3719
 
3388
3720
  warn_at("use_spaces", line, line_source.indexOf("\t") + 1);
3389
3721
  }
3390
- line_source = line_source.replace((
3391
- // rx_tab
3392
- /\t/g
3393
- ), " ");
3722
+ line_source = line_source.replace(jslint_rgx_tab, " ");
3394
3723
  }
3395
3724
  if (!option_dict.white && line_source.endsWith(" ")) {
3396
3725
 
@@ -3564,9 +3893,6 @@ function jslint_phase3_parse(state) {
3564
3893
  let catchage = catch_stack[0]; // The current catch-block.
3565
3894
  let functionage = token_global; // The current function.
3566
3895
  let mode_var; // "var" if using var; "let" if using let.
3567
- let rx_identifier = (
3568
- /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/
3569
- );
3570
3896
  let token_ii = 0; // The number of the next token.
3571
3897
  let token_now = token_global; // The current token being examined in
3572
3898
  // ... the parse.
@@ -3583,7 +3909,7 @@ function jslint_phase3_parse(state) {
3583
3909
  anon = token_now.id;
3584
3910
  } else if (
3585
3911
  token_now.id === "(string)"
3586
- && rx_identifier.test(token_now.value)
3912
+ && jslint_rgx_identifier.test(token_now.value)
3587
3913
  ) {
3588
3914
  anon = token_now.value;
3589
3915
  }
@@ -4174,6 +4500,8 @@ function jslint_phase3_parse(state) {
4174
4500
  left.id !== "["
4175
4501
  || (
4176
4502
  name.id !== "concat"
4503
+ && name.id !== "flat"
4504
+ && name.id !== "flatMap"
4177
4505
  && name.id !== "forEach"
4178
4506
  && name.id !== "join"
4179
4507
  && name.id !== "map"
@@ -4233,7 +4561,10 @@ function jslint_phase3_parse(state) {
4233
4561
  let the_subscript = parse_expression(0);
4234
4562
  if (the_subscript.id === "(string)" || the_subscript.id === "`") {
4235
4563
  name = survey(the_subscript);
4236
- if (rx_identifier.test(name)) {
4564
+
4565
+ // PR-404 - Add new directive "subscript" to play nice with Google Closure.
4566
+
4567
+ if (!option_dict.subscript && jslint_rgx_identifier.test(name)) {
4237
4568
 
4238
4569
  // test_cause:
4239
4570
  // ["aa[`aa`]", "infix_lbracket", "subscript_a", "aa", 4]
@@ -4594,13 +4925,7 @@ function jslint_phase3_parse(state) {
4594
4925
  let negative;
4595
4926
  switch (token_nxt.id) {
4596
4927
  case "(number)":
4597
- if (!(
4598
-
4599
- // https://datatracker.ietf.org/doc/html/rfc7159#section-6
4600
- // number = [ minus ] int [ frac ] [ exp ]
4601
-
4602
- /^-?(?:0|[1-9]\d*?)(?:\.\d*?)?(?:[eE][+\-]?\d+?)?$/
4603
- ).test(token_nxt.value)) {
4928
+ if (!jslint_rgx_json_number.test(token_nxt.value)) {
4604
4929
 
4605
4930
  // test_cause:
4606
4931
  // ["[-.0]", "parse_json", "unexpected_a", ".", 3]
@@ -4968,10 +5293,13 @@ function jslint_phase3_parse(state) {
4968
5293
  functionage.async += 1;
4969
5294
  }
4970
5295
  if (the_await.arity === "statement") {
4971
- the_await.block = parse_expression();
5296
+
5297
+ // PR-405 - Bugfix - fix expression after "await" mis-identified as statement.
5298
+
5299
+ the_await.expression = parse_expression(150);
4972
5300
  semicolon();
4973
5301
  } else {
4974
- the_await.expression = parse_expression();
5302
+ the_await.expression = parse_expression(150);
4975
5303
  }
4976
5304
  return the_await;
4977
5305
  }
@@ -6037,6 +6365,7 @@ function jslint_phase3_parse(state) {
6037
6365
  let names;
6038
6366
 
6039
6367
  // PR-347 - Disable warning "unexpected_directive_a".
6368
+ //
6040
6369
  // if (typeof state.mode_module === "object") {
6041
6370
  //
6042
6371
  // // test_cause:
@@ -6100,10 +6429,7 @@ function jslint_phase3_parse(state) {
6100
6429
  advance("from");
6101
6430
  advance("(string)");
6102
6431
  the_import.import = token_now;
6103
- if (!(
6104
- // rx_module
6105
- /^[a-zA-Z0-9_$:.@\-\/]+$/
6106
- ).test(token_now.value)) {
6432
+ if (!jslint_rgx_module.test(token_now.value)) {
6107
6433
 
6108
6434
  // test_cause:
6109
6435
  // ["import aa from \"!aa\"", "stmt_import", "bad_module_name_a", "!aa", 16]
@@ -6397,12 +6723,16 @@ function jslint_phase3_parse(state) {
6397
6723
  // Restore previous catch-scope after catch-block.
6398
6724
 
6399
6725
  catchage = catch_stack.pop();
6400
- } else {
6401
6726
 
6402
- // test_cause:
6403
- // ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
6727
+ // PR-404 - Relax warning about missing `catch` in `try...finally` statement.
6728
+ //
6729
+ // } else {
6730
+ //
6731
+ // // test_cause:
6732
+ // // ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
6733
+ //
6734
+ // warn("expected_a_before_b", token_nxt, "catch", artifact());
6404
6735
 
6405
- warn("expected_a_before_b", token_nxt, "catch", artifact());
6406
6736
  }
6407
6737
  if (token_nxt.id === "finally") {
6408
6738
  functionage.finally += 1;
@@ -6523,12 +6853,14 @@ function jslint_phase3_parse(state) {
6523
6853
  return stop("expected_identifier_a");
6524
6854
  }
6525
6855
 
6526
- // PR-363 - Bugfix - fix false-warning
6527
- // <uninitialized 'bb'> in code '/*jslint node*/\nlet {aa:bb} = {}; bb();'
6856
+ // PR-363 - Bugfix
6857
+ // Add test against false-warning <uninitialized 'bb'> in code
6858
+ // '/*jslint node*/\nlet {aa:bb} = {}; bb();'.
6859
+ //
6860
+ // token_nxt.label = name;
6861
+ // the_variable.names.push(token_nxt);
6862
+ // enroll(token_nxt, "variable", mode_const);
6528
6863
 
6529
- // token_nxt.label = name;
6530
- // the_variable.names.push(token_nxt);
6531
- // enroll(token_nxt, "variable", mode_const);
6532
6864
  name = token_nxt;
6533
6865
  the_variable.names.push(name);
6534
6866
  survey(name);
@@ -6714,13 +7046,13 @@ function jslint_phase3_parse(state) {
6714
7046
 
6715
7047
  if (id === "(string)") {
6716
7048
  id = name.value;
6717
- if (!rx_identifier.test(id)) {
7049
+ if (!jslint_rgx_identifier.test(id)) {
6718
7050
  return id;
6719
7051
  }
6720
7052
  } else if (id === "`") {
6721
7053
  if (name.value.length === 1) {
6722
7054
  id = name.value[0].value;
6723
- if (!rx_identifier.test(id)) {
7055
+ if (!jslint_rgx_identifier.test(id)) {
6724
7056
  return id;
6725
7057
  }
6726
7058
  }
@@ -6751,12 +7083,9 @@ function jslint_phase3_parse(state) {
6751
7083
  warn("unregistered_property_a", name);
6752
7084
  }
6753
7085
  } else if (
6754
- !option_dict.name
7086
+ !option_dict.nomen
6755
7087
  && name.identifier
6756
- && (
6757
- // rx_weird_property
6758
- /^_|\$|Sync$|_$/m
6759
- ).test(id)
7088
+ && jslint_rgx_weird_property.test(id)
6760
7089
  ) {
6761
7090
 
6762
7091
  // test_cause:
@@ -7510,10 +7839,7 @@ function jslint_phase4_walk(state) {
7510
7839
  test_cause("cack");
7511
7840
  cack = !cack;
7512
7841
  }
7513
- if ((
7514
- // rx_cap
7515
- /^[A-Z]/
7516
- ).test(left.name.id) !== cack) {
7842
+ if (jslint_rgx_cap.test(left.name.id) !== cack) {
7517
7843
  if (the_new !== undefined) {
7518
7844
 
7519
7845
  // test_cause:
@@ -7690,6 +8016,11 @@ function jslint_phase4_walk(state) {
7690
8016
  || thing.expression[0].constant === true
7691
8017
  || is_equal(thing.expression[1], thing.expression[2])
7692
8018
  ) {
8019
+
8020
+ // test_cause:
8021
+ // ["let aa=(aa?`${0}`:`${0}`);", "post_t", "unexpected_a", "?", 11]
8022
+ // ["let aa=(aa?`0`:`0`);", "post_t", "unexpected_a", "?", 11]
8023
+
7693
8024
  warn("unexpected_a", thing);
7694
8025
  } else if (is_equal(thing.expression[0], thing.expression[1])) {
7695
8026
 
@@ -8165,9 +8496,6 @@ function jslint_phase4_walk(state) {
8165
8496
  // ["+[]", "walk_statement", "unexpected_expression_a", "+", 1]
8166
8497
  // ["+new aa()", "walk_statement", "unexpected_expression_a", "+", 1]
8167
8498
  // ["0", "walk_statement", "unexpected_expression_a", "0", 1]
8168
- // ["
8169
- // async function aa(){await 0;}
8170
- // ", "walk_statement", "unexpected_expression_a", "0", 27]
8171
8499
  // ["typeof 0", "walk_statement", "unexpected_expression_a", "typeof", 1]
8172
8500
 
8173
8501
  warn("unexpected_expression_a", thing);
@@ -8909,6 +9237,7 @@ function jslint_report({
8909
9237
 
8910
9238
  // This function will create human-readable, html-report
8911
9239
  // for warnings, properties, and functions from jslint-result-object.
9240
+ //
8912
9241
  // Example usage:
8913
9242
  // let result = jslint("console.log('hello world')");
8914
9243
  // let html = jslint_report(result);
@@ -8941,7 +9270,6 @@ function jslint_report({
8941
9270
  );
8942
9271
  }
8943
9272
 
8944
- html += "<div class=\"JSLINT_\" id=\"JSLINT_REPORT_HTML\">\n";
8945
9273
  html += String(`
8946
9274
  <style class="JSLINT_REPORT_STYLE">
8947
9275
  /* jslint utility2:true */
@@ -9090,19 +9418,38 @@ pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
9090
9418
  /7xoEqvL+2E8VOyCTuT/7j269Zy4jUtN+g4="
9091
9419
  ) format("woff2");
9092
9420
  }
9093
- *,
9094
- *:after,
9095
- *:before {
9421
+ .JSLINT_,
9422
+ .JSLINT_ address,
9423
+ .JSLINT_ button,
9424
+ .JSLINT_ cite,
9425
+ .JSLINT_ dd,
9426
+ .JSLINT_ dfn,
9427
+ .JSLINT_ dl,
9428
+ .JSLINT_ dt,
9429
+ .JSLINT_ fieldset,
9430
+ .JSLINT_ fieldset > div,
9431
+ .JSLINT_ input,
9432
+ .JSLINT_ label,
9433
+ .JSLINT_ legend,
9434
+ .JSLINT_ ol,
9435
+ .JSLINT_ samp,
9436
+ .JSLINT_ style,
9437
+ .JSLINT_ textarea,
9438
+ .JSLINT_ ul {
9096
9439
  border: 0;
9097
9440
  box-sizing: border-box;
9098
9441
  margin: 0;
9099
9442
  padding: 0;
9100
9443
  }
9444
+ /* disable text inflation algorithm used on some smartphones and tablets */
9101
9445
  .JSLINT_ {
9102
9446
  -ms-text-size-adjust: none;
9103
9447
  -webkit-text-size-adjust: none;
9104
9448
  text-size-adjust: none;
9105
9449
  }
9450
+ .JSLINT_REPORT_ div {
9451
+ box-sizing: border-box;
9452
+ }
9106
9453
  /*csslint ignore:end*/
9107
9454
 
9108
9455
  /* css - jslint_report - font */
@@ -9136,7 +9483,7 @@ pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
9136
9483
  }
9137
9484
 
9138
9485
  /* css - jslint_report - general */
9139
- body {
9486
+ .JSLINT_ {
9140
9487
  background: antiquewhite;
9141
9488
  }
9142
9489
  .JSLINT_ fieldset {
@@ -9382,6 +9729,9 @@ body {
9382
9729
  : "global"
9383
9730
  );
9384
9731
  if (global.length + froms.length + exports.length > 0) {
9732
+ if (functions.length === 0) {
9733
+ html += "<br>\n";
9734
+ }
9385
9735
  html += "<div class=\"level level0\">\n";
9386
9736
  html += detail(module, global);
9387
9737
  html += detail("import from", froms);
@@ -9470,7 +9820,6 @@ body {
9470
9820
  });
9471
9821
  html += "</div>\n";
9472
9822
  html += "</fieldset>\n";
9473
- html += "</div>\n";
9474
9823
  return html;
9475
9824
  }
9476
9825
 
@@ -9481,6 +9830,7 @@ async function jstestDescribe(description, testFunction) {
9481
9830
 
9482
9831
  let message;
9483
9832
  let result;
9833
+ let timerTimeout;
9484
9834
 
9485
9835
  // Init jstestTimeStart.
9486
9836
 
@@ -9496,7 +9846,9 @@ async function jstestDescribe(description, testFunction) {
9496
9846
 
9497
9847
  // Wait for jstestItList to resolve.
9498
9848
 
9849
+ timerTimeout = setTimeout(noop, 0x7fffffff);
9499
9850
  result = await Promise.all(jstestItList);
9851
+ clearTimeout(timerTimeout);
9500
9852
 
9501
9853
  // Print test results.
9502
9854
 
@@ -9546,14 +9898,14 @@ function jstestIt(description, testFunction, mode) {
9546
9898
  }));
9547
9899
  }
9548
9900
 
9549
- function jstestOnExit(exitCode, processExit, countFailed) {
9901
+ function jstestOnExit(exitCode, mode) {
9550
9902
 
9551
9903
  // This function will on process-exit, print test-report
9552
9904
  // and exit with non-zero exit-code if any test failed.
9553
9905
 
9554
9906
  let message = (
9555
9907
  (
9556
- (jstestCountFailed || countFailed)
9908
+ (jstestCountFailed || mode === "testsFailed")
9557
9909
  ? "\n\u001b[31m"
9558
9910
  : "\n\u001b[32m"
9559
9911
  )
@@ -9561,11 +9913,10 @@ function jstestOnExit(exitCode, processExit, countFailed) {
9561
9913
  + " tests failed - " + jstestCountFailed + "\n"
9562
9914
  + "\u001b[39m"
9563
9915
  );
9564
- if (!processExit) {
9916
+ if (mode !== "testsFailed") {
9565
9917
  console.error(message);
9566
- processExit = process.exit;
9567
9918
  }
9568
- processExit(exitCode || jstestCountFailed);
9919
+ process.exitCode = exitCode || jstestCountFailed;
9569
9920
  return message;
9570
9921
  }
9571
9922
 
@@ -10287,11 +10638,11 @@ async function v8CoverageReportCreate({
10287
10638
  // 3. Create html-coverage-reports in <coverageDir>.
10288
10639
 
10289
10640
  let cwd;
10641
+ let excludeList = [];
10290
10642
  let exitCode = 0;
10291
10643
  let fileDict;
10292
- let fileExcludeList = [];
10293
- let fileIncludeList = [];
10294
- let fileIncludeNodeModules;
10644
+ let includeList = [];
10645
+ let modeIncludeNodeModules;
10295
10646
  let processArgElem;
10296
10647
  let promiseList = [];
10297
10648
  let v8CoverageObj;
@@ -10316,9 +10667,19 @@ async function v8CoverageReportCreate({
10316
10667
  <style>
10317
10668
  /* jslint utility2:true */
10318
10669
  /*csslint ignore:start*/
10319
- * {
10320
- box-sizing: border-box;
10321
- font-family: consolas, menlo, monospace;
10670
+ .coverage,
10671
+ .coverage a,
10672
+ .coverage div,
10673
+ .coverage pre,
10674
+ .coverage span,
10675
+ .coverage table,
10676
+ .coverage tbody,
10677
+ .coverage td,
10678
+ .coverage th,
10679
+ .coverage thead,
10680
+ .coverage tr {
10681
+ box-sizing: border-box;
10682
+ font-family: monospace;
10322
10683
  }
10323
10684
  /*csslint ignore:end*/
10324
10685
 
@@ -10464,6 +10825,7 @@ body {
10464
10825
  }
10465
10826
  txtBorder = (
10466
10827
  "+" + "-".repeat(padPathname + 2) + "+"
10828
+ + "-".repeat(padLines + 2) + "+"
10467
10829
  + "-".repeat(padLines + 2) + "+\n"
10468
10830
  );
10469
10831
  txt = "";
@@ -10471,7 +10833,8 @@ body {
10471
10833
  txt += txtBorder;
10472
10834
  txt += (
10473
10835
  "| " + String("Files covered").padEnd(padPathname, " ") + " | "
10474
- + String("Lines").padStart(padLines, " ") + " |\n"
10836
+ + String("Lines").padStart(padLines, " ") + " | "
10837
+ + String("Remaining").padStart(padLines, " ") + " |\n"
10475
10838
  );
10476
10839
  txt += txtBorder;
10477
10840
  fileList.forEach(function ({
@@ -10551,7 +10914,8 @@ body {
10551
10914
  + String("./" + pathname).padEnd(padPathname, " ") + " | "
10552
10915
  + String(
10553
10916
  modeCoverageIgnoreFile + " " + coveragePct + " %"
10554
- ).padStart(padLines, " ") + " |\n"
10917
+ ).padStart(padLines, " ") + " | "
10918
+ + " ".repeat(padLines) + " |\n"
10555
10919
  );
10556
10920
  txt += (
10557
10921
  "| " + "*".repeat(
@@ -10559,6 +10923,9 @@ body {
10559
10923
  ).padEnd(padPathname, "_") + " | "
10560
10924
  + String(
10561
10925
  linesCovered + " / " + linesTotal
10926
+ ).padStart(padLines, " ") + " | "
10927
+ + String(
10928
+ (linesTotal - linesCovered) + " / " + linesTotal
10562
10929
  ).padStart(padLines, " ") + " |\n"
10563
10930
  );
10564
10931
  txt += txtBorder;
@@ -10722,21 +11089,6 @@ ${String(count || "-0").padStart(7, " ")}
10722
11089
  ), txt));
10723
11090
  }
10724
11091
 
10725
- function pathnameRelativeCwd(pathname) {
10726
-
10727
- // This function will if <pathname> is inside <cwd>,
10728
- // return it relative to <cwd>, else empty-string.
10729
-
10730
- pathname = modulePath.resolve(pathname).replace((
10731
- /\\/g
10732
- ), "/");
10733
- if (!pathname.startsWith(cwd)) {
10734
- return;
10735
- }
10736
- pathname = pathname.slice(cwd.length);
10737
- return pathname;
10738
- }
10739
-
10740
11092
  /*
10741
11093
  function sentinel() {}
10742
11094
  */
@@ -10768,28 +11120,26 @@ function sentinel() {}
10768
11120
  processArgElem[1] = processArgElem.slice(1).join("=");
10769
11121
  switch (processArgElem[0]) {
10770
11122
 
10771
- // PR-371 - add cli-option `--exclude=aa,bb`
11123
+ // PR-371 - Add cli-option `--exclude=...`.
10772
11124
 
10773
11125
  case "--exclude":
10774
- fileExcludeList = fileExcludeList.concat(
10775
- processArgElem[1].split(",")
10776
- );
11126
+ excludeList.push(processArgElem[1]);
10777
11127
  break;
10778
11128
 
10779
- // PR-371 - add cli-option `--exclude-node-modules=false`
11129
+ // PR-371 - Add cli-option `--include=...`
10780
11130
 
10781
- case "--exclude-node-modules":
10782
- fileIncludeNodeModules = (
10783
- /0|false|null|undefined/
10784
- ).test(processArgElem[1]);
11131
+ case "--include":
11132
+ includeList.push(processArgElem[1]);
10785
11133
  break;
10786
11134
 
10787
- // PR-371 - add cli-option `--include=aa,bb`
11135
+ // PR-400
11136
+ // Disable default-coverage of directory `node_modules`,
11137
+ // but allow override with cli-option `--include-node-modules=1`.
10788
11138
 
10789
- case "--include":
10790
- fileIncludeList = fileIncludeList.concat(
10791
- processArgElem[1].split(",")
10792
- );
11139
+ case "--include-node-modules":
11140
+ modeIncludeNodeModules = !(
11141
+ /0|false|null|undefined/
11142
+ ).test(processArgElem[1]);
10793
11143
  break;
10794
11144
  }
10795
11145
  }
@@ -10843,9 +11193,11 @@ function sentinel() {}
10843
11193
  ).test(file);
10844
11194
  });
10845
11195
  v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
10846
- let data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
11196
+ let data;
11197
+ let pathnameDict = Object.create(null);
11198
+ data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
10847
11199
  data = JSON.parse(data);
10848
- data.result = data.result.filter(function (scriptCov) {
11200
+ data.result.forEach(function (scriptCov) {
10849
11201
  let pathname = scriptCov.url;
10850
11202
 
10851
11203
  // Filter out internal coverages.
@@ -10856,38 +11208,38 @@ function sentinel() {}
10856
11208
 
10857
11209
  // Normalize pathname.
10858
11210
 
10859
- pathname = pathnameRelativeCwd(moduleUrl.fileURLToPath(pathname));
10860
- if (
11211
+ pathname = moduleUrl.fileURLToPath(pathname);
11212
+ pathname = modulePath.resolve(pathname).replace((
11213
+ /\\/g
11214
+ ), "/");
10861
11215
 
10862
11216
  // Filter files outside of cwd.
10863
11217
 
10864
- !pathname
10865
- || pathname.startsWith("[")
11218
+ if (pathname.indexOf("[") >= 0 || !pathname.startsWith(cwd)) {
11219
+ return;
11220
+ }
10866
11221
 
10867
- // PR-371 - Filter directory node_modules.
11222
+ // Normalize pathname relative to cwd.
10868
11223
 
10869
- || (
10870
- !fileIncludeNodeModules
10871
- && (
10872
- /(?:^|\/)node_modules\//m
10873
- ).test(pathname)
10874
- )
11224
+ pathname = pathname.slice(cwd.length);
11225
+ scriptCov.url = pathname;
11226
+ pathnameDict[pathname] = scriptCov;
11227
+ });
10875
11228
 
10876
- // PR-371 - Filter fileExcludeList.
11229
+ // PR-400 - Filter directory `node_modules`.
10877
11230
 
10878
- || fileExcludeList.indexOf(pathname) >= 0
11231
+ if (!modeIncludeNodeModules) {
11232
+ excludeList.push("node_modules/");
11233
+ }
10879
11234
 
10880
- // PR-371 - Filter fileIncludeList.
11235
+ // PR-400 - Filter files by glob-patterns in excludeList, includeList.
10881
11236
 
10882
- || (
10883
- fileIncludeList.length > 0
10884
- && fileIncludeList.indexOf(pathname) === -1
10885
- )
10886
- ) {
10887
- return;
10888
- }
10889
- scriptCov.url = pathname;
10890
- return true;
11237
+ data.result = globExclude({
11238
+ excludeList,
11239
+ includeList,
11240
+ pathnameList: Object.keys(pathnameDict)
11241
+ }).pathnameList.map(function (pathname) {
11242
+ return pathnameDict[pathname];
10891
11243
  });
10892
11244
  return data;
10893
11245
  }));
@@ -10896,7 +11248,7 @@ function sentinel() {}
10896
11248
 
10897
11249
  v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
10898
11250
 
10899
- // debug v8CoverageObj.
11251
+ // Debug v8CoverageObj.
10900
11252
 
10901
11253
  await fsWriteFileWithParents(
10902
11254
  coverageDir + "v8_coverage_merged.json",
@@ -11036,6 +11388,7 @@ jslint_export = Object.freeze(Object.assign(jslint, {
11036
11388
  assertOrThrow,
11037
11389
  debugInline,
11038
11390
  fsWriteFileWithParents,
11391
+ globExclude,
11039
11392
  htmlEscape,
11040
11393
  jslint,
11041
11394
  jslint_apidoc,