wikilint 2.18.2 → 2.18.4

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.
Files changed (48) hide show
  1. package/README.md +1 -1
  2. package/bin/cli.js +1 -1
  3. package/config/minimum.json +7 -0
  4. package/dist/base.d.mts +2 -0
  5. package/dist/base.d.ts +2 -0
  6. package/dist/base.js +1 -0
  7. package/dist/base.mjs +2 -1
  8. package/dist/bin/config.js +3 -2
  9. package/dist/index.d.ts +12 -1
  10. package/dist/index.js +45 -28
  11. package/dist/lib/lsp.d.ts +1 -0
  12. package/dist/lib/lsp.js +19 -14
  13. package/dist/lib/text.js +2 -2
  14. package/dist/lib/title.d.ts +18 -4
  15. package/dist/lib/title.js +12 -4
  16. package/dist/parser/braces.js +79 -37
  17. package/dist/parser/commentAndExt.js +5 -16
  18. package/dist/parser/links.js +1 -1
  19. package/dist/parser/redirect.js +1 -3
  20. package/dist/src/arg.js +1 -1
  21. package/dist/src/attribute.js +1 -1
  22. package/dist/src/converter.js +1 -1
  23. package/dist/src/gallery.js +1 -1
  24. package/dist/src/heading.js +3 -3
  25. package/dist/src/imageParameter.js +9 -9
  26. package/dist/src/imagemap.js +3 -2
  27. package/dist/src/index.d.ts +1 -1
  28. package/dist/src/index.js +7 -5
  29. package/dist/src/link/base.js +1 -1
  30. package/dist/src/link/file.d.ts +2 -0
  31. package/dist/src/link/file.js +15 -13
  32. package/dist/src/link/galleryImage.js +1 -1
  33. package/dist/src/link/redirectTarget.js +1 -2
  34. package/dist/src/magicLink.js +1 -1
  35. package/dist/src/nested.js +5 -5
  36. package/dist/src/nowiki/index.js +3 -2
  37. package/dist/src/redirect.js +1 -2
  38. package/dist/src/syntax.d.ts +4 -2
  39. package/dist/src/syntax.js +4 -2
  40. package/dist/src/table/base.js +1 -1
  41. package/dist/src/table/index.d.ts +1 -0
  42. package/dist/src/table/index.js +3 -6
  43. package/dist/src/table/trBase.js +31 -14
  44. package/dist/src/transclude.js +14 -6
  45. package/dist/util/debug.js +11 -1
  46. package/dist/util/diff.js +1 -1
  47. package/dist/util/string.js +3 -4
  48. package/package.json +2 -2
@@ -9,7 +9,9 @@ declare type SyntaxTypes = 'heading-trail' | 'magic-word-name' | 'table-syntax'
9
9
  export declare class SyntaxToken extends Token {
10
10
  #private;
11
11
  get type(): SyntaxTypes;
12
- /** @param pattern 语法正则 */
13
- constructor(wikitext: string | undefined, pattern: RegExp, type: SyntaxTypes, config?: Config, accum?: Token[], acceptable?: Acceptable);
12
+ /**
13
+ * @class
14
+ */
15
+ constructor(wikitext: string | undefined, type: SyntaxTypes, config?: Config, accum?: Token[], acceptable?: Acceptable);
14
16
  }
15
17
  export {};
@@ -12,8 +12,10 @@ class SyntaxToken extends index_1.Token {
12
12
  get type() {
13
13
  return this.#type;
14
14
  }
15
- /** @param pattern 语法正则 */
16
- constructor(wikitext, pattern, type, config, accum, acceptable) {
15
+ /**
16
+ * @class
17
+ */
18
+ constructor(wikitext, type, config, accum, acceptable) {
17
19
  super(wikitext, config, accum, acceptable);
18
20
  this.#type = type;
19
21
  }
@@ -24,7 +24,7 @@ class TableBaseToken extends (0, attributesParent_1.attributesParent)(1)(index_2
24
24
  */
25
25
  constructor(pattern, syntax, type, attr, config = index_1.default.getConfig(), accum = [], acceptable) {
26
26
  super(undefined, config, accum, acceptable);
27
- this.append(new syntax_1.SyntaxToken(syntax, pattern, 'table-syntax', config, accum, {}),
27
+ this.append(new syntax_1.SyntaxToken(syntax, 'table-syntax', config, accum),
28
28
  // @ts-expect-error abstract class
29
29
  new attributes_1.AttributesToken(attr, 'table-attrs', type, config, accum));
30
30
  }
@@ -11,6 +11,7 @@ export type TableTokens = TableToken | TrToken | TdToken;
11
11
  export declare const isRowEnd: ({ type }: Token) => boolean;
12
12
  /** @extends {Array<TableCoords[]>} */
13
13
  export declare class Layout extends Array<TableCoords[]> {
14
+ abstract static from(arr: TableCoords[][]): Layout;
14
15
  }
15
16
  /**
16
17
  * table
@@ -10,7 +10,6 @@ const rect_1 = require("../../lib/rect");
10
10
  const index_1 = __importDefault(require("../../index"));
11
11
  const trBase_1 = require("./trBase");
12
12
  const syntax_1 = require("../syntax");
13
- const closingPattern = /^\n[^\S\n]*(?:\|\}|\{\{\s*!\s*\}\}\}|\{\{\s*!\)\s*\}\})$/u;
14
13
  /**
15
14
  * 生成一个指定长度的空数组
16
15
  * @param n 数组长度
@@ -91,11 +90,9 @@ class TableToken extends trBase_1.TrBaseToken {
91
90
  * @param halfParsed
92
91
  */
93
92
  close(syntax = '\n|}', halfParsed) {
94
- const config = this.getAttribute('config'), accum = this.getAttribute('accum'), inner = halfParsed
95
- ? [syntax]
96
- : index_1.default.parse(syntax, this.getAttribute('include'), 2, config).childNodes;
93
+ const config = this.getAttribute('config'), accum = this.getAttribute('accum'), inner = [syntax];
97
94
  debug_1.Shadow.run(() => {
98
- const token = new syntax_1.SyntaxToken(undefined, closingPattern, 'table-syntax', config, accum);
95
+ const token = new syntax_1.SyntaxToken(undefined, 'table-syntax', config, accum);
99
96
  super.insertAt(token);
100
97
  });
101
98
  this.lastChild.replaceChildren(...inner);
@@ -111,7 +108,7 @@ class TableToken extends trBase_1.TrBaseToken {
111
108
  * @param stop.y stop at the column / 中止列
112
109
  */
113
110
  getLayout(stop) {
114
- const rows = this.getAllRows(), { length } = rows, layout = new Layout(...emptyArray(length, () => []));
111
+ const rows = this.getAllRows(), { length } = rows, layout = Layout.from(emptyArray(length, () => []));
115
112
  for (let i = 0; i < layout.length; i++) {
116
113
  const rowLayout = layout[i];
117
114
  let j = 0, k = 0, last;
@@ -4,6 +4,34 @@ exports.TrBaseToken = void 0;
4
4
  const lint_1 = require("../../util/lint");
5
5
  const base_1 = require("./base");
6
6
  const td_1 = require("./td");
7
+ const tableTags = new Set(['tr', 'td', 'th', 'caption']), tableTemplates = new Set(['Template:!!', 'Template:!-']);
8
+ /**
9
+ * Check if the content is fostered
10
+ * @param token
11
+ */
12
+ const isFostered = (token) => {
13
+ const first = token.childNodes.find(child => child.text().trim());
14
+ if (!first
15
+ || first.type === 'text' && first.data.trim().startsWith('!')
16
+ || first.type === 'magic-word' && first.name === '!'
17
+ || first.type === 'template' && tableTemplates.has(first.name)
18
+ || first.is('html') && tableTags.has(first.name)) {
19
+ return false;
20
+ }
21
+ else if (first.is('arg')) {
22
+ return first.length > 1 && isFostered(first.childNodes[1]);
23
+ }
24
+ else if (first.is('magic-word')) {
25
+ try {
26
+ const severity = first.getPossibleValues().map(isFostered);
27
+ return severity.includes('error')
28
+ ? 'error'
29
+ : severity.includes('warning') && 'warning';
30
+ }
31
+ catch { }
32
+ }
33
+ return first.type === 'template' || first.type === 'magic-word' && first.name === 'invoke' ? 'warning' : 'error';
34
+ };
7
35
  /**
8
36
  * table row or table
9
37
  *
@@ -16,22 +44,11 @@ class TrBaseToken extends base_1.TableBaseToken {
16
44
  if (!inter) {
17
45
  return errors;
18
46
  }
19
- const first = inter.childNodes.find(child => child.text().trim()), tdPattern = /^\s*(?:!|\{\{\s*![!-]?\s*\}\})/u;
20
- if (!first
21
- || tdPattern.test(first.toString())
22
- || first.is('arg') && tdPattern.test(first.default || '')) {
47
+ const severity = isFostered(inter);
48
+ if (!severity) {
23
49
  return errors;
24
50
  }
25
- else if (first.is('magic-word')) {
26
- try {
27
- if (first.getPossibleValues().every(token => tdPattern.test(token.text()))) {
28
- return errors;
29
- }
30
- }
31
- catch { }
32
- }
33
- const error = (0, lint_1.generateForChild)(inter, { start }, 'fostered-content', 'content to be moved out from the table');
34
- error.severity = first.type === 'template' ? 'warning' : 'error';
51
+ const error = (0, lint_1.generateForChild)(inter, { start }, 'fostered-content', 'content to be moved out from the table', severity);
35
52
  error.startIndex++;
36
53
  error.startLine++;
37
54
  error.startCol = 0;
@@ -66,7 +66,7 @@ class TranscludeToken extends index_1.Token {
66
66
  if (fullWidth) {
67
67
  this.#colon = ':';
68
68
  }
69
- const pattern = new RegExp(String.raw `^\s*${name}\s*$`, isSensitive ? 'u' : 'iu'), token = new syntax_1.SyntaxToken(magicWord, pattern, 'magic-word-name', config, accum, {});
69
+ const token = new syntax_1.SyntaxToken(magicWord, 'magic-word-name', config, accum);
70
70
  super.insertAt(token);
71
71
  if (arg !== false) {
72
72
  parts.unshift([arg]);
@@ -85,7 +85,7 @@ class TranscludeToken extends index_1.Token {
85
85
  }
86
86
  if (this.type === 'template') {
87
87
  const name = (0, string_1.removeComment)(title).trim();
88
- if (!this.normalizeTitle(name, 10, true, true).valid) {
88
+ if (!this.normalizeTitle(name, 10, { halfParsed: true, temporary: true }).valid) {
89
89
  accum.pop();
90
90
  throw new SyntaxError('Invalid template name');
91
91
  }
@@ -144,7 +144,7 @@ class TranscludeToken extends index_1.Token {
144
144
  }
145
145
  /** 获取模板或模块名 */
146
146
  #getTitle() {
147
- const isTemplate = this.type === 'template', title = this.normalizeTitle(this.childNodes[isTemplate ? 0 : 1].toString(true), isTemplate ? 10 : 828, true);
147
+ const isTemplate = this.type === 'template', title = this.normalizeTitle(this.childNodes[isTemplate ? 0 : 1].text(), isTemplate ? 10 : 828, { temporary: true });
148
148
  return title;
149
149
  }
150
150
  /**
@@ -162,7 +162,7 @@ class TranscludeToken extends index_1.Token {
162
162
  return [
163
163
  this.#getTitle().title,
164
164
  // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
165
- this.childNodes[2]?.toString(true).trim(),
165
+ this.childNodes[2]?.text().trim(),
166
166
  ];
167
167
  }
168
168
  }
@@ -344,7 +344,7 @@ class TranscludeToken extends index_1.Token {
344
344
  if (type === 'template') {
345
345
  throw new Error('TranscludeToken.getPossibleValues method is only for specific magic words!');
346
346
  }
347
- let start;
347
+ let start, queue;
348
348
  switch (name) {
349
349
  case 'if':
350
350
  case 'ifexist':
@@ -355,10 +355,18 @@ class TranscludeToken extends index_1.Token {
355
355
  case 'ifeq':
356
356
  start = 3;
357
357
  break;
358
+ case 'switch': {
359
+ const parameters = childNodes.slice(2), last = parameters[parameters.length - 1];
360
+ queue = [
361
+ ...parameters.filter(({ anon }) => !anon),
362
+ ...last?.anon ? [last] : [],
363
+ ].map(({ lastChild }) => lastChild);
364
+ break;
365
+ }
358
366
  default:
359
367
  throw new Error('TranscludeToken.getPossibleValues method is only for specific magic words!');
360
368
  }
361
- const queue = childNodes.slice(start, start + 2).map(({ childNodes: [, value] }) => value);
369
+ queue ??= childNodes.slice(start, start + 2).map(({ lastChild }) => lastChild);
362
370
  for (let i = 0; i < queue.length;) {
363
371
  const { length, 0: first } = queue[i].childNodes.filter(child => child.text().trim());
364
372
  if (length === 0) {
@@ -37,7 +37,14 @@ exports.isToken = isToken;
37
37
  * @param inserted 插入的子节点
38
38
  */
39
39
  const setChildNodes = (parent, position, deleteCount, inserted = []) => {
40
- const nodes = parent.getChildNodes(), removed = nodes.splice(position, deleteCount, ...inserted);
40
+ let nodes = parent.getChildNodes(), removed;
41
+ if (nodes.length === deleteCount) {
42
+ removed = nodes;
43
+ nodes = inserted;
44
+ }
45
+ else {
46
+ removed = nodes.splice(position, deleteCount, ...inserted);
47
+ }
41
48
  for (let i = 0; i < inserted.length; i++) {
42
49
  const node = inserted[i];
43
50
  node.setAttribute('parentNode', parent);
@@ -46,6 +53,9 @@ const setChildNodes = (parent, position, deleteCount, inserted = []) => {
46
53
  }
47
54
  nodes[position - 1]?.setAttribute('nextSibling', nodes[position]);
48
55
  nodes[position + inserted.length]?.setAttribute('previousSibling', nodes[position + inserted.length - 1]);
56
+ if (nodes === inserted) {
57
+ parent.setAttribute('childNodes', nodes);
58
+ }
49
59
  return removed;
50
60
  };
51
61
  exports.setChildNodes = setChildNodes;
package/dist/util/diff.js CHANGED
@@ -31,7 +31,7 @@ const cmd = (command, args) => new Promise(resolve => {
31
31
  shell = (0, child_process_1.spawn)(command, args);
32
32
  timer = setTimeout(() => {
33
33
  shell.kill('SIGINT');
34
- }, 60 * 1000);
34
+ }, 60 * 1e3);
35
35
  let buf = '';
36
36
  shell.stdout.on('data', data => {
37
37
  buf += String(data);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.noWrap = exports.decodeNumber = exports.decodeHtml = exports.text = exports.escapeRegExp = exports.removeComment = exports.tidy = exports.extUrlChar = exports.extUrlCharFirst = exports.zs = exports.rawurldecode = void 0;
3
+ exports.noWrap = exports.decodeNumber = exports.decodeHtml = exports.decodeHtmlBasic = exports.text = exports.escapeRegExp = exports.removeComment = exports.tidy = exports.extUrlChar = exports.extUrlCharFirst = exports.zs = exports.rawurldecode = void 0;
4
4
  var common_1 = require("@bhsd/common");
5
5
  Object.defineProperty(exports, "rawurldecode", { enumerable: true, get: function () { return common_1.rawurldecode; } });
6
6
  exports.zs = String.raw ` \xA0\u1680\u2000-\u200A\u202F\u205F\u3000`;
@@ -27,9 +27,8 @@ exports.escapeRegExp = factory(/[\\{}()|.?*+^$[\]]/gu, String.raw `\$&`);
27
27
  const text = (childNodes, separator = '') => childNodes.map(child => typeof child === 'string' ? child : child.text()).join(separator);
28
28
  exports.text = text;
29
29
  const names = { lt: '<', gt: '>', lbrack: '[', rbrack: ']', lbrace: '{', rbrace: '}', nbsp: ' ', amp: '&', quot: '"' };
30
- /* istanbul ignore next */
31
30
  /** decode HTML entities */
32
- const decodeHtmlBasic = factory(/&(?:#(\d+|[Xx][\da-fA-F]+)|([lg]t|[LG]T|[lr]brac[ke]|nbsp|amp|AMP|quot|QUOT));/gu, (_, code, name) => code
31
+ exports.decodeHtmlBasic = factory(/&(?:#(\d+|[Xx][\da-fA-F]+)|([lg]t|[LG]T|[lr]brac[ke]|nbsp|amp|AMP|quot|QUOT));/gu, (_, code, name) => code
33
32
  ? String.fromCodePoint(Number((/^x/iu.test(code) ? '0' : '') + code))
34
33
  : names[name.toLowerCase()]);
35
34
  /**
@@ -48,7 +47,7 @@ const decodeHtml = (str) => {
48
47
  }
49
48
  /* istanbul ignore next */
50
49
  /* NOT FOR BROWSER ONLY END */
51
- return decodeHtmlBasic(str);
50
+ return (0, exports.decodeHtmlBasic)(str);
52
51
  };
53
52
  exports.decodeHtml = decodeHtml;
54
53
  /** decode numbered HTML entities */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.18.2",
3
+ "version": "2.18.4",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -65,7 +65,7 @@
65
65
  ]
66
66
  },
67
67
  "dependencies": {
68
- "@bhsd/common": "^0.8.1",
68
+ "@bhsd/common": "^0.9.1",
69
69
  "vscode-languageserver-types": "^3.17.5"
70
70
  },
71
71
  "optionalDependencies": {