wikilint 2.44.0 → 2.45.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.
Files changed (79) hide show
  1. package/config/default.json +1 -2
  2. package/config/enwiki.json +1 -1
  3. package/config/jawiki.json +1 -1
  4. package/config/minimum.json +1 -1
  5. package/config/zhwiki.json +1 -1
  6. package/data/ext/templatedata.json +13 -5
  7. package/data/signatures.json +38 -32
  8. package/dist/base.d.mts +1 -1
  9. package/dist/base.d.ts +1 -1
  10. package/dist/bin/config.js +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/internal.d.ts +6 -1
  13. package/dist/lib/element.js +5 -5
  14. package/dist/lib/lintConfig.js +7 -0
  15. package/dist/lib/lsp.d.ts +1 -2
  16. package/dist/lib/lsp.js +18 -42
  17. package/dist/lib/node.js +2 -2
  18. package/dist/lib/text.js +2 -2
  19. package/dist/map.d.ts +4 -1
  20. package/dist/mixin/elementLike.js +29 -31
  21. package/dist/mixin/hidden.js +0 -1
  22. package/dist/mixin/paramLineParent.d.ts +26 -0
  23. package/dist/mixin/paramLineParent.js +51 -0
  24. package/dist/src/arg.js +17 -35
  25. package/dist/src/atom.d.ts +1 -1
  26. package/dist/src/atom.js +2 -0
  27. package/dist/src/attribute.js +10 -5
  28. package/dist/src/attributes.js +15 -13
  29. package/dist/src/commented.d.ts +1 -0
  30. package/dist/src/commented.js +1 -3
  31. package/dist/src/converterFlags.js +9 -5
  32. package/dist/src/converterRule.js +2 -2
  33. package/dist/src/funcTag.d.ts +23 -0
  34. package/dist/src/funcTag.js +85 -0
  35. package/dist/src/heading.js +8 -3
  36. package/dist/src/hidden.d.ts +3 -2
  37. package/dist/src/hidden.js +29 -5
  38. package/dist/src/imageParameter.js +16 -4
  39. package/dist/src/index.js +2 -2
  40. package/dist/src/link/base.js +14 -2
  41. package/dist/src/link/categorytree.d.ts +2 -0
  42. package/dist/src/link/categorytree.js +8 -5
  43. package/dist/src/link/file.js +18 -12
  44. package/dist/src/multiLine/charinsert.d.ts +16 -0
  45. package/dist/src/multiLine/charinsert.js +84 -0
  46. package/dist/src/multiLine/gallery.js +4 -4
  47. package/dist/src/multiLine/imagemap.d.ts +1 -1
  48. package/dist/src/multiLine/imagemap.js +7 -7
  49. package/dist/src/multiLine/index.d.ts +3 -0
  50. package/dist/src/multiLine/index.js +79 -18
  51. package/dist/src/multiLine/inputbox.d.ts +1 -0
  52. package/dist/src/multiLine/paramTag.d.ts +3 -0
  53. package/dist/src/multiLine/paramTag.js +60 -13
  54. package/dist/src/nested.js +7 -7
  55. package/dist/src/nowiki/quote.js +6 -5
  56. package/dist/src/paramLine.d.ts +17 -3
  57. package/dist/src/paramLine.js +123 -31
  58. package/dist/src/parameter.d.ts +6 -0
  59. package/dist/src/parameter.js +15 -1
  60. package/dist/src/singleLine/charinsertLine.d.ts +21 -0
  61. package/dist/src/singleLine/charinsertLine.js +69 -0
  62. package/dist/src/{imagemapLink.d.ts → singleLine/imagemapLink.d.ts} +8 -7
  63. package/dist/src/singleLine/imagemapLink.js +95 -0
  64. package/dist/src/singleLine/index.d.ts +10 -0
  65. package/dist/src/singleLine/index.js +16 -0
  66. package/dist/src/tag/html.js +26 -8
  67. package/dist/src/tag/index.js +18 -17
  68. package/dist/src/tagPair/ext.js +23 -2
  69. package/dist/src/tagPair/index.js +1 -10
  70. package/dist/src/transclude.js +13 -13
  71. package/dist/util/sharable.js +22 -0
  72. package/dist/util/sharable.mjs +22 -0
  73. package/dist/util/string.js +27 -2
  74. package/i18n/en.json +4 -0
  75. package/i18n/zh-hans.json +4 -0
  76. package/i18n/zh-hant.json +4 -0
  77. package/package.json +10 -18
  78. package/dist/src/imagemapLink.js +0 -34
  79. /package/dist/{util → vendor}/search.js +0 -0
package/dist/lib/lsp.js CHANGED
@@ -21,7 +21,7 @@ const util_1 = __importDefault(require("util"));
21
21
  const child_process_1 = require("child_process");
22
22
  const crypto_1 = require("crypto");
23
23
  const stylelint_util_1 = require("@bhsd/stylelint-util");
24
- const search_1 = __importDefault(require("../util/search"));
24
+ const search_1 = __importDefault(require("../vendor/search"));
25
25
  const constants_2 = require("../util/constants");
26
26
  const document_1 = require("./document");
27
27
  exports.tasks = new WeakMap();
@@ -105,7 +105,7 @@ const createNodeRange = (token) => {
105
105
  * @param extra extra text
106
106
  * @param getDoc documentation method
107
107
  */
108
- const getCompletion = (words, kind, mt, { line, character }, extra, getDoc) => [...new Set(words)].map((w) => {
108
+ const getCompletion = (words, kind, mt, { line, character }, extra = '', getDoc) => [...new Set(words)].map((w) => {
109
109
  const doc = getDoc?.(w)?.description;
110
110
  return {
111
111
  label: w,
@@ -115,7 +115,7 @@ const getCompletion = (words, kind, mt, { line, character }, extra, getDoc) => [
115
115
  start: { line, character: character - mt.length },
116
116
  end: { line, character },
117
117
  },
118
- newText: w + (extra ?? ''),
118
+ newText: w + extra,
119
119
  },
120
120
  ...doc && {
121
121
  documentation: {
@@ -272,8 +272,7 @@ const partialParse = async (wikitext, watch, include, config = index_1.default.g
272
272
  };
273
273
  /* NOT FOR BROWSER ONLY */
274
274
  /** @see https://www.npmjs.com/package/stylelint-config-recommended */
275
- const cssRules = { 'block-no-empty': null }, sources = { 'invalid-css': 'css', 'invalid-math': 'texvc' }, jsonSelector = constants_2.jsonTags.map(s => `ext#${s}`).join(), scores = new Map();
276
- let colors;
275
+ const cssRules = { 'block-no-empty': null }, colors = Object.keys(common_1.colorsNamed), sources = { 'invalid-css': 'css', 'invalid-math': 'texvc' }, jsonSelector = constants_2.jsonTags.map(s => `ext#${s}`).join(), scores = new Map();
277
276
  /**
278
277
  * Correct the position of an error.
279
278
  * @param height
@@ -479,22 +478,9 @@ class LanguageService {
479
478
  * 提供颜色指示
480
479
  * @param rgba color parser / 颜色解析函数
481
480
  * @param text source Wikitext / 源代码
482
- * @param hsl whether HSL colors are treated / 是否允许HSL颜色
483
481
  */
484
- async provideDocumentColors(rgba, text, hsl = true) {
482
+ async provideDocumentColors(rgba, text) {
485
483
  const root = await this.#queue(text);
486
- /* NOT FOR BROWSER ONLY */
487
- if (colors === undefined) {
488
- try {
489
- const { default: colorName } = require('color-name');
490
- colors = new RegExp(String.raw `\b${Object.keys(colorName).join('|')}\b`, 'giu');
491
- }
492
- catch {
493
- /* c8 ignore next */
494
- colors = false;
495
- }
496
- }
497
- /* NOT FOR BROWSER ONLY END */
498
484
  return root.querySelectorAll('attr-value,parameter-value,arg-default').reverse().flatMap(token => {
499
485
  const { type, childNodes,
500
486
  /* NOT FOR BROWSER ONLY */
@@ -509,15 +495,10 @@ class LanguageService {
509
495
  /* NOT FOR BROWSER ONLY END */
510
496
  }
511
497
  /* NOT FOR BROWSER ONLY */
512
- const isStyle = colors && type === 'attr-value' && parentNode.name === 'style';
498
+ const isStyle = type === 'attr-value' && parentNode.name === 'style';
513
499
  /* NOT FOR BROWSER ONLY END */
514
500
  return childNodes.filter((child) => child.type === 'text').reverse().flatMap(child => {
515
- const { data } = child, parts = (0, common_1.splitColors)(data, hsl).filter(([, , , isColor]) => isColor);
516
- /* NOT FOR BROWSER ONLY */
517
- if (isStyle) {
518
- parts.push(...[...data.matchAll(colors)].map(({ index, 0: s }) => [s, index, index + s.length, true]));
519
- }
520
- /* NOT FOR BROWSER ONLY END */
501
+ const { data } = child, parts = (0, common_1.splitColors)(data, isStyle && colors).filter(([, , , isColor]) => isColor);
521
502
  if (parts.length === 0) {
522
503
  return [];
523
504
  }
@@ -688,13 +669,8 @@ class LanguageService {
688
669
  if (mt?.[7] !== undefined || type === 'image-parameter') { // image parameter
689
670
  const index = root.indexFromPos(line, character), match = mt?.[7]?.trimStart()
690
671
  ?? this.#text.slice(cur.getAbsoluteIndex(), index).trimStart(), equal = this.#text[index] === '=';
691
- return [
692
- ...getCompletion(params, 'Property', match, position)
693
- .filter(({ label }) => !equal || !/[= ]$/u.test(label)),
694
- ...getCompletion(root.querySelectorAll('image-parameter#width')
695
- .filter(token => token !== cur)
696
- .map(width => width.text()), 'Unit', match, position),
697
- ];
672
+ return getCompletion(params, 'Property', match, position)
673
+ .filter(({ label }) => !equal || !/[= ]$/u.test(label));
698
674
  }
699
675
  else if (mt?.[8] !== undefined || type === 'attr-key') { // attribute key
700
676
  const tag = mt?.[8]?.toLowerCase() ?? parentNode.tag, key = mt?.[10]
@@ -739,11 +715,11 @@ class LanguageService {
739
715
  }).map(({ name }) => name), 'Variable', key, position, type === 'parameter-value' ? '=' : '')
740
716
  : undefined;
741
717
  }
742
- else if (type === 'param-line') {
743
- // parameter line of `<dynamicpagelist>` or `<inputbox>`
718
+ else if (type === 'param-line-key') {
719
+ // parameter line of `<dynamicpagelist>`, `<inputbox>` or `<seo>`
744
720
  const key = this.#text.slice(cur.getAbsoluteIndex(), root.indexFromPos(line, character)).trimStart();
745
721
  return /^[a-z]+$/iu.test(key)
746
- ? getCompletion(sharable_1.extParams[cur.name], 'Property', key, position)
722
+ ? getCompletion(sharable_1.extParams[parentNode.name], 'Property', key, position)
747
723
  : undefined;
748
724
  /* NOT FOR BROWSER ONLY */
749
725
  }
@@ -989,8 +965,8 @@ class LanguageService {
989
965
  */
990
966
  async provideFoldingRanges(text) {
991
967
  const root = await this.#queue(text), { length } = root.getLines(), ranges = [], levels = Array.from({ length: 6 }), tokens = root.querySelectorAll('heading-title,table,template,magic-word');
992
- for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
993
- token.getRelativeIndex();
968
+ for (let i = tokens.length - 1; i >= 0; i--) { // 提高 getBoundingClientRect 的性能
969
+ tokens[i].getRelativeIndex();
994
970
  }
995
971
  for (const token of tokens) {
996
972
  const { offsetHeight } = token;
@@ -1225,7 +1201,7 @@ class LanguageService {
1225
1201
  return undefined;
1226
1202
  }
1227
1203
  const { type } = node, refName = getRefName(node), refNameGroup = refName && node.parentNode.parentNode.getAttr('group'), refGroup = getRefGroup(node), name = getName(node), refs = root.querySelectorAll(type).filter(token => {
1228
- const { type: t } = token.parentNode;
1204
+ const t = token.parentNode.type;
1229
1205
  if (type === 'link-target' && t !== 'link' && t !== 'redirect-target') {
1230
1206
  return false;
1231
1207
  }
@@ -1415,10 +1391,10 @@ class LanguageService {
1415
1391
  * @since v1.16.3
1416
1392
  */
1417
1393
  async provideInlayHints(text) {
1418
- const root = await this.#queue(text);
1394
+ const root = await this.#queue(text), templates = root.querySelectorAll('template,magic-word#invoke');
1419
1395
  let hints = [];
1420
- for (const token of root.querySelectorAll('template,magic-word#invoke').reverse()) {
1421
- const { type, childNodes } = token;
1396
+ for (let i = templates.length - 1; i >= 0; i--) {
1397
+ const { type, childNodes } = templates[i];
1422
1398
  hints = [
1423
1399
  ...hints,
1424
1400
  ...childNodes.slice(type === 'template' ? 1 : 3).filter(({ anon }) => anon)
package/dist/lib/node.js CHANGED
@@ -40,7 +40,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.AstNode = void 0;
41
41
  /* eslint-disable @typescript-eslint/no-base-to-string */
42
42
  const common_1 = require("@bhsd/common");
43
- const search_1 = __importDefault(require("../util/search"));
43
+ const search_1 = __importDefault(require("../vendor/search"));
44
44
  const lint_1 = require("../util/lint");
45
45
  const debug_1 = require("../util/debug");
46
46
  const cached_1 = require("../mixin/cached");
@@ -145,7 +145,7 @@ let AstNode = (() => {
145
145
  * @param left column number / 列号
146
146
  */
147
147
  indexFromPos(top, left) {
148
- LINT: {
148
+ LSP: {
149
149
  if (top < 0 || left < 0) {
150
150
  return undefined;
151
151
  }
package/dist/lib/text.js CHANGED
@@ -16,7 +16,7 @@ const errorSyntaxUrl = /* #__PURE__ */ new RegExp(source, 'giu'), noLinkTypes =
16
16
  '{': /[{}]/u,
17
17
  ']': /[[\]](?=[^[\]]*$)/u,
18
18
  '}': /[{}](?=[^{}]*$)/u,
19
- }, disallowedTags = new Set([
19
+ }, magic = new Set(['rfc', 'pmid', 'isbn']), disallowedTags = new Set([
20
20
  'html',
21
21
  'head',
22
22
  'style',
@@ -136,7 +136,7 @@ class AstText extends node_1.AstNode {
136
136
  error = error.slice(1);
137
137
  }
138
138
  error = error.toLowerCase();
139
- const [char] = error, magicLink = error === 'rfc' || error === 'pmid' || error === 'isbn', lbrace = char === '{', rbrace = char === '}', lbrack = char === '[', rbrack = char === ']';
139
+ const [char] = error, magicLink = magic.has(error), lbrace = char === '{', rbrace = char === '}', lbrack = char === '[', rbrack = char === ']';
140
140
  let { length } = error;
141
141
  if (rbrack && (index || length > 1)) {
142
142
  errorRegex.lastIndex--;
package/dist/map.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { RedirectToken, RedirectTargetToken, OnlyincludeToken, IncludeToken, CommentToken, ExtToken, AttributesToken, AttributeToken, AtomToken, ArgToken, TranscludeToken, SyntaxToken, ParameterToken, HeadingToken, HtmlToken, TableToken, TrToken, TdToken, DoubleUnderscoreToken, HrToken, LinkToken, CategoryToken, FileToken, ImageParameterToken, QuoteToken, ExtLinkToken, MagicLinkToken, ListToken, DdToken, ConverterToken, ConverterFlagsToken, ConverterRuleToken, TranslateToken, TvarToken, HiddenToken, GalleryImageToken, ParamLineToken, ImagemapLinkToken } from './internal';
1
+ import type { RedirectToken, RedirectTargetToken, OnlyincludeToken, IncludeToken, CommentToken, ExtToken, AttributesToken, AttributeToken, AtomToken, ArgToken, TranscludeToken, SyntaxToken, ParameterToken, HeadingToken, HtmlToken, TableToken, TrToken, TdToken, DoubleUnderscoreToken, HrToken, LinkToken, CategoryToken, FileToken, ImageParameterToken, QuoteToken, ExtLinkToken, MagicLinkToken, ListToken, DdToken, ConverterToken, ConverterFlagsToken, ConverterRuleToken, TranslateToken, TvarToken, HiddenToken, GalleryImageToken, ParamLineToken, ImagemapLinkToken, CharinsertLineToken } from './internal';
2
2
  export interface TokenTypeMap {
3
3
  redirect: RedirectToken;
4
4
  'redirect-syntax': SyntaxToken;
@@ -60,6 +60,9 @@ export interface TokenTypeMap {
60
60
  'converter-rule': ConverterRuleToken;
61
61
  'converter-rule-variant': AtomToken;
62
62
  'param-line': ParamLineToken;
63
+ 'param-line-key': AtomToken;
64
+ 'param-line-value': AtomToken;
63
65
  'imagemap-link': ImagemapLinkToken;
66
+ 'charinsert-line': CharinsertLineToken;
64
67
  }
65
68
  export type SelectedTokenTypes = keyof TokenTypeMap;
@@ -5,23 +5,23 @@ const debug_1 = require("../util/debug");
5
5
  const selector_1 = require("../util/selector");
6
6
  /** @ignore */
7
7
  const elementLike = (constructor) => {
8
- class ElementLike extends constructor {
9
- #getCondition(selector) {
10
- return (0, selector_1.getCondition)(selector, this);
11
- }
12
- closest(selector) {
13
- const condition = this.#getCondition(selector);
14
- let { parentNode } = this;
15
- while (parentNode) {
16
- if (condition(parentNode)) {
17
- return parentNode;
8
+ LINT: {
9
+ class ElementLike extends constructor {
10
+ #getCondition(selector) {
11
+ return (0, selector_1.getCondition)(selector, this);
12
+ }
13
+ closest(selector) {
14
+ const condition = this.#getCondition(selector);
15
+ let { parentNode } = this;
16
+ while (parentNode) {
17
+ if (condition(parentNode)) {
18
+ return parentNode;
19
+ }
20
+ ({ parentNode } = parentNode);
18
21
  }
19
- ({ parentNode } = parentNode);
22
+ return undefined;
20
23
  }
21
- return undefined;
22
- }
23
- getElementBy(condition) {
24
- LINT: {
24
+ getElementBy(condition) {
25
25
  const stack = [...this.childNodes].reverse();
26
26
  while (stack.length > 0) {
27
27
  const child = stack.pop(), { type, childNodes } = child;
@@ -37,12 +37,10 @@ const elementLike = (constructor) => {
37
37
  }
38
38
  return undefined;
39
39
  }
40
- }
41
- querySelector(selector) {
42
- LINT: return this.getElementBy(this.#getCondition(selector));
43
- }
44
- getElementsBy(condition) {
45
- LINT: {
40
+ querySelector(selector) {
41
+ return this.getElementBy(this.#getCondition(selector));
42
+ }
43
+ getElementsBy(condition) {
46
44
  const stack = [...this.childNodes].reverse(), descendants = [];
47
45
  while (stack.length > 0) {
48
46
  const child = stack.pop(), { type, childNodes } = child;
@@ -58,19 +56,19 @@ const elementLike = (constructor) => {
58
56
  }
59
57
  return descendants;
60
58
  }
61
- }
62
- querySelectorAll(selector) {
63
- LINT: return this.getElementsBy(this.#getCondition(selector));
64
- }
65
- escape() {
66
- LSP: {
67
- for (const child of this.childNodes) {
68
- child.escape();
59
+ querySelectorAll(selector) {
60
+ return this.getElementsBy(this.#getCondition(selector));
61
+ }
62
+ escape() {
63
+ LSP: {
64
+ for (const child of this.childNodes) {
65
+ child.escape();
66
+ }
69
67
  }
70
68
  }
71
69
  }
70
+ (0, debug_1.mixin)(ElementLike, constructor);
71
+ return ElementLike;
72
72
  }
73
- (0, debug_1.mixin)(ElementLike, constructor);
74
- return ElementLike;
75
73
  };
76
74
  exports.elementLike = elementLike;
@@ -13,7 +13,6 @@ const hiddenToken = (linter = true, html = true) => (constructor) => {
13
13
  return '';
14
14
  }
15
15
  lint(start) {
16
- // @ts-expect-error private argument
17
16
  LINT: return linter ? [] : super.lint(start);
18
17
  }
19
18
  }
@@ -0,0 +1,26 @@
1
+ import { ParamLineToken } from '../src/paramLine';
2
+ export interface ParamLineParentBase {
3
+ /**
4
+ * Get all parameter keys
5
+ *
6
+ * 获取所有参数键
7
+ */
8
+ getKeys(): Set<string>;
9
+ /**
10
+ * Get parameters with the specified key
11
+ *
12
+ * 获取指定参数
13
+ * @param key parameter key / 参数键
14
+ */
15
+ getParams(key: string): ParamLineToken[];
16
+ /**
17
+ * Get duplicated parameters
18
+ *
19
+ * 获取重复参数
20
+ */
21
+ getDuplicatedParams(): [string, ParamLineToken[]][];
22
+ }
23
+ /**
24
+ * 子节点为ParamLineToken的类
25
+ * @ignore
26
+ */
@@ -0,0 +1,51 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.paramLineParent = void 0;
7
+ const debug_1 = require("../util/debug");
8
+ const lint_1 = require("../util/lint");
9
+ const rect_1 = require("../lib/rect");
10
+ const index_1 = __importDefault(require("../index"));
11
+ /**
12
+ * 子节点为ParamLineToken的类
13
+ * @ignore
14
+ */
15
+ const paramLineParent = (constructor) => {
16
+ LINT: {
17
+ class ParamLineParent extends constructor {
18
+ getKeys() {
19
+ return new Set(this.childNodes.map(({ key }) => key).filter((key) => key !== undefined));
20
+ }
21
+ getParams(key) {
22
+ return this.childNodes.filter(({ key: k }) => k === key);
23
+ }
24
+ getDuplicatedParams() {
25
+ return [...this.getKeys()].map((key) => [key, this.getParams(key)])
26
+ .filter(([, { length }]) => length > 1);
27
+ }
28
+ lint(start = this.getAbsoluteIndex()) {
29
+ const errors = super.lint(start), { name, firstChild } = this, rule = 'no-duplicate', { lintConfig } = index_1.default, s = lintConfig.getSeverity(rule, name);
30
+ if (s) {
31
+ const msg = index_1.default.msg('duplicate-ext-parameter', name), rect = new rect_1.BoundingRect(this, start), { computeEditInfo } = lintConfig;
32
+ for (const [, params] of this.getDuplicatedParams()) {
33
+ const duplication = Array.from({ length: params.length });
34
+ for (let i = params.length - 1; i >= 0; i--) {
35
+ const param = params[i], e = (0, lint_1.generateForChild)(param, rect, rule, msg, s);
36
+ if (computeEditInfo) {
37
+ e.suggestions = [(0, lint_1.fixByRemove)(e, param === firstChild ? 0 : -1)];
38
+ }
39
+ duplication[i] = e;
40
+ }
41
+ Array.prototype.push.apply(errors, duplication);
42
+ }
43
+ }
44
+ return errors;
45
+ }
46
+ }
47
+ (0, debug_1.mixin)(ParamLineParent, constructor);
48
+ return ParamLineParent;
49
+ }
50
+ };
51
+ exports.paramLineParent = paramLineParent;
package/dist/src/arg.js CHANGED
@@ -38,7 +38,6 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
38
38
  };
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.ArgToken = void 0;
41
- const string_1 = require("../util/string");
42
41
  const lint_1 = require("../util/lint");
43
42
  const rect_1 = require("../lib/rect");
44
43
  const padded_1 = require("../mixin/padded");
@@ -99,11 +98,17 @@ let ArgToken = (() => {
99
98
  }
100
99
  /** @private */
101
100
  text() {
102
- return `{{{${(0, string_1.text)(this.childNodes.slice(0, 2), '|')}}}}`;
101
+ // eslint-disable-next-line @typescript-eslint/no-useless-default-assignment
102
+ const { length, childNodes, name = this.#getName() } = this;
103
+ return length === 1 ? `{{{${name}}}}` : `{{{${name}|${childNodes[1].text()}}}}`;
104
+ }
105
+ /** 获取name */
106
+ #getName() {
107
+ return this.firstChild.text().trim();
103
108
  }
104
109
  /** 更新name */
105
110
  #setName() {
106
- LSP: this.setAttribute('name', this.firstChild.text().trim());
111
+ LSP: this.setAttribute('name', this.#getName());
107
112
  }
108
113
  /** @private */
109
114
  afterBuild() {
@@ -113,44 +118,21 @@ let ArgToken = (() => {
113
118
  /** @private */
114
119
  lint(start = this.getAbsoluteIndex(), re) {
115
120
  LINT: {
116
- const [argName, argDefault, ...rest] = this.childNodes;
117
- argName.setAttribute('aIndex', start + 3);
118
- const errors = argName.lint(start + 3, re);
119
- if (argDefault) {
120
- const index = start + 4 + argName.toString().length;
121
- argDefault.setAttribute('aIndex', index);
122
- const childErrors = argDefault.lint(index, re);
123
- if (childErrors.length > 0) {
124
- Array.prototype.push.apply(errors, childErrors);
125
- }
126
- }
127
- const rules = ['no-ignored', 'no-arg'], { lintConfig } = index_1.default, { computeEditInfo } = lintConfig, rect = new rect_1.BoundingRect(this, start), s = rules.map(rule => lintConfig.getSeverity(rule, 'arg'));
128
- if (s[0] && rest.length > 0) {
129
- Array.prototype.push.apply(errors, rest.map(child => {
130
- const e = (0, lint_1.generateForChild)(child, rect, rules[0], 'invisible-triple-braces', s[0]);
131
- e.startIndex--;
132
- e.startCol--;
133
- if (computeEditInfo) {
134
- e.suggestions = [
135
- (0, lint_1.fixByRemove)(e),
136
- (0, lint_1.fixByEscape)(e.startIndex, '{{!}}'),
137
- ];
138
- }
139
- return e;
140
- }));
141
- }
142
- if (s[1] && !this.getAttribute('include')) {
143
- const e = (0, lint_1.generateForSelf)(this, rect, rules[1], 'unexpected-argument', s[1]);
144
- if (computeEditInfo && argDefault) {
121
+ const errors = super.lint(start, re), { lintConfig } = index_1.default, rect = new rect_1.BoundingRect(this, start);
122
+ let rule = 'no-arg', s = lintConfig.getSeverity(rule);
123
+ if (s && !this.getAttribute('include')) {
124
+ const e = (0, lint_1.generateForSelf)(this, rect, rule, 'unexpected-argument', s), [, argDefault] = this.childNodes;
125
+ if (lintConfig.computeEditInfo && argDefault) {
145
126
  e.suggestions = [(0, lint_1.fixBy)(e, 'expand', argDefault.text())];
146
127
  }
147
128
  errors.push(e);
148
129
  }
149
130
  const ext = this.closest('ext');
150
131
  if (ext) {
151
- const rule = 'arg-in-ext', severity = lintConfig.getSeverity(rule, ext.name);
152
- if (severity) {
153
- errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'argument-in-ext', severity));
132
+ rule = 'arg-in-ext';
133
+ s = lintConfig.getSeverity(rule, ext.name);
134
+ if (s) {
135
+ errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'argument-in-ext', s));
154
136
  }
155
137
  }
156
138
  return errors;
@@ -1,6 +1,6 @@
1
1
  import { Token } from './index';
2
2
  import type { Config } from '../base';
3
- declare const atomTypes: readonly ["arg-name", "attr-key", "attr-value", "ext-attr-dirty", "html-attr-dirty", "table-attr-dirty", "converter-flag", "converter-rule-variant", "invoke-function", "invoke-module", "template-name", "link-target"];
3
+ declare const atomTypes: readonly ["arg-name", "attr-key", "attr-value", "ext-attr-dirty", "html-attr-dirty", "table-attr-dirty", "converter-flag", "converter-rule-variant", "invoke-function", "invoke-module", "template-name", "link-target", "param-line-key", "param-line-value"];
4
4
  declare type AtomTypes = typeof atomTypes[number];
5
5
  /**
6
6
  * plain Token that will not be parsed further
package/dist/src/atom.js CHANGED
@@ -16,6 +16,8 @@ const atomTypes = [
16
16
  'invoke-module',
17
17
  'template-name',
18
18
  'link-target',
19
+ 'param-line-key',
20
+ 'param-line-value',
19
21
  ];
20
22
  /**
21
23
  * plain Token that will not be parsed further
@@ -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|\*\/)(?:java|vb)script(?:\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']), itemAttrs = new Set(['itemtype', 'itemid', 'itemref']), urlAttrs = new Set([
18
18
  'about',
19
19
  'property',
20
20
  'resource',
@@ -88,9 +88,13 @@ class AttributeToken extends index_2.Token {
88
88
  this.#tag = tag;
89
89
  this.setAttribute('name', (0, string_1.trimLc)((0, string_1.removeComment)(key)));
90
90
  }
91
+ /** 获取name */
92
+ #getName() {
93
+ return (0, string_1.trimLc)(this.firstChild.text());
94
+ }
91
95
  /** 更新name */
92
96
  #setName() {
93
- this.setAttribute('name', (0, string_1.trimLc)(this.firstChild.text()));
97
+ this.setAttribute('name', this.#getName());
94
98
  }
95
99
  /** @private */
96
100
  afterBuild() {
@@ -110,7 +114,9 @@ class AttributeToken extends index_2.Token {
110
114
  }
111
115
  /** @private */
112
116
  text() {
113
- return this.#equal ? `${super.text(`${this.#equal.trim()}"`)}"` : this.firstChild.text();
117
+ // eslint-disable-next-line @typescript-eslint/no-useless-default-assignment
118
+ const { lastChild, name = this.#getName() } = this;
119
+ return this.#equal ? `${name}${this.#equal.trim()}"${lastChild.text()}"` : name;
114
120
  }
115
121
  /** @private */
116
122
  getGaps() {
@@ -138,8 +144,7 @@ class AttributeToken extends index_2.Token {
138
144
  // 或非通用HTML属性
139
145
  || !/^(?:xmlns:[\w:.-]+|data-(?!ooui|mw|parsoid)[^:_]*)$/u.test(name)
140
146
  && (tag === 'meta' || tag === 'link' || !sharable_1.commonHtmlAttrs.has(name)))
141
- || (name === 'itemtype' || name === 'itemid' || name === 'itemref')
142
- && !parentNode?.hasAttr('itemscope')) {
147
+ || itemAttrs.has(name) && !parentNode?.hasAttr('itemscope')) {
143
148
  LINT: {
144
149
  const s = lintConfig.getSeverity(rule, 'unknown');
145
150
  if (s) {
@@ -124,10 +124,8 @@ class AttributesToken extends index_2.Token {
124
124
  * @param key attribute name / 属性名
125
125
  */
126
126
  getAttrToken(key) {
127
- LINT: {
128
- const tokens = this.getAttrTokens(key);
129
- return tokens[tokens.length - 1];
130
- }
127
+ const tokens = this.getAttrTokens(key);
128
+ return tokens[tokens.length - 1];
131
129
  }
132
130
  /**
133
131
  * Get the attribute
@@ -136,7 +134,7 @@ class AttributesToken extends index_2.Token {
136
134
  * @param key attribute name / 属性键
137
135
  */
138
136
  getAttr(key) {
139
- LINT: return this.getAttrToken(key)?.getValue();
137
+ return this.getAttrToken(key)?.getValue();
140
138
  }
141
139
  /** 是否位于闭合标签内 */
142
140
  #lint() {
@@ -219,20 +217,24 @@ class AttributesToken extends index_2.Token {
219
217
  const severity = lintConfig.getSeverity(rules[3], 'attribute');
220
218
  if (severity && duplicated.size > 0) {
221
219
  for (const key of duplicated) {
222
- const pairs = attrs.get(key).map(attr => [attr, attr.getValue()]);
223
- Array.prototype.push.apply(errors, pairs.map(([attr, value], i) => {
224
- const e = (0, lint_1.generateForChild)(attr, rect, rules[3], index_1.default.msg('duplicate-attribute', key), severity);
220
+ const pairs = attrs.get(key).map(attr => [attr, attr.getValue()]), duplication = Array.from({ length: pairs.length }), values = new Set();
221
+ for (let i = pairs.length - 1; i >= 0; i--) {
222
+ const [attr, value] = pairs[i], e = (0, lint_1.generateForChild)(attr, rect, rules[3], index_1.default.msg('duplicate-attribute', key), severity);
225
223
  if (computeEditInfo || fix) {
226
224
  const remove = (0, lint_1.fixByRemove)(e);
227
- if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
225
+ if (!value || values.has(value)) {
228
226
  e.fix = remove;
229
227
  }
230
- else if (computeEditInfo) {
231
- e.suggestions = [remove];
228
+ else {
229
+ values.add(value);
230
+ if (computeEditInfo) {
231
+ e.suggestions = [remove];
232
+ }
232
233
  }
233
234
  }
234
- return e;
235
- }));
235
+ duplication[i] = e;
236
+ }
237
+ Array.prototype.push.apply(errors, duplication);
236
238
  }
237
239
  }
238
240
  return errors;
@@ -7,6 +7,7 @@ import type { AstText, AttributesToken, ExtToken } from '../internal';
7
7
  * @classdesc `{childNodes: (AstText|CommentToken)[]}`
8
8
  */
9
9
  export declare abstract class CommentedToken extends Token {
10
+ readonly name: 'hiero';
10
11
  readonly childNodes: readonly (CommentToken | AstText)[];
11
12
  abstract get firstChild(): CommentToken | AstText | undefined;
12
13
  abstract get lastChild(): CommentToken | AstText | undefined;
@@ -13,9 +13,7 @@ class CommentedToken extends index_1.Token {
13
13
  }
14
14
  /** @class */
15
15
  constructor(wikitext, config, accum = []) {
16
- super(undefined, config, accum, {
17
- AstText: ':', CommentToken: ':',
18
- });
16
+ super(undefined, config, accum, {});
19
17
  if (wikitext) {
20
18
  let i = wikitext.indexOf('<!--'), j = i !== -1 && wikitext.indexOf('-->', i + 4), lastIndex = 0;
21
19
  while (j !== false && j !== -1) {
@@ -77,9 +77,13 @@ let ConverterFlagsToken = (() => {
77
77
  super(undefined, config, accum, {});
78
78
  this.safeAppend(flags.map(flag => new atom_1.AtomToken(flag, 'converter-flag', config, accum)));
79
79
  }
80
+ /** 获取全部转换类型标记 */
81
+ #getFlags() {
82
+ return this.childNodes.map(child => child.text().trim());
83
+ }
80
84
  /** @private */
81
85
  afterBuild() {
82
- this.#flags = this.childNodes.map(child => child.text().trim());
86
+ this.#flags = this.#getFlags();
83
87
  super.afterBuild();
84
88
  }
85
89
  /** @private */
@@ -88,7 +92,7 @@ let ConverterFlagsToken = (() => {
88
92
  }
89
93
  /** @private */
90
94
  text() {
91
- return super.text(';');
95
+ return (this.#flags ?? this.#getFlags()).join(';');
92
96
  }
93
97
  /**
94
98
  * Get unknown language conversion flags
@@ -129,9 +133,9 @@ let ConverterFlagsToken = (() => {
129
133
  }
130
134
  const rule = 'no-ignored', s = lintConfig.getSeverity(rule, 'conversionFlag');
131
135
  if (s) {
132
- const rect = new rect_1.BoundingRect(this, start);
133
- for (let i = 0; i < this.length; i++) {
134
- const child = this.childNodes[i], flag = child.text().trim();
136
+ const rect = new rect_1.BoundingRect(this, start), { childNodes, length } = this;
137
+ for (let i = 0; i < length; i++) {
138
+ const child = childNodes[i], flag = child.text().trim();
135
139
  if (this.isInvalidFlag(flag, variantFlags, unknownFlags)) {
136
140
  const e = (0, lint_1.generateForChild)(child, rect, rule, 'invalid-conversion-flag', s);
137
141
  if (computeEditInfo || fix) {
@@ -109,8 +109,8 @@ let ConverterRuleToken = (() => {
109
109
  text() {
110
110
  const { childNodes, firstChild, lastChild } = this;
111
111
  return childNodes.length === 3
112
- ? `${firstChild.text()}=>${childNodes[1].text()}:${lastChild.text()}`
113
- : super.text(':');
112
+ ? `${firstChild.text().trim()}=>${childNodes[1].text().trim()}:${lastChild.text().trim()}`
113
+ : childNodes.map(child => child.text().trim()).join(':');
114
114
  }
115
115
  /** @private */
116
116
  getGaps(i) {