wikilint 2.40.0 → 2.41.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.
package/README.md CHANGED
@@ -5,8 +5,8 @@
5
5
  [![npm version](https://badge.fury.io/js/wikilint.svg)](https://www.npmjs.com/package/wikilint)
6
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)
7
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)
8
- [![Codacy Badge](https://app.codacy.com/project/badge/Grade/a2fbe7641031451baca2947ae6d7891f)](https://app.codacy.com/gh/bhsd-harry/wikiparser-node/dashboard)
9
- ![Istanbul coverage](./coverage/badge.svg)
8
+ [![NPM downloads](https://img.shields.io/npm/dm/wikilint)](https://www.npmjs.com/package/wikilint)
9
+ ![Coverage](./coverage/badge.svg)
10
10
 
11
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.
12
12
 
@@ -242,6 +242,11 @@
242
242
  "description": "base URL of internal links",
243
243
  "type": "string",
244
244
  "pattern": "\\$1"
245
+ },
246
+ "server": {
247
+ "description": "base URL of the server",
248
+ "type": "string",
249
+ "pattern": "^(?:https?:)?//"
245
250
  }
246
251
  },
247
252
  "required": [
@@ -1465,7 +1465,7 @@
1465
1465
  "EXPECTUNUSEDTEMPLATE": "EXPECTUNUSEDTEMPLATE"
1466
1466
  }
1467
1467
  ],
1468
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
1468
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
1469
1469
  "interwiki": [],
1470
1470
  "img": {
1471
1471
  "thumbnail": "thumbnail",
@@ -591,7 +591,7 @@
591
591
  "EXPECTED_UNCONNECTED_PAGE": "EXPECTEDUNCONNECTEDPAGE"
592
592
  }
593
593
  ],
594
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
594
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
595
595
  "interwiki": [],
596
596
  "img": {
597
597
  "alt=$1": "alt",
@@ -632,5 +632,6 @@
632
632
  "#redirect"
633
633
  ],
634
634
  "variants": [],
635
- "articlePath": "/wiki/$1"
635
+ "articlePath": "/wiki/$1",
636
+ "server": "//en.wikipedia.org"
636
637
  }
@@ -899,7 +899,7 @@
899
899
  "EXPECTED_UNCONNECTED_PAGE": "EXPECTEDUNCONNECTEDPAGE"
900
900
  }
901
901
  ],
902
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
902
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
903
903
  "interwiki": [],
904
904
  "img": {
905
905
  "代替文=$1": "alt",
@@ -915,12 +915,14 @@
915
915
  "中央": "center",
916
916
  "center": "center",
917
917
  "centre": "center",
918
+ "class=$1": "class",
918
919
  "フレーム": "framed",
919
920
  "frame": "framed",
920
921
  "framed": "framed",
921
922
  "enframed": "framed",
922
923
  "フレームなし": "frameless",
923
924
  "frameless": "frameless",
925
+ "lang=$1": "lang",
924
926
  "左": "left",
925
927
  "left": "left",
926
928
  "リンク=$1": "link",
@@ -959,9 +961,7 @@
959
961
  "upright=$1": "upright",
960
962
  "upright $1": "upright",
961
963
  "$1ピクセル": "width",
962
- "$1px": "width",
963
- "class=$1": "class",
964
- "lang=$1": "lang"
964
+ "$1px": "width"
965
965
  },
966
966
  "redirection": [
967
967
  "#転送",
@@ -971,5 +971,6 @@
971
971
  "#redirect"
972
972
  ],
973
973
  "variants": [],
974
- "articlePath": "/wiki/$1"
974
+ "articlePath": "/wiki/$1",
975
+ "server": "//ja.wikipedia.org"
975
976
  }
@@ -1011,5 +1011,6 @@
1011
1011
  "zh-sg",
1012
1012
  "zh-tw"
1013
1013
  ],
1014
- "articlePath": "/zh/$1"
1014
+ "articlePath": "/zh/$1",
1015
+ "server": "//llwiki.org"
1015
1016
  }
@@ -125,7 +125,7 @@
125
125
  {},
126
126
  {}
127
127
  ],
128
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
128
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
129
129
  "interwiki": [],
130
130
  "img": {},
131
131
  "redirection": [
@@ -997,5 +997,6 @@
997
997
  "zh-hk",
998
998
  "zh-tw"
999
999
  ],
1000
- "articlePath": "/$1"
1000
+ "articlePath": "/$1",
1001
+ "server": "https://zh.moegirl.org.cn"
1001
1002
  }
@@ -961,7 +961,7 @@
961
961
  "EXPECTED_UNCONNECTED_PAGE": "EXPECTEDUNCONNECTEDPAGE"
962
962
  }
963
963
  ],
964
- "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:",
964
+ "protocol": "bitcoin:|ftp://|ftps://|geo:|git://|gopher://|http://|https://|irc://|ircs://|magnet:|mailto:|matrix:|mms://|news:|nntp://|redis://|sftp://|sip:|sips:|sms:|ssh://|svn://|tel:|telnet://|urn:|wikipedia://|worldwind://|xmpp:|commonsfinder://",
965
965
  "interwiki": [],
966
966
  "img": {
967
967
  "alt=$1": "alt",
@@ -1060,5 +1060,6 @@
1060
1060
  "zh-sg",
1061
1061
  "zh-tw"
1062
1062
  ],
1063
- "articlePath": "/wiki/$1"
1063
+ "articlePath": "/wiki/$1",
1064
+ "server": "//zh.wikipedia.org"
1064
1065
  }
package/dist/base.d.mts CHANGED
@@ -9,7 +9,6 @@ export interface Config {
9
9
  readonly parserFunction: [Record<string, string>, Record<string, string>, string[], string[]];
10
10
  readonly doubleUnderscore: [string[], string[], Record<string, string>, Record<string, string>];
11
11
  readonly protocol: string;
12
- readonly interwiki: string[];
13
12
  readonly img: Record<string, string>;
14
13
  readonly redirection: string[];
15
14
  readonly variants: string[];
@@ -267,8 +266,9 @@ export interface LanguageService {
267
266
  [Symbol.dispose](): void;
268
267
  }
269
268
  export type SeverityLevel = 0 | 1 | 2 | false | 'off' | 'warning' | 'error';
270
- export type LintConfigValue = SeverityLevel | [SeverityLevel, Record<string, SeverityLevel>?];
271
- export type LintRuleConfig = Partial<Record<LintError.Rule, LintConfigValue>>;
269
+ export type FullLintConfigValue = [SeverityLevel, Record<string, SeverityLevel>?];
270
+ export type LintConfigValue = SeverityLevel | FullLintConfigValue | Record<string, SeverityLevel>;
271
+ export type LintRuleConfig<T = LintConfigValue> = Partial<Record<LintError.Rule, T>>;
272
272
  export interface FullLintConfig {
273
273
  rules: LintRuleConfig;
274
274
  configurationComment?: string;
package/dist/base.d.ts CHANGED
@@ -9,7 +9,6 @@ export interface Config {
9
9
  readonly parserFunction: [Record<string, string>, Record<string, string>, string[], string[]];
10
10
  readonly doubleUnderscore: [string[], string[], Record<string, string>, Record<string, string>];
11
11
  readonly protocol: string;
12
- readonly interwiki: string[];
13
12
  readonly img: Record<string, string>;
14
13
  readonly redirection: string[];
15
14
  readonly variants: string[];
@@ -267,8 +266,9 @@ export interface LanguageService {
267
266
  [Symbol.dispose](): void;
268
267
  }
269
268
  export type SeverityLevel = 0 | 1 | 2 | false | 'off' | 'warning' | 'error';
270
- export type LintConfigValue = SeverityLevel | [SeverityLevel, Record<string, SeverityLevel>?];
271
- export type LintRuleConfig = Partial<Record<LintError.Rule, LintConfigValue>>;
269
+ export type FullLintConfigValue = [SeverityLevel, Record<string, SeverityLevel>?];
270
+ export type LintConfigValue = SeverityLevel | FullLintConfigValue | Record<string, SeverityLevel>;
271
+ export type LintRuleConfig<T = LintConfigValue> = Partial<Record<LintError.Rule, T>>;
272
272
  export interface FullLintConfig {
273
273
  rules: LintRuleConfig;
274
274
  configurationComment?: string;
package/dist/bin/cli.js CHANGED
@@ -148,7 +148,7 @@ const plural = (n, word) => `${n} ${word}${n === 1 ? '' : 's'}`;
148
148
  */
149
149
  const styleText = (format, text) => {
150
150
  if (!colors) {
151
- format = (Array.isArray(format) ? format : [format]).filter(f => !colorSet.has(f));
151
+ format = (Array.isArray(format) ? format : [format]).filter((f) => !colorSet.has(f));
152
152
  }
153
153
  return util_1.default.styleText(format, text);
154
154
  };
@@ -40,7 +40,7 @@ const filterGadget = (id) => {
40
40
  const n = Number(id);
41
41
  return n < 2300 || n > 2303; // Gadget, Gadget talk, Gadget definition, Gadget definition talk
42
42
  };
43
- const pkg = "wikilint", version = "2.40.0";
43
+ const pkg = "wikilint", version = "2.41.0";
44
44
  /**
45
45
  * Get the parser configuration for a Wikimedia Foundation project.
46
46
  * @param site site nickname
@@ -78,13 +78,7 @@ exports.default = async (site, url, user, force, internal) => {
78
78
  'User-Agent': `${pkg}/${version} (https://www.npmjs.com/package/${pkg}; ${user}) Node.js/${process.version}`,
79
79
  },
80
80
  }
81
- : undefined, m = await (await fetch(`${url}/load.php?modules=ext.CodeMirror.data|ext.CodeMirror`, headers)).text(), params = {
82
- action: 'query',
83
- meta: 'siteinfo',
84
- siprop: 'general|magicwords|functionhooks|namespaces|namespacealiases',
85
- format: 'json',
86
- formatversion: '2',
87
- }, { general: { articlepath, variants, langconversion }, magicwords, namespaces, namespacealiases, functionhooks, } = (await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json()).query, tempFile = path_1.default.join(__dirname, 'mw.js');
81
+ : undefined, m = await (await fetch(`${url}/load.php?modules=ext.CodeMirror.data|ext.CodeMirror`, headers)).text(), tempFile = path_1.default.join(__dirname, 'mw.js');
88
82
  fs_1.default.writeFileSync(tempFile, m);
89
83
  const { stdout, stderr } = (0, child_process_1.spawnSync)(process.execPath, [
90
84
  '-r',
@@ -108,13 +102,19 @@ exports.default = async (site, url, user, force, internal) => {
108
102
  catch {
109
103
  throw new RangeError('Extension:CodeMirror is not installed!');
110
104
  }
111
- const ns = Object.entries(namespaces).filter(([id]) => filterGadget(id))
105
+ const params = {
106
+ action: 'query',
107
+ meta: 'siteinfo',
108
+ siprop: `general|magicwords|namespaces|namespacealiases${mwConfig.functionHooks ? '' : '|functionhooks'}`,
109
+ format: 'json',
110
+ formatversion: '2',
111
+ }, { general: { articlepath, server, variants, langconversion }, magicwords, namespaces, namespacealiases, functionhooks, } = (await (await fetch(`${url}/api.php?${new URLSearchParams(params).toString()}`, headers)).json()).query, ns = Object.entries(namespaces).filter(([id]) => filterGadget(id))
112
112
  .flatMap(([id, { name, canonical = '' }]) => [
113
113
  [id, name],
114
114
  ...name === canonical ? [] : [[id, canonical]],
115
115
  ]), config = {
116
116
  ...(0, cm_util_1.getParserConfig)(require(path_1.default.join(dir, 'minimum.json')), mwConfig),
117
- ...(0, cm_util_1.getKeywords)(magicwords),
117
+ ...!(mwConfig.imageKeywords && mwConfig.redirection) && (0, cm_util_1.getKeywords)(magicwords),
118
118
  variants: langconversion ? (0, cm_util_1.getVariants)(variants) : [],
119
119
  namespaces: Object.fromEntries(ns),
120
120
  nsid: Object.fromEntries([
@@ -122,6 +122,7 @@ exports.default = async (site, url, user, force, internal) => {
122
122
  ...namespacealiases.filter(({ id }) => filterGadget(id)).map(({ id, alias }) => [alias.toLowerCase(), id]),
123
123
  ]),
124
124
  articlePath: articlepath,
125
+ server,
125
126
  }, { doubleUnderscore, parserFunction, variable } = config;
126
127
  doubleUnderscore[0] = [];
127
128
  doubleUnderscore[1] = [];
@@ -12,8 +12,8 @@ const dict = new Map([
12
12
  ['error', 'error'],
13
13
  ]);
14
14
  const defaultLintRuleConfig = {
15
- 'arg-in-ext': 1,
16
- 'blank-alt': 1,
15
+ 'arg-in-ext': [1],
16
+ 'blank-alt': [1],
17
17
  'bold-header': [
18
18
  1,
19
19
  {
@@ -47,7 +47,7 @@ const defaultLintRuleConfig = {
47
47
  // value: 2,
48
48
  },
49
49
  ],
50
- 'insecure-style': 2,
50
+ 'insecure-style': [2],
51
51
  'invalid-gallery': [
52
52
  2,
53
53
  {
@@ -72,14 +72,14 @@ const defaultLintRuleConfig = {
72
72
  // name: 2,
73
73
  },
74
74
  ],
75
- 'invalid-isbn': 2,
75
+ 'invalid-isbn': [2],
76
76
  'invalid-json': [
77
77
  2,
78
78
  {
79
79
  duplicate: 1,
80
80
  },
81
81
  ],
82
- 'invalid-url': 1,
82
+ 'invalid-url': [1],
83
83
  'lonely-apos': [
84
84
  1,
85
85
  {
@@ -110,7 +110,7 @@ const defaultLintRuleConfig = {
110
110
  // ref: 2,
111
111
  },
112
112
  ],
113
- 'no-arg': 1,
113
+ 'no-arg': [1],
114
114
  'no-duplicate': [
115
115
  2,
116
116
  {
@@ -144,8 +144,8 @@ const defaultLintRuleConfig = {
144
144
  // references: 2,
145
145
  },
146
146
  ],
147
- 'obsolete-attr': 1,
148
- 'obsolete-tag': 1,
147
+ 'obsolete-attr': [1],
148
+ 'obsolete-tag': [1],
149
149
  'parsing-order': [
150
150
  2,
151
151
  {
@@ -182,7 +182,7 @@ const defaultLintRuleConfig = {
182
182
  // redirect: 2,
183
183
  },
184
184
  ],
185
- 'table-layout': 1,
185
+ 'table-layout': [1],
186
186
  'tag-like': [
187
187
  2,
188
188
  {
@@ -190,17 +190,17 @@ const defaultLintRuleConfig = {
190
190
  invalid: 1,
191
191
  },
192
192
  ],
193
- 'unbalanced-header': 2,
193
+ 'unbalanced-header': [2],
194
194
  'unclosed-comment': [
195
195
  1,
196
196
  {
197
197
  // include: 1,
198
198
  },
199
199
  ],
200
- 'unclosed-quote': 1,
201
- 'unclosed-table': 2,
202
- unescaped: 2,
203
- 'unknown-page': 1,
200
+ 'unclosed-quote': [1],
201
+ 'unclosed-table': [2],
202
+ unescaped: [2],
203
+ 'unknown-page': [1],
204
204
  'unmatched-tag': [
205
205
  1,
206
206
  {
@@ -247,7 +247,7 @@ const defaultLintRuleConfig = {
247
247
  warn: 1,
248
248
  },
249
249
  ],
250
- 'invalid-math': 2,
250
+ 'invalid-math': [2],
251
251
  };
252
252
  const defaultLintConfig = {
253
253
  configurationComment: 'lint',
@@ -264,8 +264,9 @@ const validateSeverity = (severity) => dict.has(severity);
264
264
  * 验证设置值是否符合规范
265
265
  * @param value 设置值
266
266
  */
267
- const validateConfigValue = (value) => validateSeverity(value)
268
- || Array.isArray(value) && validateSeverity(value[0]) && (value.length === 1 || typeof value[1] === 'object');
267
+ const validateConfigValue = (value) => validateSeverity(value) || (Array.isArray(value)
268
+ ? validateSeverity(value[0]) && (value.length === 1 || typeof value[1] === 'object')
269
+ : typeof value === 'object');
269
270
  /**
270
271
  * 设置语法检查规则
271
272
  * @param obj 语法检查设置对象
@@ -282,7 +283,16 @@ const set = (obj, key, value) => {
282
283
  return false;
283
284
  }
284
285
  if (validateConfigValue(value)) {
285
- obj[key] = value;
286
+ if (Array.isArray(value)) {
287
+ obj[key] = value;
288
+ }
289
+ else if (typeof value === 'object') {
290
+ const [base, options = {}] = defaultLintRuleConfig[key];
291
+ obj[key] = [base, { ...clone(options), ...value }];
292
+ }
293
+ else {
294
+ obj[key] = [value];
295
+ }
286
296
  return true;
287
297
  }
288
298
  /* c8 ignore next */
@@ -305,11 +315,8 @@ class LintRuleConfiguration {
305
315
  }
306
316
  /** @implements */
307
317
  getSeverity(rule, key) {
308
- const value = this[rule];
309
- if (typeof value !== 'object') {
310
- return dict.get(value);
311
- }
312
- return key ? dict.get(value[1]?.[key]) ?? dict.get(value[0]) : dict.get(value[0]);
318
+ const [base, options] = this[rule], severity = dict.get(base);
319
+ return key ? dict.get(options?.[key]) ?? severity : severity;
313
320
  }
314
321
  }
315
322
  /** 语法检查设置 */
package/dist/lib/text.js CHANGED
@@ -104,7 +104,7 @@ class AstText extends node_1.AstNode {
104
104
  return [];
105
105
  }
106
106
  errorRegex.lastIndex = 0;
107
- const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html, variants } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), { lintConfig } = index_1.default, tagLike = lintConfig.rules['tag-like'], specified = typeof tagLike === 'object' && tagLike[1]
107
+ const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html, variants } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), { lintConfig } = index_1.default, tagLike = lintConfig.rules['tag-like'], specified = tagLike[1]
108
108
  ? new Set(Object.keys(tagLike[1]).filter(tag => tag !== 'invalid' && tag !== 'disallowed'))
109
109
  : new Set(), tags = new Set([
110
110
  'onlyinclude',
@@ -175,7 +175,7 @@ class AttributeToken extends index_2.Token {
175
175
  }
176
176
  else if (typeof value === 'string' && ((/^xmlns:[\w:.-]+$/u.test(name) || urlAttrs.has(name)) && evil.test(value)
177
177
  || simple
178
- && (name === 'href' || tag === 'img' && name === 'src')
178
+ && (name === 'href' || type === 'ext-attr' && tag === 'img' && name === 'src')
179
179
  && !new RegExp(String.raw `^(?:${this.getAttribute('config').protocol}|//)\S+$`, 'iu')
180
180
  .test(value))) {
181
181
  LINT: {
@@ -146,7 +146,7 @@ class AttributesToken extends index_2.Token {
146
146
  /** @private */
147
147
  lint(start = this.getAbsoluteIndex(), re) {
148
148
  LINT: {
149
- const errors = super.lint(start, re), { parentNode, childNodes, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'no-duplicate', 'required-attr'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
149
+ const errors = super.lint(start, re), { parentNode, childNodes, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'required-attr', 'no-duplicate'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
150
150
  .map(k => lintConfig.getSeverity(rules[0], k));
151
151
  if (s[0] && this.#lint()) {
152
152
  const e = (0, lint_1.generateForSelf)(this, rect, rules[0], 'attributes-of-closing-tag', s[0]);
@@ -182,7 +182,7 @@ class AttributesToken extends index_2.Token {
182
182
  }
183
183
  }
184
184
  if (type === 'ext-attrs' && required.has(tag)) {
185
- const severity = lintConfig.getSeverity(rules[2], tag);
185
+ const severity = lintConfig.getSeverity(rules[1], tag);
186
186
  if (severity) {
187
187
  for (const key of required.get(tag)) {
188
188
  const keys = typeof key === 'string' ? [key] : key, missing = keys.every(k => {
@@ -190,12 +190,12 @@ class AttributesToken extends index_2.Token {
190
190
  return value === true || !value;
191
191
  });
192
192
  if (missing) {
193
- errors.push((0, lint_1.generateForSelf)(this, rect, rules[2], index_1.default.msg('required-attribute', keys.join('/')), severity));
193
+ errors.push((0, lint_1.generateForSelf)(this, rect, rules[1], index_1.default.msg('required-attribute', keys.join('/')), severity));
194
194
  }
195
195
  }
196
196
  }
197
197
  }
198
- const severity = lintConfig.getSeverity(rules[1], 'attribute');
198
+ const severity = lintConfig.getSeverity(rules[2], 'attribute');
199
199
  if (severity && duplicated.size > 0) {
200
200
  for (const key of duplicated) {
201
201
  const pairs = attrs.get(key).map(attr => {
@@ -203,7 +203,7 @@ class AttributesToken extends index_2.Token {
203
203
  return [attr, value === true ? '' : value];
204
204
  });
205
205
  Array.prototype.push.apply(errors, pairs.map(([attr, value], i) => {
206
- const e = (0, lint_1.generateForChild)(attr, rect, rules[1], index_1.default.msg('duplicate-attribute', key), severity);
206
+ const e = (0, lint_1.generateForChild)(attr, rect, rules[2], index_1.default.msg('duplicate-attribute', key), severity);
207
207
  if (computeEditInfo || fix) {
208
208
  const remove = (0, lint_1.fixByRemove)(e);
209
209
  if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
@@ -88,6 +88,8 @@ exports.htmlAttrs = (() => ({
88
88
  categorytree: blockAttrs,
89
89
  combooption: blockAttrs,
90
90
  img: new Set(['alt', 'src', 'width', 'height', 'loading', 'srcset']),
91
+ /* NOT FOR BROWSER ONLY */
92
+ a: new Set(['href', 'rel', 'rev']),
91
93
  }))();
92
94
  exports.extAttrs = (() => ({
93
95
  pre: new Set(['format']),
@@ -85,7 +85,9 @@ const htmlAttrs = /* @__PURE__ */ (() => ({
85
85
  poem: blockAttrs,
86
86
  categorytree: blockAttrs,
87
87
  combooption: blockAttrs,
88
- img: /* @__PURE__ */ new Set(["alt", "src", "width", "height", "loading", "srcset"])
88
+ img: /* @__PURE__ */ new Set(["alt", "src", "width", "height", "loading", "srcset"]),
89
+ /* NOT FOR BROWSER ONLY */
90
+ a: /* @__PURE__ */ new Set(["href", "rel", "rev"])
89
91
  }))();
90
92
  const extAttrs = /* @__PURE__ */ (() => ({
91
93
  pre: /* @__PURE__ */ new Set(["format"]),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.40.0",
3
+ "version": "2.41.0",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -18,7 +18,7 @@
18
18
  "/errors/README",
19
19
  "/config/",
20
20
  "!/config/mediawikiwiki.json",
21
- "!/config/testwiki.json",
21
+ "!/config/github.json",
22
22
  "/data/",
23
23
  "/i18n/",
24
24
  "/coverage/badge.svg",
@@ -74,9 +74,9 @@
74
74
  ]
75
75
  },
76
76
  "dependencies": {
77
- "@bhsd/cm-util": "^1.1.0",
77
+ "@bhsd/cm-util": "^2.0.1",
78
78
  "@bhsd/common": "^2.2.1",
79
- "@bhsd/stylelint-util": "^1.0.2",
79
+ "@bhsd/stylelint-util": "^1.0.3",
80
80
  "binary-search": "^1.3.6",
81
81
  "vscode-languageserver-types": "^3.17.5"
82
82
  },
@@ -84,29 +84,29 @@
84
84
  "color-name": "~2.0.2",
85
85
  "entities": "^8.0.0",
86
86
  "mathoid-texvcjs": "^0.6.0",
87
- "stylelint": "^17.11.0",
87
+ "stylelint": "^17.12.0",
88
88
  "vscode-css-languageservice": "^6.3.10",
89
89
  "vscode-html-languageservice": "^5.6.2",
90
90
  "vscode-json-languageservice": "^5.7.2"
91
91
  },
92
92
  "devDependencies": {
93
- "@bhsd/code-standard": "^2.4.2",
94
- "@bhsd/nodejs": "^1.0.0",
95
- "@bhsd/test-util": "^1.2.0",
93
+ "@bhsd/code-standard": "^2.5.1",
94
+ "@bhsd/nodejs": "^1.0.1",
95
+ "@bhsd/test-util": "^1.3.1",
96
96
  "@types/color-name": "^2.0.0",
97
97
  "@types/color-rgba": "^2.1.3",
98
98
  "@types/mocha": "^10.0.10",
99
- "@types/node": "^24.11.0",
100
- "@typescript-eslint/parser": "^8.59.2",
99
+ "@types/node": "^25.9.0",
100
+ "@typescript-eslint/parser": "^8.59.4",
101
101
  "c8": "^11.0.0",
102
102
  "color-rgba": "^3.0.0",
103
103
  "diff2html-cli": "^5.2.15",
104
104
  "esbuild": "^0.28.0",
105
- "eslint": "^10.3.0",
105
+ "eslint": "^10.4.0",
106
106
  "markdownlint-cli2": "^0.22.1",
107
107
  "mocha": "^11.7.5",
108
108
  "typescript": "^6.0.3",
109
- "v8r": "^6.0.0",
109
+ "v8r": "^6.1.0",
110
110
  "vscode-languageserver-textdocument": "^1.0.12"
111
111
  },
112
112
  "engines": {