wikilint 2.9.3 → 2.10.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 (54) hide show
  1. package/config/.schema.json +5 -0
  2. package/config/enwiki.json +2 -1
  3. package/config/llwiki.json +2 -1
  4. package/config/moegirl.json +2 -1
  5. package/config/zhwiki.json +2 -1
  6. package/dist/base.d.ts +2 -1
  7. package/dist/index.js +3 -4
  8. package/dist/lib/element.js +2 -2
  9. package/dist/lib/node.d.ts +6 -1
  10. package/dist/lib/node.js +7 -0
  11. package/dist/lib/text.d.ts +0 -2
  12. package/dist/lib/text.js +5 -4
  13. package/dist/mixin/hidden.d.ts +1 -0
  14. package/dist/mixin/hidden.js +2 -2
  15. package/dist/parser/list.js +8 -6
  16. package/dist/parser/table.js +2 -2
  17. package/dist/src/arg.js +2 -2
  18. package/dist/src/attribute.js +8 -24
  19. package/dist/src/attributes.js +1 -1
  20. package/dist/src/converter.d.ts +1 -1
  21. package/dist/src/converter.js +4 -3
  22. package/dist/src/converterFlags.js +2 -2
  23. package/dist/src/converterRule.js +9 -13
  24. package/dist/src/extLink.js +3 -3
  25. package/dist/src/gallery.js +2 -2
  26. package/dist/src/heading.js +4 -3
  27. package/dist/src/hidden.js +1 -1
  28. package/dist/src/html.js +2 -2
  29. package/dist/src/imageParameter.js +2 -2
  30. package/dist/src/imagemap.js +2 -2
  31. package/dist/src/index.js +10 -9
  32. package/dist/src/link/base.js +12 -7
  33. package/dist/src/link/file.js +1 -1
  34. package/dist/src/link/redirectTarget.d.ts +1 -1
  35. package/dist/src/link/redirectTarget.js +2 -6
  36. package/dist/src/magicLink.d.ts +2 -0
  37. package/dist/src/magicLink.js +37 -53
  38. package/dist/src/nowiki/comment.js +3 -3
  39. package/dist/src/nowiki/doubleUnderscore.js +1 -1
  40. package/dist/src/nowiki/noinclude.js +5 -1
  41. package/dist/src/onlyinclude.js +2 -2
  42. package/dist/src/paramTag/index.js +2 -2
  43. package/dist/src/parameter.js +11 -9
  44. package/dist/src/redirect.js +3 -3
  45. package/dist/src/syntax.d.ts +1 -1
  46. package/dist/src/syntax.js +2 -2
  47. package/dist/src/table/td.js +2 -2
  48. package/dist/src/table/trBase.js +3 -4
  49. package/dist/src/tagPair/include.js +5 -1
  50. package/dist/src/tagPair/index.js +3 -3
  51. package/dist/src/transclude.js +14 -13
  52. package/dist/util/lint.js +1 -1
  53. package/errors/README +2 -0
  54. package/package.json +1 -1
@@ -162,6 +162,11 @@
162
162
  "minItems": 2,
163
163
  "maxItems": 2
164
164
  }
165
+ },
166
+ "articlePath": {
167
+ "description": "base URL of internal links",
168
+ "type": "string",
169
+ "pattern": "\\$1"
165
170
  }
166
171
  },
167
172
  "required": [
@@ -409,5 +409,6 @@
409
409
  "redirection": [
410
410
  "#redirect"
411
411
  ],
412
- "variants": []
412
+ "variants": [],
413
+ "articlePath": "/wiki/$1"
413
414
  }
@@ -597,5 +597,6 @@
597
597
  "zh-sg",
598
598
  "zh-my",
599
599
  "zh-mo"
600
- ]
600
+ ],
601
+ "articlePath": "/zh/$1"
601
602
  }
@@ -687,5 +687,6 @@
687
687
  "zh-cn",
688
688
  "zh-tw",
689
689
  "zh-hk"
690
- ]
690
+ ],
691
+ "articlePath": "/$1"
691
692
  }
@@ -805,5 +805,6 @@
805
805
  "zh-sg",
806
806
  "zh-my",
807
807
  "zh-mo"
808
- ]
808
+ ],
809
+ "articlePath": "/wiki/$1"
809
810
  }
package/dist/base.d.ts CHANGED
@@ -38,8 +38,9 @@ export interface LintError {
38
38
  }
39
39
  /** 类似Node */
40
40
  export interface AstNode {
41
- type: string;
42
41
  readonly childNodes: readonly AstNode[];
42
+ /** 节点类型 */
43
+ type: string;
43
44
  /** Linter */
44
45
  lint(): LintError[];
45
46
  }
package/dist/index.js CHANGED
@@ -11,8 +11,7 @@ const string_1 = require("./util/string");
11
11
  * @param file 文件名
12
12
  * @param dir 子路径
13
13
  */
14
- const rootRequire = (file, dir) => require(file.startsWith('/') ? file : `../${file.includes('/') ? '' : dir}${file}`);
15
- // eslint-disable-next-line @typescript-eslint/no-redeclare
14
+ const rootRequire = (file, dir) => require(path.isAbsolute(file) ? file : path.join('..', file.includes('/') ? '' : dir, file));
16
15
  const Parser = {
17
16
  config: 'default',
18
17
  i18n: undefined,
@@ -20,7 +19,7 @@ const Parser = {
20
19
  /** @implements */
21
20
  getConfig() {
22
21
  if (typeof this.config === 'string') {
23
- this.config = rootRequire(this.config, 'config/');
22
+ this.config = rootRequire(this.config, 'config');
24
23
  return this.getConfig();
25
24
  }
26
25
  return {
@@ -31,7 +30,7 @@ const Parser = {
31
30
  /** @implements */
32
31
  msg(msg, arg = '') {
33
32
  if (typeof this.i18n === 'string') {
34
- this.i18n = rootRequire(this.i18n, 'i18n/');
33
+ this.i18n = rootRequire(this.i18n, 'i18n');
35
34
  return this.msg(msg, arg);
36
35
  }
37
36
  return msg && (this.i18n?.[msg] ?? msg).replace('$1', this.msg(arg));
@@ -158,8 +158,8 @@ class AstElement extends node_1.AstNode {
158
158
  return data;
159
159
  }
160
160
  /** @private */
161
- toString(separator = '') {
162
- return this.childNodes.map(String).join(separator);
161
+ toString(skip, separator = '') {
162
+ return this.childNodes.map(child => child.toString(skip)).join(separator);
163
163
  }
164
164
  /** @private */
165
165
  lint(start = this.getAbsoluteIndex(), re) {
@@ -18,9 +18,9 @@ export declare abstract class AstNode implements AstNodeBase {
18
18
  #private;
19
19
  data?: string | undefined;
20
20
  readonly childNodes: readonly AstNodes[];
21
- /** 节点类型 */
22
21
  abstract get type(): TokenTypes | 'text';
23
22
  abstract set type(value: TokenTypes | 'text');
23
+ /** 可见部分 */
24
24
  text(): string;
25
25
  lint(): LintError[];
26
26
  /** 首位子节点 */
@@ -51,4 +51,9 @@ export declare abstract class AstNode implements AstNodeBase {
51
51
  getRelativeIndex(j?: number): number;
52
52
  /** 获取当前节点的绝对位置 */
53
53
  getAbsoluteIndex(): number;
54
+ /**
55
+ * 是否是某种类型的节点
56
+ * @param type 节点类型
57
+ */
58
+ is<T extends Token>(type: string): this is T;
54
59
  }
package/dist/lib/node.js CHANGED
@@ -114,5 +114,12 @@ class AstNode {
114
114
  configurable: true,
115
115
  });
116
116
  }
117
+ /**
118
+ * 是否是某种类型的节点
119
+ * @param type 节点类型
120
+ */
121
+ is(type) {
122
+ return this.type === type;
123
+ }
117
124
  }
118
125
  exports.AstNode = AstNode;
@@ -8,8 +8,6 @@ export declare class AstText extends AstNode {
8
8
  get type(): 'text';
9
9
  /** @param text 包含文本 */
10
10
  constructor(text: string);
11
- /** 可见部分 */
12
- text(): string;
13
11
  /**
14
12
  * 替换字符串
15
13
  * @param text 替换的字符串
package/dist/lib/text.js CHANGED
@@ -63,12 +63,15 @@ class AstText extends node_1.AstNode {
63
63
  toString() {
64
64
  return this.data;
65
65
  }
66
- /** 可见部分 */
66
+ /** @private */
67
67
  text() {
68
68
  return this.data;
69
69
  }
70
70
  /** @private */
71
71
  lint(start = this.getAbsoluteIndex(), errorRegex) {
72
+ if (errorRegex === false) {
73
+ return [];
74
+ }
72
75
  const { data, parentNode, nextSibling, previousSibling } = this;
73
76
  if (!parentNode) {
74
77
  throw new Error('An isolated text node cannot be linted!');
@@ -108,9 +111,7 @@ class AstText extends node_1.AstNode {
108
111
  || char === '['
109
112
  && type === 'ext-link-text'
110
113
  && (/&(?:rbrack|#93|#x5[Dd];);/u.test(data.slice(index + 1))
111
- || nextType === 'ext'
112
- && nextName === 'nowiki'
113
- && nextSibling.innerText?.includes(']'))) {
114
+ || nextSibling?.is('ext') && nextName === 'nowiki' && nextSibling.innerText?.includes(']'))) {
114
115
  continue;
115
116
  }
116
117
  else if (char === ']' && (index || length > 1)) {
@@ -1,6 +1,7 @@
1
1
  /**
2
2
  * 解析后不可见的类
3
3
  * @param linter 是否覆写 lint 方法
4
+ * @param html 是否覆写 toHtml 方法
4
5
  * @param constructor 基类
5
6
  * @param _ context
6
7
  */
@@ -5,17 +5,17 @@ const debug_1 = require("../util/debug");
5
5
  /**
6
6
  * 解析后不可见的类
7
7
  * @param linter 是否覆写 lint 方法
8
+ * @param html 是否覆写 toHtml 方法
8
9
  * @param constructor 基类
9
10
  * @param _ context
10
11
  */
11
- const hiddenToken = (linter) => (constructor, _) => {
12
+ const hiddenToken = (linter = true, html = true) => (constructor, _) => {
12
13
  /** 解析后不可见的类 */
13
14
  class AnyHiddenToken extends constructor {
14
15
  /** 没有可见部分 */
15
16
  text() {
16
17
  return '';
17
18
  }
18
- /** @private */
19
19
  lint(start) {
20
20
  // @ts-expect-error private argument
21
21
  return linter ? [] : super.lint(start);
@@ -10,18 +10,20 @@ const dd_1 = require("../src/nowiki/dd");
10
10
  * @param accum
11
11
  */
12
12
  const parseList = (wikitext, config, accum) => {
13
- const mt = /^((?:\0\d+c\x7F)*)([;:*#]+)/u.exec(wikitext);
13
+ const mt = /^((?:\0\d+c\x7F)*)([;:*#]+\s*)/u.exec(wikitext);
14
14
  if (!mt) {
15
15
  return wikitext;
16
16
  }
17
- const [total, comment, prefix] = mt;
18
- let text = `${comment}\0${accum.length}d\x7F${wikitext.slice(total.length)}`, dt = prefix.split(';').length - 1;
19
- // @ts-expect-error abstract class
20
- new list_1.ListToken(prefix, config, accum);
17
+ const [total, comment, prefix] = mt, parts = prefix.split(/(?=;)/u);
18
+ let text = comment + parts.map((_, i) => `\0${accum.length + i}d\x7F`).join('') + wikitext.slice(total.length), dt = parts.length - (parts[0].startsWith(';') ? 0 : 1);
19
+ for (const part of parts) {
20
+ // @ts-expect-error abstract class
21
+ new list_1.ListToken(part, config, accum);
22
+ }
21
23
  if (!dt) {
22
24
  return text;
23
25
  }
24
- const { html: [normalTags] } = config, fullRegex = /:+|-\{|\0\d+[xq]\x7F/gu;
26
+ const { html: [normalTags] } = config, fullRegex = /:+\s*|-\{|\0\d+[xq]\x7F/gu;
25
27
  let regex = fullRegex, ex = regex.exec(text), lt = 0, lb = false, li = false, lc = 0;
26
28
  /**
27
29
  * 创建`DdToken`
@@ -67,8 +67,8 @@ const parseTable = ({ firstChild: { data }, type, name }, config, accum) => {
67
67
  out += `\n${outLine}`;
68
68
  continue;
69
69
  }
70
- // eslint-disable-next-line @stylistic/operator-linebreak
71
- const matches = /^(?:(\|\}|\0\d+!\x7F\}|\0\d+\}\x7F)|(\|-+|\0\d+!\x7F-+|\0\d+-\x7F-*)(?!-)|(!|(?:\||\0\d+!\x7F)\+?))(.*)$/u
70
+ const matches = // eslint-disable-line @stylistic/operator-linebreak
71
+ /^(?:(\|\}|\0\d+!\x7F\}|\0\d+\}\x7F)|(\|-+|\0\d+!\x7F-+|\0\d+-\x7F-*)(?!-)|(!|(?:\||\0\d+!\x7F)\+?))(.*)$/u
72
72
  .exec(line);
73
73
  if (!matches) {
74
74
  push(`\n${outLine}`, top);
package/dist/src/arg.js CHANGED
@@ -41,8 +41,8 @@ class ArgToken extends index_2.Token {
41
41
  }
42
42
  }
43
43
  /** @private */
44
- toString() {
45
- return `{{{${super.toString('|')}}}}`;
44
+ toString(skip) {
45
+ return `{{{${super.toString(skip, '|')}}}}`;
46
46
  }
47
47
  /** @private */
48
48
  text() {
@@ -60,7 +60,6 @@ const commonHtmlAttrs = new Set([
60
60
  img: new Set(['alt', 'src', 'width', 'height', 'srcset']),
61
61
  font: new Set(['size', 'color', 'face']),
62
62
  hr: widthAttrs,
63
- rt: new Set(['rbspan']),
64
63
  data: new Set(['value']),
65
64
  time: new Set(['datetime']),
66
65
  meta: new Set(['itemprop', 'content']),
@@ -194,23 +193,15 @@ class AttributeToken extends index_2.Token {
194
193
  * @param quotes 引号
195
194
  */
196
195
  constructor(type, tag, key, equal = '', value, quotes = [], config = index_1.default.getConfig(), accum = []) {
197
- const keyToken = new atom_1.AtomToken(key, 'attr-key', config, accum, {});
196
+ const keyToken = new atom_1.AtomToken(key, 'attr-key', config, accum);
198
197
  let valueToken;
199
198
  if (key === 'title' || tag === 'img' && key === 'alt') {
200
199
  valueToken = new index_2.Token(value, config, accum, {});
201
200
  valueToken.type = 'attr-value';
202
201
  valueToken.setAttribute('stage', constants_1.MAX_STAGE - 1);
203
202
  }
204
- else if (tag === 'gallery' && key === 'caption') {
205
- const newConfig = {
206
- ...config,
207
- excludes: [...config.excludes, 'quote', 'extLink', 'magicLink', 'list'],
208
- };
209
- valueToken = new index_2.Token(value, newConfig, accum, {});
210
- valueToken.type = 'attr-value';
211
- valueToken.setAttribute('stage', 5);
212
- }
213
- else if (tag === 'choose' && (key === 'before' || key === 'after')) {
203
+ else if (tag === 'gallery' && key === 'caption'
204
+ || tag === 'choose' && (key === 'before' || key === 'after')) {
214
205
  const newConfig = {
215
206
  ...config,
216
207
  excludes: [...config.excludes, 'heading', 'html', 'table', 'hr', 'list'],
@@ -238,13 +229,13 @@ class AttributeToken extends index_2.Token {
238
229
  if (this.parentNode) {
239
230
  this.#tag = this.parentNode.name;
240
231
  }
241
- this.setAttribute('name', this.firstChild.text().trim().toLowerCase());
232
+ this.setAttribute('name', this.firstChild.toString(true).trim().toLowerCase());
242
233
  super.afterBuild();
243
234
  }
244
235
  /** @private */
245
- toString() {
236
+ toString(skip) {
246
237
  const [quoteStart = '', quoteEnd = ''] = this.#quotes;
247
- return this.#equal ? super.toString(this.#equal + quoteStart) + quoteEnd : this.firstChild.toString();
238
+ return this.#equal ? super.toString(skip, this.#equal + quoteStart) + quoteEnd : this.firstChild.toString(skip);
248
239
  }
249
240
  /** @private */
250
241
  text() {
@@ -292,7 +283,7 @@ class AttributeToken extends index_2.Token {
292
283
  else if (name === 'style' && typeof value === 'string' && insecureStyle.test(value)) {
293
284
  errors.push((0, lint_1.generateForChild)(lastChild, rect, 'insecure-style', 'insecure style'));
294
285
  }
295
- else if (name === 'tabindex' && typeof value === 'string' && value.trim() !== '0') {
286
+ else if (name === 'tabindex' && typeof value === 'string' && value !== '0') {
296
287
  const e = (0, lint_1.generateForChild)(lastChild, rect, 'illegal-attr', 'nonzero tabindex');
297
288
  e.suggestions = [
298
289
  {
@@ -312,14 +303,7 @@ class AttributeToken extends index_2.Token {
312
303
  }
313
304
  /** 获取属性值 */
314
305
  getValue() {
315
- if (this.#equal) {
316
- const value = this.lastChild.text();
317
- if (this.#quotes[1]) {
318
- return value;
319
- }
320
- return value[this.#quotes[0] ? 'trimEnd' : 'trim']();
321
- }
322
- return this.type === 'ext-attr' || '';
306
+ return this.#equal ? this.lastChild.text().trim() : this.type === 'ext-attr' || '';
323
307
  }
324
308
  }
325
309
  exports.AttributeToken = AttributeToken;
@@ -123,7 +123,7 @@ class AttributesToken extends index_2.Token {
123
123
  duplicated.add(name);
124
124
  attrs.get(name).push(attr);
125
125
  }
126
- else if (name !== 'class') {
126
+ else {
127
127
  attrs.set(name, [attr]);
128
128
  }
129
129
  }
@@ -7,7 +7,7 @@ import { ConverterRuleToken } from './converterRule';
7
7
  * @classdesc `{childNodes: [ConverterFlagsToken, ...ConverterRuleToken]}`
8
8
  */
9
9
  export declare abstract class ConverterToken extends Token {
10
- readonly childNodes: readonly [ConverterFlagsToken, ...ConverterRuleToken[]];
10
+ readonly childNodes: readonly [ConverterFlagsToken, ConverterRuleToken, ...ConverterRuleToken[]];
11
11
  abstract get firstChild(): ConverterFlagsToken;
12
12
  abstract get lastChild(): ConverterFlagsToken | ConverterRuleToken;
13
13
  get type(): 'converter';
@@ -25,7 +25,8 @@ class ConverterToken extends index_2.Token {
25
25
  const [firstRule] = rules, hasColon = firstRule.includes(':'),
26
26
  // @ts-expect-error abstract class
27
27
  firstRuleToken = new converterRule_1.ConverterRuleToken(firstRule, hasColon, config, accum);
28
- if (hasColon && firstRuleToken.length === 1) {
28
+ if (hasColon && firstRuleToken.length === 1
29
+ || !hasColon && rules.length === 2 && !(0, string_1.removeComment)(rules[1]).trim()) {
29
30
  // @ts-expect-error abstract class
30
31
  this.insertAt(new converterRule_1.ConverterRuleToken(rules.join(';'), false, config, accum));
31
32
  }
@@ -36,9 +37,9 @@ class ConverterToken extends index_2.Token {
36
37
  }
37
38
  }
38
39
  /** @private */
39
- toString() {
40
+ toString(skip) {
40
41
  const { childNodes: [flags, ...rules] } = this;
41
- return `-{${flags.toString()}${flags.length > 0 ? '|' : ''}${rules.map(String).join(';')}}-`;
42
+ return `-{${flags.toString(skip)}${flags.length > 0 ? '|' : ''}${rules.map(rule => rule.toString(skip)).join(';')}}-`;
42
43
  }
43
44
  /** @private */
44
45
  text() {
@@ -27,8 +27,8 @@ class ConverterFlagsToken extends index_2.Token {
27
27
  super.afterBuild();
28
28
  }
29
29
  /** @private */
30
- toString() {
31
- return super.toString(';');
30
+ toString(skip) {
31
+ return super.toString(skip, ';');
32
32
  }
33
33
  /** @private */
34
34
  text() {
@@ -31,22 +31,18 @@ class ConverterRuleToken extends index_2.Token {
31
31
  }
32
32
  }
33
33
  /** @private */
34
- toString() {
35
- const { childNodes } = this;
36
- if (childNodes.length === 3) {
37
- const [from, variant, to] = childNodes;
38
- return `${from.toString()}=>${variant.toString()}:${to.toString()}`;
39
- }
40
- return super.toString(':');
34
+ toString(skip) {
35
+ const { childNodes, firstChild, lastChild } = this;
36
+ return childNodes.length === 3
37
+ ? `${firstChild.toString(skip)}=>${childNodes[1].toString(skip)}:${lastChild.toString(skip)}`
38
+ : super.toString(skip, ':');
41
39
  }
42
40
  /** @private */
43
41
  text() {
44
- const { childNodes } = this;
45
- if (childNodes.length === 3) {
46
- const [from, variant, to] = childNodes;
47
- return `${from.text()}=>${variant.text()}:${to.text()}`;
48
- }
49
- return super.text(':');
42
+ const { childNodes, firstChild, lastChild } = this;
43
+ return childNodes.length === 3
44
+ ? `${firstChild.text()}=>${childNodes[1].text()}:${lastChild.text()}`
45
+ : super.text(':');
50
46
  }
51
47
  /** @private */
52
48
  getGaps(i) {
@@ -36,11 +36,11 @@ class ExtLinkToken extends index_2.Token {
36
36
  }
37
37
  }
38
38
  /** @private */
39
- toString() {
39
+ toString(skip) {
40
40
  if (this.length === 1) {
41
- return `[${super.toString()}${this.#space}]`;
41
+ return `[${super.toString(skip)}${this.#space}]`;
42
42
  }
43
- return `[${super.toString(this.#space)}]`;
43
+ return `[${super.toString(skip, this.#space)}]`;
44
44
  }
45
45
  /** @private */
46
46
  text() {
@@ -42,8 +42,8 @@ class GalleryToken extends index_2.Token {
42
42
  return this.normalizeTitle(file, 6, true, true).valid;
43
43
  }
44
44
  /** @private */
45
- toString() {
46
- return super.toString('\n');
45
+ toString(skip) {
46
+ return super.toString(skip, '\n');
47
47
  }
48
48
  /** @private */
49
49
  text() {
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.HeadingToken = void 0;
4
4
  const lint_1 = require("../util/lint");
5
5
  const rect_1 = require("../lib/rect");
6
+ const debug_1 = require("../util/debug");
6
7
  const index_1 = require("../index");
7
8
  const index_2 = require("./index");
8
9
  const syntax_1 = require("./syntax");
@@ -37,9 +38,9 @@ class HeadingToken extends index_2.Token {
37
38
  this.append(token, trail);
38
39
  }
39
40
  /** @private */
40
- toString() {
41
+ toString(skip) {
41
42
  const equals = this.#equals;
42
- return equals + this.firstChild.toString() + equals + this.lastChild.toString();
43
+ return equals + this.firstChild.toString(skip) + equals + this.lastChild.toString(skip);
43
44
  }
44
45
  /** @private */
45
46
  text() {
@@ -56,7 +57,7 @@ class HeadingToken extends index_2.Token {
56
57
  }
57
58
  /** @private */
58
59
  lint(start = this.getAbsoluteIndex(), re) {
59
- const errors = super.lint(start, re), { firstChild, level } = this, innerStr = firstChild.toString(), quotes = firstChild.childNodes.filter((node) => node.type === 'quote'), boldQuotes = quotes.filter(({ bold }) => bold), italicQuotes = quotes.filter(({ italic }) => italic), rect = new rect_1.BoundingRect(this, start);
60
+ const errors = super.lint(start, re), { firstChild, level } = this, innerStr = firstChild.toString(), quotes = firstChild.childNodes.filter((0, debug_1.isToken)('quote')), boldQuotes = quotes.filter(({ bold }) => bold), italicQuotes = quotes.filter(({ italic }) => italic), rect = new rect_1.BoundingRect(this, start);
60
61
  if (this.level === 1) {
61
62
  errors.push((0, lint_1.generateForChild)(firstChild, rect, 'h1', '<h1>'));
62
63
  }
@@ -39,7 +39,7 @@ const hidden_1 = require("../mixin/hidden");
39
39
  const index_1 = require("./index");
40
40
  /** 不可见的节点 */
41
41
  let HiddenToken = (() => {
42
- let _classDecorators = [(0, hidden_1.hiddenToken)(true)];
42
+ let _classDecorators = [(0, hidden_1.hiddenToken)()];
43
43
  let _classDescriptor;
44
44
  let _classExtraInitializers = [];
45
45
  let _classThis;
package/dist/src/html.js CHANGED
@@ -66,8 +66,8 @@ class HtmlToken extends index_1.Token {
66
66
  this.#tag = name;
67
67
  }
68
68
  /** @private */
69
- toString() {
70
- return `<${this.closing ? '/' : ''}${this.#tag}${super.toString()}${this.#selfClosing ? '/' : ''}>`;
69
+ toString(skip) {
70
+ return `<${this.closing ? '/' : ''}${this.#tag}${super.toString(skip)}${this.#selfClosing ? '/' : ''}>`;
71
71
  }
72
72
  /** @private */
73
73
  text() {
@@ -86,8 +86,8 @@ class ImageParameterToken extends index_2.Token {
86
86
  super.afterBuild();
87
87
  }
88
88
  /** @private */
89
- toString() {
90
- return this.#syntax ? this.#syntax.replace('$1', super.toString()) : super.toString();
89
+ toString(skip) {
90
+ return this.#syntax ? this.#syntax.replace('$1', super.toString(skip)) : super.toString(skip);
91
91
  }
92
92
  /** @private */
93
93
  text() {
@@ -77,8 +77,8 @@ class ImagemapToken extends index_2.Token {
77
77
  }
78
78
  }
79
79
  /** @private */
80
- toString() {
81
- return super.toString('\n');
80
+ toString(skip) {
81
+ return super.toString(skip, '\n');
82
82
  }
83
83
  /** @private */
84
84
  text() {
package/dist/src/index.js CHANGED
@@ -80,7 +80,7 @@ class Token extends element_1.AstElement {
80
80
  }
81
81
  /** @private */
82
82
  parseOnce(n = this.#stage, include = false) {
83
- if (n < this.#stage || !this.getAttribute('plain') || this.length === 0) {
83
+ if (n < this.#stage || this.length === 0 || !this.getAttribute('plain')) {
84
84
  return this;
85
85
  }
86
86
  else if (this.#stage >= constants_1.MAX_STAGE) {
@@ -89,7 +89,7 @@ class Token extends element_1.AstElement {
89
89
  switch (n) {
90
90
  case 0:
91
91
  if (this.type === 'root') {
92
- this.#accum.shift();
92
+ this.#accum.pop();
93
93
  const isRedirect = this.#parseRedirect();
94
94
  include &&= !isRedirect;
95
95
  }
@@ -129,7 +129,7 @@ class Token extends element_1.AstElement {
129
129
  }
130
130
  if (this.type === 'root') {
131
131
  for (const token of this.#accum) {
132
- token.parseOnce(n, include);
132
+ token?.parseOnce(n, include); // eslint-disable-line @typescript-eslint/no-unnecessary-condition
133
133
  }
134
134
  }
135
135
  this.#stage++;
@@ -163,7 +163,7 @@ class Token extends element_1.AstElement {
163
163
  this.normalize();
164
164
  if (this.type === 'root') {
165
165
  for (const token of this.#accum) {
166
- token.build();
166
+ token?.build(); // eslint-disable-line @typescript-eslint/no-unnecessary-condition
167
167
  }
168
168
  }
169
169
  }
@@ -172,7 +172,7 @@ class Token extends element_1.AstElement {
172
172
  afterBuild() {
173
173
  if (this.type === 'root') {
174
174
  for (const token of this.#accum) {
175
- token.afterBuild();
175
+ token?.afterBuild(); // eslint-disable-line @typescript-eslint/no-unnecessary-condition
176
176
  }
177
177
  }
178
178
  this.#built = true;
@@ -401,14 +401,15 @@ class Token extends element_1.AstElement {
401
401
  return errors;
402
402
  }
403
403
  /** @private */
404
- toString(separator) {
404
+ toString(skip, separator) {
405
405
  const { rev } = debug_1.Shadow, root = this.getRootNode();
406
- if (root.type === 'root'
406
+ if (!skip
407
+ && root.type === 'root'
407
408
  && root.#built) {
408
- this.#string ??= [rev, super.toString(separator)];
409
+ this.#string ??= [rev, super.toString(false, separator)];
409
410
  return this.#string[1];
410
411
  }
411
- return super.toString(separator);
412
+ return super.toString(skip, separator);
412
413
  }
413
414
  }
414
415
  exports.Token = Token;
@@ -7,6 +7,11 @@ const constants_1 = require("../../util/constants");
7
7
  const index_1 = require("../../index");
8
8
  const index_2 = require("../index");
9
9
  const atom_1 = require("../atom");
10
+ /**
11
+ * 是否为普通内链
12
+ * @param type 节点类型
13
+ */
14
+ const isLink = (type) => type === 'redirect-target' || type === 'link';
10
15
  /**
11
16
  * 内链
12
17
  * @classdesc `{childNodes: [AtomToken, ...Token]}`
@@ -53,8 +58,8 @@ class LinkBaseToken extends index_2.Token {
53
58
  }
54
59
  }
55
60
  /** @private */
56
- toString() {
57
- const str = super.toString(this.#delimiter);
61
+ toString(skip) {
62
+ const str = super.toString(skip, this.#delimiter);
58
63
  return this.#bracket ? `[[${str}]]` : str;
59
64
  }
60
65
  /** @private */
@@ -75,14 +80,14 @@ class LinkBaseToken extends index_2.Token {
75
80
  }
76
81
  /** @private */
77
82
  lint(start = this.getAbsoluteIndex(), re) {
78
- const errors = super.lint(start, re), { childNodes: [target, linkText], type: linkType } = this, { encoded, fragment } = this.#title, rect = new rect_1.BoundingRect(this, start);
79
- if (target.childNodes.some(({ type }) => type === 'template')) {
83
+ const errors = super.lint(start, re), { childNodes: [target, linkText], type } = this, { encoded, fragment } = this.#title, rect = new rect_1.BoundingRect(this, start);
84
+ if (target.childNodes.some(({ type: t }) => t === 'template')) {
80
85
  errors.push((0, lint_1.generateForChild)(target, rect, 'unknown-page', 'template in an internal link target', 'warning'));
81
86
  }
82
87
  if (encoded) {
83
88
  errors.push((0, lint_1.generateForChild)(target, rect, 'url-encoding', 'unnecessary URL encoding in an internal link'));
84
89
  }
85
- if (linkType === 'link' || linkType === 'category') {
90
+ if (type === 'link' || type === 'category') {
86
91
  const textNode = linkText?.childNodes.find((c) => c.type === 'text' && c.data.includes('|'));
87
92
  if (textNode) {
88
93
  const e = (0, lint_1.generateForChild)(linkText, rect, 'pipe-like', 'additional "|" in the link text', 'warning');
@@ -99,7 +104,7 @@ class LinkBaseToken extends index_2.Token {
99
104
  errors.push(e);
100
105
  }
101
106
  }
102
- if (linkType !== 'link' && linkType !== 'redirect-target' && fragment !== undefined) {
107
+ if (fragment !== undefined && !isLink(type)) {
103
108
  const e = (0, lint_1.generateForChild)(target, rect, 'no-ignored', 'useless fragment'), textNode = target.childNodes.find((c) => c.type === 'text' && c.data.includes('#'));
104
109
  if (textNode) {
105
110
  e.fix = {
@@ -113,7 +118,7 @@ class LinkBaseToken extends index_2.Token {
113
118
  }
114
119
  /** @private */
115
120
  getTitle(halfParsed) {
116
- return this.normalizeTitle(this.firstChild.text(), 0, halfParsed, true, true);
121
+ return this.normalizeTitle(this.firstChild.toString(true), 0, halfParsed, true, true);
117
122
  }
118
123
  }
119
124
  exports.LinkBaseToken = LinkBaseToken;
@@ -57,7 +57,7 @@ class FileToken extends base_1.LinkBaseToken {
57
57
  const { extension } = this.getTitle(true);
58
58
  this.append(...explode('-{', '}-', '|', text).map(
59
59
  // @ts-expect-error abstract class
60
- part => new imageParameter_1.ImageParameterToken(part, extension, config, accum)));
60
+ (part) => new imageParameter_1.ImageParameterToken(part, extension, config, accum)));
61
61
  }
62
62
  /** @private */
63
63
  lint(start = this.getAbsoluteIndex(), re) {
@@ -6,7 +6,7 @@ import type { Title } from '../../lib/title';
6
6
  import type { Token, AtomToken } from '../../internal';
7
7
  /**
8
8
  * 重定向目标
9
- * @classdesc `{childNodes: [AtomToken, ?Token]}`
9
+ * @classdesc `{childNodes: [AtomToken, ?NoincludeToken]}`
10
10
  */
11
11
  export declare abstract class RedirectTargetToken extends LinkBaseToken {
12
12
  readonly childNodes: readonly [AtomToken] | readonly [AtomToken, NoincludeToken];
@@ -7,7 +7,7 @@ const base_1 = require("./base");
7
7
  const noinclude_1 = require("../nowiki/noinclude");
8
8
  /**
9
9
  * 重定向目标
10
- * @classdesc `{childNodes: [AtomToken, ?Token]}`
10
+ * @classdesc `{childNodes: [AtomToken, ?NoincludeToken]}`
11
11
  */
12
12
  class RedirectTargetToken extends base_1.LinkBaseToken {
13
13
  get type() {
@@ -30,12 +30,8 @@ class RedirectTargetToken extends base_1.LinkBaseToken {
30
30
  return this.normalizeTitle(this.firstChild.toString(), 0, true, true);
31
31
  }
32
32
  /** @private */
33
- text() {
34
- return `[[${this.firstChild.toString()}]]`;
35
- }
36
- /** @private */
37
33
  lint(start = this.getAbsoluteIndex()) {
38
- const errors = super.lint(start, /\]\]/u);
34
+ const errors = super.lint(start, false);
39
35
  if (this.length === 2) {
40
36
  const e = (0, lint_1.generateForChild)(this.lastChild, { start }, 'no-ignored', 'useless link text');
41
37
  e.startIndex--;
@@ -13,6 +13,8 @@ export declare abstract class MagicLinkToken extends Token {
13
13
  abstract get firstChild(): AstText | TranscludeToken;
14
14
  abstract get lastChild(): AstText | CommentToken | IncludeToken | NoincludeToken | TranscludeToken;
15
15
  get type(): ExtLinkTypes;
16
+ /** 链接显示文字 */
17
+ get innerText(): string;
16
18
  /** 和内链保持一致 */
17
19
  get link(): string;
18
20
  /**
@@ -16,21 +16,26 @@ class MagicLinkToken extends index_2.Token {
16
16
  get type() {
17
17
  return this.#type;
18
18
  }
19
- /** 和内链保持一致 */
20
- get link() {
21
- const map = { '!': '|', '=': '=' };
19
+ /** 链接显示文字 */
20
+ get innerText() {
21
+ const map = new Map([['!', '|'], ['=', '=']]);
22
22
  let link = (0, string_1.text)(this.childNodes.map(child => {
23
- const { type, name } = child;
24
- return type === 'magic-word' && String(name) in map ? map[name] : child;
23
+ const { type } = child, name = String(child.name);
24
+ return type === 'magic-word' && map.has(name) ? map.get(name) : child;
25
25
  }));
26
26
  if (this.type === 'magic-link') {
27
27
  link = link.replace(spaceRegex, ' ');
28
- if (link.startsWith('ISBN')) {
29
- link = `ISBN ${link.slice(5).replace(/[- ]/gu, '').replace(/x$/u, 'X')}`;
30
- }
31
28
  }
32
29
  return link;
33
30
  }
31
+ /** 和内链保持一致 */
32
+ get link() {
33
+ let { innerText } = this;
34
+ if (this.type === 'magic-link' && innerText.startsWith('ISBN')) {
35
+ innerText = `ISBN ${innerText.slice(5).replace(/[- ]/gu, '').replace(/x$/u, 'X')}`;
36
+ }
37
+ return innerText;
38
+ }
34
39
  /**
35
40
  * @param url 网址
36
41
  * @param type 类型
@@ -55,51 +60,30 @@ class MagicLinkToken extends index_2.Token {
55
60
  }
56
61
  return errors;
57
62
  }
58
- const pipe = this.type === 'ext-link-url', source = pipe ? String.raw `\|+` : '[,;。:!?()]+', regex = new RegExp(source, 'u'), regexGlobal = new RegExp(source, 'gu');
59
- for (const child of this.childNodes) {
60
- const { type, data } = child;
61
- if (type !== 'text' || !regex.test(data)) {
62
- continue;
63
- }
64
- const refError = (0, lint_1.generateForChild)(child, rect, 'unterminated-url', '', 'warning');
65
- regexGlobal.lastIndex = 0;
66
- for (let mt = regexGlobal.exec(data); mt; mt = regexGlobal.exec(data)) {
67
- const { index, 0: s } = mt, lines = data.slice(0, index).split('\n'), top = lines.length, left = lines[top - 1].length, startIndex = refError.startIndex + index, startLine = refError.startLine + top - 1, startCol = top === 1 ? refError.startCol + left : left;
68
- const e = {
69
- ...refError,
70
- message: index_1.default.msg('$1 in URL', pipe ? '"|"' : 'full-width punctuation'),
71
- startIndex,
72
- endIndex: startIndex + s.length,
73
- startLine,
74
- endLine: startLine,
75
- startCol,
76
- endCol: startCol + s.length,
77
- };
78
- if (!pipe) {
79
- e.suggestions = [
80
- {
81
- desc: 'whitespace',
82
- range: [startIndex, startIndex],
83
- text: ' ',
84
- },
85
- {
86
- desc: 'escape',
87
- range: [startIndex, e.endIndex],
88
- text: encodeURI(s),
89
- },
90
- ];
91
- }
92
- else if (s.length === 1) {
93
- e.suggestions = [
94
- {
95
- desc: 'whitespace',
96
- range: [startIndex, startIndex + 1],
97
- text: ' ',
98
- },
99
- ];
100
- }
101
- errors.push(e);
102
- }
63
+ const pipe = this.type === 'ext-link-url', regex = pipe ? /\|/u : /[,;。:!?()]+/u, child = this.childNodes.find((c) => c.type === 'text' && regex.test(c.data));
64
+ if (child) {
65
+ const { data } = child, e = (0, lint_1.generateForChild)(child, rect, 'unterminated-url', index_1.default.msg('$1 in URL', pipe ? '"|"' : 'full-width punctuation'), 'warning'), { index, 0: s } = regex.exec(data), i = e.startIndex + index;
66
+ e.suggestions = pipe
67
+ ? [
68
+ {
69
+ desc: 'whitespace',
70
+ range: [i, i + 1],
71
+ text: ' ',
72
+ },
73
+ ]
74
+ : [
75
+ {
76
+ desc: 'whitespace',
77
+ range: [i, i],
78
+ text: ' ',
79
+ },
80
+ {
81
+ desc: 'escape',
82
+ range: [i, i + s.length],
83
+ text: encodeURI(s),
84
+ },
85
+ ];
86
+ errors.push(e);
103
87
  }
104
88
  return errors;
105
89
  }
@@ -41,7 +41,7 @@ const index_1 = require("../../index");
41
41
  const base_1 = require("./base");
42
42
  /** HTML注释,不可见 */
43
43
  let CommentToken = (() => {
44
- let _classDecorators = [(0, hidden_1.hiddenToken)()];
44
+ let _classDecorators = [(0, hidden_1.hiddenToken)(false)];
45
45
  let _classDescriptor;
46
46
  let _classExtraInitializers = [];
47
47
  let _classThis;
@@ -81,8 +81,8 @@ let CommentToken = (() => {
81
81
  return [e];
82
82
  }
83
83
  /** @private */
84
- toString() {
85
- return `<!--${this.innerText}${this.closed ? '-->' : ''}`;
84
+ toString(skip) {
85
+ return skip ? '' : `<!--${this.innerText}${this.closed ? '-->' : ''}`;
86
86
  }
87
87
  };
88
88
  return CommentToken = _classThis;
@@ -39,7 +39,7 @@ const hidden_1 = require("../../mixin/hidden");
39
39
  const base_1 = require("./base");
40
40
  /** 状态开关 */
41
41
  let DoubleUnderscoreToken = (() => {
42
- let _classDecorators = [(0, hidden_1.hiddenToken)(true)];
42
+ let _classDecorators = [(0, hidden_1.hiddenToken)()];
43
43
  let _classDescriptor;
44
44
  let _classExtraInitializers = [];
45
45
  let _classThis;
@@ -39,7 +39,7 @@ const hidden_1 = require("../../mixin/hidden");
39
39
  const base_1 = require("./base");
40
40
  /** `<noinclude>`和`</noinclude>`,不可进行任何更改 */
41
41
  let NoincludeToken = (() => {
42
- let _classDecorators = [(0, hidden_1.hiddenToken)(true)];
42
+ let _classDecorators = [(0, hidden_1.hiddenToken)()];
43
43
  let _classDescriptor;
44
44
  let _classExtraInitializers = [];
45
45
  let _classThis;
@@ -56,6 +56,10 @@ let NoincludeToken = (() => {
56
56
  get type() {
57
57
  return 'noinclude';
58
58
  }
59
+ /** @private */
60
+ toString(skip) {
61
+ return skip ? '' : super.toString();
62
+ }
59
63
  };
60
64
  return NoincludeToken = _classThis;
61
65
  })();
@@ -11,8 +11,8 @@ class OnlyincludeToken extends index_1.Token {
11
11
  return 'onlyinclude';
12
12
  }
13
13
  /** @private */
14
- toString() {
15
- return `<onlyinclude>${super.toString()}</onlyinclude>`;
14
+ toString(skip) {
15
+ return `<onlyinclude>${super.toString(skip)}</onlyinclude>`;
16
16
  }
17
17
  /** @private */
18
18
  getAttribute(key) {
@@ -23,8 +23,8 @@ class ParamTagToken extends index_2.Token {
23
23
  }
24
24
  }
25
25
  /** @private */
26
- toString() {
27
- return super.toString('\n');
26
+ toString(skip) {
27
+ return super.toString(skip, '\n');
28
28
  }
29
29
  /** @private */
30
30
  text() {
@@ -5,11 +5,6 @@ const string_1 = require("../util/string");
5
5
  const lint_1 = require("../util/lint");
6
6
  const index_1 = require("../index");
7
7
  const index_2 = require("./index");
8
- /**
9
- * 准确获取参数名
10
- * @param name 预定的参数名
11
- */
12
- const getName = (name) => name.text().replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1');
13
8
  const linkRegex = new RegExp(`https?://${string_1.extUrlCharFirst}${string_1.extUrlChar}$`, 'iu');
14
9
  /**
15
10
  * 模板或魔术字参数
@@ -31,15 +26,22 @@ class ParameterToken extends index_2.Token {
31
26
  super(undefined, config, accum);
32
27
  const keyToken = new index_2.Token(typeof key === 'number' ? undefined : key, config, accum, {}), token = new index_2.Token(value, config, accum);
33
28
  keyToken.type = 'parameter-key';
29
+ keyToken.setAttribute('stage', 2);
34
30
  token.type = 'parameter-value';
35
31
  token.setAttribute('stage', 2);
36
32
  this.append(keyToken, token);
37
33
  }
38
34
  /** @private */
35
+ trimName(name, set = true) {
36
+ const trimmed = (typeof name === 'string' ? name : name.toString(true))
37
+ .replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1');
38
+ this.setAttribute('name', trimmed);
39
+ return trimmed;
40
+ }
41
+ /** @private */
39
42
  afterBuild() {
40
43
  if (!this.anon) {
41
- const { parentNode, firstChild } = this, name = getName(firstChild);
42
- this.setAttribute('name', name);
44
+ const { parentNode, firstChild } = this, name = this.trimName(firstChild);
43
45
  if (parentNode) {
44
46
  parentNode.getArgs(name, false, false).add(this);
45
47
  }
@@ -47,8 +49,8 @@ class ParameterToken extends index_2.Token {
47
49
  super.afterBuild();
48
50
  }
49
51
  /** @private */
50
- toString() {
51
- return this.anon ? this.lastChild.toString() : super.toString('=');
52
+ toString(skip) {
53
+ return this.anon ? this.lastChild.toString(skip) : super.toString(skip, '=');
52
54
  }
53
55
  text() {
54
56
  return this.anon ? this.lastChild.text() : super.text('=');
@@ -45,7 +45,7 @@ const redirectTarget_1 = require("./link/redirectTarget");
45
45
  * @classdesc `{childNodes: [SyntaxToken, LinkToken]}`
46
46
  */
47
47
  let RedirectToken = (() => {
48
- let _classDecorators = [(0, hidden_1.hiddenToken)()];
48
+ let _classDecorators = [(0, hidden_1.hiddenToken)(false, false)];
49
49
  let _classDescriptor;
50
50
  let _classExtraInitializers = [];
51
51
  let _classThis;
@@ -85,8 +85,8 @@ let RedirectToken = (() => {
85
85
  return key === 'padding' ? this.#pre.length : super.getAttribute(key);
86
86
  }
87
87
  /** @private */
88
- toString() {
89
- return this.#pre + super.toString() + this.#post;
88
+ toString(skip) {
89
+ return this.#pre + super.toString(skip) + this.#post;
90
90
  }
91
91
  /** @private */
92
92
  lint(start = this.getAbsoluteIndex()) {
@@ -1,5 +1,5 @@
1
1
  import { Token } from './index';
2
- import type { Config } from '../base';
2
+ import type { Config, LintError } from '../base';
3
3
  declare type SyntaxTypes = 'heading-trail' | 'magic-word-name' | 'table-syntax' | 'redirect-syntax';
4
4
  /** 满足特定语法格式的plain Token */
5
5
  export declare class SyntaxToken extends Token {
@@ -14,8 +14,8 @@ class SyntaxToken extends index_1.Token {
14
14
  this.#type = type;
15
15
  }
16
16
  /** @private */
17
- lint() {
18
- return [];
17
+ lint(start = this.getAbsoluteIndex()) {
18
+ return super.lint(start, false);
19
19
  }
20
20
  }
21
21
  exports.SyntaxToken = SyntaxToken;
@@ -82,9 +82,9 @@ class TdToken extends base_1.TableBaseToken {
82
82
  super.afterBuild();
83
83
  }
84
84
  /** @private */
85
- toString() {
85
+ toString(skip) {
86
86
  const { childNodes: [syntax, attr, inner] } = this;
87
- return syntax.toString() + attr.toString() + this.#innerSyntax + inner.toString();
87
+ return syntax.toString(skip) + attr.toString(skip) + this.#innerSyntax + inner.toString(skip);
88
88
  }
89
89
  /** @private */
90
90
  text() {
@@ -2,7 +2,6 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.TrBaseToken = void 0;
4
4
  const lint_1 = require("../../util/lint");
5
- const debug_1 = require("../../util/debug");
6
5
  const base_1 = require("./base");
7
6
  const td_1 = require("./td");
8
7
  /** 表格行或表格 */
@@ -13,13 +12,13 @@ class TrBaseToken extends base_1.TableBaseToken {
13
12
  if (!inter) {
14
13
  return errors;
15
14
  }
16
- const first = inter.childNodes.find(child => child.text().trim()), tdPattern = /^\s*(?:!|\{\{\s*![!-]?\s*\}\})/u, isArg = (0, debug_1.isToken)('arg'), isTransclude = (0, debug_1.isToken)('magic-word');
15
+ const first = inter.childNodes.find(child => child.text().trim()), tdPattern = /^\s*(?:!|\{\{\s*![!-]?\s*\}\})/u;
17
16
  if (!first
18
17
  || tdPattern.test(first.toString())
19
- || isArg(first) && tdPattern.test(first.default || '')) {
18
+ || first.is('arg') && tdPattern.test(first.default || '')) {
20
19
  return errors;
21
20
  }
22
- else if (isTransclude(first)) {
21
+ else if (first.is('magic-word')) {
23
22
  try {
24
23
  if (first.getPossibleValues().every(token => tdPattern.test(token.text()))) {
25
24
  return errors;
@@ -44,7 +44,7 @@ const index_2 = require("./index");
44
44
  * @classdesc `{childNodes: [AstText, AstText]}`
45
45
  */
46
46
  let IncludeToken = (() => {
47
- let _classDecorators = [(0, hidden_1.hiddenToken)()];
47
+ let _classDecorators = [(0, hidden_1.hiddenToken)(false)];
48
48
  let _classDescriptor;
49
49
  let _classExtraInitializers = [];
50
50
  let _classThis;
@@ -71,6 +71,10 @@ let IncludeToken = (() => {
71
71
  super(name, attr, inner ?? '', inner === undefined ? closed : closed ?? '', config, accum);
72
72
  }
73
73
  /** @private */
74
+ toString(skip) {
75
+ return skip ? '' : super.toString();
76
+ }
77
+ /** @private */
74
78
  lint(start = this.getAbsoluteIndex()) {
75
79
  if (this.closed) {
76
80
  return [];
@@ -28,11 +28,11 @@ class TagPairToken extends index_1.Token {
28
28
  accum.splice(index === -1 ? Infinity : index, 0, this);
29
29
  }
30
30
  /** @private */
31
- toString() {
31
+ toString(skip) {
32
32
  const { selfClosing, firstChild, lastChild, } = this, [opening, closing] = this.#tags;
33
33
  return selfClosing
34
- ? `<${opening}${firstChild.toString()}/>`
35
- : `<${opening}${firstChild.toString()}>${lastChild.toString()}${this.closed ? `</${closing}>` : ''}`;
34
+ ? `<${opening}${firstChild.toString(skip)}/>`
35
+ : `<${opening}${firstChild.toString(skip)}>${lastChild.toString(skip)}${this.closed ? `</${closing}>` : ''}`;
36
36
  }
37
37
  /** @private */
38
38
  text() {
@@ -124,7 +124,7 @@ class TranscludeToken extends index_2.Token {
124
124
  /** 获取模板或模块名 */
125
125
  #getTitle() {
126
126
  const isTemplate = this.type === 'template', child = this.childNodes[isTemplate ? 0 : 1];
127
- return this.normalizeTitle(child.text(), isTemplate ? 10 : 828);
127
+ return this.normalizeTitle(child.toString(true), isTemplate ? 10 : 828);
128
128
  }
129
129
  /** @private */
130
130
  afterBuild() {
@@ -134,10 +134,10 @@ class TranscludeToken extends index_2.Token {
134
134
  super.afterBuild();
135
135
  }
136
136
  /** @private */
137
- toString() {
137
+ toString(skip) {
138
138
  return `{{${this.modifier}${this.type === 'magic-word'
139
- ? `${this.firstChild.toString()}${this.length === 1 ? '' : ':'}${this.childNodes.slice(1).map(String).join('|')}`
140
- : super.toString('|')}}}`;
139
+ ? `${this.firstChild.toString(skip)}${this.length === 1 ? '' : ':'}${this.childNodes.slice(1).map(child => child.toString(skip)).join('|')}`
140
+ : super.toString(skip, '|')}}}`;
141
141
  }
142
142
  /** @private */
143
143
  text() {
@@ -163,25 +163,26 @@ class TranscludeToken extends index_2.Token {
163
163
  }
164
164
  /** @private */
165
165
  lint(start = this.getAbsoluteIndex(), re) {
166
- const errors = super.lint(start, re), { type, childNodes, length } = this, rect = new rect_1.BoundingRect(this, start);
166
+ const errors = super.lint(start, re);
167
167
  if (!this.isTemplate()) {
168
168
  return errors;
169
169
  }
170
- const title = this.#getTitle();
171
- if (title.fragment !== undefined) {
172
- const child = childNodes[type === 'template' ? 0 : 1], e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'useless fragment'), textNode = child.childNodes.find((c) => c.type === 'text' && c.data.includes('#'));
170
+ const { type, childNodes, length } = this, rect = new rect_1.BoundingRect(this, start), invoke = type === 'magic-word';
171
+ if (invoke && !this.#getTitle().valid) {
172
+ errors.push((0, lint_1.generateForChild)(childNodes[1], rect, 'invalid-invoke', 'illegal module name'));
173
+ }
174
+ else {
175
+ const child = childNodes[invoke ? 1 : 0], textNode = child.childNodes.find((c) => c.type === 'text' && c.data.includes('#'));
173
176
  if (textNode) {
177
+ const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'useless fragment');
174
178
  e.fix = {
175
179
  range: [e.startIndex + textNode.getRelativeIndex() + textNode.data.indexOf('#'), e.endIndex],
176
180
  text: '',
177
181
  };
182
+ errors.push(e);
178
183
  }
179
- errors.push(e);
180
- }
181
- if (!title.valid) {
182
- errors.push((0, lint_1.generateForChild)(childNodes[1], rect, 'invalid-invoke', 'illegal module name'));
183
184
  }
184
- if (type === 'magic-word' && length === 2) {
185
+ if (invoke && length === 2) {
185
186
  errors.push((0, lint_1.generateForSelf)(this, rect, 'invalid-invoke', 'missing module function'));
186
187
  return errors;
187
188
  }
package/dist/util/lint.js CHANGED
@@ -8,7 +8,7 @@ const index_1 = require("../index");
8
8
  * @param func lint函数
9
9
  */
10
10
  const factory = (func) => (token, rect, rule, msg, severity = 'error') => {
11
- const { start } = rect, { top, left } = 'top' in rect ? rect : new rect_1.BoundingRect(token, start), { offsetHeight, offsetWidth } = token, { startIndex, startLine, startCol } = func(token, start, top, left);
11
+ const { start } = rect, { top, left } = rect instanceof rect_1.BoundingRect ? rect : new rect_1.BoundingRect(token, start), { offsetHeight, offsetWidth } = token, { startIndex, startLine, startCol } = func(token, start, top, left);
12
12
  return {
13
13
  rule,
14
14
  message: index_1.default.msg(msg),
package/errors/README CHANGED
@@ -1 +1,3 @@
1
1
  这里记录解析失败时处于半解析状态的维基文本以及错误信息。
2
+
3
+ When parsing fails, the half-parsed wikitext and the error message are recorded here.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikilint",
3
- "version": "2.9.3",
3
+ "version": "2.10.0",
4
4
  "description": "A Node.js linter for MediaWiki markup",
5
5
  "keywords": [
6
6
  "mediawiki",