wikilint 2.35.0 → 2.35.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,13 @@
1
+ <div align="center"><img src="https://github.com/bhsd-harry/wikiparser-node/raw/main/logo.png" width="200" alt="WikiParser-Node logo"></div>
2
+
3
+ # WikiLint
4
+
1
5
  [![npm version](https://badge.fury.io/js/wikilint.svg)](https://www.npmjs.com/package/wikilint)
2
6
  [![CodeQL](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/codeql.yml/badge.svg)](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/codeql.yml)
3
7
  [![CI](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/node.js.yml/badge.svg)](https://github.com/bhsd-harry/wikiparser-node/actions/workflows/node.js.yml)
4
8
  [![Codacy Badge](https://app.codacy.com/project/badge/Grade/a2fbe7641031451baca2947ae6d7891f)](https://app.codacy.com/gh/bhsd-harry/wikiparser-node/dashboard)
5
9
  ![Istanbul coverage](./coverage/badge.svg)
6
10
 
7
- # WikiLint
8
-
9
11
  This is a minimal version of [WikiParser-Node](https://www.npmjs.com/package/wikiparser-node). The [Wikitext LSP](https://www.npmjs.com/package/wikitext-lsp) and the [WikiParser Language Server](https://marketplace.visualstudio.com/items?itemName=Bhsd.vscode-extension-wikiparser) VS Code extension is written based on this package.
10
12
 
11
13
  You can also directly lint Wikitext articles in the command line using this package:
@@ -496,6 +496,7 @@
496
496
  "revisionuser",
497
497
  "cascadingsources",
498
498
  "namespace",
499
+ "isbn",
499
500
  "int",
500
501
  "special",
501
502
  "speciale",
@@ -659,6 +660,7 @@
659
660
  "contentmodel",
660
661
  "dir",
661
662
  "language",
663
+ "isbn",
662
664
  "numberofwikis",
663
665
  "pendingchangelevel",
664
666
  "noexternallanglinks",
@@ -1331,6 +1333,7 @@
1331
1333
  "#interwikilink": "interwikilink",
1332
1334
  "#interlanguagelink": "interlanguagelink",
1333
1335
  "#contentmodel": "contentmodel",
1336
+ "#isbn": "isbn",
1334
1337
  "#timef": "timef",
1335
1338
  "#timefl": "timefl",
1336
1339
  "USERLANGUAGE": "userlanguage"
@@ -243,6 +243,7 @@
243
243
  "interwikilink",
244
244
  "interlanguagelink",
245
245
  "contentmodel",
246
+ "isbn",
246
247
  "int",
247
248
  "special",
248
249
  "speciale",
@@ -367,6 +368,7 @@
367
368
  "contentmodel",
368
369
  "dir",
369
370
  "language",
371
+ "isbn",
370
372
  "numberofwikis",
371
373
  "pendingchangelevel",
372
374
  "noexternallanglinks",
@@ -502,6 +504,7 @@
502
504
  "#interwikilink": "interwikilink",
503
505
  "#interlanguagelink": "interlanguagelink",
504
506
  "#contentmodel": "contentmodel",
507
+ "#isbn": "isbn",
505
508
  "DISPLAYTITLE": "displaytitle",
506
509
  "#timef": "timef",
507
510
  "#timefl": "timefl",
@@ -272,6 +272,7 @@
272
272
  "interwikilink",
273
273
  "interlanguagelink",
274
274
  "contentmodel",
275
+ "isbn",
275
276
  "int",
276
277
  "special",
277
278
  "speciale",
@@ -393,6 +394,7 @@
393
394
  "contentmodel",
394
395
  "dir",
395
396
  "language",
397
+ "isbn",
396
398
  "numberofwikis",
397
399
  "noexternallanglinks",
398
400
  "wbreponame"
@@ -682,6 +684,7 @@
682
684
  "#interwikilink": "interwikilink",
683
685
  "#interlanguagelink": "interlanguagelink",
684
686
  "#contentmodel": "contentmodel",
687
+ "#isbn": "isbn",
685
688
  "表示タイトル": "displaytitle",
686
689
  "DISPLAYTITLE": "displaytitle",
687
690
  "#timef": "timef",
@@ -184,6 +184,7 @@
184
184
  "#interwikilink": "interwikilink",
185
185
  "#interlanguagelink": "interlanguagelink",
186
186
  "#contentmodel": "contentmodel",
187
+ "#isbn": "isbn",
187
188
  "#timef": "timef",
188
189
  "#timefl": "timefl"
189
190
  },
@@ -384,6 +384,7 @@
384
384
  "interwikilink",
385
385
  "interlanguagelink",
386
386
  "contentmodel",
387
+ "isbn",
387
388
  "int",
388
389
  "special",
389
390
  "speciale",
@@ -506,6 +507,7 @@
506
507
  "contentmodel",
507
508
  "dir",
508
509
  "language",
510
+ "isbn",
509
511
  "numberofwikis",
510
512
  "noexternallanglinks",
511
513
  "wbreponame"
@@ -793,6 +795,7 @@
793
795
  "#interwikilink": "interwikilink",
794
796
  "#interlanguagelink": "interlanguagelink",
795
797
  "#contentmodel": "contentmodel",
798
+ "#isbn": "isbn",
796
799
  "DISPLAYTITLE": "displaytitle",
797
800
  "显示标题": "displaytitle",
798
801
  "顯示標題": "displaytitle",
@@ -1 +1 @@
1
- <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="98" height="20" role="img" aria-label="Coverage: 90%"><title>Coverage: 90%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="98" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="35" height="20" fill="#4c1"/><rect width="98" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="795" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="250">90%</text><text x="795" y="140" transform="scale(.1)" fill="#fff" textLength="250">90%</text></g></svg>
1
+ <svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="98" height="20" role="img" aria-label="Coverage: 96%"><title>Coverage: 96%</title><linearGradient id="s" x2="0" y2="100%"><stop offset="0" stop-color="#bbb" stop-opacity=".1"/><stop offset="1" stop-opacity=".1"/></linearGradient><clipPath id="r"><rect width="98" height="20" rx="3" fill="#fff"/></clipPath><g clip-path="url(#r)"><rect width="63" height="20" fill="#555"/><rect x="63" width="35" height="20" fill="#4c1"/><rect width="98" height="20" fill="url(#s)"/></g><g fill="#fff" text-anchor="middle" font-family="Verdana,Geneva,DejaVu Sans,sans-serif" text-rendering="geometricPrecision" font-size="110"><text aria-hidden="true" x="325" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="530">Coverage</text><text x="325" y="140" transform="scale(.1)" fill="#fff" textLength="530">Coverage</text><text aria-hidden="true" x="795" y="150" fill="#010101" fill-opacity=".3" transform="scale(.1)" textLength="250">96%</text><text x="795" y="140" transform="scale(.1)" fill="#fff" textLength="250">96%</text></g></svg>
@@ -784,6 +784,19 @@
784
784
  ],
785
785
  "description": "Creates an interlanguage link."
786
786
  },
787
+ {
788
+ "aliases": [
789
+ "#isbn"
790
+ ],
791
+ "signatures": [
792
+ [
793
+ {
794
+ "label": "ISBN number"
795
+ }
796
+ ]
797
+ ],
798
+ "description": "Create a link to [Special:Booksources](https://www.mediawiki.org/wiki/Special:Booksources) with the given ISBN number. This provides the same functionality as the deprecated [ISBN magic link](https://en.wikipedia.org/wiki/Help:Magic_links)."
799
+ },
787
800
  {
788
801
  "aliases": [
789
802
  "#special"
package/dist/bin/cli.js CHANGED
@@ -297,7 +297,12 @@ try {
297
297
  ({ minimatch } = require('minimatch'));
298
298
  }
299
299
  catch {
300
- minimatch = path_1.default.matchesGlob.bind(path_1.default); // eslint-disable-line n/no-unsupported-features/node-builtins
300
+ /* eslint-disable n/no-unsupported-features/node-builtins */
301
+ if (typeof path_1.default.matchesGlob !== 'function') {
302
+ exit('Cannot load Node.js package "minimatch"');
303
+ }
304
+ minimatch = path_1.default.matchesGlob.bind(path_1.default);
305
+ /* eslint-enable n/no-unsupported-features/node-builtins */
301
306
  }
302
307
  (async () => {
303
308
  if (lintConfigFile) {
@@ -77,7 +77,7 @@ const mw = {
77
77
  },
78
78
  },
79
79
  };
80
- const pkg = "wikilint", version = "2.35.0";
80
+ const pkg = "wikilint", version = "2.35.1";
81
81
  let mwConfig;
82
82
  /**
83
83
  * Get the parser configuration for a Wikimedia Foundation project.
@@ -122,7 +122,7 @@ exports.default = async (site, url, user, force, internal) => {
122
122
  siprop: 'general|magicwords|functionhooks|namespaces|namespacealiases',
123
123
  format: 'json',
124
124
  formatversion: '2',
125
- }, { query: { general: { articlepath, variants, langconversion }, magicwords, namespaces, namespacealiases, functionhooks, }, } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json();
125
+ }, { general: { articlepath, variants, langconversion }, magicwords, namespaces, namespacealiases, functionhooks, } = (await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json()).query;
126
126
  try {
127
127
  eval(m); // eslint-disable-line no-eval
128
128
  }
@@ -157,7 +157,7 @@ exports.default = async (site, url, user, force, internal) => {
157
157
  Object.assign(config, { functionHook: [...functionhooks.map(s => s.toLowerCase()), 'msgnw'] });
158
158
  }
159
159
  if (!mwConfig.variableIDs) {
160
- const { query: { variables } } = await (await fetch(`${url}/api.php?${new URLSearchParams({ ...params, siprop: 'variables' }).toString()}`, headers)).json();
160
+ const { variables } = (await (await fetch(`${url}/api.php?${new URLSearchParams({ ...params, siprop: 'variables' }).toString()}`, headers)).json()).query;
161
161
  Object.assign(config, { variable: [...new Set([...variables, '='])] });
162
162
  }
163
163
  if ('#choose' in parserFunction[0]) {
package/dist/index.js CHANGED
@@ -22,7 +22,7 @@ const re = new RegExp(String.raw `^https?:\/\/([^./]+)\.(${common_1.wmf})\.org`,
22
22
  * @param dir 子路径
23
23
  */
24
24
  const rootRequire = (file, dir) => require(path_1.default.isAbsolute(file)
25
- ? /* istanbul ignore next */ file
25
+ ? /* c8 ignore next */ file
26
26
  : path_1.default.join('..', file.includes('/') ? '' : dir, file));
27
27
  /* NOT FOR BROWSER ONLY END */
28
28
  let viewOnly = true;
@@ -94,7 +94,7 @@ const Parser = {
94
94
  if (typeof this.config === 'string') {
95
95
  this.config = rootRequire(this.config, 'config');
96
96
  }
97
- /* istanbul ignore if */
97
+ /* c8 ignore next 3 */
98
98
  if (this.config.doubleUnderscore.length < 3 || !('functionHook' in this.config)) {
99
99
  (0, diff_1.error)(`The schema (${path_1.default.join(__dirname, '..', 'config', '.schema.json')}) of parser configuration is updated.`);
100
100
  }
@@ -185,7 +185,7 @@ const Parser = {
185
185
  return token.parse(maxStage, include);
186
186
  /* NOT FOR BROWSER ONLY */
187
187
  }
188
- catch (e) /* istanbul ignore next */ {
188
+ catch (e) /* c8 ignore start */ {
189
189
  if (e instanceof Error) {
190
190
  const file = path_1.default.join(__dirname, '..', 'errors', new Date().toISOString()), stage = token.getAttribute('stage');
191
191
  for (const k of Object.keys(config)) {
@@ -199,6 +199,7 @@ const Parser = {
199
199
  }
200
200
  throw e;
201
201
  }
202
+ /* c8 ignore stop */
202
203
  /* NOT FOR BROWSER ONLY END */
203
204
  });
204
205
  return root;
@@ -225,19 +226,20 @@ const Parser = {
225
226
  /** @implements */
226
227
  getWMFSite(url) {
227
228
  const mt = re.exec(url);
228
- /* istanbul ignore if */
229
+ /* c8 ignore next 3 */
229
230
  if (!mt) {
230
231
  throw new RangeError('Not a recognizable WMF site!');
231
232
  }
232
233
  const type = mt[2].toLowerCase();
233
234
  return [mt[1].toLowerCase() + (type === 'wikipedia' ? 'wiki' : type), mt[0]];
234
235
  },
235
- /* istanbul ignore next */
236
+ /* c8 ignore start */
236
237
  /** @implements */
237
238
  async fetchConfig(site, url, user) {
238
239
  const { default: fetchConfig } = require('./bin/config');
239
240
  return this.getConfig(await fetchConfig(site, url, user, false, true));
240
241
  },
242
+ /* c8 ignore stop */
241
243
  };
242
244
  const def = {
243
245
  default: { value: Parser },
@@ -13,10 +13,10 @@ const loadTexvcjs = () => {
13
13
  try {
14
14
  texcvjs = require('mathoid-texvcjs');
15
15
  }
16
- catch {
17
- /* istanbul ignore next */
16
+ catch /* c8 ignore start */ {
18
17
  texcvjs = null;
19
18
  }
19
+ /* c8 ignore stop */
20
20
  }
21
21
  return texcvjs;
22
22
  }
@@ -29,10 +29,12 @@ const loadJsonLSP = () => {
29
29
  try {
30
30
  jsonLSP = require('vscode-json-languageservice')
31
31
  .getLanguageService({
32
+ /* c8 ignore start */
32
33
  /** @implements */
33
34
  async schemaRequestService(uri) {
34
35
  return (await fetch(uri)).text();
35
36
  },
37
+ /* c8 ignore stop */
36
38
  });
37
39
  const dir = path_1.default.join('..', '..', 'data', 'ext');
38
40
  jsonLSP.configure({
@@ -46,17 +48,17 @@ const loadJsonLSP = () => {
46
48
  schema,
47
49
  };
48
50
  }
49
- catch {
50
- /* istanbul ignore next */
51
+ catch /* c8 ignore start */ {
51
52
  return false;
52
53
  }
54
+ /* c8 ignore stop */
53
55
  }).filter(schema => schema !== false),
54
56
  });
55
57
  }
56
- catch {
57
- /* istanbul ignore next */
58
+ catch /* c8 ignore start */ {
58
59
  jsonLSP = null;
59
60
  }
61
+ /* c8 ignore stop */
60
62
  }
61
63
  return jsonLSP;
62
64
  };
@@ -68,10 +70,10 @@ const loadCssLSP = () => {
68
70
  cssLSP = require('vscode-css-languageservice')
69
71
  .getCSSLanguageService();
70
72
  }
71
- catch {
72
- /* istanbul ignore next */
73
+ catch /* c8 ignore start */ {
73
74
  cssLSP = null;
74
75
  }
76
+ /* c8 ignore stop */
75
77
  }
76
78
  return cssLSP;
77
79
  };
@@ -83,10 +85,10 @@ const loadHtmlData = () => {
83
85
  htmlData = require('vscode-html-languageservice')
84
86
  .getDefaultHTMLDataProvider();
85
87
  }
86
- catch {
87
- /* istanbul ignore next */
88
+ catch /* c8 ignore start */ {
88
89
  htmlData = null;
89
90
  }
91
+ /* c8 ignore stop */
90
92
  }
91
93
  return htmlData;
92
94
  };
@@ -98,10 +100,10 @@ const loadStylelint = () => {
98
100
  try {
99
101
  return (await import('stylelint')).default;
100
102
  }
101
- catch {
102
- /* istanbul ignore next */
103
+ catch /* c8 ignore start */ {
103
104
  return null;
104
105
  }
106
+ /* c8 ignore stop */
105
107
  })();
106
108
  return stylelint;
107
109
  }
@@ -263,23 +263,23 @@ const validateConfigValue = (value) => validateSeverity(value)
263
263
  * @throws `RangeError` 未知的规则或无效的值
264
264
  */
265
265
  const set = (obj, key, value) => {
266
- /* istanbul ignore if */
266
+ /* c8 ignore next 6 */
267
267
  if (!base_1.rules.includes(key)) {
268
268
  throw new RangeError(`Unknown lint rule: ${key}`);
269
269
  }
270
- else /* istanbul ignore if */ if (value === undefined) {
270
+ if (value === undefined) {
271
271
  return false;
272
272
  }
273
- else if (validateConfigValue(value)) {
273
+ if (validateConfigValue(value)) {
274
274
  obj[key] = value;
275
275
  return true;
276
276
  }
277
- /* istanbul ignore next */
277
+ /* c8 ignore next */
278
278
  throw new RangeError(`Invalid lint config for ${key}: ${JSON.stringify(value)}`);
279
279
  };
280
280
  const clone = typeof structuredClone === 'function'
281
281
  ? structuredClone
282
- : /* istanbul ignore next */ (obj) => JSON.parse(JSON.stringify(obj));
282
+ : /* c8 ignore next */ (obj) => JSON.parse(JSON.stringify(obj));
283
283
  /** 语法规则设置 */
284
284
  class LintRuleConfiguration {
285
285
  /** @param config 语法规则设置 */
@@ -311,11 +311,12 @@ class LintConfiguration {
311
311
  set rules(config) {
312
312
  this.#rules = new Proxy(new LintRuleConfiguration(config), {
313
313
  set,
314
- /* istanbul ignore next */
314
+ /* c8 ignore start */
315
315
  /** @ignore */
316
316
  deleteProperty() {
317
317
  return false;
318
318
  },
319
+ /* c8 ignore stop */
319
320
  });
320
321
  }
321
322
  /** @param config 语法检查设置 */
package/dist/lib/lsp.js CHANGED
@@ -236,7 +236,7 @@ const getFixAll = (root, rule) => {
236
236
  * @param config
237
237
  */
238
238
  const partialParse = async (wikitext, watch, include, config = index_1.default.getConfig()) => {
239
- const set = typeof setImmediate === 'function' ? setImmediate : /* istanbul ignore next */ setTimeout, { running } = debug_1.Shadow;
239
+ const set = typeof setImmediate === 'function' ? setImmediate : /* c8 ignore next */ setTimeout, { running } = debug_1.Shadow;
240
240
  debug_1.Shadow.running = true;
241
241
  /** restore state before exit */
242
242
  const finish = () => {
@@ -269,10 +269,11 @@ const partialParse = async (wikitext, watch, include, config = index_1.default.g
269
269
  set(parseOnce, 0);
270
270
  });
271
271
  }
272
- catch (e) /* istanbul ignore next */ {
272
+ catch (e) /* c8 ignore start */ {
273
273
  finish();
274
274
  throw e;
275
275
  }
276
+ /* c8 ignore stop */
276
277
  finish();
277
278
  return token;
278
279
  };
@@ -436,10 +437,10 @@ class LanguageService {
436
437
  this.#running = undefined;
437
438
  return root;
438
439
  }
439
- /* istanbul ignore next */
440
+ /* c8 ignore start */
440
441
  this.#running = this.#parse();
441
- /* istanbul ignore next */
442
442
  return this.#running;
443
+ /* c8 ignore stop */
443
444
  }
444
445
  /**
445
446
  * 提交签名解析任务
@@ -474,10 +475,10 @@ class LanguageService {
474
475
  this.#running2 = undefined;
475
476
  return root;
476
477
  }
477
- /* istanbul ignore next */
478
+ /* c8 ignore start */
478
479
  this.#running2 = this.#parseSignature();
479
- /* istanbul ignore next */
480
480
  return this.#running2;
481
+ /* c8 ignore stop */
481
482
  }
482
483
  /**
483
484
  * Provide color decorators
@@ -939,6 +940,7 @@ class LanguageService {
939
940
  const file = path_1.default.join(dir, `${hash.digest('hex')}.ly`);
940
941
  fs_1.default.writeFileSync(file, score);
941
942
  try {
943
+ // eslint-disable-next-line @typescript-eslint/strict-void-return
942
944
  await util_1.default.promisify(child_process_1.execFile)(this.lilypond, ['-s', '-o', dir, file]);
943
945
  scores.set(score, []);
944
946
  }
@@ -1268,7 +1270,7 @@ class LanguageService {
1268
1270
  * @param position position / 位置
1269
1271
  */
1270
1272
  async provideHover(text, position) {
1271
- /* istanbul ignore next */
1273
+ /* c8 ignore next 3 */
1272
1274
  if (!this.data) {
1273
1275
  return undefined;
1274
1276
  }
@@ -1366,7 +1368,7 @@ class LanguageService {
1366
1368
  * @param position position / 位置
1367
1369
  */
1368
1370
  async provideSignatureHelp(text, position) {
1369
- /* istanbul ignore next */
1371
+ /* c8 ignore next 3 */
1370
1372
  if (!this.data) {
1371
1373
  return undefined;
1372
1374
  }
package/dist/lib/node.js CHANGED
@@ -94,7 +94,7 @@ let AstNode = (() => {
94
94
  }
95
95
  /** @private */
96
96
  getAttribute(key) {
97
- return (key === 'padding' ? 0 : /* istanbul ignore next */ this[key]);
97
+ return (key === 'padding' ? 0 : /* c8 ignore next */ this[key]);
98
98
  }
99
99
  /** @private */
100
100
  setAttribute(key, value) {
package/dist/lib/text.js CHANGED
@@ -48,9 +48,10 @@ const wordRegex = /* #__PURE__ */ (() => {
48
48
  // eslint-disable-next-line prefer-regex-literals
49
49
  return new RegExp(String.raw `[\p{L}\p{N}_]`, 'u');
50
50
  }
51
- catch /* istanbul ignore next */ {
51
+ catch /* c8 ignore start */ {
52
52
  return /\w/u;
53
53
  }
54
+ /* c8 ignore stop */
54
55
  })();
55
56
  /**
56
57
  * text node
@@ -82,7 +83,7 @@ class AstText extends node_1.AstNode {
82
83
  return [];
83
84
  }
84
85
  const { data, parentNode, nextSibling, previousSibling } = this;
85
- /* istanbul ignore if */
86
+ /* c8 ignore next 3 */
86
87
  if (!parentNode) {
87
88
  throw new Error('An isolated text node cannot be linted!');
88
89
  }
@@ -116,17 +117,17 @@ class AstText extends node_1.AstNode {
116
117
  for (let mt = errorRegex.exec(data); mt; mt = errorRegex.exec(data)) {
117
118
  let { index, 0: error } = mt;
118
119
  const [, tag, prefix] = mt, lbrackInExtLinkText = error === '[' && type === 'ext-link-text';
119
- if (error.startsWith('<') && !tags.has(tag.toLowerCase())
120
+ if (prefix && prefix !== ']') {
121
+ const { length } = prefix;
122
+ index += length;
123
+ error = error.slice(length);
124
+ }
125
+ else if (error.startsWith('<') && !tags.has(tag.toLowerCase())
120
126
  || lbrackInExtLinkText && (/&(?:rbrack|#93|#x5[Dd];);/u.test(data.slice(index + 1))
121
127
  || nextSibling?.is('ext') && nextName === 'nowiki'
122
128
  && nextSibling.innerText?.includes(']'))) {
123
129
  continue;
124
130
  }
125
- else if (prefix && prefix !== ']') {
126
- const { length } = prefix;
127
- index += length;
128
- error = error.slice(length);
129
- }
130
131
  else if (error.startsWith('\n==')) {
131
132
  index++;
132
133
  error = error.slice(1);
@@ -323,7 +324,7 @@ class AstText extends node_1.AstNode {
323
324
  splitText(offset) {
324
325
  LSP: {
325
326
  const { parentNode, data } = this;
326
- /* istanbul ignore if */
327
+ /* c8 ignore next 3 */
327
328
  if (!parentNode) {
328
329
  throw new Error('The text node to be split has no parent node!');
329
330
  }
@@ -343,7 +344,7 @@ class AstText extends node_1.AstNode {
343
344
  escape() {
344
345
  LSP: {
345
346
  const { parentNode } = this;
346
- /* istanbul ignore if */
347
+ /* c8 ignore next 3 */
347
348
  if (!parentNode) {
348
349
  throw new Error('The text node to be escaped has no parent node!');
349
350
  }
package/dist/lib/title.js CHANGED
@@ -83,7 +83,7 @@ class Title {
83
83
  title = (0, common_1.rawurldecode)(title);
84
84
  this.encoded = encoded;
85
85
  }
86
- catch { }
86
+ catch /* c8 ignore next */ { }
87
87
  }
88
88
  title = (0, string_1.decodeHtml)(title).replace(/[_ ]+/gu, ' ').trim();
89
89
  if (subpage || page && trimmed.startsWith('/')) {
@@ -112,7 +112,7 @@ class Title {
112
112
  try {
113
113
  fragment = (0, common_1.rawurldecode)(fragment);
114
114
  }
115
- catch { }
115
+ catch /* c8 ignore next */ { }
116
116
  }
117
117
  this.#fragment = fragment.replace(/ /gu, '_');
118
118
  title = title.slice(0, i).trim();
@@ -172,7 +172,7 @@ class Title {
172
172
  LSP: {
173
173
  if (typeof articlePath === 'string') {
174
174
  this.#path = articlePath;
175
- /* istanbul ignore if */
175
+ /* c8 ignore next 3 */
176
176
  if (!this.#path.includes('$1')) {
177
177
  this.#path += `${this.#path.endsWith('/') ? '' : '/'}$1`;
178
178
  }
@@ -61,7 +61,7 @@ const getSymbol = (s) => {
61
61
  * @throws `TranscludeToken.constructor()`
62
62
  */
63
63
  const parseBraces = (wikitext, config, accum) => {
64
- const source = String.raw `${config.excludes.includes('heading') ? '' : String.raw `^((?:\0\d+[cno]\x7F)*)={1,6}|`}\[\[|-\{(?!\{)`, { parserFunction: [, , , subst] } = config, stack = [], linkStack = [];
64
+ const source = String.raw `${config.excludes.includes('heading') ? '' : String.raw `^((?:\0\d+[cno]\x7F)*)={1,6}|`}\[\[|-\{(?!\{)`, [, , , subst] = config.parserFunction, stack = [], linkStack = [];
65
65
  /**
66
66
  * 填入模板内容
67
67
  * @param text wikitext全文
@@ -90,7 +90,7 @@ const parseBraces = (wikitext, config, accum) => {
90
90
  return `\0${length}${getSymbol(parts[0])}\x7F`;
91
91
  }
92
92
  catch (e) {
93
- /* istanbul ignore if */
93
+ /* c8 ignore next 3 */
94
94
  if (!(e instanceof SyntaxError) || e.message !== 'Invalid template name') {
95
95
  throw e;
96
96
  }
@@ -169,13 +169,11 @@ const parseBraces = (wikitext, config, accum) => {
169
169
  ch = getSymbol(parts[0][0]);
170
170
  }
171
171
  catch (e) {
172
- /* istanbul ignore else */
173
- if (e instanceof SyntaxError && e.message === 'Invalid template name') {
174
- skip = true;
175
- }
176
- else {
172
+ /* c8 ignore next 3 */
173
+ if (!(e instanceof SyntaxError && e.message === 'Invalid template name')) {
177
174
  throw e;
178
175
  }
176
+ skip = true;
179
177
  }
180
178
  }
181
179
  if (!skip) {
@@ -12,7 +12,7 @@ const heading_1 = require("../src/heading");
12
12
  * @param accum
13
13
  */
14
14
  const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config, accum) => {
15
- const { doubleUnderscore: [insensitive, sensitive, aliases] } = config, all = [...insensitive, ...sensitive];
15
+ const [insensitive, sensitive, aliases] = config.doubleUnderscore, all = [...insensitive, ...sensitive];
16
16
  config.insensitiveDoubleUnderscore ??= new Set(insensitive.filter(cm_util_1.isUnderscore));
17
17
  config.sensitiveDoubleUnderscore ??= new Set(sensitive.filter(cm_util_1.isUnderscore));
18
18
  config.regexHrAndDoubleUnderscore ??= new RegExp(String.raw `^((?:\0\d+[cno]\x7F)*)(-{4,})|__(${all.filter(cm_util_1.isUnderscore).join('|')})__|_{2}(${all.filter(s => !(0, cm_util_1.isUnderscore)(s)).map(s => s.slice(2, -2)).join('|')})_{2}`, 'gimu');
@@ -29,7 +29,7 @@ const parseHrAndDoubleUnderscore = ({ firstChild: { data }, type, name }, config
29
29
  if (caseSensitive || caseInsensitive) {
30
30
  // @ts-expect-error abstract class
31
31
  new doubleUnderscore_1.DoubleUnderscoreToken(key, caseSensitive, Boolean(p4), config, accum);
32
- return `\0${accum.length - 1}${caseInsensitive && (aliases?.[lc] ?? /* istanbul ignore next */ lc) === 'toc' ? 'u' : 'n'}\x7F`;
32
+ return `\0${accum.length - 1}${caseInsensitive && (aliases?.[lc] ?? /* c8 ignore next */ lc) === 'toc' ? 'u' : 'n'}\x7F`;
33
33
  }
34
34
  return m;
35
35
  });
@@ -43,7 +43,7 @@ const parseList = (wikitext, state, config, accum) => {
43
43
  if (!dt) {
44
44
  return text;
45
45
  }
46
- const { html: [normalTags, , voidTags] } = config, fullRegex = /:+|-\{|\0\d+[xq]\x7F/gu;
46
+ const [normalTags, , voidTags] = config.html, fullRegex = /:+|-\{|\0\d+[xq]\x7F/gu;
47
47
  let regex = fullRegex, ex = regex.exec(text), lt = 0, lb = false, li = false, lc = 0;
48
48
  /**
49
49
  * 创建`DdToken`
@@ -15,9 +15,10 @@ const parseMagicLinks = (wikitext, config, accum) => {
15
15
  try {
16
16
  config.regexMagicLinks = new RegExp(String.raw `(^|[^\p{L}\p{N}_])(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
17
17
  }
18
- catch /* istanbul ignore next */ {
18
+ catch /* c8 ignore start */ {
19
19
  config.regexMagicLinks = new RegExp(String.raw `(^|\W)(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
20
20
  }
21
+ /* c8 ignore stop */
21
22
  }
22
23
  return wikitext.replace(config.regexMagicLinks, (m, lead, p1) => {
23
24
  let url = lead ? m.slice(lead.length) : m;
package/dist/src/arg.js CHANGED
@@ -113,7 +113,7 @@ let ArgToken = (() => {
113
113
  /** @private */
114
114
  lint(start = this.getAbsoluteIndex(), re) {
115
115
  LINT: {
116
- const { childNodes: [argName, argDefault, ...rest] } = this;
116
+ const [argName, argDefault, ...rest] = this.childNodes;
117
117
  argName.setAttribute('aIndex', start + 3);
118
118
  const errors = argName.lint(start + 3, re);
119
119
  if (argDefault) {
@@ -27,9 +27,10 @@ const wordRegex = /* #__PURE__ */ (() => {
27
27
  // eslint-disable-next-line prefer-regex-literals
28
28
  return new RegExp(String.raw `[\p{L}\p{N}]`, 'u');
29
29
  }
30
- catch /* istanbul ignore next */ {
30
+ catch /* c8 ignore start */ {
31
31
  return /[^\W_]/u;
32
32
  }
33
+ /* c8 ignore stop */
33
34
  })();
34
35
  /**
35
36
  * attributes of extension and HTML tags
@@ -92,12 +92,12 @@ let ConverterToken = (() => {
92
92
  }
93
93
  /** @private */
94
94
  toString(skip) {
95
- const { childNodes: [flags, ...rules] } = this;
95
+ const [flags, ...rules] = this.childNodes;
96
96
  return `-{${flags.toString(skip)}${flags.length > 0 ? '|' : ''}${rules.map(rule => rule.toString(skip)).join(';')}}-`;
97
97
  }
98
98
  /** @private */
99
99
  text() {
100
- const { childNodes: [flags, ...rules] } = this;
100
+ const [flags, ...rules] = this.childNodes;
101
101
  return `-{${flags.text()}|${(0, string_1.text)(rules, ';')}}-`;
102
102
  }
103
103
  /** @private */
@@ -137,12 +137,12 @@ let ImageParameterToken = (() => {
137
137
  }
138
138
  const value = super.text().trim();
139
139
  return debug_1.Shadow.run(() => {
140
- const token = new index_2.Token(value, this.getAttribute('config'));
140
+ const config = this.getAttribute('config'), token = new index_2.Token(value, config);
141
141
  token.parseOnce(0, this.getAttribute('include')).parseOnce();
142
142
  if (/^\0\d+m\x7F/u.test(token.firstChild.toString())) {
143
143
  return value;
144
144
  }
145
- const link = validate('link', value, this.getAttribute('config'), this.parentNode?.type);
145
+ const link = validate('link', value, config, this.parentNode?.type);
146
146
  return link === true ? undefined : link;
147
147
  }, index_1.default);
148
148
  }
@@ -229,7 +229,16 @@ let ImageParameterToken = (() => {
229
229
  if (link === undefined) {
230
230
  const rule = 'invalid-gallery', s = lintConfig.getSeverity(rule, 'link');
231
231
  if (s) {
232
- errors.push((0, lint_1.generateForSelf)(this, { start }, rule, 'invalid-gallery-link', s));
232
+ const e = (0, lint_1.generateForSelf)(this, { start }, rule, 'invalid-gallery-link', s);
233
+ if (computeEditInfo) {
234
+ const rawLink = super.toString(), index = rawLink.indexOf('|'), before = rawLink.slice(0, index).trim();
235
+ if (index !== -1
236
+ && !/[<{]/u.test(before)
237
+ && typeof validate('link', before, this.getAttribute('config'), this.parentNode?.type) === 'string') {
238
+ e.suggestions = [(0, lint_1.fixBySpace)(start + this.getRelativeIndex(0) + index)];
239
+ }
240
+ }
241
+ errors.push(e);
233
242
  }
234
243
  }
235
244
  else if (typeof link === 'string') {
package/dist/src/index.js CHANGED
@@ -112,9 +112,11 @@ class Token extends element_1.AstElement {
112
112
  if (n < this.#stage || this.length !== 1 || !this.isPlain()) {
113
113
  return this;
114
114
  }
115
- else /* istanbul ignore if */ if (this.#stage >= constants_1.MAX_STAGE) {
115
+ /* c8 ignore start */
116
+ if (this.#stage >= constants_1.MAX_STAGE) {
116
117
  return this;
117
118
  }
119
+ /* c8 ignore stop */
118
120
  switch (n) {
119
121
  case 0:
120
122
  if (this.type === 'root') {
@@ -327,7 +329,7 @@ class Token extends element_1.AstElement {
327
329
  return this.#accum;
328
330
  case 'built':
329
331
  return this.#built;
330
- /* istanbul ignore next */
332
+ /* c8 ignore next 2 */
331
333
  case 'stage':
332
334
  return this.#stage;
333
335
  default:
@@ -111,7 +111,8 @@ let LinkBaseToken = (() => {
111
111
  if (key === 'bracket') {
112
112
  this.#bracket = value;
113
113
  }
114
- else /* istanbul ignore if */ if (key === 'title') {
114
+ else if (key === 'title') {
115
+ /* c8 ignore next */
115
116
  this.#title = value;
116
117
  }
117
118
  else {
@@ -79,7 +79,7 @@ let CommentToken = (() => {
79
79
  return [];
80
80
  }
81
81
  const rule = 'unclosed-comment', { lintConfig } = index_1.default, s = lintConfig.getSeverity(rule);
82
- /* istanbul ignore if */
82
+ /* c8 ignore next 3 */
83
83
  if (!s) {
84
84
  return [];
85
85
  }
@@ -69,7 +69,7 @@ let DoubleUnderscoreToken = (() => {
69
69
  */
70
70
  constructor(word, sensitive, fullWidth, config, accum) {
71
71
  super(word, config, accum);
72
- const lc = word.toLowerCase(), { doubleUnderscore: [, , iAlias, sAlias] } = config;
72
+ const lc = word.toLowerCase(), [, , iAlias, sAlias] = config.doubleUnderscore;
73
73
  this.setAttribute('name', (sensitive ? sAlias?.[word]?.toLowerCase() : iAlias?.[lc]) ?? lc);
74
74
  this.#fullWidth = fullWidth;
75
75
  }
@@ -65,7 +65,7 @@ class QuoteToken extends base_1.NowikiBaseToken {
65
65
  startCol: endCol - length,
66
66
  endCol,
67
67
  };
68
- if (computeEditInfo) {
68
+ if (computeEditInfo && bold) {
69
69
  eNew.suggestions = [
70
70
  (0, lint_1.fixByEscape)(startIndex, '&apos;', length),
71
71
  (0, lint_1.fixByRemove)(eNew),
@@ -192,7 +192,7 @@ let TableToken = (() => {
192
192
  && (isRow)) {
193
193
  return this;
194
194
  }
195
- else if (isRow) {
195
+ if (isRow) {
196
196
  n--;
197
197
  }
198
198
  for (const child of this.childNodes.slice(2)) {
@@ -130,12 +130,12 @@ let TdToken = (() => {
130
130
  }
131
131
  /** @private */
132
132
  toString(skip) {
133
- const { childNodes: [syntax, attr, inner] } = this;
133
+ const [syntax, attr, inner] = this.childNodes;
134
134
  return syntax.toString(skip) + attr.toString(skip) + this.#innerSyntax + inner.toString(skip);
135
135
  }
136
136
  /** @private */
137
137
  text() {
138
- const { childNodes: [syntax, attr, inner] } = this;
138
+ const [syntax, attr, inner] = this.childNodes;
139
139
  return syntax.text() + attr.text() + this.#innerSyntax + inner.text();
140
140
  }
141
141
  /** @private */
@@ -112,7 +112,7 @@ let HtmlToken = (() => {
112
112
  }
113
113
  /** @private */
114
114
  text() {
115
- const { closing, selfClosing, name } = this, { html: [, , voidTags] } = this.getAttribute('config');
115
+ const { closing, selfClosing, name } = this, [, , voidTags] = this.getAttribute('config').html;
116
116
  if (voidTags.includes(name)) {
117
117
  return closing && name !== 'br' ? '' : super.text('/');
118
118
  }
@@ -153,7 +153,7 @@ let HtmlToken = (() => {
153
153
  }
154
154
  errors.push(e);
155
155
  }
156
- const { html: [, flexibleTags, voidTags] } = this.getAttribute('config'), isVoid = voidTags.includes(name), isFlexible = flexibleTags.includes(name), isNormal = !isVoid && !isFlexible;
156
+ const [, flexibleTags, voidTags] = this.getAttribute('config').html, isVoid = voidTags.includes(name), isFlexible = flexibleTags.includes(name), isNormal = !isVoid && !isFlexible;
157
157
  rule = 'unmatched-tag';
158
158
  if (closing && (selfClosing || isVoid) || selfClosing && isNormal) {
159
159
  s = lintConfig.getSeverity(rule, closing ? 'both' : 'selfClosing');
@@ -54,14 +54,15 @@ class TagToken extends index_1.Token {
54
54
  const { type, name, parentNode, closing, selfClosing, } = this;
55
55
  let isVoid = false, isFlexible = false;
56
56
  if (type === 'html') {
57
- const { html: [, flexibleTags, voidTags] } = this.getAttribute('config');
57
+ const [, flexibleTags, voidTags] = this.getAttribute('config').html;
58
58
  isVoid = voidTags.includes(name);
59
59
  isFlexible = flexibleTags.includes(name);
60
60
  }
61
61
  if (isVoid || isFlexible && selfClosing) { // 自封闭标签
62
62
  return this;
63
63
  }
64
- else /* istanbul ignore if */ if (!parentNode) {
64
+ /* c8 ignore next 3 */
65
+ if (!parentNode) {
65
66
  return undefined;
66
67
  }
67
68
  const { childNodes } = parentNode, i = childNodes.indexOf(this), siblings = closing ? childNodes.slice(0, i).reverse() : childNodes.slice(i + 1), stack = [this], { rev } = debug_1.Shadow;
@@ -71,7 +72,7 @@ class TagToken extends index_1.Token {
71
72
  continue;
72
73
  }
73
74
  else if (token.#closing === closing) {
74
- /* istanbul ignore if */
75
+ /* c8 ignore next 3 */
75
76
  if (type === 'tvar') {
76
77
  return undefined;
77
78
  }
@@ -191,7 +191,7 @@ let TranscludeToken = (() => {
191
191
  * @param modifier transclusion modifier / 引用修饰符
192
192
  */
193
193
  setModifier(modifier) {
194
- const { parserFunction: [, , raw, subst] } = this.getAttribute('config'), lcModifier = (0, string_1.removeComment)(modifier).trim();
194
+ const [, , raw, subst] = this.getAttribute('config').parserFunction, lcModifier = (0, string_1.removeComment)(modifier).trim();
195
195
  if (modifier && !lcModifier.endsWith(':')) {
196
196
  return false;
197
197
  }
@@ -20,10 +20,11 @@ exports.Shadow = {
20
20
  finish();
21
21
  return result;
22
22
  }
23
- catch (e) /* istanbul ignore next */ {
23
+ catch (e) /* c8 ignore start */ {
24
24
  finish();
25
25
  throw e;
26
26
  }
27
+ /* c8 ignore stop */
27
28
  },
28
29
  /** @private */
29
30
  internal(callback, Parser) {
package/dist/util/diff.js CHANGED
@@ -7,11 +7,11 @@ exports.info = exports.error = exports.diff = exports.cmd = void 0;
7
7
  const promises_1 = __importDefault(require("fs/promises"));
8
8
  const util_1 = __importDefault(require("util"));
9
9
  const child_process_1 = require("child_process");
10
- /* istanbul ignore next */
10
+ /* c8 ignore start */
11
11
  process.on('unhandledRejection', e => {
12
12
  console.error(e);
13
13
  });
14
- /* istanbul ignore next */
14
+ /* c8 ignore stop */
15
15
  /**
16
16
  * 将shell命令转化为Promise对象
17
17
  * @param command shell指令
@@ -31,6 +31,7 @@ const cmd = (command, args) => new Promise(resolve => {
31
31
  try {
32
32
  shell = (0, child_process_1.spawn)(command, args);
33
33
  timer = setTimeout(() => {
34
+ /* c8 ignore next */
34
35
  shell.kill('SIGINT');
35
36
  }, 60 * 1e3);
36
37
  let buf = '';
@@ -47,12 +48,13 @@ const cmd = (command, args) => new Promise(resolve => {
47
48
  r(undefined);
48
49
  });
49
50
  }
50
- catch {
51
+ catch /* c8 ignore start */ {
51
52
  r(undefined);
52
53
  }
54
+ /* c8 ignore stop */
53
55
  });
54
56
  exports.cmd = cmd;
55
- /* istanbul ignore next */
57
+ /* c8 ignore start */
56
58
  /**
57
59
  * 比较两个文件
58
60
  * @param oldStr 旧文本
@@ -77,17 +79,20 @@ const diff = async (oldStr, newStr, uid) => {
77
79
  await Promise.allSettled([promises_1.default.unlink(oldFile), promises_1.default.unlink(newFile)]);
78
80
  };
79
81
  exports.diff = diff;
80
- /* istanbul ignore next */
82
+ /* c8 ignore stop */
83
+ /* c8 ignore start */
81
84
  /** @implements */
82
85
  const error = (msg, ...args) => {
83
86
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
84
87
  console.error(util_1.default.styleText?.('red', msg) ?? msg, ...args);
85
88
  };
86
89
  exports.error = error;
87
- /* istanbul ignore next */
90
+ /* c8 ignore stop */
91
+ /* c8 ignore start */
88
92
  /** @implements */
89
93
  const info = (msg, ...args) => {
90
94
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
91
95
  console.info(util_1.default.styleText?.('green', msg) ?? msg, ...args);
92
96
  };
93
97
  exports.info = info;
98
+ /* c8 ignore stop */
@@ -21,7 +21,7 @@ exports.basic = basic;
21
21
  */
22
22
  const getCondition = (selector, scope, has) => {
23
23
  selector = selector.trim();
24
- /* istanbul ignore if */
24
+ /* c8 ignore next 3 */
25
25
  if (!selector) {
26
26
  return (() => true);
27
27
  }
@@ -57,10 +57,10 @@ const decodeHtml = (str) => {
57
57
  const { decodeHTMLStrict } = require('entities');
58
58
  return (s) => decodeHTMLStrict(s).replace(/\xA0/gu, ' ');
59
59
  }
60
- catch { }
60
+ catch /* c8 ignore next */ { }
61
61
  }
62
62
  /* NOT FOR BROWSER ONLY END */
63
- /* istanbul ignore next */
63
+ /* c8 ignore next */
64
64
  return exports.decodeHtmlBasic;
65
65
  })();
66
66
  return decodeHtmlResolved(str);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.35.0",
3
+ "version": "2.35.1",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -41,6 +41,7 @@
41
41
  "scripts": {
42
42
  "prepublishOnly": "npm run build:core",
43
43
  "build:core": "bash build.sh",
44
+ "build:define": "bash sed.sh -i \"s/pkg = \\$PKG/pkg = $(npm pkg get name)/; s/version = \\$VERSION/version = $(npm pkg get version)/\" dist/bin/config.js",
44
45
  "build": "npm run build:core",
45
46
  "diff": "bash diff.sh",
46
47
  "diff:stat": "f() { git diff --stat --ignore-all-space --color=always $1 $2 -- . | grep '\\.ts'; }; f",
@@ -49,7 +50,7 @@
49
50
  "lint:md": "markdownlint-cli2 '*.md'",
50
51
  "lint": "npm run lint:ts && npm run lint:json && npm run lint:md",
51
52
  "prof": "node dist/test/prof.js",
52
- "coverage": "nyc --cache-dir=./.cache/nyc npm run test:ci && node dist/script/coverage.js && open coverage/index.html",
53
+ "coverage": "tsc --declaration false --target es2024 && npm run build:define && c8 npm run test:ci && node dist/script/coverage.js && open coverage/index.html",
53
54
  "test:unit": "mocha dist/test/test.js",
54
55
  "test:parser": "LC_ALL=en.UTF-8 mocha dist/test/parserTests.js",
55
56
  "test": "npm run test:unit && npm run test:parser",
@@ -58,7 +59,7 @@
58
59
  "test:end": "pkill -x http-server",
59
60
  "test:real": "node dist/test/real.js"
60
61
  },
61
- "nyc": {
62
+ "c8": {
62
63
  "exclude": [
63
64
  "dist/bin/*.js",
64
65
  "dist/script/*.js",
@@ -72,51 +73,51 @@
72
73
  },
73
74
  "dependencies": {
74
75
  "@bhsd/cm-util": "^0.1.0",
75
- "@bhsd/common": "^1.3.0",
76
+ "@bhsd/common": "^1.3.1",
76
77
  "@bhsd/stylelint-util": "^1.0.1",
77
78
  "binary-search": "^1.3.6",
78
79
  "vscode-languageserver-types": "^3.17.5"
79
80
  },
80
81
  "optionalDependencies": {
81
82
  "color-name": "^2.0.0",
82
- "entities": "^7.0.0",
83
+ "entities": "^7.0.1",
83
84
  "mathoid-texvcjs": "^0.6.0",
84
- "minimatch": "^10.1.1",
85
- "stylelint": "^17.0.0",
86
- "vscode-css-languageservice": "^6.3.8",
87
- "vscode-html-languageservice": "^5.6.0",
88
- "vscode-json-languageservice": "^5.6.3"
85
+ "minimatch": "^10.1.2",
86
+ "stylelint": "^17.1.1",
87
+ "vscode-css-languageservice": "^6.3.9",
88
+ "vscode-html-languageservice": "^5.6.1",
89
+ "vscode-json-languageservice": "^5.7.1"
89
90
  },
90
91
  "devDependencies": {
91
- "@bhsd/code-standard": "^1.3.2",
92
+ "@bhsd/code-standard": "^2.0.0",
92
93
  "@bhsd/nodejs": "^0.1.0",
93
94
  "@bhsd/test-util": "^0.3.0",
94
- "@stylistic/eslint-plugin": "^5.5.0",
95
+ "@stylistic/eslint-plugin": "^5.7.1",
95
96
  "@types/color-name": "^2.0.0",
96
97
  "@types/color-rgba": "^2.1.3",
97
98
  "@types/mocha": "^10.0.10",
98
- "@types/node": "^24.10.1",
99
- "@typescript-eslint/eslint-plugin": "^8.46.4",
100
- "@typescript-eslint/parser": "^8.46.4",
99
+ "@types/node": "^24.10.11",
100
+ "@typescript-eslint/eslint-plugin": "^8.54.0",
101
+ "@typescript-eslint/parser": "^8.54.0",
102
+ "c8": "^10.1.3",
101
103
  "color-rgba": "^3.0.0",
102
104
  "diff2html-cli": "^5.2.15",
103
- "esbuild": "^0.25.12",
104
- "eslint": "^9.39.1",
105
+ "esbuild": "^0.27.3",
106
+ "eslint": "^9.39.2",
105
107
  "eslint-plugin-eslint-comments": "^3.2.0",
106
- "eslint-plugin-jsdoc": "^61.2.1",
108
+ "eslint-plugin-jsdoc": "^62.5.3",
107
109
  "eslint-plugin-jsonc": "^2.21.0",
108
- "eslint-plugin-n": "^17.23.1",
110
+ "eslint-plugin-n": "^17.23.2",
109
111
  "eslint-plugin-promise": "^7.2.1",
110
- "eslint-plugin-regexp": "^2.10.0",
112
+ "eslint-plugin-regexp": "^3.0.0",
111
113
  "eslint-plugin-unicorn": "^62.0.0",
112
- "markdownlint-cli2": "^0.19.0",
114
+ "markdownlint-cli2": "^0.20.0",
113
115
  "mocha": "^11.7.5",
114
- "nyc": "^17.1.0",
115
116
  "typescript": "^5.9.3",
116
117
  "v8r": "^5.1.0",
117
118
  "vscode-languageserver-textdocument": "^1.0.12"
118
119
  },
119
120
  "engines": {
120
- "node": ">=20.19.5"
121
+ "node": ">=20.19.0"
121
122
  }
122
123
  }