wikilint 2.33.0 → 2.35.0

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.
@@ -41,6 +41,7 @@
41
41
  "templatedata",
42
42
  "timeline",
43
43
  "page-collection",
44
+ "wish",
44
45
  "img"
45
46
  ],
46
47
  "html": [
package/dist/base.d.mts CHANGED
@@ -44,7 +44,7 @@ export declare const stages: {
44
44
  converter: number;
45
45
  };
46
46
  export type Stage = keyof typeof stages;
47
- export declare const rules: readonly ["arg-in-ext", "bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "syntax-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css", "invalid-math"];
47
+ export declare const rules: readonly ["arg-in-ext", "bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-json", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "syntax-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css", "invalid-math"];
48
48
  export declare namespace LintError {
49
49
  type Severity = 'error' | 'warning';
50
50
  type Rule = typeof rules[number];
package/dist/base.d.ts CHANGED
@@ -44,7 +44,7 @@ export declare const stages: {
44
44
  converter: number;
45
45
  };
46
46
  export type Stage = keyof typeof stages;
47
- export declare const rules: readonly ["arg-in-ext", "bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "syntax-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css", "invalid-math"];
47
+ export declare const rules: readonly ["arg-in-ext", "bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-json", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "syntax-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css", "invalid-math"];
48
48
  export declare namespace LintError {
49
49
  type Severity = 'error' | 'warning';
50
50
  type Rule = typeof rules[number];
package/dist/base.js CHANGED
@@ -44,6 +44,7 @@ exports.rules = (() => {
44
44
  'invalid-imagemap',
45
45
  'invalid-invoke',
46
46
  'invalid-isbn',
47
+ 'invalid-json',
47
48
  'invalid-url',
48
49
  'lonely-apos',
49
50
  'lonely-bracket',
package/dist/base.mjs CHANGED
@@ -41,6 +41,7 @@ const rules = /* @__PURE__ */ (() => {
41
41
  "invalid-imagemap",
42
42
  "invalid-invoke",
43
43
  "invalid-isbn",
44
+ "invalid-json",
44
45
  "invalid-url",
45
46
  "lonely-apos",
46
47
  "lonely-bracket",
package/dist/bin/cli.js CHANGED
@@ -7,21 +7,8 @@ Object.defineProperty(exports, "__esModule", { value: true });
7
7
  const fs_1 = __importDefault(require("fs"));
8
8
  const path_1 = __importDefault(require("path"));
9
9
  const assert_1 = __importDefault(require("assert"));
10
+ const util_1 = __importDefault(require("util"));
10
11
  const index_1 = __importDefault(require("../index"));
11
- const chalk = (() => {
12
- try {
13
- return require('chalk');
14
- }
15
- catch {
16
- const f = ((text) => text), proxy = new Proxy(f, {
17
- /** @private */
18
- get() {
19
- return proxy;
20
- },
21
- });
22
- return proxy;
23
- }
24
- })();
25
12
  const man = `
26
13
  Available options:
27
14
  -c, --config <path or preset config> Choose parser's configuration
@@ -159,11 +146,13 @@ const throwOnCacheFile = (input) => {
159
146
  * @param word item name
160
147
  */
161
148
  const plural = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`;
149
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
150
+ const styleText = util_1.default.styleText ?? ((_, text) => text);
162
151
  /**
163
152
  * color the severity
164
153
  * @param severity problem severity
165
154
  */
166
- const coloredSeverity = (severity) => chalk[severity === 'error' ? 'red' : 'yellow'](severity.padEnd(7));
155
+ const coloredSeverity = (severity) => styleText(severity === 'error' ? 'red' : 'yellow', severity.padEnd(7));
167
156
  for (let i = 2; i < argv.length; i++) {
168
157
  option = argv[i];
169
158
  switch (option) {
@@ -374,10 +363,10 @@ catch {
374
363
  nFixableWarn += nLocalFixableWarn;
375
364
  }
376
365
  if (problems.length > 0) {
377
- console.error(`\n${chalk.underline('%s')}`, file);
366
+ console.error('\n%s', styleText('underline', file));
378
367
  const maxLineChars = String(Math.max(...problems.map(({ startLine }) => startLine))).length, maxColChars = String(Math.max(...problems.map(({ startCol }) => startCol))).length, maxMessageChars = Math.max(...problems.map(({ message: { length } }) => length));
379
368
  for (const { rule, message, severity, startLine, startCol } of problems) {
380
- console.error(` ${chalk.dim('%s:%s')} %s %s ${chalk.dim('%s')}`, String(startLine).padStart(maxLineChars), String(startCol).padEnd(maxColChars), coloredSeverity(severity), message.padEnd(maxMessageChars), rule);
369
+ console.error(` ${styleText('dim', '%s:%s')} %s %s %s`, String(startLine).padStart(maxLineChars), String(startCol).padEnd(maxColChars), coloredSeverity(severity), message.padEnd(maxMessageChars), styleText('dim', rule));
381
370
  }
382
371
  }
383
372
  nErr += nLocalErr;
@@ -385,9 +374,9 @@ catch {
385
374
  exiting ||= Boolean(nLocalErr || strict && nLocalWarn);
386
375
  }
387
376
  if (nErr || nWarn) {
388
- console.error(chalk.red.bold('%s'), `\n✖ ${plural(nErr + nWarn, 'problem')} (${plural(nErr, 'error')}, ${plural(nWarn, 'warning')})`);
377
+ console.error(styleText(['red', 'bold'], '%s'), `\n✖ ${plural(nErr + nWarn, 'problem')} (${plural(nErr, 'error')}, ${plural(nWarn, 'warning')})`);
389
378
  if (nFixableErr || nFixableWarn) {
390
- console.error(chalk.red.bold('%s'), ` ${plural(nFixableErr, 'error')} and ${plural(nFixableWarn, 'warning')} potentially fixable with the \`--fix\` option.`);
379
+ console.error(styleText(['red', 'bold'], '%s'), ` ${plural(nFixableErr, 'error')} and ${plural(nFixableWarn, 'warning')} potentially fixable with the \`--fix\` option.`);
391
380
  }
392
381
  console.error();
393
382
  }
@@ -77,7 +77,7 @@ const mw = {
77
77
  },
78
78
  },
79
79
  };
80
- const pkg = "wikilint", version = "2.33.0";
80
+ const pkg = "wikilint", version = "2.35.0";
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 }, magicwords, namespaces, namespacealiases, functionhooks, }, } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json();
125
+ }, { query: { general: { articlepath, variants, langconversion }, magicwords, namespaces, namespacealiases, functionhooks, }, } = await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json();
126
126
  try {
127
127
  eval(m); // eslint-disable-line no-eval
128
128
  }
@@ -140,7 +140,7 @@ exports.default = async (site, url, user, force, internal) => {
140
140
  ]), config = {
141
141
  ...(0, cm_util_1.getParserConfig)(require(path_1.default.join(dir, 'minimum')), mwConfig),
142
142
  ...(0, cm_util_1.getKeywords)(magicwords),
143
- variants: (0, cm_util_1.getVariants)(variants),
143
+ variants: langconversion ? (0, cm_util_1.getVariants)(variants) : [],
144
144
  namespaces: Object.fromEntries(ns),
145
145
  nsid: Object.fromEntries([
146
146
  ...ns.map(([id, canonical]) => [canonical.toLowerCase(), Number(id)]),
package/dist/index.js CHANGED
@@ -172,11 +172,9 @@ const Parser = {
172
172
  maxStage ??= constants_1.MAX_STAGE;
173
173
  config ??= this.getConfig();
174
174
  let types;
175
- LINT: {
176
- if (typeof maxStage !== 'number') {
177
- types = Array.isArray(maxStage) ? maxStage : [maxStage];
178
- maxStage = Math.max(...types.map(t => base_1.stages[t] || constants_1.MAX_STAGE));
179
- }
175
+ LINT: if (typeof maxStage !== 'number') {
176
+ types = Array.isArray(maxStage) ? maxStage : [maxStage];
177
+ maxStage = Math.max(...types.map(t => base_1.stages[t] || constants_1.MAX_STAGE));
180
178
  }
181
179
  const { Token } = require('./src/index');
182
180
  const root = debug_1.Shadow.run(() => {
@@ -45,5 +45,8 @@ export type { GalleryToken } from './src/multiLine/gallery';
45
45
  export type { ImagemapLinkToken } from './src/imagemapLink';
46
46
  export type { ImagemapToken } from './src/multiLine/imagemap';
47
47
  export type { CommentedToken } from './src/commented';
48
+ export type { CategorytreeToken } from './src/link/categorytree';
49
+ export type { ParamLineToken } from './src/paramLine';
50
+ export type { CommentLineToken } from './src/nowiki/commentLine';
48
51
  export type { TranslateToken } from './src/tagPair/translate';
49
52
  export type { TvarToken } from './src/tag/tvar';
@@ -72,6 +72,12 @@ const defaultLintRuleConfig = {
72
72
  },
73
73
  ],
74
74
  'invalid-isbn': 2,
75
+ 'invalid-json': [
76
+ 2,
77
+ {
78
+ duplicate: 1,
79
+ },
80
+ ],
75
81
  'invalid-url': 1,
76
82
  'lonely-apos': [
77
83
  1,
package/dist/lib/lsp.js CHANGED
@@ -820,8 +820,21 @@ class LanguageService {
820
820
  async provideDiagnostics(text, warning = true) {
821
821
  const root = await this.#queue(text), { lintConfig } = index_1.default, needFix = lintConfig.fix;
822
822
  lintConfig.fix = false;
823
+ /* NOT FOR BROWSER ONLY */
824
+ const stylelint = await (0, document_1.loadStylelint)(), jsonLSP = (0, document_1.loadJsonLSP)();
825
+ let s;
826
+ NPM: if (jsonLSP) {
827
+ s = lintConfig.rules['invalid-json'];
828
+ lintConfig.rules['invalid-json'] = 0;
829
+ }
830
+ /* NOT FOR BROWSER ONLY END */
823
831
  const errors = root.lint();
824
832
  lintConfig.fix = needFix;
833
+ /* NOT FOR BROWSER ONLY */
834
+ NPM: if (jsonLSP) {
835
+ lintConfig.rules['invalid-json'] = s;
836
+ }
837
+ /* NOT FOR BROWSER ONLY END */
825
838
  const diagnostics = (warning ? errors : errors.filter(({ severity }) => severity === 'error')).map(({ startLine, startCol, endLine, endCol, severity, rule, message, fix, suggestions,
826
839
  /* NOT FOR BROWSER ONLY */
827
840
  code, }) => ({
@@ -843,9 +856,6 @@ class LanguageService {
843
856
  ...suggestions ? suggestions.map(suggestion => getQuickFix(root, suggestion)) : [],
844
857
  ],
845
858
  })),
846
- /* NOT FOR BROWSER ONLY */
847
- stylelint = await (0, document_1.loadStylelint)(), jsonLSP = (0, document_1.loadJsonLSP)(),
848
- /* NOT FOR BROWSER ONLY END */
849
859
  /* eslint-disable @stylistic/operator-linebreak */
850
860
  cssDiagnostics = stylelint ?
851
861
  await (async () => {
package/dist/lib/node.js CHANGED
@@ -39,6 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.AstNode = void 0;
41
41
  /* eslint-disable @typescript-eslint/no-base-to-string */
42
+ const common_1 = require("@bhsd/common");
42
43
  const search_1 = __importDefault(require("../util/search"));
43
44
  const lint_1 = require("../util/lint");
44
45
  const debug_1 = require("../util/debug");
@@ -141,7 +142,7 @@ let AstNode = (() => {
141
142
  * @param left column number / 列号
142
143
  */
143
144
  indexFromPos(top, left) {
144
- LSP: {
145
+ LINT: {
145
146
  if (top < 0 || left < 0) {
146
147
  return undefined;
147
148
  }
@@ -248,16 +249,7 @@ let AstNode = (() => {
248
249
  * @since v1.16.3
249
250
  */
250
251
  getLines() {
251
- LINT: {
252
- const results = [];
253
- let start = 0;
254
- for (const line of String(this).split('\n')) {
255
- const end = start + line.length;
256
- results.push([line, start, end]);
257
- start = end + 1;
258
- }
259
- return results;
260
- }
252
+ LINT: return (0, common_1.splitLines)(String(this));
261
253
  }
262
254
  };
263
255
  return AstNode = _classThis;
package/dist/lib/text.js CHANGED
@@ -114,9 +114,15 @@ class AstText extends node_1.AstNode {
114
114
  ...lintConfig.getSeverity('tag-like', 'disallowed') ? disallowedTags : [],
115
115
  ]);
116
116
  for (let mt = errorRegex.exec(data); mt; mt = errorRegex.exec(data)) {
117
- const [, tag, prefix] = mt;
118
117
  let { index, 0: error } = mt;
119
- if (prefix && prefix !== ']') {
118
+ const [, tag, prefix] = mt, lbrackInExtLinkText = error === '[' && type === 'ext-link-text';
119
+ if (error.startsWith('<') && !tags.has(tag.toLowerCase())
120
+ || lbrackInExtLinkText && (/&(?:rbrack|#93|#x5[Dd];);/u.test(data.slice(index + 1))
121
+ || nextSibling?.is('ext') && nextName === 'nowiki'
122
+ && nextSibling.innerText?.includes(']'))) {
123
+ continue;
124
+ }
125
+ else if (prefix && prefix !== ']') {
120
126
  const { length } = prefix;
121
127
  index += length;
122
128
  error = error.slice(length);
@@ -126,20 +132,14 @@ class AstText extends node_1.AstNode {
126
132
  error = error.slice(1);
127
133
  }
128
134
  error = error.toLowerCase();
129
- const [char] = error, magicLink = char === 'r' || char === 'p' || char === 'i', lbrace = char === '{', rbrace = char === '}', lbrack = char === '[', rbrack = char === ']';
135
+ const [char] = error, magicLink = error === 'rfc' || error === 'pmid' || error === 'isbn', lbrace = char === '{', rbrace = char === '}', lbrack = char === '[', rbrack = char === ']';
130
136
  let { length } = error;
131
- if (char === '<' && !tags.has(tag.toLowerCase())
132
- || lbrack && type === 'ext-link-text' && (/&(?:rbrack|#93|#x5[Dd];);/u.test(data.slice(index + 1))
133
- || nextSibling?.is('ext') && nextName === 'nowiki'
134
- && nextSibling.innerText?.includes(']'))) {
135
- continue;
136
- }
137
- else if (rbrack && (index || length > 1)) {
137
+ if (rbrack && (index || length > 1)) {
138
138
  errorRegex.lastIndex--;
139
139
  }
140
140
  // Rule & Severity
141
141
  let startIndex = start + index, endIndex = startIndex + length, rule, severity, endLine, endCol;
142
- const nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], leftBracket = lbrace || lbrack, lConverter = lbrace && previousChar === '-' && variants.length > 0, rConverter = rbrace && nextChar === '-' && variants.length > 0, brokenExtLink = lbrack && nextType === 'free-ext-link' && !data.slice(index + 1).trim()
142
+ const nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], leftBracket = lbrace || lbrack, lConverter = error === '{' && previousChar === '-' && variants.length > 0, rConverter = error === '}' && nextChar === '-' && variants.length > 0, brokenExtLink = lbrack && nextType === 'free-ext-link' && !data.slice(index + 1).trim()
143
143
  || rbrack && previousType === 'free-ext-link'
144
144
  && !data.slice(0, index).includes(']');
145
145
  if (magicLink) {
@@ -190,7 +190,7 @@ class AstText extends node_1.AstNode {
190
190
  severity = lintConfig.getSeverity(rule, 'double');
191
191
  }
192
192
  else {
193
- if (!lbrack || type !== 'ext-link-text') {
193
+ if (!lbrackInExtLinkText) {
194
194
  const regex = regexes[char], remains = leftBracket ? data.slice(index + 1) : data.slice(0, index);
195
195
  if (lbrace && regex.exec(remains)?.[0] === '}'
196
196
  || rbrace && regex.exec(remains)?.[0] === '{') {
@@ -272,11 +272,11 @@ class AstText extends node_1.AstNode {
272
272
  else if (char === 'h' && type !== 'link-text' && wordRegex.test(previousChar || '')) {
273
273
  e.suggestions = [(0, lint_1.fixBySpace)(startIndex)];
274
274
  }
275
- else if (lbrack && type === 'ext-link-text') {
275
+ else if (lbrackInExtLinkText) {
276
276
  const i = parentNode.getAbsoluteIndex() + parentNode.toString().length;
277
277
  e.suggestions = [(0, lint_1.fixByEscape)(i, '&#93;')];
278
278
  }
279
- else if (rbrack && brokenExtLink) {
279
+ else if (error === ']' && brokenExtLink) {
280
280
  const i = start - previousSibling.toString().length;
281
281
  e.suggestions = [(0, lint_1.fixByInsert)(i, 'left-bracket', '[')];
282
282
  }
@@ -23,7 +23,7 @@ const parseMagicLinks = (wikitext, config, accum) => {
23
23
  let url = lead ? m.slice(lead.length) : m;
24
24
  if (p1) {
25
25
  let trail = '';
26
- const m2 = /&(?:lt|gt|nbsp|#x0*(?:3[ce]|a0)|#0*(?:6[02]|160));/iu.exec(url);
26
+ const m2 = /&(?:[lg]t|nbsp|#x0*(?:3[ce]|a0)|#0*(?:6[02]|160));/iu.exec(url);
27
27
  if (m2) {
28
28
  trail = url.slice(m2.index);
29
29
  url = url.slice(0, m2.index);
@@ -38,5 +38,4 @@ export declare abstract class AttributeToken extends Token {
38
38
  * 获取属性值
39
39
  */
40
40
  getValue(): string | true;
41
- escape(): void;
42
41
  }
@@ -14,7 +14,7 @@ const index_2 = require("./index");
14
14
  const atom_1 = require("./atom");
15
15
  /* NOT FOR BROWSER ONLY */
16
16
  const document_1 = require("../lib/document");
17
- const insecureStyle = /expression|(?:accelerator|-o-link(?:-source)?|-o-replace)\s*:|(?:url|src|image(?:-set)?)\s*\(|attr\s*\([^)]+[\s,]url/u, evil = /(?:^|\s|\*\/)(?:javascript|vbscript)(?:\W|$)/iu, complexTypes = new Set(['ext', 'arg', 'magic-word', 'template']), urlAttrs = new Set([
17
+ const insecureStyle = /expression|(?:accelerator|-o-link(?:-source)?|-o-replace)\s*:|(?:url|src|image(?:-set)?)\s*\(|attr\s*\([^)]+[\s,]url/u, evil = /(?:^|\s|\*\/)(?:java|vb)script(?:\W|$)/iu, complexTypes = new Set(['ext', 'arg', 'magic-word', 'template']), urlAttrs = new Set([
18
18
  'about',
19
19
  'property',
20
20
  'resource',
@@ -250,12 +250,11 @@ class AttributeToken extends index_2.Token {
250
250
  getValue() {
251
251
  return this.#equal ? this.lastChild.text().trim() : this.type === 'ext-attr' || '';
252
252
  }
253
+ /** @private */
253
254
  escape() {
254
- LSP: {
255
- if (this.type !== 'ext-attr') {
256
- this.#equal = '{{=}}';
257
- this.lastChild.escape();
258
- }
255
+ LSP: if (this.type !== 'ext-attr') {
256
+ this.#equal = '{{=}}';
257
+ this.lastChild.escape();
259
258
  }
260
259
  }
261
260
  }
@@ -60,6 +60,5 @@ export declare abstract class AttributesToken extends Token {
60
60
  * @param key attribute name / 属性键
61
61
  */
62
62
  getAttr(key: string): string | true | undefined;
63
- escape(): void;
64
63
  }
65
64
  export {};
@@ -195,11 +195,10 @@ class AttributesToken extends index_2.Token {
195
195
  return errors;
196
196
  }
197
197
  }
198
+ /** @private */
198
199
  escape() {
199
- LSP: {
200
- if (this.type !== 'ext-attrs') {
201
- super.escape();
202
- }
200
+ LSP: if (this.type !== 'ext-attrs') {
201
+ super.escape();
203
202
  }
204
203
  }
205
204
  }
@@ -16,6 +16,4 @@ export declare abstract class CategorytreeToken extends LinkBaseToken {
16
16
  get type(): 'ext-inner';
17
17
  /** @param link 链接标题 */
18
18
  constructor(link: string, linkText?: undefined, config?: Config, accum?: Token[]);
19
- getTitle(): Title;
20
- lint(start?: number): LintError[];
21
19
  }
@@ -69,12 +69,14 @@ let CategorytreeToken = (() => {
69
69
  super(link, linkText, config, accum);
70
70
  this.setAttribute('bracket', false);
71
71
  }
72
+ /** @private */
72
73
  getTitle() {
73
74
  const target = this.firstChild.toString().trim(), opt = { halfParsed: true }, title = this.normalizeTitle(target, 14, opt);
74
75
  return title.valid && title.ns === 14
75
76
  ? title
76
77
  : this.normalizeTitle(`Category:${target}`, 0, opt);
77
78
  }
79
+ /** @private */
78
80
  lint(start = this.getAbsoluteIndex()) {
79
81
  LINT: {
80
82
  const rule = 'no-ignored', s = index_1.default.lintConfig.getSeverity(rule, 'categorytree');
@@ -6,6 +6,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.NowikiToken = void 0;
7
7
  const common_1 = require("@bhsd/common");
8
8
  const lint_1 = require("../../util/lint");
9
+ const rect_1 = require("../../lib/rect");
9
10
  const index_1 = __importDefault(require("../../index"));
10
11
  const base_1 = require("./base");
11
12
  /* NOT FOR BROWSER ONLY */
@@ -42,9 +43,9 @@ class NowikiToken extends base_1.NowikiBaseToken {
42
43
  /** @private */
43
44
  lint(start = this.getAbsoluteIndex()) {
44
45
  LINT: {
45
- const { name,
46
+ const { name, innerText,
46
47
  /* NOT FOR BROWSER ONLY */
47
- innerText, previousSibling, } = this, { lintConfig } = index_1.default;
48
+ previousSibling, } = this, { lintConfig } = index_1.default;
48
49
  let rule = 'void-ext', s = lintConfig.getSeverity(rule, name);
49
50
  if (s && this.#lint()) {
50
51
  const e = (0, lint_1.generateForSelf)(this, { start }, rule, index_1.default.msg('nothing-in', name), s);
@@ -53,9 +54,42 @@ class NowikiToken extends base_1.NowikiBaseToken {
53
54
  }
54
55
  return [e];
55
56
  }
56
- const errors = super.lint(start, getLintRegex(name));
57
- /* NOT FOR BROWSER ONLY */
58
57
  NPM: {
58
+ rule = 'invalid-json';
59
+ const sSyntax = lintConfig.getSeverity(rule);
60
+ /* NOT FOR BROWSER ONLY */
61
+ const sDuplicate = lintConfig.getSeverity(rule, 'duplicate');
62
+ /* NOT FOR BROWSER ONLY END */
63
+ if (name === 'templatedata' && (sSyntax
64
+ || sDuplicate)) {
65
+ // browser版本使用`lintJSONNative()`
66
+ return (0, common_1.lintJSON)(innerText).map(({ message, from, to = from, line, endLine = line, column, endColumn = column,
67
+ /* NOT FOR BROWSER ONLY */
68
+ severity, }) => {
69
+ s =
70
+ /* eslint-disable @stylistic/operator-linebreak */
71
+ severity === 'warning' ?
72
+ sDuplicate :
73
+ /* eslint-enable @stylistic/operator-linebreak */
74
+ sSyntax;
75
+ if (!s) {
76
+ return false;
77
+ }
78
+ const rect = new rect_1.BoundingRect(this, start);
79
+ return {
80
+ rule,
81
+ message,
82
+ severity: s,
83
+ startIndex: start + from,
84
+ endIndex: start + to,
85
+ startLine: rect.top + line - 1,
86
+ endLine: rect.top + endLine - 1,
87
+ startCol: (line > 1 ? 0 : rect.left) + column - 1,
88
+ endCol: (endLine > 1 ? 0 : rect.left) + endColumn - 1,
89
+ };
90
+ }).filter((e) => e !== false);
91
+ }
92
+ /* NOT FOR BROWSER ONLY */
59
93
  rule = 'invalid-math';
60
94
  s = lintConfig.getSeverity(rule);
61
95
  if (s && constants_1.mathTags.has(name)) {
@@ -84,20 +118,21 @@ class NowikiToken extends base_1.NowikiBaseToken {
84
118
  const result = texvcjs.check(tex, {
85
119
  usemhchem: isChem || Boolean(previousSibling?.hasAttr('chem')),
86
120
  });
87
- if (result.status !== '+') {
88
- const e = (0, lint_1.generateForSelf)(this, { start }, rule, 'chem-required', s);
89
- if (result.status !== 'C') {
90
- const { message, location } = result.error, [endIndex, endLine, endCol] = updateLocation(e, location.end, n);
91
- [e.startIndex, e.startLine, e.startCol] = updateLocation(e, location.start, n);
92
- Object.assign(e, { endIndex, endLine, endCol, message });
93
- }
94
- errors.push(e);
121
+ if (result.status === '+') {
122
+ return [];
123
+ }
124
+ const e = (0, lint_1.generateForSelf)(this, { start }, rule, 'chem-required', s);
125
+ if (result.status !== 'C') {
126
+ const { message, location } = result.error, [endIndex, endLine, endCol] = updateLocation(e, location.end, n);
127
+ [e.startIndex, e.startLine, e.startCol] = updateLocation(e, location.start, n);
128
+ Object.assign(e, { endIndex, endLine, endCol, message });
95
129
  }
130
+ return [e];
96
131
  }
97
132
  }
98
133
  }
99
134
  /* NOT FOR BROWSER ONLY END */
100
- return errors;
135
+ return super.lint(start, getLintRegex(name));
101
136
  }
102
137
  }
103
138
  }
@@ -7,5 +7,4 @@ import type { LintError } from '../../base';
7
7
  */
8
8
  export declare abstract class ListToken extends ListBaseToken {
9
9
  get type(): 'list';
10
- lint(start?: number): LintError[];
11
10
  }
@@ -17,6 +17,7 @@ class ListToken extends listBase_1.ListBaseToken {
17
17
  get type() {
18
18
  return 'list';
19
19
  }
20
+ /** @private */
20
21
  lint(start = this.getAbsoluteIndex()) {
21
22
  LINT: {
22
23
  const rule = 'syntax-like', s = index_1.default.lintConfig.getSeverity(rule, 'redirect'), { innerText } = this;
@@ -7,5 +7,4 @@ import type { LintError } from '../../base';
7
7
  */
8
8
  export declare abstract class NoincludeToken extends NowikiBaseToken {
9
9
  get type(): 'noinclude';
10
- lint(start?: number): LintError[];
11
10
  }
@@ -69,11 +69,12 @@ let NoincludeToken = (() => {
69
69
  toString(skip) {
70
70
  return skip ? '' : super.toString();
71
71
  }
72
+ /** @private */
72
73
  lint(start = this.getAbsoluteIndex()) {
73
74
  LINT: {
74
75
  const { lintConfig } = index_1.default, rule = 'no-ignored', s = lintConfig.getSeverity(rule, 'include');
75
76
  if (s) {
76
- const { innerText } = this, mt = /^<(noinclude|includeonly|onlyinclude)\s+(?:[^\s>/]|\/(?!>))[^>]*>$/iu.exec(innerText);
77
+ const { innerText } = this, mt = /^<(includeonly|(?:no|only)include)\s+(?:[^\s>/]|\/(?!>))[^>]*>$/iu.exec(innerText);
77
78
  if (mt) {
78
79
  const e = (0, lint_1.generateForSelf)(this, { start }, rule, 'useless-attribute', s), { computeEditInfo } = lintConfig, before = mt[1].length + 1, after = innerText.endsWith('/>') ? 2 : 1;
79
80
  e.startIndex += before;
@@ -24,6 +24,5 @@ export declare abstract class TableBaseToken extends Token {
24
24
  * @param attr 表格属性
25
25
  */
26
26
  constructor(pattern: RegExp, syntax: string | undefined, type: TableTypes, attr?: string, config?: Config, accum?: Token[], acceptable?: WikiParserAcceptable);
27
- escape(): void;
28
27
  }
29
28
  export {};
@@ -89,15 +89,14 @@ let TableBaseToken = (() => {
89
89
  // @ts-expect-error abstract class
90
90
  new attributes_1.AttributesToken(attr, 'table-attrs', type, config, accum));
91
91
  }
92
+ /** @private */
92
93
  escape() {
93
- LSP: {
94
- for (const child of this.childNodes) {
95
- if (child instanceof syntax_1.SyntaxToken) {
96
- escapeTable(child);
97
- }
98
- else {
99
- child.escape();
100
- }
94
+ LSP: for (const child of this.childNodes) {
95
+ if (child instanceof syntax_1.SyntaxToken) {
96
+ escapeTable(child);
97
+ }
98
+ else {
99
+ child.escape();
101
100
  }
102
101
  }
103
102
  }
@@ -39,6 +39,5 @@ export declare abstract class TdToken extends TableBaseToken {
39
39
  */
40
40
  isIndependent(): boolean;
41
41
  getAttr<T extends string>(key: T): TdAttrGetter<T>;
42
- escape(): void;
43
42
  }
44
43
  export {};
@@ -187,6 +187,7 @@ let TdToken = (() => {
187
187
  return (key === 'rowspan' || key === 'colspan' ? parseInt(value) || 1 : value);
188
188
  }
189
189
  }
190
+ /** @private */
190
191
  escape() {
191
192
  LSP: {
192
193
  super.escape();
@@ -10,13 +10,14 @@ export declare abstract class TagPairToken extends Token {
10
10
  #private;
11
11
  readonly name: string;
12
12
  closed: boolean;
13
- selfClosing: boolean;
14
13
  abstract get type(): 'ext' | 'include' | 'translate';
15
14
  readonly childNodes: readonly [AstNodes, AstNodes];
16
15
  abstract get firstChild(): AstNodes;
17
16
  abstract get lastChild(): AstNodes;
18
17
  /** inner wikitext / 内部wikitext */
19
18
  get innerText(): string | undefined;
19
+ /** whether to be self-closing / 是否自封闭 */
20
+ get selfClosing(): boolean;
20
21
  /**
21
22
  * @param name 标签名
22
23
  * @param attr 标签属性
@@ -59,11 +59,15 @@ let TagPairToken = (() => {
59
59
  __runInitializers(_classThis, _classExtraInitializers);
60
60
  }
61
61
  #tags;
62
+ #selfClosing;
62
63
  closed;
63
- selfClosing;
64
64
  /** inner wikitext / 内部wikitext */
65
65
  get innerText() {
66
- return this.selfClosing ? undefined : this.lastChild.text();
66
+ return this.#selfClosing ? undefined : this.lastChild.text();
67
+ }
68
+ /** whether to be self-closing / 是否自封闭 */
69
+ get selfClosing() {
70
+ return this.#selfClosing;
67
71
  }
68
72
  /**
69
73
  * @param name 标签名
@@ -76,22 +80,22 @@ let TagPairToken = (() => {
76
80
  this.setAttribute('name', name.toLowerCase());
77
81
  this.#tags = [name, closed || name];
78
82
  this.closed = closed !== '';
79
- this.selfClosing = closed === undefined;
83
+ this.#selfClosing = closed === undefined;
80
84
  this.append(attr, inner);
81
85
  const index = typeof attr === 'string' ? -1 : accum.indexOf(attr);
82
86
  accum.splice(index === -1 ? Infinity : index, 0, this);
83
87
  }
84
88
  /** @private */
85
89
  toString(skip) {
86
- const { selfClosing, firstChild, lastChild, } = this, [opening, closing] = this.#tags;
87
- return selfClosing
90
+ const { firstChild, lastChild, } = this, [opening, closing] = this.#tags;
91
+ return this.#selfClosing
88
92
  ? `<${opening}${firstChild.toString(skip)}/>`
89
93
  : `<${opening}${firstChild.toString(skip)}>${lastChild.toString(skip)}${this.closed ? `</${closing}>` : ''}`;
90
94
  }
91
95
  /** @private */
92
96
  text() {
93
97
  const [opening, closing] = this.#tags;
94
- return this.selfClosing
98
+ return this.#selfClosing
95
99
  ? `<${opening}${this.firstChild.text()}/>`
96
100
  : `<${opening}${super.text('>')}${this.closed ? `</${closing}>` : ''}`;
97
101
  }
@@ -9,12 +9,12 @@ import type { Config } from '../../base';
9
9
  export declare abstract class TranslateToken extends TagPairToken {
10
10
  name: 'translate';
11
11
  closed: true;
12
- selfClosing: false;
13
12
  readonly childNodes: readonly [SyntaxToken, Token];
14
13
  abstract get firstChild(): SyntaxToken;
15
14
  abstract get lastChild(): Token;
16
15
  abstract get innerText(): string;
17
16
  get type(): 'translate';
17
+ get selfClosing(): false;
18
18
  /**
19
19
  * @param attr 标签属性
20
20
  * @param inner 内部wikitext
@@ -13,6 +13,9 @@ class TranslateToken extends index_2.TagPairToken {
13
13
  get type() {
14
14
  return 'translate';
15
15
  }
16
+ get selfClosing() {
17
+ return false;
18
+ }
16
19
  /**
17
20
  * @param attr 标签属性
18
21
  * @param inner 内部wikitext
package/dist/util/diff.js CHANGED
@@ -3,8 +3,9 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.info = exports.error = exports.loadChalk = exports.diff = exports.cmd = void 0;
6
+ exports.info = exports.error = exports.diff = exports.cmd = void 0;
7
7
  const promises_1 = __importDefault(require("fs/promises"));
8
+ const util_1 = __importDefault(require("util"));
8
9
  const child_process_1 = require("child_process");
9
10
  /* istanbul ignore next */
10
11
  process.on('unhandledRejection', e => {
@@ -76,29 +77,17 @@ const diff = async (oldStr, newStr, uid) => {
76
77
  await Promise.allSettled([promises_1.default.unlink(oldFile), promises_1.default.unlink(newFile)]);
77
78
  };
78
79
  exports.diff = diff;
79
- let chalk;
80
- /* istanbul ignore next */
81
- const loadChalk = () => {
82
- if (chalk === undefined) {
83
- try {
84
- chalk = require('chalk');
85
- }
86
- catch {
87
- chalk = null;
88
- }
89
- }
90
- return chalk;
91
- };
92
- exports.loadChalk = loadChalk;
93
80
  /* istanbul ignore next */
94
81
  /** @implements */
95
82
  const error = (msg, ...args) => {
96
- console.error((0, exports.loadChalk)()?.red(msg) ?? msg, ...args);
83
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
84
+ console.error(util_1.default.styleText?.('red', msg) ?? msg, ...args);
97
85
  };
98
86
  exports.error = error;
99
87
  /* istanbul ignore next */
100
88
  /** @implements */
101
89
  const info = (msg, ...args) => {
102
- console.info((0, exports.loadChalk)()?.green(msg) ?? msg, ...args);
90
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
91
+ console.info(util_1.default.styleText?.('green', msg) ?? msg, ...args);
103
92
  };
104
93
  exports.info = info;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.33.0",
3
+ "version": "2.35.0",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -72,18 +72,17 @@
72
72
  },
73
73
  "dependencies": {
74
74
  "@bhsd/cm-util": "^0.1.0",
75
- "@bhsd/common": "^1.0.1",
76
- "@bhsd/stylelint-util": "^0.1.0",
75
+ "@bhsd/common": "^1.3.0",
76
+ "@bhsd/stylelint-util": "^1.0.1",
77
77
  "binary-search": "^1.3.6",
78
78
  "vscode-languageserver-types": "^3.17.5"
79
79
  },
80
80
  "optionalDependencies": {
81
- "chalk": "^4.1.2",
82
81
  "color-name": "^2.0.0",
83
82
  "entities": "^7.0.0",
84
83
  "mathoid-texvcjs": "^0.6.0",
85
84
  "minimatch": "^10.1.1",
86
- "stylelint": "^16.26.1",
85
+ "stylelint": "^17.0.0",
87
86
  "vscode-css-languageservice": "^6.3.8",
88
87
  "vscode-html-languageservice": "^5.6.0",
89
88
  "vscode-json-languageservice": "^5.6.3"
@@ -91,7 +90,7 @@
91
90
  "devDependencies": {
92
91
  "@bhsd/code-standard": "^1.3.2",
93
92
  "@bhsd/nodejs": "^0.1.0",
94
- "@bhsd/test-util": "^0.2.1",
93
+ "@bhsd/test-util": "^0.3.0",
95
94
  "@stylistic/eslint-plugin": "^5.5.0",
96
95
  "@types/color-name": "^2.0.0",
97
96
  "@types/color-rgba": "^2.1.3",
@@ -118,6 +117,6 @@
118
117
  "vscode-languageserver-textdocument": "^1.0.12"
119
118
  },
120
119
  "engines": {
121
- "node": ">=18.17.0"
120
+ "node": ">=20.19.5"
122
121
  }
123
122
  }