wikilint 2.12.2 → 2.12.5

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.
@@ -702,7 +702,10 @@
702
702
  "CONTENTLANGUAGE",
703
703
  "CONTENTLANG",
704
704
  "PAGELANGUAGE",
705
- "="
705
+ "=",
706
+ "#FORMAL",
707
+ "#timef",
708
+ "#timefl"
706
709
  ],
707
710
  [
708
711
  "msg",
@@ -331,7 +331,10 @@
331
331
  "CONTENTLANGUAGE",
332
332
  "CONTENTLANG",
333
333
  "PAGELANGUAGE",
334
- "="
334
+ "=",
335
+ "#FORMAL",
336
+ "#timef",
337
+ "#timefl"
335
338
  ],
336
339
  [
337
340
  "msg",
@@ -69,7 +69,12 @@
69
69
  "link"
70
70
  ]
71
71
  ],
72
- "namespaces": {},
72
+ "namespaces": {
73
+ "0": "",
74
+ "6": "File",
75
+ "10": "Template",
76
+ "828": "Module"
77
+ },
73
78
  "nsid": {
74
79
  "file": 6,
75
80
  "category": 14
@@ -114,7 +119,10 @@
114
119
  },
115
120
  [
116
121
  "!",
117
- "="
122
+ "=",
123
+ "#FORMAL",
124
+ "#timef",
125
+ "#timefl"
118
126
  ],
119
127
  [
120
128
  "msg",
@@ -644,7 +644,10 @@
644
644
  "CONTENTLANGUAGE",
645
645
  "CONTENTLANG",
646
646
  "PAGELANGUAGE",
647
- "="
647
+ "=",
648
+ "#FORMAL",
649
+ "#timef",
650
+ "#timefl"
648
651
  ],
649
652
  [
650
653
  "msg",
@@ -8,10 +8,10 @@ const node_1 = require("./node");
8
8
  * 将选择器转化为类型谓词
9
9
  * @param selector 选择器
10
10
  */
11
- const getCondition = (selector) => {
12
- const types = new Set(selector.split(',').map(str => str.trim()));
13
- return (({ type }) => types.has(type));
14
- };
11
+ const getCondition = (selector) => (({ type, name }) => selector.split(',').some(str => {
12
+ const [t, ...ns] = str.trim().split('#');
13
+ return (!t || t === type) && ns.every(n => n === name);
14
+ }));
15
15
  /** 类似HTMLElement */
16
16
  class AstElement extends node_1.AstNode {
17
17
  /** 子节点总数 */
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.parseMagicLinks = void 0;
4
4
  const string_1 = require("../util/string");
5
5
  const magicLink_1 = require("../src/magicLink");
6
+ const space = String.raw `[\p{Zs}\t]| |&#0*160;|&#x0*a0;`, sp = `(?:${space})+`, spdash = `(?:${space}|-)`, magicLinkPattern = String.raw `(?:RFC|PMID)${sp}\d+\b|ISBN${sp}(?:97[89]${spdash}?)?(?:\d${spdash}?){9}[\dx]\b`;
6
7
  /**
7
8
  * 解析自由外链
8
9
  * @param wikitext
@@ -10,7 +11,7 @@ const magicLink_1 = require("../src/magicLink");
10
11
  * @param accum
11
12
  */
12
13
  const parseMagicLinks = (wikitext, config, accum) => {
13
- const space = String.raw `[\p{Zs}\t]| |&#0*160;|&#x0*a0;`, spdash = `(?:${space}|-)`, regex = new RegExp(String.raw `(^|[^\p{L}\d_])(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|(?:RFC|PMID)(?:${space})+\d+\b|ISBN(?:${space})+(?:97[89]${spdash}?)?(?:\d${spdash}?){9}[\dx]\b)`, 'giu');
14
+ const regex = new RegExp(String.raw `(^|[^\p{L}\d_])(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
14
15
  return wikitext.replace(regex, (m, lead, p1) => {
15
16
  let url = lead ? m.slice(lead.length) : m;
16
17
  if (p1) {
package/dist/src/arg.d.ts CHANGED
@@ -8,6 +8,7 @@ import type { LintError } from '../base';
8
8
  * @classdesc `{childNodes: [AtomToken, ?Token, ...HiddenToken]}`
9
9
  */
10
10
  export declare abstract class ArgToken extends Token {
11
+ #private;
11
12
  readonly childNodes: readonly [AtomToken] | readonly [AtomToken, Token, ...HiddenToken[]];
12
13
  abstract get firstChild(): AtomToken;
13
14
  abstract get lastChild(): Token;
package/dist/src/arg.js CHANGED
@@ -56,6 +56,15 @@ class ArgToken extends index_2.Token {
56
56
  getGaps() {
57
57
  return 1;
58
58
  }
59
+ /** 设置name */
60
+ #setName() {
61
+ this.setAttribute('name', this.firstChild.toString(true).trim());
62
+ }
63
+ /** @private */
64
+ afterBuild() {
65
+ this.#setName();
66
+ super.afterBuild();
67
+ }
59
68
  /** @private */
60
69
  lint(start = this.getAbsoluteIndex(), re) {
61
70
  const { childNodes: [argName, argDefault, ...rest] } = this;
@@ -64,10 +64,14 @@ const commonHtmlAttrs = new Set([
64
64
  time: new Set(['datetime']),
65
65
  meta: new Set(['itemprop', 'content']),
66
66
  link: new Set(['itemprop', 'href', 'title']),
67
- gallery: new Set(['mode', 'showfilename', 'caption', 'perrow', 'widths', 'heights', 'showthumbnails', 'type']),
68
- poem: new Set(['compact', 'align']),
67
+ gallery: typeAttrs,
68
+ poem: blockAttrs,
69
+ categorytree: blockAttrs,
70
+ combooption: blockAttrs,
71
+ }, empty = new Set(), extAttrs = {
72
+ gallery: new Set(['mode', 'showfilename', 'caption', 'perrow', 'widths', 'heights', 'showthumbnails']),
73
+ poem: new Set(['compact']),
69
74
  categorytree: new Set([
70
- 'align',
71
75
  'hideroot',
72
76
  'onlyroot',
73
77
  'depth',
@@ -77,8 +81,7 @@ const commonHtmlAttrs = new Set([
77
81
  'showcount',
78
82
  'notranslations',
79
83
  ]),
80
- combooption: new Set(['name', 'for', 'inline', 'align']),
81
- }, empty = new Set(), extAttrs = {
84
+ combooption: new Set(['name', 'for', 'inline']),
82
85
  nowiki: empty,
83
86
  indicator: new Set(['name']),
84
87
  langconvert: new Set(['from', 'to']),
@@ -267,11 +270,12 @@ class AttributeToken extends index_2.Token {
267
270
  errors.push(e);
268
271
  }
269
272
  const attrs = extAttrs[tag];
270
- if (attrs && !attrs.has(name)
271
- || (type === 'ext-attr' ? tag in htmlAttrs : !/\{\{[^{]+\}\}/u.test(name))
272
- && !htmlAttrs[tag]?.has(name)
273
- && !/^(?:xmlns:[\w:.-]+|data-(?!ooui|mw|parsoid)[^:]*)$/u.test(name)
274
- && (tag === 'meta' || tag === 'link' || !commonHtmlAttrs.has(name))) {
273
+ if (!(attrs && attrs.has(name))
274
+ && (type === 'ext-attr' || !/\{\{[^{]+\}\}/u.test(name))
275
+ && (type === 'ext-attr' && !(tag in htmlAttrs)
276
+ || !htmlAttrs[tag]?.has(name)
277
+ && !/^(?:xmlns:[\w:.-]+|data-(?!ooui|mw|parsoid)[^:]*)$/u.test(name)
278
+ && (tag === 'meta' || tag === 'link' || !commonHtmlAttrs.has(name)))) {
275
279
  errors.push((0, lint_1.generateForChild)(firstChild, rect, 'illegal-attr', 'illegal attribute name'));
276
280
  }
277
281
  else if (obsoleteAttrs[tag]?.has(name)) {
@@ -48,7 +48,7 @@ class AttributesToken extends index_2.Token {
48
48
  while (mt) {
49
49
  const { index, 0: full, 1: key, 2: equal, 3: quoteStart, 4: quoted, 5: quoteEnd, 6: unquoted } = mt;
50
50
  out += attr.slice(lastIndex, index);
51
- if (/^(?:[\w:]|\0\d+[t!~{}+-]\x7F)(?:[\w:.-]|\0\d+[t!~{}+-]\x7F)*$/u.test((0, string_1.removeComment)(key).trim())) {
51
+ if (/^(?:[\w:]|\0\d+t\x7F)(?:[\w:.-]|\0\d+t\x7F)*$/u.test((0, string_1.removeComment)(key).trim())) {
52
52
  const value = quoted ?? unquoted, quotes = [quoteStart, quoteEnd],
53
53
  // @ts-expect-error abstract class
54
54
  token = new attribute_1.AttributeToken(toAttributeType(type), name, key, equal, value, quotes, config, accum);
@@ -64,7 +64,7 @@ class HeadingToken extends index_2.Token {
64
64
  if (innerStr.startsWith('=') || innerStr.endsWith('=')) {
65
65
  errors.push((0, lint_1.generateForChild)(firstChild, rect, 'unbalanced-header', index_1.default.msg('unbalanced $1 in a section header', '"="')));
66
66
  }
67
- if (this.closest('html-attrs, table-attrs')) {
67
+ if (this.closest('html-attrs,table-attrs')) {
68
68
  errors.push((0, lint_1.generateForSelf)(this, rect, 'parsing-order', 'section header in a HTML tag'));
69
69
  }
70
70
  if (boldQuotes.length % 2) {
package/dist/src/index.js CHANGED
@@ -337,27 +337,38 @@ class Token extends element_1.AstElement {
337
337
  lint(start = this.getAbsoluteIndex(), re) {
338
338
  let errors = super.lint(start, re);
339
339
  if (this.type === 'root') {
340
- const record = {};
341
- for (const cat of this.querySelectorAll('category')) {
342
- const thisCat = record[cat.name];
340
+ const record = {}, selector = 'category,html-attr#id,ext-attr#id,table-attr#id';
341
+ for (const cat of this.querySelectorAll(selector)) {
342
+ let key;
343
+ if (cat.type === 'category') {
344
+ key = cat.name;
345
+ }
346
+ else {
347
+ const value = cat.getValue();
348
+ key = `#${value === true ? '' : value}`;
349
+ }
350
+ const thisCat = record[key];
343
351
  if (thisCat) {
344
352
  thisCat.add(cat);
345
353
  }
346
354
  else {
347
- record[cat.name] = new Set([cat]);
355
+ record[key] = new Set([cat]);
348
356
  }
349
357
  }
350
- for (const value of Object.values(record)) {
351
- if (value.size > 1) {
358
+ for (const [key, value] of Object.entries(record)) {
359
+ if (value.size > 1 && !key.startsWith('#mw-customcollapsible-')) {
360
+ const isCat = !key.startsWith('#'), msg = `duplicated ${isCat ? 'category' : 'id'}`, severity = isCat ? 'error' : 'warning';
352
361
  errors.push(...[...value].map(cat => {
353
- const e = (0, lint_1.generateForSelf)(cat, { start: cat.getAbsoluteIndex() }, 'no-duplicate', 'duplicated category');
354
- e.suggestions = [
355
- {
356
- desc: 'remove',
357
- range: [e.startIndex, e.endIndex],
358
- text: '',
359
- },
360
- ];
362
+ const e = (0, lint_1.generateForSelf)(cat, { start: cat.getAbsoluteIndex() }, 'no-duplicate', msg, severity);
363
+ if (isCat) {
364
+ e.suggestions = [
365
+ {
366
+ desc: 'remove',
367
+ range: [e.startIndex, e.endIndex],
368
+ text: '',
369
+ },
370
+ ];
371
+ }
361
372
  return e;
362
373
  }));
363
374
  }
@@ -120,7 +120,7 @@ class ExtToken extends index_3.TagPairToken {
120
120
  /** @private */
121
121
  lint(start = this.getAbsoluteIndex(), re) {
122
122
  const errors = super.lint(start, re), rect = new rect_1.BoundingRect(this, start);
123
- if (this.name !== 'nowiki' && this.closest('html-attrs, table-attrs')) {
123
+ if (this.name !== 'nowiki' && this.closest('html-attrs,table-attrs')) {
124
124
  errors.push((0, lint_1.generateForSelf)(this, rect, 'parsing-order', 'extension tag in HTML tag attributes'));
125
125
  }
126
126
  if (this.name === 'ref' && this.closest('heading-title')) {
@@ -131,6 +131,12 @@ class TranscludeToken extends index_2.Token {
131
131
  this.setAttribute('modifier', this.buildFromStr(this.modifier, constants_1.BuildMethod.String));
132
132
  }
133
133
  super.afterBuild();
134
+ if (this.isTemplate()) {
135
+ const isTemplate = this.type === 'template';
136
+ if (isTemplate) {
137
+ this.setAttribute('name', this.#getTitle().title);
138
+ }
139
+ }
134
140
  }
135
141
  /** @private */
136
142
  toString(skip) {
package/i18n/zh-hans.json CHANGED
@@ -11,6 +11,7 @@
11
11
  "content to be moved out from the table": "将被移出表格的内容",
12
12
  "duplicated $1 attribute": "重复的$1属性",
13
13
  "duplicated category": "重复的分类",
14
+ "duplicated id": "重复的id",
14
15
  "duplicated image $1 parameter": "重复的图片$1参数",
15
16
  "duplicated parameter": "重复参数",
16
17
  "extension tag in HTML tag attributes": "HTML标签属性中的扩展标签",
package/i18n/zh-hant.json CHANGED
@@ -11,6 +11,7 @@
11
11
  "content to be moved out from the table": "將被移出表格的內容",
12
12
  "duplicated $1 attribute": "重複的$1屬性",
13
13
  "duplicated category": "重複的分類",
14
+ "duplicated id": "重複的id",
14
15
  "duplicated image $1 parameter": "重複的圖片$1參數",
15
16
  "duplicated parameter": "重複參數",
16
17
  "extension tag in HTML tag attributes": "HTML標籤屬性中的擴展標籤",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.12.2",
3
+ "version": "2.12.5",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",