wikiparser-node 1.9.3 → 1.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 (82) 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/addon/token.js +282 -198
  7. package/dist/addon/transclude.js +7 -7
  8. package/dist/base.d.ts +3 -1
  9. package/dist/index.d.ts +2 -0
  10. package/dist/index.js +4 -4
  11. package/dist/lib/element.js +2 -2
  12. package/dist/lib/node.d.ts +6 -1
  13. package/dist/lib/node.js +10 -4
  14. package/dist/lib/text.d.ts +5 -2
  15. package/dist/lib/text.js +15 -5
  16. package/dist/lib/title.d.ts +2 -0
  17. package/dist/lib/title.js +8 -0
  18. package/dist/mixin/attributesParent.js +0 -3
  19. package/dist/mixin/hidden.d.ts +1 -0
  20. package/dist/mixin/hidden.js +5 -2
  21. package/dist/mixin/singleLine.js +2 -4
  22. package/dist/mixin/sol.d.ts +1 -0
  23. package/dist/mixin/sol.js +7 -7
  24. package/dist/mixin/syntax.js +0 -2
  25. package/dist/parser/list.js +8 -6
  26. package/dist/parser/selector.js +2 -1
  27. package/dist/parser/table.js +2 -2
  28. package/dist/src/arg.js +3 -3
  29. package/dist/src/attribute.js +25 -28
  30. package/dist/src/attributes.d.ts +0 -1
  31. package/dist/src/attributes.js +34 -7
  32. package/dist/src/converter.d.ts +2 -2
  33. package/dist/src/converter.js +13 -3
  34. package/dist/src/converterFlags.js +2 -2
  35. package/dist/src/converterRule.js +17 -13
  36. package/dist/src/extLink.js +7 -3
  37. package/dist/src/gallery.js +2 -2
  38. package/dist/src/heading.js +9 -4
  39. package/dist/src/hidden.js +1 -1
  40. package/dist/src/html.js +10 -2
  41. package/dist/src/imageParameter.js +2 -2
  42. package/dist/src/imagemap.js +2 -2
  43. package/dist/src/index.d.ts +11 -1
  44. package/dist/src/index.js +61 -12
  45. package/dist/src/link/base.d.ts +9 -0
  46. package/dist/src/link/base.js +48 -11
  47. package/dist/src/link/file.js +1 -1
  48. package/dist/src/link/index.d.ts +0 -12
  49. package/dist/src/link/index.js +8 -45
  50. package/dist/src/link/redirectTarget.d.ts +3 -12
  51. package/dist/src/link/redirectTarget.js +5 -31
  52. package/dist/src/magicLink.d.ts +3 -2
  53. package/dist/src/magicLink.js +45 -57
  54. package/dist/src/nowiki/base.js +1 -1
  55. package/dist/src/nowiki/comment.js +3 -3
  56. package/dist/src/nowiki/dd.js +64 -18
  57. package/dist/src/nowiki/doubleUnderscore.js +1 -1
  58. package/dist/src/nowiki/hr.js +6 -1
  59. package/dist/src/nowiki/list.d.ts +0 -11
  60. package/dist/src/nowiki/list.js +2 -48
  61. package/dist/src/nowiki/listBase.d.ts +12 -0
  62. package/dist/src/nowiki/listBase.js +67 -53
  63. package/dist/src/nowiki/noinclude.js +5 -1
  64. package/dist/src/nowiki/quote.js +5 -0
  65. package/dist/src/onlyinclude.js +2 -2
  66. package/dist/src/paramTag/index.js +2 -2
  67. package/dist/src/parameter.js +20 -13
  68. package/dist/src/redirect.js +7 -3
  69. package/dist/src/syntax.d.ts +1 -1
  70. package/dist/src/syntax.js +2 -2
  71. package/dist/src/table/index.js +11 -1
  72. package/dist/src/table/td.js +8 -2
  73. package/dist/src/table/trBase.js +15 -7
  74. package/dist/src/tagPair/ext.js +16 -0
  75. package/dist/src/tagPair/include.js +5 -1
  76. package/dist/src/tagPair/index.js +3 -3
  77. package/dist/src/transclude.js +20 -15
  78. package/dist/util/lint.js +1 -1
  79. package/dist/util/string.js +25 -1
  80. package/errors/README +2 -0
  81. package/package.json +1 -1
  82. package/printed/README +2 -0
@@ -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": [
@@ -1222,5 +1222,6 @@
1222
1222
  "redirection": [
1223
1223
  "#redirect"
1224
1224
  ],
1225
- "variants": []
1225
+ "variants": [],
1226
+ "articlePath": "/wiki/$1"
1226
1227
  }
@@ -631,5 +631,6 @@
631
631
  "zh-sg",
632
632
  "zh-my",
633
633
  "zh-mo"
634
- ]
634
+ ],
635
+ "articlePath": "/zh/$1"
635
636
  }
@@ -730,5 +730,6 @@
730
730
  "zh-cn",
731
731
  "zh-tw",
732
732
  "zh-hk"
733
- ]
733
+ ],
734
+ "articlePath": "/$1"
734
735
  }
@@ -1270,5 +1270,6 @@
1270
1270
  "zh-sg",
1271
1271
  "zh-my",
1272
1272
  "zh-mo"
1273
- ]
1273
+ ],
1274
+ "articlePath": "/wiki/$1"
1274
1275
  }
@@ -1,240 +1,324 @@
1
1
  "use strict";
2
- /* eslint @stylistic/operator-linebreak: [2, "before", {overrides: {"=": "after"}}] */
3
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.expand = void 0;
4
+ const fs = require("fs");
5
+ const path = require("path");
4
6
  const constants_1 = require("../util/constants");
5
7
  const debug_1 = require("../util/debug");
6
- const index_1 = require("../src/index");
8
+ const string_1 = require("../util/string");
9
+ const index_1 = require("../index");
10
+ const index_2 = require("../src/index");
7
11
  const comment_1 = require("../src/nowiki/comment");
8
12
  const include_1 = require("../src/tagPair/include");
9
13
  const ext_1 = require("../src/tagPair/ext");
10
14
  const html_1 = require("../src/html");
11
15
  const attributes_1 = require("../src/attributes");
12
- index_1.Token.prototype.createComment =
13
- /** @implements */
14
- function (data = '') {
15
- const config = this.getAttribute('config');
16
+ index_2.Token.prototype.createComment = /** @implements */ function (data = '') {
17
+ const config = this.getAttribute('config');
18
+ // @ts-expect-error abstract class
19
+ return debug_1.Shadow.run(() => new comment_1.CommentToken(data.replace(/-->/gu, '-->'), true, config));
20
+ };
21
+ index_2.Token.prototype.createElement = /** @implements */ function (tagName, { selfClosing, closing } = {}) {
22
+ const config = this.getAttribute('config'), include = this.getAttribute('include');
23
+ if (tagName === (include ? 'noinclude' : 'includeonly')) {
24
+ return debug_1.Shadow.run(
16
25
  // @ts-expect-error abstract class
17
- return debug_1.Shadow.run(() => new comment_1.CommentToken(data.replace(/-->/gu, '-->'), true, config));
18
- };
19
- index_1.Token.prototype.createElement =
20
- /** @implements */
21
- function (tagName, { selfClosing, closing } = {}) {
22
- const config = this.getAttribute('config'), include = this.getAttribute('include');
23
- if (tagName === (include ? 'noinclude' : 'includeonly')) {
24
- return debug_1.Shadow.run(
26
+ () => new include_1.IncludeToken(tagName, '', undefined, selfClosing ? undefined : tagName, config));
27
+ }
28
+ else if (config.ext.includes(tagName)) {
29
+ // @ts-expect-error abstract class
30
+ return debug_1.Shadow.run(() => new ext_1.ExtToken(tagName, '', undefined, selfClosing ? undefined : '', config));
31
+ }
32
+ else if (config.html.some(tags => tags.includes(tagName))) {
33
+ return debug_1.Shadow.run(() => {
25
34
  // @ts-expect-error abstract class
26
- () => new include_1.IncludeToken(tagName, '', undefined, selfClosing ? undefined : tagName, config));
27
- }
28
- else if (config.ext.includes(tagName)) {
35
+ const attr = new attributes_1.AttributesToken(undefined, 'html-attrs', tagName, config);
36
+ attr.afterBuild();
29
37
  // @ts-expect-error abstract class
30
- return debug_1.Shadow.run(() => new ext_1.ExtToken(tagName, '', undefined, selfClosing ? undefined : '', config));
31
- }
32
- else if (config.html.some(tags => tags.includes(tagName))) {
33
- return debug_1.Shadow.run(() => {
34
- // @ts-expect-error abstract class
35
- const attr = new attributes_1.AttributesToken(undefined, 'html-attrs', tagName, config);
36
- attr.afterBuild();
37
- // @ts-expect-error abstract class
38
- return new html_1.HtmlToken(tagName, attr, Boolean(closing), Boolean(selfClosing), config);
39
- });
40
- }
41
- throw new RangeError(`Invalid tag name: ${tagName}`);
42
- };
43
- index_1.Token.prototype.caretPositionFromIndex =
44
- /** @implements */
45
- function (index) {
46
- if (index === undefined) {
47
- return undefined;
38
+ return new html_1.HtmlToken(tagName, attr, Boolean(closing), Boolean(selfClosing), config);
39
+ });
40
+ }
41
+ throw new RangeError(`Invalid tag name: ${tagName}`);
42
+ };
43
+ index_2.Token.prototype.caretPositionFromIndex = /** @implements */ function (index) {
44
+ if (index === undefined) {
45
+ return undefined;
46
+ }
47
+ const { length } = this.toString();
48
+ if (index >= length || index < -length) {
49
+ return undefined;
50
+ }
51
+ index += index < 0 ? length : 0;
52
+ let self = this, acc = 0, start = 0;
53
+ while (self.type !== 'text') {
54
+ const { childNodes } = self;
55
+ acc += self.getAttribute('padding');
56
+ for (let i = 0; acc <= index && i < childNodes.length; i++) {
57
+ const cur = childNodes[i], l = cur.toString().length;
58
+ acc += l;
59
+ if (acc > index) {
60
+ self = cur;
61
+ acc -= l;
62
+ start = acc;
63
+ break;
64
+ }
65
+ acc += self.getGaps(i);
48
66
  }
49
- const { length } = this.toString();
50
- if (index >= length || index < -length) {
51
- return undefined;
67
+ if (self.childNodes === childNodes) {
68
+ return { offsetNode: self, offset: index - start };
52
69
  }
53
- index += index < 0 ? length : 0;
54
- let self = this, acc = 0, start = 0;
55
- while (self.type !== 'text') {
56
- const { childNodes } = self;
57
- acc += self.getAttribute('padding');
58
- for (let i = 0; acc <= index && i < childNodes.length; i++) {
59
- const cur = childNodes[i], l = cur.toString().length;
60
- acc += l;
61
- if (acc > index) {
62
- self = cur;
63
- acc -= l;
64
- start = acc;
65
- break;
66
- }
67
- acc += self.getGaps(i);
68
- }
69
- if (self.childNodes === childNodes) {
70
- return { offsetNode: self, offset: index - start };
70
+ }
71
+ return { offsetNode: self, offset: index - start };
72
+ };
73
+ index_2.Token.prototype.sections = /** @implements */ function () {
74
+ if (this.type !== 'root') {
75
+ return undefined;
76
+ }
77
+ const { childNodes, length } = this, headings = [...childNodes.entries()]
78
+ .filter((entry) => entry[1].type === 'heading')
79
+ .map(([i, { level }]) => [i, level]), lastHeading = [-1, -1, -1, -1, -1, -1], sections = headings.map(([i]) => {
80
+ const range = this.createRange();
81
+ range.setStart(this, i);
82
+ return range;
83
+ });
84
+ for (let i = 0; i < headings.length; i++) {
85
+ const [index, level] = headings[i];
86
+ for (let j = level; j < 6; j++) {
87
+ const last = lastHeading[j];
88
+ if (last >= 0) {
89
+ sections[last].setEnd(this, index);
71
90
  }
91
+ lastHeading[j] = j === level ? i : -1;
72
92
  }
73
- return { offsetNode: self, offset: index - start };
74
- };
75
- index_1.Token.prototype.sections =
76
- /** @implements */
77
- function () {
78
- if (this.type !== 'root') {
79
- return undefined;
93
+ }
94
+ for (const last of lastHeading) {
95
+ if (last >= 0) {
96
+ sections[last].setEnd(this, length);
80
97
  }
81
- const { childNodes, length } = this, headings = [...childNodes.entries()]
82
- .filter((entry) => entry[1].type === 'heading')
83
- .map(([i, { level }]) => [i, level]), lastHeading = [-1, -1, -1, -1, -1, -1], sections = headings.map(([i]) => {
84
- const range = this.createRange();
85
- range.setStart(this, i);
86
- return range;
87
- });
88
- for (let i = 0; i < headings.length; i++) {
89
- const [index, level] = headings[i];
90
- for (let j = level; j < 6; j++) {
91
- const last = lastHeading[j];
92
- if (last >= 0) {
93
- sections[last].setEnd(this, index);
98
+ }
99
+ const range = this.createRange();
100
+ range.setStart(this, 0);
101
+ range.setEnd(this, headings[0]?.[0] ?? length);
102
+ sections.unshift(range);
103
+ return sections;
104
+ };
105
+ index_2.Token.prototype.findEnclosingHtml = /** @implements */ function (tag) {
106
+ tag = tag?.toLowerCase();
107
+ const { html } = this.getAttribute('config'), normalTags = new Set(html[0]), voidTags = new Set(html[2]);
108
+ if (html[2].includes(tag)) {
109
+ throw new RangeError(`Void tag: ${tag}`);
110
+ }
111
+ else if (tag !== undefined && !html.slice(0, 2).some(tags => tags.includes(tag))) {
112
+ throw new RangeError(`Invalid tag name: ${tag}`);
113
+ }
114
+ const { parentNode } = this;
115
+ if (!parentNode) {
116
+ return undefined;
117
+ }
118
+ /**
119
+ * 检查是否为指定的 HTML 标签
120
+ * @param node 节点
121
+ * @param name 标签名
122
+ * @param closing 是否为闭合标签
123
+ */
124
+ const checkHtml = (node, name, closing) => node.is('html')
125
+ && (!name && !voidTags.has(node.name) || node.name === name)
126
+ && (normalTags.has(node.name) || !node.selfClosing)
127
+ && node.closing === closing;
128
+ const { childNodes, length } = parentNode, index = childNodes.indexOf(this);
129
+ let i = index - 1, j = length;
130
+ for (; i >= 0; i--) {
131
+ const open = childNodes[i];
132
+ if (checkHtml(open, tag, false)) {
133
+ for (j = index + 1; j < length; j++) {
134
+ const close = childNodes[j];
135
+ if (checkHtml(close, open.name, true)) {
136
+ break;
94
137
  }
95
- lastHeading[j] = j === level ? i : -1;
96
138
  }
97
- }
98
- for (const last of lastHeading) {
99
- if (last >= 0) {
100
- sections[last].setEnd(this, length);
139
+ if (j < length) {
140
+ break;
101
141
  }
102
142
  }
103
- const range = this.createRange();
104
- range.setStart(this, 0);
105
- range.setEnd(this, headings[0]?.[0] ?? length);
106
- sections.unshift(range);
107
- return sections;
108
- };
109
- index_1.Token.prototype.findEnclosingHtml =
110
- /** @implements */
111
- function (tag) {
112
- tag = tag?.toLowerCase();
113
- const { html } = this.getAttribute('config'), normalTags = new Set(html[0]), voidTags = new Set(html[2]);
114
- if (html[2].includes(tag)) {
115
- throw new RangeError(`Void tag: ${tag}`);
143
+ }
144
+ if (i === -1) {
145
+ return parentNode.findEnclosingHtml(tag);
146
+ }
147
+ const range = this.createRange();
148
+ range.setStart(parentNode, i);
149
+ range.setEnd(parentNode, j + 1);
150
+ return range;
151
+ };
152
+ index_2.Token.prototype.redoQuotes = /** @implements */ function () {
153
+ const acceptable = this.getAcceptable();
154
+ if (acceptable && !('QuoteToken' in acceptable)) {
155
+ return;
156
+ }
157
+ const accum = [];
158
+ for (const child of this.childNodes) {
159
+ if (child.type !== 'quote' && child.type !== 'text') {
160
+ child.replaceWith(`\0${accum.length}e\x7F`);
161
+ accum.push(child);
116
162
  }
117
- else if (tag !== undefined && !html.slice(0, 2).some(tags => tags.includes(tag))) {
118
- throw new RangeError(`Invalid tag name: ${tag}`);
163
+ }
164
+ const token = debug_1.Shadow.run(() => {
165
+ const node = new index_2.Token(this.toString(), this.getAttribute('config'), accum);
166
+ node.setAttribute('stage', 6);
167
+ return node.parse(7);
168
+ });
169
+ this.replaceChildren(...token.childNodes);
170
+ };
171
+ /**
172
+ * 展开模板
173
+ * @param wikitext
174
+ * @param config
175
+ * @param include
176
+ * @param context 模板调用环境
177
+ * @param accum
178
+ * @throws `Error` not root token
179
+ */
180
+ const expand = (wikitext, config, include, context, accum = []) => {
181
+ const magicWords = new Set(['if', 'ifeq', 'switch']), n = accum.length, token = new index_2.Token(wikitext, config, accum);
182
+ token.type = 'root';
183
+ token.parseOnce(0, include);
184
+ if (context) {
185
+ token.setText((0, string_1.removeComment)(token.firstChild.toString()));
186
+ }
187
+ token.parseOnce();
188
+ for (const plain of [...accum.slice(n), token]) {
189
+ if (plain.length !== 1 || plain.firstChild.type !== 'text') {
190
+ continue;
119
191
  }
120
- const { parentNode } = this;
121
- if (!parentNode) {
122
- return undefined;
192
+ const { data } = plain.firstChild;
193
+ if (!/\0\d+t\x7F/u.test(data)) {
194
+ continue;
123
195
  }
124
- const isHtml = (0, debug_1.isToken)('html'),
125
- /**
126
- * 检查是否为指定的 HTML 标签
127
- * @param node 节点
128
- * @param name 标签名
129
- * @param closing 是否为闭合标签
130
- */
131
- checkHtml = (node, name, closing) => isHtml(node)
132
- && (!name && !voidTags.has(node.name) || node.name === name)
133
- && (normalTags.has(node.name) || !node.selfClosing)
134
- && node.closing === closing;
135
- const { childNodes, length } = parentNode, index = childNodes.indexOf(this);
136
- let i = index - 1, j = length;
137
- for (; i >= 0; i--) {
138
- const open = childNodes[i];
139
- if (checkHtml(open, tag, false)) {
140
- for (j = index + 1; j < length; j++) {
141
- const close = childNodes[j];
142
- if (checkHtml(close, open.name, true)) {
143
- break;
144
- }
196
+ const expanded = data.replace(/\0(\d+)t\x7F/gu, (m, i) => {
197
+ const target = accum[i], { type, name, length, firstChild: f } = target;
198
+ if (type === 'arg') {
199
+ const arg = (0, string_1.removeComment)(f.toString()).trim();
200
+ if (context === undefined || /\0\d+t\x7F/u.test(arg)) {
201
+ return m;
145
202
  }
146
- if (j < length) {
147
- break;
203
+ else if (context === false || !context.hasArg(arg)) {
204
+ const effective = target.childNodes[1] ?? target;
205
+ // @ts-expect-error sparse array
206
+ accum[accum.indexOf(effective)] = undefined;
207
+ return effective.toString();
148
208
  }
209
+ // @ts-expect-error sparse array
210
+ accum[accum.indexOf(context.getArg(arg).lastChild)] = undefined;
211
+ return context.getValue(arg);
149
212
  }
150
- }
151
- if (i === -1) {
152
- return parentNode.findEnclosingHtml(tag);
153
- }
154
- const range = this.createRange();
155
- range.setStart(parentNode, i);
156
- range.setEnd(parentNode, j + 1);
157
- return range;
158
- };
159
- index_1.Token.prototype.redoQuotes =
160
- /** @implements */
161
- function () {
162
- const acceptable = this.getAcceptable();
163
- if (acceptable && !('QuoteToken' in acceptable)) {
164
- return;
165
- }
166
- const accum = [];
167
- for (const child of this.childNodes) {
168
- if (child.type !== 'quote' && child.type !== 'text') {
169
- child.replaceWith(`\0${accum.length}e\x7F`);
170
- accum.push(child);
171
- }
172
- }
173
- const token = debug_1.Shadow.run(() => {
174
- const node = new index_1.Token(this.toString(), this.getAttribute('config'), accum);
175
- node.setAttribute('stage', 6);
176
- return node.parse(7);
177
- });
178
- this.replaceChildren(...token.childNodes);
179
- };
180
- index_1.Token.prototype.solveConst =
181
- /** @implements */
182
- function () {
183
- const targets = this.querySelectorAll('magic-word, arg'), magicWords = new Set(['if', 'ifeq', 'switch']);
184
- for (let i = targets.length - 1; i >= 0; i--) {
185
- const target = targets[i], { type, name, childNodes, length } = target, [, var1, var2 = ''] = childNodes;
186
- if (type === 'arg' || type === 'magic-word' && magicWords.has(name)) {
187
- let replace = '';
188
- if (type === 'arg') {
189
- replace = target.default === false ? target.toString() : target.default;
213
+ else if (type === 'template') {
214
+ if (context === false) {
215
+ return m;
216
+ }
217
+ const c = target.getAttribute('config'), { title } = index_1.default.normalizeTitle((0, string_1.removeComment)(f.toString()), 10, include, c, true);
218
+ if (!index_1.default.templates.has(title)) {
219
+ if (index_1.default.templateDir === undefined) {
220
+ return m;
221
+ }
222
+ else if (!path.isAbsolute(index_1.default.templateDir)) {
223
+ index_1.default.templateDir = path.join(__dirname, '..', '..', index_1.default.templateDir);
224
+ }
225
+ const file = ['.wiki', '.txt', ''].map(ext => path.join(index_1.default.templateDir, title + ext))
226
+ .find(fs.existsSync);
227
+ if (!file) {
228
+ return m;
229
+ }
230
+ index_1.default.templates.set(title, fs.readFileSync(file, 'utf8'));
190
231
  }
191
- else if (name === 'if' && !var1?.getElementByTypes('magic-word, template')) {
192
- replace = String(childNodes[String(var1 ?? '').trim() ? 2 : 3] ?? '').trim();
232
+ return (0, exports.expand)(index_1.default.templates.get(title), config, true, target, accum).toString();
233
+ }
234
+ else if (!magicWords.has(name)) {
235
+ return m;
236
+ }
237
+ else if (length < 3 || name === 'ifeq' && length === 3) {
238
+ return '';
239
+ }
240
+ const c = target.childNodes, var1 = c[1].value, var2 = c[2].value, known = !/\0\d+t\x7F/u.test(var1);
241
+ if (name === 'if' && known) {
242
+ const effective = c[var1 ? 2 : 3];
243
+ if (effective) {
244
+ // @ts-expect-error sparse array
245
+ accum[accum.indexOf(effective.lastChild)] = undefined;
246
+ return effective.value;
193
247
  }
194
- else if (name === 'ifeq'
195
- && !childNodes.slice(1, 3).some(child => child.getElementByTypes('magic-word, template'))) {
196
- replace = String(childNodes[String(var1 ?? '').trim() === String(var2).trim() ? 3 : 4] ?? '').trim();
248
+ return '';
249
+ }
250
+ else if (name === 'ifeq' && known && !/\0\d+t\x7F/u.test(var2)) {
251
+ const effective = c[var1 === var2 ? 3 : 4];
252
+ if (effective) {
253
+ // @ts-expect-error sparse array
254
+ accum[accum.indexOf(effective.lastChild)] = undefined;
255
+ return effective.value;
197
256
  }
198
- else if (name === 'switch' && !var1?.getElementByTypes('magic-word, template')) {
199
- const key = String(var1 ?? '').trim();
200
- let defaultVal = '', found = false, transclusion = false;
201
- for (let j = 2; j < length; j++) {
202
- const { anon, name: option, value, firstChild } = childNodes[j];
203
- transclusion = Boolean(firstChild.getElementByTypes('magic-word, template'));
204
- if (anon) {
205
- if (j === length - 1) {
206
- defaultVal = value;
207
- }
208
- else if (transclusion) {
209
- break;
210
- }
211
- else {
212
- found ||= key === value;
213
- }
257
+ return '';
258
+ }
259
+ else if (name === 'switch' && known) {
260
+ let defaultVal = '', found = false, transclusion = false, defaultParam;
261
+ for (let j = 2; j < length; j++) {
262
+ const { anon, value, firstChild, lastChild } = c[j], option = (0, string_1.removeComment)(firstChild.toString())
263
+ .replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1');
264
+ transclusion = /\0\d+t\x7F/u.test(anon ? value : option);
265
+ if (anon) {
266
+ if (j === length - 1) {
267
+ // @ts-expect-error sparse array
268
+ accum[accum.indexOf(lastChild)] = undefined;
269
+ return value;
214
270
  }
215
271
  else if (transclusion) {
216
272
  break;
217
273
  }
218
- else if (found || option === key) {
219
- replace = value;
220
- break;
221
- }
222
- else if (option.toLowerCase() === '#default') {
223
- defaultVal = value;
224
- }
225
- if (j === length - 1) {
226
- replace = defaultVal;
274
+ else {
275
+ found ||= var1 === value;
227
276
  }
228
277
  }
229
- if (transclusion) {
230
- continue;
278
+ else if (transclusion) {
279
+ break;
280
+ }
281
+ else if (found || option === var1) {
282
+ // @ts-expect-error sparse array
283
+ accum[accum.indexOf(lastChild)] = undefined;
284
+ return value;
285
+ }
286
+ else if (option.toLowerCase() === '#default') {
287
+ defaultVal = value;
288
+ defaultParam = lastChild;
289
+ }
290
+ if (j === length - 1) {
291
+ if (defaultParam) {
292
+ // @ts-expect-error sparse array
293
+ accum[accum.indexOf(defaultParam)] = undefined;
294
+ }
295
+ return defaultVal;
231
296
  }
232
297
  }
233
- else {
234
- continue;
298
+ if (transclusion) {
299
+ return m;
235
300
  }
236
- target.replaceWith(replace);
237
301
  }
302
+ return m;
303
+ });
304
+ plain.setText(expanded);
305
+ if (plain.type === 'parameter-key') {
306
+ plain.parentNode.trimName((0, string_1.removeComment)(expanded));
238
307
  }
239
- };
308
+ }
309
+ return token;
310
+ };
311
+ exports.expand = expand;
312
+ index_2.Token.prototype.expand = /** @implements */ function (context) {
313
+ if (this.type !== 'root') {
314
+ throw new Error('Only root token can be expanded!');
315
+ }
316
+ return debug_1.Shadow.run(() => (0, exports.expand)(this.toString(), this.getAttribute('config'), this.getAttribute('include'), context).parse());
317
+ };
318
+ index_2.Token.prototype.solveConst = /** @implements */ function () {
319
+ if (this.type !== 'root') {
320
+ throw new Error('Only root token can be expanded!');
321
+ }
322
+ return debug_1.Shadow.run(() => (0, exports.expand)(this.toString(), this.getAttribute('config'), this.getAttribute('include'), false).parse());
323
+ };
240
324
  constants_1.classes['ExtendedTableToken'] = __filename;
@@ -55,9 +55,9 @@ transclude_1.TranscludeToken.prototype.replaceModule =
55
55
  }
56
56
  const config = this.getAttribute('config');
57
57
  if (this.length === 1) {
58
- index_2.Token.prototype.insertAt.call(this, new atom_1.AtomToken(undefined, 'invoke-module', config, [], {
58
+ index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-module', config, [], {
59
59
  'Stage-1': ':', '!ExtToken': '',
60
- }));
60
+ })));
61
61
  return;
62
62
  }
63
63
  const { childNodes } = index_1.default.parse(title, this.getAttribute('include'), 2, config);
@@ -74,9 +74,9 @@ transclude_1.TranscludeToken.prototype.replaceFunction =
74
74
  }
75
75
  const config = this.getAttribute('config');
76
76
  if (this.length === 2) {
77
- index_2.Token.prototype.insertAt.call(this, new atom_1.AtomToken(undefined, 'invoke-function', config, [], {
77
+ index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-function', config, [], {
78
78
  'Stage-1': ':', '!ExtToken': '',
79
- }));
79
+ })));
80
80
  return;
81
81
  }
82
82
  const { childNodes } = index_1.default.parse(func, this.getAttribute('include'), 2, config);
@@ -152,7 +152,7 @@ transclude_1.TranscludeToken.prototype.fixDuplication =
152
152
  if (remaining > 1) {
153
153
  index_1.default.error(`${this.type === 'template'
154
154
  ? this.name
155
- : this.normalizeTitle(this.childNodes[1].text(), 828)
155
+ : this.normalizeTitle(this.childNodes[1].toString(true), 828)
156
156
  .title} still has ${remaining} duplicated ${key} parameters:\n${[...this.getArgs(key)].map(arg => {
157
157
  const { top, left } = arg.getBoundingClientRect();
158
158
  return `Line ${String(top)} Column ${String(left)}`;
@@ -169,9 +169,9 @@ transclude_1.TranscludeToken.prototype.escapeTables =
169
169
  if (!/\n[^\S\n]*(?::+[^\S\n]*)?\{\|/u.test(this.text())) {
170
170
  return this;
171
171
  }
172
- const stripped = this.toString().slice(2, -2), include = this.getAttribute('include'), config = this.getAttribute('config'), parsed = index_1.default.parse(stripped, include, 4, config), isTable = (0, debug_1.isToken)('table');
172
+ const stripped = this.toString().slice(2, -2), include = this.getAttribute('include'), config = this.getAttribute('config'), parsed = index_1.default.parse(stripped, include, 4, config);
173
173
  for (const table of parsed.childNodes) {
174
- if (isTable(table)) {
174
+ if (table.is('table')) {
175
175
  table.escape();
176
176
  }
177
177
  }
package/dist/base.d.ts CHANGED
@@ -13,6 +13,7 @@ export interface Config {
13
13
  readonly interwiki: string[];
14
14
  readonly conversionTable?: [string, string][];
15
15
  readonly redirects?: [string, string][];
16
+ readonly articlePath?: string;
16
17
  }
17
18
  export type TokenTypes = 'root' | 'plain' | 'redirect' | 'redirect-syntax' | 'redirect-target' | 'onlyinclude' | 'noinclude' | 'include' | 'comment' | 'ext' | 'ext-attrs' | 'ext-attr-dirty' | 'ext-attr' | 'attr-key' | 'attr-value' | 'ext-inner' | 'arg' | 'arg-name' | 'arg-default' | 'hidden' | 'magic-word' | 'magic-word-name' | 'invoke-function' | 'invoke-module' | 'template' | 'template-name' | 'parameter' | 'parameter-key' | 'parameter-value' | 'heading' | 'heading-title' | 'heading-trail' | 'html' | 'html-attrs' | 'html-attr-dirty' | 'html-attr' | 'table' | 'tr' | 'td' | 'table-syntax' | 'table-attrs' | 'table-attr-dirty' | 'table-attr' | 'table-inter' | 'td-inner' | 'hr' | 'double-underscore' | 'link' | 'link-target' | 'link-text' | 'category' | 'file' | 'gallery-image' | 'imagemap-image' | 'image-parameter' | 'quote' | 'ext-link' | 'ext-link-text' | 'ext-link-url' | 'free-ext-link' | 'magic-link' | 'list' | 'dd' | 'converter' | 'converter-flags' | 'converter-flag' | 'converter-rule' | 'converter-rule-variant' | 'converter-rule-to' | 'converter-rule-from' | 'param-line' | 'imagemap-link';
18
19
  export declare const rules: readonly ["bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext"];
@@ -46,8 +47,9 @@ export type AST = Record<string, string | number | boolean> & {
46
47
  };
47
48
  /** 类似Node */
48
49
  export interface AstNode {
49
- type: string;
50
50
  readonly childNodes: readonly AstNode[];
51
+ /** 节点类型 */
52
+ type: string;
51
53
  /** Linter */
52
54
  lint(): LintError[];
53
55
  /** 以HTML格式打印 */