1. 1// #!/usr/bin/env node
2. 1// JSLint
3. 1// Original Author: Douglas Crockford (https://www.jslint.com).
4. 1
5. 1// This is free and unencumbered software released into the public domain.
6. 1
7. 1// Anyone is free to copy, modify, publish, use, compile, sell, or
8. 1// distribute this software, either in source code form or as a compiled
9. 1// binary, for any purpose, commercial or non-commercial, and by any
10. 1// means.
11. 1
12. 1// In jurisdictions that recognize copyright laws, the author or authors
13. 1// of this software dedicate any and all copyright interest in the
14. 1// software to the public domain. We make this dedication for the benefit
15. 1// of the public at large and to the detriment of our heirs and
16. 1// successors. We intend this dedication to be an overt act of
17. 1// relinquishment in perpetuity of all present and future rights to this
18. 1// software under copyright law.
19. 1
20. 1// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21. 1// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22. 1// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
23. 1// IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
24. 1// OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
25. 1// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
26. 1// OTHER DEALINGS IN THE SOFTWARE.
27. 1
28. 1// For more information, please refer to <https://unlicense.org/>
29. 1
30. 1
31. 1// jslint(source, option_dict, global_list) is a function that takes 3
32. 1// arguments. The second two arguments are optional.
33. 1
34. 1// source A text to analyze.
35. 1// option_dict An object whose keys correspond to option names.
36. 1// global_list An array of strings containing global variables that
37. 1// the file is allowed readonly access.
38. 1
39. 1// jslint returns an object containing its results. The object contains a lot
40. 1// of valuable information. It can be used to generate reports. The object
41. 1// contains:
42. 1
43. 1// directives: an array of directive comment tokens.
44. 1// edition: the version of JSLint that did the analysis.
45. 1// exports: the names exported from the module.
46. 1// froms: an array of strings representing each of the imports.
47. 1// functions: an array of objects that represent all functions
48. 1// declared in the file.
49. 1// global: an object representing the global object. Its .context property
50. 1// is an object containing a property for each global variable.
51. 1// id: "(JSLint)"
52. 1// json: true if the file is a JSON text.
53. 1// lines: an array of strings, the source.
54. 1// module: true if an import or export statement was used.
55. 1// ok: true if no warnings were generated. This is what you want.
56. 1// option: the option argument.
57. 1// property: a property object.
58. 1// stop: true if JSLint was unable to finish. You don't want this.
59. 1// tokens: an array of objects representing the tokens in the file.
60. 1// tree: the token objects arranged in a tree.
61. 1// warnings: an array of warning objects. A warning object can contain:
62. 1// name: "JSLintError"
63. 1// column: A column number in the file.
64. 1// line: A line number in the file.
65. 1// code: A warning code string.
66. 1// message: The warning message string.
67. 1// a: Exhibit A.
68. 1// b: Exhibit B.
69. 1// c: Exhibit C.
70. 1// d: Exhibit D.
71. 1
72. 1// jslint works in several phases. In any of these phases, errors might be
73. 1// found. Sometimes JSLint is able to recover from an error and continue
74. 1// parsing. In some cases, it cannot and will stop early. If that should happen,
75. 1// repair your code and try again.
76. 1
77. 1// Phases:
78. 1
79. 1// PHASE 1. Split <source> by newlines into <line_list>.
80. 1// PHASE 2. Lex <line_list> into <token_list>.
81. 1// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
82. 1// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
83. 1// recursive traversal. Each node may be processed on the way down
84. 1// (preaction) and on the way up (postaction).
85. 1// PHASE 5. Check whitespace between tokens in <token_list>.
86. 1
87. 1// jslint can also examine JSON text. It decides that a file is JSON text if
88. 1// the first token is "[" or "{". Processing of JSON text is much simpler than
89. 1// the processing of JavaScript programs. Only the first three phases are
90. 1// required.
91. 1
92. 1// WARNING: JSLint will hurt your feelings.
93. 1
94. 1/*jslint beta, node*/
95. 1
96. 1/*property
97. 1 NODE_V8_COVERAGE,
98. 1 char, consoleError, coverageDir,
99. 1 fileList,
100. 1 holeList,
101. 1 isHole,
102. 1 lineList, linesCovered, linesTotal,
103. 1 modeCoverageIgnoreFile, modeIndex,
104. 1 npm_config_mode_coverage,
105. 1 v8CoverageReportCreate
106. 1
107. 1 children, clear, count,
108. 1 delta,
109. 1 end, endOffset, entries,
110. 1 functionName,
111. 1 get,
112. 1 isBlockCoverage,
113. 1 parentIi,
114. 1 ranges, result,
115. 1 scriptId, set, splice, start, startOffset,
116. 1 unshift,
117. 1 v8CoverageListMerge,
118. 1
119. 1 assertErrorThrownAsync, assertJsonEqual,
120. 1 jstestDescribe, jstestIt, jstestOnExit,
121. 1 processEnv,
122. 1
123. 1 floor,
124. 1 on,
125. 1 padEnd, platform,
126. 1 rename, reverse, round,
127. 1 sep, spawn, stdio,
128. 1
129. 1 JSLINT_BETA, a, all, argv, arity, artifact, assertOrThrow, assign, async,
130. 1 b, beta, bitwise, block, body, browser, c, calls, catch, catch_list,
131. 1 catch_stack, causes, cjs_module, cjs_require, closer, closure, code, column,
132. 1 concat, console_error, console_log, constant, context, convert, create, cwd,
133. 1 d, dead, debugInline, default, devel, directive, directive_list,
134. 1 directive_quiet, directives, dirname, disrupt, dot, edition, elem_list,
135. 1 ellipsis, else, endsWith, env, error, eval, every, example_list, exec,
136. 1 execArgv, exit, export_dict, exports, expression, extra, file,
137. 1 fileURLToPath, filter, finally, flag, for, forEach, formatted_message, free,
138. 1 freeze, from, froms, fsRmRecursive, fsWriteFileWithParents, fud,
139. 1 function_list, function_stack, functions, getset, github_repo, global,
140. 1 global_dict, global_list, htmlEscape, id, identifier, import, import_list,
141. 1 inc, indent2, index, indexOf, init, initial, isArray, isNaN, is_equal,
142. 1 is_weird, join, jslint, jslint_apidoc, jslint_assert, jslint_charset_ascii,
143. 1 jslint_cli, jslint_edition, jslint_phase1_split, jslint_phase2_lex,
144. 1 jslint_phase3_parse, jslint_phase4_walk, jslint_phase5_whitage,
145. 1 jslint_report, json, keys, label, lbp, led, length, level, line, line_list,
146. 1 line_offset, line_source, lines, live, log, long, loop, m, main, map,
147. 1 margin, match, max, message, meta, min, mkdir, mode_cli, mode_json,
148. 1 mode_module, mode_noop, mode_property, mode_shebang, mode_stop, module,
149. 1 moduleFsInit, module_list, moduleName, name, names, node, noop, now, nr,
150. 1 nud, ok, open, opening, option, option_dict, order, package_name, padStart,
151. 1 parameters, parent, parse, pathname, pop, processArgv, process_exit,
152. 1 process_version, promises, property, property_dict, push, quote, readFile,
153. 1 readdir, readonly, recursive, reduce, repeat, replace, resolve, rm, rmdir,
154. 1 role, search, shebang, shift, signature, single, slice, some, sort, source,
155. 1 split, stack, stack_trace, startsWith, statement, statement_prv, stop,
156. 1 stop_at, stringify, switch, syntax_dict, tenure, test, test_cause,
157. 1 test_internal_error, this, thru, toString, token, token_global, token_list,
158. 1 token_nxt, token_tree, tokens, trace, tree, trim, trimEnd, trimRight, try,
159. 1 type, unlink, unordered, url, used, value, variable, version, versions,
160. 1 warn, warn_at, warning, warning_list, warnings, white, wrapped, writeFile
161. 1*/
162. 1
163. 1// init debugInline
164. 1let debugInline = (function () {
165. 3 let consoleError = function () {
166. 3 return;
167. 3 };
168. 1 return function (...argv) {
169. 1
170. 1// This function will both print <argv> to stderr and return <argv>[0].
171. 1
172. 1 consoleError("\n\ndebugInline");
173. 1 consoleError(...argv);
174. 1 consoleError("\n");
175. 1 consoleError = console.error;
176. 1 return argv[0];
177. 1 };
178. 1}());
179. 1let jslint_charset_ascii = (
180. 1 "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007"
181. 1 + "\b\t\n\u000b\f\r\u000e\u000f"
182. 1 + "\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017"
183. 1 + "\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f"
184. 1 + " !\"#$%&'()*+,-./0123456789:;<=>?"
185. 1 + "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
186. 1 + "`abcdefghijklmnopqrstuvwxyz{|}~\u007f"
187. 1);
188. 1let jslint_edition = "v2021.10.1-beta";
189. 1let jslint_export; // The jslint object to be exported.
190. 1let jslint_fudge = 1; // Fudge starting line and starting
191. 1 // ... column to 1.
192. 1let jslint_import_meta_url = ""; // import.meta.url used by cli.
193. 1let jstestCountFailed = 0;
194. 1let jstestCountTotal = 0;
195. 1let jstestItCount = 0;
196. 1let jstestItList = [];
197. 1let jstestTimeStart;
198. 1let moduleChildProcess;
199. 1let moduleFs;
200. 1let moduleFsInitResolveList;
201. 1let modulePath;
202. 1let moduleUrl;
203. 1
204. 6async function assertErrorThrownAsync(asyncFunc, regexp) {
205. 6
206. 6// This function will assert <asyncFunc> throws an error.
207. 6
208. 6 let err;
209. 6 try {
210. 1 await asyncFunc();
211. 5 } catch (errCaught) {
212. 5 err = errCaught;
213. 5 }
214. 6 assertOrThrow(err, "no error thrown");
215. 6 assertOrThrow(
216. 1 regexp === undefined || new RegExp(regexp).test(err.message),
217. 6 err
218. 6 );
219. 6}
220. 1
221. 90function assertJsonEqual(aa, bb) {
222. 90
223. 90// This function will assert JSON.stringify(<aa>) === JSON.stringify(<bb>).
224. 90
225. 90 aa = JSON.stringify(objectDeepCopyWithKeysSorted(aa));
226. 90 bb = JSON.stringify(objectDeepCopyWithKeysSorted(bb));
227. 1 if (aa !== bb) {
228. 1 throw new Error(
229. 1 JSON.stringify(aa) + " !== " + JSON.stringify(bb)
230. 1 );
231. 1 }
232. 90}
233. 1
234. 1738function assertOrThrow(condition, message) {
235. 1738
236. 1738// This function will throw <message> if <condition> is falsy.
237. 1738
238. 4 if (!condition) {
239. 4 throw (
240. 4 (!message || typeof message === "string")
241. 4 ? new Error(String(message).slice(0, 2048))
242. 4 : message
243. 4 );
244. 4 }
245. 1738}
246. 1
247. 88031function empty() {
248. 88031
249. 88031// The empty function produces a new empty object that inherits nothing. This is
250. 88031// much better than '{}' because confusions around accidental method names like
251. 88031// 'constructor' are completely avoided.
252. 88031
253. 88031 return Object.create(null);
254. 88031}
255. 1
256. 3async function fsRmRecursive(path, option_dict) {
257. 3
258. 3// This function will 'rm -r' <path>.
259. 3
260. 3 await moduleFsInit();
261. 3 console.error("rm -r path " + path);
262. 3 if (((
263. 1 option_dict && option_dict.process_version
264. 2 ) || process.version) < "v14") {
265. 1
266. 1// Legacy rmdir for nodejs v12
267. 1
268. 1 await Promise.all([
269. 1 moduleFs.promises.unlink(path).catch(noop),
270. 1 moduleFs.promises.rmdir(path, {
271. 1 recursive: true
272. 1 }).catch(noop)
273. 1 ]);
274. 1 return;
275. 2 }
276. 2 await moduleFs.promises.rm(path, {
277. 2 recursive: true
278. 2 }).catch(noop);
279. 2}
280. 1
281. 46async function fsWriteFileWithParents(pathname, data) {
282. 46
283. 46// This function will write <data> to <pathname> and lazy-mkdirp if necessary.
284. 46
285. 46 await moduleFsInit();
286. 46
287. 46// Try writing to pathname.
288. 46
289. 46 try {
290. 36 await moduleFs.promises.writeFile(pathname, data);
291. 36 } catch (ignore) {
292. 10
293. 10// Lazy mkdirp.
294. 10
295. 10 await moduleFs.promises.mkdir(modulePath.dirname(pathname), {
296. 10 recursive: true
297. 10 });
298. 10
299. 10// Retry writing to pathname.
300. 10
301. 10 await moduleFs.promises.writeFile(pathname, data);
302. 10 }
303. 46 console.error("wrote file " + pathname);
304. 46}
305. 1
306. 13490function htmlEscape(str) {
307. 13490
308. 13490// This function will make <str> html-safe by escaping & < >.
309. 13490
310. 13490 return String(str).replace((
311. 13490 /&/g
312. 13490 ), "&").replace((
313. 13490 /</g
314. 13490 ), "<").replace((
315. 13490 />/g
316. 13490 ), ">");
317. 13490}
318. 1
319. 628function jslint(
320. 628 source = "", // A text to analyze.
321. 628 option_dict = empty(), // An object whose keys correspond to option
322. 628 // ... names.
323. 628 global_list = [] // An array of strings containing global
324. 628 // ... variables that the file is allowed
325. 628 // ... readonly access.
326. 628) {
327. 628
328. 628// The jslint function itself.
329. 628
330. 628 let catch_list = []; // The array containing all catch-blocks.
331. 628 let catch_stack = [ // The stack of catch-blocks.
332. 628 {
333. 628 context: empty()
334. 628 }
335. 628 ];
336. 628 let cause_dict = empty(); // The object of test-causes.
337. 628 let directive_list = []; // The directive comments.
338. 628 let export_dict = empty(); // The exported names and values.
339. 628 let function_list = []; // The array containing all functions.
340. 628 let function_stack = []; // The stack of functions.
341. 628 let global_dict = empty(); // The object containing the global
342. 628 // ... declarations.
343. 628 let import_list = []; // The array collecting all import-from strings.
344. 628 let line_list = String( // The array containing source lines.
345. 628 "\n" + source
346. 628 ).split(
347. 628 // rx_crlf
348. 628 /\n|\r\n?/
349. 88788 ).map(function (line_source) {
350. 88788 return {
351. 88788 line_source
352. 88788 };
353. 88788 });
354. 628 let mode_stop = false; // true if JSLint cannot finish.
355. 628 let property_dict = empty(); // The object containing the tallied
356. 628 // ... property names.
357. 628 let state = empty(); // jslint state-object to be passed between
358. 628 // jslint functions.
359. 628 let syntax_dict = empty(); // The object containing the parser.
360. 628 let tenure = empty(); // The predefined property registry.
361. 628 let token_global = { // The global object; the outermost context.
362. 628 async: 0,
363. 628 body: true,
364. 628 context: empty(),
365. 628 finally: 0,
366. 628 from: 0,
367. 628 id: "(global)",
368. 628 level: 0,
369. 628 line: jslint_fudge,
370. 628 live: [],
371. 628 loop: 0,
372. 628 switch: 0,
373. 628 thru: 0,
374. 628 try: 0
375. 628 };
376. 628 let token_list = []; // The array of tokens.
377. 628 let warning_list = []; // The array collecting all generated warnings.
378. 628
379. 628// Error reportage functions:
380. 628
381. 7296 function artifact(the_token) {
382. 7296
383. 7296// Return a string representing an artifact.
384. 7296
385. 252 the_token = the_token || state.token_nxt;
386. 7296 return (
387. 4878 (the_token.id === "(string)" || the_token.id === "(number)")
388. 2549 ? String(the_token.value)
389. 4747 : the_token.id
390. 7296 );
391. 7296 }
392. 628
393. 30811 function is_equal(aa, bb) {
394. 30811 let aa_value;
395. 30811 let bb_value;
396. 30811
397. 30811// test_cause:
398. 30811// ["0&&0", "is_equal", "", "", 0]
399. 30811
400. 30811 test_cause("");
401. 30811
402. 30811// Probably deadcode.
403. 30811// if (aa === bb) {
404. 30811// return true;
405. 30811// }
406. 30811
407. 30811 jslint_assert(!(aa === bb), `Expected !(aa === bb).`);
408. 9 if (Array.isArray(aa)) {
409. 9 return (
410. 9 Array.isArray(bb)
411. 9 && aa.length === bb.length
412. 9 && aa.every(function (value, index) {
413. 9
414. 9// test_cause:
415. 9// ["`${0}`&&`${0}`", "is_equal", "recurse_isArray", "", 0]
416. 9
417. 9 test_cause("recurse_isArray");
418. 9 return is_equal(value, bb[index]);
419. 9 })
420. 9 );
421. 30802 }
422. 30802
423. 30802// Probably deadcode.
424. 30802// if (Array.isArray(bb)) {
425. 30802// return false;
426. 30802// }
427. 30802
428. 30802 jslint_assert(!Array.isArray(bb), `Expected !Array.isArray(bb).`);
429. 30802 if (aa.id === "(number)" && bb.id === "(number)") {
430. 67 return aa.value === bb.value;
431. 30735 }
432. 30735 if (aa.id === "(string)") {
433. 22409 aa_value = aa.value;
434. 22409 } else if (aa.id === "`" && aa.constant) {
435. 8326 aa_value = aa.value[0];
436. 30735 }
437. 30735 if (bb.id === "(string)") {
438. 24879 bb_value = bb.value;
439. 24879 } else if (bb.id === "`" && bb.constant) {
440. 5856 bb_value = bb.value[0];
441. 30735 }
442. 30735 if (typeof aa_value === "string") {
443. 22409 return aa_value === bb_value;
444. 22409 }
445. 8326 if (is_weird(aa) || is_weird(bb)) {
446. 66
447. 66// test_cause:
448. 66// ["aa(/./)||{}", "is_equal", "false", "", 0]
449. 66
450. 66 test_cause("false");
451. 66 return false;
452. 8260 }
453. 8260 if (aa.arity === bb.arity && aa.id === bb.id) {
454. 2102 if (aa.id === ".") {
455. 2102
456. 2102// test_cause:
457. 2102// ["aa.bb&&aa.bb", "is_equal", "recurse_arity_id", "", 0]
458. 2102
459. 2102 test_cause("recurse_arity_id");
460. 2102 return (
461. 2102 is_equal(aa.expression, bb.expression)
462. 2102 && is_equal(aa.name, bb.name)
463. 2102 );
464. 2102 }
465. 2102 if (aa.arity === "unary") {
466. 2102
467. 2102// test_cause:
468. 2102// ["+0&&+0", "is_equal", "recurse_unary", "", 0]
469. 2102
470. 2102 test_cause("recurse_unary");
471. 2102 return is_equal(aa.expression, bb.expression);
472. 2102 }
473. 2102 if (aa.arity === "binary") {
474. 2102
475. 2102// test_cause:
476. 2102// ["aa[0]&&aa[0]", "is_equal", "recurse_binary", "", 0]
477. 2102
478. 2102 test_cause("recurse_binary");
479. 2102 return (
480. 2102 aa.id !== "("
481. 2102 && is_equal(aa.expression[0], bb.expression[0])
482. 2102 && is_equal(aa.expression[1], bb.expression[1])
483. 2102 );
484. 2102 }
485. 2102 if (aa.arity === "ternary") {
486. 2102
487. 2102// test_cause:
488. 2102// ["aa=(``?``:``)&&(``?``:``)", "is_equal", "recurse_ternary", "", 0]
489. 2102
490. 2102 test_cause("recurse_ternary");
491. 2102 return (
492. 2102 is_equal(aa.expression[0], bb.expression[0])
493. 2102 && is_equal(aa.expression[1], bb.expression[1])
494. 2102 && is_equal(aa.expression[2], bb.expression[2])
495. 2102 );
496. 2102 }
497. 2102
498. 2102// Probably deadcode.
499. 2102// if (aa.arity === "function" || aa.arity === "regexp") {
500. 2102// return false;
501. 2102// }
502. 2102
503. 2102 jslint_assert(
504. 2102 !(aa.arity === "function" || aa.arity === "regexp"),
505. 2102 `Expected !(aa.arity === "function" || aa.arity === "regexp").`
506. 2102 );
507. 2102
508. 2102// test_cause:
509. 2102// ["undefined&&undefined", "is_equal", "true", "", 0]
510. 2102
511. 2102 test_cause("true");
512. 2102 return true;
513. 6158 }
514. 6158
515. 6158// test_cause:
516. 6158// ["null&&undefined", "is_equal", "false", "", 0]
517. 6158
518. 6158 test_cause("false");
519. 6158 return false;
520. 6158 }
521. 628
522. 28222 function is_weird(thing) {
523. 28222 switch (thing.id) {
524. 36 case "(regexp)":
525. 36 return true;
526. 1 case "=>":
527. 1 return true;
528. 536 case "[":
529. 536 return thing.arity === "unary";
530. 14 case "function":
531. 14 return true;
532. 7 case "{":
533. 7 return true;
534. 27628 default:
535. 27628 return false;
536. 28222 }
537. 28222 }
538. 628
539. 111 function stop(code, the_token, a, b, c, d) {
540. 111
541. 111// Similar to warn and stop_at. If the token already had a warning, that
542. 111// warning will be replaced with this new one. It is likely that the stopping
543. 111// warning will be the more meaningful.
544. 111
545. 38 the_token = the_token || state.token_nxt;
546. 111 delete the_token.warning;
547. 111 throw warn(code, the_token, a, b, c, d);
548. 111 }
549. 628
550. 28 function stop_at(code, line, column, a, b, c, d) {
551. 28
552. 28// Same as warn_at, except that it stops the analysis.
553. 28
554. 28 throw warn_at(code, line, column, a, b, c, d);
555. 28 }
556. 628
557. 316290 function test_cause(code, aa, column) {
558. 316290
559. 316290// This function will instrument <cause> to <cause_dict> for test-purposes.
560. 316290
561. 4726 if (option_dict.test_cause) {
562. 4726 cause_dict[JSON.stringify([
563. 4726 String(new Error().stack).replace((
564. 4726 /^ at (?:file|stop|stop_at|test_cause|warn|warn_at)\b.*?\n/gm
565. 4726 ), "").match(
566. 4726 /\n at ((?:Object\.\w+?_)?\w+?) /
567. 4726 )[1].replace((
568. 4726 /^Object\./
569. 4726 ), ""),
570. 4726 code,
571. 4726 String(
572. 4726 (aa === undefined || aa === token_global)
573. 4726 ? ""
574. 4726 : aa
575. 4726 ),
576. 4726 column || 0
577. 4726 ])] = true;
578. 4726 }
579. 316290 }
580. 628
581. 1063 function warn(code, the_token, a, b, c, d) {
582. 1063
583. 1063// Same as warn_at, except the warning will be associated with a specific token.
584. 1063// If there is already a warning on this token, suppress the new one. It is
585. 1063// likely that the first warning will be the most meaningful.
586. 1063
587. 1063 let the_warning;
588. 18 the_token = the_token || state.token_nxt;
589. 1063 the_warning = warn_at(
590. 1063 code,
591. 1063 the_token.line,
592. 373 (the_token.from || 0) + jslint_fudge,
593. 814 a || artifact(the_token),
594. 1063 b,
595. 1063 c,
596. 1063 d
597. 1063 );
598. 880 if (the_token.warning === undefined) {
599. 880 the_token.warning = the_warning;
600. 880 } else {
601. 183 warning_list.pop();
602. 183 }
603. 1063 return the_warning;
604. 1063 }
605. 628
606. 1362 function warn_at(code, line, column, a, b, c, d) {
607. 1362
608. 1362// Report an error at some line and column of the program. The warning object
609. 1362// resembles an exception.
610. 1362
611. 1362 let mm;
612. 1362 let warning = Object.assign(empty(), {
613. 1362 a,
614. 1362 b,
615. 1362 c,
616. 1362 code,
617. 1362
618. 1362// Fudge column numbers in warning message.
619. 1362
620. 22 column: column || jslint_fudge,
621. 1362 d,
622. 1362 line,
623. 1362 line_source: "",
624. 1362 name: "JSLintError"
625. 1362 }, line_list[line]);
626. 1362 warning.column = Math.max(
627. 1362 Math.min(warning.column, warning.line_source.length),
628. 1362 jslint_fudge
629. 1362 );
630. 892 test_cause(code, b || a, warning.column);
631. 1362 switch (code) {
632. 1362
633. 1362// The bundle contains the raw text messages that are generated by jslint. It
634. 1362// seems that they are all error messages and warnings. There are no "Atta
635. 1362// boy!" or "You are so awesome!" messages. There is no positive reinforcement
636. 1362// or encouragement. This relentless negativity can undermine self-esteem and
637. 1362// wound the inner child. But if you accept it as sound advice rather than as
638. 1362// personal criticism, it can make your programs better.
639. 1362
640. 1 case "and":
641. 1 mm = `The '&&' subexpression should be wrapped in parens.`;
642. 1 break;
643. 67 case "bad_assignment_a":
644. 67 mm = `Bad assignment to '${a}'.`;
645. 67 break;
646. 1 case "bad_directive_a":
647. 1 mm = `Bad directive '${a}'.`;
648. 1 break;
649. 1 case "bad_get":
650. 1 mm = `A get function takes no parameters.`;
651. 1 break;
652. 1 case "bad_module_name_a":
653. 1 mm = `Bad module name '${a}'.`;
654. 1 break;
655. 2 case "bad_option_a":
656. 2 mm = `Bad option '${a}'.`;
657. 2 break;
658. 1 case "bad_set":
659. 1 mm = `A set function takes one parameter.`;
660. 1 break;
661. 6 case "duplicate_a":
662. 6 mm = `Duplicate '${a}'.`;
663. 6 break;
664. 67 case "empty_block":
665. 67 mm = `Empty block.`;
666. 67 break;
667. 5 case "expected_a":
668. 5 mm = `Expected '${a}'.`;
669. 5 break;
670. 25 case "expected_a_at_b_c":
671. 25 mm = `Expected '${a}' at column ${b}, not column ${c}.`;
672. 25 break;
673. 284 case "expected_a_b":
674. 284 mm = `Expected '${a}' and instead saw '${b}'.`;
675. 284 break;
676. 16 case "expected_a_b_before_c_d":
677. 16 mm = `Expected ${a} '${b}' to be ordered before ${c} '${d}'.`;
678. 16 break;
679. 2 case "expected_a_b_from_c_d":
680. 2 mm = (
681. 2 `Expected '${a}' to match '${b}' from line ${c}`
682. 2 + ` and instead saw '${d}'.`
683. 2 );
684. 2 break;
685. 36 case "expected_a_before_b":
686. 36 mm = `Expected '${a}' before '${b}'.`;
687. 36 break;
688. 1 case "expected_digits_after_a":
689. 1 mm = `Expected digits after '${a}'.`;
690. 1 break;
691. 1 case "expected_four_digits":
692. 1 mm = `Expected four digits after '\\u'.`;
693. 1 break;
694. 32 case "expected_identifier_a":
695. 32 mm = `Expected an identifier and instead saw '${a}'.`;
696. 32 break;
697. 6 case "expected_line_break_a_b":
698. 6 mm = `Expected a line break between '${a}' and '${b}'.`;
699. 6 break;
700. 3 case "expected_regexp_factor_a":
701. 3 mm = `Expected a regexp factor and instead saw '${a}'.`;
702. 3 break;
703. 76 case "expected_space_a_b":
704. 76 mm = `Expected one space between '${a}' and '${b}'.`;
705. 76 break;
706. 2 case "expected_statements_a":
707. 2 mm = `Expected statements before '${a}'.`;
708. 2 break;
709. 1 case "expected_string_a":
710. 1 mm = `Expected a string and instead saw '${a}'.`;
711. 1 break;
712. 1 case "expected_type_string_a":
713. 1 mm = `Expected a type string and instead saw '${a}'.`;
714. 1 break;
715. 5 case "freeze_exports":
716. 5 mm = (
717. 5 `Expected 'Object.freeze('. All export values should be frozen.`
718. 5 );
719. 5 break;
720. 2 case "function_in_loop":
721. 2 mm = `Don't create functions within a loop.`;
722. 2 break;
723. 1 case "infix_in":
724. 1 mm = (
725. 1 `Unexpected 'in'. Compare with undefined,`
726. 1 + ` or use the hasOwnProperty method instead.`
727. 1 );
728. 1 break;
729. 1 case "label_a":
730. 1 mm = `'${a}' is a statement label.`;
731. 1 break;
732. 1 case "misplaced_a":
733. 1 mm = `Place '${a}' at the outermost level.`;
734. 1 break;
735. 1 case "misplaced_directive_a":
736. 1 mm = `Place the '/*${a}*/' directive before the first statement.`;
737. 1 break;
738. 1 case "missing_await_statement":
739. 1 mm = `Expected await statement in async function.`;
740. 1 break;
741. 1362
742. 1362// PR-347 - Disable warning "missing_browser".
743. 1362// case "missing_browser":
744. 1362// mm = `/*global*/ requires the Assume a browser option.`;
745. 1362// break;
746. 1362
747. 1 case "missing_m":
748. 1 mm = `Expected 'm' flag on a multiline regular expression.`;
749. 1 break;
750. 5 case "naked_block":
751. 5 mm = `Naked block.`;
752. 5 break;
753. 2 case "nested_comment":
754. 2 mm = `Nested comment.`;
755. 2 break;
756. 1 case "not_label_a":
757. 1 mm = `'${a}' is not a label.`;
758. 1 break;
759. 2 case "number_isNaN":
760. 2 mm = `Use Number.isNaN function to compare with NaN.`;
761. 2 break;
762. 4 case "out_of_scope_a":
763. 4 mm = `'${a}' is out of scope.`;
764. 4 break;
765. 11 case "redefinition_a_b":
766. 11 mm = `Redefinition of '${a}' from line ${b}.`;
767. 11 break;
768. 1 case "redefinition_global_a_b":
769. 1 mm = `Redefinition of global ${a} variable '${b}'.`;
770. 1 break;
771. 6 case "required_a_optional_b":
772. 6 mm = `Required parameter '${a}' after optional parameter '${b}'.`;
773. 6 break;
774. 1 case "reserved_a":
775. 1 mm = `Reserved name '${a}'.`;
776. 1 break;
777. 1 case "subscript_a":
778. 1 mm = `['${a}'] is better written in dot notation.`;
779. 1 break;
780. 16 case "todo_comment":
781. 16 mm = `Unexpected TODO comment.`;
782. 16 break;
783. 8 case "too_long":
784. 8 mm = `Line is longer than 80 characters.`;
785. 8 break;
786. 1 case "too_many_digits":
787. 1 mm = `Too many digits.`;
788. 1 break;
789. 3 case "unclosed_comment":
790. 3 mm = `Unclosed comment.`;
791. 3 break;
792. 3 case "unclosed_disable":
793. 3 mm = (
794. 3 `Directive '/*jslint-disable*/' was not closed`
795. 3 + ` with '/*jslint-enable*/'.`
796. 3 );
797. 3 break;
798. 3 case "unclosed_mega":
799. 3 mm = `Unclosed mega literal.`;
800. 3 break;
801. 2 case "unclosed_string":
802. 2 mm = `Unclosed string.`;
803. 2 break;
804. 126 case "undeclared_a":
805. 126 mm = `Undeclared '${a}'.`;
806. 126 break;
807. 238 case "unexpected_a":
808. 238 mm = `Unexpected '${a}'.`;
809. 238 break;
810. 1 case "unexpected_a_after_b":
811. 1 mm = `Unexpected '${a}' after '${b}'.`;
812. 1 break;
813. 2 case "unexpected_a_before_b":
814. 2 mm = `Unexpected '${a}' before '${b}'.`;
815. 2 break;
816. 36 case "unexpected_at_top_level_a":
817. 36 mm = `Expected '${a}' to be in a function.`;
818. 36 break;
819. 1 case "unexpected_char_a":
820. 1 mm = `Unexpected character '${a}'.`;
821. 1 break;
822. 2 case "unexpected_comment":
823. 2 mm = `Unexpected comment.`;
824. 2 break;
825. 1362
826. 1362// PR-347 - Disable warning "unexpected_directive_a".
827. 1362// case "unexpected_directive_a":
828. 1362// mm = `When using modules, don't use directive '/\u002a${a}'.`;
829. 1362// break;
830. 1362
831. 123 case "unexpected_expression_a":
832. 123 mm = `Unexpected expression '${a}' in statement position.`;
833. 123 break;
834. 4 case "unexpected_label_a":
835. 4 mm = `Unexpected label '${a}'.`;
836. 4 break;
837. 3 case "unexpected_parens":
838. 3 mm = `Don't wrap function literals in parens.`;
839. 3 break;
840. 8 case "unexpected_space_a_b":
841. 8 mm = `Unexpected space between '${a}' and '${b}'.`;
842. 8 break;
843. 1 case "unexpected_statement_a":
844. 1 mm = `Unexpected statement '${a}' in expression position.`;
845. 1 break;
846. 2 case "unexpected_trailing_space":
847. 2 mm = `Unexpected trailing space.`;
848. 2 break;
849. 1 case "unexpected_typeof_a":
850. 1 mm = (
851. 1 `Unexpected 'typeof'. Use '===' to compare directly with ${a}.`
852. 1 );
853. 1 break;
854. 1 case "uninitialized_a":
855. 1 mm = `Uninitialized '${a}'.`;
856. 1 break;
857. 1 case "unopened_enable":
858. 1 mm = (
859. 1 `Directive '/*jslint-enable*/' was not opened`
860. 1 + ` with '/*jslint-disable*/'.`
861. 1 );
862. 1 break;
863. 1 case "unreachable_a":
864. 1 mm = `Unreachable '${a}'.`;
865. 1 break;
866. 1 case "unregistered_property_a":
867. 1 mm = `Unregistered property name '${a}'.`;
868. 1 break;
869. 6 case "unused_a":
870. 6 mm = `Unused '${a}'.`;
871. 6 break;
872. 2 case "use_double":
873. 2 mm = `Use double quotes, not single quotes.`;
874. 2 break;
875. 7 case "use_open":
876. 7 mm = (
877. 7 `Wrap a ternary expression in parens,`
878. 7 + ` with a line break after the left paren.`
879. 7 );
880. 7 break;
881. 1 case "use_spaces":
882. 1 mm = `Use spaces, not tabs.`;
883. 1 break;
884. 5 case "var_on_top":
885. 5 mm = `Move variable declaration to top of function or script.`;
886. 5 break;
887. 1 case "var_switch":
888. 1 mm = `Don't declare variables in a switch.`;
889. 1 break;
890. 21 case "weird_condition_a":
891. 21 mm = `Weird condition '${a}'.`;
892. 21 break;
893. 5 case "weird_expression_a":
894. 5 mm = `Weird expression '${a}'.`;
895. 5 break;
896. 3 case "weird_loop":
897. 3 mm = `Weird loop.`;
898. 3 break;
899. 8 case "weird_property_a":
900. 8 mm = `Weird property name '${a}'.`;
901. 8 break;
902. 8 case "weird_relation_a":
903. 8 mm = `Weird relation '${a}'.`;
904. 8 break;
905. 1 case "wrap_condition":
906. 1 mm = `Wrap the condition in parens.`;
907. 1 break;
908. 1 case "wrap_immediate":
909. 1 mm = (
910. 1 `Wrap an immediate function invocation in parentheses to assist`
911. 1 + ` the reader in understanding that the expression is the`
912. 1 + ` result of a function, and not the function itself.`
913. 1 );
914. 1 break;
915. 1 case "wrap_parameter":
916. 1 mm = `Wrap the parameter in parens.`;
917. 1 break;
918. 18 case "wrap_regexp":
919. 18 mm = `Wrap this regexp in parens to avoid confusion.`;
920. 18 break;
921. 1 case "wrap_unary":
922. 1 mm = `Wrap the unary expression in parens.`;
923. 1 break;
924. 1362 }
925. 1362
926. 1362// Validate mm.
927. 1362
928. 1362 jslint_assert(mm, code);
929. 1362 warning.message = mm;
930. 1362
931. 1362// PR-242 - Include stack_trace for jslint to debug itself for errors.
932. 1362
933. 6 if (option_dict.trace) {
934. 6 warning.stack_trace = new Error().stack;
935. 6 }
936. 30 if (warning.directive_quiet) {
937. 30
938. 30// test_cause:
939. 30// ["0 //jslint-quiet", "semicolon", "directive_quiet", "", 0]
940. 30
941. 30 test_cause("directive_quiet");
942. 30 return warning;
943. 1332 }
944. 1332 warning_list.push(warning);
945. 1332 return warning;
946. 1332 }
947. 628
948. 628 try {
949. 628
950. 628// tokenize takes a source and produces from it an array of token objects.
951. 628// JavaScript is notoriously difficult to tokenize because of the horrible
952. 628// interactions between automatic semicolon insertion, regular expression
953. 628// literals, and now megastring literals. JSLint benefits from eliminating
954. 628// automatic semicolon insertion and nested megastring literals, which allows
955. 628// full tokenization to precede parsing.
956. 628
957. 628 option_dict = Object.assign(empty(), option_dict);
958. 628 Object.assign(state, {
959. 628 artifact,
960. 628 catch_list,
961. 628 catch_stack,
962. 628 directive_list,
963. 628 export_dict,
964. 628 function_list,
965. 628 function_stack,
966. 628 global_dict,
967. 628 global_list,
968. 628 import_list,
969. 628 is_equal,
970. 628 is_weird,
971. 628 line_list,
972. 628 mode_json: false, // true if parsing JSON.
973. 628 mode_module: false, // true if import or export was used.
974. 628 mode_property: false, // true if directive /*property*/ is
975. 628 // used.
976. 628 mode_shebang: false, // true if #! is seen on the first line.
977. 628 option_dict,
978. 628 property_dict,
979. 628 source,
980. 628 stop,
981. 628 stop_at,
982. 628 syntax_dict,
983. 628 tenure,
984. 628 test_cause,
985. 628 token_global,
986. 628 token_list,
987. 628 token_nxt: token_global,
988. 628 warn,
989. 628 warn_at,
990. 628 warning_list
991. 628 });
992. 628
993. 628// PHASE 1. Split <source> by newlines into <line_list>.
994. 628
995. 628 jslint_phase1_split(state);
996. 628 jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
997. 628 jslint_assert(
998. 628 function_stack.length === 0,
999. 628 `function_stack.length === 0.`
1000. 628 );
1001. 628
1002. 628// PHASE 2. Lex <line_list> into <token_list>.
1003. 628
1004. 628 jslint_phase2_lex(state);
1005. 628 jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
1006. 628 jslint_assert(
1007. 628 function_stack.length === 0,
1008. 628 `function_stack.length === 0.`
1009. 628 );
1010. 628
1011. 628// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
1012. 628
1013. 628 jslint_phase3_parse(state);
1014. 628 jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
1015. 628 jslint_assert(
1016. 628 function_stack.length === 0,
1017. 628 `function_stack.length === 0.`
1018. 628 );
1019. 628
1020. 628// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
1021. 628// recursive traversal. Each node may be processed on the way down
1022. 628// (preaction) and on the way up (postaction).
1023. 628
1024. 473 if (!state.mode_json) {
1025. 473 jslint_phase4_walk(state);
1026. 488 }
1027. 488 jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
1028. 488 jslint_assert(
1029. 488 function_stack.length === 0,
1030. 488 `function_stack.length === 0.`
1031. 488 );
1032. 488
1033. 488// PHASE 5. Check whitespace between tokens in <token_list>.
1034. 488
1035. 488 if (!state.mode_json && warning_list.length === 0) {
1036. 176 jslint_phase5_whitage(state);
1037. 488 }
1038. 488 jslint_assert(catch_stack.length === 1, `catch_stack.length === 1.`);
1039. 488 jslint_assert(
1040. 488 function_stack.length === 0,
1041. 488 `function_stack.length === 0.`
1042. 488 );
1043. 488
1044. 488// PR-347 - Disable warning "missing_browser".
1045. 488// if (!option_dict.browser) {
1046. 488// directive_list.forEach(function (comment) {
1047. 488// if (comment.directive === "global") {
1048. 488//
1049. 488// // test_cause:
1050. 488// // ["/*global aa*/", "jslint", "missing_browser", "(comment)", 1]
1051. 488//
1052. 488// warn("missing_browser", comment);
1053. 488// }
1054. 488// });
1055. 488// }
1056. 488
1057. 488 if (option_dict.test_internal_error) {
1058. 1 jslint_assert(undefined, "test_internal_error");
1059. 1 }
1060. 141 } catch (err) {
1061. 141 mode_stop = true;
1062. 141 err.message = "[JSLint was unable to finish] " + err.message;
1063. 141 err.mode_stop = true;
1064. 141 if (err.name !== "JSLintError") {
1065. 141 Object.assign(err, {
1066. 141 column: jslint_fudge,
1067. 141 line: jslint_fudge,
1068. 141 line_source: "",
1069. 141 stack_trace: err.stack
1070. 141 });
1071. 141 }
1072. 141 if (warning_list.indexOf(err) === -1) {
1073. 141 warning_list.push(err);
1074. 141 }
1075. 141 }
1076. 628
1077. 628// Sort warning_list by mode_stop first, line, column respectively.
1078. 628
1079. 973 warning_list.sort(function (aa, bb) {
1080. 973 return (
1081. 973 Boolean(bb.mode_stop) - Boolean(aa.mode_stop)
1082. 878 || aa.line - bb.line
1083. 857 || aa.column - bb.column
1084. 973 );
1085. 973
1086. 973// Update each warning with formatted_message ready-for-use by jslint_cli.
1087. 973
1088. 1151 }).map(function ({
1089. 1151 column,
1090. 1151 line,
1091. 1151 line_source,
1092. 1151 message,
1093. 1151 stack_trace = ""
1094. 1151 }, ii, list) {
1095. 1151 list[ii].formatted_message = String(
1096. 1151 String(ii + 1).padStart(2, " ")
1097. 1151 + ". \u001b[31m" + message + "\u001b[39m"
1098. 1151 + " \u001b[90m\/\/ line " + line + ", column " + column
1099. 1151 + "\u001b[39m\n"
1100. 1151 + (" " + line_source.trim()).slice(0, 72) + "\n"
1101. 1151 + stack_trace
1102. 1151 ).trimRight();
1103. 1151 });
1104. 628
1105. 628 return {
1106. 628 causes: cause_dict,
1107. 628 directives: directive_list,
1108. 628 edition: jslint_edition,
1109. 628 exports: export_dict,
1110. 628 froms: import_list,
1111. 628 functions: function_list,
1112. 628 global: token_global,
1113. 628 id: "(JSLint)",
1114. 628 json: state.mode_json,
1115. 628 lines: line_list,
1116. 628 module: state.mode_module === true,
1117. 133 ok: warning_list.length === 0 && !mode_stop,
1118. 628 option: option_dict,
1119. 628 property: property_dict,
1120. 628 shebang: (
1121. 628 state.mode_shebang
1122. 2 ? line_list[jslint_fudge].line_source
1123. 626 : undefined
1124. 628 ),
1125. 628 stop: mode_stop,
1126. 628 tokens: token_list,
1127. 628 tree: state.token_tree,
1128. 628 warnings: warning_list
1129. 628 };
1130. 628}
1131. 1
1132. 1// PR-362 - Add API Doc.
1133. 1
1134. 1async function jslint_apidoc({
1135. 1 example_list,
1136. 1 github_repo,
1137. 1 module_list,
1138. 1 package_name,
1139. 1 pathname,
1140. 1 version
1141. 1}) {
1142. 1
1143. 1// This function will create API Doc from <module_list>.
1144. 1
1145. 1 let elem_ii = 0;
1146. 1 let html;
1147. 1
1148. 26 function elem_create(moduleObj, key, moduleName) {
1149. 26
1150. 26// This function will create a sub API Doc from elem <moduleObj>[<key>].
1151. 26
1152. 26 let example = "N/A";
1153. 26 let id = encodeURIComponent("apidoc.elem." + moduleName + "." + key);
1154. 26 let name;
1155. 26 let signature;
1156. 26 let source;
1157. 26 name = htmlEscape((typeof moduleObj[key]) + " " + key);
1158. 2 if (typeof moduleObj[key] !== "function") {
1159. 2 return {
1160. 2 name,
1161. 2 signature: (`
1162. 2<a class="apidocElementLiA" href="#${id}">
1163. 2${name}
1164. 2</a>
1165. 2 `),
1166. 2 source: (`
1167. 2<li>
1168. 2 <h2>
1169. 2 <a href="#${id}" id="${id}">
1170. 2 ${name}
1171. 2 </a>
1172. 2 </h2>
1173. 2</li>
1174. 2 `)
1175. 2 };
1176. 24 }
1177. 24 // init source
1178. 24 source = htmlEscape(trim_start(moduleObj[key].toString()));
1179. 24 // init signature
1180. 24 source = source.replace((
1181. 24 /(\([\S\s]*?\)) \{/
1182. 24 ), function (match0, match1) {
1183. 24 signature = htmlEscape(
1184. 24 match1.replace((
1185. 24 / *?\/\*[\S\s]*?\*\/ */g
1186. 24 ), "").replace((
1187. 24 / *?\/\/.*/g
1188. 24 ), "").replace((
1189. 24 /\n{2,}/g
1190. 24 ), "\n")
1191. 24 );
1192. 24 return match0;
1193. 24 });
1194. 24 // init comment
1195. 24 source = source.replace((
1196. 24 /\n(?:\/\/.*?\n)+\n/
1197. 24 ), "<span class=\"apidocCodeCommentSpan\">$&</span>");
1198. 24 // init example
1199. 58 example_list.some(function (example2) {
1200. 58 example2.replace(
1201. 58 new RegExp((
1202. 58 "((?:\\n.*?){8}(function )?)\\b"
1203. 58 + key
1204. 58 + "(\\((?:.*?\\n){8})"
1205. 58 ), "g"),
1206. 100 function (ignore, header, isDeclaration, footer) {
1207. 90 if (!isDeclaration) {
1208. 90 example = "..." + trim_start(
1209. 90 htmlEscape(header)
1210. 90 + "<span class=\"apidocCodeKeywordSpan\">"
1211. 90 + htmlEscape(key)
1212. 90 + "</span>"
1213. 90 + htmlEscape(footer)
1214. 90 ).trimEnd() + "\n...";
1215. 90 }
1216. 100 return "";
1217. 100 }
1218. 58 );
1219. 58 return example !== "N/A";
1220. 58 });
1221. 24 if (source.length > 2048) {
1222. 10 source = source.slice(0, 2048) + "...\n}\n";
1223. 24 }
1224. 24 return {
1225. 24 name,
1226. 24 signature: (`
1227. 24<a class="apidocElementLiA" href="#${id}">
1228. 24${name}<span class="apidocSignatureSpan">${signature}</span>
1229. 24</a>
1230. 24 `),
1231. 24 source: (`
1232. 24<li>
1233. 24 <h2>
1234. 24 <a href="#${id}" id="${id}">
1235. 24 ${name}<span class="apidocSignatureSpan">${signature}</span>
1236. 24 </a>
1237. 24 </h2>
1238. 24</li>
1239. 24<li>Description and source-code:<pre class="apidocCodePre">${source}</pre></li>
1240. 24<li>Example usage:<pre class="apidocCodePre">${example}</pre></li>
1241. 24 `)
1242. 24 };
1243. 24 }
1244. 1
1245. 114 function trim_start(str) {
1246. 114
1247. 114// This function will normalize whitespace before <str>.
1248. 114
1249. 114 let whitespace = "";
1250. 114 str.trim().replace((
1251. 114 /^ */gm
1252. 11961 ), function (match0) {
1253. 7759 if (whitespace === "" || match0.length < whitespace.length) {
1254. 5982 whitespace = match0;
1255. 5982 }
1256. 11961 return "";
1257. 11961 });
1258. 114 str = str.replace(new RegExp("^" + whitespace, "gm"), "");
1259. 114 return str;
1260. 114 }
1261. 1 await moduleFsInit();
1262. 1
1263. 1// Html-escape params.
1264. 1
1265. 1 github_repo = htmlEscape(github_repo);
1266. 1 package_name = htmlEscape(package_name);
1267. 1 version = htmlEscape(version);
1268. 1
1269. 1// Init example_list.
1270. 1
1271. 3 example_list = await Promise.all(example_list.map(async function (file) {
1272. 3
1273. 3// This function will read example from given file.
1274. 3
1275. 3 let result = await moduleFs.promises.readFile(file, "utf8");
1276. 3 result = (
1277. 3 "\n\n\n\n\n\n\n\n"
1278. 3 // bug-workaround - truncate example to manageable size
1279. 3 + result.slice(0, 524288)
1280. 3 + "\n\n\n\n\n\n\n\n"
1281. 3 );
1282. 3 result = result.replace((
1283. 3 /\r\n*/g
1284. 3 ), "\n");
1285. 3 return result;
1286. 3 }));
1287. 1 // init module_list
1288. 1 module_list = await Promise.all(module_list.map(async function ({
1289. 1 pathname
1290. 1 }) {
1291. 1 let moduleName = htmlEscape(JSON.stringify(pathname));
1292. 1 let moduleObj = await import(pathname);
1293. 1 if (moduleObj.default) {
1294. 1 moduleObj = moduleObj.default;
1295. 1 }
1296. 1 return {
1297. 26 elem_list: Object.keys(moduleObj).map(function (key) {
1298. 26 return elem_create(moduleObj, key, moduleName);
1299. 73 }).sort(function (aa, bb) {
1300. 73 return (
1301. 73 aa.name < bb.name
1302. 20 ? -1
1303. 53 : 1
1304. 73 );
1305. 26 }).map(function (elem) {
1306. 26 elem_ii += 1;
1307. 26 elem.signature = elem.signature.replace(
1308. 26 ">",
1309. 26 ">" + elem_ii + ". "
1310. 26 );
1311. 26 elem.source = elem.source.replace(
1312. 26 "\">",
1313. 26 "\">" + elem_ii + ". "
1314. 26 );
1315. 26 return elem;
1316. 26 }),
1317. 1 id: encodeURIComponent("apidoc.module." + moduleName),
1318. 1 moduleName
1319. 1 };
1320. 1 }));
1321. 1 html = (`
1322. 1<!DOCTYPE html>
1323. 1<html lang="en">
1324. 1<head>
1325. 1<meta charset="utf-8">
1326. 1<meta name="viewport" content="width=device-width, initial-scale=1">
1327. 1<meta name="description" content="${package_name} API Doc">
1328. 1<title>${package_name} apidoc</title>
1329. 1<style>
1330. 1/* jslint utility2:true */
1331. 1/*csslint*/
1332. 1body {
1333. 1 margin: 0;
1334. 1 padding: 20px;
1335. 1}
1336. 1.apidocCodeCommentSpan,
1337. 1.apidocCodeKeywordSpan {
1338. 1 background: royalblue;
1339. 1 color: white;
1340. 1}
1341. 1.apidocCodeCommentSpan {
1342. 1 display: block;
1343. 1}
1344. 1.apidocCodePre {
1345. 1 background: #eef;
1346. 1 border: 1px solid;
1347. 1 font-size: 14px;
1348. 1 overflow-wrap: break-word;
1349. 1 padding: 5px;
1350. 1 white-space: pre-wrap;
1351. 1}
1352. 1.apidocDiv {
1353. 1 color: #555;
1354. 1 font-family: sans-serif;
1355. 1}
1356. 1.apidocDiv a[href] {
1357. 1 color: royalblue;
1358. 1 text-decoration: none;
1359. 1}
1360. 1.apidocDiv a[href]:hover {
1361. 1 text-decoration: underline;
1362. 1}
1363. 1.apidocDiv li a {
1364. 1 display: inline-block;
1365. 1 padding: 8px 0;
1366. 1}
1367. 1.apidocDiv ul {
1368. 1 list-style: none;
1369. 1 padding-left: 20px;
1370. 1}
1371. 1.apidocFooterDiv {
1372. 1 margin-top: 20px;
1373. 1 text-align: center;
1374. 1}
1375. 1.apidocModuleA {
1376. 1 font-size: 24px;
1377. 1 font-weight: bold;
1378. 1}
1379. 1.apidocSectionDiv {
1380. 1 border-top: 1px solid;
1381. 1 margin-top: 20px;
1382. 1}
1383. 1.apidocSignatureSpan {
1384. 1 color: #666;
1385. 1 white-space: pre-wrap;
1386. 1}
1387. 1</style>
1388. 1</head>
1389. 1<body>
1390. 1<div class="apidocDiv">
1391. 1<h1>API Doc for <a href="${github_repo}">${package_name} (${version})</a></h1>
1392. 1<div class="apidocSectionDiv">
1393. 1 <a href="#apidocTableOfContents1" id="apidocTableOfContents1">
1394. 1 <h1>Table of Contents</h1>
1395. 1 </a>
1396. 1 <ul>
1397. 1 `) + module_list.map(function ({
1398. 1 elem_list,
1399. 1 id,
1400. 1 moduleName
1401. 1 }) {
1402. 1 return (
1403. 1 (`
1404. 1 <li>
1405. 1 <a class="apidocModuleA" href="#${id}">Module ${moduleName}</a>
1406. 1 <ul>
1407. 1 `)
1408. 26 + elem_list.map(function ({
1409. 26 signature
1410. 26 }) {
1411. 26 return "<li>\n" + signature + "\n</li>\n";
1412. 26 }).join("")
1413. 1 + (`
1414. 1 </ul>
1415. 1 </li>
1416. 1 `)
1417. 1 );
1418. 1 }).join("") + (`
1419. 1 </ul>
1420. 1</div>
1421. 1 `) + module_list.map(function ({
1422. 1 elem_list,
1423. 1 id,
1424. 1 moduleName
1425. 1 }) {
1426. 1 return (
1427. 1 (`
1428. 1<div class="apidocSectionDiv">
1429. 1 <h1><a href="#${id}" id="${id}">Module ${moduleName}</a></h1>
1430. 1 <ul>
1431. 1 `)
1432. 26 + elem_list.map(function ({
1433. 26 source
1434. 26 }) {
1435. 26 return source;
1436. 26 }).join("")
1437. 1 + (`
1438. 1 </ul>
1439. 1</div>
1440. 1 `)
1441. 1 );
1442. 1 }).join("") + (`
1443. 1<div class="apidocFooterDiv">
1444. 1 [
1445. 1 This document was created with
1446. 1 <a href="https://github.com/jslint-org/jslint">JSLint</a>
1447. 1 ]
1448. 1</div>
1449. 1</div>
1450. 1</body>
1451. 1</html>
1452. 1 `);
1453. 1 html = html.trim().replace((
1454. 1 / +?$/gm
1455. 1 ), "") + "\n";
1456. 1 await fsWriteFileWithParents(pathname, html);
1457. 1}
1458. 1
1459. 97663function jslint_assert(condition, message) {
1460. 97663
1461. 97663// This function will throw <message> if <condition> is falsy.
1462. 97663
1463. 97662 if (condition) {
1464. 97662 return condition;
1465. 97662 }
1466. 1 throw new Error(
1467. 1 `This was caused by a bug in JSLint.
1468. 1Please open an issue with this stack-trace (and possible example-code) at
1469. 1https://github.com/jslint-org/jslint/issues.
1470. 1edition = "${jslint_edition}";
1471. 1${String(message).slice(0, 2000)}`
1472. 1 );
1473. 1}
1474. 1
1475. 21async function jslint_cli({
1476. 21 cjs_module,
1477. 21 cjs_require,
1478. 21 console_error,
1479. 21 console_log,
1480. 21 file,
1481. 21 mode_cli,
1482. 21 mode_noop,
1483. 21 option,
1484. 21 processArgv,
1485. 21 processEnv,
1486. 21 process_exit,
1487. 21 source
1488. 21}) {
1489. 21
1490. 21// This function will run jslint from nodejs-cli.
1491. 21
1492. 21 let command;
1493. 21 let data;
1494. 21 let exit_code = 0;
1495. 21 let mode_plugin_vim;
1496. 21 let mode_report;
1497. 21 let result;
1498. 21
1499. 32 function jslint_from_file({
1500. 32 code,
1501. 32 file,
1502. 32 line_offset = 0,
1503. 32 option = empty()
1504. 32 }) {
1505. 32 let result_from_file;
1506. 32 option = Object.assign(empty(), option, {
1507. 32 file
1508. 32 });
1509. 32 switch ((
1510. 32 /\.\w+?$|$/m
1511. 32 ).exec(file)[0]) {
1512. 0 case ".html":
1513. 0
1514. 0// Recursively jslint embedded "<script>\n...\n</script>".
1515. 0
1516. 0 code.replace((
1517. 0 /^<script\b[^>]*?>\n([\S\s]*?\n)<\/script>$/gm
1518. 0 ), function (ignore, match1, ii) {
1519. 0 jslint_from_file({
1520. 0 code: match1,
1521. 0 file: file + ".<script>.js",
1522. 0 line_offset: string_line_count(code.slice(0, ii)) + 1,
1523. 0 option: Object.assign(empty(), {
1524. 0 browser: true
1525. 0 }, option)
1526. 0 });
1527. 0 return "";
1528. 0 });
1529. 0 return;
1530. 2 case ".sh":
1531. 2
1532. 2// Recursively jslint embedded "node -e '\n...\n'".
1533. 2
1534. 2 code.replace((
1535. 2 /\bnode\b.*? -e '\n([\S\s]*?\n)'/gm
1536. 16 ), function (ignore, match1, ii) {
1537. 16 jslint_from_file({
1538. 16 code: match1,
1539. 16 file: file + ".<node -e>.js",
1540. 16 line_offset: string_line_count(code.slice(0, ii)) + 1,
1541. 16 option: Object.assign(empty(), {
1542. 16 beta: Boolean(
1543. 16 processEnv.JSLINT_BETA
1544. 16 && !(
1545. 16 /0|false|null|undefined/
1546. 16 ).test(processEnv.JSLINT_BETA)
1547. 16 ),
1548. 16 node: true
1549. 16 }, option)
1550. 16 });
1551. 16 return "";
1552. 16 });
1553. 2 return;
1554. 30 default:
1555. 30 result_from_file = jslint("\n".repeat(line_offset) + code, option);
1556. 30 }
1557. 30
1558. 30// Print only first 10 warnings to stderr.
1559. 30
1560. 30 if (result_from_file.warnings.length > 0) {
1561. 5 exit_code = 1;
1562. 5 console_error(
1563. 5 mode_plugin_vim
1564. 5
1565. 5// PR-349 - Print warnings in format readable by vim.
1566. 5
1567. 5 ? result_from_file.warnings.slice(0, 10).map(function ({
1568. 5 column,
1569. 5 line,
1570. 5 message
1571. 5 }, ii) {
1572. 5 return (
1573. 5 file
1574. 5 + ":" + ii
1575. 5 + ":" + line
1576. 5 + ":" + column
1577. 5 + ":" + message
1578. 5 );
1579. 5 }).join("\n")
1580. 5
1581. 5// Print warnings in format readable by human.
1582. 5
1583. 5 : "\u001b[1mjslint " + file + "\u001b[22m\n"
1584. 11 + result_from_file.warnings.slice(0, 10).map(function ({
1585. 11 formatted_message
1586. 11 }) {
1587. 11 return formatted_message;
1588. 11 }).join("\n")
1589. 5 );
1590. 30 }
1591. 30 return result_from_file;
1592. 30 }
1593. 21
1594. 16 function string_line_count(code) {
1595. 16
1596. 16// This function will count number of newlines in <code>.
1597. 16
1598. 16 let count;
1599. 16 let ii;
1600. 16
1601. 16// https://jsperf.com/regexp-counting-2/8
1602. 16
1603. 16 count = 0;
1604. 16 ii = 0;
1605. 11345 while (true) {
1606. 11345 ii = code.indexOf("\n", ii) + 1;
1607. 11345 if (ii === 0) {
1608. 11345 break;
1609. 11345 }
1610. 11345 count += 1;
1611. 11345 }
1612. 16 return count;
1613. 16 }
1614. 21
1615. 21// Feature-detect nodejs.
1616. 21
1617. 21 if (!(
1618. 21 typeof process === "object"
1619. 21 && process
1620. 21 && process.versions
1621. 21 && typeof process.versions.node === "string"
1622. 21 && !mode_noop
1623. 1 )) {
1624. 1 return exit_code;
1625. 20 }
1626. 20 console_error = console_error || console.error;
1627. 20 console_log = console_log || console.log;
1628. 7 processArgv = processArgv || process.argv;
1629. 17 processEnv = processEnv || process.env;
1630. 7 process_exit = process_exit || process.exit;
1631. 20 await moduleFsInit();
1632. 20 if (!(
1633. 20
1634. 20// Feature-detect nodejs-cjs-cli.
1635. 20
1636. 20 (cjs_module && cjs_require)
1637. 1 ? cjs_module === cjs_require.main
1638. 21
1639. 21// Feature-detect nodejs-esm-cli.
1640. 21
1641. 19 : (
1642. 19 process.execArgv.indexOf("--eval") === -1
1643. 19 && process.execArgv.indexOf("-e") === -1
1644. 19 && (
1645. 19 (
1646. 19 /[\/|\\]jslint(?:\.[cm]?js)?$/m
1647. 19 ).test(processArgv[1])
1648. 19 || mode_cli
1649. 19 )
1650. 19 && moduleUrl.fileURLToPath(jslint_import_meta_url) ===
1651. 19 modulePath.resolve(processArgv[1])
1652. 19 )
1653. 7 ) && !mode_cli) {
1654. 2 return exit_code;
1655. 18 }
1656. 18
1657. 18// init commmand
1658. 18
1659. 18 command = String(processArgv[2]).split("=");
1660. 18 command[1] = command.slice(1).join("=");
1661. 18
1662. 18 switch (command[0]) {
1663. 18
1664. 18// PR-362 - Add API Doc.
1665. 18
1666. 18 case "jslint_apidoc":
1667. 1 await jslint_apidoc(Object.assign(JSON.parse(processArgv[3]), {
1668. 1 pathname: command[1]
1669. 1 }));
1670. 1 return;
1671. 21
1672. 21// COMMIT-b26d6df2 - Add command jslint_plugin_vim.
1673. 21
1674. 1 case "jslint_plugin_vim":
1675. 1 mode_plugin_vim = true;
1676. 1 processArgv = processArgv.slice(1);
1677. 1 break;
1678. 21
1679. 21// PR-363 - Add command jslint_report.
1680. 21
1681. 5 case "jslint_report":
1682. 5 mode_report = command[1];
1683. 5 processArgv = processArgv.slice(1);
1684. 5 break;
1685. 21
1686. 21// PR-364 - Add command v8_coverage_report.
1687. 21
1688. 6 case "v8_coverage_report":
1689. 6 await v8CoverageReportCreate({
1690. 6 coverageDir: command[1],
1691. 6 processArgv: processArgv.slice(3)
1692. 6 });
1693. 6 return;
1694. 11 }
1695. 11
1696. 11// PR-349 - Detect cli-option --mode-vim-plugin.
1697. 11
1698. 11 mode_plugin_vim = (
1699. 11 processArgv.slice(2).indexOf("--mode-vim-plugin") >= 0
1700. 11 || mode_plugin_vim
1701. 21 );
1702. 21
1703. 21// Normalize file relative to process.cwd().
1704. 21
1705. 6 processArgv.slice(2).some(function (arg) {
1706. 6 if (!arg.startsWith("-")) {
1707. 6 file = file || arg;
1708. 6 return true;
1709. 6 }
1710. 6 });
1711. 1 if (!file) {
1712. 1 return;
1713. 10 }
1714. 10 file = modulePath.resolve(file) + "/";
1715. 10 if (file.startsWith(process.cwd() + "/")) {
1716. 10 file = file.replace(process.cwd() + "/", "").slice(0, -1) || ".";
1717. 10 }
1718. 10 file = file.replace((
1719. 10 /\\/g
1720. 10 ), "/").replace((
1721. 10 /\/$/g
1722. 10 ), "");
1723. 10 if (source) {
1724. 6 data = source;
1725. 6 } else {
1726. 4
1727. 4// jslint_cli - jslint directory.
1728. 4
1729. 4 try {
1730. 4 data = await moduleFs.promises.readdir(file, "utf8");
1731. 4 } catch (ignore) {}
1732. 4 if (data) {
1733. 17 await Promise.all(data.map(async function (file2) {
1734. 17 let code;
1735. 17 let time_start = Date.now();
1736. 17 file2 = file + "/" + file2;
1737. 17 switch ((
1738. 17 /\.\w+?$|$/m
1739. 17 ).exec(file2)[0]) {
1740. 0 case ".cjs":
1741. 0 case ".html":
1742. 0 case ".js":
1743. 4 case ".json":
1744. 6 case ".mjs":
1745. 8 case ".sh":
1746. 8 break;
1747. 9 default:
1748. 9 return;
1749. 8 }
1750. 8 try {
1751. 8 code = await moduleFs.promises.readFile(file2, "utf8");
1752. 0 } catch (ignore) {
1753. 0 return;
1754. 0 }
1755. 8 if (!(
1756. 8 !(
1757. 8 /(?:\b|_)(?:lock|min|raw|rollup)(?:\b|_)/
1758. 8 ).test(file2) && code && code.length < 1048576
1759. 0 )) {
1760. 0 return;
1761. 0 }
1762. 8 jslint_from_file({
1763. 8 code,
1764. 8 file: file2,
1765. 8 option
1766. 8 });
1767. 8 console_error(
1768. 8 "jslint - " + (Date.now() - time_start) + "ms - " + file2
1769. 8 );
1770. 8 }));
1771. 4 process_exit(exit_code);
1772. 4 return exit_code;
1773. 4 }
1774. 4
1775. 4// jslint_cli - jslint file.
1776. 4
1777. 4 try {
1778. 4 data = await moduleFs.promises.readFile(file, "utf8");
1779. 4 } catch (err) {
1780. 4 console_error(err);
1781. 4 exit_code = 1;
1782. 4 process_exit(exit_code);
1783. 4 return exit_code;
1784. 4 }
1785. 8 }
1786. 8 result = jslint_from_file({
1787. 8 code: data,
1788. 8 file,
1789. 8 option
1790. 8 });
1791. 8 if (mode_report) {
1792. 5 await fsWriteFileWithParents(mode_report, jslint_report(result));
1793. 8 }
1794. 8 process_exit(exit_code);
1795. 8 return exit_code;
1796. 8}
1797. 1
1798. 628function jslint_phase1_split() {
1799. 628
1800. 628// PHASE 1. Split <source> by newlines into <line_list>.
1801. 628
1802. 628 return;
1803. 628}
1804. 1
1805. 628function jslint_phase2_lex(state) {
1806. 628
1807. 628// PHASE 2. Lex <line_list> into <token_list>.
1808. 628
1809. 628 let {
1810. 628 artifact,
1811. 628 directive_list,
1812. 628 global_dict,
1813. 628 global_list,
1814. 628 line_list,
1815. 628 option_dict,
1816. 628 stop,
1817. 628 stop_at,
1818. 628 tenure,
1819. 628 test_cause,
1820. 628 token_global,
1821. 628 token_list,
1822. 628 warn,
1823. 628 warn_at
1824. 628 } = state;
1825. 628 let char; // The current character being lexed.
1826. 628 let column = 0; // The column number of the next character.
1827. 628 let from; // The starting column number of the token.
1828. 628 let from_mega; // The starting column of megastring.
1829. 628 let line = 0; // The line number of the next character.
1830. 628 let line_disable; // The starting line of "/*jslint-disable*/".
1831. 628 let line_mega; // The starting line of megastring.
1832. 628 let line_source = ""; // The remaining line source string.
1833. 628 let line_whole = ""; // The whole line source string.
1834. 628 let mode_directive = true; // true if directives are still allowed.
1835. 628 let mode_mega = false; // true if currently parsing a megastring
1836. 628 // ... literal.
1837. 628 let mode_regexp; // true if regular expression literal seen on
1838. 628 // ... this line.
1839. 628 let rx_token = new RegExp(
1840. 628 "^("
1841. 628 + "(\\s+)"
1842. 628 + "|([a-zA-Z_$][a-zA-Z0-9_$]*)"
1843. 628 + "|[(){}\\[\\],:;'\"~\\`]"
1844. 628 + "|\\?[?.]?"
1845. 628 + "|=(?:==?|>)?"
1846. 628 + "|\\.+"
1847. 628 + "|\\*[*\\/=]?"
1848. 628 + "|\\/[*\\/]?"
1849. 628 + "|\\+[=+]?"
1850. 628 + "|-[=\\-]?"
1851. 628 + "|[\\^%]=?"
1852. 628 + "|&[&=]?"
1853. 628 + "|\\"
1854. 628 + "|[|=]?"
1855. 628 + "|>{1,3}=?"
1856. 628 + "|<<?=?"
1857. 628 + "|!(?:!|==?)?"
1858. 628
1859. 628// PR-351 - Add BigInt support.
1860. 628
1861. 628 + "|(0n?|[1-9][0-9]*n?)"
1862. 628 + ")"
1863. 628 + "(.*)$"
1864. 628 );
1865. 628 let snippet = ""; // A piece of string.
1866. 628 let token_1; // The first token.
1867. 628 let token_prv = token_global; // The previous token including
1868. 628 // ... comments.
1869. 628 let token_prv_expr = token_global; // The previous token excluding
1870. 628 // ... comments.
1871. 628
1872. 628// Most tokens, including the identifiers, operators, and punctuators, can be
1873. 628// found with a regular expression. Regular expressions cannot correctly match
1874. 628// regular expression literals, so we will match those the hard way. String
1875. 628// literals and number literals can be matched by regular expressions, but they
1876. 628// don't provide good warnings. The functions char_after, char_before,
1877. 628// read_digits, and char_after_escape help in the parsing of literals.
1878. 628
1879. 219681 function char_after(match) {
1880. 219681
1881. 219681// Get the next character from the source line. Remove it from the line_source,
1882. 219681// and append it to the snippet. Optionally check that the previous character
1883. 219681// matched an expected value.
1884. 219681
1885. 4365 if (match !== undefined && char !== match) {
1886. 10
1887. 10// test_cause:
1888. 10// ["aa=/[", "char_after", "expected_a", "]", 5]
1889. 10// ["aa=/aa{/", "char_after", "expected_a_b", "/", 8]
1890. 10
1891. 10 return (
1892. 10 char === ""
1893. 10 ? stop_at("expected_a", line, column - 1, match)
1894. 10 : stop_at("expected_a_b", line, column, match, char)
1895. 10 );
1896. 219671 }
1897. 219671 char = line_source.slice(0, 1);
1898. 219671 line_source = line_source.slice(1);
1899. 219671 snippet += char || " ";
1900. 219681 column += 1;
1901. 219681 return char;
1902. 219681 }
1903. 628
1904. 2210 function char_after_escape(extra) {
1905. 2210
1906. 2210// Validate char after escape "\\".
1907. 2210
1908. 2210 char_after("\\");
1909. 2210 switch (char) {
1910. 1 case "":
1911. 1
1912. 1// test_cause:
1913. 1// ["\"\\", "char_after_escape", "unclosed_string", "", 2]
1914. 1
1915. 1 return stop_at("unclosed_string", line, column);
1916. 132 case "/":
1917. 132 return char_after();
1918. 212 case "\\":
1919. 212 return char_after();
1920. 1 case "`":
1921. 1 return char_after();
1922. 58 case "b":
1923. 58 return char_after();
1924. 6 case "f":
1925. 6 return char_after();
1926. 864 case "n":
1927. 864 return char_after();
1928. 19 case "r":
1929. 19 return char_after();
1930. 24 case "t":
1931. 24
1932. 24// test_cause:
1933. 24// ["\"\\/\\\\\\`\\b\\f\\n\\r\\t\"", "char_after_escape", "char_after", "", 0]
1934. 24
1935. 24 test_cause("char_after");
1936. 24 return char_after();
1937. 262 case "u":
1938. 262 if (char_after("u") === "{") {
1939. 262 if (state.mode_json) {
1940. 262
1941. 262// test_cause:
1942. 262// ["[\"\\u{12345}\"]", "char_after_escape", "unexpected_a", "{", 5]
1943. 262
1944. 262 warn_at("unexpected_a", line, column, char);
1945. 262 }
1946. 262 if (read_digits("x") > 5) {
1947. 262
1948. 262// test_cause:
1949. 262// ["\"\\u{123456}\"", "char_after_escape", "too_many_digits", "", 11]
1950. 262
1951. 262 warn_at("too_many_digits", line, column);
1952. 262 }
1953. 262 if (char !== "}") {
1954. 262
1955. 262// test_cause:
1956. 262// ["\"\\u{12345\"", "char_after_escape", "expected_a_before_b", "\"", 10]
1957. 262
1958. 262 stop_at("expected_a_before_b", line, column, "}", char);
1959. 262 }
1960. 262 return char_after();
1961. 262 }
1962. 262 char_before();
1963. 262 if (read_digits("x", true) < 4) {
1964. 262
1965. 262// test_cause:
1966. 262// ["\"\\u0\"", "char_after_escape", "expected_four_digits", "", 5]
1967. 262
1968. 262 warn_at("expected_four_digits", line, column);
1969. 262 }
1970. 262 return;
1971. 631 default:
1972. 631 if (extra && extra.indexOf(char) >= 0) {
1973. 631 return char_after();
1974. 631 }
1975. 631
1976. 631// test_cause:
1977. 631// ["\"\\0\"", "char_after_escape", "unexpected_a_before_b", "0", 3]
1978. 631
1979. 631 warn_at("unexpected_a_before_b", line, column, "\\", char);
1980. 2210 }
1981. 2210 }
1982. 628
1983. 9351 function char_before() {
1984. 9351
1985. 9351// Back up one character by moving a character from the end of the snippet to
1986. 9351// the front of the line_source.
1987. 9351
1988. 9351 char = snippet.slice(-1);
1989. 9351 line_source = char + line_source;
1990. 9351 column -= char.length;
1991. 9351
1992. 9351// Remove last character from snippet.
1993. 9351
1994. 9351 snippet = snippet.slice(0, -1);
1995. 9351 return char;
1996. 9351 }
1997. 628
1998. 10021 function lex_comment() {
1999. 10021 let body;
2000. 10021 let ii = 0;
2001. 10021 let jj = 0;
2002. 10021 let the_comment;
2003. 10021
2004. 10021// Create a comment object. Comments are not allowed in JSON text. Comments can
2005. 10021// include directives and notices of incompletion.
2006. 10021
2007. 10021// Create token from comment //....
2008. 10021
2009. 9928 if (snippet === "//") {
2010. 9928 snippet = line_source;
2011. 9928 line_source = "";
2012. 9928 the_comment = token_create("(comment)", snippet);
2013. 9928 if (mode_mega) {
2014. 9928
2015. 9928// test_cause:
2016. 9928// ["`${//}`", "lex_comment", "unexpected_comment", "`", 4]
2017. 9928
2018. 9928 warn("unexpected_comment", the_comment, "`");
2019. 9928 }
2020. 9928
2021. 9928// Create token from comment /*...*/.
2022. 9928
2023. 9928 } else {
2024. 93 snippet = [];
2025. 93 if (line_source[0] === "/") {
2026. 93
2027. 93// test_cause:
2028. 93// ["/*/", "lex_comment", "unexpected_a", "/", 2]
2029. 93
2030. 93 warn_at("unexpected_a", line, column + ii, "/");
2031. 93 }
2032. 93
2033. 93// Lex/loop through each line until "*/".
2034. 93
2035. 730 while (true) {
2036. 730 // rx_star_slash
2037. 730 ii = line_source.indexOf("*/");
2038. 730 if (ii >= 0) {
2039. 730 break;
2040. 730 }
2041. 730 // rx_slash_star
2042. 730 ii = line_source.indexOf("/*");
2043. 730 if (ii >= 0) {
2044. 730
2045. 730// test_cause:
2046. 730// ["/*/*", "lex_comment", "nested_comment", "", 2]
2047. 730
2048. 730 warn_at("nested_comment", line, column + ii);
2049. 730 }
2050. 730 snippet.push(line_source);
2051. 730 line_source = read_line();
2052. 730 if (line_source === undefined) {
2053. 730
2054. 730// test_cause:
2055. 730// ["/*", "lex_comment", "unclosed_comment", "", 1]
2056. 730
2057. 730 return stop_at("unclosed_comment", line, column);
2058. 730 }
2059. 730 }
2060. 93 jj = line_source.slice(0, ii).search(
2061. 93 // rx_slash_star_or_slash
2062. 93 /\/\*|\/$/
2063. 93 );
2064. 93 if (jj >= 0) {
2065. 93
2066. 93// test_cause:
2067. 93// ["/*/**/", "lex_comment", "nested_comment", "", 2]
2068. 93
2069. 93 warn_at("nested_comment", line, column + jj);
2070. 93 }
2071. 93 snippet.push(line_source.slice(0, ii));
2072. 93 snippet = snippet.join(" ");
2073. 93 column += ii + 2;
2074. 93 line_source = line_source.slice(ii + 2);
2075. 93 the_comment = token_create("(comment)", snippet);
2076. 10018 }
2077. 10018
2078. 10018// Uncompleted work comment.
2079. 10018
2080. 10018 if (
2081. 10018 !option_dict.devel
2082. 10018 && (
2083. 10018 // rx_todo
2084. 10018 /\b(?:todo|TO\s?DO|HACK)\b/
2085. 10018 ).test(snippet)
2086. 16 ) {
2087. 16
2088. 16// test_cause:
2089. 16// ["//todo", "lex_comment", "todo_comment", "(comment)", 1] //jslint-quiet
2090. 16
2091. 16 warn("todo_comment", the_comment);
2092. 10018 }
2093. 10018
2094. 10018// Lex directives in comment.
2095. 10018
2096. 10018 [
2097. 10018 the_comment.directive, body
2098. 10018 ] = Array.from(snippet.match(
2099. 10018 // rx_directive
2100. 10018 /^(jslint|property|global)\s+(.*)$/
2101. 10018 ) || []).slice(1);
2102. 9960 if (the_comment.directive === undefined) {
2103. 9960 return the_comment;
2104. 9960 }
2105. 58 directive_list.push(the_comment);
2106. 58 if (!mode_directive) {
2107. 1
2108. 1// test_cause:
2109. 1// ["0\n/*global aa*/", "lex_comment", "misplaced_directive_a", "global", 1]
2110. 1
2111. 1 warn_at("misplaced_directive_a", line, from, the_comment.directive);
2112. 1 return the_comment;
2113. 57 }
2114. 57
2115. 57// lex_directive();
2116. 57// JSLint recognizes three directives that can be encoded in comments. This
2117. 57// function processes one item, and calls itself recursively to process the
2118. 57// next one.
2119. 57
2120. 57// Lex/loop through each directive in /*...*/
2121. 57
2122. 57 ii = 0;
2123. 57 body.replace((
2124. 57 // rx_directive_part
2125. 57 /([a-zA-Z$_][a-zA-Z0-9$_]*)(?::\s*(true|false))?,?\s*|$/g
2126. 1623 ), function (match0, key, val, jj) {
2127. 57 if (ii !== jj) {
2128. 57
2129. 57// test_cause:
2130. 57// ["/*jslint !*/", "lex_comment", "bad_directive_a", "!", 1]
2131. 57
2132. 57 return stop("bad_directive_a", the_comment, body.slice(ii));
2133. 1622 }
2134. 1622 if (match0 === "") {
2135. 57 return "";
2136. 1566 }
2137. 1566 ii += match0.length;
2138. 1566 switch (the_comment.directive) {
2139. 1566 case "global":
2140. 57 if (val) {
2141. 57
2142. 57// test_cause:
2143. 57// ["/*global aa:false*/", "lex_comment", "bad_option_a", "aa:false", 1]
2144. 57
2145. 57 warn("bad_option_a", the_comment, key + ":" + val);
2146. 57 }
2147. 57 global_dict[key] = "user-defined";
2148. 57
2149. 57// PR-347 - Disable warning "unexpected_directive_a".
2150. 57// state.mode_module = the_comment;
2151. 57
2152. 57 break;
2153. 76 case "jslint":
2154. 76 if (!option_set_item(key, val !== "false")) {
2155. 76
2156. 76// test_cause:
2157. 76// ["/*jslint undefined*/", "lex_comment", "bad_option_a", "undefined", 1]
2158. 76
2159. 76 warn("bad_option_a", the_comment, key);
2160. 76 }
2161. 76 break;
2162. 1488 case "property":
2163. 1488 state.mode_property = true;
2164. 1488 tenure[key] = true;
2165. 1488 break;
2166. 1566 }
2167. 1566 return "";
2168. 1566 });
2169. 57 return the_comment;
2170. 57 }
2171. 628
2172. 709 function lex_megastring() {
2173. 709 let id;
2174. 709 let match;
2175. 709
2176. 709// The token is a megastring. We don't allow any kind of mega nesting.
2177. 709
2178. 1 if (mode_mega) {
2179. 1
2180. 1// test_cause:
2181. 1// ["`${`", "lex_megastring", "expected_a_b", "`", 4]
2182. 1
2183. 1 return stop_at("expected_a_b", line, column, "}", "`");
2184. 708 }
2185. 708 from_mega = from;
2186. 708 line_mega = line;
2187. 708 mode_mega = true;
2188. 708 snippet = "";
2189. 708
2190. 708// Parsing a mega literal is tricky. First create a ` token.
2191. 708
2192. 708 token_create("`");
2193. 708 from += 1;
2194. 708
2195. 708// Then loop, building up a string, possibly from many lines, until seeing
2196. 708// the end of file, a closing `, or a ${ indicting an expression within the
2197. 708// string.
2198. 708
2199. 5443 while (true) {
2200. 5443 match = line_source.match(
2201. 5443
2202. 5443// Vim-hack - vim-editor has trouble parsing '`' in regexp
2203. 5443
2204. 5443 // rx_mega
2205. 5443 /[\u0060\\]|\$\{/
2206. 5443 ) || {
2207. 5443 "0": "",
2208. 5443 index: 0
2209. 5443 };
2210. 5443 snippet += line_source.slice(0, match.index);
2211. 5443 column += match.index;
2212. 5443 line_source = line_source.slice(match.index);
2213. 5443 match = match[0];
2214. 5443 switch (match) {
2215. 5443 case "${":
2216. 5443
2217. 5443// if either ` or ${ was found, then the preceding joins the snippet to become
2218. 5443// a string token.
2219. 5443
2220. 5443 token_create("(string)", snippet).quote = "`";
2221. 5443 snippet = "";
2222. 5443
2223. 5443// If ${, then create tokens that will become part of an expression until
2224. 5443// a } token is made.
2225. 5443
2226. 5443 column += 2;
2227. 5443 token_create("${");
2228. 5443 line_source = line_source.slice(2);
2229. 5443
2230. 5443// Lex/loop through each token inside megastring-expression `${...}`.
2231. 5443
2232. 5443 while (true) {
2233. 5443 id = lex_token().id;
2234. 5443 if (id === "{") {
2235. 5443
2236. 5443// test_cause:
2237. 5443// ["`${{", "lex_megastring", "expected_a_b", "{", 4]
2238. 5443
2239. 5443 return stop_at("expected_a_b", line, column, "}", "{");
2240. 5443 }
2241. 5443 if (id === "}") {
2242. 5443 break;
2243. 5443 }
2244. 5443 }
2245. 5443 break;
2246. 5443 case "\\":
2247. 5443 snippet += line_source.slice(0, 2);
2248. 5443 line_source = line_source.slice(2);
2249. 5443 column += 2;
2250. 5443 break;
2251. 5443 case "`":
2252. 5443
2253. 5443// if either ` or ${ was found, then the preceding joins the snippet to become
2254. 5443// a string token.
2255. 5443
2256. 5443 token_create("(string)", snippet).quote = "`";
2257. 5443 snippet = "";
2258. 5443
2259. 5443// Terminate megastring with `.
2260. 5443
2261. 5443 line_source = line_source.slice(1);
2262. 5443 column += 1;
2263. 5443 mode_mega = false;
2264. 5443 return token_create("`");
2265. 5443 default:
2266. 5443
2267. 5443// If neither ` nor ${ is seen, then the whole line joins the snippet.
2268. 5443
2269. 5443 snippet += line_source + "\n";
2270. 5443 if (read_line() === undefined) {
2271. 5443
2272. 5443// test_cause:
2273. 5443// ["`", "lex_megastring", "unclosed_mega", "", 1]
2274. 5443
2275. 5443 return stop_at("unclosed_mega", line_mega, from_mega);
2276. 5443 }
2277. 5443 }
2278. 5443 }
2279. 709 }
2280. 628
2281. 8597 function lex_number() {
2282. 8597 let prefix = snippet;
2283. 8597 char_after();
2284. 2812 switch (prefix === "0" && char) {
2285. 2 case "b":
2286. 4 case "o":
2287. 9 case "x":
2288. 9 read_digits(char);
2289. 9
2290. 9// PR-351 - Ignore BigInt suffix 'n'.
2291. 9
2292. 9 if (char === "n") {
2293. 9 char_after("n");
2294. 9 }
2295. 9 break;
2296. 8588 default:
2297. 8588 if (char === ".") {
2298. 8588 read_digits("d");
2299. 8588 }
2300. 8588 if (char === "E" || char === "e") {
2301. 8588 char_after(char);
2302. 8588 if (char !== "+" && char !== "-") {
2303. 8588 char_before();
2304. 8588 }
2305. 8588 read_digits("d");
2306. 8588 }
2307. 8597 }
2308. 8597
2309. 8597// If the next character after a number is a digit or letter, then something
2310. 8597// unexpected is going on.
2311. 8597
2312. 8597 if (
2313. 1475 (char >= "0" && char <= "9")
2314. 39 || (char >= "a" && char <= "z")
2315. 8596 || (char >= "A" && char <= "Z")
2316. 1 ) {
2317. 1
2318. 1// test_cause:
2319. 1// ["0a", "lex_number", "unexpected_a_after_b", "0", 2]
2320. 1
2321. 1 return stop_at(
2322. 1 "unexpected_a_after_b",
2323. 1 line,
2324. 1 column,
2325. 1 snippet.slice(-1),
2326. 1 snippet.slice(0, -1)
2327. 1 );
2328. 8596 }
2329. 8596 char_before();
2330. 8596 return token_create("(number)", snippet);
2331. 8596 }
2332. 628
2333. 402 function lex_regexp() {
2334. 402
2335. 402// Regexp
2336. 402// Lex a regular expression literal.
2337. 402
2338. 402 let flag;
2339. 402 let mode_regexp_multiline;
2340. 402 let result;
2341. 402 let value;
2342. 402 mode_regexp = true;
2343. 402
2344. 134 function lex_regexp_bracketed() {
2345. 134 let mode_regexp_range;
2346. 134
2347. 134// RegExp
2348. 134// Match a class.
2349. 134
2350. 134 char_after("[");
2351. 10 if (char === "^") {
2352. 10 char_after("^");
2353. 10 }
2354. 562 while (true) {
2355. 562
2356. 562// RegExp
2357. 562// Match a character in a character class.
2358. 562
2359. 562 switch (char) {
2360. 562 case "":
2361. 562 case "]":
2362. 562
2363. 562// test_cause:
2364. 562// ["aa=/[", "lex_regexp_bracketed", "closer", "", 0]
2365. 562// ["aa=/[]/", "lex_regexp_bracketed", "closer", "", 0]
2366. 562
2367. 562 test_cause("closer");
2368. 562 if (mode_regexp_range) {
2369. 562
2370. 562// test_cause:
2371. 562// ["aa=/[0-]/", "lex_regexp_bracketed", "unexpected_a", "-", 7]
2372. 562
2373. 562 warn_at("unexpected_a", line, column - 1, "-");
2374. 562 }
2375. 562 return char_after("]");
2376. 562
2377. 562// PR-362 - Relax regexp-warning against using <space>.
2378. 562// case " ":
2379. 562//
2380. 562// // test_cause:
2381. 562// // ["aa=/[ ]/", "lex_regexp_bracketed", "expected_a_b", " ", 6]
2382. 562//
2383. 562// warn_at("expected_a_b", line, column, "\\u0020", " ");
2384. 562// break;
2385. 562
2386. 562 case "-":
2387. 562 case "/":
2388. 562 case "[":
2389. 562 case "^":
2390. 562
2391. 562// test_cause:
2392. 562// ["aa=/[-]/", "lex_regexp_bracketed", "expected_a_before_b", "-", 6]
2393. 562// ["aa=/[.^]/", "lex_regexp_bracketed", "expected_a_before_b", "^", 7]
2394. 562// ["aa=/[/", "lex_regexp_bracketed", "expected_a_before_b", "/", 6]
2395. 562// ["aa=/[\\\\/]/", "lex_regexp_bracketed", "expected_a_before_b", "/", 8]
2396. 562// ["aa=/[\\\\[]/", "lex_regexp_bracketed", "expected_a_before_b", "[", 8]
2397. 562
2398. 562 warn_at("expected_a_before_b", line, column, "\\", char);
2399. 562 break;
2400. 562 case "\\":
2401. 562 char_after_escape("BbDdSsWw-[]^");
2402. 562 char_before();
2403. 562 break;
2404. 562 case "`":
2405. 562 if (mode_mega) {
2406. 562
2407. 562// test_cause:
2408. 562// ["`${/[`]/}`", "lex_regexp_bracketed", "unexpected_a", "`", 6]
2409. 562
2410. 562 warn_at("unexpected_a", line, column, "`");
2411. 562 }
2412. 562 break;
2413. 562 }
2414. 562 char_after();
2415. 562 mode_regexp_range = false;
2416. 562 if (char === "-") {
2417. 562
2418. 562// RegExp
2419. 562// Match a range of subclasses.
2420. 562
2421. 562 mode_regexp_range = true;
2422. 562 char_after("-");
2423. 562 }
2424. 562 }
2425. 134 }
2426. 402
2427. 551 function lex_regexp_group() {
2428. 551
2429. 551// RegExp
2430. 551// Lex sequence of characters in regexp.
2431. 551
2432. 551 switch (char) {
2433. 1 case "":
2434. 1 warn_at("expected_regexp_factor_a", line, column, char);
2435. 1 break;
2436. 1 case ")":
2437. 1 warn_at("expected_regexp_factor_a", line, column, char);
2438. 1 break;
2439. 1 case "]":
2440. 1
2441. 1// test_cause:
2442. 1// ["/ /", "lex_regexp_group", "expected_regexp_factor_a", "", 3]
2443. 1// ["aa=/)", "lex_regexp_group", "expected_regexp_factor_a", ")", 5]
2444. 1// ["aa=/]", "lex_regexp_group", "expected_regexp_factor_a", "]", 5]
2445. 1
2446. 1 warn_at("expected_regexp_factor_a", line, column, char);
2447. 1 break;
2448. 551 }
2449. 3728 while (true) {
2450. 3728 switch (char) {
2451. 3728 case "":
2452. 3728 case ")":
2453. 3728 case "/":
2454. 3728 case "]":
2455. 3728 return;
2456. 3728
2457. 3728// PR-362 - Relax regexp-warning against using <space>.
2458. 3728// case " ":
2459. 3728//
2460. 3728// // test_cause:
2461. 3728// // ["aa=/ /", "lex_regexp_group", "expected_a_b", " ", 5]
2462. 3728//
2463. 3728// warn_at("expected_a_b", line, column, "\\s", " ");
2464. 3728// char_after();
2465. 3728// break;
2466. 3728
2467. 3728 case "$":
2468. 3728 if (line_source[0] !== "/") {
2469. 3728 mode_regexp_multiline = true;
2470. 3728 }
2471. 3728 char_after();
2472. 3728 break;
2473. 3728 case "(":
2474. 3728
2475. 3728// RegExp
2476. 3728// Match a group that starts with left paren.
2477. 3728
2478. 3728 char_after("(");
2479. 3728 if (char === "?") {
2480. 3728 char_after("?");
2481. 3728 if (char === "=" || char === "!") {
2482. 3728 char_after();
2483. 3728 } else {
2484. 3728 char_after(":");
2485. 3728 }
2486. 3728 } else if (char === ":") {
2487. 3728
2488. 3728// test_cause:
2489. 3728// ["aa=/(:)/", "lex_regexp_group", "expected_a_before_b", ":", 6]
2490. 3728// ["aa=/?/", "lex_regexp_group", "expected_a_before_b", "?", 5]
2491. 3728
2492. 3728 warn_at("expected_a_before_b", line, column, "?", ":");
2493. 3728 }
2494. 3728
2495. 3728// RegExp
2496. 3728// Recurse lex_regexp_group().
2497. 3728
2498. 3728 lex_regexp_group();
2499. 3728 char_after(")");
2500. 3728 break;
2501. 3728 case "*":
2502. 3728 case "+":
2503. 3728 case "?":
2504. 3728 case "{":
2505. 3728 case "}":
2506. 3728
2507. 3728// test_cause:
2508. 3728// ["aa=/+/", "lex_regexp_group", "expected_a_before_b", "+", 5]
2509. 3728// ["aa=/.**/", "lex_regexp_group", "expected_a_before_b", "*", 7]
2510. 3728// ["aa=/?/", "lex_regexp_group", "expected_a_before_b", "?", 5]
2511. 3728// ["aa=/{/", "lex_regexp_group", "expected_a_before_b", "{", 5]
2512. 3728// ["aa=/}/", "lex_regexp_group", "expected_a_before_b", "}", 5]
2513. 3728
2514. 3728 warn_at("expected_a_before_b", line, column, "\\", char);
2515. 3728 char_after();
2516. 3728 break;
2517. 3728 case "[":
2518. 3728 lex_regexp_bracketed();
2519. 3728 break;
2520. 3728 case "\\":
2521. 3728
2522. 3728// test_cause:
2523. 3728// ["aa=/\\/", "lex_regexp_group", "escape", "", 0]
2524. 3728
2525. 3728 test_cause("escape");
2526. 3728 char_after_escape("BbDdSsWw^${}[]():=!.|*+?");
2527. 3728 break;
2528. 3728 case "^":
2529. 3728 if (snippet !== "^") {
2530. 3728 mode_regexp_multiline = true;
2531. 3728 }
2532. 3728 char_after();
2533. 3728 break;
2534. 3728 case "`":
2535. 3728 if (mode_mega) {
2536. 3728
2537. 3728// test_cause:
2538. 3728// ["`${/`/}`", "lex_regexp_group", "unexpected_a", "`", 5]
2539. 3728
2540. 3728 warn_at("unexpected_a", line, column, "`");
2541. 3728 }
2542. 3728 char_after();
2543. 3728 break;
2544. 3728 default:
2545. 3728 char_after();
2546. 3728 }
2547. 3728
2548. 3728// RegExp
2549. 3728// Match an optional quantifier.
2550. 3728
2551. 3728 switch (char) {
2552. 3728 case "*":
2553. 3728 case "+":
2554. 3728 if (char_after(char) === "?") {
2555. 3728
2556. 3728// test_cause:
2557. 3728// ["aa=/.*?/", "lex_regexp_group", "?", "", 0]
2558. 3728// ["aa=/.+?/", "lex_regexp_group", "?", "", 0]
2559. 3728
2560. 3728 test_cause("?");
2561. 3728 char_after("?");
2562. 3728 }
2563. 3728 break;
2564. 3728 case "?":
2565. 3728 if (char_after("?") === "?") {
2566. 3728
2567. 3728// test_cause:
2568. 3728// ["aa=/.??/", "lex_regexp_group", "unexpected_a", "?", 7]
2569. 3728
2570. 3728 warn_at("unexpected_a", line, column, char);
2571. 3728 char_after("?");
2572. 3728 }
2573. 3728 break;
2574. 3728 case "{":
2575. 3728 if (read_digits("d", true) === 0) {
2576. 3728
2577. 3728// test_cause:
2578. 3728// ["aa=/aa{/", "lex_regexp_group", "expected_a_before_b", ",", 8]
2579. 3728
2580. 3728 warn_at("expected_a_before_b", line, column, "0", ",");
2581. 3728 }
2582. 3728 if (char === ",") {
2583. 3728
2584. 3728// test_cause:
2585. 3728// ["aa=/.{,/", "lex_regexp_group", "comma", "", 0]
2586. 3728
2587. 3728 test_cause("comma");
2588. 3728 read_digits("d", true);
2589. 3728 }
2590. 3728 if (char_after("}") === "?") {
2591. 3728
2592. 3728// test_cause:
2593. 3728// ["aa=/.{0}?/", "lex_regexp_group", "unexpected_a", "?", 9]
2594. 3728
2595. 3728 warn_at("unexpected_a", line, column, char);
2596. 3728 char_after("?");
2597. 3728 }
2598. 3728 break;
2599. 3728 }
2600. 3728 }
2601. 551 }
2602. 402
2603. 402// RegExp
2604. 402// Scan the regexp literal. Give a warning if the first character is = because
2605. 402// /= looks like a division assignment operator.
2606. 402
2607. 402 snippet = "";
2608. 402 char_after();
2609. 1 if (char === "=") {
2610. 1
2611. 1// test_cause:
2612. 1// ["aa=/=/", "lex_regexp", "expected_a_before_b", "=", 5]
2613. 1
2614. 1 warn_at("expected_a_before_b", line, column, "\\", "=");
2615. 1 }
2616. 402 lex_regexp_group();
2617. 402
2618. 402// RegExp
2619. 402// Remove last character from snippet.
2620. 402
2621. 402 snippet = snippet.slice(0, -1);
2622. 402
2623. 402// RegExp
2624. 402// Make sure there is a closing slash.
2625. 402
2626. 402 value = snippet;
2627. 402 char_after("/");
2628. 402
2629. 402// RegExp
2630. 402// Create flag.
2631. 402
2632. 402 flag = empty();
2633. 402 while (
2634. 402
2635. 402// Regexp
2636. 402// char is a letter.
2637. 402
2638. 274 (char >= "a" && char <= "z\uffff")
2639. 392 || (char >= "A" && char <= "Z\uffff")
2640. 272 ) {
2641. 272
2642. 272// RegExp
2643. 272// Process dangling flag letters.
2644. 272
2645. 272 switch (!flag[char] && char) {
2646. 272 case "g":
2647. 272 break;
2648. 272 case "i":
2649. 272 break;
2650. 272 case "m":
2651. 272 break;
2652. 272 case "u":
2653. 272 break;
2654. 272 case "y":
2655. 272
2656. 272// test_cause:
2657. 272// ["aa=/./gimuy", "lex_regexp", "flag", "", 0]
2658. 272
2659. 272 test_cause("flag");
2660. 272 break;
2661. 272 default:
2662. 272
2663. 272// test_cause:
2664. 272// ["aa=/./gg", "lex_regexp", "unexpected_a", "g", 8]
2665. 272// ["aa=/./z", "lex_regexp", "unexpected_a", "z", 7]
2666. 272
2667. 272 warn_at("unexpected_a", line, column, char);
2668. 272 }
2669. 272 flag[char] = true;
2670. 272 char_after();
2671. 392 }
2672. 392 char_before();
2673. 392 if (char === "/" || char === "*") {
2674. 1
2675. 1// test_cause:
2676. 1// ["aa=/.//", "lex_regexp", "unexpected_a", "/", 3]
2677. 1
2678. 1 return stop_at("unexpected_a", line, from, char);
2679. 391 }
2680. 391 result = token_create("(regexp)", char);
2681. 391 result.flag = flag;
2682. 391 result.value = value;
2683. 391 if (mode_regexp_multiline && !flag.m) {
2684. 1
2685. 1// test_cause:
2686. 1// ["aa=/$^/", "lex_regexp", "missing_m", "", 7]
2687. 1
2688. 1 warn_at("missing_m", line, column);
2689. 391 }
2690. 391 return result;
2691. 391 }
2692. 628
2693. 416 function lex_slash_or_regexp() {
2694. 416
2695. 416// The / can be a division operator or the beginning of a regular expression
2696. 416// literal. It is not possible to know which without doing a complete parse.
2697. 416// We want to complete the tokenization before we begin to parse, so we will
2698. 416// estimate. This estimator can fail in some cases. For example, it cannot
2699. 416// know if "}" is ending a block or ending an object literal, so it can
2700. 416// behave incorrectly in that case; it is not meaningful to divide an
2701. 416// object, so it is likely that we can get away with it. We avoided the worst
2702. 416// cases by eliminating automatic semicolon insertion.
2703. 416
2704. 416 let the_token;
2705. 416 switch (
2706. 416 token_prv_expr.identifier
2707. 17 && !token_prv_expr.dot
2708. 15 && token_prv_expr.id
2709. 416 ) {
2710. 1 case "case":
2711. 2 case "delete":
2712. 3 case "in":
2713. 4 case "instanceof":
2714. 5 case "new":
2715. 6 case "typeof":
2716. 7 case "void":
2717. 8 case "yield":
2718. 8 the_token = lex_regexp();
2719. 8
2720. 8// test_cause:
2721. 8// ["case /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
2722. 8// ["delete /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
2723. 8// ["in /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 4]
2724. 8// ["instanceof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 12]
2725. 8// ["new /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 5]
2726. 8// ["typeof /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 8]
2727. 8// ["void /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 6]
2728. 8// ["yield /./", "lex_slash_or_regexp", "unexpected_a", "(regexp)", 7]
2729. 8
2730. 8 return stop("unexpected_a", the_token);
2731. 1 case "return":
2732. 1 return lex_regexp();
2733. 407 }
2734. 407 switch (!token_prv_expr.identifier && token_prv_expr.id.slice(-1)) {
2735. 1 case "!":
2736. 2 case "%":
2737. 4 case "&":
2738. 5 case "*":
2739. 6 case "+":
2740. 7 case "-":
2741. 9 case "/":
2742. 10 case ";":
2743. 11 case "<":
2744. 12 case ">":
2745. 13 case "^":
2746. 16 case "{":
2747. 17 case "|":
2748. 18 case "}":
2749. 19 case "~":
2750. 19 the_token = lex_regexp();
2751. 19
2752. 19// test_cause:
2753. 19// ["!/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2754. 19// ["%/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2755. 19// ["&/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2756. 19// ["+/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2757. 19// ["-/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2758. 19// ["0 * /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
2759. 19// ["0 / /./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 5]
2760. 19// [";/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2761. 19// ["</./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2762. 19// [">/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2763. 19// ["^/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2764. 19// ["{/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2765. 19// ["|/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2766. 19// ["}/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2767. 19// ["~/./", "lex_slash_or_regexp", "wrap_regexp", "(regexp)", 2]
2768. 19
2769. 19 warn("wrap_regexp", the_token);
2770. 19 return the_token;
2771. 333 case "(":
2772. 334 case ",":
2773. 335 case ":":
2774. 372 case "=":
2775. 373 case "?":
2776. 374 case "[":
2777. 374
2778. 374// test_cause:
2779. 374// ["(/./", "lex_slash_or_regexp", "recurse", "", 0]
2780. 374// [",/./", "lex_slash_or_regexp", "recurse", "", 0]
2781. 374// [":/./", "lex_slash_or_regexp", "recurse", "", 0]
2782. 374// ["=/./", "lex_slash_or_regexp", "recurse", "", 0]
2783. 374// ["?/./", "lex_slash_or_regexp", "recurse", "", 0]
2784. 374// ["aa[/./", "lex_slash_or_regexp", "recurse", "", 0]
2785. 374
2786. 374 test_cause("recurse");
2787. 374 return lex_regexp();
2788. 14 }
2789. 14 if (line_source[0] === "=") {
2790. 1 column += 1;
2791. 1 line_source = line_source.slice(1);
2792. 1 snippet = "/=";
2793. 1 warn_at("unexpected_a", line, column, "/=");
2794. 14 }
2795. 14 return token_create(snippet);
2796. 14 }
2797. 628
2798. 23090 function lex_string(quote) {
2799. 23090
2800. 23090// Create a string token.
2801. 23090
2802. 23090 let the_token;
2803. 23088 if (!option_dict.single && quote === "'") {
2804. 2
2805. 2// test_cause:
2806. 2// ["''", "lex_string", "use_double", "", 1]
2807. 2
2808. 2 warn_at("use_double", line, column);
2809. 2 }
2810. 23090 snippet = "";
2811. 23090 char_after();
2812. 23090
2813. 23090// Lex/loop through each character in "...".
2814. 23090
2815. 202707 while (true) {
2816. 202707 switch (char) {
2817. 202707 case "":
2818. 202707
2819. 202707// test_cause:
2820. 202707// ["\"", "lex_string", "unclosed_string", "", 1]
2821. 202707
2822. 202707 return stop_at("unclosed_string", line, column);
2823. 202707 case "\\":
2824. 202707 char_after_escape(quote);
2825. 202707 break;
2826. 202707 case "`":
2827. 202707 if (mode_mega) {
2828. 202707
2829. 202707// test_cause:
2830. 202707// ["`${\"`\"}`", "lex_string", "unexpected_a", "`", 5]
2831. 202707
2832. 202707 warn_at("unexpected_a", line, column, "`");
2833. 202707 }
2834. 202707 char_after("`");
2835. 202707 break;
2836. 202707 case quote:
2837. 202707
2838. 202707// Remove last character from snippet.
2839. 202707
2840. 202707 snippet = snippet.slice(0, -1);
2841. 202707 the_token = token_create("(string)", snippet);
2842. 202707 the_token.quote = quote;
2843. 202707 return the_token;
2844. 202707 default:
2845. 202707 char_after();
2846. 202707 }
2847. 202707 }
2848. 23090 }
2849. 628
2850. 236979 function lex_token() {
2851. 236979 let match;
2852. 236979
2853. 236979// Lex/loop through each whitespace.
2854. 236979
2855. 354078 while (true) {
2856. 354078
2857. 354078// Lex/loop through each blank-line.
2858. 354078
2859. 354078 while (!line_source) {
2860. 354078 line_source = read_line();
2861. 354078 from = 0;
2862. 354078 if (line_source === undefined) {
2863. 354078 return (
2864. 354078 mode_mega
2865. 354078
2866. 354078// test_cause:
2867. 354078// ["`${//}`", "lex_token", "unclosed_mega", "", 1]
2868. 354078
2869. 354078 ? stop_at("unclosed_mega", line_mega, from_mega)
2870. 354078 : line_disable !== undefined
2871. 354078
2872. 354078// test_cause:
2873. 354078// ["/*jslint-disable*/", "lex_token", "unclosed_disable", "", 1]
2874. 354078
2875. 354078 ? stop_at("unclosed_disable", line_disable)
2876. 354078 : token_create("(end)")
2877. 354078 );
2878. 354078 }
2879. 354078 }
2880. 354078 from = column;
2881. 354078 match = line_source.match(rx_token);
2882. 354078
2883. 354078// match[1] token
2884. 354078// match[2] whitespace
2885. 354078// match[3] identifier
2886. 354078// match[4] number
2887. 354078// match[5] rest
2888. 354078
2889. 354078 if (!match) {
2890. 354078
2891. 354078// test_cause:
2892. 354078// ["#", "lex_token", "unexpected_char_a", "#", 1]
2893. 354078
2894. 354078 return stop_at(
2895. 354078 "unexpected_char_a",
2896. 354078 line,
2897. 354078 column,
2898. 354078 line_source[0]
2899. 354078 );
2900. 354078 }
2901. 354078 snippet = match[1];
2902. 354078 column += snippet.length;
2903. 354078 line_source = match[5];
2904. 354078 if (!match[2]) {
2905. 354078 break;
2906. 354078 }
2907. 354078 }
2908. 236376
2909. 236376// The token is an identifier.
2910. 236376
2911. 236376 if (match[3]) {
2912. 63540 return token_create(snippet, undefined, true);
2913. 172836 }
2914. 172836
2915. 172836// Create token from number.
2916. 172836
2917. 172836 if (match[4]) {
2918. 8597 return lex_number();
2919. 164239 }
2920. 164239
2921. 164239// Create token from string "..." or '...'.
2922. 164239
2923. 164239 if (snippet === "\"" || snippet === "'") {
2924. 23090 return lex_string(snippet);
2925. 141149 }
2926. 141149
2927. 141149// Create token from megastring `...`.
2928. 141149
2929. 141149 if (snippet === "`") {
2930. 709 return lex_megastring();
2931. 140440 }
2932. 140440
2933. 140440// Create token from comment /*...*/ or //....
2934. 140440
2935. 140440 if (snippet === "/*" || snippet === "//") {
2936. 10021 return lex_comment();
2937. 130419 }
2938. 130419
2939. 130419// Create token from slash /.
2940. 130419
2941. 130419 if (snippet === "/") {
2942. 416 return lex_slash_or_regexp();
2943. 130003 }
2944. 130003 return token_create(snippet);
2945. 130003 }
2946. 628
2947. 2490 function option_set_item(key, val) {
2948. 2490
2949. 2490// These are the options that are recognized in the option object or that may
2950. 2490// appear in a /*jslint*/ directive. Most options will have a boolean value,
2951. 2490// usually true. Some options will also predefine some number of global
2952. 2490// variables.
2953. 2490
2954. 2490 switch (key) {
2955. 619 case "beta": // Enable experimental warnings.
2956. 621 case "bitwise": // Allow bitwise operators.
2957. 624 case "browser": // Assume browser environment.
2958. 626 case "convert": // Allow conversion operators.
2959. 628 case "couch": // Assume CouchDb environment.
2960. 630 case "devel": // Allow console.log() and friends.
2961. 1886 case "ecma": // Assume ECMAScript environment.
2962. 1890 case "eval": // Allow eval().
2963. 1895 case "for": // Allow for-statement.
2964. 1901 case "getset": // Allow get() and set().
2965. 1906 case "indent2": // Use 2-space indent.
2966. 1908 case "long": // Allow long lines.
2967. 1910 case "name": // Allow weird property names.
2968. 1944 case "node": // Assume Node.js environment.
2969. 1946 case "single": // Allow single-quote strings.
2970. 2443 case "test_cause": // Test jslint's causes.
2971. 2444 case "test_internal_error": // Test jslint's internal-error
2972. 2490 // ... handling-ability.
2973. 2446 case "this": // Allow 'this'.
2974. 2449 case "trace": // Include jslint stack-trace in warnings.
2975. 2453 case "unordered": // Allow unordered cases, params, properties,
2976. 2490 // ... and variables.
2977. 2457 case "variable": // Allow unordered const and let declarations
2978. 2490 // ... that are not at top of function-scope.
2979. 2459 case "white": // Allow messy whitespace.
2980. 2459 option_dict[key] = val;
2981. 2459 break;
2982. 31 default:
2983. 31 return false;
2984. 2459 }
2985. 2459
2986. 2459// Initialize global-variables.
2987. 2459
2988. 2459 switch (val && key) {
2989. 2490
2990. 2490// Assign global browser variables to global_dict.
2991. 2490// /*jslint beta, browser, devel*/
2992. 2490// console.log(JSON.stringify(Array.from([
2993. 2490// ...
2994. 2490// ]).filter(function (key) {
2995. 2490// return window.hasOwnProperty(key);
2996. 2490// }), undefined, 4));
2997. 2490
2998. 2 case "browser":
2999. 2 object_assign_from_list(global_dict, [
3000. 2
3001. 2// Shared with Node.js.
3002. 2
3003. 2 "AbortController",
3004. 2 "DOMException",
3005. 2 "Event",
3006. 2 "EventTarget",
3007. 2 "MessageChannel",
3008. 2 "MessageEvent",
3009. 2 "MessagePort",
3010. 2 "TextDecoder",
3011. 2 "TextEncoder",
3012. 2 "URL",
3013. 2 "URLSearchParams",
3014. 2 "WebAssembly",
3015. 2 // "atob",
3016. 2 // "btoa",
3017. 2 "clearInterval",
3018. 2 "clearTimeout",
3019. 2 // "console",
3020. 2 "performance",
3021. 2 "queueMicrotask",
3022. 2 "setInterval",
3023. 2 "setTimeout",
3024. 2
3025. 2// Browser only.
3026. 2
3027. 2 // "CharacterData",
3028. 2 // "DocumentType",
3029. 2 // "Element",
3030. 2 // "Event",
3031. 2 "FileReader",
3032. 2 // "FontFace",
3033. 2 "FormData",
3034. 2 "IntersectionObserver",
3035. 2 "MutationObserver",
3036. 2 // "Storage",
3037. 2 // "TextDecoder",
3038. 2 // "TextEncoder",
3039. 2 // "URL",
3040. 2 "Worker",
3041. 2 "XMLHttpRequest",
3042. 2 // "caches",
3043. 2 // "clearInterval",
3044. 2 // "clearTimeout",
3045. 2 "document",
3046. 2 // "event",
3047. 2 "fetch",
3048. 2 // "history",
3049. 2 "localStorage",
3050. 2 "location",
3051. 2 // "name",
3052. 2 "navigator",
3053. 2 // "screen",
3054. 2 "sessionStorage",
3055. 2 // "setInterval",
3056. 2 // "setTimeout",
3057. 2 "window"
3058. 2 ], "browser");
3059. 2 break;
3060. 2490
3061. 2490// https://docs.couchdb.org/en/stable/query-server/javascript.html#javascript
3062. 2490
3063. 2 case "couch":
3064. 2 object_assign_from_list(global_dict, [
3065. 2 "emit",
3066. 2 "getRow",
3067. 2 "isArray",
3068. 2 "log",
3069. 2 "provides",
3070. 2 "registerType",
3071. 2 "require",
3072. 2 "send",
3073. 2 "start",
3074. 2 "sum",
3075. 2 "toJSON"
3076. 2 ], "CouchDb");
3077. 2 break;
3078. 2 case "devel":
3079. 2 object_assign_from_list(global_dict, [
3080. 2 "alert", "confirm", "console", "prompt"
3081. 2 ], "development");
3082. 2 break;
3083. 2490
3084. 2490// These are the globals that are provided by the language standard.
3085. 2490// Assign global ECMAScript variables to global_dict.
3086. 2490/*
3087. 2490node --input-type=module -e '
3088. 2490// /\*jslint beta, node*\/
3089. 2490import https from "https";
3090. 2490(async function () {
3091. 2490 let dict = {import: true};
3092. 2490 let result = "";
3093. 2490 await new Promise(function (resolve) {
3094. 2490 https.get((
3095. 2490 "https://raw.githubusercontent.com/mdn/content/main/files/"
3096. 2490 + "en-us/web/javascript/reference/global_objects/index.md"
3097. 2490 ), function (res) {
3098. 2490 res.on("data", function (chunk) {
3099. 2490 result += chunk;
3100. 2490 }).on("end", resolve).setEncoding("utf8");
3101. 2490 });
3102. 2490 });
3103. 2490 result.replace((
3104. 2490 /\n- \{\{JSxRef\("(?:Global_Objects\/)?([^"\/]+?)"/g
3105. 2490 ), function (ignore, key) {
3106. 2490 if (globalThis.hasOwnProperty(key)) {
3107. 2490 dict[key] = true;
3108. 2490 }
3109. 2490 return "";
3110. 2490 });
3111. 2490 console.log(JSON.stringify(Object.keys(dict).sort(), undefined, 4));
3112. 2490}());
3113. 2490'
3114. 2490*/
3115. 2490
3116. 1256 case "ecma":
3117. 1256 object_assign_from_list(global_dict, [
3118. 1256 "Array",
3119. 1256 "ArrayBuffer",
3120. 1256 "Atomics",
3121. 1256 "BigInt",
3122. 1256 "BigInt64Array",
3123. 1256 "BigUint64Array",
3124. 1256 "Boolean",
3125. 1256 "DataView",
3126. 1256 "Date",
3127. 1256 "Error",
3128. 1256 "EvalError",
3129. 1256 "Float32Array",
3130. 1256 "Float64Array",
3131. 1256 "Function",
3132. 1256 "Infinity",
3133. 1256 "Int16Array",
3134. 1256 "Int32Array",
3135. 1256 "Int8Array",
3136. 1256 "Intl",
3137. 1256 "JSON",
3138. 1256 "Map",
3139. 1256 "Math",
3140. 1256 "NaN",
3141. 1256 "Number",
3142. 1256 "Object",
3143. 1256 "Promise",
3144. 1256 "Proxy",
3145. 1256 "RangeError",
3146. 1256 "ReferenceError",
3147. 1256 "Reflect",
3148. 1256 "RegExp",
3149. 1256 "Set",
3150. 1256 "SharedArrayBuffer",
3151. 1256 "String",
3152. 1256 "Symbol",
3153. 1256 "SyntaxError",
3154. 1256 "TypeError",
3155. 1256 "URIError",
3156. 1256 "Uint16Array",
3157. 1256 "Uint32Array",
3158. 1256 "Uint8Array",
3159. 1256 "Uint8ClampedArray",
3160. 1256 "WeakMap",
3161. 1256 "WeakSet",
3162. 1256 "WebAssembly",
3163. 1256 "decodeURI",
3164. 1256 "decodeURIComponent",
3165. 1256 "encodeURI",
3166. 1256 "encodeURIComponent",
3167. 1256 "eval",
3168. 1256 "globalThis",
3169. 1256 "import",
3170. 1256 "isFinite",
3171. 1256 "isNaN",
3172. 1256 "parseFloat",
3173. 1256 "parseInt",
3174. 1256 "undefined"
3175. 1256 ], "ECMAScript");
3176. 1256 break;
3177. 2490
3178. 2490// Assign global Node.js variables to global_dict.
3179. 2490/*
3180. 2490node --input-type=module -e '
3181. 2490// /\*jslint beta, node*\/
3182. 2490import moduleHttps from "https";
3183. 2490(async function () {
3184. 2490 let dict = {};
3185. 2490 let result = "";
3186. 2490 await new Promise(function (resolve) {
3187. 2490 moduleHttps.get((
3188. 2490 "https://raw.githubusercontent.com/nodejs/node/master/doc/api/"
3189. 2490 + "globals.md"
3190. 2490 ), function (res) {
3191. 2490 res.on("data", function (chunk) {
3192. 2490 result += chunk;
3193. 2490 }).on("end", resolve).setEncoding("utf8");
3194. 2490 });
3195. 2490 });
3196. 2490 result.replace((
3197. 2490 /\n(?:\* \[`|## |## Class: )`\w+/g
3198. 2490 ), function (match0) {
3199. 2490 dict[match0.split("`")[1]] = true;
3200. 2490 return "";
3201. 2490 });
3202. 2490 console.log(JSON.stringify(Object.keys(dict).sort(), undefined, 4));
3203. 2490}());
3204. 2490'
3205. 2490*/
3206. 2490
3207. 34 case "node":
3208. 34 object_assign_from_list(global_dict, [
3209. 34 "AbortController",
3210. 34 "Buffer",
3211. 34 "DOMException",
3212. 34 "Event",
3213. 34 "EventTarget",
3214. 34 "MessageChannel",
3215. 34 "MessageEvent",
3216. 34 "MessagePort",
3217. 34 "TextDecoder",
3218. 34 "TextEncoder",
3219. 34 "URL",
3220. 34 "URLSearchParams",
3221. 34 "WebAssembly",
3222. 34 "__dirname",
3223. 34 "__filename",
3224. 34 // "atob",
3225. 34 // "btoa",
3226. 34 "clearImmediate",
3227. 34 "clearInterval",
3228. 34 "clearTimeout",
3229. 34 "console",
3230. 34 "exports",
3231. 34 "global",
3232. 34 "module",
3233. 34 "performance",
3234. 34 "process",
3235. 34 "queueMicrotask",
3236. 34 "require",
3237. 34 "setImmediate",
3238. 34 "setInterval",
3239. 34 "setTimeout"
3240. 34 ], "Node.js");
3241. 34 break;
3242. 2459 }
3243. 2459 return true;
3244. 2459 }
3245. 628
3246. 323 function read_digits(base, quiet) {
3247. 323 let digits = line_source.match(
3248. 323 base === "b"
3249. 2 ? (
3250. 2 // rx_bits
3251. 2 /^[01]*/
3252. 2 )
3253. 321 : base === "o"
3254. 321 ? (
3255. 321 // rx_octals
3256. 321 /^[0-7]*/
3257. 321 )
3258. 321 : base === "x"
3259. 321 ? (
3260. 321 // rx_hexs
3261. 321 /^[0-9A-F]*/i
3262. 321 )
3263. 321 : (
3264. 321 // rx_digits
3265. 321 /^[0-9]*/
3266. 321 )
3267. 323 )[0];
3268. 323 let length = digits.length;
3269. 46 if (!quiet && length === 0) {
3270. 1
3271. 1// test_cause:
3272. 1// ["0x", "read_digits", "expected_digits_after_a", "0x", 2]
3273. 1
3274. 1 warn_at("expected_digits_after_a", line, column, snippet);
3275. 1 }
3276. 323 column += length;
3277. 323 line_source = line_source.slice(length);
3278. 323 snippet += digits;
3279. 323 char_after();
3280. 323 return length;
3281. 323 }
3282. 628
3283. 88763 function read_line() {
3284. 88763
3285. 88763// Put the next line of source in line_source. If the line contains tabs,
3286. 88763// replace them with spaces and give a warning. Also warn if the line contains
3287. 88763// unsafe characters or is too damn long.
3288. 88763
3289. 88763 if (
3290. 88763 !option_dict.long
3291. 88759 && line_whole.length > 80
3292. 46 && line_disable === undefined
3293. 46 && !state.mode_json
3294. 12 && token_1
3295. 12 && !mode_regexp
3296. 8 ) {
3297. 8
3298. 8// test_cause:
3299. 8// ["/////////////////////////////////////////////////////////////////////////////////", "read_line", "too_long", "", 1] //jslint-quiet
3300. 8
3301. 8 warn_at("too_long", line);
3302. 8 }
3303. 88763 column = 0;
3304. 88763 line += 1;
3305. 88763 mode_regexp = false;
3306. 88763 line_source = undefined;
3307. 88763 line_whole = "";
3308. 605 if (line_list[line] === undefined) {
3309. 605 return line_source;
3310. 88158 }
3311. 88158 line_source = line_list[line].line_source;
3312. 88158 line_whole = line_source;
3313. 88158
3314. 88158// Scan each line for following ignore-directives:
3315. 88158// "/*jslint-disable*/"
3316. 88158// "/*jslint-enable*/"
3317. 88158// "//jslint-quiet"
3318. 88158
3319. 88158 if (line_source === "/*jslint-disable*/") {
3320. 4
3321. 4// test_cause:
3322. 4// ["/*jslint-disable*/", "read_line", "jslint_disable", "", 0]
3323. 4
3324. 4 test_cause("jslint_disable");
3325. 4 line_disable = line;
3326. 88154 } else if (line_source === "/*jslint-enable*/") {
3327. 88154 if (line_disable === undefined) {
3328. 88154
3329. 88154// test_cause:
3330. 88154// ["/*jslint-enable*/", "read_line", "unopened_enable", "", 1]
3331. 88154
3332. 88154 stop_at("unopened_enable", line);
3333. 88154 }
3334. 88154 line_disable = undefined;
3335. 88154 } else if (line_source.endsWith(" //jslint-quiet")) {
3336. 88154
3337. 88154// test_cause:
3338. 88154// ["0 //jslint-quiet", "read_line", "jslint_quiet", "", 0]
3339. 88154
3340. 88154 test_cause("jslint_quiet");
3341. 88154 line_list[line].directive_quiet = true;
3342. 88157 }
3343. 88157 if (line_disable !== undefined) {
3344. 6
3345. 6// test_cause:
3346. 6// ["/*jslint-disable*/\n0", "read_line", "line_disable", "", 0]
3347. 6
3348. 6 test_cause("line_disable");
3349. 6 line_source = "";
3350. 88157 }
3351. 88157 if (line_source.indexOf("\t") >= 0) {
3352. 3 if (!option_dict.white) {
3353. 3
3354. 3// test_cause:
3355. 3// ["\t", "read_line", "use_spaces", "", 1]
3356. 3
3357. 3 warn_at("use_spaces", line, line_source.indexOf("\t") + 1);
3358. 3 }
3359. 3 line_source = line_source.replace((
3360. 3 // rx_tab
3361. 3 /\t/g
3362. 3 ), " ");
3363. 88157 }
3364. 88157 if (!option_dict.white && line_source.endsWith(" ")) {
3365. 2
3366. 2// test_cause:
3367. 2// [" ", "read_line", "unexpected_trailing_space", "", 1]
3368. 2
3369. 2 warn_at("unexpected_trailing_space", line, line_source.length - 1);
3370. 88157 }
3371. 88157 return line_source;
3372. 88157 }
3373. 628
3374. 239621 function token_create(id, value, identifier) {
3375. 239621
3376. 239621// Create the token object and append it to token_list.
3377. 239621
3378. 239621 let the_token = {
3379. 239621 from,
3380. 239621 id,
3381. 239621 identifier: Boolean(identifier),
3382. 239621 line,
3383. 239621 nr: token_list.length,
3384. 239621 thru: column
3385. 239621 };
3386. 239621 token_list.push(the_token);
3387. 239621
3388. 239621// Directives must appear before the first statement.
3389. 239621
3390. 229603 if (id !== "(comment)" && id !== ";") {
3391. 214619 mode_directive = false;
3392. 214619 }
3393. 239621
3394. 239621// If the token is to have a value, give it one.
3395. 239621
3396. 43426 if (value !== undefined) {
3397. 43426 the_token.value = value;
3398. 43426 }
3399. 239621
3400. 239621// If this token is an identifier that touches a preceding number, or
3401. 239621// a "/", comment, or regular expression literal that touches a preceding
3402. 239621// comment or regular expression literal, then give a missing space warning.
3403. 239621// This warning is not suppressed by option_dict.white.
3404. 239621
3405. 239621 if (
3406. 239621 token_prv.line === line
3407. 174883 && token_prv.thru === from
3408. 112528 && (id === "(comment)" || id === "(regexp)" || id === "/")
3409. 108 && (token_prv.id === "(comment)" || token_prv.id === "(regexp)")
3410. 1 ) {
3411. 1
3412. 1// test_cause:
3413. 1// ["/**//**/", "token_create", "expected_space_a_b", "(comment)", 5]
3414. 1
3415. 1 warn(
3416. 1 "expected_space_a_b",
3417. 1 the_token,
3418. 1 artifact(token_prv),
3419. 1 artifact(the_token)
3420. 1 );
3421. 1 }
3422. 10929 if (token_prv.id === "." && id === "(number)") {
3423. 4
3424. 4// test_cause:
3425. 4// [".0", "token_create", "expected_a_before_b", ".", 1]
3426. 4
3427. 4 warn("expected_a_before_b", token_prv, "0", ".");
3428. 4 }
3429. 10929 if (token_prv_expr.id === "." && the_token.identifier) {
3430. 10924 the_token.dot = true;
3431. 10924 }
3432. 239621
3433. 239621// The previous token is used to detect adjacency problems.
3434. 239621
3435. 239621 token_prv = the_token;
3436. 239621
3437. 239621// The token_prv_expr token is a previous token that was not a comment.
3438. 239621// The token_prv_expr token
3439. 239621// is used to disambiguate "/", which can mean division or regular expression
3440. 239621// literal.
3441. 239621
3442. 229603 if (token_prv.id !== "(comment)") {
3443. 229603 token_prv_expr = token_prv;
3444. 229603 }
3445. 239621 return the_token;
3446. 239621 }
3447. 628
3448. 628// Init global_dict and option_dict.
3449. 628
3450. 628 option_set_item("ecma", true);
3451. 1786 Object.keys(option_dict).sort().forEach(function (key) {
3452. 1786 option_set_item(key, option_dict[key] === true);
3453. 1786 });
3454. 628 object_assign_from_list(global_dict, global_list, "user-defined");
3455. 628
3456. 628// Scan first line for "#!" and ignore it.
3457. 628
3458. 2 if (line_list[jslint_fudge].line_source.startsWith("#!")) {
3459. 2 line += 1;
3460. 2 state.mode_shebang = true;
3461. 2 }
3462. 628 token_1 = lex_token();
3463. 601 state.mode_json = token_1.id === "{" || token_1.id === "[";
3464. 628
3465. 628// Lex/loop through each token until (end).
3466. 628
3467. 234499 while (true) {
3468. 234499 if (lex_token().id === "(end)") {
3469. 234499 break;
3470. 234499 }
3471. 234499 }
3472. 628}
3473. 1
3474. 591function jslint_phase3_parse(state) {
3475. 591
3476. 591// PHASE 3. Parse <token_list> into <token_tree> using the Pratt-parser.
3477. 591
3478. 591// Parsing:
3479. 591
3480. 591// Parsing weaves the tokens into an abstract syntax tree. During that process,
3481. 591// a token may be given any of these properties:
3482. 591
3483. 591// arity string
3484. 591// label identifier
3485. 591// name identifier
3486. 591// expression expressions
3487. 591// block statements
3488. 591// else statements (else, default, catch)
3489. 591
3490. 591// Specialized tokens may have additional properties.
3491. 591
3492. 591 let anon = "anonymous"; // The guessed name for anonymous functions.
3493. 591 let {
3494. 591 artifact,
3495. 591 catch_list,
3496. 591 catch_stack,
3497. 591 export_dict,
3498. 591 function_list,
3499. 591 function_stack,
3500. 591 global_dict,
3501. 591 import_list,
3502. 591 is_equal,
3503. 591 option_dict,
3504. 591 property_dict,
3505. 591 stop,
3506. 591 syntax_dict,
3507. 591 tenure,
3508. 591 test_cause,
3509. 591 token_global,
3510. 591 token_list,
3511. 591 warn,
3512. 591 warn_at
3513. 591 } = state;
3514. 591 let catchage = catch_stack[0]; // The current catch-block.
3515. 591 let functionage = token_global; // The current function.
3516. 591 let mode_var; // "var" if using var; "let" if using let.
3517. 591 let rx_identifier = (
3518. 591 /^([a-zA-Z_$][a-zA-Z0-9_$]*)$/
3519. 591 );
3520. 591 let token_ii = 0; // The number of the next token.
3521. 591 let token_now = token_global; // The current token being examined in
3522. 591 // ... the parse.
3523. 591 let token_nxt = token_global; // The next token to be examined in
3524. 591 // ... <token_list>.
3525. 591
3526. 229893 function advance(id, match) {
3527. 229893
3528. 229893// Produce the next token.
3529. 229893
3530. 229893// Attempt to give helpful names to anonymous functions.
3531. 229893
3532. 63499 if (token_now.identifier && token_now.id !== "function") {
3533. 61671 anon = token_now.id;
3534. 168222 } else if (
3535. 168222 token_now.id === "(string)"
3536. 168222 && rx_identifier.test(token_now.value)
3537. 168222 ) {
3538. 168222 anon = token_now.value;
3539. 168222 }
3540. 229893
3541. 229893// Attempt to match token_nxt with an expected id.
3542. 229893
3543. 114088 if (id !== undefined && token_nxt.id !== id) {
3544. 26 return (
3545. 26 match === undefined
3546. 26
3547. 26// test_cause:
3548. 26// ["()", "advance", "expected_a_b", "(end)", 1]
3549. 26
3550. 26 ? stop("expected_a_b", token_nxt, id, artifact())
3551. 26
3552. 26// test_cause:
3553. 26// ["{\"aa\":0", "advance", "expected_a_b_from_c_d", "{", 1]
3554. 26
3555. 26 : stop(
3556. 26 "expected_a_b_from_c_d",
3557. 26 token_nxt,
3558. 26 id,
3559. 26 artifact(match),
3560. 26 match.line,
3561. 26 artifact()
3562. 26 )
3563. 26 );
3564. 229867 }
3565. 229867
3566. 229867// Promote the tokens, skipping comments.
3567. 229867
3568. 229867 token_now = token_nxt;
3569. 239882 while (true) {
3570. 239882 token_nxt = token_list[token_ii];
3571. 239882 state.token_nxt = token_nxt;
3572. 239882 token_ii += 1;
3573. 239882 if (token_nxt.id !== "(comment)") {
3574. 239882 if (token_nxt.id === "(end)") {
3575. 239882 token_ii -= 1;
3576. 239882 }
3577. 239882 break;
3578. 239882 }
3579. 239882 if (state.mode_json) {
3580. 239882
3581. 239882// test_cause:
3582. 239882// ["[//]", "advance", "unexpected_a", "(comment)", 2]
3583. 239882
3584. 239882 warn("unexpected_a");
3585. 239882 }
3586. 239882 }
3587. 229893 }
3588. 591
3589. 7092 function assignment(id) {
3590. 7092
3591. 7092// Create an assignment operator. The one true assignment is different because
3592. 7092// its left side, when it is a variable, is not treated as an expression.
3593. 7092// That case is special because that is when a variable gets initialized. The
3594. 7092// other assignment operators can modify, but they cannot initialize.
3595. 7092
3596. 7092 const the_symbol = symbol(id, 20);
3597. 4721 the_symbol.led = function (left) {
3598. 4721 const the_token = token_now;
3599. 4721 let right;
3600. 4721 the_token.arity = "assignment";
3601. 4721 right = parse_expression(20 - 1);
3602. 4009 if (id === "=" && left.arity === "variable") {
3603. 2596 the_token.names = left;
3604. 2596 the_token.expression = right;
3605. 2596 } else {
3606. 2121 the_token.expression = [left, right];
3607. 4717 }
3608. 4717 if (
3609. 4717 right.arity === "assignment"
3610. 4717 || right.arity === "preassign"
3611. 4715 || right.arity === "postassign"
3612. 2 ) {
3613. 2 warn("unexpected_a", right);
3614. 4717 }
3615. 4717 check_mutation(left);
3616. 4717 return the_token;
3617. 4717 };
3618. 7092 return the_symbol;
3619. 7092 }
3620. 591
3621. 5511 function block(special) {
3622. 5511
3623. 5511// Parse a block, a sequence of statements wrapped in braces.
3624. 5511// special "body" The block is a function body.
3625. 5511// "ignore" No warning on an empty block.
3626. 5511// "naked" No advance.
3627. 5511// undefined An ordinary block.
3628. 5511
3629. 5511 let stmts;
3630. 5511 let the_block;
3631. 5506 if (special !== "naked") {
3632. 5506 advance("{");
3633. 5510 }
3634. 5510 the_block = token_now;
3635. 5510 if (special !== "body") {
3636. 3678 functionage.statement_prv = the_block;
3637. 5510 }
3638. 5510 the_block.arity = "statement";
3639. 5510 the_block.body = special === "body";
3640. 5510
3641. 5510// Top level function bodies may include the "use strict" pragma.
3642. 5510
3643. 5510 if (
3644. 5510 special === "body"
3645. 5510 && function_stack.length === 1
3646. 255 && token_nxt.value === "use strict"
3647. 2 ) {
3648. 2 token_nxt.statement = true;
3649. 2 advance("(string)");
3650. 2 advance(";");
3651. 5510 }
3652. 5510 stmts = parse_statements();
3653. 5510 the_block.block = stmts;
3654. 5510 if (stmts.length === 0) {
3655. 82 if (!option_dict.devel && special !== "ignore") {
3656. 82
3657. 82// test_cause:
3658. 82// ["function aa(){}", "block", "empty_block", "{", 14]
3659. 82
3660. 82 warn("empty_block", the_block);
3661. 82 }
3662. 82 the_block.disrupt = false;
3663. 5421 } else {
3664. 5421 the_block.disrupt = stmts[stmts.length - 1].disrupt;
3665. 5503 }
3666. 5503 advance("}");
3667. 5503 return the_block;
3668. 5503 }
3669. 591
3670. 21724 function check_left(left, right) {
3671. 21724
3672. 21724// Warn if the left is not one of these:
3673. 21724// ?.
3674. 21724// ?:
3675. 21724// e()
3676. 21724// e.b
3677. 21724// e[b]
3678. 21724// identifier
3679. 21724
3680. 21724 const id = left.id;
3681. 21724 if (
3682. 21724 !left.identifier
3683. 5580 && (
3684. 5580 left.arity !== "ternary"
3685. 5580 || (
3686. 5580 !check_left(left.expression[1])
3687. 5580 && !check_left(left.expression[2])
3688. 5580 )
3689. 5580 )
3690. 5580 && (
3691. 5580 left.arity !== "binary"
3692. 5580 || (id !== "." && id !== "?." && id !== "(" && id !== "[")
3693. 5580 )
3694. 11 ) {
3695. 11 warn("unexpected_a", right || token_nxt);
3696. 11 return false;
3697. 21713 }
3698. 21713 return true;
3699. 21713 }
3700. 591
3701. 4720 function check_mutation(the_thing) {
3702. 4720
3703. 4720// The only expressions that may be assigned to are
3704. 4720// e.b
3705. 4720// e[b]
3706. 4720// v
3707. 4720// [destructure]
3708. 4720// {destructure}
3709. 4720
3710. 4720 if (
3711. 4720 the_thing.arity !== "variable"
3712. 1540 && the_thing.id !== "."
3713. 164 && the_thing.id !== "["
3714. 7 && the_thing.id !== "{"
3715. 7 ) {
3716. 7
3717. 7// test_cause:
3718. 7// ["0=0", "check_mutation", "bad_assignment_a", "0", 1]
3719. 7
3720. 7 warn("bad_assignment_a", the_thing);
3721. 7 return false;
3722. 4713 }
3723. 4713 return true;
3724. 4713 }
3725. 591
3726. 2084 function check_not_top_level(thing) {
3727. 2084
3728. 2084// Some features should not be at the outermost level.
3729. 2084
3730. 36 if (functionage === token_global) {
3731. 36
3732. 36// test_cause:
3733. 36// ["
3734. 36// while(0){}
3735. 36// ", "check_not_top_level", "unexpected_at_top_level_a", "while", 1]
3736. 36
3737. 36 warn("unexpected_at_top_level_a", thing);
3738. 36 }
3739. 2084 }
3740. 591
3741. 3013 function check_ordered(type, token_list) {
3742. 3013
3743. 3013// This function will warn if <token_list> is unordered.
3744. 3013
3745. 3561 token_list.reduce(function (aa, token) {
3746. 3561 const bb = artifact(token);
3747. 3547 if (!option_dict.unordered && aa > bb) {
3748. 3 warn("expected_a_b_before_c_d", token, type, bb, type, aa);
3749. 3 }
3750. 3561 return bb;
3751. 3561 }, "");
3752. 3013 }
3753. 591
3754. 1168 function check_ordered_case(case_list) {
3755. 1168
3756. 1168// This function will warn if <case_list> is unordered.
3757. 1168
3758. 2460 case_list.filter(noop).map(function (token) {
3759. 2419 switch (token.identifier || token.id) {
3760. 40 case "(number)":
3761. 40 return {
3762. 40 order: 1,
3763. 40 token,
3764. 40 type: "number",
3765. 40 value: Number(artifact(token))
3766. 40 };
3767. 2379 case "(string)":
3768. 2379 return {
3769. 2379 order: 2,
3770. 2379 token,
3771. 2379 type: "string",
3772. 2379 value: artifact(token)
3773. 2379 };
3774. 41 case true:
3775. 41 return {
3776. 41 order: 3,
3777. 41 token,
3778. 41 type: "identifier",
3779. 41 value: artifact(token)
3780. 41 };
3781. 2460 }
3782. 2460 }).reduce(function (aa, bb) {
3783. 2460 if (
3784. 2460 !option_dict.unordered
3785. 2452 && aa && bb
3786. 1292 && (
3787. 1292 aa.order > bb.order
3788. 1292 || (aa.order === bb.order && aa.value > bb.value)
3789. 1292 )
3790. 10 ) {
3791. 10 warn(
3792. 10 "expected_a_b_before_c_d",
3793. 10 bb.token,
3794. 10 `case-${bb.type}`,
3795. 10 bb.value,
3796. 10 `case-${aa.type}`,
3797. 10 aa.value
3798. 10 );
3799. 10 }
3800. 2460 return bb;
3801. 2460 }, undefined);
3802. 1168 }
3803. 591
3804. 3211 function condition() {
3805. 3211
3806. 3211// Parse the condition part of a do, if, while.
3807. 3211
3808. 3211 const the_paren = token_nxt;
3809. 3211 let the_value;
3810. 3211
3811. 3211// test_cause:
3812. 3211// ["do{}while()", "condition", "", "", 0]
3813. 3211// ["if(){}", "condition", "", "", 0]
3814. 3211// ["while(){}", "condition", "", "", 0]
3815. 3211
3816. 3211 test_cause("");
3817. 3211 the_paren.free = true;
3818. 3211 advance("(");
3819. 3211 the_value = parse_expression(0);
3820. 3211 advance(")");
3821. 1 if (the_value.wrapped === true) {
3822. 1
3823. 1// test_cause:
3824. 1// ["while((0)){}", "condition", "unexpected_a", "(", 6]
3825. 1
3826. 1 warn("unexpected_a", the_paren);
3827. 3207 }
3828. 3207
3829. 3207// Check for anticondition.
3830. 3207
3831. 3207 switch (the_value.id) {
3832. 3207 case "%":
3833. 1 warn("unexpected_a", the_value);
3834. 1 break;
3835. 1 case "&":
3836. 1 warn("unexpected_a", the_value);
3837. 1 break;
3838. 19 case "(number)":
3839. 19 warn("unexpected_a", the_value);
3840. 19 break;
3841. 1 case "(string)":
3842. 1 warn("unexpected_a", the_value);
3843. 1 break;
3844. 1 case "*":
3845. 1 warn("unexpected_a", the_value);
3846. 1 break;
3847. 1 case "+":
3848. 1 warn("unexpected_a", the_value);
3849. 1 break;
3850. 1 case "-":
3851. 1 warn("unexpected_a", the_value);
3852. 1 break;
3853. 1 case "/":
3854. 1 warn("unexpected_a", the_value);
3855. 1 break;
3856. 1 case "<<":
3857. 1 warn("unexpected_a", the_value);
3858. 1 break;
3859. 1 case ">>":
3860. 1 warn("unexpected_a", the_value);
3861. 1 break;
3862. 1 case ">>>":
3863. 1 warn("unexpected_a", the_value);
3864. 1 break;
3865. 1 case "?":
3866. 1 warn("unexpected_a", the_value);
3867. 1 break;
3868. 1 case "^":
3869. 1 warn("unexpected_a", the_value);
3870. 1 break;
3871. 1 case "typeof":
3872. 1 warn("unexpected_a", the_value);
3873. 1 break;
3874. 1 case "|":
3875. 1 warn("unexpected_a", the_value);
3876. 1 break;
3877. 1 case "~":
3878. 1
3879. 1// test_cause:
3880. 1// ["if(0%0){}", "condition", "unexpected_a", "%", 5]
3881. 1// ["if(0&0){}", "condition", "unexpected_a", "&", 5]
3882. 1// ["if(0){}", "condition", "unexpected_a", "0", 4]
3883. 1// ["if(0*0){}", "condition", "unexpected_a", "*", 5]
3884. 1// ["if(0+0){}", "condition", "unexpected_a", "+", 5]
3885. 1// ["if(0-0){}", "condition", "unexpected_a", "-", 5]
3886. 1// ["if(0/0){}", "condition", "unexpected_a", "/", 5]
3887. 1// ["if(0<<0){}", "condition", "unexpected_a", "<<", 5]
3888. 1// ["if(0>>0){}", "condition", "unexpected_a", ">>", 5]
3889. 1// ["if(0>>>0){}", "condition", "unexpected_a", ">>>", 5]
3890. 1// ["if(0?0:0){}", "condition", "unexpected_a", "?", 5]
3891. 1// ["if(0^0){}", "condition", "unexpected_a", "^", 5]
3892. 1// ["if(0|0){}", "condition", "unexpected_a", "|", 5]
3893. 1// ["if(\"aa\"){}", "condition", "unexpected_a", "aa", 4]
3894. 1// ["if(typeof 0){}", "condition", "unexpected_a", "typeof", 4]
3895. 1// ["if(~0){}", "condition", "unexpected_a", "~", 4]
3896. 1
3897. 1 warn("unexpected_a", the_value);
3898. 1 break;
3899. 3207 }
3900. 3207 return the_value;
3901. 3207 }
3902. 591
3903. 9456 function constant(id, type, value) {
3904. 9456
3905. 9456// Create a constant symbol.
3906. 9456
3907. 9456 const the_symbol = symbol(id);
3908. 9456 the_symbol.constant = true;
3909. 9456 the_symbol.nud = (
3910. 9456 typeof value === "function"
3911. 4137 ? value
3912. 17136 : function () {
3913. 17136 token_now.constant = true;
3914. 5319 if (value !== undefined) {
3915. 5319 token_now.value = value;
3916. 5319 }
3917. 17136 return token_now;
3918. 17136 }
3919. 9456 );
3920. 9456 the_symbol.type = type;
3921. 9456 the_symbol.value = value;
3922. 9456 return the_symbol;
3923. 9456 }
3924. 591
3925. 5 function constant_Function() {
3926. 2 if (!option_dict.eval) {
3927. 2
3928. 2// test_cause:
3929. 2// ["Function", "constant_Function", "unexpected_a", "Function", 1]
3930. 2
3931. 2 warn("unexpected_a", token_now);
3932. 3 } else if (token_nxt.id !== "(") {
3933. 3
3934. 3// test_cause:
3935. 3// ["
3936. 3// /*jslint eval*/
3937. 3// Function
3938. 3// ", "constant_Function", "expected_a_before_b", "(end)", 1]
3939. 3
3940. 3 warn("expected_a_before_b", token_nxt, "(", artifact());
3941. 3 }
3942. 5 return token_now;
3943. 5 }
3944. 591
3945. 1 function constant_arguments() {
3946. 1
3947. 1// test_cause:
3948. 1// ["arguments", "constant_arguments", "unexpected_a", "arguments", 1]
3949. 1
3950. 1 warn("unexpected_a", token_now);
3951. 1 return token_now;
3952. 1 }
3953. 591
3954. 4 function constant_eval() {
3955. 1 if (!option_dict.eval) {
3956. 1
3957. 1// test_cause:
3958. 1// ["eval", "constant_eval", "unexpected_a", "eval", 1]
3959. 1
3960. 1 warn("unexpected_a", token_now);
3961. 3 } else if (token_nxt.id !== "(") {
3962. 3
3963. 3// test_cause:
3964. 3// ["/*jslint eval*/\neval", "constant_eval", "expected_a_before_b", "(end)", 1]
3965. 3
3966. 3 warn("expected_a_before_b", token_nxt, "(", artifact());
3967. 3 }
3968. 4 return token_now;
3969. 4 }
3970. 591
3971. 1 function constant_ignore() {
3972. 1
3973. 1// test_cause:
3974. 1// ["ignore", "constant_ignore", "unexpected_a", "ignore", 1]
3975. 1
3976. 1 warn("unexpected_a", token_now);
3977. 1 return token_now;
3978. 1 }
3979. 591
3980. 1 function constant_isInfinite() {
3981. 1
3982. 1// test_cause:
3983. 1// ["isFinite", "constant_isInfinite", "expected_a_b", "isFinite", 1]
3984. 1
3985. 1 warn("expected_a_b", token_now, "Number.isFinite", "isFinite");
3986. 1 return token_now;
3987. 1 }
3988. 591
3989. 1 function constant_isNaN() {
3990. 1
3991. 1// test_cause:
3992. 1// ["isNaN(0)", "constant_isNaN", "number_isNaN", "isNaN", 1]
3993. 1
3994. 1 warn("number_isNaN", token_now);
3995. 1 return token_now;
3996. 1 }
3997. 591
3998. 3 function constant_this() {
3999. 1 if (!option_dict.this) {
4000. 1
4001. 1// test_cause:
4002. 1// ["this", "constant_this", "unexpected_a", "this", 1]
4003. 1
4004. 1 warn("unexpected_a", token_now);
4005. 1 }
4006. 3 return token_now;
4007. 3 }
4008. 591
4009. 5860 function enroll(name, role, readonly) {
4010. 5860
4011. 5860// Enroll a name into the current function context. The role can be exception,
4012. 5860// function, label, parameter, or variable. We look for variable redefinition
4013. 5860// because it causes confusion.
4014. 5860
4015. 5860 let earlier;
4016. 5860 let id = name.id;
4017. 5860
4018. 5860// Reserved words may not be enrolled.
4019. 5860
4020. 36 if (syntax_dict[id] !== undefined && id !== "ignore") {
4021. 1
4022. 1// test_cause:
4023. 1// ["let undefined", "enroll", "reserved_a", "undefined", 5]
4024. 1
4025. 1 warn("reserved_a", name);
4026. 1 return;
4027. 5859 }
4028. 5859
4029. 5859// Has the name been enrolled in this context?
4030. 5859
4031. 5859 earlier = functionage.context[id] || catchage.context[id];
4032. 7 if (earlier) {
4033. 7
4034. 7// test_cause:
4035. 7// ["let aa;let aa", "enroll", "redefinition_a_b", "1", 12]
4036. 7
4037. 7 warn("redefinition_a_b", name, id, earlier.line);
4038. 7 return;
4039. 5852 }
4040. 5852
4041. 5852// Has the name been enrolled in an outer context?
4042. 5852
4043. 10101 function_stack.forEach(function ({
4044. 10101 context
4045. 10101 }) {
4046. 9994 earlier = context[id] || earlier;
4047. 10101 });
4048. 5852 if (earlier && id === "ignore") {
4049. 4 if (earlier.role === "variable") {
4050. 4
4051. 4// test_cause:
4052. 4// ["let ignore;function aa(ignore){}", "enroll", "redefinition_a_b", "1", 24]
4053. 4
4054. 4 warn("redefinition_a_b", name, id, earlier.line);
4055. 4 }
4056. 5848 } else if (
4057. 5848 earlier
4058. 5848 && role !== "parameter" && role !== "function"
4059. 5848 && (role !== "exception" || earlier.role !== "exception")
4060. 5848 ) {
4061. 5848
4062. 5848// test_cause:
4063. 5848// ["
4064. 5848// function aa(){try{aa();}catch(aa){aa();}}
4065. 5848// ", "enroll", "redefinition_a_b", "1", 31]
4066. 5848// ["function aa(){var aa;}", "enroll", "redefinition_a_b", "1", 19]
4067. 5848
4068. 5848 warn("redefinition_a_b", name, id, earlier.line);
4069. 5848 } else if (
4070. 5848 option_dict.beta
4071. 5848 && global_dict[id]
4072. 5848 && role !== "parameter"
4073. 5848 ) {
4074. 5848
4075. 5848// test_cause:
4076. 5848// ["let Array", "enroll", "redefinition_global_a_b", "Array", 5]
4077. 5848
4078. 5848 warn("redefinition_global_a_b", name, global_dict[id], id);
4079. 5852 }
4080. 5852
4081. 5852// Enroll it.
4082. 5852
4083. 5852 Object.assign(name, {
4084. 5852 dead: true,
4085. 5852 init: false,
4086. 5852 parent: (
4087. 5852 role === "exception"
4088. 5852 ? catchage
4089. 5824 : functionage
4090. 5860 ),
4091. 5860 readonly,
4092. 5860 role,
4093. 5860 used: 0
4094. 5860 });
4095. 5860 name.parent.context[id] = name;
4096. 5860 }
4097. 591
4098. 17730 function infix(bp, id, f) {
4099. 17730
4100. 17730// Create an infix operator.
4101. 17730
4102. 17730 const the_symbol = symbol(id, bp);
4103. 30000 the_symbol.led = function (left) {
4104. 30000 const the_token = token_now;
4105. 30000 the_token.arity = "binary";
4106. 21897 if (f !== undefined) {
4107. 21897 return f(left);
4108. 21897 }
4109. 8103 the_token.expression = [left, parse_expression(bp)];
4110. 8103 return the_token;
4111. 8103 };
4112. 17730 return the_symbol;
4113. 17730 }
4114. 591
4115. 10923 function infix_dot(left) {
4116. 10923 const the_token = token_now;
4117. 10923 let name = token_nxt;
4118. 10923 if (
4119. 10923 (
4120. 10923 left.id !== "(string)"
4121. 31 || (name.id !== "indexOf" && name.id !== "repeat")
4122. 10923 )
4123. 10893 && (
4124. 10893 left.id !== "["
4125. 10893 || (
4126. 10893 name.id !== "concat"
4127. 10893 && name.id !== "forEach"
4128. 10893 && name.id !== "join"
4129. 10893 && name.id !== "map"
4130. 10893 )
4131. 10893 )
4132. 10876 && (left.id !== "+" || name.id !== "slice")
4133. 10871 && (
4134. 10871 left.id !== "(regexp)"
4135. 10871 || (name.id !== "exec" && name.id !== "test")
4136. 10871 )
4137. 10790 ) {
4138. 10790
4139. 10790// test_cause:
4140. 10790// ["\"\".aa", "check_left", "unexpected_a", ".", 3]
4141. 10790
4142. 10790 check_left(left, the_token);
4143. 10790 }
4144. 1 if (!name.identifier) {
4145. 1
4146. 1// test_cause:
4147. 1// ["aa.0", "infix_dot", "expected_identifier_a", "0", 4]
4148. 1
4149. 1 stop("expected_identifier_a");
4150. 10922 }
4151. 10922 advance();
4152. 10922 survey(name);
4153. 10922
4154. 10922// The property name is not an expression.
4155. 10922
4156. 10922 the_token.name = name;
4157. 10922 the_token.expression = left;
4158. 10922 return the_token;
4159. 10922 }
4160. 591
4161. 1 function infix_fart_unwrapped(left) {
4162. 1
4163. 1// test_cause:
4164. 1// ["aa=>0", "infix_fart_unwrapped", "wrap_parameter", "aa", 1]
4165. 1
4166. 1 return stop("wrap_parameter", left);
4167. 1 }
4168. 591
4169. 1 function infix_grave(left) {
4170. 1 const the_tick = prefix_tick();
4171. 1
4172. 1// test_cause:
4173. 1// ["0``", "check_left", "unexpected_a", "`", 2]
4174. 1
4175. 1 check_left(left, the_tick);
4176. 1 the_tick.expression = [left].concat(the_tick.expression);
4177. 1 return the_tick;
4178. 1 }
4179. 591
4180. 1355 function infix_lbracket(left) {
4181. 1355 const the_token = token_now;
4182. 1355 let name;
4183. 1355 let the_subscript = parse_expression(0);
4184. 1345 if (the_subscript.id === "(string)" || the_subscript.id === "`") {
4185. 12 name = survey(the_subscript);
4186. 12 if (rx_identifier.test(name)) {
4187. 12
4188. 12// test_cause:
4189. 12// ["aa[`aa`]", "infix_lbracket", "subscript_a", "aa", 4]
4190. 12
4191. 12 warn("subscript_a", the_subscript, name);
4192. 12 }
4193. 12 }
4194. 1355
4195. 1355// test_cause:
4196. 1355// ["0[0]", "check_left", "unexpected_a", "[", 2]
4197. 1355
4198. 1355 check_left(left, the_token);
4199. 1355 the_token.expression = [left, the_subscript];
4200. 1355 advance("]");
4201. 1355 return the_token;
4202. 1355 }
4203. 591
4204. 9609 function infix_lparen(left) {
4205. 9609 const the_paren = token_now;
4206. 9609 let ellipsis;
4207. 9609 let the_argument;
4208. 9568 if (left.id !== "function") {
4209. 9568
4210. 9568// test_cause:
4211. 9568// ["(0?0:0)()", "check_left", "unexpected_a", "(", 8]
4212. 9568// ["0()", "check_left", "unexpected_a", "(", 2]
4213. 9568
4214. 9568 check_left(left, the_paren);
4215. 9568 }
4216. 7296 if (functionage.arity === "statement" && left.identifier) {
4217. 5371 functionage.name.calls[left.id] = left;
4218. 5371 }
4219. 9609 the_paren.expression = [left];
4220. 8207 if (token_nxt.id !== ")") {
4221. 8207
4222. 8207// Parse/loop through each token in expression (...).
4223. 8207
4224. 13100 while (true) {
4225. 13100 if (token_nxt.id === "...") {
4226. 13100 ellipsis = true;
4227. 13100 advance("...");
4228. 13100 }
4229. 13100 the_argument = parse_expression(10);
4230. 13100 if (ellipsis) {
4231. 13100 the_argument.ellipsis = true;
4232. 13100 }
4233. 13100 the_paren.expression.push(the_argument);
4234. 13100 if (token_nxt.id !== ",") {
4235. 13100 break;
4236. 13100 }
4237. 13100 advance(",");
4238. 13100 }
4239. 8207 }
4240. 9609 advance(")", the_paren);
4241. 4917 if (the_paren.expression.length === 2) {
4242. 4917
4243. 4917// test_cause:
4244. 4917// ["aa(0)", "infix_lparen", "free", "", 0]
4245. 4917
4246. 4917 test_cause("free");
4247. 4917 the_paren.free = true;
4248. 4917 if (the_argument.wrapped === true) {
4249. 4917
4250. 4917// test_cause:
4251. 4917// ["aa((0))", "infix_lparen", "unexpected_a", "(", 3]
4252. 4917
4253. 4917 warn("unexpected_a", the_paren);
4254. 4917 }
4255. 4917 if (the_argument.id === "(") {
4256. 4917 the_argument.wrapped = true;
4257. 4917 }
4258. 4917 } else {
4259. 4692
4260. 4692// test_cause:
4261. 4692// ["aa()", "infix_lparen", "not_free", "", 0]
4262. 4692// ["aa(0,0)", "infix_lparen", "not_free", "", 0]
4263. 4692
4264. 4692 test_cause("not_free");
4265. 4692 the_paren.free = false;
4266. 4692 }
4267. 9609 return the_paren;
4268. 9609 }
4269. 591
4270. 8 function infix_option_chain(left) {
4271. 8 const the_token = token_now;
4272. 8 let name;
4273. 8 name = token_nxt;
4274. 8 if (
4275. 8 (
4276. 8 left.id !== "(string)"
4277. 1 || (name.id !== "indexOf" && name.id !== "repeat")
4278. 8 )
4279. 8 && (
4280. 8 left.id !== "["
4281. 1 || (
4282. 1 name.id !== "concat"
4283. 1 && name.id !== "forEach"
4284. 1 && name.id !== "join"
4285. 1 && name.id !== "map"
4286. 1 )
4287. 8 )
4288. 8
4289. 8// test_cause:
4290. 8// ["(0+0)?.0", "infix_option_chain", "check_left", "", 0]
4291. 8
4292. 1 && (left.id !== "+" || name.id !== "slice")
4293. 8 && (
4294. 8 left.id !== "(regexp)"
4295. 1 || (name.id !== "exec" && name.id !== "test")
4296. 8 )
4297. 8 ) {
4298. 8 test_cause("check_left");
4299. 8
4300. 8// test_cause:
4301. 8// ["(/./)?.0", "check_left", "unexpected_a", "?.", 6]
4302. 8// ["\"aa\"?.0", "check_left", "unexpected_a", "?.", 5]
4303. 8// ["aa=[]?.aa", "check_left", "unexpected_a", "?.", 6]
4304. 8
4305. 8 check_left(left, the_token);
4306. 8 }
4307. 4 if (!name.identifier) {
4308. 4
4309. 4// test_cause:
4310. 4// ["aa?.0", "infix_option_chain", "expected_identifier_a", "0", 5]
4311. 4
4312. 4 stop("expected_identifier_a");
4313. 4 }
4314. 4 advance();
4315. 4 survey(name);
4316. 4
4317. 4// The property name is not an expression.
4318. 4
4319. 4 the_token.name = name;
4320. 4 the_token.expression = left;
4321. 4 return the_token;
4322. 4 }
4323. 591
4324. 591 function infixr(bp, id) {
4325. 591
4326. 591// Create a right associative infix operator.
4327. 591
4328. 591 const the_symbol = symbol(id, bp);
4329. 1 the_symbol.led = function parse_infixr_led(left) {
4330. 1 const the_token = token_now;
4331. 1
4332. 1// test_cause:
4333. 1// ["0**0", "parse_infixr_led", "led", "", 0]
4334. 1
4335. 1 test_cause("led");
4336. 1 the_token.arity = "binary";
4337. 1 the_token.expression = [left, parse_expression(bp - 1)];
4338. 1 return the_token;
4339. 1 };
4340. 591 return the_symbol;
4341. 591 }
4342. 591
4343. 1357 function lookahead() {
4344. 1357
4345. 1357// Look ahead one token without advancing, skipping comments.
4346. 1357
4347. 1357 let cadet;
4348. 1357 let ii = token_ii;
4349. 1372 while (true) {
4350. 1372 cadet = token_list[ii];
4351. 1372 if (cadet.id !== "(comment)") {
4352. 1372 return cadet;
4353. 1372 }
4354. 1372 ii += 1;
4355. 1372 }
4356. 1357 }
4357. 591
4358. 51795 function parse_expression(rbp, initial) {
4359. 51795
4360. 51795// This is the heart of JSLINT, the Pratt parser. In addition to parsing, it
4361. 51795// is looking for ad hoc lint patterns. We add .fud to Pratt's model, which is
4362. 51795// like .nud except that it is only used on the first token of a statement.
4363. 51795// Having .fud makes it much easier to define statement-oriented languages like
4364. 51795// JavaScript. I retained Pratt's nomenclature.
4365. 51795// They are elements of the parsing method called Top Down Operator Precedence.
4366. 51795
4367. 51795// .nud Null denotation
4368. 51795// .fud First null denotation
4369. 51795// .led Left denotation
4370. 51795// lbp Left binding power
4371. 51795// rbp Right binding power
4372. 51795
4373. 51795// It processes a nud (variable, constant, prefix operator). It will then
4374. 51795// process leds (infix operators) until the bind powers cause it to stop. It
4375. 51795// returns the expression's parse tree.
4376. 51795
4377. 51795 let left;
4378. 51795 let the_symbol;
4379. 51795
4380. 51795// Statements will have already advanced, so advance now only if the token is
4381. 51795// not the first of a statement.
4382. 51795
4383. 41128 if (!initial) {
4384. 41128 advance();
4385. 41128 }
4386. 51795 the_symbol = syntax_dict[token_now.id];
4387. 22179 if (the_symbol !== undefined && the_symbol.nud !== undefined) {
4388. 22121
4389. 22121// test_cause:
4390. 22121// ["0", "parse_expression", "symbol", "", 0]
4391. 22121
4392. 22121 test_cause("symbol");
4393. 22121 left = the_symbol.nud();
4394. 29674 } else if (token_now.identifier) {
4395. 29674
4396. 29674// test_cause:
4397. 29674// ["aa", "parse_expression", "identifier", "", 0]
4398. 29674
4399. 29674 test_cause("identifier");
4400. 29674 left = token_now;
4401. 29674 left.arity = "variable";
4402. 29674 } else {
4403. 29674
4404. 29674// test_cause:
4405. 29674// ["!", "parse_expression", "unexpected_a", "(end)", 1]
4406. 29674// ["/./", "parse_expression", "unexpected_a", "/", 1]
4407. 29674// ["let aa=`${}`;", "parse_expression", "unexpected_a", "}", 11]
4408. 29674
4409. 29674 return stop("unexpected_a", token_now);
4410. 51753 }
4411. 51753
4412. 51753// Parse/loop through each symbol in expression.
4413. 51753
4414. 86678 while (true) {
4415. 86678 the_symbol = syntax_dict[token_nxt.id];
4416. 86678 if (
4417. 86678 the_symbol === undefined
4418. 86678 || the_symbol.led === undefined
4419. 86678 || the_symbol.lbp <= rbp
4420. 86678 ) {
4421. 86678 break;
4422. 86678 }
4423. 86678 advance();
4424. 86678 left = the_symbol.led(left);
4425. 86678 }
4426. 51742 return left;
4427. 51742 }
4428. 591
4429. 10 function parse_fart(pl) {
4430. 10 let the_fart;
4431. 10 advance("=>");
4432. 10 the_fart = token_now;
4433. 10 the_fart.arity = "binary";
4434. 10 the_fart.name = "=>";
4435. 10 the_fart.level = functionage.level + 1;
4436. 10 function_list.push(the_fart);
4437. 1 if (functionage.loop > 0) {
4438. 1
4439. 1// test_cause:
4440. 1// ["while(0){aa.map(()=>0);}", "parse_fart", "function_in_loop", "=>", 19]
4441. 1
4442. 1 warn("function_in_loop", the_fart);
4443. 9 }
4444. 9
4445. 9// Give the function properties storing its names and for observing the depth
4446. 9// of loops and switches.
4447. 9
4448. 9 the_fart.context = empty();
4449. 9 the_fart.finally = 0;
4450. 9 the_fart.loop = 0;
4451. 9 the_fart.switch = 0;
4452. 9 the_fart.try = 0;
4453. 9
4454. 9// Push the current function context and establish a new one.
4455. 9
4456. 9 function_stack.push(functionage);
4457. 9 functionage = the_fart;
4458. 9 the_fart.parameters = pl[0];
4459. 9 the_fart.signature = pl[1];
4460. 9 the_fart.parameters.forEach(function (name) {
4461. 9
4462. 9// test_cause:
4463. 9// ["(aa)=>{}", "parse_fart", "parameter", "", 0]
4464. 9
4465. 9 test_cause("parameter");
4466. 9 enroll(name, "parameter", true);
4467. 9 });
4468. 9 if (token_nxt.id === "{") {
4469. 2
4470. 2// test_cause:
4471. 2// ["()=>{}", "parse_fart", "expected_a_b", "=>", 3]
4472. 2
4473. 2 warn("expected_a_b", the_fart, "function", "=>");
4474. 2 the_fart.block = block("body");
4475. 7 } else {
4476. 7 the_fart.expression = parse_expression(0);
4477. 9 }
4478. 9 functionage = function_stack.pop();
4479. 9 return the_fart;
4480. 9 }
4481. 591
4482. 12943 function parse_json() {
4483. 12943 let container;
4484. 12943 let is_dup;
4485. 12943 let name;
4486. 12943 let negative;
4487. 12943 switch (token_nxt.id) {
4488. 5260 case "(number)":
4489. 5260 if (!(
4490. 5260
4491. 5260// https://datatracker.ietf.org/doc/html/rfc7159#section-6
4492. 5260// number = [ minus ] int [ frac ] [ exp ]
4493. 5260
4494. 5260 /^-?(?:0|[1-9]\d*?)(?:\.\d*?)?(?:[eE][+\-]?\d+?)?$/
4495. 5260 ).test(token_nxt.value)) {
4496. 5260
4497. 5260// test_cause:
4498. 5260// ["[-.0]", "parse_json", "unexpected_a", ".", 3]
4499. 5260// ["[-0x0]", "parse_json", "unexpected_a", "0x0", 3]
4500. 5260// ["[.0]", "parse_json", "unexpected_a", ".", 2]
4501. 5260// ["[0x0]", "parse_json", "unexpected_a", "0x0", 2]
4502. 5260
4503. 5260 warn("unexpected_a");
4504. 5260 }
4505. 5260 advance("(number)");
4506. 5260 return token_now;
4507. 1756 case "(string)":
4508. 1756 if (token_nxt.quote !== "\"") {
4509. 1756
4510. 1756// test_cause:
4511. 1756// ["['']", "parse_json", "unexpected_a", "'", 2]
4512. 1756
4513. 1756 warn("unexpected_a", token_nxt, token_nxt.quote);
4514. 1756 }
4515. 1756 advance("(string)");
4516. 1756 return token_now;
4517. 3 case "-":
4518. 3 negative = token_nxt;
4519. 3 negative.arity = "unary";
4520. 3 advance("-");
4521. 3
4522. 3// Recurse parse_json().
4523. 3
4524. 3 negative.expression = parse_json();
4525. 3 return negative;
4526. 1648 case "[":
4527. 1648
4528. 1648// test_cause:
4529. 1648// ["[]", "parse_json", "bracket", "", 0]
4530. 1648
4531. 1648 test_cause("bracket");
4532. 1648 container = token_nxt;
4533. 1648 container.expression = [];
4534. 1648 advance("[");
4535. 1648 if (token_nxt.id !== "]") {
4536. 3294 while (true) {
4537. 3294
4538. 3294// Recurse parse_json().
4539. 3294
4540. 3294 container.expression.push(parse_json());
4541. 3294 if (token_nxt.id !== ",") {
4542. 3294
4543. 3294// test_cause:
4544. 3294// ["[0,0]", "parse_json", "comma", "", 0]
4545. 3294
4546. 3294 test_cause("comma");
4547. 3294 break;
4548. 3294 }
4549. 3294 advance(",");
4550. 3294 }
4551. 1648 }
4552. 1648 advance("]", container);
4553. 1648 return container;
4554. 509 case "false":
4555. 511 case "null":
4556. 896 case "true":
4557. 896
4558. 896// test_cause:
4559. 896// ["[false]", "parse_json", "constant", "", 0]
4560. 896// ["[null]", "parse_json", "constant", "", 0]
4561. 896// ["[true]", "parse_json", "constant", "", 0]
4562. 896
4563. 896 test_cause("constant");
4564. 896 advance();
4565. 896 return token_now;
4566. 3375 case "{":
4567. 3375
4568. 3375// test_cause:
4569. 3375// ["{}", "parse_json", "brace", "", 0]
4570. 3375
4571. 3375 test_cause("brace");
4572. 3375 container = token_nxt;
4573. 3375
4574. 3375// Explicit empty-object required to detect "__proto__".
4575. 3375
4576. 3375 is_dup = empty();
4577. 3375 container.expression = [];
4578. 3375 advance("{");
4579. 3375 if (token_nxt.id !== "}") {
4580. 3375
4581. 3375// JSON
4582. 3375// Parse/loop through each property in {...}.
4583. 3375
4584. 9624 while (true) {
4585. 9624 if (token_nxt.quote !== "\"") {
4586. 9624
4587. 9624// test_cause:
4588. 9624// ["{0:0}", "parse_json", "unexpected_a", "0", 2]
4589. 9624
4590. 9624 warn(
4591. 9624 "unexpected_a",
4592. 9624 token_nxt,
4593. 9624 token_nxt.quote
4594. 9624 );
4595. 9624 }
4596. 9624 name = token_nxt;
4597. 9624 advance("(string)");
4598. 9624 if (is_dup[token_now.value] !== undefined) {
4599. 9624
4600. 9624// test_cause:
4601. 9624// ["{\"aa\":0,\"aa\":0}", "parse_json", "duplicate_a", "aa", 9]
4602. 9624
4603. 9624 warn("duplicate_a", token_now);
4604. 9624 } else if (token_now.value === "__proto__") {
4605. 9624
4606. 9624// test_cause:
4607. 9624// ["{\"__proto__\":0}", "parse_json", "weird_property_a", "__proto__", 2]
4608. 9624
4609. 9624 warn("weird_property_a", token_now);
4610. 9624 } else {
4611. 9624 is_dup[token_now.value] = token_now;
4612. 9624 }
4613. 9624 advance(":");
4614. 9624 container.expression.push(
4615. 9624
4616. 9624// Recurse parse_json().
4617. 9624
4618. 9624 Object.assign(parse_json(), {
4619. 9624 label: name
4620. 9624 })
4621. 9624 );
4622. 9624 if (token_nxt.id !== ",") {
4623. 9624 break;
4624. 9624 }
4625. 9624 advance(",");
4626. 9624 }
4627. 3375 }
4628. 3375 advance("}", container);
4629. 3375 return container;
4630. 5 default:
4631. 5
4632. 5// test_cause:
4633. 5// ["[undefined]", "parse_json", "unexpected_a", "undefined", 2]
4634. 5
4635. 5 stop("unexpected_a");
4636. 12943 }
4637. 12943 }
4638. 591
4639. 19773 function parse_statement() {
4640. 19773
4641. 19773// Parse a statement. Any statement may have a label, but only four statements
4642. 19773// have use for one. A statement can be one of the standard statements, or
4643. 19773// an assignment expression, or an invocation expression.
4644. 19773
4645. 19773 let first;
4646. 19773 let the_label;
4647. 19773 let the_statement;
4648. 19773 let the_symbol;
4649. 19773 advance();
4650. 19592 if (token_now.identifier && token_nxt.id === ":") {
4651. 13 the_label = token_now;
4652. 13 if (the_label.id === "ignore") {
4653. 13
4654. 13// test_cause:
4655. 13// ["ignore:", "parse_statement", "unexpected_a", "ignore", 1]
4656. 13
4657. 13 warn("unexpected_a", the_label);
4658. 13 }
4659. 13 advance(":");
4660. 13 switch (token_nxt.id) {
4661. 13 case "do":
4662. 13 case "for":
4663. 13 case "switch":
4664. 13 case "while":
4665. 13
4666. 13// test_cause:
4667. 13// ["aa:do{}", "parse_statement", "the_statement_label", "do", 0]
4668. 13// ["aa:for{}", "parse_statement", "the_statement_label", "for", 0]
4669. 13// ["aa:switch{}", "parse_statement", "the_statement_label", "switch", 0]
4670. 13// ["aa:while{}", "parse_statement", "the_statement_label", "while", 0]
4671. 13
4672. 13 test_cause("the_statement_label", token_nxt.id);
4673. 13 enroll(the_label, "label", true);
4674. 13 the_label.dead = false;
4675. 13 the_label.init = true;
4676. 13 the_statement = parse_statement();
4677. 13 functionage.statement_prv = the_statement;
4678. 13 the_statement.label = the_label;
4679. 13 the_statement.statement = true;
4680. 13 return the_statement;
4681. 13 }
4682. 13 advance();
4683. 13
4684. 13// test_cause:
4685. 13// ["aa:", "parse_statement", "unexpected_label_a", "aa", 1]
4686. 13
4687. 13 warn("unexpected_label_a", the_label);
4688. 19764 }
4689. 19764
4690. 19764// Parse the statement.
4691. 19764
4692. 19764 first = token_now;
4693. 19764 first.statement = true;
4694. 19764 the_symbol = syntax_dict[first.id];
4695. 19764 if (
4696. 19764 the_symbol !== undefined
4697. 19764 && the_symbol.fud !== undefined
4698. 19773
4699. 19773// PR-318 - Bugfix - Fixes issues #316, #317 - dynamic-import().
4700. 19773
4701. 9617 && !(the_symbol.id === "import" && token_nxt.id === "(")
4702. 9615 ) {
4703. 9615 the_symbol.disrupt = false;
4704. 9615 the_symbol.statement = true;
4705. 9615 token_now.arity = "statement";
4706. 9615 the_statement = the_symbol.fud();
4707. 9615 functionage.statement_prv = the_statement;
4708. 10149 } else {
4709. 10149
4710. 10149// It is an expression statement.
4711. 10149
4712. 10149 the_statement = parse_expression(0, true);
4713. 10149 functionage.statement_prv = the_statement;
4714. 10149 if (the_statement.wrapped && the_statement.id !== "(") {
4715. 10149
4716. 10149// test_cause:
4717. 10149// ["(0)", "parse_statement", "unexpected_a", "(", 1]
4718. 10149
4719. 10149 warn("unexpected_a", first);
4720. 10149 }
4721. 10149 semicolon();
4722. 19664 }
4723. 19664 if (the_label !== undefined) {
4724. 1 the_label.dead = true;
4725. 19664 }
4726. 19664 return the_statement;
4727. 19664 }
4728. 591
4729. 7150 function parse_statements() {
4730. 7150
4731. 7150// Parse a list of statements. Give a warning if an unreachable statement
4732. 7150// follows a disruptive statement.
4733. 7150
4734. 7150 const statement_list = [];
4735. 7150 let a_statement;
4736. 7150 let disrupt = false;
4737. 7150
4738. 7150// Parse/loop each statement until a statement-terminator is reached.
4739. 7150
4740. 26488 while (true) {
4741. 26488 switch (token_nxt.id) {
4742. 26488 case "(end)":
4743. 26488 case "case":
4744. 26488 case "default":
4745. 26488 case "else":
4746. 26488 case "}":
4747. 26488
4748. 26488// test_cause:
4749. 26488// [";", "parse_statements", "closer", "", 0]
4750. 26488// ["case", "parse_statements", "closer", "", 0]
4751. 26488// ["default", "parse_statements", "closer", "", 0]
4752. 26488// ["else", "parse_statements", "closer", "", 0]
4753. 26488// ["}", "parse_statements", "closer", "", 0]
4754. 26488
4755. 26488 test_cause("closer");
4756. 26488 return statement_list;
4757. 26488 }
4758. 26488 a_statement = parse_statement();
4759. 26488 statement_list.push(a_statement);
4760. 26488 if (disrupt) {
4761. 26488
4762. 26488// test_cause:
4763. 26488// ["while(0){break;0;}", "parse_statements", "unreachable_a", "0", 16]
4764. 26488
4765. 26488 warn("unreachable_a", a_statement);
4766. 26488 }
4767. 26488 disrupt = a_statement.disrupt;
4768. 26488 }
4769. 7150 }
4770. 591
4771. 1182 function postassign(id) {
4772. 1182
4773. 1182// Create one of the postassign operators.
4774. 1182
4775. 1182 const the_symbol = symbol(id, 150);
4776. 1 the_symbol.led = function (left) {
4777. 1 token_now.expression = left;
4778. 1 token_now.arity = "postassign";
4779. 1 check_mutation(token_now.expression);
4780. 1 return token_now;
4781. 1 };
4782. 1182 return the_symbol;
4783. 1182 }
4784. 591
4785. 1182 function preassign(id) {
4786. 1182
4787. 1182// Create one of the preassign operators.
4788. 1182
4789. 1182 const the_symbol = symbol(id);
4790. 2 the_symbol.nud = function () {
4791. 2 const the_token = token_now;
4792. 2 the_token.arity = "preassign";
4793. 2 the_token.expression = parse_expression(150);
4794. 2 check_mutation(the_token.expression);
4795. 2 return the_token;
4796. 2 };
4797. 1182 return the_symbol;
4798. 1182 }
4799. 591
4800. 10047 function prefix(id, f) {
4801. 10047
4802. 10047// Create a prefix operator.
4803. 10047
4804. 10047 const the_symbol = symbol(id);
4805. 4967 the_symbol.nud = function () {
4806. 4967 const the_token = token_now;
4807. 4967 the_token.arity = "unary";
4808. 4211 if (typeof f === "function") {
4809. 4211 return f();
4810. 4211 }
4811. 756 the_token.expression = parse_expression(150);
4812. 756 return the_token;
4813. 756 };
4814. 10047 return the_symbol;
4815. 10047 }
4816. 591
4817. 1 function prefix_assign_divide() {
4818. 1
4819. 1// test_cause:
4820. 1// ["/=", "prefix_assign_divide", "expected_a_b", "/=", 1]
4821. 1
4822. 1 stop("expected_a_b", token_now, "/\\=", "/=");
4823. 1 }
4824. 591
4825. 113 function prefix_async() {
4826. 113 let the_async;
4827. 113 let the_function;
4828. 113 the_async = token_now;
4829. 113 advance("function");
4830. 113 the_function = Object.assign(token_now, {
4831. 113 arity: the_async.arity,
4832. 113 async: 1
4833. 113 });
4834. 113 prefix_function();
4835. 1 if (the_function.async === 1) {
4836. 1
4837. 1// test_cause:
4838. 1// ["
4839. 1// async function aa(){}
4840. 1// ", "prefix_async", "missing_await_statement", "function", 7]
4841. 1
4842. 1 warn("missing_await_statement", the_function);
4843. 1 }
4844. 113 return the_function;
4845. 113 }
4846. 591
4847. 260 function prefix_await() {
4848. 260 const the_await = token_now;
4849. 3 if (functionage.async === 0) {
4850. 3
4851. 3// test_cause:
4852. 3// ["await", "prefix_await", "unexpected_a", "await", 1]
4853. 3// ["function aa(){aa=await 0;}", "prefix_await", "unexpected_a", "await", 18]
4854. 3// ["function aa(){await 0;}", "prefix_await", "unexpected_a", "await", 15]
4855. 3
4856. 3 warn("unexpected_a", the_await);
4857. 257 } else {
4858. 257 functionage.async += 1;
4859. 257 }
4860. 160 if (the_await.arity === "statement") {
4861. 160 the_await.block = parse_expression();
4862. 160 semicolon();
4863. 160 } else {
4864. 100 the_await.expression = parse_expression();
4865. 259 }
4866. 259 return the_await;
4867. 259 }
4868. 591
4869. 1 function prefix_fart() {
4870. 1
4871. 1// test_cause:
4872. 1// ["=>0", "prefix_fart", "expected_a_before_b", "=>", 1]
4873. 1
4874. 1 return stop("expected_a_before_b", token_now, "()", "=>");
4875. 1 }
4876. 591
4877. 1841 function prefix_function(the_function) {
4878. 11 let name = the_function && the_function.name;
4879. 1830 if (the_function === undefined) {
4880. 1830 the_function = token_now;
4881. 1830
4882. 1830// A function statement must have a name that will be in the parent's scope.
4883. 1830
4884. 1830 if (the_function.arity === "statement") {
4885. 1830 if (!token_nxt.identifier) {
4886. 1830
4887. 1830// test_cause:
4888. 1830// ["function(){}", "prefix_function", "expected_identifier_a", "(", 9]
4889. 1830// ["function*aa(){}", "prefix_function", "expected_identifier_a", "*", 9]
4890. 1830
4891. 1830 return stop("expected_identifier_a");
4892. 1830 }
4893. 1830 name = token_nxt;
4894. 1830 enroll(name, "variable", true);
4895. 1830 the_function.name = Object.assign(name, {
4896. 1830 calls: empty(),
4897. 1830
4898. 1830// PR-331 - Bugfix - Fixes issue #272 - function hoisting not allowed.
4899. 1830
4900. 1830 dead: false,
4901. 1830 init: true
4902. 1830 });
4903. 1830 advance();
4904. 1830 } else if (name === undefined) {
4905. 1830
4906. 1830// A function expression may have an optional name.
4907. 1830
4908. 1830 the_function.name = anon;
4909. 1830 if (token_nxt.identifier) {
4910. 1830 name = token_nxt;
4911. 1830 the_function.name = name;
4912. 1830 advance();
4913. 1830 }
4914. 1830 }
4915. 1839 }
4916. 1839 the_function.level = functionage.level + 1;
4917. 1839
4918. 1839// Probably deadcode.
4919. 1839// if (mode_mega) {
4920. 1839// warn("unexpected_a", the_function);
4921. 1839// }
4922. 1839// jslint_assert(!mode_mega, `Expected !mode_mega.`);
4923. 1839
4924. 1839// Don't create functions in loops. It is inefficient, and it can lead to
4925. 1839// scoping errors.
4926. 1839
4927. 1839 if (functionage.loop > 0) {
4928. 1
4929. 1// test_cause:
4930. 1// ["
4931. 1// while(0){aa.map(function(){});}
4932. 1// ", "prefix_function", "function_in_loop", "function", 17]
4933. 1
4934. 1 warn("function_in_loop", the_function);
4935. 1839 }
4936. 1839
4937. 1839// Give the function properties for storing its names and for observing the
4938. 1839// depth of loops and switches.
4939. 1839
4940. 1839 Object.assign(the_function, {
4941. 1839 async: the_function.async || 0,
4942. 1841 context: empty(),
4943. 1841 finally: 0,
4944. 1841 loop: 0,
4945. 1841 statement_prv: undefined,
4946. 1841 switch: 0,
4947. 1841 try: 0
4948. 1841 });
4949. 801 if (the_function.arity !== "statement" && typeof name === "object") {
4950. 38
4951. 38// test_cause:
4952. 38// ["let aa=function bb(){return;};", "prefix_function", "expression", "", 0]
4953. 38
4954. 38 test_cause("expression");
4955. 38 enroll(name, "function", true);
4956. 38 name.dead = false;
4957. 38 name.init = true;
4958. 38 name.used = 1;
4959. 1839 }
4960. 1839
4961. 1839// Bugfix - fix function-redefinitions not warned inside function-calls.
4962. 1839// Push the current function context and establish a new one.
4963. 1839
4964. 1839 function_stack.push(functionage);
4965. 1839 function_list.push(the_function);
4966. 1839 functionage = the_function;
4967. 1839
4968. 1839// Parse the parameter list.
4969. 1839
4970. 1839 advance("(");
4971. 1839
4972. 1839// test_cause:
4973. 1839// ["function aa(){}", "prefix_function", "opener", "", 0]
4974. 1839
4975. 1839 test_cause("opener");
4976. 1839 token_now.free = false;
4977. 1839 token_now.arity = "function";
4978. 1839 [functionage.parameters, functionage.signature] = prefix_function_arg();
4979. 2513 functionage.parameters.forEach(function enroll_parameter(name) {
4980. 2288 if (name.identifier) {
4981. 2288 enroll(name, "parameter", false);
4982. 2288 } else {
4983. 1839 name.names.forEach(enroll_parameter);
4984. 1839 }
4985. 2513 });
4986. 1839
4987. 1839// The function's body is a block.
4988. 1839
4989. 1839 the_function.block = block("body");
4990. 1839 if (
4991. 1839 the_function.arity === "statement"
4992. 1839 && token_nxt.line === token_now.line
4993. 2 ) {
4994. 2
4995. 2// test_cause:
4996. 2// ["function aa(){}0", "prefix_function", "unexpected_a", "0", 16]
4997. 2
4998. 2 return stop("unexpected_a");
4999. 1826 }
5000. 1826 if (
5001. 1826 token_nxt.id === "."
5002. 1826 || token_nxt.id === "?."
5003. 1824 || token_nxt.id === "["
5004. 3 ) {
5005. 3
5006. 3// test_cause:
5007. 3// ["function aa(){}\n.aa", "prefix_function", "unexpected_a", ".", 1]
5008. 3// ["function aa(){}\n?.aa", "prefix_function", "unexpected_a", "?.", 1]
5009. 3// ["function aa(){}\n[]", "prefix_function", "unexpected_a", "[", 1]
5010. 3
5011. 3 warn("unexpected_a");
5012. 1826 }
5013. 1826
5014. 1826// Check functions are ordered.
5015. 1826
5016. 1826 check_ordered(
5017. 1826 "function",
5018. 1826 function_list.slice(
5019. 1826 function_list.indexOf(the_function) + 1
5020. 2311 ).map(function ({
5021. 2311 level,
5022. 2311 name
5023. 2311 }) {
5024. 1826 return (level === the_function.level + 1) && name;
5025. 2311 }).filter(function (name) {
5026. 1826 return option_dict.beta && name && name.id;
5027. 2311 })
5028. 1826 );
5029. 1826
5030. 1826// Restore the previous context.
5031. 1826
5032. 1826 functionage = function_stack.pop();
5033. 1826 return the_function;
5034. 1826 }
5035. 591
5036. 1847 function prefix_function_arg() {
5037. 1847 const list = [];
5038. 1847 const signature = ["("];
5039. 1847 let optional;
5040. 1847 let subparam;
5041. 1912 function parameter() {
5042. 1912 let ellipsis = false;
5043. 1912 let param;
5044. 198 if (token_nxt.id === "{") {
5045. 198 if (optional !== undefined) {
5046. 198
5047. 198// test_cause:
5048. 198// ["function aa(aa=0,{}){}", "parameter", "required_a_optional_b", "aa", 18]
5049. 198
5050. 198 warn(
5051. 198 "required_a_optional_b",
5052. 198 token_nxt,
5053. 198 token_nxt.id,
5054. 198 optional.id
5055. 198 );
5056. 198 }
5057. 198 param = token_nxt;
5058. 198 param.names = [];
5059. 198 advance("{");
5060. 198 signature.push("{");
5061. 548 while (true) {
5062. 548 subparam = token_nxt;
5063. 548 if (!subparam.identifier) {
5064. 548
5065. 548// test_cause:
5066. 548// ["function aa(aa=0,{}){}", "parameter", "expected_identifier_a", "}", 19]
5067. 548// ["function aa({0}){}", "parameter", "expected_identifier_a", "0", 14]
5068. 548
5069. 548 return stop("expected_identifier_a");
5070. 548 }
5071. 548 survey(subparam);
5072. 548 advance();
5073. 548 signature.push(subparam.id);
5074. 548 if (token_nxt.id === ":") {
5075. 548 advance(":");
5076. 548 advance();
5077. 548 token_now.label = subparam;
5078. 548 subparam = token_now;
5079. 548 if (!subparam.identifier) {
5080. 548
5081. 548// test_cause:
5082. 548// ["function aa({aa:0}){}", "parameter", "expected_identifier_a", "}", 18]
5083. 548
5084. 548 return stop(
5085. 548 "expected_identifier_a",
5086. 548 token_nxt
5087. 548 );
5088. 548 }
5089. 548 }
5090. 548
5091. 548// test_cause:
5092. 548// ["function aa({aa=aa},aa){}", "parameter", "equal", "", 0]
5093. 548
5094. 548 test_cause("equal");
5095. 548 if (token_nxt.id === "=") {
5096. 548 advance("=");
5097. 548 subparam.expression = parse_expression();
5098. 548 param.open = true;
5099. 548 }
5100. 548 param.names.push(subparam);
5101. 548 if (token_nxt.id === ",") {
5102. 548 advance(",");
5103. 548 signature.push(", ");
5104. 548 } else {
5105. 548 break;
5106. 548 }
5107. 548 }
5108. 198 list.push(param);
5109. 198
5110. 198// test_cause:
5111. 198// ["
5112. 198// function aa({bb,aa}){}
5113. 198// ", "check_ordered", "expected_a_b_before_c_d", "aa", 17]
5114. 198
5115. 198 check_ordered("parameter", param.names);
5116. 198 advance("}");
5117. 198 signature.push("}");
5118. 198 if (token_nxt.id === ",") {
5119. 198 advance(",");
5120. 198 signature.push(", ");
5121. 198 return parameter();
5122. 198 }
5123. 1714 } else if (token_nxt.id === "[") {
5124. 1714 if (optional !== undefined) {
5125. 1714
5126. 1714// test_cause:
5127. 1714// ["function aa(aa=0,[]){}", "parameter", "required_a_optional_b", "aa", 18]
5128. 1714
5129. 1714 warn(
5130. 1714 "required_a_optional_b",
5131. 1714 token_nxt,
5132. 1714 token_nxt.id,
5133. 1714 optional.id
5134. 1714 );
5135. 1714 }
5136. 1714 param = token_nxt;
5137. 1714 param.names = [];
5138. 1714 advance("[");
5139. 1714 signature.push("[]");
5140. 1714 while (true) {
5141. 1714 subparam = token_nxt;
5142. 1714 if (!subparam.identifier) {
5143. 1714
5144. 1714// test_cause:
5145. 1714// ["function aa(aa=0,[]){}", "parameter", "expected_identifier_a", "]", 19]
5146. 1714
5147. 1714 return stop("expected_identifier_a");
5148. 1714 }
5149. 1714 advance();
5150. 1714 param.names.push(subparam);
5151. 1714
5152. 1714// test_cause:
5153. 1714// ["function aa([aa=aa],aa){}", "parameter", "id", "", 0]
5154. 1714
5155. 1714 test_cause("id");
5156. 1714 if (token_nxt.id === "=") {
5157. 1714 advance("=");
5158. 1714 subparam.expression = parse_expression();
5159. 1714 param.open = true;
5160. 1714 }
5161. 1714 if (token_nxt.id === ",") {
5162. 1714 advance(",");
5163. 1714 } else {
5164. 1714 break;
5165. 1714 }
5166. 1714 }
5167. 1714 list.push(param);
5168. 1714 advance("]");
5169. 1714 if (token_nxt.id === ",") {
5170. 1714 advance(",");
5171. 1714 signature.push(", ");
5172. 1714 return parameter();
5173. 1714 }
5174. 1714 } else {
5175. 1714 if (token_nxt.id === "...") {
5176. 1714 ellipsis = true;
5177. 1714 signature.push("...");
5178. 1714 advance("...");
5179. 1714 if (optional !== undefined) {
5180. 1714
5181. 1714// test_cause:
5182. 1714// ["function aa(aa=0,...){}", "parameter", "required_a_optional_b", "aa", 21]
5183. 1714
5184. 1714 warn(
5185. 1714 "required_a_optional_b",
5186. 1714 token_nxt,
5187. 1714 token_nxt.id,
5188. 1714 optional.id
5189. 1714 );
5190. 1714 }
5191. 1714 }
5192. 1714 if (!token_nxt.identifier) {
5193. 1714
5194. 1714// test_cause:
5195. 1714// ["function aa(0){}", "parameter", "expected_identifier_a", "0", 13]
5196. 1714
5197. 1714 return stop("expected_identifier_a");
5198. 1714 }
5199. 1714 param = token_nxt;
5200. 1714 list.push(param);
5201. 1714 advance();
5202. 1714 signature.push(param.id);
5203. 1714 if (ellipsis) {
5204. 1714 param.ellipsis = true;
5205. 1714 } else {
5206. 1714 if (token_nxt.id === "=") {
5207. 1714 optional = param;
5208. 1714 advance("=");
5209. 1714 param.expression = parse_expression(0);
5210. 1714 } else {
5211. 1714 if (optional !== undefined) {
5212. 1714
5213. 1714// test_cause:
5214. 1714// ["function aa(aa=0,bb){}", "parameter", "required_a_optional_b", "aa", 18]
5215. 1714
5216. 1714 warn(
5217. 1714 "required_a_optional_b",
5218. 1714 param,
5219. 1714 param.id,
5220. 1714 optional.id
5221. 1714 );
5222. 1714 }
5223. 1714 }
5224. 1714 if (token_nxt.id === ",") {
5225. 1714 advance(",");
5226. 1714 signature.push(", ");
5227. 1714 return parameter();
5228. 1714 }
5229. 1714 }
5230. 1714 }
5231. 1912 }
5232. 1359 if (token_nxt.id !== ")" && token_nxt.id !== "(end)") {
5233. 1359 parameter();
5234. 1839 }
5235. 1839 advance(")");
5236. 1839 signature.push(")");
5237. 1839 return [list, signature.join("")];
5238. 1839 }
5239. 591
5240. 485 function prefix_lbrace() {
5241. 485 const seen = empty();
5242. 485 const the_brace = token_now;
5243. 485 let extra;
5244. 485 let full;
5245. 485 let id;
5246. 485 let name;
5247. 485 let the_colon;
5248. 485 let value;
5249. 485 the_brace.expression = [];
5250. 445 if (token_nxt.id !== "}") {
5251. 445
5252. 445// Parse/loop through each property in {...}.
5253. 445
5254. 1632 while (true) {
5255. 1632 name = token_nxt;
5256. 1632 advance();
5257. 1632 if (
5258. 1632 (name.id === "get" || name.id === "set")
5259. 1632 && token_nxt.identifier
5260. 1632 ) {
5261. 1632 if (!option_dict.getset) {
5262. 1632
5263. 1632// test_cause:
5264. 1632// ["aa={get aa(){}}", "prefix_lbrace", "unexpected_a", "get", 5]
5265. 1632
5266. 1632 warn("unexpected_a", name);
5267. 1632 }
5268. 1632 extra = name.id;
5269. 1632 full = extra + " " + token_nxt.id;
5270. 1632 name = token_nxt;
5271. 1632 advance();
5272. 1632 id = survey(name);
5273. 1632 if (seen[full] === true || seen[id] === true) {
5274. 1632
5275. 1632// test_cause:
5276. 1632// ["aa={get aa(){},get aa(){}}", "prefix_lbrace", "duplicate_a", "aa", 20]
5277. 1632
5278. 1632 warn("duplicate_a", name);
5279. 1632 }
5280. 1632 seen[id] = false;
5281. 1632 seen[full] = true;
5282. 1632 } else if (name.id === "`") {
5283. 1632
5284. 1632// test_cause:
5285. 1632// ["aa={`aa`:0}", "prefix_lbrace", "unexpected_a", "`", 5]
5286. 1632
5287. 1632 stop("unexpected_a", name);
5288. 1632
5289. 1632 } else {
5290. 1632 id = survey(name);
5291. 1632 if (typeof seen[id] === "boolean") {
5292. 1632
5293. 1632// test_cause:
5294. 1632// ["aa={aa,aa}", "prefix_lbrace", "duplicate_a", "aa", 8]
5295. 1632
5296. 1632 warn("duplicate_a", name);
5297. 1632 }
5298. 1632 seen[id] = true;
5299. 1632 }
5300. 1632 if (name.identifier) {
5301. 1632 if (token_nxt.id === "}" || token_nxt.id === ",") {
5302. 1632 if (typeof extra === "string") {
5303. 1632
5304. 1632// test_cause:
5305. 1632// ["aa={get aa}", "prefix_lbrace", "closer", "", 0]
5306. 1632
5307. 1632 test_cause("closer");
5308. 1632 advance("(");
5309. 1632 }
5310. 1632 value = parse_expression(Infinity, true);
5311. 1632 } else if (token_nxt.id === "(") {
5312. 1632
5313. 1632// test_cause:
5314. 1632// ["aa={aa()}", "prefix_lbrace", "paren", "", 0]
5315. 1632// ["aa={get aa(){}}", "prefix_lbrace", "paren", "", 0]
5316. 1632
5317. 1632 test_cause("paren");
5318. 1632 value = prefix_function({
5319. 1632 arity: "unary",
5320. 1632 from: name.from,
5321. 1632 id: "function",
5322. 1632 line: name.line,
5323. 1632 name: (
5324. 1632 typeof extra === "string"
5325. 1632 ? extra
5326. 1632 : id
5327. 1632 ),
5328. 1632 thru: name.from
5329. 1632 });
5330. 1632 } else {
5331. 1632 if (typeof extra === "string") {
5332. 1632
5333. 1632// test_cause:
5334. 1632// ["aa={get aa.aa}", "prefix_lbrace", "paren", "", 0]
5335. 1632
5336. 1632 test_cause("paren");
5337. 1632 advance("(");
5338. 1632 }
5339. 1632 the_colon = token_nxt;
5340. 1632 advance(":");
5341. 1632 value = parse_expression(0);
5342. 1632 if (
5343. 1632 value.id === name.id
5344. 1632 && value.id !== "function"
5345. 1632 ) {
5346. 1632
5347. 1632// test_cause:
5348. 1632// ["aa={aa:aa}", "prefix_lbrace", "unexpected_a", ": aa", 7]
5349. 1632
5350. 1632 warn("unexpected_a", the_colon, ": " + name.id);
5351. 1632 }
5352. 1632 }
5353. 1632 value.label = name;
5354. 1632 if (typeof extra === "string") {
5355. 1632 value.extra = extra;
5356. 1632 }
5357. 1632 the_brace.expression.push(value);
5358. 1632 } else {
5359. 1632
5360. 1632// test_cause:
5361. 1632// ["aa={\"aa\":0}", "prefix_lbrace", "colon", "", 0]
5362. 1632
5363. 1632 test_cause("colon");
5364. 1632 advance(":");
5365. 1632 value = parse_expression(0);
5366. 1632 value.label = name;
5367. 1632 the_brace.expression.push(value);
5368. 1632 }
5369. 1632 if (token_nxt.id !== ",") {
5370. 1632 break;
5371. 1632 }
5372. 1632
5373. 1632// test_cause:
5374. 1632// ["aa={\"aa\":0,\"bb\":0}", "prefix_lbrace", "comma", "", 0]
5375. 1632
5376. 1632 test_cause("comma");
5377. 1632 advance(",");
5378. 1632 if (token_nxt.id === "}") {
5379. 1632
5380. 1632// test_cause:
5381. 1632// ["let aa={aa:0,}", "prefix_lbrace", "unexpected_a", ",", 13]
5382. 1632
5383. 1632 warn("unexpected_a", token_now);
5384. 1632 break;
5385. 1632 }
5386. 1632 }
5387. 480 }
5388. 480
5389. 480// test_cause:
5390. 480// ["aa={bb,aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
5391. 480
5392. 480 check_ordered(
5393. 480 "property",
5394. 1627 the_brace.expression.map(function ({
5395. 1627 label
5396. 1627 }) {
5397. 1627 return label;
5398. 1627 })
5399. 480 );
5400. 480 advance("}");
5401. 480 return the_brace;
5402. 480 }
5403. 591
5404. 651 function prefix_lbracket() {
5405. 651 const the_token = token_now;
5406. 651 let element;
5407. 651 let ellipsis;
5408. 651 the_token.expression = [];
5409. 331 if (token_nxt.id !== "]") {
5410. 331
5411. 331// Parse/loop through each element in [...].
5412. 331
5413. 1546 while (true) {
5414. 1546 ellipsis = false;
5415. 1546 if (token_nxt.id === "...") {
5416. 1546 ellipsis = true;
5417. 1546 advance("...");
5418. 1546 }
5419. 1546 element = parse_expression(10);
5420. 1546 if (ellipsis) {
5421. 1546 element.ellipsis = true;
5422. 1546 }
5423. 1546 the_token.expression.push(element);
5424. 1546 if (token_nxt.id !== ",") {
5425. 1546 break;
5426. 1546 }
5427. 1546 advance(",");
5428. 1546 if (token_nxt.id === "]") {
5429. 1546
5430. 1546// test_cause:
5431. 1546// ["let aa=[0,]", "prefix_lbracket", "unexpected_a", ",", 10]
5432. 1546
5433. 1546 warn("unexpected_a", token_now);
5434. 1546 break;
5435. 1546 }
5436. 1546 }
5437. 331 }
5438. 651 advance("]");
5439. 651 return the_token;
5440. 651 }
5441. 591
5442. 1357 function prefix_lparen() {
5443. 1357 const cadet = lookahead().id;
5444. 1357 const the_paren = token_now;
5445. 1357 let the_value;
5446. 1357
5447. 1357// We can distinguish between a parameter list for => and a wrapped expression
5448. 1357// with one token of lookahead.
5449. 1357
5450. 1357 if (
5451. 1357 token_nxt.id === ")"
5452. 1349 || token_nxt.id === "..."
5453. 1349 || (token_nxt.identifier && (cadet === "," || cadet === "="))
5454. 8 ) {
5455. 8
5456. 8// test_cause:
5457. 8// ["()=>0", "prefix_lparen", "fart", "", 0]
5458. 8
5459. 8 test_cause("fart");
5460. 8 the_paren.free = false;
5461. 8 return parse_fart(prefix_function_arg());
5462. 1349 }
5463. 1349
5464. 1349// test_cause:
5465. 1349// ["(0)", "prefix_lparen", "expr", "", 0]
5466. 1349
5467. 1349 test_cause("expr");
5468. 1349 the_paren.free = true;
5469. 1349 the_value = parse_expression(0);
5470. 1349 if (the_value.wrapped === true) {
5471. 1
5472. 1// test_cause:
5473. 1// ["((0))", "prefix_lparen", "unexpected_a", "(", 1]
5474. 1
5475. 1 warn("unexpected_a", the_paren);
5476. 1349 }
5477. 1349 the_value.wrapped = true;
5478. 1349 advance(")", the_paren);
5479. 1349 if (token_nxt.id === "=>") {
5480. 7 if (the_value.arity !== "variable") {
5481. 7 if (the_value.id === "{" || the_value.id === "[") {
5482. 7
5483. 7// test_cause:
5484. 7// ["([])=>0", "prefix_lparen", "expected_a_before_b", "(", 1]
5485. 7// ["({})=>0", "prefix_lparen", "expected_a_before_b", "(", 1]
5486. 7
5487. 7 warn("expected_a_before_b", the_paren, "function", "(");
5488. 7
5489. 7// test_cause:
5490. 7// ["([])=>0", "prefix_lparen", "expected_a_b", "=>", 5]
5491. 7// ["({})=>0", "prefix_lparen", "expected_a_b", "=>", 5]
5492. 7
5493. 7 return stop("expected_a_b", token_nxt, "{", "=>");
5494. 7 }
5495. 7
5496. 7// test_cause:
5497. 7// ["(0)=>0", "prefix_lparen", "expected_identifier_a", "0", 2]
5498. 7
5499. 7 return stop("expected_identifier_a", the_value);
5500. 7 }
5501. 7 the_paren.expression = [the_value];
5502. 7 return parse_fart([the_paren.expression, "(" + the_value.id + ")"]);
5503. 1341 }
5504. 1341 return the_value;
5505. 1341 }
5506. 591
5507. 123 function prefix_new() {
5508. 123 const the_new = token_now;
5509. 123 let right;
5510. 123 right = parse_expression(160);
5511. 1 if (token_nxt.id !== "(") {
5512. 1
5513. 1// test_cause:
5514. 1// ["new aa", "prefix_new", "expected_a_before_b", "(end)", 1]
5515. 1
5516. 1 warn("expected_a_before_b", token_nxt, "()", artifact());
5517. 1 }
5518. 123 the_new.expression = right;
5519. 123 return the_new;
5520. 123 }
5521. 591
5522. 702 function prefix_tick() {
5523. 702 const the_tick = token_now;
5524. 702 the_tick.value = [];
5525. 702 the_tick.expression = [];
5526. 702 if (token_nxt.id !== "`") {
5527. 702
5528. 702// Parse/loop through each token in `${...}`.
5529. 702
5530. 1327 while (true) {
5531. 1327 advance("(string)");
5532. 1327 the_tick.value.push(token_now);
5533. 1327 if (token_nxt.id !== "${") {
5534. 1327 break;
5535. 1327 }
5536. 1327 advance("${");
5537. 1327
5538. 1327// test_cause:
5539. 1327// ["let aa=`${}`;", "prefix_tick", "${", "", 0]
5540. 1327
5541. 1327 test_cause("${");
5542. 1327 the_tick.expression.push(parse_expression(0));
5543. 1327 advance("}");
5544. 1327 }
5545. 700 }
5546. 700 advance("`");
5547. 700 return the_tick;
5548. 700 }
5549. 591
5550. 2 function prefix_void() {
5551. 2 const the_void = token_now;
5552. 2
5553. 2// test_cause:
5554. 2// ["void 0", "prefix_void", "unexpected_a", "void", 1]
5555. 2// ["void", "prefix_void", "unexpected_a", "void", 1]
5556. 2
5557. 2 warn("unexpected_a", the_void);
5558. 2 the_void.expression = parse_expression(0);
5559. 2 return the_void;
5560. 2 }
5561. 591
5562. 12545 function semicolon() {
5563. 12545
5564. 12545// Try to match a semicolon.
5565. 12545
5566. 12327 if (token_nxt.id === ";") {
5567. 12327 advance(";");
5568. 12327 } else {
5569. 218
5570. 218// test_cause:
5571. 218// ["0", "semicolon", "expected_a_b", "(end)", 1]
5572. 218
5573. 218 warn_at(
5574. 218 "expected_a_b",
5575. 218 token_now.line,
5576. 218 token_now.thru + 1,
5577. 218 ";",
5578. 218 artifact()
5579. 218 );
5580. 218 }
5581. 12545 anon = "anonymous";
5582. 12545 }
5583. 591
5584. 13593 function stmt(id, fud) {
5585. 13593
5586. 13593// Create a statement.
5587. 13593
5588. 13593 const the_symbol = symbol(id);
5589. 13593 the_symbol.fud = fud;
5590. 13593 return the_symbol;
5591. 13593 }
5592. 591
5593. 959 function stmt_break() {
5594. 959 const the_break = token_now;
5595. 959 let the_label;
5596. 959 if (
5597. 688 (functionage.loop < 1 && functionage.switch < 1)
5598. 952 || functionage.finally > 0
5599. 7 ) {
5600. 7
5601. 7// test_cause:
5602. 7// ["break", "stmt_break", "unexpected_a", "break", 1]
5603. 7
5604. 7 warn("unexpected_a", the_break);
5605. 7 }
5606. 959 the_break.disrupt = true;
5607. 5 if (token_nxt.identifier && token_now.line === token_nxt.line) {
5608. 5 the_label = functionage.context[token_nxt.id];
5609. 5 if (
5610. 5 the_label === undefined
5611. 5 || the_label.role !== "label"
5612. 5 || the_label.dead
5613. 5 ) {
5614. 5 if (the_label !== undefined && the_label.dead) {
5615. 5
5616. 5// test_cause:
5617. 5// ["aa:{function aa(aa){break aa;}}", "stmt_break", "out_of_scope_a", "aa", 27]
5618. 5
5619. 5 warn("out_of_scope_a");
5620. 5 } else {
5621. 5
5622. 5// test_cause:
5623. 5// ["aa:{break aa;}", "stmt_break", "not_label_a", "aa", 11]
5624. 5
5625. 5 warn("not_label_a");
5626. 5 }
5627. 5 } else {
5628. 5 the_label.used += 1;
5629. 5 }
5630. 5 the_break.label = token_nxt;
5631. 5 advance();
5632. 5 }
5633. 959 advance(";");
5634. 959 return the_break;
5635. 959 }
5636. 591
5637. 2 function stmt_continue() {
5638. 2 const the_continue = token_now;
5639. 1 if (functionage.loop < 1 || functionage.finally > 0) {
5640. 2
5641. 2// test_cause:
5642. 2// ["continue", "stmt_continue", "unexpected_a", "continue", 1]
5643. 2// ["
5644. 2// function aa(){while(0){try{}finally{continue}}}
5645. 2// ", "stmt_continue", "unexpected_a", "continue", 37]
5646. 2
5647. 2 warn("unexpected_a", the_continue);
5648. 2 }
5649. 2 check_not_top_level(the_continue);
5650. 2 the_continue.disrupt = true;
5651. 2 warn("unexpected_a", the_continue);
5652. 2 advance(";");
5653. 2 return the_continue;
5654. 2 }
5655. 591
5656. 3 function stmt_debugger() {
5657. 3 const the_debug = token_now;
5658. 1 if (!option_dict.devel) {
5659. 1
5660. 1// test_cause:
5661. 1// ["debugger", "stmt_debugger", "unexpected_a", "debugger", 1]
5662. 1
5663. 1 warn("unexpected_a", the_debug);
5664. 1 }
5665. 3 semicolon();
5666. 3 return the_debug;
5667. 3 }
5668. 591
5669. 71 function stmt_delete() {
5670. 71 const the_token = token_now;
5671. 71 const the_value = parse_expression(0);
5672. 71 if (
5673. 1 (the_value.id !== "." && the_value.id !== "[")
5674. 70 || the_value.arity !== "binary"
5675. 1 ) {
5676. 1
5677. 1// test_cause:
5678. 1// ["delete 0", "stmt_delete", "expected_a_b", "0", 8]
5679. 1
5680. 1 stop("expected_a_b", the_value, ".", artifact(the_value));
5681. 70 }
5682. 70 the_token.expression = the_value;
5683. 70 semicolon();
5684. 70 return the_token;
5685. 70 }
5686. 591
5687. 5 function stmt_do() {
5688. 5 const the_do = token_now;
5689. 5 check_not_top_level(the_do);
5690. 5 functionage.loop += 1;
5691. 5 the_do.block = block();
5692. 5 advance("while");
5693. 5 the_do.expression = condition();
5694. 5 semicolon();
5695. 1 if (the_do.block.disrupt === true) {
5696. 1
5697. 1// test_cause:
5698. 1// ["function aa(){do{break;}while(0)}", "stmt_do", "weird_loop", "do", 15]
5699. 1
5700. 1 warn("weird_loop", the_do);
5701. 3 }
5702. 3 functionage.loop -= 1;
5703. 3 return the_do;
5704. 3 }
5705. 591
5706. 22 function stmt_export() {
5707. 22 const the_export = token_now;
5708. 22 let the_id;
5709. 22 let the_name;
5710. 22 let the_thing;
5711. 22
5712. 22 the_export.expression = [];
5713. 11 if (token_nxt.id === "default") {
5714. 11 if (export_dict.default !== undefined) {
5715. 11
5716. 11// test_cause:
5717. 11// ["
5718. 11// export default 0;export default 0
5719. 11// ", "stmt_export", "duplicate_a", "default", 25]
5720. 11
5721. 11 warn("duplicate_a");
5722. 11 }
5723. 11 advance("default");
5724. 11 the_thing = parse_expression(0);
5725. 11 if (
5726. 11 the_thing.id !== "("
5727. 11 || the_thing.expression[0].id !== "."
5728. 11 || the_thing.expression[0].expression.id !== "Object"
5729. 11 || the_thing.expression[0].name.id !== "freeze"
5730. 11 ) {
5731. 11
5732. 11// test_cause:
5733. 11// ["export default {}", "stmt_export", "freeze_exports", "{", 16]
5734. 11
5735. 11 warn("freeze_exports", the_thing);
5736. 11
5737. 11// PR-301 - Bugfix - Fixes issues #282 - optional-semicolon.
5738. 11
5739. 11 } else {
5740. 11
5741. 11// test_cause:
5742. 11// ["
5743. 11// export default Object.freeze({})
5744. 11// ", "semicolon", "expected_a_b", "(end)", 32]
5745. 11
5746. 11 semicolon();
5747. 11 }
5748. 11 export_dict.default = the_thing;
5749. 11 the_export.expression.push(the_thing);
5750. 11 } else {
5751. 11 if (token_nxt.id === "function") {
5752. 11
5753. 11// test_cause:
5754. 11// ["export function aa(){}", "stmt_export", "freeze_exports", "function", 8]
5755. 11
5756. 11 warn("freeze_exports");
5757. 11 the_thing = parse_statement();
5758. 11 the_name = the_thing.name;
5759. 11 the_id = the_name.id;
5760. 11 the_name.used += 1;
5761. 11 if (export_dict[the_id] !== undefined) {
5762. 11
5763. 11// test_cause:
5764. 11// ["
5765. 11// let aa;export{aa};export function aa(){}
5766. 11// ", "stmt_export", "duplicate_a", "aa", 35]
5767. 11
5768. 11 warn("duplicate_a", the_name);
5769. 11 }
5770. 11 export_dict[the_id] = the_thing;
5771. 11 the_export.expression.push(the_thing);
5772. 11 the_thing.statement = false;
5773. 11 the_thing.arity = "unary";
5774. 11 } else if (
5775. 11 token_nxt.id === "var"
5776. 11 || token_nxt.id === "let"
5777. 11 || token_nxt.id === "const"
5778. 11 ) {
5779. 11
5780. 11// test_cause:
5781. 11// ["export const", "stmt_export", "unexpected_a", "const", 8]
5782. 11// ["export let", "stmt_export", "unexpected_a", "let", 8]
5783. 11// ["export var", "stmt_export", "unexpected_a", "var", 8]
5784. 11
5785. 11 warn("unexpected_a");
5786. 11 parse_statement();
5787. 11 } else if (token_nxt.id === "{") {
5788. 11
5789. 11// test_cause:
5790. 11// ["export {}", "stmt_export", "advance{", "", 0]
5791. 11
5792. 11 test_cause("advance{");
5793. 11 advance("{");
5794. 11 while (true) {
5795. 11 if (!token_nxt.identifier) {
5796. 11
5797. 11// test_cause:
5798. 11// ["export {}", "stmt_export", "expected_identifier_a", "}", 9]
5799. 11
5800. 11 stop("expected_identifier_a");
5801. 11 }
5802. 11 the_id = token_nxt.id;
5803. 11 the_name = token_global.context[the_id];
5804. 11 if (the_name === undefined) {
5805. 11
5806. 11// test_cause:
5807. 11// ["export {aa}", "stmt_export", "unexpected_a", "aa", 9]
5808. 11
5809. 11 warn("unexpected_a");
5810. 11 } else {
5811. 11 the_name.used += 1;
5812. 11 if (export_dict[the_id] !== undefined) {
5813. 11
5814. 11// test_cause:
5815. 11// ["let aa;export{aa,aa}", "stmt_export", "duplicate_a", "aa", 18]
5816. 11
5817. 11 warn("duplicate_a");
5818. 11 }
5819. 11 export_dict[the_id] = the_name;
5820. 11 }
5821. 11 advance();
5822. 11 the_export.expression.push(the_thing);
5823. 11 if (token_nxt.id === ",") {
5824. 11 advance(",");
5825. 11 } else {
5826. 11 break;
5827. 11 }
5828. 11 }
5829. 11 advance("}");
5830. 11 semicolon();
5831. 11 } else {
5832. 11
5833. 11// test_cause:
5834. 11// ["export", "stmt_export", "unexpected_a", "(end)", 1]
5835. 11
5836. 11 stop("unexpected_a");
5837. 11 }
5838. 16 }
5839. 16 state.mode_module = true;
5840. 16 return the_export;
5841. 16 }
5842. 591
5843. 12 function stmt_for() {
5844. 12 let first;
5845. 12 let the_for = token_now;
5846. 7 if (!option_dict.for) {
5847. 7
5848. 7// test_cause:
5849. 7// ["for", "stmt_for", "unexpected_a", "for", 1]
5850. 7
5851. 7 warn("unexpected_a", the_for);
5852. 7 }
5853. 12 check_not_top_level(the_for);
5854. 12 functionage.loop += 1;
5855. 12 advance("(");
5856. 12 token_now.free = true;
5857. 1 if (token_nxt.id === ";") {
5858. 1
5859. 1// test_cause:
5860. 1// ["for(;;){}", "stmt_for", "expected_a_b", "for (;", 1]
5861. 1
5862. 1 return stop("expected_a_b", the_for, "while (", "for (;");
5863. 9 }
5864. 9 switch (token_nxt.id) {
5865. 9 case "const":
5866. 1 case "let":
5867. 1 case "var":
5868. 1
5869. 1// test_cause:
5870. 1// ["for(const aa in aa){}", "stmt_for", "unexpected_a", "const", 5]
5871. 1
5872. 1 return stop("unexpected_a");
5873. 8 }
5874. 8 first = parse_expression(0);
5875. 8 if (first.id === "in") {
5876. 2 if (first.expression[0].arity !== "variable") {
5877. 2
5878. 2// test_cause:
5879. 2// ["for(0 in aa){}", "stmt_for", "bad_assignment_a", "0", 5]
5880. 2
5881. 2 warn("bad_assignment_a", first.expression[0]);
5882. 2 }
5883. 2 the_for.name = first.expression[0];
5884. 2 the_for.expression = first.expression[1];
5885. 2 warn("expected_a_b", the_for, "Object.keys", "for in");
5886. 6 } else {
5887. 6 the_for.initial = first;
5888. 6 advance(";");
5889. 6 the_for.expression = parse_expression(0);
5890. 6 advance(";");
5891. 6 the_for.inc = parse_expression(0);
5892. 6 if (the_for.inc.id === "++") {
5893. 6
5894. 6// test_cause:
5895. 6// ["for(aa;aa;aa++){}", "stmt_for", "expected_a_b", "++", 13]
5896. 6
5897. 6 warn("expected_a_b", the_for.inc, "+= 1", "++");
5898. 6 }
5899. 8 }
5900. 8 advance(")");
5901. 8 the_for.block = block();
5902. 8 if (the_for.block.disrupt === true) {
5903. 1
5904. 1// test_cause:
5905. 1// ["
5906. 1// /*jslint for*/
5907. 1// function aa(bb,cc){for(0;0;0){break;}}
5908. 1// ", "stmt_for", "weird_loop", "for", 20]
5909. 1
5910. 1 warn("weird_loop", the_for);
5911. 8 }
5912. 8 functionage.loop -= 1;
5913. 8 return the_for;
5914. 8 }
5915. 591
5916. 2999 function stmt_if() {
5917. 2999 const the_if = token_now;
5918. 2999 let the_else;
5919. 2999 the_if.expression = condition();
5920. 2999 the_if.block = block();
5921. 658 if (token_nxt.id === "else") {
5922. 658 advance("else");
5923. 658 the_else = token_now;
5924. 658 the_if.else = (
5925. 658 token_nxt.id === "if"
5926. 658 ? parse_statement()
5927. 658 : block()
5928. 658 );
5929. 658
5930. 658// test_cause:
5931. 658// ["if(0){0}else if(0){0}", "stmt_if", "else", "", 0]
5932. 658// ["if(0){0}else{0}", "stmt_if", "else", "", 0]
5933. 658
5934. 658 test_cause("else");
5935. 658 if (the_if.block.disrupt === true) {
5936. 658 if (the_if.else.disrupt === true) {
5937. 658
5938. 658// test_cause:
5939. 658// ["if(0){break;}else{break;}", "stmt_if", "disrupt", "", 0]
5940. 658
5941. 658 test_cause("disrupt");
5942. 658 the_if.disrupt = true;
5943. 658 } else {
5944. 658
5945. 658// test_cause:
5946. 658// ["if(0){break;}else{}", "stmt_if", "unexpected_a", "else", 14]
5947. 658
5948. 658 warn("unexpected_a", the_else);
5949. 658 }
5950. 658 }
5951. 2998 }
5952. 2998 return the_if;
5953. 2998 }
5954. 591
5955. 42 function stmt_import() {
5956. 42 const the_import = token_now;
5957. 42 let name;
5958. 42 let names;
5959. 42
5960. 42// PR-347 - Disable warning "unexpected_directive_a".
5961. 42// if (typeof state.mode_module === "object") {
5962. 42//
5963. 42// // test_cause:
5964. 42// // ["
5965. 42// // /*global aa*/
5966. 42// // import aa from "aa"
5967. 42// // ", "stmt_import", "unexpected_directive_a", "global", 1]
5968. 42//
5969. 42// warn(
5970. 42// "unexpected_directive_a",
5971. 42// state.mode_module,
5972. 42// state.mode_module.directive
5973. 42// );
5974. 42// }
5975. 42
5976. 42 state.mode_module = true;
5977. 38 if (token_nxt.identifier) {
5978. 38 name = token_nxt;
5979. 38 advance();
5980. 38 if (name.id === "ignore") {
5981. 38
5982. 38// test_cause:
5983. 38// ["import ignore from \"aa\"", "stmt_import", "unexpected_a", "ignore", 8]
5984. 38
5985. 38 warn("unexpected_a", name);
5986. 38 }
5987. 38 enroll(name, "variable", true);
5988. 38 the_import.name = name;
5989. 38 } else {
5990. 4 names = [];
5991. 4 advance("{");
5992. 4 if (token_nxt.id !== "}") {
5993. 4 while (true) {
5994. 4 if (!token_nxt.identifier) {
5995. 4
5996. 4// test_cause:
5997. 4// ["import {", "stmt_import", "expected_identifier_a", "(end)", 1]
5998. 4
5999. 4 stop("expected_identifier_a");
6000. 4 }
6001. 4 name = token_nxt;
6002. 4 advance();
6003. 4 if (name.id === "ignore") {
6004. 4
6005. 4// test_cause:
6006. 4// ["import {ignore} from \"aa\"", "stmt_import", "unexpected_a", "ignore", 9]
6007. 4
6008. 4 warn("unexpected_a", name);
6009. 4 }
6010. 4 enroll(name, "variable", true);
6011. 4 names.push(name);
6012. 4 if (token_nxt.id !== ",") {
6013. 4 break;
6014. 4 }
6015. 4 advance(",");
6016. 4 }
6017. 4 }
6018. 4 advance("}");
6019. 4 the_import.name = names;
6020. 41 }
6021. 41 advance("from");
6022. 41 advance("(string)");
6023. 41 the_import.import = token_now;
6024. 41 if (!(
6025. 41 // rx_module
6026. 41 /^[a-zA-Z0-9_$:.@\-\/]+$/
6027. 41 ).test(token_now.value)) {
6028. 1
6029. 1// test_cause:
6030. 1// ["import aa from \"!aa\"", "stmt_import", "bad_module_name_a", "!aa", 16]
6031. 1
6032. 1 warn("bad_module_name_a", token_now);
6033. 41 }
6034. 41 import_list.push(token_now.value);
6035. 41 semicolon();
6036. 41 return the_import;
6037. 41 }
6038. 591
6039. 5 function stmt_lbrace() {
6040. 5
6041. 5// test_cause:
6042. 5// [";{}", "stmt_lbrace", "naked_block", "{", 2]
6043. 5// ["class aa{}", "stmt_lbrace", "naked_block", "{", 9]
6044. 5
6045. 5 warn("naked_block", token_now);
6046. 5 return block("naked");
6047. 5 }
6048. 591
6049. 1673 function stmt_return() {
6050. 1673 const the_return = token_now;
6051. 1673 check_not_top_level(the_return);
6052. 1 if (functionage.finally > 0) {
6053. 1
6054. 1// test_cause:
6055. 1// ["
6056. 1// function aa(){try{}finally{return;}}
6057. 1// ", "stmt_return", "unexpected_a", "return", 28]
6058. 1
6059. 1 warn("unexpected_a", the_return);
6060. 1 }
6061. 1673 the_return.disrupt = true;
6062. 1480 if (token_nxt.id !== ";" && the_return.line === token_nxt.line) {
6063. 1480 the_return.expression = parse_expression(10);
6064. 1480 }
6065. 1673 advance(";");
6066. 1673 return the_return;
6067. 1673 }
6068. 591
6069. 5 function stmt_semicolon() {
6070. 5
6071. 5// test_cause:
6072. 5// [";", "stmt_semicolon", "unexpected_a", ";", 1]
6073. 5
6074. 5 warn("unexpected_a", token_now);
6075. 5 return token_now;
6076. 5 }
6077. 591
6078. 184 function stmt_switch() {
6079. 184 const the_cases = [];
6080. 184 const the_switch = token_now;
6081. 184 let dups = [];
6082. 184 let exp;
6083. 184 let last;
6084. 184 let stmts;
6085. 184 let the_case;
6086. 184 let the_default;
6087. 184 let the_disrupt = true;
6088. 184 let the_last;
6089. 22077 function is_dup(thing) {
6090. 22077 return is_equal(thing, exp);
6091. 22077 }
6092. 184 check_not_top_level(the_switch);
6093. 1 if (functionage.finally > 0) {
6094. 1
6095. 1// test_cause:
6096. 1// ["
6097. 1// function aa(){try{}finally{switch(0){}}}
6098. 1// ", "stmt_switch", "unexpected_a", "switch", 28]
6099. 1
6100. 1 warn("unexpected_a", the_switch);
6101. 1 }
6102. 184 functionage.switch += 1;
6103. 184 advance("(");
6104. 184 token_now.free = true;
6105. 184 the_switch.expression = parse_expression(0);
6106. 184 the_switch.block = the_cases;
6107. 184 advance(")");
6108. 184 advance("{");
6109. 988 while (true) {
6110. 988
6111. 988// Loop through cases with breaks.
6112. 988
6113. 988 the_case = token_nxt;
6114. 988 the_case.arity = "statement";
6115. 988 the_case.expression = [];
6116. 1478 while (true) {
6117. 1478
6118. 1478// Loop through fallthrough cases.
6119. 1478
6120. 1478 advance("case");
6121. 1478 token_now.switch = true;
6122. 1478 exp = parse_expression(0);
6123. 1478 if (dups.some(is_dup)) {
6124. 1478
6125. 1478// test_cause:
6126. 1478// ["
6127. 1478// switch(0){case 0:break;case 0:break}
6128. 1478// ", "stmt_switch", "unexpected_a", "0", 29]
6129. 1478
6130. 1478 warn("unexpected_a", exp);
6131. 1478 }
6132. 1478 dups.push(exp);
6133. 1478 the_case.expression.push(exp);
6134. 1478 advance(":");
6135. 1478 if (token_nxt.id !== "case") {
6136. 1478 break;
6137. 1478 }
6138. 1478 }
6139. 988
6140. 988// test_cause:
6141. 988// ["
6142. 988// switch(0){case 1:case 0:break;}
6143. 988// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 23]
6144. 988// ["
6145. 988// switch(0){case "aa":case 0:break;}
6146. 988// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 26]
6147. 988// ["
6148. 988// switch(0){case "bb":case "aa":break;}
6149. 988// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 26]
6150. 988// ["
6151. 988// switch(0){case aa:case "aa":break;}
6152. 988// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
6153. 988// ["
6154. 988// switch(0){case bb:case aa:break;}
6155. 988// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 24]
6156. 988
6157. 988 check_ordered_case(the_case.expression);
6158. 988 stmts = parse_statements();
6159. 988 if (stmts.length < 1) {
6160. 988
6161. 988// test_cause:
6162. 988// ["
6163. 988// switch(0){case 0:default:}
6164. 988// ", "stmt_switch", "expected_statements_a", "default", 18]
6165. 988// ["switch(0){case 0:}", "stmt_switch", "expected_statements_a", "}", 18]
6166. 988
6167. 988 warn("expected_statements_a");
6168. 988
6169. 988// PR-359 - Bugfix - Fixes issue #358 - switch-statement crashes jslint.
6170. 988
6171. 988 break;
6172. 988 }
6173. 988 the_case.block = stmts;
6174. 988 the_cases.push(the_case);
6175. 988 last = stmts[stmts.length - 1];
6176. 988 if (last.disrupt) {
6177. 988 if (last.id === "break" && last.label === undefined) {
6178. 988 the_disrupt = false;
6179. 988 }
6180. 988 } else {
6181. 988 warn("expected_a_before_b", token_nxt, "break;", artifact());
6182. 988 }
6183. 988 if (token_nxt.id !== "case") {
6184. 988 break;
6185. 988 }
6186. 988 }
6187. 181
6188. 181// test_cause:
6189. 181// ["
6190. 181// switch(0){case 1:break;case 0:break;}
6191. 181// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 29]
6192. 181// ["
6193. 181// switch(0){case "aa":break;case 0:break;}
6194. 181// ", "check_ordered_case", "expected_a_b_before_c_d", "case-number", 32]
6195. 181// ["
6196. 181// switch(0){case "bb":break;case "aa":break;}
6197. 181// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 32]
6198. 181// ["
6199. 181// switch(0){case aa:break;case "aa":break;}
6200. 181// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
6201. 181// ["
6202. 181// switch(0){case bb:break;case aa:break;}
6203. 181// ", "check_ordered_case", "expected_a_b_before_c_d", "aa", 30]
6204. 181
6205. 983 check_ordered_case(the_cases.map(function ({
6206. 983 expression
6207. 983 }) {
6208. 983 return expression[0];
6209. 983 }));
6210. 181 dups = undefined;
6211. 181 if (token_nxt.id === "default") {
6212. 86 the_default = token_nxt;
6213. 86 advance("default");
6214. 86 token_now.switch = true;
6215. 86 advance(":");
6216. 86 the_switch.else = parse_statements();
6217. 86 if (the_switch.else.length < 1) {
6218. 86
6219. 86// test_cause:
6220. 86// ["
6221. 86// switch(0){case 0:break;default:}
6222. 86// ", "stmt_switch", "unexpected_a", "default", 24]
6223. 86
6224. 86 warn("unexpected_a", the_default);
6225. 86 the_disrupt = false;
6226. 86 } else {
6227. 86 the_last = the_switch.else[
6228. 86 the_switch.else.length - 1
6229. 86 ];
6230. 86 if (
6231. 86 the_last.id === "break"
6232. 86 && the_last.label === undefined
6233. 86 ) {
6234. 86
6235. 86// test_cause:
6236. 86// ["
6237. 86// switch(0){case 0:break;default:break;}
6238. 86// ", "stmt_switch", "unexpected_a", "break", 32]
6239. 86
6240. 86 warn("unexpected_a", the_last);
6241. 86 the_last.disrupt = false;
6242. 86 }
6243. 86 the_disrupt = the_disrupt && the_last.disrupt;
6244. 86 }
6245. 95 } else {
6246. 95 the_disrupt = false;
6247. 181 }
6248. 181 advance("}", the_switch);
6249. 181 functionage.switch -= 1;
6250. 181 the_switch.disrupt = the_disrupt;
6251. 181 return the_switch;
6252. 181 }
6253. 591
6254. 34 function stmt_throw() {
6255. 34 const the_throw = token_now;
6256. 34 the_throw.disrupt = true;
6257. 34 the_throw.expression = parse_expression(10);
6258. 34 semicolon();
6259. 1 if (functionage.try > 0) {
6260. 1
6261. 1// test_cause:
6262. 1// ["try{throw 0}catch(){}", "stmt_throw", "unexpected_a", "throw", 5]
6263. 1
6264. 1 warn("unexpected_a", the_throw);
6265. 1 }
6266. 34 return the_throw;
6267. 34 }
6268. 591
6269. 63 function stmt_try() {
6270. 63 const the_try = token_now;
6271. 63 let ignored;
6272. 63 let the_catch;
6273. 63 let the_disrupt;
6274. 1 if (functionage.try > 0) {
6275. 1
6276. 1// test_cause:
6277. 1// ["try{try{}catch(){}}catch(){}", "stmt_try", "unexpected_a", "try", 5]
6278. 1
6279. 1 warn("unexpected_a", the_try);
6280. 1 }
6281. 63 functionage.try += 1;
6282. 63 the_try.block = block();
6283. 63 the_disrupt = the_try.block.disrupt;
6284. 58 if (token_nxt.id === "catch") {
6285. 58 ignored = "ignore";
6286. 58 the_catch = token_nxt;
6287. 58 the_try.catch = the_catch;
6288. 58 advance("catch");
6289. 58
6290. 58// Create new catch-scope for catch-parameter.
6291. 58
6292. 58 catch_stack.push(catchage);
6293. 58 catchage = the_catch;
6294. 58 catch_list.push(catchage);
6295. 58 the_catch.context = empty();
6296. 58 if (token_nxt.id === "(") {
6297. 58 advance("(");
6298. 58 if (!token_nxt.identifier) {
6299. 58
6300. 58// test_cause:
6301. 58// ["try{}catch(){}", "stmt_try", "expected_identifier_a", ")", 12]
6302. 58
6303. 58 return stop("expected_identifier_a");
6304. 58 }
6305. 58 if (token_nxt.id !== "ignore") {
6306. 58 ignored = undefined;
6307. 58 the_catch.name = token_nxt;
6308. 58 enroll(token_nxt, "exception", true);
6309. 58 }
6310. 58 advance();
6311. 58 advance(")");
6312. 58 }
6313. 58 the_catch.block = block(ignored);
6314. 58 if (the_catch.block.disrupt !== true) {
6315. 58 the_disrupt = false;
6316. 58 }
6317. 58
6318. 58// Restore previous catch-scope after catch-block.
6319. 58
6320. 58 catchage = catch_stack.pop();
6321. 58 } else {
6322. 4
6323. 4// test_cause:
6324. 4// ["try{}finally{break;}", "stmt_try", "expected_a_before_b", "finally", 6]
6325. 4
6326. 4 warn("expected_a_before_b", token_nxt, "catch", artifact());
6327. 59 }
6328. 59 if (token_nxt.id === "finally") {
6329. 4 functionage.finally += 1;
6330. 4 advance("finally");
6331. 4 the_try.else = block();
6332. 4 the_disrupt = the_try.else.disrupt;
6333. 4 functionage.finally -= 1;
6334. 57 }
6335. 57 the_try.disrupt = the_disrupt;
6336. 57 functionage.try -= 1;
6337. 57 return the_try;
6338. 57 }
6339. 591
6340. 2127 function stmt_var() {
6341. 2127 let ellipsis;
6342. 2127 let mode_const;
6343. 2127 let name;
6344. 2127 let the_brace;
6345. 2127 let the_bracket;
6346. 2127 let the_variable = token_now;
6347. 2127 let variable_prv;
6348. 2127 mode_const = the_variable.id === "const";
6349. 2127 the_variable.names = [];
6350. 2127
6351. 2127// A program may use var or let, but not both.
6352. 2127
6353. 1826 if (!mode_const) {
6354. 1826 if (mode_var === undefined) {
6355. 1826 mode_var = the_variable.id;
6356. 1826 } else if (the_variable.id !== mode_var) {
6357. 1826
6358. 1826// test_cause:
6359. 1826// ["let aa;var aa", "stmt_var", "expected_a_b", "var", 8]
6360. 1826
6361. 1826 warn("expected_a_b", the_variable, mode_var, the_variable.id);
6362. 1826 }
6363. 1826 }
6364. 2127
6365. 2127// We don't expect to see variables created in switch statements.
6366. 2127
6367. 1 if (functionage.switch > 0) {
6368. 1
6369. 1// test_cause:
6370. 1// ["switch(0){case 0:var aa}", "stmt_var", "var_switch", "var", 18]
6371. 1
6372. 1 warn("var_switch", the_variable);
6373. 1 }
6374. 2127 switch (
6375. 2127 Boolean(functionage.statement_prv)
6376. 1270 && functionage.statement_prv.id
6377. 2127 ) {
6378. 132 case "const":
6379. 1259 case "let":
6380. 1261 case "var":
6381. 1261
6382. 1261// test_cause:
6383. 1261// ["const aa=0;const bb=0;", "stmt_var", "var_prv", "const", 0]
6384. 1261// ["let aa=0;let bb=0;", "stmt_var", "var_prv", "let", 0]
6385. 1261// ["var aa=0;var bb=0;", "stmt_var", "var_prv", "var", 0]
6386. 1261
6387. 1261 test_cause("var_prv", functionage.statement_prv.id);
6388. 1261 variable_prv = functionage.statement_prv;
6389. 1261 break;
6390. 2 case "import":
6391. 2
6392. 2// test_cause:
6393. 2// ["import aa from \"aa\";\nlet bb=0;", "stmt_var", "import_prv", "", 0]
6394. 2
6395. 2 test_cause("import_prv");
6396. 2 break;
6397. 857 case false:
6398. 857 break;
6399. 7 default:
6400. 7 if (
6401. 7 (option_dict.beta && !option_dict.variable)
6402. 7 || the_variable.id === "var"
6403. 7 ) {
6404. 7
6405. 7// test_cause:
6406. 7// ["console.log();let aa=0;", "stmt_var", "var_on_top", "let", 15]
6407. 7// ["console.log();var aa=0;", "stmt_var", "var_on_top", "var", 15]
6408. 7// ["try{aa();}catch(aa){var aa=0;}", "stmt_var", "var_on_top", "var", 21]
6409. 7// ["while(0){var aa;}", "stmt_var", "var_on_top", "var", 10]
6410. 7
6411. 7 warn("var_on_top", token_now);
6412. 7 }
6413. 2127 }
6414. 2128 while (true) {
6415. 2128 if (token_nxt.id === "{") {
6416. 2128 if (the_variable.id === "var") {
6417. 2128
6418. 2128// test_cause:
6419. 2128// ["var{aa}=0", "stmt_var", "unexpected_a", "var", 1]
6420. 2128
6421. 2128 warn("unexpected_a", the_variable);
6422. 2128 }
6423. 2128 the_brace = token_nxt;
6424. 2128 advance("{");
6425. 2128 while (true) {
6426. 2128 name = token_nxt;
6427. 2128 if (!name.identifier) {
6428. 2128
6429. 2128// test_cause:
6430. 2128// ["let {0}", "stmt_var", "expected_identifier_a", "0", 6]
6431. 2128
6432. 2128 return stop("expected_identifier_a");
6433. 2128 }
6434. 2128 survey(name);
6435. 2128 advance();
6436. 2128 if (token_nxt.id === ":") {
6437. 2128 advance(":");
6438. 2128 if (!token_nxt.identifier) {
6439. 2128
6440. 2128// test_cause:
6441. 2128// ["let {aa:0}", "stmt_var", "expected_identifier_a", "0", 9]
6442. 2128// ["let {aa:{aa}}", "stmt_var", "expected_identifier_a", "{", 9]
6443. 2128
6444. 2128 return stop("expected_identifier_a");
6445. 2128 }
6446. 2128
6447. 2128// PR-363 - Bugfix - fix false-warning
6448. 2128// <uninitialized 'bb'> in code '/*jslint node*/\nlet {aa:bb} = {}; bb();'
6449. 2128
6450. 2128 // token_nxt.label = name;
6451. 2128 // the_variable.names.push(token_nxt);
6452. 2128 // enroll(token_nxt, "variable", mode_const);
6453. 2128 name = token_nxt;
6454. 2128 the_variable.names.push(name);
6455. 2128 survey(name);
6456. 2128 enroll(name, "variable", mode_const);
6457. 2128
6458. 2128 advance();
6459. 2128 the_brace.open = true;
6460. 2128 } else {
6461. 2128 the_variable.names.push(name);
6462. 2128 enroll(name, "variable", mode_const);
6463. 2128 }
6464. 2128 name.dead = false;
6465. 2128 name.init = true;
6466. 2128 if (token_nxt.id === "=") {
6467. 2128
6468. 2128// test_cause:
6469. 2128// ["let {aa=0}", "stmt_var", "assign", "", 0]
6470. 2128
6471. 2128 test_cause("assign");
6472. 2128 advance("=");
6473. 2128 name.expression = parse_expression();
6474. 2128 the_brace.open = true;
6475. 2128 }
6476. 2128 if (token_nxt.id !== ",") {
6477. 2128 break;
6478. 2128 }
6479. 2128 advance(",");
6480. 2128 }
6481. 2128
6482. 2128// test_cause:
6483. 2128// ["let{bb,aa}", "check_ordered", "expected_a_b_before_c_d", "aa", 8]
6484. 2128
6485. 2128 check_ordered(the_variable.id, the_variable.names);
6486. 2128 advance("}");
6487. 2128 advance("=");
6488. 2128 the_variable.expression = parse_expression(0);
6489. 2128 } else if (token_nxt.id === "[") {
6490. 2128 if (the_variable.id === "var") {
6491. 2128
6492. 2128// test_cause:
6493. 2128// ["var[aa]=0", "stmt_var", "unexpected_a", "var", 1]
6494. 2128
6495. 2128 warn("unexpected_a", the_variable);
6496. 2128 }
6497. 2128 the_bracket = token_nxt;
6498. 2128 advance("[");
6499. 2128 while (true) {
6500. 2128 ellipsis = false;
6501. 2128 if (token_nxt.id === "...") {
6502. 2128 ellipsis = true;
6503. 2128 advance("...");
6504. 2128 }
6505. 2128 if (!token_nxt.identifier) {
6506. 2128
6507. 2128// test_cause:
6508. 2128// ["let[]", "stmt_var", "expected_identifier_a", "]", 5]
6509. 2128
6510. 2128 return stop("expected_identifier_a");
6511. 2128 }
6512. 2128 name = token_nxt;
6513. 2128 advance();
6514. 2128 the_variable.names.push(name);
6515. 2128 enroll(name, "variable", mode_const);
6516. 2128 name.dead = false;
6517. 2128 name.init = true;
6518. 2128 if (ellipsis) {
6519. 2128 name.ellipsis = true;
6520. 2128 break;
6521. 2128 }
6522. 2128 if (token_nxt.id === "=") {
6523. 2128 advance("=");
6524. 2128 name.expression = parse_expression();
6525. 2128 the_bracket.open = true;
6526. 2128 }
6527. 2128 if (token_nxt.id !== ",") {
6528. 2128 break;
6529. 2128 }
6530. 2128 advance(",");
6531. 2128 }
6532. 2128 advance("]");
6533. 2128 advance("=");
6534. 2128 the_variable.expression = parse_expression(0);
6535. 2128 } else if (token_nxt.identifier) {
6536. 2128 name = token_nxt;
6537. 2128 advance();
6538. 2128 if (name.id === "ignore") {
6539. 2128
6540. 2128// test_cause:
6541. 2128// ["
6542. 2128// let ignore;function aa(ignore) {}
6543. 2128// ", "stmt_var", "unexpected_a", "ignore", 5]
6544. 2128
6545. 2128 warn("unexpected_a", name);
6546. 2128 }
6547. 2128 enroll(name, "variable", mode_const);
6548. 2128 if (token_nxt.id === "=" || mode_const) {
6549. 2128 advance("=");
6550. 2128 name.dead = false;
6551. 2128 name.init = true;
6552. 2128 name.expression = parse_expression(0);
6553. 2128 }
6554. 2128 the_variable.names.push(name);
6555. 2128 } else {
6556. 2128
6557. 2128// test_cause:
6558. 2128// ["let 0", "stmt_var", "expected_identifier_a", "0", 5]
6559. 2128// ["var{aa:{aa}}", "stmt_var", "expected_identifier_a", "{", 8]
6560. 2128
6561. 2128 return stop("expected_identifier_a");
6562. 2128 }
6563. 2128 if (token_nxt.id !== ",") {
6564. 2128 break;
6565. 2128 }
6566. 2128
6567. 2128// test_cause:
6568. 2128// ["let aa,bb;", "stmt_var", "expected_a_b", ",", 7]
6569. 2128
6570. 2128 warn("expected_a_b", token_nxt, ";", ",");
6571. 2128 advance(",");
6572. 2128 }
6573. 2113
6574. 2113// Warn if variable declarations are unordered.
6575. 2113
6576. 2113 if (
6577. 2113 option_dict.beta
6578. 2113 && !option_dict.unordered
6579. 2111 && !option_dict.variable
6580. 2105 && variable_prv
6581. 1259 && (
6582. 1259 variable_prv.id + " " + variable_prv.names[0].id
6583. 1259 > the_variable.id + " " + the_variable.names[0].id
6584. 1259 )
6585. 3 ) {
6586. 3
6587. 3// test_cause:
6588. 3// ["const bb=0;const aa=0;", "stmt_var", "expected_a_b_before_c_d", "aa", 12]
6589. 3// ["let bb;let aa;", "stmt_var", "expected_a_b_before_c_d", "aa", 8]
6590. 3// ["var bb;var aa;", "stmt_var", "expected_a_b_before_c_d", "aa", 8]
6591. 3
6592. 3 warn(
6593. 3 "expected_a_b_before_c_d",
6594. 3 the_variable,
6595. 3 the_variable.id,
6596. 3 the_variable.names[0].id,
6597. 3 variable_prv.id,
6598. 3 variable_prv.names[0].id
6599. 3 );
6600. 2113 }
6601. 2113 semicolon();
6602. 2113 return the_variable;
6603. 2113 }
6604. 591
6605. 208 function stmt_while() {
6606. 208 const the_while = token_now;
6607. 208 check_not_top_level(the_while);
6608. 208 functionage.loop += 1;
6609. 208 the_while.expression = condition();
6610. 208 the_while.block = block();
6611. 1 if (the_while.block.disrupt === true) {
6612. 1
6613. 1// test_cause:
6614. 1// ["function aa(){while(0){break;}}", "stmt_while", "weird_loop", "while", 15]
6615. 1
6616. 1 warn("weird_loop", the_while);
6617. 205 }
6618. 205 functionage.loop -= 1;
6619. 205 return the_while;
6620. 205 }
6621. 591
6622. 1 function stmt_with() {
6623. 1
6624. 1// test_cause:
6625. 1// ["with", "stmt_with", "unexpected_a", "with", 1]
6626. 1
6627. 1 stop("unexpected_a", token_now);
6628. 1 }
6629. 591
6630. 13452 function survey(name) {
6631. 13452 let id = name.id;
6632. 13452
6633. 13452// Tally the property name. If it is a string, only tally strings that conform
6634. 13452// to the identifier rules.
6635. 13452
6636. 40 if (id === "(string)") {
6637. 40 id = name.value;
6638. 40 if (!rx_identifier.test(id)) {
6639. 40 return id;
6640. 40 }
6641. 13412 } else if (id === "`") {
6642. 13412 if (name.value.length === 1) {
6643. 13412 id = name.value[0].value;
6644. 13412 if (!rx_identifier.test(id)) {
6645. 13412 return id;
6646. 13412 }
6647. 13412 }
6648. 13412 } else if (!name.identifier) {
6649. 13412
6650. 13412// test_cause:
6651. 13412// ["let aa={0:0}", "survey", "expected_identifier_a", "0", 9]
6652. 13412
6653. 13412 return stop("expected_identifier_a", name);
6654. 13413 }
6655. 13413
6656. 13413// If we have seen this name before, increment its count.
6657. 13413
6658. 13413 if (typeof property_dict[id] === "number") {
6659. 11370 property_dict[id] += 1;
6660. 11370
6661. 11370// If this is the first time seeing this property name, and if there is a
6662. 11370// tenure list, then it must be on the list. Otherwise, it must conform to
6663. 11370// the rules for good property names.
6664. 11370
6665. 11370 } else {
6666. 2043 if (state.mode_property) {
6667. 2043 if (tenure[id] !== true) {
6668. 2043
6669. 2043// test_cause:
6670. 2043// ["/*property aa*/\naa.bb", "survey", "unregistered_property_a", "bb", 4]
6671. 2043
6672. 2043 warn("unregistered_property_a", name);
6673. 2043 }
6674. 2043 } else if (
6675. 2043 !option_dict.name
6676. 2043 && name.identifier
6677. 2043 && (
6678. 2043 // rx_weird_property
6679. 2043 /^_|\$|Sync$|_$/m
6680. 2043 ).test(id)
6681. 2043 ) {
6682. 2043
6683. 2043// test_cause:
6684. 2043// ["aa.$", "survey", "weird_property_a", "$", 4]
6685. 2043// ["aa._", "survey", "weird_property_a", "_", 4]
6686. 2043// ["aa._aa", "survey", "weird_property_a", "_aa", 4]
6687. 2043// ["aa.aaSync", "survey", "weird_property_a", "aaSync", 4]
6688. 2043// ["aa.aa_", "survey", "weird_property_a", "aa_", 4]
6689. 2043
6690. 2043 warn("weird_property_a", name);
6691. 2043 }
6692. 2043 property_dict[id] = 1;
6693. 13413 }
6694. 13413 return id;
6695. 13413 }
6696. 591
6697. 591// These functions are used to specify the grammar of our language:
6698. 591
6699. 76830 function symbol(id, bp) {
6700. 76830
6701. 76830// Create a symbol if it does not already exist in the language's syntax.
6702. 76830
6703. 76830 let the_symbol = syntax_dict[id];
6704. 66783 if (the_symbol === undefined) {
6705. 66783 the_symbol = empty();
6706. 66783 the_symbol.id = id;
6707. 66783 the_symbol.lbp = bp || 0;
6708. 66783 syntax_dict[id] = the_symbol;
6709. 66783 }
6710. 76830 return the_symbol;
6711. 76830 }
6712. 591
6713. 591 function ternary(id1, id2) {
6714. 591
6715. 591// Create a ternary operator.
6716. 591
6717. 591 const the_symbol = symbol(id1, 30);
6718. 213 the_symbol.led = function parse_ternary_led(left) {
6719. 213 const the_token = token_now;
6720. 213 let second;
6721. 213 second = parse_expression(20);
6722. 213 advance(id2);
6723. 213 token_now.arity = "ternary";
6724. 213 the_token.arity = "ternary";
6725. 213 the_token.expression = [left, second, parse_expression(10)];
6726. 5 if (token_nxt.id !== ")") {
6727. 5
6728. 5// test_cause:
6729. 5// ["0?0:0", "parse_ternary_led", "use_open", "?", 2]
6730. 5
6731. 5 warn("use_open", the_token);
6732. 5 }
6733. 213 return the_token;
6734. 213 };
6735. 591 return the_symbol;
6736. 591 }
6737. 591
6738. 591// Now we parse JavaScript.
6739. 591// Begin defining the language.
6740. 591
6741. 591 assignment("%=");
6742. 591 assignment("&=");
6743. 591 assignment("*=");
6744. 591 assignment("+=");
6745. 591 assignment("-=");
6746. 591 assignment("/=");
6747. 591 assignment("<<=");
6748. 591 assignment("=");
6749. 591 assignment(">>=");
6750. 591 assignment(">>>=");
6751. 591 assignment("^=");
6752. 591 assignment("|=");
6753. 591 constant("(number)", "number");
6754. 591 constant("(regexp)", "regexp");
6755. 591 constant("(string)", "string");
6756. 591 constant("Function", "function", constant_Function);
6757. 591 constant("Infinity", "number", Infinity);
6758. 591 constant("NaN", "number", NaN);
6759. 591 constant("arguments", "object", constant_arguments);
6760. 591 constant("eval", "function", constant_eval);
6761. 591 constant("false", "boolean", false);
6762. 591 constant("ignore", "undefined", constant_ignore);
6763. 591 constant("isFinite", "function", constant_isInfinite);
6764. 591 constant("isNaN", "function", constant_isNaN);
6765. 591 constant("null", "null", null);
6766. 591 constant("this", "object", constant_this);
6767. 591 constant("true", "boolean", true);
6768. 591 constant("undefined", "undefined");
6769. 591 infix(100, "!=");
6770. 591 infix(100, "!==");
6771. 591 infix(100, "==");
6772. 591 infix(100, "===");
6773. 591 infix(110, "<");
6774. 591 infix(110, "<=");
6775. 591 infix(110, ">");
6776. 591 infix(110, ">=");
6777. 591 infix(110, "in");
6778. 591 infix(110, "instanceof");
6779. 591 infix(120, "<<");
6780. 591 infix(120, ">>");
6781. 591 infix(120, ">>>");
6782. 591 infix(130, "+");
6783. 591 infix(130, "-");
6784. 591 infix(140, "%");
6785. 591 infix(140, "*");
6786. 591 infix(140, "/");
6787. 591 infix(160, "(", infix_lparen);
6788. 591 infix(160, "`", infix_grave);
6789. 591 infix(170, ".", infix_dot);
6790. 591 infix(170, "=>", infix_fart_unwrapped);
6791. 591 infix(170, "?.", infix_option_chain);
6792. 591 infix(170, "[", infix_lbracket);
6793. 591 infix(35, "??");
6794. 591 infix(40, "||");
6795. 591 infix(50, "&&");
6796. 591 infix(70, "|");
6797. 591 infix(80, "^");
6798. 591 infix(90, "&");
6799. 591 infixr(150, "**");
6800. 591 postassign("++");
6801. 591 postassign("--");
6802. 591 preassign("++");
6803. 591 preassign("--");
6804. 591 prefix("!!");
6805. 591 prefix("!");
6806. 591 prefix("(", prefix_lparen);
6807. 591 prefix("+");
6808. 591 prefix("-");
6809. 591 prefix("/=", prefix_assign_divide);
6810. 591 prefix("=>", prefix_fart);
6811. 591 prefix("[", prefix_lbracket);
6812. 591 prefix("`", prefix_tick);
6813. 591 prefix("async", prefix_async);
6814. 591 prefix("await", prefix_await);
6815. 591 prefix("function", prefix_function);
6816. 591 prefix("new", prefix_new);
6817. 591 prefix("typeof");
6818. 591 prefix("void", prefix_void);
6819. 591 prefix("{", prefix_lbrace);
6820. 591 prefix("~");
6821. 591 stmt(";", stmt_semicolon);
6822. 591 stmt("async", prefix_async);
6823. 591 stmt("await", prefix_await);
6824. 591 stmt("break", stmt_break);
6825. 591 stmt("const", stmt_var);
6826. 591 stmt("continue", stmt_continue);
6827. 591 stmt("debugger", stmt_debugger);
6828. 591 stmt("delete", stmt_delete);
6829. 591 stmt("do", stmt_do);
6830. 591 stmt("export", stmt_export);
6831. 591 stmt("for", stmt_for);
6832. 591 stmt("function", prefix_function);
6833. 591 stmt("if", stmt_if);
6834. 591 stmt("import", stmt_import);
6835. 591 stmt("let", stmt_var);
6836. 591 stmt("return", stmt_return);
6837. 591 stmt("switch", stmt_switch);
6838. 591 stmt("throw", stmt_throw);
6839. 591 stmt("try", stmt_try);
6840. 591 stmt("var", stmt_var);
6841. 591 stmt("while", stmt_while);
6842. 591 stmt("with", stmt_with);
6843. 591 stmt("{", stmt_lbrace);
6844. 591 symbol(")");
6845. 591 symbol("*/");
6846. 591 symbol(",");
6847. 591 symbol(":");
6848. 591 symbol(";");
6849. 591 symbol("]");
6850. 591 symbol("async");
6851. 591 symbol("await");
6852. 591 symbol("case");
6853. 591 symbol("catch");
6854. 591 symbol("class");
6855. 591 symbol("default");
6856. 591 symbol("else");
6857. 591 symbol("enum");
6858. 591 symbol("finally");
6859. 591 symbol("implements");
6860. 591 symbol("interface");
6861. 591 symbol("package");
6862. 591 symbol("private");
6863. 591 symbol("protected");
6864. 591 symbol("public");
6865. 591 symbol("static");
6866. 591 symbol("super");
6867. 591 symbol("void");
6868. 591 symbol("yield");
6869. 591 symbol("}");
6870. 591 ternary("?", ":");
6871. 591
6872. 591// Init token_nxt.
6873. 591
6874. 591 advance();
6875. 591
6876. 591// Parsing of JSON is simple:
6877. 591
6878. 24 if (state.mode_json) {
6879. 24 state.token_tree = parse_json();
6880. 24 advance("(end)");
6881. 24 return;
6882. 567 }
6883. 567
6884. 567// Because browsers encourage combining of script files, the first token might
6885. 567// be a semicolon to defend against a missing semicolon in the preceding file.
6886. 567
6887. 567 if (option_dict.browser) {
6888. 2 if (token_nxt.id === ";") {
6889. 2 advance(";");
6890. 2 }
6891. 2
6892. 2// If we are not in a browser, then the file form of strict pragma may be used.
6893. 2
6894. 565 } else if (token_nxt.value === "use strict") {
6895. 565 advance("(string)");
6896. 565 advance(";");
6897. 567 }
6898. 567 state.token_tree = parse_statements();
6899. 567 advance("(end)");
6900. 567
6901. 567// Check global functions are ordered.
6902. 567
6903. 567 check_ordered(
6904. 567 "function",
6905. 1833 function_list.map(function ({
6906. 1833 level,
6907. 1833 name
6908. 1833 }) {
6909. 567 return (level === 1) && name;
6910. 1833 }).filter(function (name) {
6911. 1831 return option_dict.beta && name && name.id;
6912. 1833 })
6913. 567 );
6914. 567}
6915. 1
6916. 473function jslint_phase4_walk(state) {
6917. 473
6918. 473// PHASE 4. Walk <token_tree>, traversing all nodes of the tree. It is a
6919. 473// recursive traversal. Each node may be processed on the way down
6920. 473// (preaction) and on the way up (postaction).
6921. 473
6922. 473 let {
6923. 473 artifact,
6924. 473 catch_stack,
6925. 473 function_stack,
6926. 473 global_dict,
6927. 473 is_equal,
6928. 473 is_weird,
6929. 473 option_dict,
6930. 473 syntax_dict,
6931. 473 test_cause,
6932. 473 token_global,
6933. 473 warn
6934. 473 } = state;
6935. 473 let block_stack = []; // The stack of blocks.
6936. 473 let blockage = token_global; // The current block.
6937. 473 let catchage = catch_stack[0]; // The current catch-block.
6938. 473 let functionage = token_global; // The current function.
6939. 473 let postaction;
6940. 473 let postamble;
6941. 473 let posts = empty();
6942. 473 let preaction;
6943. 473 let preamble;
6944. 473 let pres = empty();
6945. 473
6946. 473// The relational operators.
6947. 473
6948. 473 let relationop = object_assign_from_list(empty(), [
6949. 473 "!=", "!==", "<", "<=", "==", "===", ">", ">="
6950. 473 ], true);
6951. 473
6952. 473// Ambulation of the parse tree.
6953. 473
6954. 946 function action(when) {
6955. 946
6956. 946// Produce a function that will register task functions that will be called as
6957. 946// the tree is traversed.
6958. 946
6959. 17974 return function (arity, id, task) {
6960. 17974 let a_set = when[arity];
6961. 17974 let i_set;
6962. 17974
6963. 17974// The id parameter is optional. If excluded, the task will be applied to all
6964. 17974// ids.
6965. 17974
6966. 3784 if (typeof id !== "string") {
6967. 3784 task = id;
6968. 3784 id = "(all)";
6969. 3784 }
6970. 17974
6971. 17974// If this arity has no registrations yet, then create a set object to hold
6972. 17974// them.
6973. 17974
6974. 4730 if (a_set === undefined) {
6975. 4730 a_set = empty();
6976. 4730 when[arity] = a_set;
6977. 4730 }
6978. 17974
6979. 17974// If this id has no registrations yet, then create a set array to hold them.
6980. 17974
6981. 17974 i_set = a_set[id];
6982. 17501 if (i_set === undefined) {
6983. 17501 i_set = [];
6984. 17501 a_set[id] = i_set;
6985. 17501 }
6986. 17974
6987. 17974// Register the task with the arity and the id.
6988. 17974
6989. 17974 i_set.push(task);
6990. 17974 };
6991. 946 }
6992. 473
6993. 946 function amble(when) {
6994. 946
6995. 946// Produce a function that will act on the tasks registered by an action
6996. 946// function while walking the tree.
6997. 946
6998. 197392 return function (the_token) {
6999. 197392
7000. 197392// Given a task set that was built by an action function, run all
7001. 197392// relevant tasks on the token.
7002. 197392
7003. 197392 let a_set = when[the_token.arity];
7004. 197392 let i_set;
7005. 197392
7006. 197392// If there are tasks associated with the token's arity...
7007. 197392
7008. 135909 if (a_set !== undefined) {
7009. 135909
7010. 135909// If there are tasks associated with the token's id...
7011. 135909
7012. 135909 i_set = a_set[the_token.id];
7013. 135909 if (i_set !== undefined) {
7014. 135909 i_set.forEach(function (task) {
7015. 135909 return task(the_token);
7016. 135909 });
7017. 135909 }
7018. 135909
7019. 135909// If there are tasks for all ids.
7020. 135909
7021. 135909 i_set = a_set["(all)"];
7022. 135909 if (i_set !== undefined) {
7023. 135909 i_set.forEach(function (task) {
7024. 135909 return task(the_token);
7025. 135909 });
7026. 135909 }
7027. 135909 }
7028. 197392 };
7029. 946 }
7030. 473
7031. 2596 function init_variable(name) {
7032. 2596 let the_variable = lookup(name);
7033. 2541 if (!the_variable || the_variable.readonly) {
7034. 57 warn("bad_assignment_a", name);
7035. 57 return;
7036. 2539 }
7037. 2539 the_variable.init = true;
7038. 2539 }
7039. 473
7040. 29634 function lookup(thing) {
7041. 29634 let id = thing.id;
7042. 29634 let the_variable;
7043. 1 if (thing.arity !== "variable") {
7044. 1 return;
7045. 29633 }
7046. 29633
7047. 29633// Look up the variable in the current context.
7048. 29633
7049. 29633 the_variable = (
7050. 29633 functionage.context[id] || catchage.context[id]
7051. 29634 );
7052. 29634
7053. 29634// If it isn't local, search all the other contexts. If there are name
7054. 29634// collisions, take the most recent.
7055. 29634
7056. 23353 if (the_variable && the_variable.role === "label") {
7057. 1
7058. 1// test_cause:
7059. 1// ["aa:while(0){aa;}", "lookup", "label_a", "aa", 13]
7060. 1
7061. 1 warn("label_a", thing);
7062. 1 return the_variable;
7063. 29632 }
7064. 29632 if (!the_variable) {
7065. 13479 function_stack.forEach(function ({
7066. 13479 context
7067. 13479 }) {
7068. 6280 if (context[id] && context[id].role !== "label") {
7069. 6280 the_variable = context[id];
7070. 6280 }
7071. 13479 });
7072. 6280
7073. 6280// If it isn't in any of those either, perhaps it is a predefined global.
7074. 6280// If so, add it to the global context.
7075. 6280
7076. 6280 if (!the_variable && global_dict[id] === undefined) {
7077. 6280
7078. 6280// test_cause:
7079. 6280// ["aa", "lookup", "undeclared_a", "aa", 1]
7080. 6280// ["class aa{}", "lookup", "undeclared_a", "aa", 7]
7081. 6280// ["
7082. 6280// let aa=0;try{aa();}catch(bb){bb();}bb();
7083. 6280// ", "lookup", "undeclared_a", "bb", 36]
7084. 6280// ["
7085. 6280// let aa=0;try{aa();}catch(ignore){bb();}
7086. 6280// ", "lookup", "undeclared_a", "bb", 34]
7087. 6280
7088. 6280 warn("undeclared_a", thing);
7089. 6280 return;
7090. 6280 }
7091. 6280 if (!the_variable) {
7092. 6280 the_variable = {
7093. 6280 dead: false,
7094. 6280 id,
7095. 6280 init: true,
7096. 6280 parent: token_global,
7097. 6280 readonly: true,
7098. 6280 role: "variable",
7099. 6280 used: 0
7100. 6280 };
7101. 6280 token_global.context[id] = the_variable;
7102. 6280 }
7103. 6280 the_variable.closure = true;
7104. 6280 functionage.context[id] = the_variable;
7105. 29506 }
7106. 29506 if (
7107. 29506 (
7108. 29506 the_variable.calls === undefined
7109. 29506 || functionage.name === undefined
7110. 4276 || the_variable.calls[functionage.name.id] === undefined
7111. 29634 )
7112. 29336 && the_variable.dead
7113. 3 ) {
7114. 3
7115. 3// test_cause:
7116. 3// ["let aa;if(aa){let bb;}bb;", "lookup", "out_of_scope_a", "bb", 23]
7117. 3
7118. 3 warn("out_of_scope_a", thing);
7119. 29506 }
7120. 29506 return the_variable;
7121. 29506 }
7122. 473
7123. 4717 function post_a(thing) {
7124. 4717
7125. 4717// Assignment using = sets the init property of a variable. No other assignment
7126. 4717// operator can do this. A = token keeps that variable (or array of variables
7127. 4717// in case of destructuring) in its name property.
7128. 4717
7129. 4717 const lvalue = thing.expression[0];
7130. 4717 let right;
7131. 4009 if (thing.id === "=") {
7132. 4009 if (thing.names !== undefined) {
7133. 4009
7134. 4009// test_cause:
7135. 4009// ["if(0){aa=0}", "post_a", "=", "", 0]
7136. 4009
7137. 4009 test_cause("=");
7138. 4009
7139. 4009// Probably deadcode.
7140. 4009// if (Array.isArray(thing.names)) {
7141. 4009// thing.names.forEach(init_variable);
7142. 4009// } else {
7143. 4009// init_variable(thing.names);
7144. 4009// }
7145. 4009
7146. 4009 jslint_assert(
7147. 4009 !Array.isArray(thing.names),
7148. 4009 `Expected !Array.isArray(thing.names).`
7149. 4009 );
7150. 4009 init_variable(thing.names);
7151. 4009 } else {
7152. 4009 if (lvalue.id === "[" || lvalue.id === "{") {
7153. 4009 lvalue.expression.forEach(function (thing) {
7154. 4009 if (thing.variable) {
7155. 4009 thing.variable.init = true;
7156. 4009 }
7157. 4009 });
7158. 4009 } else if (
7159. 4009 lvalue.id === "."
7160. 4009 && thing.expression[1].id === "undefined"
7161. 4009 ) {
7162. 4009
7163. 4009// test_cause:
7164. 4009// ["aa.aa=undefined", "post_a", "expected_a_b", "undefined", 1]
7165. 4009
7166. 4009 warn(
7167. 4009 "expected_a_b",
7168. 4009 lvalue.expression,
7169. 4009 "delete",
7170. 4009 "undefined"
7171. 4009 );
7172. 4009 }
7173. 4009 }
7174. 4009 } else {
7175. 708 if (lvalue.arity === "variable") {
7176. 708 if (!lvalue.variable || lvalue.variable.readonly) {
7177. 708 warn("bad_assignment_a", lvalue);
7178. 708 }
7179. 708 }
7180. 708 right = syntax_dict[thing.expression[1].id];
7181. 708 if (
7182. 708 right !== undefined
7183. 708 && (
7184. 708 right.id === "function"
7185. 708 || right.id === "=>"
7186. 708 || (
7187. 708 right.constant
7188. 708 && right.id !== "(number)"
7189. 708 && (right.id !== "(string)" || thing.id !== "+=")
7190. 708 )
7191. 708 )
7192. 708 ) {
7193. 708
7194. 708// test_cause:
7195. 708// ["aa+=undefined", "post_a", "unexpected_a", "undefined", 5]
7196. 708
7197. 708 warn("unexpected_a", thing.expression[1]);
7198. 708 }
7199. 708 }
7200. 4717 }
7201. 473
7202. 645 function post_a_pluseq(thing) {
7203. 645 const right = thing.expression[1];
7204. 342 if (right.constant) {
7205. 342 if (
7206. 342 right.value === ""
7207. 342 || (right.id === "(number)" && right.value === "0")
7208. 342 || right.id === "(boolean)"
7209. 342 || right.id === "null"
7210. 342 || right.id === "undefined"
7211. 342 || Number.isNaN(right.value)
7212. 342 ) {
7213. 342 warn("unexpected_a", right);
7214. 342 }
7215. 342 }
7216. 645 }
7217. 473
7218. 29995 function post_b(thing) {
7219. 29995 let right;
7220. 3951 if (relationop[thing.id]) {
7221. 3951 if (
7222. 3951 is_weird(thing.expression[0])
7223. 3951 || is_weird(thing.expression[1])
7224. 3951 || is_equal(thing.expression[0], thing.expression[1])
7225. 3951 || (
7226. 3951 thing.expression[0].constant === true
7227. 3951 && thing.expression[1].constant === true
7228. 3951 )
7229. 3951 ) {
7230. 3951
7231. 3951// test_cause:
7232. 3951// ["if(0===0){0}", "post_b", "weird_relation_a", "===", 5]
7233. 3951
7234. 3951 warn("weird_relation_a", thing);
7235. 3951 }
7236. 3951 }
7237. 1784 if (thing.id === "+") {
7238. 1784 if (!option_dict.convert) {
7239. 1784 if (thing.expression[0].value === "") {
7240. 1784
7241. 1784// test_cause:
7242. 1784// ["\"\"+0", "post_b", "expected_a_b", "\"\" +", 3]
7243. 1784
7244. 1784 warn("expected_a_b", thing, "String(...)", "\"\" +");
7245. 1784 } else if (thing.expression[1].value === "") {
7246. 1784
7247. 1784// test_cause:
7248. 1784// ["0+\"\"", "post_b", "expected_a_b", "+ \"\"", 2]
7249. 1784
7250. 1784 warn("expected_a_b", thing, "String(...)", "+ \"\"");
7251. 1784 }
7252. 1784 }
7253. 28211 } else if (thing.id === "[") {
7254. 28211 if (thing.expression[0].id === "window") {
7255. 28211
7256. 28211// test_cause:
7257. 28211// ["aa=window[0]", "post_b", "weird_expression_a", "window[...]", 10]
7258. 28211
7259. 28211 warn("weird_expression_a", thing, "window[...]");
7260. 28211 }
7261. 28211 if (thing.expression[0].id === "self") {
7262. 28211
7263. 28211// test_cause:
7264. 28211// ["aa=self[0]", "post_b", "weird_expression_a", "self[...]", 8]
7265. 28211
7266. 28211 warn("weird_expression_a", thing, "self[...]");
7267. 28211 }
7268. 28211 } else if (thing.id === "." || thing.id === "?.") {
7269. 28211 if (thing.expression.id === "RegExp") {
7270. 28211
7271. 28211// test_cause:
7272. 28211// ["aa=RegExp.aa", "post_b", "weird_expression_a", ".", 10]
7273. 28211
7274. 28211 warn("weird_expression_a", thing);
7275. 28211 }
7276. 28211 } else if (thing.id !== "=>" && thing.id !== "(") {
7277. 28211 right = thing.expression[1];
7278. 28211 if (
7279. 28211 (thing.id === "+" || thing.id === "-")
7280. 28211 && right.id === thing.id
7281. 28211 && right.arity === "unary"
7282. 28211 && !right.wrapped
7283. 28211 ) {
7284. 28211
7285. 28211// test_cause:
7286. 28211// ["0- -0", "post_b", "wrap_unary", "-", 4]
7287. 28211
7288. 28211 warn("wrap_unary", right);
7289. 28211 }
7290. 28211 if (
7291. 28211 thing.expression[0].constant === true
7292. 28211 && right.constant === true
7293. 28211 ) {
7294. 28211 thing.constant = true;
7295. 28211 }
7296. 28211 }
7297. 29995 }
7298. 473
7299. 1160 function post_b_and(thing) {
7300. 1160 if (
7301. 1160 is_weird(thing.expression[0])
7302. 1155 || is_equal(thing.expression[0], thing.expression[1])
7303. 1142 || thing.expression[0].constant === true
7304. 1141 || thing.expression[1].constant === true
7305. 19 ) {
7306. 19
7307. 19// test_cause:
7308. 19// ["aa=(()=>0)&&(()=>0)", "post_b_and", "weird_condition_a", "&&", 11]
7309. 19// ["aa=(``?``:``)&&(``?``:``)", "post_b_and", "weird_condition_a", "&&", 14]
7310. 19// ["aa=/./&&/./", "post_b_and", "weird_condition_a", "&&", 7]
7311. 19// ["aa=0&&0", "post_b_and", "weird_condition_a", "&&", 5]
7312. 19// ["aa=[]&&[]", "post_b_and", "weird_condition_a", "&&", 6]
7313. 19// ["aa=`${0}`&&`${0}`", "post_b_and", "weird_condition_a", "&&", 10]
7314. 19// ["
7315. 19// aa=function aa(){}&&function aa(){}
7316. 19// ", "post_b_and", "weird_condition_a", "&&", 19]
7317. 19// ["aa={}&&{}", "post_b_and", "weird_condition_a", "&&", 6]
7318. 19
7319. 19 warn("weird_condition_a", thing);
7320. 19 }
7321. 1160 }
7322. 473
7323. 1354 function post_b_lbracket(thing) {
7324. 1 if (thing.expression[0].id === "RegExp") {
7325. 1
7326. 1// test_cause:
7327. 1// ["aa=RegExp[0]", "post_b_lbracket", "weird_expression_a", "[", 10]
7328. 1
7329. 1 warn("weird_expression_a", thing);
7330. 1 }
7331. 1 if (is_weird(thing.expression[1])) {
7332. 1
7333. 1// test_cause:
7334. 1// ["aa[[0]]", "post_b_lbracket", "weird_expression_a", "[", 4]
7335. 1
7336. 1 warn("weird_expression_a", thing.expression[1]);
7337. 1 }
7338. 1354 }
7339. 473
7340. 9604 function post_b_lparen(thing) {
7341. 9604 let arg;
7342. 9604 let array;
7343. 9604 let cack;
7344. 9604 let left = thing.expression[0];
7345. 9604 let new_date;
7346. 9604 let paren;
7347. 9604 let the_new;
7348. 122 if (left.id === "new") {
7349. 122 the_new = left;
7350. 122 left = left.expression;
7351. 122 }
7352. 41 if (left.id === "function") {
7353. 41 if (!thing.wrapped) {
7354. 41
7355. 41// test_cause:
7356. 41// ["aa=function(){}()", "post_b_lparen", "wrap_immediate", "(", 16]
7357. 41
7358. 41 warn("wrap_immediate", thing);
7359. 41 }
7360. 9563 } else if (left.identifier) {
7361. 9563 if (the_new !== undefined) {
7362. 9563 if (
7363. 9563 left.id[0] > "Z"
7364. 9563 || left.id === "BigInt"
7365. 9563 || left.id === "Boolean"
7366. 9563 || left.id === "Number"
7367. 9563 || left.id === "String"
7368. 9563 || left.id === "Symbol"
7369. 9563 ) {
7370. 9563
7371. 9563// test_cause:
7372. 9563// ["new BigInt()", "post_b_lparen", "unexpected_a", "new", 1]
7373. 9563// ["new Boolean()", "post_b_lparen", "unexpected_a", "new", 1]
7374. 9563// ["new Number()", "post_b_lparen", "unexpected_a", "new", 1]
7375. 9563// ["new String()", "post_b_lparen", "unexpected_a", "new", 1]
7376. 9563// ["new Symbol()", "post_b_lparen", "unexpected_a", "new", 1]
7377. 9563// ["new aa()", "post_b_lparen", "unexpected_a", "new", 1]
7378. 9563
7379. 9563 warn("unexpected_a", the_new);
7380. 9563 } else if (left.id === "Function") {
7381. 9563 if (!option_dict.eval) {
7382. 9563
7383. 9563// test_cause:
7384. 9563// ["new Function()", "post_b_lparen", "unexpected_a", "new Function", 5]
7385. 9563
7386. 9563 warn("unexpected_a", left, "new Function");
7387. 9563 }
7388. 9563 } else if (left.id === "Array") {
7389. 9563 arg = thing.expression;
7390. 9563 if (arg.length !== 2 || arg[1].id === "(string)") {
7391. 9563
7392. 9563// test_cause:
7393. 9563// ["new Array()", "post_b_lparen", "expected_a_b", "new Array", 5]
7394. 9563
7395. 9563 warn("expected_a_b", left, "[]", "new Array");
7396. 9563 }
7397. 9563 } else if (left.id === "Object") {
7398. 9563
7399. 9563// test_cause:
7400. 9563// ["new Object()", "post_b_lparen", "expected_a_b", "new Object", 5]
7401. 9563
7402. 9563 warn(
7403. 9563 "expected_a_b",
7404. 9563 left,
7405. 9563 "Object.create(null)",
7406. 9563 "new Object"
7407. 9563 );
7408. 9563 }
7409. 9563 } else {
7410. 9563 if (
7411. 9563 left.id[0] >= "A"
7412. 9563 && left.id[0] <= "Z"
7413. 9563 && left.id !== "BigInt"
7414. 9563 && left.id !== "Boolean"
7415. 9563 && left.id !== "Number"
7416. 9563 && left.id !== "String"
7417. 9563 && left.id !== "Symbol"
7418. 9563 ) {
7419. 9563
7420. 9563// test_cause:
7421. 9563// ["let Aa=Aa()", "post_b_lparen", "expected_a_before_b", "Aa", 8]
7422. 9563
7423. 9563 warn("expected_a_before_b", left, "new", artifact(left));
7424. 9563 }
7425. 9563 }
7426. 9563 } else if (left.id === ".") {
7427. 9563 cack = the_new !== undefined;
7428. 9563 if (left.expression.id === "Date" && left.name.id === "UTC") {
7429. 9563
7430. 9563// test_cause:
7431. 9563// ["new Date.UTC()", "post_b_lparen", "cack", "", 0]
7432. 9563
7433. 9563 test_cause("cack");
7434. 9563 cack = !cack;
7435. 9563 }
7436. 9563 if ((
7437. 9563 // rx_cap
7438. 9563 /^[A-Z]/
7439. 9563 ).test(left.name.id) !== cack) {
7440. 9563 if (the_new !== undefined) {
7441. 9563
7442. 9563// test_cause:
7443. 9563// ["new Date.UTC()", "post_b_lparen", "unexpected_a", "new", 1]
7444. 9563
7445. 9563 warn("unexpected_a", the_new);
7446. 9563 } else {
7447. 9563
7448. 9563// test_cause:
7449. 9563// ["let Aa=Aa.Aa()", "post_b_lparen", "expected_a_before_b", "Aa", 8]
7450. 9563
7451. 9563 warn(
7452. 9563 "expected_a_before_b",
7453. 9563 left.expression,
7454. 9563 "new",
7455. 9563 left.name.id
7456. 9563 );
7457. 9563 }
7458. 9563 }
7459. 9563 if (left.name.id === "getTime") {
7460. 9563 paren = left.expression;
7461. 9563 if (paren.id === "(") {
7462. 9563 array = paren.expression;
7463. 9563 if (array.length === 1) {
7464. 9563 new_date = array[0];
7465. 9563 if (
7466. 9563 new_date.id === "new"
7467. 9563 && new_date.expression.id === "Date"
7468. 9563 ) {
7469. 9563
7470. 9563// test_cause:
7471. 9563// ["
7472. 9563// new Date().getTime()
7473. 9563// ", "post_b_lparen", "expected_a_b", "new Date().getTime()", 1]
7474. 9563
7475. 9563 warn(
7476. 9563 "expected_a_b",
7477. 9563 new_date,
7478. 9563 "Date.now()",
7479. 9563 "new Date().getTime()"
7480. 9563 );
7481. 9563 }
7482. 9563 }
7483. 9563 }
7484. 9563 }
7485. 9563 }
7486. 9604 }
7487. 473
7488. 956 function post_b_or(thing) {
7489. 956 if (
7490. 956 is_weird(thing.expression[0])
7491. 956 || is_equal(thing.expression[0], thing.expression[1])
7492. 955 || thing.expression[0].constant === true
7493. 2 ) {
7494. 2
7495. 2// test_cause:
7496. 2// ["aa=0||0", "post_b_or", "weird_condition_a", "||", 5]
7497. 2
7498. 2 warn("weird_condition_a", thing);
7499. 2 }
7500. 956 }
7501. 473
7502. 57 function post_s_export(the_thing) {
7503. 57
7504. 57// Some features must be at the most outermost level.
7505. 57
7506. 1 if (blockage !== token_global) {
7507. 1
7508. 1// test_cause:
7509. 1// ["
7510. 1// if(0){import aa from "aa";}
7511. 1// ", "post_s_export", "misplaced_a", "import", 7]
7512. 1
7513. 1 warn("misplaced_a", the_thing);
7514. 1 }
7515. 57 }
7516. 473
7517. 8 function post_s_for(thing) {
7518. 8
7519. 8// Recurse walk_statement().
7520. 8
7521. 8 walk_statement(thing.inc);
7522. 8 }
7523. 473
7524. 1833 function post_s_function(thing) {
7525. 1833 delete functionage.async;
7526. 1833 delete functionage.finally;
7527. 1833 delete functionage.loop;
7528. 1833 delete functionage.statement_prv;
7529. 1833 delete functionage.switch;
7530. 1833 delete functionage.try;
7531. 1833 functionage = function_stack.pop();
7532. 3 if (thing.wrapped) {
7533. 3
7534. 3// test_cause:
7535. 3// ["aa=(function(){})", "post_s_function", "unexpected_parens", "function", 5]
7536. 3
7537. 3 warn("unexpected_parens", thing);
7538. 3 }
7539. 1833 return post_s_lbrace();
7540. 1833 }
7541. 473
7542. 41 function post_s_import(the_thing) {
7543. 41 const name = the_thing.name;
7544. 41 if (name) {
7545. 3 if (Array.isArray(name)) {
7546. 3 name.forEach(function (name) {
7547. 3 name.dead = false;
7548. 3 name.init = true;
7549. 3 blockage.live.push(name);
7550. 3 });
7551. 38 } else {
7552. 38 name.dead = false;
7553. 38 name.init = true;
7554. 38 blockage.live.push(name);
7555. 38 }
7556. 41 return post_s_export(the_thing);
7557. 41 }
7558. 41 }
7559. 473
7560. 7325 function post_s_lbrace() {
7561. 2787 blockage.live.forEach(function (name) {
7562. 2787 name.dead = true;
7563. 2787 });
7564. 7325 delete blockage.live;
7565. 7325 blockage = block_stack.pop();
7566. 7325 }
7567. 473
7568. 57 function post_s_try(thing) {
7569. 55 if (thing.catch) {
7570. 55 if (thing.catch.name) {
7571. 55 Object.assign(catchage.context[thing.catch.name.id], {
7572. 55 dead: false,
7573. 55 init: true
7574. 55 });
7575. 55 }
7576. 55
7577. 55// Recurse walk_statement().
7578. 55
7579. 55 walk_statement(thing.catch.block);
7580. 55
7581. 55// Restore previous catch-scope after catch-block.
7582. 55
7583. 55 catchage = catch_stack.pop();
7584. 55 }
7585. 57 }
7586. 473
7587. 2113 function post_s_var(thing) {
7588. 2410 thing.names.forEach(function (name) {
7589. 2410 name.dead = false;
7590. 1063 if (name.expression !== undefined) {
7591. 1063 walk_expression(name.expression);
7592. 1063
7593. 1063// Probably deadcode.
7594. 1063// if (name.id === "{" || name.id === "[") {
7595. 1063// name.names.forEach(subactivate);
7596. 1063// } else {
7597. 1063// name.init = true;
7598. 1063// }
7599. 1063
7600. 1063 jslint_assert(
7601. 1063 !(name.id === "{" || name.id === "["),
7602. 1063 `Expected !(name.id === "{" || name.id === "[").`
7603. 1063 );
7604. 1063 name.init = true;
7605. 1063 }
7606. 2410 blockage.live.push(name);
7607. 2410 });
7608. 2113 }
7609. 473
7610. 213 function post_t(thing) {
7611. 213 if (
7612. 213 is_weird(thing.expression[0])
7613. 213 || thing.expression[0].constant === true
7614. 206 || is_equal(thing.expression[1], thing.expression[2])
7615. 7 ) {
7616. 7 warn("unexpected_a", thing);
7617. 206 } else if (is_equal(thing.expression[0], thing.expression[1])) {
7618. 206
7619. 206// test_cause:
7620. 206// ["aa?aa:0", "post_t", "expected_a_b", "?", 3]
7621. 206
7622. 206 warn("expected_a_b", thing, "||", "?");
7623. 206 } else if (is_equal(thing.expression[0], thing.expression[2])) {
7624. 206
7625. 206// test_cause:
7626. 206// ["aa?0:aa", "post_t", "expected_a_b", "?", 3]
7627. 206
7628. 206 warn("expected_a_b", thing, "&&", "?");
7629. 206 } else if (
7630. 206 thing.expression[1].id === "true"
7631. 206 && thing.expression[2].id === "false"
7632. 206 ) {
7633. 206
7634. 206// test_cause:
7635. 206// ["aa?true:false", "post_t", "expected_a_b", "?", 3]
7636. 206
7637. 206 warn("expected_a_b", thing, "!!", "?");
7638. 206 } else if (
7639. 206 thing.expression[1].id === "false"
7640. 206 && thing.expression[2].id === "true"
7641. 206 ) {
7642. 206
7643. 206// test_cause:
7644. 206// ["aa?false:true", "post_t", "expected_a_b", "?", 3]
7645. 206
7646. 206 warn("expected_a_b", thing, "!", "?");
7647. 206 } else if (
7648. 206 thing.expression[0].wrapped !== true
7649. 206 && (
7650. 206 thing.expression[0].id === "||"
7651. 206 || thing.expression[0].id === "&&"
7652. 206 )
7653. 206 ) {
7654. 206
7655. 206// test_cause:
7656. 206// ["(aa&&!aa?0:1)", "post_t", "wrap_condition", "&&", 4]
7657. 206
7658. 206 warn("wrap_condition", thing.expression[0]);
7659. 206 }
7660. 213 }
7661. 473
7662. 3601 function post_u(thing) {
7663. 699 if (thing.id === "`") {
7664. 699 if (thing.expression.every(function (thing) {
7665. 699 return thing.constant;
7666. 699 })) {
7667. 699 thing.constant = true;
7668. 699 }
7669. 2902 } else if (thing.id === "!") {
7670. 2902 if (thing.expression.constant === true) {
7671. 2902 warn("unexpected_a", thing);
7672. 2902 }
7673. 2902 } else if (thing.id === "!!") {
7674. 2902 if (!option_dict.convert) {
7675. 2902
7676. 2902// test_cause:
7677. 2902// ["!!0", "post_u", "expected_a_b", "!!", 1]
7678. 2902
7679. 2902 warn("expected_a_b", thing, "Boolean(...)", "!!");
7680. 2902 }
7681. 2902 } else if (
7682. 2902 thing.id !== "["
7683. 2902 && thing.id !== "{"
7684. 2902 && thing.id !== "function"
7685. 2902 && thing.id !== "new"
7686. 2902 ) {
7687. 2902 if (thing.expression.constant === true) {
7688. 2902 thing.constant = true;
7689. 2902 }
7690. 2902 }
7691. 3601 }
7692. 473
7693. 7 function post_u_plus(thing) {
7694. 7 const right = thing.expression;
7695. 7 if (!option_dict.convert) {
7696. 7
7697. 7// test_cause:
7698. 7// ["aa=+0", "post_u_plus", "expected_a_b", "+", 4]
7699. 7
7700. 7 warn("expected_a_b", thing, "Number(...)", "+");
7701. 7 }
7702. 1 if (right.id === "(" && right.expression[0].id === "new") {
7703. 1 warn("unexpected_a_before_b", thing, "+", "new");
7704. 6 } else if (
7705. 6 right.constant
7706. 6 || right.id === "{"
7707. 6 || (right.id === "[" && right.arity !== "binary")
7708. 6 ) {
7709. 6 warn("unexpected_a", thing, "+");
7710. 6 }
7711. 7 }
7712. 473
7713. 34715 function pre_a_bitwise(thing) {
7714. 34715
7715. 34715// These are the bitwise operators.
7716. 34715
7717. 34713 switch (!option_dict.bitwise && thing.id) {
7718. 2 case "&":
7719. 3 case "&=":
7720. 5 case "<<":
7721. 6 case "<<=":
7722. 8 case ">>":
7723. 9 case ">>=":
7724. 11 case ">>>":
7725. 12 case ">>>=":
7726. 14 case "^":
7727. 15 case "^=":
7728. 17 case "|":
7729. 18 case "|=":
7730. 21 case "~":
7731. 21
7732. 21// test_cause:
7733. 21// ["0&0", "pre_a_bitwise", "unexpected_a", "&", 2]
7734. 21// ["0&=0", "pre_a_bitwise", "unexpected_a", "&=", 2]
7735. 21// ["0<<0", "pre_a_bitwise", "unexpected_a", "<<", 2]
7736. 21// ["0<<=0", "pre_a_bitwise", "unexpected_a", "<<=", 2]
7737. 21// ["0>>0", "pre_a_bitwise", "unexpected_a", ">>", 2]
7738. 21// ["0>>=0", "pre_a_bitwise", "unexpected_a", ">>=", 2]
7739. 21// ["0>>>0", "pre_a_bitwise", "unexpected_a", ">>>", 2]
7740. 21// ["0>>>=0", "pre_a_bitwise", "unexpected_a", ">>>=", 2]
7741. 21// ["0^0", "pre_a_bitwise", "unexpected_a", "^", 2]
7742. 21// ["0^=0", "pre_a_bitwise", "unexpected_a", "^=", 2]
7743. 21// ["0|0", "pre_a_bitwise", "unexpected_a", "|", 2]
7744. 21// ["0|=0", "pre_a_bitwise", "unexpected_a", "|=", 2]
7745. 21// ["~0", "pre_a_bitwise", "unexpected_a", "~", 1]
7746. 21
7747. 21 warn("unexpected_a", thing);
7748. 21 break;
7749. 34715 }
7750. 34715 if (
7751. 34715 thing.id !== "("
7752. 25111 && thing.id !== "&&"
7753. 23951 && thing.id !== "||"
7754. 22995 && thing.id !== "="
7755. 18986 && Array.isArray(thing.expression)
7756. 8048 && thing.expression.length === 2
7757. 8047 && (
7758. 8047 relationop[thing.expression[0].id] === true
7759. 8047 || relationop[thing.expression[1].id] === true
7760. 8047 )
7761. 1 ) {
7762. 1
7763. 1// test_cause:
7764. 1// ["0<0<0", "pre_a_bitwise", "unexpected_a", "<", 4]
7765. 1
7766. 1 warn("unexpected_a", thing);
7767. 1 }
7768. 34715 }
7769. 473
7770. 29995 function pre_b(thing) {
7771. 29995 let left;
7772. 29995 let right;
7773. 29995 let value;
7774. 3951 if (relationop[thing.id] === true) {
7775. 3951 left = thing.expression[0];
7776. 3951 right = thing.expression[1];
7777. 3951 if (left.id === "NaN" || right.id === "NaN") {
7778. 3951
7779. 3951// test_cause:
7780. 3951// ["NaN===NaN", "pre_b", "number_isNaN", "===", 4]
7781. 3951
7782. 3951 warn("number_isNaN", thing);
7783. 3951 } else if (left.id === "typeof") {
7784. 3951 if (right.id !== "(string)") {
7785. 3951 if (right.id !== "typeof") {
7786. 3951
7787. 3951// test_cause:
7788. 3951// ["typeof 0===0", "pre_b", "expected_string_a", "0", 12]
7789. 3951
7790. 3951 warn("expected_string_a", right);
7791. 3951 }
7792. 3951 } else {
7793. 3951 value = right.value;
7794. 3951 if (value === "null" || value === "undefined") {
7795. 3951
7796. 3951// test_cause:
7797. 3951// ["
7798. 3951// typeof aa==="undefined"
7799. 3951// ", "pre_b", "unexpected_typeof_a", "undefined", 13]
7800. 3951
7801. 3951 warn("unexpected_typeof_a", right, value);
7802. 3951 } else if (
7803. 3951 value !== "bigint"
7804. 3951 && value !== "boolean"
7805. 3951 && value !== "function"
7806. 3951 && value !== "number"
7807. 3951 && value !== "object"
7808. 3951 && value !== "string"
7809. 3951 && value !== "symbol"
7810. 3951 ) {
7811. 3951
7812. 3951// test_cause:
7813. 3951// ["typeof 0===\"aa\"", "pre_b", "expected_type_string_a", "aa", 12]
7814. 3951
7815. 3951 warn("expected_type_string_a", right, value);
7816. 3951 }
7817. 3951 }
7818. 3951 }
7819. 3951 }
7820. 29995 }
7821. 473
7822. 1 function pre_b_eqeq(thing) {
7823. 1
7824. 1// test_cause:
7825. 1// ["0==0", "pre_b_eqeq", "expected_a_b", "==", 2]
7826. 1
7827. 1 warn("expected_a_b", thing, "===", "==");
7828. 1 }
7829. 473
7830. 1 function pre_b_in(thing) {
7831. 1
7832. 1// test_cause:
7833. 1// ["aa in aa", "pre_b_in", "infix_in", "in", 4]
7834. 1
7835. 1 warn("infix_in", thing);
7836. 1 }
7837. 473
7838. 1 function pre_b_instanceof(thing) {
7839. 1
7840. 1// test_cause:
7841. 1// ["0 instanceof 0", "pre_b_instanceof", "unexpected_a", "instanceof", 3]
7842. 1
7843. 1 warn("unexpected_a", thing);
7844. 1 }
7845. 473
7846. 9604 function pre_b_lparen(thing) {
7847. 9604 const left = thing.expression[0];
7848. 9604 let left_variable;
7849. 9604 let parent;
7850. 9604 if (
7851. 9604 left.identifier
7852. 6444 && functionage.context[left.id] === undefined
7853. 2904 && typeof functionage.name === "object"
7854. 2321 ) {
7855. 2321 parent = functionage.name.parent;
7856. 2321 if (parent) {
7857. 2321 left_variable = parent.context[left.id];
7858. 2321 if (
7859. 2321 left_variable !== undefined
7860. 2321 // Coverage-hack.
7861. 2321 // && left_variable.dead
7862. 2321 && left_variable.parent === parent
7863. 2321 && left_variable.calls !== undefined
7864. 2321 && left_variable.calls[functionage.name.id] !== undefined
7865. 2321 ) {
7866. 2321 left_variable.dead = false;
7867. 2321 }
7868. 2321 }
7869. 2321 }
7870. 9604 }
7871. 473
7872. 1 function pre_b_noteq(thing) {
7873. 1
7874. 1// test_cause:
7875. 1// ["0!=0", "pre_b_noteq", "expected_a_b", "!=", 2]
7876. 1
7877. 1 warn("expected_a_b", thing, "!==", "!=");
7878. 1 }
7879. 473
7880. 956 function pre_b_or(thing) {
7881. 1912 thing.expression.forEach(function (thang) {
7882. 186 if (thang.id === "&&" && !thang.wrapped) {
7883. 1
7884. 1// test_cause:
7885. 1// ["0&&0||0", "pre_b_or", "and", "&&", 2]
7886. 1
7887. 1 warn("and", thang);
7888. 1 }
7889. 1912 });
7890. 956 }
7891. 473
7892. 8 function pre_s_for(thing) {
7893. 8 let the_variable;
7894. 2 if (thing.name !== undefined) {
7895. 2 thing.name.dead = false;
7896. 2 the_variable = lookup(thing.name);
7897. 2 if (the_variable !== undefined) {
7898. 2 if (the_variable.init && the_variable.readonly) {
7899. 2
7900. 2// test_cause:
7901. 2// ["const aa=0;for(aa in aa){}", "pre_s_for", "bad_assignment_a", "aa", 16]
7902. 2
7903. 2 warn("bad_assignment_a", thing.name);
7904. 2 }
7905. 2 the_variable.init = true;
7906. 2 }
7907. 2 }
7908. 8
7909. 8// Recurse walk_statement().
7910. 8
7911. 8 walk_statement(thing.initial);
7912. 8 }
7913. 473
7914. 1833 function pre_s_function(thing) {
7915. 1833
7916. 1833// test_cause:
7917. 1833// ["()=>0", "pre_s_function", "", "", 0]
7918. 1833// ["(function (){}())", "pre_s_function", "", "", 0]
7919. 1833// ["function aa(){}", "pre_s_function", "", "", 0]
7920. 1833
7921. 1833 test_cause("");
7922. 1022 if (thing.arity === "statement" && blockage.body !== true) {
7923. 1
7924. 1// test_cause:
7925. 1// ["if(0){function aa(){}\n}", "pre_s_function", "unexpected_a", "function", 7]
7926. 1
7927. 1 warn("unexpected_a", thing);
7928. 1 }
7929. 1833 function_stack.push(functionage);
7930. 1833 block_stack.push(blockage);
7931. 1833 functionage = thing;
7932. 1833 blockage = thing;
7933. 1833 thing.live = [];
7934. 1062 if (typeof thing.name === "object") {
7935. 1062 thing.name.dead = false;
7936. 1062 thing.name.init = true;
7937. 1062 }
7938. 7 if (thing.extra === "get") {
7939. 7 if (thing.parameters.length !== 0) {
7940. 7
7941. 7// test_cause:
7942. 7// ["
7943. 7// /*jslint getset*/
7944. 7// aa={get aa(aa){}}
7945. 7// ", "pre_s_function", "bad_get", "function", 9]
7946. 7
7947. 7 warn("bad_get", thing);
7948. 7 }
7949. 1826 } else if (thing.extra === "set") {
7950. 1826 if (thing.parameters.length !== 1) {
7951. 1826
7952. 1826// test_cause:
7953. 1826// ["
7954. 1826// /*jslint getset*/
7955. 1826// aa={set aa(){}}
7956. 1826// ", "pre_s_function", "bad_set", "function", 9]
7957. 1826
7958. 1826 warn("bad_set", thing);
7959. 1826 }
7960. 1826 }
7961. 1900 thing.parameters.forEach(function (name) {
7962. 1900 walk_expression(name.expression);
7963. 1706 if (name.id === "{" || name.id === "[") {
7964. 225 name.names.forEach(subactivate);
7965. 1675 } else {
7966. 1675 name.dead = false;
7967. 1675 name.init = true;
7968. 1675 }
7969. 1900 });
7970. 1833 }
7971. 473
7972. 5492 function pre_s_lbrace(thing) {
7973. 5492 block_stack.push(blockage);
7974. 5492 blockage = thing;
7975. 5492 thing.live = [];
7976. 5492 }
7977. 473
7978. 57 function pre_try(thing) {
7979. 55 if (thing.catch !== undefined) {
7980. 55
7981. 55// Create new catch-scope for catch-parameter.
7982. 55
7983. 55 catch_stack.push(catchage);
7984. 55 catchage = thing.catch;
7985. 55 }
7986. 57 }
7987. 473
7988. 27036 function pre_v(thing) {
7989. 27036 const the_variable = lookup(thing);
7990. 26965 if (the_variable !== undefined) {
7991. 26965 thing.variable = the_variable;
7992. 26965 the_variable.used += 1;
7993. 26965 }
7994. 27036 }
7995. 473
7996. 614 function subactivate(name) {
7997. 614 name.init = true;
7998. 614 name.dead = false;
7999. 614 blockage.live.push(name);
8000. 614 }
8001. 473
8002. 153443 function walk_expression(thing) {
8003. 96610 if (thing) {
8004. 96610 if (Array.isArray(thing)) {
8005. 96610
8006. 96610// test_cause:
8007. 96610// ["(function(){}())", "walk_expression", "isArray", "", 0]
8008. 96610// ["0&&0", "walk_expression", "isArray", "", 0]
8009. 96610
8010. 96610 test_cause("isArray");
8011. 96610 thing.forEach(walk_expression);
8012. 96610 } else {
8013. 96610 preamble(thing);
8014. 96610 walk_expression(thing.expression);
8015. 96610 if (thing.id === "function") {
8016. 96610
8017. 96610// test_cause:
8018. 96610// ["aa=function(){}", "walk_expression", "function", "", 0]
8019. 96610
8020. 96610 test_cause("function");
8021. 96610
8022. 96610// Recurse walk_statement().
8023. 96610
8024. 96610 walk_statement(thing.block);
8025. 96610 }
8026. 96610 if (
8027. 96610 thing.arity === "preassign" || thing.arity === "postassign"
8028. 96610 ) {
8029. 96610
8030. 96610// test_cause:
8031. 96610// ["aa=++aa", "walk_expression", "unexpected_a", "++", 4]
8032. 96610// ["aa=--aa", "walk_expression", "unexpected_a", "--", 4]
8033. 96610
8034. 96610 warn("unexpected_a", thing);
8035. 96610 } else if (
8036. 96610 thing.arity === "statement"
8037. 96610 || thing.arity === "assignment"
8038. 96610 ) {
8039. 96610
8040. 96610// test_cause:
8041. 96610// ["aa[aa=0]", "walk_expression", "unexpected_statement_a", "=", 6]
8042. 96610
8043. 96610 warn("unexpected_statement_a", thing);
8044. 96610 }
8045. 96610
8046. 96610// test_cause:
8047. 96610// ["aa=0", "walk_expression", "default", "", 0]
8048. 96610
8049. 96610 test_cause("default");
8050. 96610 postamble(thing);
8051. 96610 }
8052. 96610 }
8053. 153443 }
8054. 473
8055. 74260 function walk_statement(thing) {
8056. 33514 if (thing) {
8057. 33514 if (Array.isArray(thing)) {
8058. 33514
8059. 33514// test_cause:
8060. 33514// ["+[]", "walk_statement", "isArray", "", 0]
8061. 33514
8062. 33514 test_cause("isArray");
8063. 33514
8064. 33514// Recurse walk_statement().
8065. 33514
8066. 33514 thing.forEach(walk_statement);
8067. 33514 } else {
8068. 33514 preamble(thing);
8069. 33514 walk_expression(thing.expression);
8070. 33514 if (thing.arity === "binary") {
8071. 33514 if (thing.id !== "(") {
8072. 33514
8073. 33514// test_cause:
8074. 33514// ["0&&0", "walk_statement", "unexpected_expression_a", "&&", 2]
8075. 33514
8076. 33514 warn("unexpected_expression_a", thing);
8077. 33514 }
8078. 33514 } else if (
8079. 33514 thing.arity !== "statement"
8080. 33514 && thing.arity !== "assignment"
8081. 33514 && thing.id !== "import"
8082. 33514 ) {
8083. 33514
8084. 33514// test_cause:
8085. 33514// ["!0", "walk_statement", "unexpected_expression_a", "!", 1]
8086. 33514// ["+[]", "walk_statement", "unexpected_expression_a", "+", 1]
8087. 33514// ["+new aa()", "walk_statement", "unexpected_expression_a", "+", 1]
8088. 33514// ["0", "walk_statement", "unexpected_expression_a", "0", 1]
8089. 33514// ["
8090. 33514// async function aa(){await 0;}
8091. 33514// ", "walk_statement", "unexpected_expression_a", "0", 27]
8092. 33514// ["typeof 0", "walk_statement", "unexpected_expression_a", "typeof", 1]
8093. 33514
8094. 33514 warn("unexpected_expression_a", thing);
8095. 33514 }
8096. 33514
8097. 33514// Recurse walk_statement().
8098. 33514
8099. 33514 walk_statement(thing.block);
8100. 33514 walk_statement(thing.else);
8101. 33514 postamble(thing);
8102. 33514 }
8103. 33514 }
8104. 74260 }
8105. 473
8106. 473 postaction = action(posts);
8107. 473 postamble = amble(posts);
8108. 473 preaction = action(pres);
8109. 473 preamble = amble(pres);
8110. 473 postaction("assignment", "+=", post_a_pluseq);
8111. 473 postaction("assignment", post_a);
8112. 473 postaction("binary", "&&", post_b_and);
8113. 473 postaction("binary", "(", post_b_lparen);
8114. 473 postaction("binary", "=>", post_s_function);
8115. 473 postaction("binary", "[", post_b_lbracket);
8116. 473 postaction("binary", "||", post_b_or);
8117. 473 postaction("binary", post_b);
8118. 473 postaction("statement", "const", post_s_var);
8119. 473 postaction("statement", "export", post_s_export);
8120. 473 postaction("statement", "for", post_s_for);
8121. 473 postaction("statement", "function", post_s_function);
8122. 473 postaction("statement", "import", post_s_import);
8123. 473 postaction("statement", "let", post_s_var);
8124. 473 postaction("statement", "try", post_s_try);
8125. 473 postaction("statement", "var", post_s_var);
8126. 473 postaction("statement", "{", post_s_lbrace);
8127. 473 postaction("ternary", post_t);
8128. 473 postaction("unary", "+", post_u_plus);
8129. 473 postaction("unary", "function", post_s_function);
8130. 473 postaction("unary", post_u);
8131. 473 preaction("assignment", pre_a_bitwise);
8132. 473 preaction("binary", "!=", pre_b_noteq);
8133. 473 preaction("binary", "(", pre_b_lparen);
8134. 473 preaction("binary", "==", pre_b_eqeq);
8135. 473 preaction("binary", "=>", pre_s_function);
8136. 473 preaction("binary", "in", pre_b_in);
8137. 473 preaction("binary", "instanceof", pre_b_instanceof);
8138. 473 preaction("binary", "||", pre_b_or);
8139. 473 preaction("binary", pre_b);
8140. 473 preaction("binary", pre_a_bitwise);
8141. 473 preaction("statement", "for", pre_s_for);
8142. 473 preaction("statement", "function", pre_s_function);
8143. 473 preaction("statement", "try", pre_try);
8144. 473 preaction("statement", "{", pre_s_lbrace);
8145. 473 preaction("unary", "function", pre_s_function);
8146. 473 preaction("unary", "~", pre_a_bitwise);
8147. 473 preaction("variable", pre_v);
8148. 473
8149. 473 walk_statement(state.token_tree);
8150. 473}
8151. 1
8152. 176function jslint_phase5_whitage(state) {
8153. 176
8154. 176// PHASE 5. Check whitespace between tokens in <token_list>.
8155. 176
8156. 176 let {
8157. 176 artifact,
8158. 176 catch_list,
8159. 176 function_list,
8160. 176 function_stack,
8161. 176 option_dict,
8162. 176 test_cause,
8163. 176 token_global,
8164. 176 token_list,
8165. 176 warn
8166. 176 } = state;
8167. 176 let closer = "(end)";
8168. 176 let free = false;
8169. 176
8170. 176// free = false
8171. 176
8172. 176// cause:
8173. 176// "()=>0"
8174. 176// "aa()"
8175. 176// "aa(0,0)"
8176. 176// "function(){}"
8177. 176
8178. 176// free = true
8179. 176
8180. 176// cause:
8181. 176// "(0)"
8182. 176// "(aa)"
8183. 176// "aa(0)"
8184. 176// "do{}while()"
8185. 176// "for(){}"
8186. 176// "if(){}"
8187. 176// "switch(){}"
8188. 176// "while(){}"
8189. 176
8190. 176 let left = token_global;
8191. 176 let margin = 0;
8192. 176 let mode_indent = (
8193. 176
8194. 176// PR-330 - Allow 2-space indent.
8195. 176
8196. 176 option_dict.indent2
8197. 5 ? 2
8198. 171 : 4
8199. 176 );
8200. 176 let nr_comments_skipped = 0;
8201. 176 let open = true;
8202. 176 let opening = true;
8203. 176 let right;
8204. 176
8205. 176// This is the set of infix operators that require a space on each side.
8206. 176
8207. 176 let spaceop = object_assign_from_list(empty(), [
8208. 176 "!=", "!==", "%", "%=", "&", "&&", "&=", "*", "*=", "+=", "-=", "/",
8209. 176 "/=", "<", "<<", "<<=", "<=", "=", "==", "===", "=>", ">", ">=", ">>",
8210. 176 ">>=", ">>>", ">>>=", "^", "^=", "|", "|=", "||"
8211. 176 ], true);
8212. 176
8213. 34811 function at_margin(fit) {
8214. 34811 const at = margin + fit;
8215. 21 if (right.from !== at) {
8216. 21 return expected_at(at);
8217. 21 }
8218. 34811 }
8219. 176
8220. 1878 function delve(the_function) {
8221. 11915 Object.keys(the_function.context).forEach(function (id) {
8222. 11915 const name = the_function.context[id];
8223. 11886 if (id !== "ignore" && name.parent === the_function) {
8224. 5763
8225. 5763// test_cause:
8226. 5763// ["function aa(aa) {return aa;}", "delve", "id", "", 0]
8227. 5763
8228. 5763 test_cause("id");
8229. 5763 if (
8230. 5763 name.used === 0
8231. 5763
8232. 5763// Probably deadcode.
8233. 5763// && (
8234. 5763// name.role !== "function"
8235. 5763// || name.parent.arity !== "unary"
8236. 5763// )
8237. 5763
8238. 5763 && jslint_assert(
8239. 5763 name.role !== "function",
8240. 5763 `Expected name.role !== "function".`
8241. 5763 )
8242. 5763 ) {
8243. 5763
8244. 5763// test_cause:
8245. 5763// ["/*jslint node*/\nlet aa;", "delve", "unused_a", "aa", 5]
8246. 5763// ["function aa(aa){return;}", "delve", "unused_a", "aa", 13]
8247. 5763// ["let aa=0;try{aa();}catch(bb){aa();}", "delve", "unused_a", "bb", 26]
8248. 5763
8249. 5763 warn("unused_a", name);
8250. 5763 } else if (!name.init) {
8251. 5763
8252. 5763// test_cause:
8253. 5763// ["/*jslint node*/\nlet aa;aa();", "delve", "uninitialized_a", "aa", 5]
8254. 5763
8255. 5763 warn("uninitialized_a", name);
8256. 5763 }
8257. 5763 }
8258. 11915 });
8259. 1878 }
8260. 176
8261. 25 function expected_at(at) {
8262. 25
8263. 25// Probably deadcode.
8264. 25// if (right === undefined) {
8265. 25// right = token_nxt;
8266. 25// }
8267. 25
8268. 25 jslint_assert(
8269. 25 !(right === undefined),
8270. 25 `Expected !(right === undefined).`
8271. 25 );
8272. 25 warn(
8273. 25 "expected_a_at_b_c",
8274. 25 right,
8275. 25 artifact(right),
8276. 25
8277. 25// Fudge column numbers in warning message.
8278. 25
8279. 25 at + jslint_fudge,
8280. 25 right.from + jslint_fudge
8281. 25 );
8282. 25 }
8283. 176
8284. 2866 function no_space() {
8285. 2865 if (left.line === right.line) {
8286. 2865
8287. 2865// from:
8288. 2865// if (left.line === right.line) {
8289. 2865// no_space();
8290. 2865// } else {
8291. 2865
8292. 2865 if (left.thru !== right.from && nr_comments_skipped === 0) {
8293. 2865
8294. 2865// test_cause:
8295. 2865// ["let aa = aa( );", "no_space", "unexpected_space_a_b", ")", 14]
8296. 2865
8297. 2865 warn(
8298. 2865 "unexpected_space_a_b",
8299. 2865 right,
8300. 2865 artifact(left),
8301. 2865 artifact(right)
8302. 2865 );
8303. 2865 }
8304. 2865 } else {
8305. 1
8306. 1// from:
8307. 1// } else if (
8308. 1// right.arity === "binary"
8309. 1// && right.id === "("
8310. 1// && free
8311. 1// ) {
8312. 1// no_space();
8313. 1// } else if (
8314. 1
8315. 1// Probably deadcode.
8316. 1// if (open) {
8317. 1// const at = (
8318. 1// free
8319. 1// ? margin
8320. 1// : margin + 8
8321. 1// );
8322. 1// if (right.from < at) {
8323. 1// expected_at(at);
8324. 1// }
8325. 1// } else {
8326. 1// if (right.from !== margin + 8) {
8327. 1// expected_at(margin + 8);
8328. 1// }
8329. 1// }
8330. 1
8331. 1 jslint_assert(open, `Expected open.`);
8332. 1 jslint_assert(free, `Expected free.`);
8333. 1 if (right.from < margin) {
8334. 1
8335. 1// test_cause:
8336. 1// ["let aa = aa(\naa\n()\n);", "expected_at", "expected_a_at_b_c", "5", 1]
8337. 1
8338. 1 expected_at(margin);
8339. 1 }
8340. 1 }
8341. 2866 }
8342. 176
8343. 89050 function no_space_only() {
8344. 89050 if (
8345. 89050 left.id !== "(global)"
8346. 89048 && left.nr + 1 === right.nr
8347. 89048 && (
8348. 89048 left.line !== right.line
8349. 89048 || left.thru !== right.from
8350. 89048 )
8351. 5 ) {
8352. 5 warn(
8353. 5 "unexpected_space_a_b",
8354. 5 right,
8355. 5 artifact(left),
8356. 5 artifact(right)
8357. 5 );
8358. 5 }
8359. 89050 }
8360. 176
8361. 43175 function one_space() {
8362. 41445 if (left.line === right.line || !open) {
8363. 41445 if (left.thru + 1 !== right.from && nr_comments_skipped === 0) {
8364. 41445 warn(
8365. 41445 "expected_space_a_b",
8366. 41445 right,
8367. 41445 artifact(left),
8368. 41445 artifact(right)
8369. 41445 );
8370. 41445 }
8371. 41445 } else {
8372. 1730 if (right.from !== margin) {
8373. 1730 expected_at(margin);
8374. 1730 }
8375. 1730 }
8376. 43175 }
8377. 176
8378. 8955 function one_space_only() {
8379. 8 if (left.line !== right.line || left.thru + 1 !== right.from) {
8380. 8 warn("expected_space_a_b", right, artifact(left), artifact(right));
8381. 8 }
8382. 8955 }
8383. 176
8384. 22789 function pop() {
8385. 22789 const previous = function_stack.pop();
8386. 22789 closer = previous.closer;
8387. 22789 free = previous.free;
8388. 22789 margin = previous.margin;
8389. 22789 open = previous.open;
8390. 22789 opening = previous.opening;
8391. 22789 }
8392. 176
8393. 22789 function push() {
8394. 22789 function_stack.push({
8395. 22789 closer,
8396. 22789 free,
8397. 22789 margin,
8398. 22789 open,
8399. 22789 opening
8400. 22789 });
8401. 22789 }
8402. 176
8403. 176// uninitialized_and_unused();
8404. 176// Delve into the functions looking for variables that were not initialized
8405. 176// or used. If the file imports or exports, then its global object is also
8406. 176// delved.
8407. 176
8408. 150 if (state.mode_module === true || option_dict.node) {
8409. 40 delve(token_global);
8410. 40 }
8411. 176 catch_list.forEach(delve);
8412. 176 function_list.forEach(delve);
8413. 176
8414. 2 if (option_dict.white) {
8415. 2 return;
8416. 174 }
8417. 174
8418. 174// whitage();
8419. 174// Go through the token list, looking at usage of whitespace.
8420. 174
8421. 191641 token_list.forEach(function whitage(the_token) {
8422. 191641 right = the_token;
8423. 181642 if (right.id === "(comment)" || right.id === "(end)") {
8424. 10175 nr_comments_skipped += 1;
8425. 181466 } else {
8426. 181466
8427. 181466// If left is an opener and right is not the closer, then push the previous
8428. 181466// state. If the token following the opener is on the next line, then this is
8429. 181466// an open form. If the tokens are on the same line, then it is a closed form.
8430. 181466// Open form is more readable, with each item (statement, argument, parameter,
8431. 181466// etc) starting on its own line. Closed form is more compact. Statement blocks
8432. 181466// are always in open form.
8433. 181466
8434. 181466// The open and close pairs.
8435. 181466
8436. 181466 switch (left.id) {
8437. 181466 case "${":
8438. 181466 case "(":
8439. 181466 case "[":
8440. 181466 case "{":
8441. 181466
8442. 181466// test_cause:
8443. 181466// ["let aa=[];", "whitage", "opener", "", 0]
8444. 181466// ["let aa=`${0}`;", "whitage", "opener", "", 0]
8445. 181466// ["let aa=aa();", "whitage", "opener", "", 0]
8446. 181466// ["let aa={};", "whitage", "opener", "", 0]
8447. 181466
8448. 181466 test_cause("opener");
8449. 181466
8450. 181466// Probably deadcode.
8451. 181466// case "${}":
8452. 181466
8453. 181466 jslint_assert(
8454. 181466 !(left.id + right.id === "${}"),
8455. 181466 "Expected !(left.id + right.id === \"${}\")."
8456. 181466 );
8457. 181466 switch (left.id + right.id) {
8458. 181466 case "()":
8459. 181466 case "[]":
8460. 181466 case "{}":
8461. 181466
8462. 181466// If left and right are opener and closer, then the placement of right depends
8463. 181466// on the openness. Illegal pairs (like '{]') have already been detected.
8464. 181466
8465. 181466// test_cause:
8466. 181466// ["let aa=[];", "whitage", "opener_closer", "", 0]
8467. 181466// ["let aa=aa();", "whitage", "opener_closer", "", 0]
8468. 181466// ["let aa={};", "whitage", "opener_closer", "", 0]
8469. 181466
8470. 181466 test_cause("opener_closer");
8471. 181466 if (left.line === right.line) {
8472. 181466
8473. 181466// test_cause:
8474. 181466// ["let aa = aa( );", "no_space", "unexpected_space_a_b", ")", 14]
8475. 181466
8476. 181466 no_space();
8477. 181466 } else {
8478. 181466
8479. 181466// test_cause:
8480. 181466// ["let aa = aa(\n );", "expected_at", "expected_a_at_b_c", "1", 2]
8481. 181466
8482. 181466 at_margin(0);
8483. 181466 }
8484. 181466 break;
8485. 181466 default:
8486. 181466
8487. 181466// test_cause:
8488. 181466// ["let aa=(0);", "whitage", "opener_operand", "", 0]
8489. 181466// ["let aa=[0];", "whitage", "opener_operand", "", 0]
8490. 181466// ["let aa=`${0}`;", "whitage", "opener_operand", "", 0]
8491. 181466// ["let aa=aa(0);", "whitage", "opener_operand", "", 0]
8492. 181466// ["let aa={aa:0};", "whitage", "opener_operand", "", 0]
8493. 181466
8494. 181466 test_cause("opener_operand");
8495. 181466 opening = left.open || (left.line !== right.line);
8496. 181466 push();
8497. 181466 switch (left.id) {
8498. 181466 case "${":
8499. 181466 closer = "}";
8500. 181466 break;
8501. 181466 case "(":
8502. 181466 closer = ")";
8503. 181466 break;
8504. 181466 case "[":
8505. 181466 closer = "]";
8506. 181466 break;
8507. 181466 case "{":
8508. 181466 closer = "}";
8509. 181466 break;
8510. 181466 }
8511. 181466 if (opening) {
8512. 181466
8513. 181466// test_cause:
8514. 181466// ["function aa(){\nreturn;\n}", "whitage", "opening", "", 0]
8515. 181466// ["let aa=(\n0\n);", "whitage", "opening", "", 0]
8516. 181466// ["let aa=[\n0\n];", "whitage", "opening", "", 0]
8517. 181466// ["let aa=`${\n0\n}`;", "whitage", "opening", "", 0]
8518. 181466// ["let aa={\naa:0\n};", "whitage", "opening", "", 0]
8519. 181466
8520. 181466 test_cause("opening");
8521. 181466 free = closer === ")" && left.free;
8522. 181466 open = true;
8523. 181466 margin += mode_indent;
8524. 181466 if (right.role === "label") {
8525. 181466 if (right.from !== 0) {
8526. 181466
8527. 181466// test_cause:
8528. 181466// ["
8529. 181466// function aa() {
8530. 181466// bb:
8531. 181466// while (aa) {
8532. 181466// if (aa) {
8533. 181466// break bb;
8534. 181466// }
8535. 181466// }
8536. 181466// }
8537. 181466// ", "expected_at", "expected_a_at_b_c", "1", 2]
8538. 181466
8539. 181466 expected_at(0);
8540. 181466 }
8541. 181466 } else if (right.switch) {
8542. 181466 at_margin(-mode_indent);
8543. 181466 } else {
8544. 181466 at_margin(0);
8545. 181466 }
8546. 181466 } else {
8547. 181466 if (right.statement || right.role === "label") {
8548. 181466
8549. 181466// test_cause:
8550. 181466// ["
8551. 181466// function aa() {bb:
8552. 181466// while (aa) {
8553. 181466// aa();
8554. 181466// }
8555. 181466// }
8556. 181466// ", "whitage", "expected_line_break_a_b", "bb", 16]
8557. 181466
8558. 181466 warn(
8559. 181466 "expected_line_break_a_b",
8560. 181466 right,
8561. 181466 artifact(left),
8562. 181466 artifact(right)
8563. 181466 );
8564. 181466 }
8565. 181466
8566. 181466// test_cause:
8567. 181466// ["let aa=(0);", "whitage", "not_free", "", 0]
8568. 181466// ["let aa=[0];", "whitage", "not_free", "", 0]
8569. 181466// ["let aa=`${0}`;", "whitage", "not_free", "", 0]
8570. 181466// ["let aa={aa:0};", "whitage", "not_free", "", 0]
8571. 181466
8572. 181466 test_cause("not_free");
8573. 181466 free = false;
8574. 181466 open = false;
8575. 181466
8576. 181466// test_cause:
8577. 181466// ["let aa = ( 0 );", "no_space_only", "unexpected_space_a_b", "0", 12]
8578. 181466
8579. 181466 no_space_only();
8580. 181466 }
8581. 181466 }
8582. 181466 break;
8583. 181466 default:
8584. 181466 if (right.statement === true) {
8585. 181466 if (left.id === "else") {
8586. 181466
8587. 181466// test_cause:
8588. 181466// ["
8589. 181466// let aa = 0;
8590. 181466// if (aa) {
8591. 181466// aa();
8592. 181466// } else if (aa) {
8593. 181466// aa();
8594. 181466// }
8595. 181466// ", "one_space_only", "expected_space_a_b", "if", 9]
8596. 181466
8597. 181466 one_space_only();
8598. 181466 } else {
8599. 181466
8600. 181466// test_cause:
8601. 181466// [" let aa = 0;", "expected_at", "expected_a_at_b_c", "1", 2]
8602. 181466
8603. 181466 at_margin(0);
8604. 181466 open = false;
8605. 181466 }
8606. 181466
8607. 181466// If right is a closer, then pop the previous state.
8608. 181466
8609. 181466 } else if (right.id === closer) {
8610. 181466 pop();
8611. 181466 if (opening && right.id !== ";") {
8612. 181466 at_margin(0);
8613. 181466 } else {
8614. 181466 no_space_only();
8615. 181466 }
8616. 181466 } else {
8617. 181466
8618. 181466// Left is not an opener, and right is not a closer.
8619. 181466// The nature of left and right will determine the space between them.
8620. 181466
8621. 181466// If left is ',' or ';' or right is a statement then if open,
8622. 181466// right must go at the margin, or if closed, a space between.
8623. 181466
8624. 181466 if (right.switch) {
8625. 181466 at_margin(-mode_indent);
8626. 181466 } else if (right.role === "label") {
8627. 181466 if (right.from !== 0) {
8628. 181466
8629. 181466// test_cause:
8630. 181466// ["
8631. 181466// function aa() {
8632. 181466// aa();cc:
8633. 181466// while (aa) {
8634. 181466// if (aa) {
8635. 181466// break cc;
8636. 181466// }
8637. 181466// }
8638. 181466// }
8639. 181466// ", "expected_at", "expected_a_at_b_c", "1", 10]
8640. 181466
8641. 181466 expected_at(0);
8642. 181466 }
8643. 181466 } else if (left.id === ",") {
8644. 181466 if (!open || (
8645. 181466 (free || closer === "]")
8646. 181466 && left.line === right.line
8647. 181466 )) {
8648. 181466
8649. 181466// test_cause:
8650. 181466// ["let {aa,bb} = 0;", "one_space", "expected_space_a_b", "bb", 9]
8651. 181466
8652. 181466 one_space();
8653. 181466 } else {
8654. 181466
8655. 181466// test_cause:
8656. 181466// ["
8657. 181466// function aa() {
8658. 181466// aa(
8659. 181466// 0,0
8660. 181466// );
8661. 181466// }
8662. 181466// ", "expected_at", "expected_a_at_b_c", "9", 11]
8663. 181466
8664. 181466 at_margin(0);
8665. 181466 }
8666. 181466
8667. 181466// If right is a ternary operator, line it up on the margin.
8668. 181466
8669. 181466 } else if (right.arity === "ternary") {
8670. 181466 if (open) {
8671. 181466
8672. 181466// test_cause:
8673. 181466// ["
8674. 181466// let aa = (
8675. 181466// aa
8676. 181466// ? 0
8677. 181466// : 1
8678. 181466// );
8679. 181466// ", "expected_at", "expected_a_at_b_c", "5", 1]
8680. 181466
8681. 181466 at_margin(0);
8682. 181466 } else {
8683. 181466
8684. 181466// test_cause:
8685. 181466// ["let aa = (aa ? 0 : 1);", "whitage", "use_open", "?", 14]
8686. 181466
8687. 181466 warn("use_open", right);
8688. 181466 }
8689. 181466 } else if (
8690. 181466 right.arity === "binary"
8691. 181466 && right.id === "("
8692. 181466 && free
8693. 181466 ) {
8694. 181466
8695. 181466// test_cause:
8696. 181466// ["let aa = aa(\naa ()\n);", "no_space", "unexpected_space_a_b", "(", 4]
8697. 181466
8698. 181466 no_space();
8699. 181466 } else if (
8700. 181466 left.id === "."
8701. 181466 || left.id === "?."
8702. 181466 || left.id === "..."
8703. 181466 || right.id === ","
8704. 181466 || right.id === ";"
8705. 181466 || right.id === ":"
8706. 181466 || (
8707. 181466 right.arity === "binary"
8708. 181466 && (right.id === "(" || right.id === "[")
8709. 181466 )
8710. 181466 || (
8711. 181466 right.arity === "function"
8712. 181466 && left.id !== "function"
8713. 181466 )
8714. 181466 || (right.id === "." || right.id === "?.")
8715. 181466 ) {
8716. 181466
8717. 181466// test_cause:
8718. 181466// ["let aa = 0 ;", "no_space_only", "unexpected_space_a_b", ";", 12]
8719. 181466// ["let aa = aa ?.aa;", "no_space_only", "unexpected_space_a_b", "?.", 13]
8720. 181466
8721. 181466 no_space_only();
8722. 181466 } else if (left.id === ";") {
8723. 181466
8724. 181466// test_cause:
8725. 181466// ["
8726. 181466// /*jslint for*/
8727. 181466// function aa() {
8728. 181466// for (
8729. 181466// aa();
8730. 181466// aa;
8731. 181466// aa()
8732. 181466// ) {
8733. 181466// aa();
8734. 181466// }
8735. 181466// }
8736. 181466// ", "expected_at", "expected_a_at_b_c", "9", 1]
8737. 181466
8738. 181466 if (open) {
8739. 181466 at_margin(0);
8740. 181466 }
8741. 181466 } else if (
8742. 181466 left.arity === "ternary"
8743. 181466 || left.id === "case"
8744. 181466 || left.id === "catch"
8745. 181466 || left.id === "else"
8746. 181466 || left.id === "finally"
8747. 181466 || left.id === "while"
8748. 181466 || left.id === "await"
8749. 181466 || right.id === "catch"
8750. 181466 || right.id === "else"
8751. 181466 || right.id === "finally"
8752. 181466 || (right.id === "while" && !right.statement)
8753. 181466 || (left.id === ")" && right.id === "{")
8754. 181466 ) {
8755. 181466
8756. 181466// test_cause:
8757. 181466// ["
8758. 181466// function aa() {
8759. 181466// do {
8760. 181466// aa();
8761. 181466// } while(aa());
8762. 181466// }
8763. 181466// ", "one_space_only", "expected_space_a_b", "(", 12]
8764. 181466
8765. 181466 one_space_only();
8766. 181466 } else if (
8767. 181466
8768. 181466// There is a space between left and right.
8769. 181466
8770. 181466 spaceop[left.id] === true
8771. 181466 || spaceop[right.id] === true
8772. 181466 || (
8773. 181466 left.arity === "binary"
8774. 181466 && (left.id === "+" || left.id === "-")
8775. 181466 )
8776. 181466 || (
8777. 181466 right.arity === "binary"
8778. 181466 && (right.id === "+" || right.id === "-")
8779. 181466 )
8780. 181466 || left.id === "function"
8781. 181466 || left.id === ":"
8782. 181466 || (
8783. 181466 (
8784. 181466 left.identifier
8785. 181466 || left.id === "(string)"
8786. 181466 || left.id === "(number)"
8787. 181466 )
8788. 181466 && (
8789. 181466 right.identifier
8790. 181466 || right.id === "(string)"
8791. 181466 || right.id === "(number)"
8792. 181466 )
8793. 181466 )
8794. 181466 || (left.arity === "statement" && right.id !== ";")
8795. 181466 ) {
8796. 181466
8797. 181466// test_cause:
8798. 181466// ["let aa=0;", "one_space", "expected_space_a_b", "0", 8]
8799. 181466// ["let aa={\naa:\n0\n};", "expected_at", "expected_a_at_b_c", "5", 1]
8800. 181466
8801. 181466 one_space();
8802. 181466 } else if (left.arity === "unary" && left.id !== "`") {
8803. 181466 no_space_only();
8804. 181466 }
8805. 181466 }
8806. 181466 }
8807. 181466 nr_comments_skipped = 0;
8808. 181466 delete left.calls;
8809. 181466 delete left.dead;
8810. 181466 delete left.free;
8811. 181466 delete left.init;
8812. 181466 delete left.open;
8813. 181466 delete left.used;
8814. 181466 left = right;
8815. 181466 }
8816. 191641 });
8817. 174}
8818. 1
8819. 5function jslint_report({
8820. 5 exports,
8821. 5 froms,
8822. 5 functions,
8823. 5 global,
8824. 5 json,
8825. 5 module,
8826. 5 property,
8827. 5 stop,
8828. 5 warnings
8829. 5}) {
8830. 5
8831. 5// This function will create human-readable, html-report
8832. 5// for warnings, properties, and functions from jslint-result-object.
8833. 5// Example usage:
8834. 5// let result = jslint("console.log('hello world')");
8835. 5// let html = jslint_report(result);
8836. 5
8837. 5 let html = "";
8838. 5 let length_80 = 1111;
8839. 5
8840. 2190 function detail(title, list) {
8841. 2190 return (
8842. 2190 (Array.isArray(list) && list.length > 0)
8843. 751 ? (
8844. 751
8845. 751// Google Lighthouse Accessibility - <dl>'s do not contain only properly-ordered
8846. 751// <dt> and <dd> groups, <script>, <template> or <div> elements.
8847. 751
8848. 751 "<dl>"
8849. 751 + "<dt>" + htmlEscape(title) + "</dt>"
8850. 751 + "<dd>" + list.join(", ") + "</dd>"
8851. 751 + "</dl>"
8852. 751 )
8853. 1439 : ""
8854. 2190 );
8855. 2190 }
8856. 5
8857. 5 html += "<div class=\"JSLINT_\" id=\"JSLINT_REPORT_HTML\">\n";
8858. 5 html += String(`
8859. 5<style class="JSLINT_REPORT_STYLE">
8860. 5/* jslint utility2:true */
8861. 5/*csslint box-model: false, ids:false */
8862. 5/*csslint ignore:start*/
8863. 5@font-face {
8864. 5 font-display: swap;
8865. 5 font-family: "Daley";
8866. 5 src: url(
8867. 5"data:font/woff2;base64,d09GMgABAAAAABy4AA4AAAAAThwAABxiAAEAAAAAAAAAAAAA\
8868. 5AAAAAAAAAAAAAAAABmAAgiQINAmcDBEICuc41DEBNgIkA4R2C4I+AAQgBYkuByAMgScfYUIF\
8869. 57NgjsHGAbcDVFkXZ5Jwd+P96IGPc9rl9ETBEaCzCJkvY2UpziRZ7zftZWk8052U9+NqX6vXL\
8870. 5KDflSQnlJ0bP+QnPQAy744n9mup6H9PaCDFwM5zjf8exB89bZ1cdrYOP0NgnuRDRWlk9u/fE\
8871. 5llkxqmfH8lmRQ/DAmER9opk9wR6suc1LvTiXNEe1vbhUCH2USgnEwH3vUm05JQqejGvZvOtz\
8872. 57sIKEGgLdDNl/IrfqWVZG/wr42ekomEm91VA1p4LhHBuFzHF8//u7vvbREHMQqGtNLmiOOD/\
8873. 5X7WWiwqyCE98qt0jk5JJmgR5WJJElBmzRb1F7a66MmSLTNWZ2XSHfKBSKHoVteSEJ6EOdvVw\
8874. 5fNZOtXKDe39jXdRlkmMnOWIOFBgeEK/b0mFsgffnPyyAitNyutKky7J8a8MSEkAKGLgfptnS\
8875. 5/gDRSo7vwdNUmQDB7oP6pK7QF5d9SrY8M/tkrXcurSIQAmX7tz7pd33LIB7GQkBQ/k81s/0D\
8876. 5gpt4gbw7x0Cn/PocitK5KIGPGQIzQzAMuCeC2ERAidx9TySVqX06goT0SFFOOV9Kuxdi5Rg7\
8877. 5l6n3c+nKRemidOm2dtFV1jXMk4rP2m6RJ8xEdPYONLTbeMgaJ1nwS2W4su3MHwqkkvJ2PdDU\
8878. 5r7pgAnVRt4Kh789FXlD0r3p6jUtNO19O1s74U9pnIxqFpw+mBgF+8y30PAyw1dzlknLLVcSB\
8879. 5J2OuCr9eV5Efew6cOGd47ZEfhrW7HXI+FBNFvWgWnugUU4UvlrV63niv2ZPeKu8M76y/HQaG\
8880. 5weU+4Gzp+Y+cfb9R9djDWcd1Svr1xG7l+j/yf3eM996548qlC+dOzOqQ8//Lo0uaSEQCFuLD\
8881. 5/bXyWhJ6aPmyaRonVPxGABFL4/0slcKI6f+PmT0M+QRsplmWnv4F49VT+JsPifoa6aeyr2Hz\
8882. 5EeLdP1FEOV/ZN+c9sAuoNh0BRS0xgCCc9wME5s0HOKj/wc0fWYsTbFQpsZL5SayJPkL45kDo\
8883. 5DcJJ10MvD0ZSq7FEIr1TfqZ7NC6s75zSp8viaNO5/PczYCV9z6NTa0KBdnGBg6kbdeBkRLfU\
8884. 5qRd3D9Pqw5jWCc5WM/i95OE8731MBd1u2EmsXIa5dCvavY32U1Ytza4nfbERg6OVRZka7jq0\
8885. 5r2FcXNDyEhXheaHtaU1o1kvO9MuBOHqugLUEzN+4jznu0oK9wZPur1lWVFfxl8lZzn2XwcjZ\
8886. 5Csg/RJy0mAMMmgnqXS8ELhOCRUSLzvsM5gAPudEh2lVoRxGgyUVnArZMruE0YS1PqFMD3upb\
8887. 5jVoecGj1KpWl6/ZysuyzkG4SGA4bps6FBQSg4e4IxNUgdmosmoDn0TpIex/s1BFau6GBNO4z\
8888. 5cvWXypm4hEg5k3llelySFqNmUtRZ3PHBA7p4MBX1nK4awwAV6kWzIVbUA67A55QKYbMsgVaH\
8889. 5c1ZxKuZ0DCyqxCsJjLyCEY36gf0wjAu3t0zemc87PmBCJbU9Lso0YAaYJUx8wsR02hYz5hGy\
8890. 5Js0+A4uHGZgfuf5SOR9iBQuLhpOExaIFrHj6JlXanebzGHp2ELDh6av09PVE1fmdsj2oHRWs\
8891. 5fOtYrV6wRCyx7XogHqvpnZiPBBdNcL6kIoS9UI/DOIlumlveSgv9oqMBYp7WZ2fGxAXmZmaG\
8892. 5OCyJG6+wAszZFCQw/EXVjx+YA2uVyN6bhNWiZhgtYjAwR5U/7uV1scghiTGiAPZbA5ZqHw5u\
8893. 5Yu1cDjhRwREBFyq2wa0R8GgceDUKPo2BX+MhoAkQ1EQIaZqVHMwH3xM+P32TTA34tmOMNZ4n\
8894. 5mHXqn49fmE3qX1+wMNYoYetOsPx6wxKzkURImERJIjGSSJwkkiCJJEkiKZJImiSSIYlkSYqK\
8895. 5UBu0UOopuLMmasiJW0PMFOO2UgbDif2NaQUqkBbyaGjdTUvuyamEQwCq9DWsxsG9qPt+VFqV\
8896. 56cIsXcyWujWIEtNFdeia9ssNrJUpe3IDMPQZOReC8x+qvt17drPWdcHeL0gTarWwoQ6o828o\
8897. 50EJzrA20yZsgVyVHdlCJOF3NaACxHbP38TA+MGx3St9c5t2CxbGtunB4J9AF4Px2rSr1wyK9\
8898. 59KoXBR13vw9Fk9qhTX0ivZoanrvhLa5oiJO8cqR0lX7QtJ2c1a62V3PMtutaaoit+hxtXuC5\
8899. 5ZUXJePSR6btQlt5g7PqPQ822g7F8D123pc4kaGXz7qYztJxDXCxJr7foKqxwy4rikI/NvINx\
8900. 5bkArRTTnnMWy6YA8J39LfTweThKsqlt7Mz078NDSOPOGgtGTpeG8ZRBF+xKBjdSoNe8gE6uC\
8901. 5ucOH98jE4+cv1JEjI555TFjYj4+0KdFlojzJGWp2wc1tCaYGSeO8dBfT0u3lpDY3tazzu4wn\
8902. 5lF9wzy2nK+sTr/qEVdANoZ0ToBdD+MY4ewOHNnkXPBvKVXLSbEGfGVD0Nzr0Fs3HID3Y1Kqx\
8903. 5mzJ6p1C1/R6Xneyw/q9YRDLahbnsI1u76XzMLPqsK0yvQDeQ4TMR41709sIssmEgs0XH1lcj\
8904. 57HLnUG6u2Xpy5vbOowIGqrR6cwF0TLGI5PF7pkbzIVYQU0sIaoNgul3LGAH2B1nREFYXUMia\
8905. 5prCeAzggGxrC5gIK2dK0exs/AIRKdlIIuxkUspdSsU+rqXagqXaooXakqTiWS/a0E7zA6QIK\
8906. 5OdMUznMAh+RCQ7hcQCFXmspr3ciuds/6gPsZFPIgpfJhwUIepRAeZ1DIk5Tue4oKfSfKZyNV\
8907. 5pKU/J7J4Abx1EMV5mXSRDl6lMfU6jfBmBww4k7f6gLzTB+J9od/kA/uGj2mET2nkn7+zQ/JF\
8908. 5H5Kv+pB804fkOyvwI43wM438V5sdkd/6iPzRR+SvPiL/WIH/aYRxGqMb/Oqe3d54+LWR1vr2\
8909. 5knnnc467iD247eXBA3YYBAiFfierClXz/8jyL3Qh/zP8y+Y/1eN8jq+SKZAML/lIidjwZ8N4\
8910. 5aLthvhxGUkGPo+p0eHKZ0sT5FsqJcQCy9UhHIvcJFIlIvANTPFWUTUhSiVdsNRnvwEQxm5uc\
8911. 5ksjdv5evJfpOgI6c7juH8pnG2RKwlXaDYe9g8rMwYfML3A2SMWeBDopJJsmS5dUE2KttnmQa\
8912. 5JZlMspvEpJioiEDFNpPUTbwqG3Zjhx2VCeJrIf60s2mI6blZMZVyAyYzI+1a2Y0AIqcbLUgR\
8913. 56iRbNtnp82GrImXW0YbcbczDgqQDWNdTenvtTAlT9iPHenluV+d3eed1/5MjMBrX2LgrK2ml\
8914. 5FuoDOz036n/kaHbAeszR3jHoI4NWB3lusTfuVgkMUkLQaH0F6+pSCS11fXRwT421vs9s7axd\
8915. 5nvtF7/eeIeq9s1aCLsLWdh+w7sXz3IYdEsSQ0LVsebmES/vXDU9k653W4MiNq8bMj5nLioCY\
8916. 5edGgOT6tmYwqiOW1ugiEmew6iwjvvYb3SaeZJb7XNufOo9oH8FTneWGL+BLiclptpnhPwcui\
8917. 5T+rzcF34+ycsL7p3AveuML9i9h13beylyg8CzEz5HppadqmmDxKrAquG9L3ztedRoWxEsAYt\
8918. 5OM1Eu0G0gyTHkxf7cSkHJQRbA4xmlqHWkv1C0KhFhBq1z81Wq1CZoWic8TJ570WfSj5qsM+Q\
8919. 5nl4k3H5+P+P3zlv9ltQrzv41qyiSwV/gOadyQBchsmwDGu/JI8tXflE8jqUVA0Zw0SKbdDC9\
8920. 5c4FR+fak95SdF7uqpoRe9z6YRv+85YUzF4qJy6Q8GOVNwUn/ymyjNNbmcuVfXYeH2osLdCte\
8921. 5ebmZRyUfQQZA1BSCLK4PWA/z1kBvDZm0t+i3or1LkMD6en95pGG0UOa8ZJXgS9TdEA1I2mZw\
8922. 51JOWWxDu0NEh4rM19H55rvueMBUZV1RjkmB3oxkXhAckpa5gzzxUDA2VLOrWFAXx+4gmfU17\
8923. 55o3v9H7EYdvGFuM+tDB3TA4ITjVUKduO/R4bXRAcPXZusWkN+t59sFz7Hyi0FkSdzrHXQVFq\
8924. 5b8c9k9eLRjVlBbNvt4172CanYg/F3Rket1zCTc77UZ61Gq/Be9J8hrKrxbDZMEotf5o8zHDc\
8925. 5/UJaEtdhgwHEcBEQKM+6NBWIewLmI1sHuWYAedZCw8U1hJfSWcld+2tv3jpCFc5FnosLWC0+\
8926. 5DnAlnOXUXLoMXrmCVerNQkZHvRm8YtE12vG8+N/vOnPcu3vM1uOnzE3u3VP2ppmLZawm2NuO\
8927. 5tPa7xwHFCgVKpox5PVrOmaDHrThk1tX864a2+/qhJd3nCFRQ+bfUKI4O+Wgk5byB3saMcUfV\
8928. 5C8G137yMd16zRm3ZSq+UrDlk5ha3TiAj0b74prWO/vYG+RC+ronP1/McDtefBtY1XhZE0PIB\
8929. 5wTe7CBTte2U6KPbYd5GffApQlDGssdfmxYGSlnHrQt7++KEwUg3ikkoQyKPixgUDB6Lozjv5\
8930. 5vM5PBnllt+UzMnP6DStFsOfossbXOefWhQApACCNpkTYGAONIowDfndqDKRFuzn685nthZPe\
8931. 5vEL7TIWkXAG2yxKBH90+yMzuRzWn3KMmyKGwZWnIErlJ9Vwt8OtR6+4TKad5y9+ViBtTzVG+\
8932. 5tpv/xiLrcGKJRtYvCUlGeL4Dwy1jo1CSQe0X71EXK1YG44ztxTONjIslL8SwY0Cki0k0vsX/\
8933. 5/xz7CxkAc9dEdJZhMy/JCGzD2FAGtUcag0tc2e2miJkp477V2qTKB+nFnDl/noxpXJ+yqVdO\
8934. 5wNjbplmeiuburg9ii1Z1zwtG8QjcJAiVPSOV2mHzq1Qt7p2+YCcIKPmFusE5O+m8s+Wd8o3t\
8935. 5qO1b1IZF8N0tx6RQnZ9Ux3gXijHlolixst6vhJV6ao0ZFzSprfAc3x0MLvxU0OsmXEVddMVK\
8936. 529CC6mPgPtXTUW7tVnZxwm0DTJwNOeVRV4axMSPlpgyv1Va1MQhQqWwUOb0s+gVLOecos4Nf\
8937. 5eqlFW3fLQrlP86R4XRxrDHF0VIx6ArM5/sTWtObY6U2aosgxbN6FUa1iNTUpMThk1sUfJOC6\
8938. 5s1SKo9D0g1NfiVmavyful/K7nZdDgutV1A26i7FR3r16bv3zz1cGw+ta17IX/+ripyutix3C\
8939. 5xNmCxs7uiqKu9/Zjjn06tblXpJxlaLF5Od0d5W9QhQrs2u6UN0trQlCyEK2j9VYgCEIDrhQN\
8940. 5c00rxg/FOfZ1N+nLV7RXDsYP+p0EzqKcuPujzuzEQsu2mFf4nYvf3Yp32rq/RYLetDLuOOTc\
8941. 50WXBtgoech7AHUxAxPBg81qWCsYlzTofRU5/MpuyNoegR6mCJO5ckrLOhWbG7xo/VGwGgpRb\
8942. 5+Ch+TmlcuY6Qct/2x3gxzeDUU9u+ltexrjelJ0VRR9KXH/AqrbYxHa0vmQ/kBnE5EORBK1ZH\
8943. 5mTSy7A8DJMgzzqDsu9ML5J3ufkuUNDCfN5UKAjBgw2I/QlS8MQ6o/ll9dTAdoM7HYtV4cNWE\
8944. 5U4pOl5Y4SIzdMbNSjXFmsBV1uXXf7GaBZZslpFGFiIpokSzxWj4hjlGl4VKJDACo7ScxQf29\
8945. 5kM8gHD3nUJkwkN2aW2TGttqwOrygJ7r9nYX2tYqy7Z3TQV5ocWzUI8l871y3LsQLoTgEO76B\
8946. 5Upp69hy6VKRpZvpvgfQ2T06qgXjxh38eatREitX6bzKggIYmN4sAkA3a5oeJZDK3ahQrVJwa\
8947. 5AD65cEGBkS/tKH9TtybiREEWCMcKD0HH0gELtjB+KNSk7bspmpr6eb0CscIiFyZpmXu8+gxw\
8948. 5O7pJNbAK2h9q2c5dMHBaoi5DylbNGdweVVdN3Jm9u6YXXlmx4nYY2vIPfSkrE/vyv9gn/Z+j\
8949. 5R3HKExaUhdV0Az77YWbQPhNfjw+F0vTteSMin+wIfxyPe0DEoI4uz6o2IXwsZC7sg8MicQ3o\
8950. 5wys+NJYKVW72YiVQ5LKDVwrEg2jNVM6XdNjbsHlRDcAkD08o5iWtFB2dVoydRmmDRLalE+4t\
8951. 53gBbAPa7n7qXXXbTZTJXZKy5+1W0K7dgYEcIlu90ovC0C+5gxXiKtZisT14qDJ7f2ksyK59U\
8952. 5r3QeHtBb24mPz7YDB3rgMTyUZ/fxM8h2i1Z21B8/VA5+9l7BKaOJZ15lWsyPv/z6CjU32ZKq\
8953. 5+QFeyUywxYnUxUmcQfGc1Sp69oE2n6zFL8BXf5rc3cJMM6S97gagTT1bi7cmAV4MibkC4rz/\
8954. 5icmmFtMlo5aN1Wp3uxsBfd4+9T42xmxvd79FV/hfuviBcrIaX092PrY5rle9FR4wTnDzrwj4\
8955. 57frD2d0KsMcdcADQ1Yu1LECg9Wj3yOS8OhrJdQBqXqsam17vmt2wjjjouHE/EO9sGPdqt23v\
8956. 5j8rL6wid6ulagtNK5p1hjRkFtUxTIaZnIXk63Zb3P0t5MQ+3vxHIFrmgAdWwiDuA67tbVIF6\
8957. 5wJ53z0uhyhsfH9bgF0kPT9v2hrT3HKIBgUXIYoxsVU+uryemiUiQEwh+BfxP//qLShlumR26\
8958. 5I8OqjD+x3hHDj/IrEWmvyL6ioG/atfxe+5GzIqRgfaoayWOiTk+YixO15KDO6Os3XACDjboe\
8959. 5ryXXOuEmTpDsc7czk+H04Kw1PNJazW32CAURHwBldqK0/nqYHtcrtLyyTYmoD8hbcnJUfa3U\
8960. 53FxWNus7uic3Qm1BzEecJW0MAz+W2CyN9FLIy+EpSy6CjkXsllZw1uBs1SxrQWM97/vnHu7m\
8961. 5OtrkRl8AtBN3RDxI/fg7dZLLtDFYuCYYPMwXiO6ZIpwJ1GGydI9oUYYgnQQKDKoMTcwsjrfe\
8962. 5Tcht6y18bLcpNfX41WE27447vLNzHuF+j15co5N7Py8vKUpTCoghHMEYKkM6y02lvX+9XiFg\
8963. 5xBKMRNiwX69+LJb2Xa5WGqo7Rlk0cxsLVd0l2UXAW5jORg31sFMKYWXsDcRUKRDP8Q87OjiM\
8964. 5dI1hNEt43netf8rOyfp+L58fq3holY9gxXwRJLY6gahgLQi4hS8w9LS+rFcJtdSCBrQLWsMs\
8965. 5aDg/n8/P8/N+fcyoLepYr3W/CIUT7HsRQTtkduddbVfbo6Twt6fyJVPRrUGqRkWp3rdry65v\
8966. 5sPYInyq1mPHrQDrqGJYI/LzA/QAzAXLnx+lu9uxHTEka9xgWgRvqEioskh+UWgD4nDvTAxaz\
8967. 53v9BqqmFuQwy1wSXye1Df1NXVF7G8bUFxUE4F9axG5fm+vFQJvP8iuYjrFveB6++AqmJTQJ0\
8968. 59GHjbPhzdSzkZGxokQzONVs0R0FCPJz1hJKbvDKsaj9hT0vp/gH5oiT8pAbWsBChwAbxHgDd\
8969. 559iJVZE3bAzPRN1RuG+MT7th+J3i6KFwVJvPvsGRDIZW4P2rVfiKjDVBM2Va+w6PgI0c5u3K\
8970. 5O7MrWryPhXFFdBoAwi2JCaW9sZ3fTagQ4Tld6u4djwcWzeCdiYoeNbfalsRYo740afYQ1Rid\
8971. 5Bp/E9mbcTemEjoWWXIU7I5nK5H/BEqmZnPMyhDV234BTLQKCe6nhU+frwQo1gNFWf+eQGN62\
8972. 5aeF7BuzaN/94W2xlKd8t8KMA/3uoxymFt19OlCjYZeaMWbTKM9Yog9zDhptYMOzIQAoO7kn6\
8973. 5nTao8CxjrRRgjKe7mKa+tzuufhAAZtgjA92THkulWvIzEi0++j1DvXMnupDUS8aVusWain+c\
8974. 5CcvmR5orC+RcJs3wVahLYyEcqbvAS2e0QJ6BlU36R/IEd9Aol9q+M+UGvlo8EyRzISvqusNS\
8975. 57ePQ6cQzG1s725db4jNYNHAfF3KFG8wHqDwZDpWDsJ5qRLXR1ulFx85GhkypPubYaCiOQ5DR\
8976. 5PQUiNpgk4fLJHenSMLMiswXsqW4Cpln1rFoHzpOoBbuZIixmVyhKajeqlFmp8zNAEsbEJz0g\
8977. 5X0qlQuykZhf82pkhq2hWtCtYUdBODn6iPTBJT5Zk8IqFxqfBeFKjXk/sMeumhT8muOtq2Bgn\
8978. 5dR4fj6RoOi0zI25kajAXlDZhUhS39jipk39h/69AfDPBLmOxhDj7Lg/WUTbOwJiJ3p7WtOpm\
8979. 5ypARmhorQifINNm1CNS99GfDcLbD8sn8Fvlmvn7CmW65Pdmu6bKtuE0tn7NglIX1e/JAJP+G\
8980. 5gB3At7cSOp92rl0lp0pp0xVb5YaQedwGgcJA1pT4cy24lS+jvzDw86YTfb2igJm5MysHmejW\
8981. 5ZTGXpoAoLBLucUGEz/DwbjqOdzGAl5jy5VoCQws5zNYl4SVt030aZulYMgpDBPZd+kL0wV+w\
8982. 5nob2LPRDQGEbdUoeFm4fEKio9c/ferVlpSO8Bx7OFZyHip1PIizvoqFe02kpmS17TvIOty42\
8983. 5+Q0QaCnOpeLsPwwo+vixIeIeUjucUsKejVlez35qyuC0mm5pJJJLEVP2JAe/LTOwUUfKJkNy\
8984. 5lEe3Kdth241ZNQmkVcAIh6DZJBzvQov5fn3JZA0phBWdNq5iTsm5N2D8gyve3V3X2o3zF3VY\
8985. 5OqEBgTIADAbC69z7vOKJjGOzHRmUUwLU66iabtIbqR6SPOHCL+fCTfvpKcB/oG2p3wRKErEJ\
8986. 5v1YOfu9iaKEMLXS3ptdH8fwN2Rdww9bZ7rFa2bwrzcyux3o+hPV6bJZpb71j7lLAdzge3VX7\
8987. 59uSCdz6f/FDb7+wzWnbbDSPj9R20+PybDUm/lVAsTuF0aycFQwJfPCUwcBvCGWEq6xoTIEOy\
8988. 5b0bLta20+LYRYdyEceX7ypfezQKIy5OvJTAHCJy/WyOYaDVyPucMsHnZ0GCH75Cd//te1Bv2\
8989. 5RkMykqYurBiNbuH3Xfuprirr4Dd453O6abAYGb5tw1d6wrBL8p1J1Sx9Lgw7yxqYn0FTrc0y\
8990. 559yLlV+4zIkLfZlPFRVnanHpTyrIlpn4lGkt269+JXnIWhEQWNvuVsrt531jr+8AHkVZfQU8\
8991. 58U/4AUZMuOj5iliigFrof/usmloYEI1f8erhJku75snYW7YmFmUcoC7UtG/KfJRuz6j0tWPa\
8992. 556J5QA0rJHwSIhNT4GWvez19HT2lia+Pz7/+MVEWlvjY6+9P85a0y9qWkTzQ7nF0wDXpQpw3\
8993. 5K4xnfK2L08b5MrxdeI+DDfVDeV2JY0Fp6KH602tj2MbxxKM8oG+wTkE/dr8jyo4Sfs/IV6uf\
8994. 5+IIXpH2Nca1+WCJV5qEv193bcUELLR4iFu83xUedKy9353tn+3o01dF2bNEQ3fK9Q5tCXrCi\
8995. 5La+woCuvEeYrr+PiN2+i2V/eDJck580pyra8BV5ZIZbpe3kr5vJD3pqoGsnbcl/d+ndvR23b\
8996. 5K41M4dKwaAwDaMA1gZGBoQWAcYE9mYkmQOnAjkaG41FkGkIP2BAIgKvUvzhpE5JbA6lze2iL\
8997. 55Nr+AwiDo2W4BStvK30dKy0JGNbzAY5akexsrV0xo5K8rY50LOTLvDyukIZNbRLKOCk18mD3\
8998. 5WxmZGlsCMxNdGFYGNJnetUWyCPgo4BONEL4I9b8UeEBGYXuCdCd+DkctrqVLYXGSfE46kvAu\
8999. 5+ltK5SRxQPnjUqyJXsSYs6VY6WPKfns9+IXjHhd5wQvGipgFdMwVEQ+A7a2AAS0clQwH7KHW\
9000. 5SEGjhnklSVRghMtPy6gEtJRIKJeYkpQyQiequQunFOOU4BLdK1yp55olZS6npyPhMnvK7xIa\
9001. 5pyNj+JctcQLXenBOCms46aMkenIx45WpXqxxVJQLz/vgpmAVa0fmDv6Pue9xVTBPfVxCUGfj\
9002. 51R8uVi8Zu9nRFqk/t0gR6wmWOlzuKRqk33HpO8qQ+nbGoEZLL/0Va156SJ+u+t86/os7ic49\
9003. 5/7xoEqvL+2E8VOyCTuT/7j269Zy4jUtN+g4="
9004. 5 ) format("woff2");
9005. 5}
9006. 5*,
9007. 5*:after,
9008. 5*:before {
9009. 5 border: 0;
9010. 5 box-sizing: border-box;
9011. 5 margin: 0;
9012. 5 padding: 0;
9013. 5}
9014. 5.JSLINT_ {
9015. 5 -ms-text-size-adjust: none;
9016. 5 -webkit-text-size-adjust: none;
9017. 5 text-size-adjust: none;
9018. 5}
9019. 5/*csslint ignore:end*/
9020. 5
9021. 5.JSLINT_ {
9022. 5 font-family: daley, sans-serif;
9023. 5 font-size: 14px;
9024. 5}
9025. 5.JSLINT_ fieldset legend,
9026. 5.JSLINT_ .center {
9027. 5 font-family: daley, sans-serif;
9028. 5 font-size: 14px;
9029. 5 text-align: center;
9030. 5}
9031. 5.JSLINT_ fieldset textarea,
9032. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS dt,
9033. 5.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
9034. 5 font-size: 12px;
9035. 5}
9036. 5.JSLINT_ fieldset textarea,
9037. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS > div {
9038. 5 font-family: monospace;
9039. 5}
9040. 5.JSLINT_ fieldset > div {
9041. 5 font-family: sans-serif;
9042. 5}
9043. 5
9044. 5body {
9045. 5 background: antiquewhite;
9046. 5}
9047. 5.JSLINT_ fieldset {
9048. 5 background: gainsboro;
9049. 5 clear: both;
9050. 5 margin: 16px 40px;
9051. 5 width: auto;
9052. 5}
9053. 5.JSLINT_ fieldset address {
9054. 5 float: right;
9055. 5}
9056. 5.JSLINT_ fieldset legend {
9057. 5 background: darkslategray;
9058. 5 color: white;
9059. 5 padding: 4px 0;
9060. 5 width: 100%;
9061. 5}
9062. 5.JSLINT_ fieldset textarea {
9063. 5 padding: 4px;
9064. 5 resize: none;
9065. 5 white-space: pre;
9066. 5 width: 100%;
9067. 5}
9068. 5.JSLINT_ fieldset textarea::selection {
9069. 5 background: wheat;
9070. 5}
9071. 5.JSLINT_ fieldset > div {
9072. 5 padding: 16px;
9073. 5 width: 100%;
9074. 5 word-wrap: break-word;
9075. 5}
9076. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level {
9077. 5 background: cornsilk;
9078. 5 padding: 8px 16px;
9079. 5}
9080. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dd {
9081. 5 line-height: 20px;
9082. 5 padding-left: 120px;
9083. 5}
9084. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dfn {
9085. 5 display: block;
9086. 5 font-style: normal;
9087. 5 font-weight: bold;
9088. 5 line-height: 20px;
9089. 5}
9090. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dl {
9091. 5 position: relative
9092. 5}
9093. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level dt {
9094. 5 font-style: italic;
9095. 5 line-height: 20px;
9096. 5 position: absolute;
9097. 5 text-align: right;
9098. 5 width: 100px;
9099. 5}
9100. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level0 {
9101. 5 background: white;
9102. 5}
9103. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level1 {
9104. 5 /* yellow */
9105. 5 background: #ffffe0;
9106. 5 margin-left: 16px;
9107. 5}
9108. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level2 {
9109. 5 /* green */
9110. 5 background: #e0ffe0;
9111. 5 margin-left: 32px;
9112. 5}
9113. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level3 {
9114. 5 /* blue */
9115. 5 background: #D0D0ff;
9116. 5 margin-left: 48px;
9117. 5}
9118. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level4 {
9119. 5 /* purple */
9120. 5 background: #ffe0ff;
9121. 5 margin-left: 64px;
9122. 5}
9123. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level5 {
9124. 5 /* red */
9125. 5 background: #ffe0e0;
9126. 5 margin-left: 80px;
9127. 5}
9128. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level6 {
9129. 5 /* orange */
9130. 5 background: #ffe390;
9131. 5 margin-left: 96px;
9132. 5}
9133. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level7 {
9134. 5 /* gray */
9135. 5 background: #e0e0e0;
9136. 5 margin-left: 112px;
9137. 5}
9138. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level8 {
9139. 5 margin-left: 128px;
9140. 5}
9141. 5.JSLINT_ #JSLINT_REPORT_FUNCTIONS .level9 {
9142. 5 margin-left: 144px;
9143. 5}
9144. 5.JSLINT_ #JSLINT_REPORT_PROPERTIES {
9145. 5 background: transparent;
9146. 5}
9147. 5.JSLINT_ #JSLINT_REPORT_PROPERTIES textarea {
9148. 5 background: honeydew;
9149. 5 height: 100px;
9150. 5}
9151. 5.JSLINT_ #JSLINT_REPORT_TITLE {
9152. 5 color: darkslategray;
9153. 5 font-size: 32px;
9154. 5 padding-top: 16px;
9155. 5 text-align: center;
9156. 5}
9157. 5.JSLINT_ #JSLINT_REPORT_WARNINGS cite {
9158. 5 display: block;
9159. 5 margin: 16px 0 4px 0;
9160. 5 overflow-x: hidden;
9161. 5 white-space: pre-line;
9162. 5}
9163. 5.JSLINT_ #JSLINT_REPORT_WARNINGS cite:nth-child(1) {
9164. 5 margin-top: 0;
9165. 5}
9166. 5.JSLINT_ #JSLINT_REPORT_WARNINGS samp {
9167. 5 background: lavenderblush;
9168. 5 display: block;
9169. 5 padding: 4px;
9170. 5 white-space: pre-wrap;
9171. 5}
9172. 5.JSLINT_ #JSLINT_REPORT_WARNINGS > div {
9173. 5 background: pink;
9174. 5 max-height: 400px;
9175. 5 overflow-y: auto;
9176. 5}
9177. 5.JSLINT_ #JSLINT_REPORT_WARNINGS > legend {
9178. 5/* Google Lighthouse Accessibility - Background and foreground colors do not */
9179. 5/* have a sufficient contrast ratio. */
9180. 5 /* background: indianred; */
9181. 5 background: #b44;
9182. 5}
9183. 5</style>
9184. 5 `).trim() + "\n";
9185. 5
9186. 5// Produce the Title.
9187. 5
9188. 5 html += "<div id=\"JSLINT_REPORT_TITLE\">\n";
9189. 5 html += "JSLint Report\n";
9190. 5 html += "</div>\n";
9191. 5
9192. 5// Produce the HTML Error Report.
9193. 5// <cite>
9194. 5// <address>LINE_NUMBER</address>
9195. 5// MESSAGE
9196. 5// </cite>
9197. 5// <samp>EVIDENCE</samp>
9198. 5
9199. 5 html += "<fieldset id=\"JSLINT_REPORT_WARNINGS\">\n";
9200. 5 html += "<legend>Report: Warnings (" + warnings.length + ")</legend>\n";
9201. 5 html += "<div>\n";
9202. 1 if (stop) {
9203. 1 html += "<div class=\"center\">JSLint was unable to finish.</div>\n";
9204. 1 }
9205. 7 warnings.forEach(function ({
9206. 7 column,
9207. 7 line,
9208. 7 line_source,
9209. 7 message,
9210. 7 stack_trace = ""
9211. 7 }, ii) {
9212. 7 html += (
9213. 7 "<cite>"
9214. 7 + "<address>" + htmlEscape(line + ": " + column) + "</address>"
9215. 7 + htmlEscape((ii + 1) + ". " + message)
9216. 7 + "</cite>"
9217. 7 + "<samp>"
9218. 7 + htmlEscape(line_source.slice(0, 400) + "\n" + stack_trace)
9219. 7 + "</samp>\n"
9220. 7 );
9221. 7 });
9222. 2 if (warnings.length === 0) {
9223. 2 html += "<div class=\"center\">There are no warnings.</div>\n";
9224. 2 }
9225. 5 html += "</div>\n";
9226. 5 html += "</fieldset>\n";
9227. 5
9228. 5// Produce the /*property*/ directive.
9229. 5
9230. 5 html += "<fieldset id=\"JSLINT_REPORT_PROPERTIES\">\n";
9231. 5 html += (
9232. 5 "<legend>Report: Properties ("
9233. 5 + Object.keys(property).length
9234. 5 + ")</legend>\n"
9235. 5 );
9236. 5 html += "<label>\n";
9237. 5 html += "<textarea readonly>";
9238. 5 html += "/*property";
9239. 295 Object.keys(property).sort().forEach(function (key, ii) {
9240. 294 if (ii !== 0) {
9241. 294 html += ",";
9242. 294 length_80 += 2;
9243. 294 }
9244. 41 if (length_80 + key.length >= 80) {
9245. 41 length_80 = 4;
9246. 41 html += "\n ";
9247. 41 }
9248. 295 html += " " + key;
9249. 295 length_80 += key.length;
9250. 295 });
9251. 5 html += "\n*/\n";
9252. 5 html += "</textarea>\n";
9253. 5 html += "</label>\n";
9254. 5 html += "</fieldset>\n";
9255. 5
9256. 5// Produce the HTML Function Report.
9257. 5// <div class=LEVEL>
9258. 5// <address>LINE_NUMBER</address>
9259. 5// <dfn>FUNCTION_NAME_AND_SIGNATURE</dfn>
9260. 5// <dl>
9261. 5// <dt>DETAIL</dt>
9262. 5// <dd>NAMES</dd>
9263. 5// </dl>
9264. 5// </div>
9265. 5
9266. 5 html += "<fieldset id=\"JSLINT_REPORT_FUNCTIONS\">\n";
9267. 5 html += "<legend>Report: Functions (" + functions.length + ")</legend>\n";
9268. 5 html += "<div>\n";
9269. 2 if (json) {
9270. 2
9271. 2// Bugfix - fix website crashing when linting pure json-object.
9272. 2// return (
9273. 2
9274. 2 html += (
9275. 2 warnings.length === 0
9276. 2 ? "<div class=\"center\">JSON: good.</div>\n"
9277. 2 : "<div class=\"center\">JSON: bad.</div>\n"
9278. 2 );
9279. 3 } else if (functions.length === 0) {
9280. 3 html += "<div class=\"center\">There are no functions.</div>\n";
9281. 3 }
9282. 5 exports = Object.keys(exports).sort();
9283. 5 froms.sort();
9284. 5 global = Object.keys(global.context).sort();
9285. 5 module = (
9286. 5 module
9287. 1 ? "module"
9288. 4 : "global"
9289. 5 );
9290. 2 if (global.length + froms.length + exports.length > 0) {
9291. 2 html += "<div class=\"level level0\">\n";
9292. 2 html += detail(module, global);
9293. 2 html += detail("import from", froms);
9294. 2 html += detail("export", exports);
9295. 2 html += "</div>\n";
9296. 2 }
9297. 312 functions.forEach(function (the_function) {
9298. 312 let {
9299. 312 context,
9300. 312 level,
9301. 312 line,
9302. 312 name,
9303. 312
9304. 312// Bugfix - fix html-report from crashing if parameters is undefined.
9305. 312
9306. 312 parameters = [],
9307. 312 signature
9308. 312 } = the_function;
9309. 312 let list = Object.keys(context);
9310. 312 let params;
9311. 312 html += (
9312. 312 "<div class=\"level level" + htmlEscape(level) + "\">"
9313. 312 + "<address>" + htmlEscape(line) + "</address>"
9314. 312 + "<dfn>"
9315. 312 + (
9316. 312 name === "=>"
9317. 1 ? htmlEscape(signature) + " =>"
9318. 311 : (
9319. 311 typeof name === "string"
9320. 311 ? "\u00ab" + htmlEscape(name) + "\u00bb"
9321. 311 : htmlEscape(name.id)
9322. 311 )
9323. 312 ) + htmlEscape(signature)
9324. 312 + "</dfn>"
9325. 312 );
9326. 312 params = [];
9327. 447 parameters.forEach(function extract({
9328. 447 id,
9329. 447 names
9330. 447 }) {
9331. 447 switch (id) {
9332. 5 case "[":
9333. 39 case "{":
9334. 39
9335. 39// Recurse extract().
9336. 39
9337. 39 names.forEach(extract);
9338. 39 break;
9339. 3 case "ignore":
9340. 3 break;
9341. 405 default:
9342. 405 params.push(id);
9343. 447 }
9344. 447 });
9345. 312 html += detail("parameter", params.sort());
9346. 312 list.sort();
9347. 2114 html += detail("variable", list.filter(function (id) {
9348. 2114 return (
9349. 2114 context[id].role === "variable"
9350. 1630 && context[id].parent === the_function
9351. 2114 );
9352. 2114 }));
9353. 2114 html += detail("exception", list.filter(function (id) {
9354. 2114 return context[id].role === "exception";
9355. 2114 }));
9356. 2114 html += detail("closure", list.filter(function (id) {
9357. 2114 return (
9358. 2114 context[id].closure === true
9359. 1414 && context[id].parent === the_function
9360. 2114 );
9361. 2114 }));
9362. 2114 html += detail("outer", list.filter(function (id) {
9363. 2114 return (
9364. 2114 context[id].parent !== the_function
9365. 1131 && context[id].parent.id !== "(global)"
9366. 2114 );
9367. 2114 }));
9368. 2114 html += detail(module, list.filter(function (id) {
9369. 2114 return context[id].parent.id === "(global)";
9370. 2114 }));
9371. 2114 html += detail("label", list.filter(function (id) {
9372. 2114 return context[id].role === "label";
9373. 2114 }));
9374. 312 html += "</div>\n";
9375. 312 });
9376. 5 html += "</div>\n";
9377. 5 html += "</fieldset>\n";
9378. 5 html += "</div>\n";
9379. 5 return html;
9380. 5}
9381. 1
9382. 3async function jstestDescribe(description, testFunction) {
9383. 3
9384. 3// This function will create-and-run test-group <testFunction>
9385. 3// with given <description>.
9386. 3
9387. 3 let message;
9388. 3 let result;
9389. 3
9390. 3// Init jstestTimeStart.
9391. 3
9392. 1 if (jstestTimeStart === undefined) {
9393. 1 jstestTimeStart = jstestTimeStart || Date.now();
9394. 1 process.on("exit", jstestOnExit);
9395. 1 }
9396. 3
9397. 3// Init jstestItList.
9398. 3
9399. 3 jstestItList = [];
9400. 3 testFunction();
9401. 3
9402. 3// Wait for jstestItList to resolve.
9403. 3
9404. 3 result = await Promise.all(jstestItList);
9405. 3
9406. 3// Print test results.
9407. 3
9408. 3 message = (
9409. 3 "\n " + (Date.now() - jstestTimeStart) + "ms"
9410. 3 + " - test describe - " + description + "\n"
9411. 19 + result.map(function ([
9412. 19 err, description, mode
9413. 19 ]) {
9414. 19 jstestItCount += 1;
9415. 1 if (err) {
9416. 1 jstestCountFailed += 1;
9417. 1 err = (
9418. 1 " \u001b[31m\u2718 " + jstestItCount + ". test it - "
9419. 1 + description + "\n" + err.stack + "\u001b[39m"
9420. 1 );
9421. 1 if (mode === "pass") {
9422. 1 jstestCountFailed -= 1;
9423. 1 err = "";
9424. 1 }
9425. 1 }
9426. 19 return err || (
9427. 19 " \u001b[32m\u2714 " + jstestItCount + ". test it - "
9428. 19 + description + "\u001b[39m"
9429. 19 );
9430. 19 }).join("\n")
9431. 3 );
9432. 3 console.error(message);
9433. 3}
9434. 1
9435. 19function jstestIt(description, testFunction, mode) {
9436. 19
9437. 19// This function will create-and-run test-case <testFunction>
9438. 19// inside current test-group with given <description>.
9439. 19
9440. 19 jstestCountTotal += 1;
9441. 19 jstestItList.push(new Promise(async function (resolve) {
9442. 19 let err;
9443. 19 try {
9444. 18 await testFunction();
9445. 18 } catch (errCaught) {
9446. 1 err = errCaught;
9447. 1 }
9448. 19 resolve([
9449. 19 err, description, mode
9450. 19 ]);
9451. 19 }));
9452. 19}
9453. 1
9454. 2function jstestOnExit(exitCode, processExit, countFailed) {
9455. 2
9456. 2// This function will on process-exit, print test-report
9457. 2// and exit with non-zero exit-code if any test failed.
9458. 2
9459. 2 let message = (
9460. 2 (
9461. 2 (jstestCountFailed || countFailed)
9462. 1 ? "\n\u001b[31m"
9463. 1 : "\n\u001b[32m"
9464. 2 )
9465. 2 + " tests total - " + jstestCountTotal + "\n"
9466. 2 + " tests failed - " + jstestCountFailed + "\n"
9467. 2 + "\u001b[39m"
9468. 2 );
9469. 1 if (!processExit) {
9470. 1 console.error(message);
9471. 1 processExit = process.exit;
9472. 1 }
9473. 2 processExit(exitCode || jstestCountFailed);
9474. 2 return message;
9475. 2}
9476. 1
9477. 77async function moduleFsInit() {
9478. 77
9479. 77// This function will import nodejs builtin-modules if they have not yet been
9480. 77// imported.
9481. 77
9482. 77// State 3 - Modules already imported.
9483. 77
9484. 73 if (moduleFs !== undefined) {
9485. 73 return;
9486. 73 }
9487. 4
9488. 4// State 2 - Wait while modules are importing.
9489. 4
9490. 4 if (moduleFsInitResolveList !== undefined) {
9491. 3 return new Promise(function (resolve) {
9492. 3 moduleFsInitResolveList.push(resolve);
9493. 3 });
9494. 3 }
9495. 1
9496. 1// State 1 - Start importing modules.
9497. 1
9498. 1 moduleFsInitResolveList = [];
9499. 1 [
9500. 1 moduleChildProcess,
9501. 1 moduleFs,
9502. 1 modulePath,
9503. 1 moduleUrl
9504. 1 ] = await Promise.all([
9505. 1 import("child_process"),
9506. 1 import("fs"),
9507. 1 import("path"),
9508. 1 import("url")
9509. 1 ]);
9510. 3 while (moduleFsInitResolveList.length > 0) {
9511. 3 moduleFsInitResolveList.shift()();
9512. 3 }
9513. 77}
9514. 1
9515. 2480function noop(val) {
9516. 2480
9517. 2480// This function will do nothing except return <val>.
9518. 2480
9519. 2480 return val;
9520. 2480}
9521. 1
9522. 10077function objectDeepCopyWithKeysSorted(obj) {
9523. 10077
9524. 10077// This function will recursively deep-copy <obj> with keys sorted.
9525. 10077
9526. 10077 let sorted;
9527. 6357 if (typeof obj !== "object" || !obj) {
9528. 6357 return obj;
9529. 6357 }
9530. 3720
9531. 3720// recursively deep-copy list with child-keys sorted
9532. 3720
9533. 3720 if (Array.isArray(obj)) {
9534. 1126 return obj.map(objectDeepCopyWithKeysSorted);
9535. 2594 }
9536. 2594
9537. 2594// recursively deep-copy obj with keys sorted
9538. 2594
9539. 2594 sorted = {};
9540. 7481 Object.keys(obj).sort().forEach(function (key) {
9541. 7481 sorted[key] = objectDeepCopyWithKeysSorted(obj[key]);
9542. 7481 });
9543. 2594 return sorted;
9544. 2594}
9545. 1
9546. 2573function object_assign_from_list(dict, list, val) {
9547. 2573
9548. 2573// Assign each property-name from <list> to <dict>.
9549. 2573
9550. 82087 list.forEach(function (key) {
9551. 82087 dict[key] = val;
9552. 82087 });
9553. 2573 return dict;
9554. 2573}
9555. 1
9556. 96function v8CoverageListMerge(processCovs) {
9557. 96
9558. 96// This function is derived from MIT Licensed v8-coverage at
9559. 96// https://github.com/demurgos/v8-coverage/tree/master/ts
9560. 96// https://github.com/demurgos/v8-coverage/blob/master/ts/LICENSE.md
9561. 96//
9562. 96// Merges a list of v8 process coverages.
9563. 96// The result is normalized.
9564. 96// The input values may be mutated, it is not safe to use them after passing
9565. 96// them to this function.
9566. 96// The computation is synchronous.
9567. 96// @param processCovs Process coverages to merge.
9568. 96// @return Merged process coverage.
9569. 96
9570. 96 let resultMerged = []; // List of merged scripts from processCovs.
9571. 96 let urlToScriptDict = new Map(); // Map scriptCov.url to scriptCovs.
9572. 96
9573. 1090 function compareRangeList(aa, bb) {
9574. 1090
9575. 1090// Compares two range coverages.
9576. 1090// The ranges are first ordered by ascending `startOffset` and then by
9577. 1090// descending `endOffset`.
9578. 1090// This corresponds to a pre-order tree traversal.
9579. 1090
9580. 1061 if (aa.startOffset !== bb.startOffset) {
9581. 1061 return aa.startOffset - bb.startOffset;
9582. 1061 }
9583. 29 return bb.endOffset - aa.endOffset;
9584. 29 }
9585. 96
9586. 1668 function dictKeyValueAppend(dict, key, val) {
9587. 1668
9588. 1668// This function will append <val> to list <dict>[<key>].
9589. 1668
9590. 1668 let list = dict.get(key);
9591. 1130 if (list === undefined) {
9592. 1130 list = [];
9593. 1130 dict.set(key, list);
9594. 1130 }
9595. 1668 list.push(val);
9596. 1668 }
9597. 96
9598. 381 function mergeTreeList(parentTrees) {
9599. 381
9600. 381// This function will return RangeTree object with <parentTrees> merged into
9601. 381// property-children.
9602. 381// @precondition Same `start` and `end` for all the parentTrees
9603. 381
9604. 119 if (parentTrees.length <= 1) {
9605. 119 return parentTrees[0];
9606. 262 }
9607. 262
9608. 262// new RangeTree().
9609. 262
9610. 262 return {
9611. 262
9612. 262// Merge parentTrees into property-children.
9613. 262
9614. 262 children: mergeTreeListToChildren(parentTrees),
9615. 663 delta: parentTrees.reduce(function (aa, bb) {
9616. 663 return aa + bb.delta;
9617. 663 }, 0),
9618. 262 end: parentTrees[0].end,
9619. 262 start: parentTrees[0].start
9620. 262 };
9621. 262 }
9622. 96
9623. 262 function mergeTreeListToChildren(parentTrees) {
9624. 262
9625. 262// This function will return <resultChildren> with <parentTrees> merged.
9626. 262
9627. 262 let openRange;
9628. 262 let parentToChildDict = new Map(); // Map parent to child.
9629. 262 let queueList;
9630. 262 let queueListIi = 0;
9631. 262 let queueOffset;
9632. 262 let queueTrees;
9633. 262 let resultChildren = [];
9634. 262 let startToTreeDict = new Map(); // Map tree.start to tree.
9635. 634 function nextXxx() {
9636. 634
9637. 634// Increment nextOffset, nextTrees.
9638. 634
9639. 634 let [
9640. 634 nextOffset, nextTrees
9641. 297 ] = queueList[queueListIi] || [];
9642. 634 let openRangeEnd;
9643. 578 if (queueTrees === undefined) {
9644. 578 queueListIi += 1;
9645. 578
9646. 578// Increment nextOffset, nextTrees.
9647. 578
9648. 578 } else if (nextOffset === undefined || nextOffset > queueOffset) {
9649. 56 nextOffset = queueOffset;
9650. 56 nextTrees = queueTrees;
9651. 56 queueTrees = undefined;
9652. 56
9653. 56// Concat queueTrees to nextTrees.
9654. 56
9655. 56 } else {
9656. 56 if (nextOffset === queueOffset) {
9657. 56 queueTrees.forEach(function (tree) {
9658. 56 nextTrees.push(tree);
9659. 56 });
9660. 56 queueTrees = undefined;
9661. 56 }
9662. 56 queueListIi += 1;
9663. 56 }
9664. 634
9665. 634// Reached end of queueList.
9666. 634
9667. 262 if (nextOffset === undefined) {
9668. 262 if (openRange !== undefined) {
9669. 262
9670. 262// Append nested-children from parentToChildDict (within openRange) to
9671. 262// resultChildren.
9672. 262
9673. 262 resultAppendNextChild();
9674. 262 }
9675. 262 return true;
9676. 372 }
9677. 372 if (openRange !== undefined && openRange.end <= nextOffset) {
9678. 128
9679. 128// Append nested-children from parentToChildDict (within openRange) to
9680. 128// resultChildren.
9681. 128
9682. 128 resultAppendNextChild();
9683. 128 openRange = undefined;
9684. 372 }
9685. 372 if (openRange === undefined) {
9686. 290 openRangeEnd = nextOffset + 1;
9687. 498 nextTrees.forEach(function ({
9688. 498 parentIi,
9689. 498 tree
9690. 498 }) {
9691. 498 openRangeEnd = Math.max(openRangeEnd, tree.end);
9692. 498
9693. 498// Append children from nextTrees to parentToChildDict.
9694. 498
9695. 498 dictKeyValueAppend(parentToChildDict, parentIi, tree);
9696. 498 });
9697. 290 queueOffset = openRangeEnd;
9698. 290 openRange = {
9699. 290 end: openRangeEnd,
9700. 290 start: nextOffset
9701. 290 };
9702. 290 } else {
9703. 114 nextTrees.forEach(function ({
9704. 114 parentIi,
9705. 114 tree
9706. 114 }) {
9707. 114 let right;
9708. 82 if (tree.end > openRange.end) {
9709. 82 right = treeSplit(tree, openRange.end);
9710. 82 if (queueTrees === undefined) {
9711. 82 queueTrees = [];
9712. 82 }
9713. 82
9714. 82// new RangeTreeWithParent().
9715. 82
9716. 82 queueTrees.push({
9717. 82 parentIi,
9718. 82 tree: right
9719. 82 });
9720. 82 }
9721. 114
9722. 114// Append children from nextTrees to parentToChildDict.
9723. 114
9724. 114 dictKeyValueAppend(parentToChildDict, parentIi, tree);
9725. 114 });
9726. 82 }
9727. 634 }
9728. 290 function resultAppendNextChild() {
9729. 290
9730. 290// This function will append next child to <resultChildren>.
9731. 290
9732. 290 let treesMatching = [];
9733. 585 parentToChildDict.forEach(function (nested) {
9734. 585 if (
9735. 585 nested.length === 1
9736. 559 && nested[0].start === openRange.start
9737. 476 && nested[0].end === openRange.end
9738. 464 ) {
9739. 464 treesMatching.push(nested[0]);
9740. 464 } else {
9741. 121
9742. 121// new rangeTreeCreate().
9743. 121
9744. 121 treesMatching.push({
9745. 121 children: nested,
9746. 121 delta: 0,
9747. 121 end: openRange.end,
9748. 121 start: openRange.start
9749. 121 });
9750. 121 }
9751. 585 });
9752. 290 parentToChildDict.clear();
9753. 290
9754. 290// Recurse mergeTreeList().
9755. 290
9756. 290 resultChildren.push(mergeTreeList(treesMatching));
9757. 290 }
9758. 75 function treeSplit(tree, offset) {
9759. 75
9760. 75// This function will split <tree> along <offset> and return the right-side.
9761. 75// @precondition `tree.start < offset && offset < tree.end`
9762. 75// @return RangeTree Right part
9763. 75
9764. 75 let child;
9765. 75 let ii = 0;
9766. 75 let leftChildLen = tree.children.length;
9767. 75 let mid;
9768. 75 let resultTree;
9769. 75 let rightChildren;
9770. 75
9771. 75// TODO(perf): Binary search (check overhead) //jslint-quiet
9772. 75
9773. 19 while (ii < tree.children.length) {
9774. 19 child = tree.children[ii];
9775. 19 if (child.start < offset && offset < child.end) {
9776. 19
9777. 19// Recurse treeSplit().
9778. 19
9779. 19 mid = treeSplit(child, offset);
9780. 19 leftChildLen = ii + 1;
9781. 19 break;
9782. 19 }
9783. 19 if (child.start >= offset) {
9784. 19 leftChildLen = ii;
9785. 19 break;
9786. 19 }
9787. 19 ii += 1;
9788. 19 }
9789. 75 rightChildren = tree.children.splice(
9790. 75 leftChildLen,
9791. 75 tree.children.length - leftChildLen
9792. 75 );
9793. 4 if (mid !== undefined) {
9794. 4 rightChildren.unshift(mid);
9795. 4 }
9796. 75
9797. 75// new rangeTreeCreate().
9798. 75
9799. 75 resultTree = {
9800. 75 children: rightChildren,
9801. 75 delta: tree.delta,
9802. 75 end: tree.end,
9803. 75 start: offset
9804. 75 };
9805. 75 tree.end = offset;
9806. 75 return resultTree;
9807. 75 }
9808. 262
9809. 262// Init startToTreeDict.
9810. 262
9811. 663 parentTrees.forEach(function (parentTree, parentIi) {
9812. 541 parentTree.children.forEach(function (child) {
9813. 541
9814. 541// Append child with child.start to startToTreeDict.
9815. 541
9816. 541 dictKeyValueAppend(startToTreeDict, child.start, {
9817. 541 parentIi,
9818. 541 tree: child
9819. 541 });
9820. 541 });
9821. 663 });
9822. 262
9823. 262// init queueList.
9824. 262
9825. 333 queueList = Array.from(startToTreeDict).map(function ([
9826. 333 startOffset, trees
9827. 333 ]) {
9828. 333
9829. 333// new StartEvent().
9830. 333
9831. 333 return [
9832. 333 startOffset, trees
9833. 333 ];
9834. 216 }).sort(function (aa, bb) {
9835. 216 return aa[0] - bb[0];
9836. 216 });
9837. 634 while (true) {
9838. 634 if (nextXxx()) {
9839. 634 break;
9840. 634 }
9841. 634 }
9842. 262 return resultChildren;
9843. 262 }
9844. 96
9845. 689 function sortFunc(funcCov) {
9846. 689
9847. 689// This function will normalize-and-sort <funcCov>.ranges.
9848. 689// Sorts the ranges (pre-order sort).
9849. 689// TODO: Tree-based normalization of the ranges. //jslint-quiet
9850. 689// @param funcCov Function coverage to normalize.
9851. 689
9852. 689 funcCov.ranges = treeToRanges(treeFromSortedRanges(
9853. 689 funcCov.ranges.sort(compareRangeList)
9854. 689 ));
9855. 689 return funcCov;
9856. 689 }
9857. 96
9858. 95 function sortProcess(processCov) {
9859. 95
9860. 95// This function will sort <processCov>.result.
9861. 95// Sorts the scripts alphabetically by `url`.
9862. 95// Reassigns script ids: the script at index `0` receives `"0"`, the script at
9863. 95// index `1` receives `"1"` etc.
9864. 95
9865. 73 Object.entries(processCov.result.sort(function (aa, bb) {
9866. 73 return (
9867. 73 aa.url < bb.url
9868. 32 ? -1
9869. 41 : aa.url > bb.url
9870. 41 ? 1
9871. 41 : 0
9872. 73 );
9873. 129 })).forEach(function ([
9874. 129 scriptId, scriptCov
9875. 129 ]) {
9876. 129 scriptCov.scriptId = scriptId.toString(10);
9877. 129 });
9878. 95 return processCov;
9879. 95 }
9880. 96
9881. 129 function sortScript(scriptCov) {
9882. 129
9883. 129// This function will normalize-and-sort <scriptCov>.functions.
9884. 129
9885. 129// Normalize-and-sort functions[xxx].ranges.
9886. 129
9887. 688 scriptCov.functions.forEach(function (funcCov) {
9888. 688 sortFunc(funcCov);
9889. 688 });
9890. 129
9891. 129// Sort functions by root range (pre-order sort).
9892. 129
9893. 559 scriptCov.functions.sort(function (aa, bb) {
9894. 559 return compareRangeList(aa.ranges[0], bb.ranges[0]);
9895. 559 });
9896. 129 return scriptCov;
9897. 129 }
9898. 96
9899. 886 function treeFromSortedRanges(ranges) {
9900. 886
9901. 886// @precondition `ranges` are well-formed and pre-order sorted
9902. 886
9903. 886 let root;
9904. 886 let stack = []; // Stack of parent trees and parent counts.
9905. 1849 ranges.forEach(function (range) {
9906. 1849
9907. 1849// new rangeTreeCreate().
9908. 1849
9909. 1849 let node = {
9910. 1849 children: [],
9911. 1849 delta: range.count,
9912. 1849 end: range.endOffset,
9913. 1849 start: range.startOffset
9914. 1849 };
9915. 1849 let parent;
9916. 1849 let parentCount;
9917. 886 if (root === undefined) {
9918. 886 root = node;
9919. 886 stack.push([
9920. 886 node, range.count
9921. 886 ]);
9922. 886 return;
9923. 963 }
9924. 1558 while (true) {
9925. 1558 [
9926. 1558 parent, parentCount
9927. 1558 ] = stack[stack.length - 1];
9928. 1558
9929. 1558// assert: `top !== undefined` (the ranges are sorted)
9930. 1558
9931. 1558 if (range.startOffset < parent.end) {
9932. 1558 break;
9933. 1558 }
9934. 1558 stack.pop();
9935. 1558 }
9936. 963 node.delta -= parentCount;
9937. 963 parent.children.push(node);
9938. 963 stack.push([
9939. 963 node, range.count
9940. 963 ]);
9941. 963 });
9942. 886 return root;
9943. 886 }
9944. 96
9945. 780 function treeToRanges(tree) {
9946. 780
9947. 780// Get the range coverages corresponding to the tree.
9948. 780// The ranges are pre-order sorted.
9949. 780
9950. 780 let count;
9951. 780 let cur;
9952. 780 let ii;
9953. 780 let parentCount;
9954. 780 let ranges = [];
9955. 780 let stack = [ // Stack of parent trees and counts.
9956. 780 [
9957. 780 tree, 0
9958. 780 ]
9959. 780 ];
9960. 1625 function normalizeRange(tree) {
9961. 1625
9962. 1625// @internal
9963. 1625
9964. 1625 let children = [];
9965. 1625 let curEnd;
9966. 1625 let head;
9967. 1625 let tail = [];
9968. 845 function endChain() {
9969. 19 if (tail.length !== 0) {
9970. 19 head.end = tail[tail.length - 1].end;
9971. 19 tail.forEach(function (tailTree) {
9972. 19 tailTree.children.forEach(function (subChild) {
9973. 19 subChild.delta += tailTree.delta - head.delta;
9974. 19 head.children.push(subChild);
9975. 19 });
9976. 19 });
9977. 19 tail.length = 0;
9978. 19 }
9979. 845
9980. 845// Recurse normalizeRange().
9981. 845
9982. 845 normalizeRange(head);
9983. 845 children.push(head);
9984. 845 }
9985. 864 tree.children.forEach(function (child) {
9986. 429 if (head === undefined) {
9987. 429 head = child;
9988. 435 } else if (
9989. 435 child.delta === head.delta && child.start === curEnd
9990. 435 ) {
9991. 435 tail.push(child);
9992. 435 } else {
9993. 435 endChain();
9994. 435 head = child;
9995. 435 }
9996. 864 curEnd = child.end;
9997. 864 });
9998. 429 if (head !== undefined) {
9999. 429 endChain();
10000. 429 }
10001. 236 if (children.length === 1) {
10002. 236 if (
10003. 236 children[0].start === tree.start
10004. 236 && children[0].end === tree.end
10005. 236 ) {
10006. 236 tree.delta += children[0].delta;
10007. 236 tree.children = children[0].children;
10008. 236
10009. 236// `.lazyCount` is zero for both (both are after normalization)
10010. 236
10011. 236 return;
10012. 236 }
10013. 1619 }
10014. 1619 tree.children = children;
10015. 1619 }
10016. 780 normalizeRange(tree);
10017. 1619 while (stack.length > 0) {
10018. 1619 [
10019. 1619 cur, parentCount
10020. 1619 ] = stack.pop();
10021. 1619 count = parentCount + cur.delta;
10022. 1619 ranges.push({
10023. 1619 count,
10024. 1619 endOffset: cur.end,
10025. 1619 startOffset: cur.start
10026. 1619 });
10027. 1619 ii = cur.children.length - 1;
10028. 1619 while (ii >= 0) {
10029. 1619 stack.push([
10030. 1619 cur.children[ii], count
10031. 1619 ]);
10032. 1619 ii -= 1;
10033. 1619 }
10034. 1619 }
10035. 780 return ranges;
10036. 780 }
10037. 96
10038. 1 if (processCovs.length === 0) {
10039. 1 return {
10040. 1 result: []
10041. 1 };
10042. 95 }
10043. 95 if (processCovs.length === 1) {
10044. 11
10045. 11// Normalize-and-sort scriptCov.
10046. 11
10047. 28 processCovs[0].result.forEach(function (scriptCov) {
10048. 28 sortScript(scriptCov);
10049. 28 });
10050. 11
10051. 11// Sort processCovs[0].result.
10052. 11
10053. 11 return sortProcess(processCovs[0]);
10054. 84 }
10055. 84
10056. 84// Init urlToScriptDict.
10057. 84
10058. 222 processCovs.forEach(function ({
10059. 222 result
10060. 222 }) {
10061. 240 result.forEach(function (scriptCov) {
10062. 240 dictKeyValueAppend(urlToScriptDict, scriptCov.url, scriptCov);
10063. 240 });
10064. 222 });
10065. 101 urlToScriptDict.forEach(function (scriptCovs) {
10066. 101
10067. 101// assert: `scriptCovs.length > 0`
10068. 101
10069. 101// function mergeScriptList(scriptCovs) {
10070. 101// Merges a list of matching script coverages.
10071. 101// Scripts are matching if they have the same `url`.
10072. 101// The result is normalized.
10073. 101// The input values may be mutated, it is not safe to use them after passing
10074. 101// them to this function.
10075. 101// The computation is synchronous.
10076. 101// @param scriptCovs Process coverages to merge.
10077. 101// @return Merged script coverage, or `undefined` if the input list was empty.
10078. 101
10079. 101 let functions = [];
10080. 101
10081. 101// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
10082. 101
10083. 101 let rangeToFuncDict = new Map();
10084. 101
10085. 101// Probably deadcode.
10086. 101// if (scriptCovs.length === 0) {
10087. 101// return undefined;
10088. 101// }
10089. 101
10090. 84 if (scriptCovs.length === 1) {
10091. 84 resultMerged.push(sortScript(scriptCovs[0]));
10092. 84 return;
10093. 85 }
10094. 85
10095. 85// Init rangeToFuncDict.
10096. 85// Map funcCovRoot.startOffset:funcCovRoot.endOffset to funcCov.
10097. 85
10098. 224 scriptCovs.forEach(function ({
10099. 224 functions
10100. 224 }) {
10101. 275 functions.forEach(function (funcCov) {
10102. 275 dictKeyValueAppend(
10103. 275 rangeToFuncDict,
10104. 275
10105. 275// This string can be used to match function with same root range.
10106. 275// The string is derived from the start and end offsets of the root range of
10107. 275// the function.
10108. 275// This assumes that `ranges` is non-empty (true for valid function coverages).
10109. 275
10110. 275 (
10111. 275 funcCov.ranges[0].startOffset
10112. 275 + ";" + funcCov.ranges[0].endOffset
10113. 275 ),
10114. 275 funcCov
10115. 275 );
10116. 275 });
10117. 224 });
10118. 111 rangeToFuncDict.forEach(function (funcCovs) {
10119. 111
10120. 111// assert: `funcCovs.length > 0`
10121. 111
10122. 111// function mergeFuncList(funcCovs) {
10123. 111// Merges a list of matching function coverages.
10124. 111// Functions are matching if their root ranges have the same span.
10125. 111// The result is normalized.
10126. 111// The input values may be mutated, it is not safe to use them after passing
10127. 111// them to this function.
10128. 111// The computation is synchronous.
10129. 111// @param funcCovs Function coverages to merge.
10130. 111// @return Merged function coverage, or `undefined` if the input list was empty.
10131. 111
10132. 111 let count = 0;
10133. 111 let isBlockCoverage;
10134. 111 let merged;
10135. 111 let ranges;
10136. 111 let trees = [];
10137. 111
10138. 111// Probably deadcode.
10139. 111// if (funcCovs.length === 0) {
10140. 111// return undefined;
10141. 111// }
10142. 111
10143. 85 if (funcCovs.length === 1) {
10144. 85 functions.push(sortFunc(funcCovs[0]));
10145. 85 return;
10146. 110 }
10147. 110
10148. 110// assert: `funcCovs[0].ranges.length > 0`
10149. 110
10150. 274 funcCovs.forEach(function (funcCov) {
10151. 274
10152. 274// assert: `funcCov.ranges.length > 0`
10153. 274// assert: `funcCov.ranges` is sorted
10154. 274
10155. 274 count += (
10156. 274 funcCov.count !== undefined
10157. 110 ? funcCov.count
10158. 272 : funcCov.ranges[0].count
10159. 274 );
10160. 197 if (funcCov.isBlockCoverage) {
10161. 197 trees.push(treeFromSortedRanges(funcCov.ranges));
10162. 197 }
10163. 274 });
10164. 110 if (trees.length > 0) {
10165. 91 isBlockCoverage = true;
10166. 91 ranges = treeToRanges(mergeTreeList(trees));
10167. 91 } else {
10168. 85 isBlockCoverage = false;
10169. 85 ranges = [
10170. 85 {
10171. 85 count,
10172. 85 endOffset: funcCovs[0].ranges[0].endOffset,
10173. 85 startOffset: funcCovs[0].ranges[0].startOffset
10174. 85 }
10175. 85 ];
10176. 110 }
10177. 110 merged = {
10178. 110 functionName: funcCovs[0].functionName,
10179. 110 isBlockCoverage,
10180. 110 ranges
10181. 110 };
10182. 110 if (count !== ranges[0].count) {
10183. 85 merged.count = count;
10184. 110 }
10185. 110
10186. 110// assert: `merged` is normalized
10187. 110
10188. 110 functions.push(merged);
10189. 110 });
10190. 85 resultMerged.push(sortScript({
10191. 85 functions,
10192. 85 scriptId: scriptCovs[0].scriptId,
10193. 85 url: scriptCovs[0].url
10194. 85 }));
10195. 85 });
10196. 84 return sortProcess({
10197. 84 result: resultMerged
10198. 84 });
10199. 84}
10200. 1
10201. 7async function v8CoverageReportCreate({
10202. 7 consoleError,
10203. 7 coverageDir,
10204. 7 processArgv = []
10205. 7}) {
10206. 7
10207. 7// This function will create html-coverage-reports directly from
10208. 7// v8-coverage-files in <coverageDir>.
10209. 7// 1. Spawn node.js program <processArgv> with NODE_V8_COVERAGE.
10210. 7// 2. Merge JSON v8-coverage-files in <coverageDir>.
10211. 7// 3. Create html-coverage-reports in <coverageDir>.
10212. 7
10213. 7 let cwd;
10214. 7 let exitCode = 0;
10215. 7 let fileDict;
10216. 7 let promiseList = [];
10217. 7 let v8CoverageObj;
10218. 7
10219. 11 function htmlRender({
10220. 11 fileList,
10221. 11 lineList,
10222. 11 modeIndex,
10223. 11 pathname
10224. 11 }) {
10225. 11 let html;
10226. 11 let padLines;
10227. 11 let padPathname;
10228. 11 let txt;
10229. 11 let txtBorder;
10230. 11 html = "";
10231. 11 html += String(`
10232. 11<!DOCTYPE html>
10233. 11<html lang="en">
10234. 11<head>
10235. 11<title>V8 Coverage Report</title>
10236. 11<style>
10237. 11/* jslint utility2:true */
10238. 11/*csslint ignore:start*/
10239. 11* {
10240. 11box-sizing: border-box;
10241. 11 font-family: consolas, menlo, monospace;
10242. 11}
10243. 11/*csslint ignore:end*/
10244. 11body {
10245. 11 margin: 0;
10246. 11}
10247. 11.coverage pre {
10248. 11 margin: 5px 0;
10249. 11}
10250. 11.coverage table {
10251. 11 border-collapse: collapse;
10252. 11}
10253. 11.coverage td,
10254. 11.coverage th {
10255. 11 border: 1px solid #777;
10256. 11 margin: 0;
10257. 11 padding: 5px;
10258. 11}
10259. 11.coverage td span {
10260. 11 display: inline-block;
10261. 11 width: 100%;
10262. 11}
10263. 11.coverage .content {
10264. 11 padding: 0 5px;
10265. 11}
10266. 11.coverage .content a {
10267. 11 text-decoration: none;
10268. 11}
10269. 11.coverage .count {
10270. 11 margin: 0 5px;
10271. 11 padding: 0 5px;
10272. 11}
10273. 11.coverage .footer,
10274. 11.coverage .header {
10275. 11 padding: 20px;
10276. 11}
10277. 11.coverage .footer {
10278. 11 text-align: center;
10279. 11}
10280. 11.coverage .percentbar {
10281. 11 height: 12px;
10282. 11 margin: 2px 0;
10283. 11 min-width: 200px;
10284. 11 position: relative;
10285. 11 width: 100%;
10286. 11}
10287. 11.coverage .percentbar div {
10288. 11 height: 100%;
10289. 11 position: absolute;
10290. 11}
10291. 11.coverage .title {
10292. 11 font-size: large;
10293. 11 font-weight: bold;
10294. 11 margin-bottom: 10px;
10295. 11}
10296. 11
10297. 11.coverage td,
10298. 11.coverage th {
10299. 11 background: #fff;
10300. 11}
10301. 11.coverage .count {
10302. 11 background: #9d9;
10303. 11 color: #777;
10304. 11}
10305. 11.coverage .coverageHigh{
10306. 11 background: #9d9;
10307. 11}
10308. 11.coverage .coverageIgnore{
10309. 11 background: #ccc;
10310. 11}
10311. 11.coverage .coverageLow{
10312. 11 background: #ebb;
10313. 11}
10314. 11.coverage .coverageMedium{
10315. 11 background: #fd7;
10316. 11}
10317. 11.coverage .footer,
10318. 11.coverage .header {
10319. 11 background: #ddd;
10320. 11}
10321. 11.coverage .lineno {
10322. 11 background: #ddd;
10323. 11}
10324. 11.coverage .percentbar {
10325. 11 background: #999;
10326. 11}
10327. 11.coverage .percentbar div {
10328. 11 background: #666;
10329. 11}
10330. 11.coverage .uncovered {
10331. 11 background: #dbb;
10332. 11}
10333. 11
10334. 11.coverage pre:hover span,
10335. 11.coverage tr:hover td {
10336. 11 background: #7d7;
10337. 11}
10338. 11.coverage pre:hover span.uncovered,
10339. 11.coverage tr:hover td.coverageLow {
10340. 11 background: #d99;
10341. 11}
10342. 11</style>
10343. 11</head>
10344. 11<body class="coverage">
10345. 11<!-- header start -->
10346. 11<div class="header">
10347. 11<div class="title">V8 Coverage Report</div>
10348. 11<table>
10349. 11<thead>
10350. 11 <tr>
10351. 11 <th>Files covered</th>
10352. 11 <th>Lines</th>
10353. 11 </tr>
10354. 11</thead>
10355. 11<tbody>
10356. 11 `).trim() + "\n";
10357. 6 if (modeIndex) {
10358. 6 padLines = String("(ignore) 100.00 %").length;
10359. 6 padPathname = 32;
10360. 6 fileList.unshift({
10361. 6 linesCovered: 0,
10362. 6 linesTotal: 0,
10363. 6 modeCoverageIgnoreFile: "",
10364. 6 pathname: "./"
10365. 6 });
10366. 6 fileList.slice(1).forEach(function ({
10367. 6 linesCovered,
10368. 6 linesTotal,
10369. 6 modeCoverageIgnoreFile,
10370. 6 pathname
10371. 6 }) {
10372. 6 if (!modeCoverageIgnoreFile) {
10373. 6 fileList[0].linesCovered += linesCovered;
10374. 6 fileList[0].linesTotal += linesTotal;
10375. 6 }
10376. 6 padPathname = Math.max(padPathname, pathname.length + 2);
10377. 6 padLines = Math.max(
10378. 6 padLines,
10379. 6 String(linesCovered + " / " + linesTotal).length
10380. 6 );
10381. 6 });
10382. 6 }
10383. 11 txtBorder = (
10384. 11 "+" + "-".repeat(padPathname + 2) + "+"
10385. 11 + "-".repeat(padLines + 2) + "+\n"
10386. 11 );
10387. 11 txt = "";
10388. 11 txt += "V8 Coverage Report\n";
10389. 11 txt += txtBorder;
10390. 11 txt += (
10391. 11 "| " + String("Files covered").padEnd(padPathname, " ") + " | "
10392. 11 + String("Lines").padStart(padLines, " ") + " |\n"
10393. 11 );
10394. 11 txt += txtBorder;
10395. 16 fileList.forEach(function ({
10396. 16 linesCovered,
10397. 16 linesTotal,
10398. 16 modeCoverageIgnoreFile,
10399. 16 pathname
10400. 16 }, ii) {
10401. 16 let coverageLevel;
10402. 16 let coveragePct;
10403. 16 let fill;
10404. 16 let str1;
10405. 16 let str2;
10406. 16 let xx1;
10407. 16 let xx2;
10408. 2 coveragePct = Math.floor(10000 * linesCovered / linesTotal || 0);
10409. 16 coverageLevel = (
10410. 16 modeCoverageIgnoreFile
10411. 2 ? "coverageIgnore"
10412. 14 : coveragePct >= 8000
10413. 14 ? "coverageHigh"
10414. 14 : coveragePct >= 5000
10415. 14 ? "coverageMedium"
10416. 14 : "coverageLow"
10417. 16 );
10418. 16 coveragePct = String(coveragePct).replace((
10419. 16 /..$/m
10420. 16 ), ".$&");
10421. 11 if (modeIndex && ii === 0) {
10422. 6 fill = (
10423. 6
10424. 6// Badge-color rgb-red.
10425. 6
10426. 6 "#" + Math.round(
10427. 6 (100 - Number(coveragePct)) * 2.21
10428. 6 ).toString(16).padStart(2, "0")
10429. 6
10430. 6// Badge-color rgb-green.
10431. 6
10432. 6 + Math.round(
10433. 6 Number(coveragePct) * 2.21
10434. 6 ).toString(16).padStart(2, "0")
10435. 6
10436. 6// Badge-color rgb-blue.
10437. 6
10438. 6 + "00"
10439. 6 );
10440. 6 str1 = "coverage";
10441. 6 str2 = coveragePct + " %";
10442. 6 xx1 = 6 * str1.length + 20;
10443. 6 xx2 = 6 * str2.length + 20;
10444. 6
10445. 6// Fs - write coverage_badge.svg
10446. 6
10447. 6 promiseList.push(fsWriteFileWithParents((
10448. 6 coverageDir + "coverage_badge.svg"
10449. 6 ), String(`
10450. 6<svg height="20" width="${xx1 + xx2}" xmlns="http://www.w3.org/2000/svg">
10451. 6<rect fill="#555" height="20" width="${xx1 + xx2}"/>
10452. 6<rect fill="${fill}" height="20" width="${xx2}" x="${xx1}"/>
10453. 6<g
10454. 6 fill="#fff"
10455. 6 font-family="dejavu sans, verdana, geneva, sans-serif"
10456. 6 font-size="11"
10457. 6 font-weight="bold"
10458. 6 text-anchor="middle"
10459. 6>
10460. 6<text x="${0.5 * xx1}" y="14">${str1}</text>
10461. 6<text x="${xx1 + 0.5 * xx2}" y="14">${str2}</text>
10462. 6</g>
10463. 6</svg>
10464. 6 `).trim() + "\n"));
10465. 6 pathname = "";
10466. 6 }
10467. 16 txt += (
10468. 16 "| "
10469. 16 + String("./" + pathname).padEnd(padPathname, " ") + " | "
10470. 16 + String(
10471. 16 modeCoverageIgnoreFile + " " + coveragePct + " %"
10472. 16 ).padStart(padLines, " ") + " |\n"
10473. 16 );
10474. 16 txt += (
10475. 16 "| " + "*".repeat(
10476. 16 Math.round(0.01 * coveragePct * padPathname)
10477. 16 ).padEnd(padPathname, "_") + " | "
10478. 16 + String(
10479. 16 linesCovered + " / " + linesTotal
10480. 16 ).padStart(padLines, " ") + " |\n"
10481. 16 );
10482. 16 txt += txtBorder;
10483. 16 pathname = htmlEscape(pathname);
10484. 16
10485. 16// CL-37251d17 - Bugfix - Fix incorrect http-link to index.html.
10486. 16
10487. 16 html += String(`
10488. 16 <tr>
10489. 16 <td class="${coverageLevel}">
10490. 16 ${(
10491. 16 modeIndex
10492. 11 ? (
10493. 11 "<a href=\"" + (pathname || "index") + ".html\">. / "
10494. 11 + pathname + "</a><br>"
10495. 11 )
10496. 5 : (
10497. 5 "<a href=\""
10498. 5 + "../".repeat(pathname.split("/").length - 1)
10499. 5 + "index.html\">. / </a>"
10500. 5 + pathname + "<br>"
10501. 5 )
10502. 16 )}
10503. 16 <div class="percentbar">
10504. 16 <div style="width: ${coveragePct}%;"></div>
10505. 16 </div>
10506. 16 </td>
10507. 16 <td style="text-align: right;">
10508. 16 ${modeCoverageIgnoreFile} ${coveragePct} %<br>
10509. 16 ${linesCovered} / ${linesTotal}
10510. 16 </td>
10511. 16 </tr>
10512. 16 `).trim() + "\n";
10513. 16 });
10514. 11 html += String(`
10515. 11</tbody>
10516. 11</table>
10517. 11</div>
10518. 11<!-- header end -->
10519. 11 `).trim() + "\n";
10520. 5 if (!modeIndex) {
10521. 5 html += String(`
10522. 5<!-- content start -->
10523. 5<div class="content">
10524. 5 `).trim() + "\n";
10525. 10980 lineList.forEach(function ({
10526. 10980 count,
10527. 10980 holeList,
10528. 10980 line,
10529. 10980 startOffset
10530. 10980 }, ii) {
10531. 10980 let chunk;
10532. 10980 let inHole;
10533. 10980 let lineHtml;
10534. 10980 let lineId;
10535. 10980 lineHtml = "";
10536. 10980 lineId = "line_" + (ii + 1);
10537. 10980 switch (count) {
10538. 10980
10539. 10980// PR-364 - Probably deadcode.
10540. 10980// case -1:
10541. 10980
10542. 10555 case 0:
10543. 10555 if (holeList.length === 0) {
10544. 10555 lineHtml += "</span>";
10545. 10555 lineHtml += "<span class=\"uncovered\">";
10546. 10555 lineHtml += htmlEscape(line);
10547. 10555 break;
10548. 10555 }
10549. 10555 line = line.split("").map(function (char) {
10550. 10555 return {
10551. 10555 char,
10552. 10555 isHole: undefined
10553. 10555 };
10554. 10555 });
10555. 10555 holeList.forEach(function ([
10556. 10555 aa, bb
10557. 10555 ]) {
10558. 10555 aa = Math.max(aa - startOffset, 0);
10559. 10555 bb = Math.min(bb - startOffset, line.length);
10560. 10555 while (aa < bb) {
10561. 10555 line[aa].isHole = true;
10562. 10555 aa += 1;
10563. 10555 }
10564. 10555 });
10565. 10555 chunk = "";
10566. 10555 line.forEach(function ({
10567. 10555 char,
10568. 10555 isHole
10569. 10555 }) {
10570. 10555 if (inHole !== isHole) {
10571. 10555 lineHtml += htmlEscape(chunk);
10572. 10555 lineHtml += (
10573. 10555 isHole
10574. 10555 ? "</span><span class=\"uncovered\">"
10575. 10555 : "</span><span>"
10576. 10555 );
10577. 10555 chunk = "";
10578. 10555 inHole = isHole;
10579. 10555 }
10580. 10555 chunk += char;
10581. 10555 });
10582. 10555 lineHtml += htmlEscape(chunk);
10583. 10555 break;
10584. 425 default:
10585. 425 lineHtml += htmlEscape(line);
10586. 10980 }
10587. 10980 html += String(`
10588. 10980<pre>
10589. 10980<span class="lineno">
10590. 10980<a href="#${lineId}" id="${lineId}">${String(ii + 1).padStart(5, " ")}.</a>
10591. 10980</span>
10592. 10980<span class="count
10593. 10980 ${(
10594. 10980 count <= 0
10595. 10555 ? "uncovered"
10596. 425 : ""
10597. 10980 )}"
10598. 10980>
10599. 10980${String(count).padStart(7, " ")}
10600. 10980</span>
10601. 10980<span>${lineHtml}</span>
10602. 10980</pre>
10603. 10980 `).replace((
10604. 10980 /\n/g
10605. 10980 ), "").trim() + "\n";
10606. 10980 });
10607. 5 html += String(`
10608. 5</div>
10609. 5<!-- content end -->
10610. 5 `).trim() + "\n";
10611. 5 }
10612. 11 html += String(`
10613. 11<div class="footer">
10614. 11 [
10615. 11 This document was created with
10616. 11 <a href="https://github.com/jslint-org/jslint">JSLint</a>
10617. 11 ]
10618. 11</div>
10619. 11</body>
10620. 11</html>
10621. 11 `).trim() + "\n";
10622. 11
10623. 11// Fs - write <file>.html
10624. 11
10625. 11 promiseList.push(fsWriteFileWithParents(pathname + ".html", html));
10626. 5 if (!modeIndex) {
10627. 5 return;
10628. 6 }
10629. 6
10630. 6// Fs - write coverage_report.txt
10631. 6
10632. 6 consoleError("\n" + txt);
10633. 6 promiseList.push(fsWriteFileWithParents((
10634. 6 coverageDir + "coverage_report.txt"
10635. 6 ), txt));
10636. 6 }
10637. 7
10638. 181 function pathnameRelativeCwd(pathname) {
10639. 181
10640. 181// This function will if <pathname> is inside <cwd>,
10641. 181// return it relative to <cwd>, else empty-string.
10642. 181
10643. 181 pathname = modulePath.resolve(pathname).replace((
10644. 181 /\\/g
10645. 181 ), "/");
10646. 176 if (!pathname.startsWith(cwd)) {
10647. 176 return;
10648. 176 }
10649. 5 pathname = pathname.slice(cwd.length);
10650. 5 return pathname;
10651. 5 }
10652. 7
10653. 7/*
10654. 7function sentinel() {}
10655. 7*/
10656. 7
10657. 7 await moduleFsInit();
10658. 7 consoleError = consoleError || console.error;
10659. 7 cwd = process.cwd().replace((
10660. 7 /\\/g
10661. 7 ), "/") + "/";
10662. 7
10663. 7// Init coverageDir.
10664. 7// Assert coverageDir is subdirectory of cwd.
10665. 7
10666. 7 assertOrThrow(coverageDir, "invalid coverageDir " + coverageDir);
10667. 7
10668. 7// CL-xxx - coverage - Relax requirement for coverageDir to be in cwd.
10669. 7// assertOrThrow(
10670. 7// pathnameRelativeCwd(coverageDir),
10671. 7// "coverageDir " + coverageDir + " is not subdirectory of cwd " + cwd
10672. 7// );
10673. 7
10674. 7 coverageDir = modulePath.resolve(coverageDir).replace((
10675. 7 /\\/g
10676. 7 ), "/") + "/";
10677. 7
10678. 7// 1. Spawn node.js program <processArgv> with coverage
10679. 7
10680. 6 if (processArgv.length > 0) {
10681. 6
10682. 6// Remove old coverage-files.
10683. 6
10684. 6 await fsWriteFileWithParents(coverageDir + "/touch.txt", "");
10685. 6 await Promise.all(Array.from(
10686. 6 await moduleFs.promises.readdir(coverageDir)
10687. 17 ).map(async function (file) {
10688. 17 if ((
10689. 17 /^coverage-\d+?-\d+?-\d+?\.json$/
10690. 6 ).test(file)) {
10691. 6 console.error("rm file " + coverageDir + file);
10692. 6 await moduleFs.promises.unlink(coverageDir + file);
10693. 6 }
10694. 17 }));
10695. 6 exitCode = await new Promise(function (resolve) {
10696. 6 moduleChildProcess.spawn((
10697. 6 processArgv[0] === "npm"
10698. 6
10699. 6// If win32 environment, then replace program npm with npm.cmd.
10700. 6// Coverage-hack - Ugly hack to get test-coverage under both win32 and linux.
10701. 6
10702. 6 ? process.platform.replace("win32", "npm.cmd").replace(
10703. 6 process.platform,
10704. 6 "npm"
10705. 6 )
10706. 6 : processArgv[0]
10707. 6 ), processArgv.slice(1), {
10708. 6 env: Object.assign({}, process.env, {
10709. 6 NODE_V8_COVERAGE: coverageDir
10710. 6 }),
10711. 6 stdio: [
10712. 6 "ignore", 1, 2
10713. 6 ]
10714. 6 }).on("exit", resolve);
10715. 6 });
10716. 6 }
10717. 6
10718. 6// 2. Merge JSON v8-coverage-files in <coverageDir>.
10719. 6
10720. 6 v8CoverageObj = await moduleFs.promises.readdir(coverageDir);
10721. 22 v8CoverageObj = v8CoverageObj.filter(function (file) {
10722. 22 return (
10723. 22 /^coverage-\d+?-\d+?-\d+?\.json$/
10724. 22 ).test(file);
10725. 22 });
10726. 6 v8CoverageObj = await Promise.all(v8CoverageObj.map(async function (file) {
10727. 6 let data = await moduleFs.promises.readFile(coverageDir + file, "utf8");
10728. 6 data = JSON.parse(data);
10729. 688 data.result = data.result.filter(function (scriptCov) {
10730. 688 let pathname = scriptCov.url;
10731. 688
10732. 688// Filter out internal coverages.
10733. 688
10734. 507 if (!pathname.startsWith("file:///")) {
10735. 507 return;
10736. 507 }
10737. 181
10738. 181// Normalize pathname.
10739. 181
10740. 181 pathname = pathnameRelativeCwd(moduleUrl.fileURLToPath(pathname));
10741. 181 if (
10742. 181
10743. 181// Filter files outside of cwd.
10744. 181
10745. 181 !pathname
10746. 181 || pathname.startsWith("[")
10747. 688
10748. 688// Filter directory node_modules.
10749. 688
10750. 6 || (
10751. 6 process.env.npm_config_mode_coverage !== "all"
10752. 6 && (
10753. 6 /(?:^|\/)node_modules\//m
10754. 6 ).test(pathname)
10755. 6 )
10756. 176 ) {
10757. 176 return;
10758. 176 }
10759. 6 scriptCov.url = pathname;
10760. 6 return true;
10761. 6 });
10762. 6 return data;
10763. 6 }));
10764. 6
10765. 6// Merge v8CoverageObj.
10766. 6
10767. 6 v8CoverageObj = v8CoverageListMerge(v8CoverageObj);
10768. 6
10769. 6// debug v8CoverageObj.
10770. 6
10771. 6 await fsWriteFileWithParents(
10772. 6 coverageDir + "v8_coverage_merged.json",
10773. 6 JSON.stringify(v8CoverageObj)
10774. 6 );
10775. 6
10776. 6// 3. Create html-coverage-reports in <coverageDir>.
10777. 6
10778. 6 fileDict = {};
10779. 6 await Promise.all(v8CoverageObj.result.map(async function ({
10780. 6 functions,
10781. 6 url: pathname
10782. 6 }) {
10783. 6 let lineList;
10784. 6 let linesCovered;
10785. 6 let linesTotal;
10786. 6 let source;
10787. 6 source = await moduleFs.promises.readFile(pathname, "utf8");
10788. 6 lineList = [{}];
10789. 6 source.replace((
10790. 6 /^.*$/gm
10791. 10980 ), function (line, startOffset) {
10792. 10980 lineList[lineList.length - 1].endOffset = startOffset - 1;
10793. 10980 lineList.push({
10794. 10980 count: -1,
10795. 10980 endOffset: 0,
10796. 10980 holeList: [],
10797. 10980 line,
10798. 10980 startOffset
10799. 10980 });
10800. 10980 return "";
10801. 10980 });
10802. 6 lineList.shift();
10803. 6 lineList[lineList.length - 1].endOffset = source.length;
10804. 40 functions.reverse().forEach(function ({
10805. 40 ranges
10806. 40 }) {
10807. 60 ranges.reverse().forEach(function ({
10808. 60 count,
10809. 60 endOffset,
10810. 60 startOffset
10811. 60 }, ii, list) {
10812. 547962 lineList.forEach(function (elem) {
10813. 547962 if (!(
10814. 547962 (
10815. 547962 elem.startOffset <= startOffset
10816. 197426 && startOffset <= elem.endOffset
10817. 547902 ) || (
10818. 547902 elem.startOffset <= endOffset
10819. 547902 && endOffset <= elem.endOffset
10820. 547902 ) || (
10821. 547852 startOffset <= elem.startOffset
10822. 547852 && elem.endOffset <= endOffset
10823. 547852 )
10824. 525980 )) {
10825. 525980 return;
10826. 525980 }
10827. 21982
10828. 21982// Handle tree-root.
10829. 21982
10830. 21982 if (ii + 1 === list.length) {
10831. 21852 if (elem.count === -1) {
10832. 21852 elem.count = count;
10833. 21852 }
10834. 21852 return;
10835. 21852 }
10836. 130
10837. 130// Handle tree-children.
10838. 130
10839. 130 if (elem.count !== 0) {
10840. 88 elem.count = Math.max(count, elem.count);
10841. 130 }
10842. 130 if (count === 0) {
10843. 130 elem.count = 0;
10844. 130 elem.holeList.push([
10845. 130 startOffset, endOffset
10846. 130 ]);
10847. 130 }
10848. 547962 });
10849. 60 });
10850. 40 });
10851. 6 linesTotal = lineList.length;
10852. 10980 linesCovered = lineList.filter(function ({
10853. 10980 count
10854. 10980 }) {
10855. 10980 return count > 0;
10856. 10980 }).length;
10857. 6 await moduleFs.promises.mkdir((
10858. 6 modulePath.dirname(coverageDir + pathname)
10859. 6 ), {
10860. 6 recursive: true
10861. 6 });
10862. 6 fileDict[pathname] = {
10863. 6 lineList,
10864. 6 linesCovered,
10865. 6 linesTotal,
10866. 6 modeCoverageIgnoreFile: (
10867. 6 (
10868. 6 /^\/\*mode-coverage-ignore-file\*\/$/m
10869. 6 ).test(source.slice(0, 65536))
10870. 6 ? "(ignore)"
10871. 6 : ""
10872. 6 ),
10873. 6 pathname
10874. 6 };
10875. 6 htmlRender({
10876. 6 fileList: [
10877. 6 fileDict[pathname]
10878. 6 ],
10879. 6 lineList,
10880. 6 pathname: coverageDir + pathname
10881. 6 });
10882. 6 }));
10883. 6 htmlRender({
10884. 6 fileList: Object.keys(fileDict).sort().map(function (pathname) {
10885. 6 return fileDict[pathname];
10886. 6 }),
10887. 6 modeIndex: true,
10888. 6 pathname: coverageDir + "index"
10889. 6 });
10890. 6 assertOrThrow(
10891. 6 exitCode === 0,
10892. 6 "v8CoverageReportCreate - nonzero exitCode " + exitCode
10893. 6 );
10894. 6 await Promise.all(promiseList);
10895. 6}
10896. 1
10897. 1/*
10898. 1function sentinel() {}
10899. 1*/
10900. 1
10901. 1// Export jslint as cjs/esm.
10902. 1
10903. 1jslint_export = Object.freeze(Object.assign(jslint, {
10904. 1 assertErrorThrownAsync,
10905. 1 assertJsonEqual,
10906. 1 assertOrThrow,
10907. 1 debugInline,
10908. 1 fsRmRecursive,
10909. 1 fsWriteFileWithParents,
10910. 1 htmlEscape,
10911. 1 jslint,
10912. 1 jslint_apidoc,
10913. 1 jslint_assert,
10914. 1 jslint_charset_ascii,
10915. 1 jslint_cli,
10916. 1 jslint_edition,
10917. 1 jslint_phase1_split,
10918. 1 jslint_phase2_lex,
10919. 1 jslint_phase3_parse,
10920. 1 jslint_phase4_walk,
10921. 1 jslint_phase5_whitage,
10922. 1 jslint_report,
10923. 1 jstestDescribe,
10924. 1 jstestIt,
10925. 1 jstestOnExit,
10926. 1 moduleFsInit,
10927. 1 noop,
10928. 1 v8CoverageListMerge,
10929. 1 v8CoverageReportCreate
10930. 1}));
10931. 1// module.exports = jslint_export; // Export jslint as cjs.
10932. 1export default Object.freeze(jslint_export); // Export jslint as esm.
10933. 1jslint_import_meta_url = import.meta.url;
10934. 1
10935. 1// Run jslint_cli.
10936. 1
10937. 1(function () {
10938. 1 let cjs_module;
10939. 1 let cjs_require;
10940. 1
10941. 1// Coverage-hack.
10942. 1// Init commonjs builtins in try-catch-block in case we're in es-module-mode.
10943. 1
10944. 1 try {
10945. 1 cjs_module = module;
10946. 1 } catch (ignore) {}
10947. 1 try {
10948. 1 cjs_require = require;
10949. 1 } catch (ignore) {}
10950. 1 jslint_cli({
10951. 1 cjs_module,
10952. 1 cjs_require
10953. 1 });
10954. 1}());
10955. 1
10956. 1// Coverage-hack.
10957. 1debugInline();
10958. 1