@jslint-org/jslint 2022.3.30 → 2022.7.20

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_ignore_line, directive_list, 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; //jslint-ignore-line
159
157
  return debug;
160
158
  }());
161
159
  let jslint_charset_ascii = (
@@ -167,7 +165,7 @@ let jslint_charset_ascii = (
167
165
  + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
168
166
  + "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"
169
167
  );
170
- let jslint_edition = "v2022.3.30";
168
+ let jslint_edition = "v2022.7.20";
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.
@@ -254,6 +252,9 @@ let jslint_rgx_token = new RegExp(
254
252
  + ")"
255
253
  + "(.*)$"
256
254
  );
255
+ let jslint_rgx_url_search_window_jslint = (
256
+ /[&?]window_jslint=1(?:$|&)/m
257
+ );
257
258
  let jslint_rgx_weird_property = (
258
259
  /^_|\$|Sync$|_$/m
259
260
  );
@@ -352,6 +353,226 @@ async function fsWriteFileWithParents(pathname, data) {
352
353
  console.error("wrote file " + pathname);
353
354
  }
354
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
+
355
576
  function htmlEscape(str) {
356
577
 
357
578
  // This function will make <str> html-safe by escaping & < >.
@@ -437,8 +658,6 @@ function jslint(
437
658
  }
438
659
 
439
660
  function is_equal(aa, bb) {
440
- let aa_value;
441
- let bb_value;
442
661
 
443
662
  // test_cause:
444
663
  // ["0&&0", "is_equal", "", "", 0]
@@ -459,6 +678,7 @@ function jslint(
459
678
 
460
679
  // test_cause:
461
680
  // ["`${0}`&&`${0}`", "is_equal", "recurse_isArray", "", 0]
681
+ // ["`${0}`&&`${1}`", "is_equal", "recurse_isArray", "", 0]
462
682
 
463
683
  test_cause("recurse_isArray");
464
684
  return is_equal(value, bb[index]);
@@ -472,21 +692,19 @@ function jslint(
472
692
  // }
473
693
 
474
694
  jslint_assert(!Array.isArray(bb), `Expected !Array.isArray(bb).`);
475
- if (aa.id === "(number)" && bb.id === "(number)") {
695
+ switch (aa.id === bb.id && aa.id) {
696
+ case "(number)":
697
+ case "(string)":
476
698
  return aa.value === bb.value;
477
- }
478
- if (aa.id === "(string)") {
479
- aa_value = aa.value;
480
- } else if (aa.id === "`" && aa.constant) {
481
- aa_value = aa.value[0];
482
- }
483
- if (bb.id === "(string)") {
484
- bb_value = bb.value;
485
- } else if (bb.id === "`" && bb.constant) {
486
- bb_value = bb.value[0];
487
- }
488
- if (typeof aa_value === "string") {
489
- 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;
490
708
  }
491
709
  if (is_weird(aa) || is_weird(bb)) {
492
710
 
@@ -497,10 +715,11 @@ function jslint(
497
715
  return false;
498
716
  }
499
717
  if (aa.arity === bb.arity && aa.id === bb.id) {
500
- if (aa.id === ".") {
718
+ if (aa.id === "." || aa.id === "?.") {
501
719
 
502
720
  // test_cause:
503
721
  // ["aa.bb&&aa.bb", "is_equal", "recurse_arity_id", "", 0]
722
+ // ["aa?.bb&&aa?.bb", "is_equal", "recurse_arity_id", "", 0]
504
723
 
505
724
  test_cause("recurse_arity_id");
506
725
  return (
@@ -641,11 +860,22 @@ function jslint(
641
860
  c,
642
861
  d
643
862
  );
644
- if (the_token.warning === undefined) {
645
- the_token.warning = the_warning;
646
- } else {
863
+
864
+ // Issue #408
865
+ // Warnings that should be ignored sometimes suppress legitimate warnings.
866
+
867
+ if (the_warning.directive_ignore_line) {
868
+ return the_warning;
869
+ }
870
+
871
+ // If there is already a warning on this token, suppress the new one. It is
872
+ // likely that the first warning will be the most meaningful.
873
+
874
+ if (the_token.warning) {
647
875
  warning_list.pop();
876
+ return the_warning;
648
877
  }
878
+ the_token.warning = the_warning;
649
879
  return the_warning;
650
880
  }
651
881
 
@@ -795,6 +1025,7 @@ function jslint(
795
1025
  break;
796
1026
 
797
1027
  // PR-347 - Disable warning "missing_browser".
1028
+ //
798
1029
  // case "missing_browser":
799
1030
  // mm = `/*global*/ requires the Assume a browser option.`;
800
1031
  // break;
@@ -879,6 +1110,7 @@ function jslint(
879
1110
  break;
880
1111
 
881
1112
  // PR-347 - Disable warning "unexpected_directive_a".
1113
+ //
882
1114
  // case "unexpected_directive_a":
883
1115
  // mm = `When using modules, don't use directive '/\u002a${a}'.`;
884
1116
  // break;
@@ -1000,12 +1232,12 @@ function jslint(
1000
1232
  if (option_dict.trace) {
1001
1233
  warning.stack_trace = new Error().stack;
1002
1234
  }
1003
- if (warning.directive_quiet) {
1235
+ if (warning.directive_ignore_line) {
1004
1236
 
1005
1237
  // test_cause:
1006
- // ["0 //jslint-quiet", "semicolon", "directive_quiet", "", 0]
1238
+ // ["0 //jslint-ignore-line", "semicolon", "directive_ignore_line", "", 0]
1007
1239
 
1008
- test_cause("directive_quiet");
1240
+ test_cause("directive_ignore_line");
1009
1241
  return warning;
1010
1242
  }
1011
1243
  warning_list.push(warning);
@@ -1039,7 +1271,7 @@ function jslint(
1039
1271
  mode_json: false, // true if parsing JSON.
1040
1272
  mode_module: false, // true if import or export was used.
1041
1273
  mode_property: false, // true if directive /*property*/ is
1042
- // used.
1274
+ // ... used.
1043
1275
  mode_shebang: false, // true if #! is seen on the first line.
1044
1276
  option_dict,
1045
1277
  property_dict,
@@ -1109,6 +1341,7 @@ function jslint(
1109
1341
  );
1110
1342
 
1111
1343
  // PR-347 - Disable warning "missing_browser".
1344
+ //
1112
1345
  // if (!option_dict.browser) {
1113
1346
  // directive_list.forEach(function (comment) {
1114
1347
  // if (comment.directive === "global") {
@@ -1543,6 +1776,7 @@ async function jslint_cli({
1543
1776
  console_error,
1544
1777
  console_log,
1545
1778
  file,
1779
+ import_meta_url,
1546
1780
  mode_cli,
1547
1781
  mode_noop,
1548
1782
  option,
@@ -1711,11 +1945,26 @@ async function jslint_cli({
1711
1945
  return count;
1712
1946
  }
1713
1947
 
1948
+ // PR-396 - window.jslint
1949
+ // Check import.meta.url for directive to export jslint to window-object.
1950
+ // Useful for ES5-era browser-scripts that rely on window.jslint,
1951
+ // like CodeMirror.
1952
+ //
1953
+ // Example usage:
1954
+ // <script type="module" src="./jslint.mjs?window_jslint=1"></script>
1955
+
1956
+ import_meta_url = import_meta_url || jslint_import_meta_url;
1957
+ if (
1958
+ jslint_rgx_url_search_window_jslint.test(import_meta_url)
1959
+ && (typeof globalThis === "object" && globalThis)
1960
+ ) {
1961
+ globalThis.jslint = jslint;
1962
+ }
1963
+
1714
1964
  // Feature-detect nodejs.
1715
1965
 
1716
1966
  if (!(
1717
- typeof process === "object"
1718
- && process
1967
+ (typeof process === "object" && process)
1719
1968
  && process.versions
1720
1969
  && typeof process.versions.node === "string"
1721
1970
  && !mode_noop
@@ -1741,7 +1990,7 @@ async function jslint_cli({
1741
1990
  ).test(process_argv[1])
1742
1991
  || mode_cli
1743
1992
  )
1744
- && moduleUrl.fileURLToPath(jslint_import_meta_url)
1993
+ && moduleUrl.fileURLToPath(import_meta_url)
1745
1994
  === modulePath.resolve(process_argv[1])
1746
1995
  )
1747
1996
  && !mode_cli
@@ -1887,7 +2136,9 @@ async function jslint_cli({
1887
2136
  option
1888
2137
  });
1889
2138
  if (mode_report) {
1890
- await fsWriteFileWithParents(mode_report, jslint_report(result));
2139
+ result = jslint.jslint_report(result);
2140
+ result = `<body class="JSLINT_ JSLINT_REPORT_">\n${result}</body>\n`;
2141
+ await fsWriteFileWithParents(mode_report, result);
1891
2142
  }
1892
2143
  process_exit(exit_code);
1893
2144
  return exit_code;
@@ -2176,7 +2427,7 @@ function jslint_phase2_lex(state) {
2176
2427
  if (!option_dict.devel && jslint_rgx_todo.test(snippet)) {
2177
2428
 
2178
2429
  // test_cause:
2179
- // ["//todo", "lex_comment", "todo_comment", "(comment)", 1] //jslint-quiet
2430
+ // ["//todo", "lex_comment", "todo_comment", "(comment)", 1] //jslint-ignore-line
2180
2431
 
2181
2432
  warn("todo_comment", the_comment);
2182
2433
  }
@@ -2236,6 +2487,7 @@ function jslint_phase2_lex(state) {
2236
2487
  global_dict[key] = "user-defined";
2237
2488
 
2238
2489
  // PR-347 - Disable warning "unexpected_directive_a".
2490
+ //
2239
2491
  // state.mode_module = the_comment;
2240
2492
 
2241
2493
  break;
@@ -2462,6 +2714,7 @@ function jslint_phase2_lex(state) {
2462
2714
  return char_after("]");
2463
2715
 
2464
2716
  // PR-362 - Relax regexp-warning against using <space>.
2717
+ //
2465
2718
  // case " ":
2466
2719
  //
2467
2720
  // // test_cause:
@@ -2542,6 +2795,7 @@ function jslint_phase2_lex(state) {
2542
2795
  return;
2543
2796
 
2544
2797
  // PR-362 - Relax regexp-warning against using <space>.
2798
+ //
2545
2799
  // case " ":
2546
2800
  //
2547
2801
  // // test_cause:
@@ -3051,9 +3305,10 @@ function jslint_phase2_lex(state) {
3051
3305
  case "getset": // Allow get() and set().
3052
3306
  case "indent2": // Use 2-space indent.
3053
3307
  case "long": // Allow long lines.
3054
- case "name": // Allow weird property names.
3055
3308
  case "node": // Assume Node.js environment.
3309
+ case "nomen": // Allow weird property names.
3056
3310
  case "single": // Allow single-quote strings.
3311
+ case "subscript": // Allow identifier in subscript-notation.
3057
3312
  case "test_cause": // Test jslint's causes.
3058
3313
  case "test_internal_error": // Test jslint's internal-error
3059
3314
  // ... handling-ability.
@@ -3066,6 +3321,16 @@ function jslint_phase2_lex(state) {
3066
3321
  case "white": // Allow messy whitespace.
3067
3322
  option_dict[key] = val;
3068
3323
  break;
3324
+
3325
+ // PR-404 - Alias "evil" to jslint-directive "eval" for backwards-compat.
3326
+
3327
+ case "evil":
3328
+ return option_set_item("eval", val);
3329
+
3330
+ // PR-404 - Alias "nomen" to jslint-directive "name" for backwards-compat.
3331
+
3332
+ case "name":
3333
+ return option_set_item("nomen", val);
3069
3334
  default:
3070
3335
  return false;
3071
3336
  }
@@ -3087,12 +3352,16 @@ console.log(JSON.stringify(Object.keys(window).sort(), undefined, 4));
3087
3352
 
3088
3353
  "AbortController",
3089
3354
  // "Buffer",
3090
- "DOMException",
3355
+ // "Crypto",
3356
+ // "CryptoKey",
3091
3357
  "Event",
3092
3358
  "EventTarget",
3093
3359
  "MessageChannel",
3094
3360
  "MessageEvent",
3095
3361
  "MessagePort",
3362
+ // "Request",
3363
+ // "Response",
3364
+ // "SubtleCrypto",
3096
3365
  "TextDecoder",
3097
3366
  "TextEncoder",
3098
3367
  "URL",
@@ -3106,7 +3375,9 @@ console.log(JSON.stringify(Object.keys(window).sort(), undefined, 4));
3106
3375
  "clearInterval",
3107
3376
  "clearTimeout",
3108
3377
  // "console",
3378
+ // "crypto",
3109
3379
  // "exports",
3380
+ // "fetch",
3110
3381
  // "global",
3111
3382
  // "module",
3112
3383
  "performance",
@@ -3116,7 +3387,6 @@ console.log(JSON.stringify(Object.keys(window).sort(), undefined, 4));
3116
3387
  // "setImmediate",
3117
3388
  "setInterval",
3118
3389
  "setTimeout",
3119
- "structuredClone",
3120
3390
 
3121
3391
  // Web worker only.
3122
3392
  // https://github.com/mdn/content/blob/main/files/en-us/web/api
@@ -3154,10 +3424,12 @@ console.log(JSON.stringify(Object.keys(window).sort(), undefined, 4));
3154
3424
  "location",
3155
3425
  // "name",
3156
3426
  "navigator",
3427
+ "postMessage",
3157
3428
  // "screen",
3158
3429
  "sessionStorage",
3159
3430
  // "setInterval",
3160
3431
  // "setTimeout",
3432
+ "structuredClone",
3161
3433
  "window"
3162
3434
  ], "browser");
3163
3435
  break;
@@ -3219,6 +3491,7 @@ import https from "https";
3219
3491
 
3220
3492
  case "ecma":
3221
3493
  object_assign_from_list(global_dict, [
3494
+ "AggregateError",
3222
3495
  "Array",
3223
3496
  "ArrayBuffer",
3224
3497
  "Atomics",
@@ -3289,7 +3562,7 @@ import moduleHttps from "https";
3289
3562
  let result = "";
3290
3563
  await new Promise(function (resolve) {
3291
3564
  moduleHttps.get((
3292
- "https://raw.githubusercontent.com/nodejs/node/master/doc/api"
3565
+ "https://raw.githubusercontent.com/nodejs/node/v16.x/doc/api"
3293
3566
  + "/globals.md"
3294
3567
  ), function (res) {
3295
3568
  res.on("data", function (chunk) {
@@ -3312,12 +3585,16 @@ import moduleHttps from "https";
3312
3585
  object_assign_from_list(global_dict, [
3313
3586
  "AbortController",
3314
3587
  "Buffer",
3315
- "DOMException",
3588
+ // "Crypto",
3589
+ // "CryptoKey",
3316
3590
  "Event",
3317
3591
  "EventTarget",
3318
3592
  "MessageChannel",
3319
3593
  "MessageEvent",
3320
3594
  "MessagePort",
3595
+ // "Request",
3596
+ // "Response",
3597
+ // "SubtleCrypto",
3321
3598
  "TextDecoder",
3322
3599
  "TextEncoder",
3323
3600
  "URL",
@@ -3331,7 +3608,9 @@ import moduleHttps from "https";
3331
3608
  "clearInterval",
3332
3609
  "clearTimeout",
3333
3610
  "console",
3611
+ // "crypto",
3334
3612
  "exports",
3613
+ // "fetch",
3335
3614
  "global",
3336
3615
  "module",
3337
3616
  "performance",
@@ -3340,8 +3619,7 @@ import moduleHttps from "https";
3340
3619
  "require",
3341
3620
  "setImmediate",
3342
3621
  "setInterval",
3343
- "setTimeout",
3344
- "structuredClone"
3622
+ "setTimeout"
3345
3623
  ], "Node.js");
3346
3624
  break;
3347
3625
  }
@@ -3408,7 +3686,7 @@ import moduleHttps from "https";
3408
3686
  ) {
3409
3687
 
3410
3688
  // test_cause:
3411
- // ["/////////////////////////////////////////////////////////////////////////////////", "read_line", "too_long", "", 1] //jslint-quiet
3689
+ // ["/////////////////////////////////////////////////////////////////////////////////", "read_line", "too_long", "", 1] //jslint-ignore-line
3412
3690
 
3413
3691
  warn_at("too_long", line);
3414
3692
  }
@@ -3426,7 +3704,7 @@ import moduleHttps from "https";
3426
3704
  // Scan each line for following ignore-directives:
3427
3705
  // "/*jslint-disable*/"
3428
3706
  // "/*jslint-enable*/"
3429
- // "//jslint-quiet"
3707
+ // "//jslint-ignore-line"
3430
3708
 
3431
3709
  if (line_source === "/*jslint-disable*/") {
3432
3710
 
@@ -3444,13 +3722,16 @@ import moduleHttps from "https";
3444
3722
  stop_at("unopened_enable", line);
3445
3723
  }
3446
3724
  line_disable = undefined;
3447
- } else if (line_source.endsWith(" //jslint-quiet")) {
3725
+ } else if (
3726
+ line_source.endsWith(" //jslint-ignore-line")
3727
+ || line_source.endsWith(" //jslint-quiet")
3728
+ ) {
3448
3729
 
3449
3730
  // test_cause:
3450
- // ["0 //jslint-quiet", "read_line", "jslint_quiet", "", 0]
3731
+ // ["0 //jslint-ignore-line", "read_line", "jslint_ignore_line", "", 0]
3451
3732
 
3452
- test_cause("jslint_quiet");
3453
- line_list[line].directive_quiet = true;
3733
+ test_cause("jslint_ignore_line");
3734
+ line_list[line].directive_ignore_line = true;
3454
3735
  }
3455
3736
  if (line_disable !== undefined) {
3456
3737
 
@@ -4250,6 +4531,8 @@ function jslint_phase3_parse(state) {
4250
4531
  left.id !== "["
4251
4532
  || (
4252
4533
  name.id !== "concat"
4534
+ && name.id !== "flat"
4535
+ && name.id !== "flatMap"
4253
4536
  && name.id !== "forEach"
4254
4537
  && name.id !== "join"
4255
4538
  && name.id !== "map"
@@ -4309,7 +4592,10 @@ function jslint_phase3_parse(state) {
4309
4592
  let the_subscript = parse_expression(0);
4310
4593
  if (the_subscript.id === "(string)" || the_subscript.id === "`") {
4311
4594
  name = survey(the_subscript);
4312
- if (jslint_rgx_identifier.test(name)) {
4595
+
4596
+ // PR-404 - Add new directive "subscript" to play nice with Google Closure.
4597
+
4598
+ if (!option_dict.subscript && jslint_rgx_identifier.test(name)) {
4313
4599
 
4314
4600
  // test_cause:
4315
4601
  // ["aa[`aa`]", "infix_lbracket", "subscript_a", "aa", 4]
@@ -5038,10 +5324,13 @@ function jslint_phase3_parse(state) {
5038
5324
  functionage.async += 1;
5039
5325
  }
5040
5326
  if (the_await.arity === "statement") {
5041
- the_await.block = parse_expression();
5327
+
5328
+ // PR-405 - Bugfix - fix expression after "await" mis-identified as statement.
5329
+
5330
+ the_await.expression = parse_expression(150);
5042
5331
  semicolon();
5043
5332
  } else {
5044
- the_await.expression = parse_expression();
5333
+ the_await.expression = parse_expression(150);
5045
5334
  }
5046
5335
  return the_await;
5047
5336
  }
@@ -6107,6 +6396,7 @@ function jslint_phase3_parse(state) {
6107
6396
  let names;
6108
6397
 
6109
6398
  // PR-347 - Disable warning "unexpected_directive_a".
6399
+ //
6110
6400
  // if (typeof state.mode_module === "object") {
6111
6401
  //
6112
6402
  // // test_cause:
@@ -6464,12 +6754,16 @@ function jslint_phase3_parse(state) {
6464
6754
  // Restore previous catch-scope after catch-block.
6465
6755
 
6466
6756
  catchage = catch_stack.pop();
6467
- } else {
6468
6757
 
6469
- // test_cause:
6470
- // ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
6758
+ // PR-404 - Relax warning about missing `catch` in `try...finally` statement.
6759
+ //
6760
+ // } else {
6761
+ //
6762
+ // // test_cause:
6763
+ // // ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
6764
+ //
6765
+ // warn("expected_a_before_b", token_nxt, "catch", artifact());
6471
6766
 
6472
- warn("expected_a_before_b", token_nxt, "catch", artifact());
6473
6767
  }
6474
6768
  if (token_nxt.id === "finally") {
6475
6769
  functionage.finally += 1;
@@ -6590,12 +6884,14 @@ function jslint_phase3_parse(state) {
6590
6884
  return stop("expected_identifier_a");
6591
6885
  }
6592
6886
 
6593
- // PR-363 - Bugfix - fix false-warning
6594
- // <uninitialized 'bb'> in code '/*jslint node*/\nlet {aa:bb} = {}; bb();'
6887
+ // PR-363 - Bugfix
6888
+ // Add test against false-warning <uninitialized 'bb'> in code
6889
+ // '/*jslint node*/\nlet {aa:bb} = {}; bb();'.
6890
+ //
6891
+ // token_nxt.label = name;
6892
+ // the_variable.names.push(token_nxt);
6893
+ // enroll(token_nxt, "variable", mode_const);
6595
6894
 
6596
- // token_nxt.label = name;
6597
- // the_variable.names.push(token_nxt);
6598
- // enroll(token_nxt, "variable", mode_const);
6599
6895
  name = token_nxt;
6600
6896
  the_variable.names.push(name);
6601
6897
  survey(name);
@@ -6818,7 +7114,7 @@ function jslint_phase3_parse(state) {
6818
7114
  warn("unregistered_property_a", name);
6819
7115
  }
6820
7116
  } else if (
6821
- !option_dict.name
7117
+ !option_dict.nomen
6822
7118
  && name.identifier
6823
7119
  && jslint_rgx_weird_property.test(id)
6824
7120
  ) {
@@ -7751,6 +8047,11 @@ function jslint_phase4_walk(state) {
7751
8047
  || thing.expression[0].constant === true
7752
8048
  || is_equal(thing.expression[1], thing.expression[2])
7753
8049
  ) {
8050
+
8051
+ // test_cause:
8052
+ // ["let aa=(aa?`${0}`:`${0}`);", "post_t", "unexpected_a", "?", 11]
8053
+ // ["let aa=(aa?`0`:`0`);", "post_t", "unexpected_a", "?", 11]
8054
+
7754
8055
  warn("unexpected_a", thing);
7755
8056
  } else if (is_equal(thing.expression[0], thing.expression[1])) {
7756
8057
 
@@ -8226,9 +8527,6 @@ function jslint_phase4_walk(state) {
8226
8527
  // ["+[]", "walk_statement", "unexpected_expression_a", "+", 1]
8227
8528
  // ["+new aa()", "walk_statement", "unexpected_expression_a", "+", 1]
8228
8529
  // ["0", "walk_statement", "unexpected_expression_a", "0", 1]
8229
- // ["
8230
- // async function aa(){await 0;}
8231
- // ", "walk_statement", "unexpected_expression_a", "0", 27]
8232
8530
  // ["typeof 0", "walk_statement", "unexpected_expression_a", "typeof", 1]
8233
8531
 
8234
8532
  warn("unexpected_expression_a", thing);
@@ -8970,6 +9268,7 @@ function jslint_report({
8970
9268
 
8971
9269
  // This function will create human-readable, html-report
8972
9270
  // for warnings, properties, and functions from jslint-result-object.
9271
+ //
8973
9272
  // Example usage:
8974
9273
  // let result = jslint("console.log('hello world')");
8975
9274
  // let html = jslint_report(result);
@@ -9002,7 +9301,6 @@ function jslint_report({
9002
9301
  );
9003
9302
  }
9004
9303
 
9005
- html += "<div class=\"JSLINT_\" id=\"JSLINT_REPORT_HTML\">\n";
9006
9304
  html += String(`
9007
9305
  <style class="JSLINT_REPORT_STYLE">
9008
9306
  /* jslint utility2:true */
@@ -9151,19 +9449,38 @@ pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
9151
9449
  /7xoEqvL+2E8VOyCTuT/7j269Zy4jUtN+g4="
9152
9450
  ) format("woff2");
9153
9451
  }
9154
- *,
9155
- *:after,
9156
- *:before {
9452
+ .JSLINT_,
9453
+ .JSLINT_ address,
9454
+ .JSLINT_ button,
9455
+ .JSLINT_ cite,
9456
+ .JSLINT_ dd,
9457
+ .JSLINT_ dfn,
9458
+ .JSLINT_ dl,
9459
+ .JSLINT_ dt,
9460
+ .JSLINT_ fieldset,
9461
+ .JSLINT_ fieldset > div,
9462
+ .JSLINT_ input,
9463
+ .JSLINT_ label,
9464
+ .JSLINT_ legend,
9465
+ .JSLINT_ ol,
9466
+ .JSLINT_ samp,
9467
+ .JSLINT_ style,
9468
+ .JSLINT_ textarea,
9469
+ .JSLINT_ ul {
9157
9470
  border: 0;
9158
9471
  box-sizing: border-box;
9159
9472
  margin: 0;
9160
9473
  padding: 0;
9161
9474
  }
9475
+ /* disable text inflation algorithm used on some smartphones and tablets */
9162
9476
  .JSLINT_ {
9163
9477
  -ms-text-size-adjust: none;
9164
9478
  -webkit-text-size-adjust: none;
9165
9479
  text-size-adjust: none;
9166
9480
  }
9481
+ .JSLINT_REPORT_ div {
9482
+ box-sizing: border-box;
9483
+ }
9167
9484
  /*csslint ignore:end*/
9168
9485
 
9169
9486
  /* css - jslint_report - font */
@@ -9197,7 +9514,7 @@ pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
9197
9514
  }
9198
9515
 
9199
9516
  /* css - jslint_report - general */
9200
- body {
9517
+ .JSLINT_ {
9201
9518
  background: antiquewhite;
9202
9519
  }
9203
9520
  .JSLINT_ fieldset {
@@ -9534,7 +9851,6 @@ body {
9534
9851
  });
9535
9852
  html += "</div>\n";
9536
9853
  html += "</fieldset>\n";
9537
- html += "</div>\n";
9538
9854
  return html;
9539
9855
  }
9540
9856
 
@@ -9545,6 +9861,7 @@ async function jstestDescribe(description, testFunction) {
9545
9861
 
9546
9862
  let message;
9547
9863
  let result;
9864
+ let timerTimeout;
9548
9865
 
9549
9866
  // Init jstestTimeStart.
9550
9867
 
@@ -9560,7 +9877,9 @@ async function jstestDescribe(description, testFunction) {
9560
9877
 
9561
9878
  // Wait for jstestItList to resolve.
9562
9879
 
9880
+ timerTimeout = setTimeout(noop, 0x7fffffff);
9563
9881
  result = await Promise.all(jstestItList);
9882
+ clearTimeout(timerTimeout);
9564
9883
 
9565
9884
  // Print test results.
9566
9885
 
@@ -9610,14 +9929,14 @@ function jstestIt(description, testFunction, mode) {
9610
9929
  }));
9611
9930
  }
9612
9931
 
9613
- function jstestOnExit(exitCode, processExit, countFailed) {
9932
+ function jstestOnExit(exitCode, mode) {
9614
9933
 
9615
9934
  // This function will on process-exit, print test-report
9616
9935
  // and exit with non-zero exit-code if any test failed.
9617
9936
 
9618
9937
  let message = (
9619
9938
  (
9620
- (jstestCountFailed || countFailed)
9939
+ (jstestCountFailed || mode === "testsFailed")
9621
9940
  ? "\n\u001b[31m"
9622
9941
  : "\n\u001b[32m"
9623
9942
  )
@@ -9625,11 +9944,10 @@ function jstestOnExit(exitCode, processExit, countFailed) {
9625
9944
  + " tests failed - " + jstestCountFailed + "\n"
9626
9945
  + "\u001b[39m"
9627
9946
  );
9628
- if (!processExit) {
9947
+ if (mode !== "testsFailed") {
9629
9948
  console.error(message);
9630
- processExit = process.exit;
9631
9949
  }
9632
- processExit(exitCode || jstestCountFailed);
9950
+ process.exitCode = exitCode || jstestCountFailed;
9633
9951
  return message;
9634
9952
  }
9635
9953
 
@@ -9927,7 +10245,7 @@ function v8CoverageListMerge(processCovs) {
9927
10245
  let resultTree;
9928
10246
  let rightChildren;
9929
10247
 
9930
- // TODO(perf): Binary search (check overhead) //jslint-quiet
10248
+ // TODO(perf): Binary search (check overhead) //jslint-ignore-line
9931
10249
 
9932
10250
  while (ii < tree.children.length) {
9933
10251
  child = tree.children[ii];
@@ -10005,7 +10323,7 @@ function v8CoverageListMerge(processCovs) {
10005
10323
 
10006
10324
  // This function will normalize-and-sort <funcCov>.ranges.
10007
10325
  // Sorts the ranges (pre-order sort).
10008
- // TODO: Tree-based normalization of the ranges. //jslint-quiet
10326
+ // TODO: Tree-based normalization of the ranges. //jslint-ignore-line
10009
10327
  // @param funcCov Function coverage to normalize.
10010
10328
 
10011
10329
  funcCov.ranges = treeToRanges(treeFromSortedRanges(
@@ -10351,11 +10669,11 @@ async function v8CoverageReportCreate({
10351
10669
  // 3. Create html-coverage-reports in <coverageDir>.
10352
10670
 
10353
10671
  let cwd;
10672
+ let excludeList = [];
10354
10673
  let exitCode = 0;
10355
10674
  let fileDict;
10356
- let fileExcludeList = [];
10357
- let fileIncludeList = [];
10358
- let fileIncludeNodeModules;
10675
+ let includeList = [];
10676
+ let modeIncludeNodeModules;
10359
10677
  let processArgElem;
10360
10678
  let promiseList = [];
10361
10679
  let v8CoverageObj;
@@ -10380,9 +10698,19 @@ async function v8CoverageReportCreate({
10380
10698
  <style>
10381
10699
  /* jslint utility2:true */
10382
10700
  /*csslint ignore:start*/
10383
- * {
10384
- box-sizing: border-box;
10385
- font-family: consolas, menlo, monospace;
10701
+ .coverage,
10702
+ .coverage a,
10703
+ .coverage div,
10704
+ .coverage pre,
10705
+ .coverage span,
10706
+ .coverage table,
10707
+ .coverage tbody,
10708
+ .coverage td,
10709
+ .coverage th,
10710
+ .coverage thead,
10711
+ .coverage tr {
10712
+ box-sizing: border-box;
10713
+ font-family: monospace;
10386
10714
  }
10387
10715
  /*csslint ignore:end*/
10388
10716
 
@@ -10528,6 +10856,7 @@ body {
10528
10856
  }
10529
10857
  txtBorder = (
10530
10858
  "+" + "-".repeat(padPathname + 2) + "+"
10859
+ + "-".repeat(padLines + 2) + "+"
10531
10860
  + "-".repeat(padLines + 2) + "+\n"
10532
10861
  );
10533
10862
  txt = "";
@@ -10535,7 +10864,8 @@ body {
10535
10864
  txt += txtBorder;
10536
10865
  txt += (
10537
10866
  "| " + String("Files covered").padEnd(padPathname, " ") + " | "
10538
- + String("Lines").padStart(padLines, " ") + " |\n"
10867
+ + String("Lines").padStart(padLines, " ") + " | "
10868
+ + String("Remaining").padStart(padLines, " ") + " |\n"
10539
10869
  );
10540
10870
  txt += txtBorder;
10541
10871
  fileList.forEach(function ({
@@ -10615,7 +10945,8 @@ body {
10615
10945
  + String("./" + pathname).padEnd(padPathname, " ") + " | "
10616
10946
  + String(
10617
10947
  modeCoverageIgnoreFile + " " + coveragePct + " %"
10618
- ).padStart(padLines, " ") + " |\n"
10948
+ ).padStart(padLines, " ") + " | "
10949
+ + " ".repeat(padLines) + " |\n"
10619
10950
  );
10620
10951
  txt += (
10621
10952
  "| " + "*".repeat(
@@ -10623,6 +10954,9 @@ body {
10623
10954
  ).padEnd(padPathname, "_") + " | "
10624
10955
  + String(
10625
10956
  linesCovered + " / " + linesTotal
10957
+ ).padStart(padLines, " ") + " | "
10958
+ + String(
10959
+ (linesTotal - linesCovered) + " / " + linesTotal
10626
10960
  ).padStart(padLines, " ") + " |\n"
10627
10961
  );
10628
10962
  txt += txtBorder;
@@ -10786,21 +11120,6 @@ ${String(count || "-0").padStart(7, " ")}
10786
11120
  ), txt));
10787
11121
  }
10788
11122
 
10789
- function pathnameRelativeCwd(pathname) {
10790
-
10791
- // This function will if <pathname> is inside <cwd>,
10792
- // return it relative to <cwd>, else empty-string.
10793
-
10794
- pathname = modulePath.resolve(pathname).replace((
10795
- /\\/g
10796
- ), "/");
10797
- if (!pathname.startsWith(cwd)) {
10798
- return;
10799
- }
10800
- pathname = pathname.slice(cwd.length);
10801
- return pathname;
10802
- }
10803
-
10804
11123
  /*
10805
11124
  function sentinel() {}
10806
11125
  */
@@ -10832,28 +11151,26 @@ function sentinel() {}
10832
11151
  processArgElem[1] = processArgElem.slice(1).join("=");
10833
11152
  switch (processArgElem[0]) {
10834
11153
 
10835
- // PR-371 - add cli-option `--exclude=aa,bb`
11154
+ // PR-371 - Add cli-option `--exclude=...`.
10836
11155
 
10837
11156
  case "--exclude":
10838
- fileExcludeList = fileExcludeList.concat(
10839
- processArgElem[1].split(",")
10840
- );
11157
+ excludeList.push(processArgElem[1]);
10841
11158
  break;
10842
11159
 
10843
- // PR-371 - add cli-option `--exclude-node-modules=false`
11160
+ // PR-371 - Add cli-option `--include=...`
10844
11161
 
10845
- case "--exclude-node-modules":
10846
- fileIncludeNodeModules = (
10847
- /0|false|null|undefined/
10848
- ).test(processArgElem[1]);
11162
+ case "--include":
11163
+ includeList.push(processArgElem[1]);
10849
11164
  break;
10850
11165
 
10851
- // PR-371 - add cli-option `--include=aa,bb`
11166
+ // PR-400
11167
+ // Disable default-coverage of directory `node_modules`,
11168
+ // but allow override with cli-option `--include-node-modules=1`.
10852
11169
 
10853
- case "--include":
10854
- fileIncludeList = fileIncludeList.concat(
10855
- processArgElem[1].split(",")
10856
- );
11170
+ case "--include-node-modules":
11171
+ modeIncludeNodeModules = !(
11172
+ /0|false|null|undefined/
11173
+ ).test(processArgElem[1]);
10857
11174
  break;
10858
11175
  }
10859
11176
  }
@@ -10907,9 +11224,11 @@ function sentinel() {}
10907
11224
  ).test(file);
10908
11225
  });
10909
11226
  v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
10910
- let data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
11227
+ let data;
11228
+ let pathnameDict = Object.create(null);
11229
+ data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
10911
11230
  data = JSON.parse(data);
10912
- data.result = data.result.filter(function (scriptCov) {
11231
+ data.result.forEach(function (scriptCov) {
10913
11232
  let pathname = scriptCov.url;
10914
11233
 
10915
11234
  // Filter out internal coverages.
@@ -10920,38 +11239,38 @@ function sentinel() {}
10920
11239
 
10921
11240
  // Normalize pathname.
10922
11241
 
10923
- pathname = pathnameRelativeCwd(moduleUrl.fileURLToPath(pathname));
10924
- if (
11242
+ pathname = moduleUrl.fileURLToPath(pathname);
11243
+ pathname = modulePath.resolve(pathname).replace((
11244
+ /\\/g
11245
+ ), "/");
10925
11246
 
10926
11247
  // Filter files outside of cwd.
10927
11248
 
10928
- !pathname
10929
- || pathname.startsWith("[")
11249
+ if (pathname.indexOf("[") >= 0 || !pathname.startsWith(cwd)) {
11250
+ return;
11251
+ }
10930
11252
 
10931
- // PR-371 - Filter directory node_modules.
11253
+ // Normalize pathname relative to cwd.
10932
11254
 
10933
- || (
10934
- !fileIncludeNodeModules
10935
- && (
10936
- /(?:^|\/)node_modules\//m
10937
- ).test(pathname)
10938
- )
11255
+ pathname = pathname.slice(cwd.length);
11256
+ scriptCov.url = pathname;
11257
+ pathnameDict[pathname] = scriptCov;
11258
+ });
10939
11259
 
10940
- // PR-371 - Filter fileExcludeList.
11260
+ // PR-400 - Filter directory `node_modules`.
10941
11261
 
10942
- || fileExcludeList.indexOf(pathname) >= 0
11262
+ if (!modeIncludeNodeModules) {
11263
+ excludeList.push("node_modules/");
11264
+ }
10943
11265
 
10944
- // PR-371 - Filter fileIncludeList.
11266
+ // PR-400 - Filter files by glob-patterns in excludeList, includeList.
10945
11267
 
10946
- || (
10947
- fileIncludeList.length > 0
10948
- && fileIncludeList.indexOf(pathname) === -1
10949
- )
10950
- ) {
10951
- return;
10952
- }
10953
- scriptCov.url = pathname;
10954
- return true;
11268
+ data.result = globExclude({
11269
+ excludeList,
11270
+ includeList,
11271
+ pathnameList: Object.keys(pathnameDict)
11272
+ }).pathnameList.map(function (pathname) {
11273
+ return pathnameDict[pathname];
10955
11274
  });
10956
11275
  return data;
10957
11276
  }));
@@ -10960,7 +11279,7 @@ function sentinel() {}
10960
11279
 
10961
11280
  v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
10962
11281
 
10963
- // debug v8CoverageObj.
11282
+ // Debug v8CoverageObj.
10964
11283
 
10965
11284
  await fsWriteFileWithParents(
10966
11285
  coverageDir + "v8_coverage_merged.json",
@@ -11100,6 +11419,7 @@ jslint_export = Object.freeze(Object.assign(jslint, {
11100
11419
  assertOrThrow,
11101
11420
  debugInline,
11102
11421
  fsWriteFileWithParents,
11422
+ globExclude,
11103
11423
  htmlEscape,
11104
11424
  jslint,
11105
11425
  jslint_apidoc,