wikiparser-node 1.18.1 → 1.18.3

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 (86) hide show
  1. package/README.md +7 -2
  2. package/bin/config.js +2 -2
  3. package/bundle/bundle-es7.min.js +29 -29
  4. package/bundle/bundle-lsp.min.js +95 -29
  5. package/bundle/bundle.min.js +26 -26
  6. package/config/.schema.json +13 -0
  7. package/config/default.json +460 -4
  8. package/config/enwiki.json +111 -0
  9. package/config/jawiki.json +954 -0
  10. package/config/llwiki.json +117 -0
  11. package/config/minimum.json +10 -0
  12. package/config/moegirl.json +104 -0
  13. package/config/zhwiki.json +109 -0
  14. package/dist/addon/token.js +10 -9
  15. package/dist/addon/transclude.js +1 -3
  16. package/dist/base.d.mts +5 -0
  17. package/dist/base.d.ts +5 -0
  18. package/dist/base.js +1 -0
  19. package/dist/base.mjs +2 -1
  20. package/dist/bin/config.js +82 -59
  21. package/dist/index.d.ts +5 -1
  22. package/dist/index.js +68 -73
  23. package/dist/lib/document.d.ts +6 -6
  24. package/dist/lib/document.js +43 -36
  25. package/dist/lib/element.d.ts +6 -0
  26. package/dist/lib/element.js +543 -466
  27. package/dist/lib/lsp.d.ts +1 -0
  28. package/dist/lib/lsp.js +84 -56
  29. package/dist/lib/redirectMap.d.ts +7 -0
  30. package/dist/lib/redirectMap.js +31 -0
  31. package/dist/lib/text.d.ts +2 -2
  32. package/dist/lib/text.js +383 -325
  33. package/dist/lib/title.d.ts +23 -4
  34. package/dist/lib/title.js +17 -5
  35. package/dist/mixin/noEscape.d.ts +4 -0
  36. package/dist/mixin/noEscape.js +22 -0
  37. package/dist/mixin/readOnly.d.ts +4 -0
  38. package/dist/mixin/readOnly.js +26 -0
  39. package/dist/parser/braces.js +29 -15
  40. package/dist/parser/commentAndExt.js +5 -16
  41. package/dist/parser/links.js +1 -1
  42. package/dist/parser/quotes.js +1 -1
  43. package/dist/parser/redirect.js +1 -3
  44. package/dist/src/arg.js +253 -202
  45. package/dist/src/attribute.d.ts +0 -5
  46. package/dist/src/attribute.js +3 -7
  47. package/dist/src/converter.js +213 -162
  48. package/dist/src/gallery.js +1 -2
  49. package/dist/src/heading.js +5 -6
  50. package/dist/src/imageParameter.js +16 -16
  51. package/dist/src/imagemap.js +3 -2
  52. package/dist/src/index.d.ts +1 -1
  53. package/dist/src/index.js +722 -694
  54. package/dist/src/link/base.js +292 -241
  55. package/dist/src/link/file.js +13 -17
  56. package/dist/src/link/galleryImage.js +1 -1
  57. package/dist/src/link/redirectTarget.js +1 -2
  58. package/dist/src/magicLink.d.ts +0 -6
  59. package/dist/src/magicLink.js +5 -15
  60. package/dist/src/nested.js +7 -7
  61. package/dist/src/nowiki/base.js +2 -1
  62. package/dist/src/nowiki/index.js +4 -3
  63. package/dist/src/onlyinclude.js +95 -44
  64. package/dist/src/parameter.d.ts +0 -6
  65. package/dist/src/parameter.js +1 -13
  66. package/dist/src/redirect.js +6 -6
  67. package/dist/src/syntax.d.ts +4 -1
  68. package/dist/src/syntax.js +4 -1
  69. package/dist/src/table/base.d.ts +0 -5
  70. package/dist/src/table/base.js +2 -9
  71. package/dist/src/table/index.js +6 -3
  72. package/dist/src/table/td.d.ts +1 -0
  73. package/dist/src/table/td.js +2 -3
  74. package/dist/src/table/trBase.js +3 -1
  75. package/dist/src/tagPair/index.js +2 -1
  76. package/dist/src/transclude.js +706 -647
  77. package/dist/util/debug.js +10 -3
  78. package/dist/util/lint.js +31 -30
  79. package/dist/util/string.js +4 -5
  80. package/extensions/dist/base.js +8 -6
  81. package/extensions/dist/lint.js +1 -1
  82. package/extensions/dist/lsp.js +0 -5
  83. package/extensions/es7/base.js +8 -6
  84. package/extensions/es7/lint.js +1 -1
  85. package/extensions/ui.css +1 -1
  86. package/package.json +3 -4
@@ -1,4 +1,38 @@
1
1
  "use strict";
2
+ var __esDecorate = (this && this.__esDecorate) || function (ctor, descriptorIn, decorators, contextIn, initializers, extraInitializers) {
3
+ function accept(f) { if (f !== void 0 && typeof f !== "function") throw new TypeError("Function expected"); return f; }
4
+ var kind = contextIn.kind, key = kind === "getter" ? "get" : kind === "setter" ? "set" : "value";
5
+ var target = !descriptorIn && ctor ? contextIn["static"] ? ctor : ctor.prototype : null;
6
+ var descriptor = descriptorIn || (target ? Object.getOwnPropertyDescriptor(target, contextIn.name) : {});
7
+ var _, done = false;
8
+ for (var i = decorators.length - 1; i >= 0; i--) {
9
+ var context = {};
10
+ for (var p in contextIn) context[p] = p === "access" ? {} : contextIn[p];
11
+ for (var p in contextIn.access) context.access[p] = contextIn.access[p];
12
+ context.addInitializer = function (f) { if (done) throw new TypeError("Cannot add initializers after decoration has completed"); extraInitializers.push(accept(f || null)); };
13
+ var result = (0, decorators[i])(kind === "accessor" ? { get: descriptor.get, set: descriptor.set } : descriptor[key], context);
14
+ if (kind === "accessor") {
15
+ if (result === void 0) continue;
16
+ if (result === null || typeof result !== "object") throw new TypeError("Object expected");
17
+ if (_ = accept(result.get)) descriptor.get = _;
18
+ if (_ = accept(result.set)) descriptor.set = _;
19
+ if (_ = accept(result.init)) initializers.unshift(_);
20
+ }
21
+ else if (_ = accept(result)) {
22
+ if (kind === "field") initializers.unshift(_);
23
+ else descriptor[key] = _;
24
+ }
25
+ }
26
+ if (target) Object.defineProperty(target, contextIn.name, descriptor);
27
+ done = true;
28
+ };
29
+ var __runInitializers = (this && this.__runInitializers) || function (thisArg, initializers, value) {
30
+ var useValue = arguments.length > 2;
31
+ for (var i = 0; i < initializers.length; i++) {
32
+ value = useValue ? initializers[i].call(thisArg, value) : initializers[i].call(thisArg);
33
+ }
34
+ return useValue ? value : void 0;
35
+ };
2
36
  var __importDefault = (this && this.__importDefault) || function (mod) {
3
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
38
  };
@@ -14,6 +48,7 @@ const parameter_1 = require("./parameter");
14
48
  const atom_1 = require("./atom");
15
49
  const syntax_1 = require("./syntax");
16
50
  /* NOT FOR BROWSER */
51
+ const noEscape_1 = require("../mixin/noEscape");
17
52
  const index_2 = __importDefault(require("../index"));
18
53
  const basicMagicWords = new Map([['=', '='], ['!', '|']]);
19
54
  /**
@@ -22,694 +57,718 @@ const basicMagicWords = new Map([['=', '='], ['!', '|']]);
22
57
  * 模板或魔术字
23
58
  * @classdesc `{childNodes: [AtomToken|SyntaxToken, ...AtomToken[], ...ParameterToken[]]}`
24
59
  */
25
- class TranscludeToken extends index_1.Token {
26
- modifier = '';
27
- #type = 'template';
28
- #raw = false;
29
- #args = new Map();
30
- #title;
31
- /* NOT FOR BROWSER */
32
- #keys = new Set();
33
- /* NOT FOR BROWSER END */
34
- get type() {
35
- return this.#type;
36
- }
37
- /* NOT FOR BROWSER */
38
- /** whether to contain duplicated parameters / 是否存在重复参数 */
39
- get duplication() {
40
- return this.isTemplate() && Boolean(this.hasDuplicatedArgs());
41
- }
42
- set duplication(duplication) {
43
- if (this.duplication && !duplication) {
44
- this.fixDuplication();
60
+ let TranscludeToken = (() => {
61
+ let _classDecorators = [noEscape_1.noEscape];
62
+ let _classDescriptor;
63
+ let _classExtraInitializers = [];
64
+ let _classThis;
65
+ let _classSuper = index_1.Token;
66
+ var TranscludeToken = class extends _classSuper {
67
+ static { _classThis = this; }
68
+ static {
69
+ const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
70
+ __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
71
+ TranscludeToken = _classThis = _classDescriptor.value;
72
+ if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
73
+ __runInitializers(_classThis, _classExtraInitializers);
74
+ }
75
+ modifier = '';
76
+ #type = 'template';
77
+ #colon = ':';
78
+ #raw = false;
79
+ #args = new Map();
80
+ #title;
81
+ /* NOT FOR BROWSER */
82
+ #keys = new Set();
83
+ /* NOT FOR BROWSER END */
84
+ get type() {
85
+ return this.#type;
45
86
  }
46
- }
47
- /* NOT FOR BROWSER END */
48
- /**
49
- * @param title 模板标题或魔术字
50
- * @param parts 参数各部分
51
- * @throws `SyntaxError` 非法的模板名称
52
- */
53
- constructor(title, parts, config, accum = []) {
54
- let heading;
55
- const m = /^(?:\s|\0\d+[cn]\x7F)*\0(\d+)h\x7F(?:\s|\0\d+[cn]\x7F)*/u.exec(title);
56
- if (m) {
57
- heading = Number(m[1]);
58
- title = title.replace(`\0${heading}h\x7F`, accum[heading].toString().replace(/^\n/u, ''));
59
- }
60
- super(undefined, config, accum, {
61
- AtomToken: 0, SyntaxToken: 0, ParameterToken: '1:',
62
- });
63
- const { parserFunction: [insensitive, sensitive], variable } = config, argSubst = /^(?:\s|\0\d+[cn]\x7F)*\0\d+s\x7F/u.exec(title)?.[0];
64
- if (argSubst) {
65
- this.setAttribute('modifier', argSubst);
66
- title = title.slice(argSubst.length);
67
- }
68
- else if (title.includes(':')) {
69
- const [modifier, ...arg] = title.split(':'), [mt] = /^(?:\s|\0\d+[cn]\x7F)*/u.exec(arg[0] ?? '');
70
- if (this.setModifier(`${modifier}:${mt}`)) {
71
- title = arg.join(':').slice(mt.length);
72
- }
73
- }
74
- const isFunction = title.includes(':');
75
- if (isFunction || parts.length === 0 && !this.#raw) {
76
- const colon = title.indexOf(':'), magicWord = colon === -1 ? title : title.slice(0, colon), arg = colon === -1 ? undefined : title.slice(colon + 1), cleaned = (0, string_1.removeComment)(magicWord), name = cleaned[arg === undefined ? 'trim' : 'trimStart'](), lcName = name.toLowerCase(), isOldSchema = Array.isArray(sensitive), isSensitive = isOldSchema
77
- ? sensitive.includes(name)
78
- : Object.prototype.hasOwnProperty.call(sensitive, name), canonicalName = !isOldSchema && isSensitive
79
- ? sensitive[name]
80
- : Object.prototype.hasOwnProperty.call(insensitive, lcName) && insensitive[lcName], isVar = isOldSchema && isSensitive || variable.includes(canonicalName);
81
- if (isVar || isFunction && canonicalName) {
82
- this.setAttribute('name', canonicalName || lcName.replace(/^#/u, ''));
83
- this.#type = 'magic-word';
84
- /^\s*uc\s*$/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
85
- const pattern = new RegExp(String.raw `^\s*${name}\s*$`, isSensitive ? 'u' : 'iu'), token = new syntax_1.SyntaxToken(magicWord, pattern, 'magic-word-name', config, accum, {
86
- 'Stage-1': ':', '!ExtToken': '',
87
- });
88
- super.insertAt(token);
89
- if (arg !== undefined) {
90
- parts.unshift([arg]);
87
+ /* NOT FOR BROWSER */
88
+ /** whether to contain duplicated parameters / 是否存在重复参数 */
89
+ get duplication() {
90
+ return this.isTemplate() && Boolean(this.hasDuplicatedArgs());
91
+ }
92
+ set duplication(duplication) {
93
+ if (this.duplication && !duplication) {
94
+ this.fixDuplication();
95
+ }
96
+ }
97
+ /* NOT FOR BROWSER END */
98
+ /**
99
+ * @param title 模板标题或魔术字
100
+ * @param parts 参数各部分
101
+ * @throws `SyntaxError` 非法的模板名称
102
+ */
103
+ constructor(title, parts, config, accum = []) {
104
+ let heading;
105
+ const m = /^(?:\s|\0\d+[cn]\x7F)*\0(\d+)h\x7F(?:\s|\0\d+[cn]\x7F)*/u.exec(title);
106
+ if (m) {
107
+ heading = Number(m[1]);
108
+ title = title.replace(`\0${heading}h\x7F`, accum[heading].toString().replace(/^\n/u, ''));
109
+ }
110
+ super(undefined, config, accum, {
111
+ AtomToken: 0, SyntaxToken: 0, ParameterToken: '1:',
112
+ });
113
+ const { parserFunction: [insensitive, sensitive], variable, functionHook } = config, argSubst = /^(?:\s|\0\d+[cn]\x7F)*\0\d+s\x7F/u.exec(title)?.[0];
114
+ if (argSubst) {
115
+ this.setAttribute('modifier', argSubst);
116
+ title = title.slice(argSubst.length);
117
+ }
118
+ else if (title.includes(':')) {
119
+ const [modifier, ...arg] = title.split(':'), [mt] = /^(?:\s|\0\d+[cn]\x7F)*/u.exec(arg[0] ?? '');
120
+ if (this.setModifier(`${modifier}:${mt}`)) {
121
+ title = arg.join(':').slice(mt.length);
91
122
  }
92
- if (this.name === 'invoke') {
93
- /* NOT FOR BROWSER */
94
- this.setAttribute('acceptable', { SyntaxToken: 0, AtomToken: '1:3', ParameterToken: '3:' });
95
- this.protectChildren('1:3');
96
- /* NOT FOR BROWSER END */
97
- for (let i = 0; i < 2; i++) {
98
- const part = parts.shift();
99
- if (!part) {
100
- break;
123
+ }
124
+ const colon = title.search(/[::]/u), fullWidth = title[colon] === ':', isFunction = colon !== -1;
125
+ if (isFunction || parts.length === 0 && !this.#raw) {
126
+ const magicWord = isFunction ? title.slice(0, colon) : title, arg = isFunction && title.slice(colon + 1), cleaned = (0, string_1.removeComment)(magicWord), name = isFunction
127
+ ? cleaned.slice(cleaned.search(/\S/u)) + (fullWidth ? ':' : '')
128
+ : cleaned.trim(), lcName = name.toLowerCase(), isOldSchema = Array.isArray(sensitive), isSensitive = isOldSchema
129
+ ? sensitive.includes(name)
130
+ : Object.prototype.hasOwnProperty.call(sensitive, name), canonicalName = !isOldSchema && isSensitive
131
+ ? sensitive[name]
132
+ : Object.prototype.hasOwnProperty.call(insensitive, lcName) && insensitive[lcName], isFunc = isOldSchema && isSensitive
133
+ || !('functionHook' in config) || functionHook.includes(canonicalName), isVar = isOldSchema && isSensitive || variable.includes(canonicalName);
134
+ if (isFunction ? canonicalName && isFunc : isVar) {
135
+ this.setAttribute('name', canonicalName || lcName.replace(/^#|:$/u, ''));
136
+ this.#type = 'magic-word';
137
+ if (fullWidth) {
138
+ this.#colon = ':';
139
+ }
140
+ /^\s*uc\s*$/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
141
+ const token = new syntax_1.SyntaxToken(magicWord, new RegExp(String.raw `^\s*${name}\s*$`, isSensitive ? 'u' : 'iu'), 'magic-word-name', config, accum, { 'Stage-1': ':', '!ExtToken': '' });
142
+ super.insertAt(token);
143
+ if (arg !== false) {
144
+ parts.unshift([arg]);
145
+ }
146
+ if (this.name === 'invoke') {
147
+ /* NOT FOR BROWSER */
148
+ this.setAttribute('acceptable', { SyntaxToken: 0, AtomToken: '1:3', ParameterToken: '3:' });
149
+ this.protectChildren('1:3');
150
+ /* NOT FOR BROWSER END */
151
+ for (let i = 0; i < 2; i++) {
152
+ const part = parts.shift();
153
+ if (!part) {
154
+ break;
155
+ }
156
+ const invoke = new atom_1.AtomToken(part.join('='), `invoke-${i ? 'function' : 'module'}`, config, accum, { 'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '' });
157
+ super.insertAt(invoke);
101
158
  }
102
- const invoke = new atom_1.AtomToken(part.join('='), `invoke-${i ? 'function' : 'module'}`, config, accum, { 'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '' });
103
- super.insertAt(invoke);
104
159
  }
105
160
  }
106
161
  }
107
- }
108
- if (this.type === 'template') {
109
- const name = (0, string_1.removeComment)(title).trim();
110
- if (!this.normalizeTitle(name, 10, true, true).valid) {
111
- accum.pop();
112
- /* NOT FOR BROWSER */
113
- index_2.default.debug(`Invalid template name: ${(0, string_1.noWrap)(name)}`);
114
- /* NOT FOR BROWSER END */
115
- throw new SyntaxError('Invalid template name');
162
+ if (this.type === 'template') {
163
+ const name = (0, string_1.removeComment)(title).trim();
164
+ if (!this.normalizeTitle(name, 10, { halfParsed: true, temporary: true }).valid) {
165
+ accum.pop();
166
+ /* NOT FOR BROWSER */
167
+ index_2.default.debug(`Invalid template name: ${(0, string_1.noWrap)(name)}`);
168
+ /* NOT FOR BROWSER END */
169
+ throw new SyntaxError('Invalid template name');
170
+ }
171
+ const token = new atom_1.AtomToken(title, 'template-name', config, accum, {
172
+ 'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '',
173
+ });
174
+ super.insertAt(token);
116
175
  }
117
- const token = new atom_1.AtomToken(title, 'template-name', config, accum, {
118
- 'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '',
119
- });
120
- super.insertAt(token);
121
- }
122
- if (typeof heading === 'number') {
123
- // @ts-expect-error sparse array
124
- accum[heading] = undefined;
125
- }
126
- const templateLike = this.isTemplate();
127
- let i = 1;
128
- for (let j = 0; j < parts.length; j++) {
129
- const part = parts[j];
130
- if (!(templateLike || this.name === 'switch' && j > 0 || this.name === 'tag' && j > 1)) {
131
- part[0] = part.join('=');
132
- part.length = 1;
176
+ if (typeof heading === 'number') {
177
+ // @ts-expect-error sparse array
178
+ accum[heading] = undefined;
133
179
  }
134
- if (part.length === 1) {
135
- part.unshift(i);
136
- i++;
180
+ const templateLike = this.isTemplate();
181
+ let i = 1;
182
+ for (let j = 0; j < parts.length; j++) {
183
+ const part = parts[j];
184
+ if (!(templateLike || this.name === 'switch' && j > 0 || this.name === 'tag' && j > 1)) {
185
+ part[0] = part.join('=');
186
+ part.length = 1;
187
+ }
188
+ if (part.length === 1) {
189
+ part.unshift(i);
190
+ i++;
191
+ }
192
+ // @ts-expect-error abstract class
193
+ this.insertAt(new parameter_1.ParameterToken(...part, config, accum));
194
+ }
195
+ this.seal('modifier');
196
+ /* NOT FOR BROWSER */
197
+ this.protectChildren(0);
198
+ }
199
+ /**
200
+ * Set the transclusion modifier
201
+ *
202
+ * 设置引用修饰符
203
+ * @param modifier transclusion modifier / 引用修饰符
204
+ */
205
+ setModifier(modifier) {
206
+ const { parserFunction: [, , raw, subst] } = this.getAttribute('config'), lcModifier = (0, string_1.removeComment)(modifier).trim();
207
+ if (modifier && !lcModifier.endsWith(':')) {
208
+ return false;
209
+ }
210
+ const magicWord = lcModifier.slice(0, -1).toLowerCase(), isRaw = raw.includes(magicWord), isSubst = subst.includes(magicWord);
211
+ if (this.#raw && isRaw
212
+ || !this.#raw && (isSubst || modifier === '')
213
+ || (debug_1.Shadow.running || this.length > 1) && (isRaw || isSubst || modifier === '')) {
214
+ this.setAttribute('modifier', modifier);
215
+ this.#raw = isRaw;
216
+ return Boolean(modifier);
137
217
  }
138
- // @ts-expect-error abstract class
139
- this.insertAt(new parameter_1.ParameterToken(...part, config, accum));
140
- }
141
- this.seal('modifier');
142
- /* NOT FOR BROWSER */
143
- this.protectChildren(0);
144
- }
145
- /**
146
- * Set the transclusion modifier
147
- *
148
- * 设置引用修饰符
149
- * @param modifier transclusion modifier / 引用修饰符
150
- */
151
- setModifier(modifier) {
152
- const { parserFunction: [, , raw, subst] } = this.getAttribute('config'), lcModifier = (0, string_1.removeComment)(modifier).trim();
153
- if (modifier && !lcModifier.endsWith(':')) {
154
218
  return false;
155
219
  }
156
- const magicWord = lcModifier.slice(0, -1).toLowerCase(), isRaw = raw.includes(magicWord), isSubst = subst.includes(magicWord);
157
- if (this.#raw && isRaw
158
- || !this.#raw && (isSubst || modifier === '')
159
- || (debug_1.Shadow.running || this.length > 1) && (isRaw || isSubst || modifier === '')) {
160
- this.setAttribute('modifier', modifier);
161
- this.#raw = isRaw;
162
- return Boolean(modifier);
163
- }
164
- return false;
165
- }
166
- /**
167
- * Check if it is a template or a module
168
- *
169
- * 是否是模板或模块
170
- */
171
- isTemplate() {
172
- return this.type === 'template' || this.name === 'invoke';
173
- }
174
- /** 获取模板或模块名 */
175
- #getTitle() {
176
- const isTemplate = this.type === 'template', title = this.normalizeTitle(this.childNodes[isTemplate ? 0 : 1].toString(true), isTemplate ? 10 : 828, true);
177
- title.fragment = undefined;
178
- return title;
179
- }
180
- /**
181
- * Get the module name and module function name
182
- *
183
- * 获取模块名和模块函数名
184
- * @throws `Error` 仅用于模块
185
- */
186
- getModule() {
187
- LSP: { // eslint-disable-line no-unused-labels
188
- /* istanbul ignore if */
189
- if (this.type !== 'magic-word' || this.name !== 'invoke') {
190
- throw new Error('TranscludeToken.getModule method is only for modules!');
191
- }
192
- return [
193
- this.#getTitle().title,
194
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
195
- this.childNodes[2]?.toString(true).trim(),
196
- ];
220
+ /**
221
+ * Check if it is a template or a module
222
+ *
223
+ * 是否是模板或模块
224
+ */
225
+ isTemplate() {
226
+ return this.type === 'template' || this.name === 'invoke';
227
+ }
228
+ /** 获取模板或模块名 */
229
+ #getTitle() {
230
+ const isTemplate = this.type === 'template', title = this.normalizeTitle(this.childNodes[isTemplate ? 0 : 1].toString(true), isTemplate ? 10 : 828, { temporary: true });
231
+ title.fragment = undefined;
232
+ return title;
233
+ }
234
+ /**
235
+ * Get the module name and module function name
236
+ *
237
+ * 获取模块名和模块函数名
238
+ * @throws `Error` 仅用于模块
239
+ */
240
+ getModule() {
241
+ LSP: { // eslint-disable-line no-unused-labels
242
+ /* istanbul ignore if */
243
+ if (this.type !== 'magic-word' || this.name !== 'invoke') {
244
+ throw new Error('TranscludeToken.getModule method is only for modules!');
245
+ }
246
+ return [
247
+ this.#getTitle().title,
248
+ // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
249
+ this.childNodes[2]?.toString(true).trim(),
250
+ ];
251
+ }
197
252
  }
198
- }
199
- /** @private */
200
- afterBuild() {
201
- if (this.modifier.includes('\0')) {
202
- this.setAttribute('modifier', this.buildFromStr(this.modifier, constants_1.BuildMethod.String));
203
- }
204
- super.afterBuild();
205
- if (this.isTemplate()) {
206
- const isTemplate = this.type === 'template';
207
- if (isTemplate) {
208
- this.#title = this.#getTitle();
209
- this.setAttribute('name', this.#title.title);
253
+ /** @private */
254
+ afterBuild() {
255
+ if (this.modifier.includes('\0')) {
256
+ this.setAttribute('modifier', this.buildFromStr(this.modifier, constants_1.BuildMethod.String));
210
257
  }
211
- /* NOT FOR BROWSER */
212
- /**
213
- * 当事件bubble到`parameter`时,将`oldKey`和`newKey`保存进AstEventData。
214
- * 当继续bubble到`template`时,处理并删除`oldKey`和`newKey`。
215
- * @implements
216
- */
217
- const transcludeListener = (e, data) => {
218
- const { prevTarget } = e, { oldKey, newKey } = data;
219
- if (typeof oldKey === 'string') {
220
- delete data.oldKey;
221
- delete data.newKey;
222
- }
223
- if (prevTarget === this.firstChild && isTemplate) {
258
+ super.afterBuild();
259
+ if (this.isTemplate()) {
260
+ const isTemplate = this.type === 'template';
261
+ if (isTemplate) {
224
262
  this.#title = this.#getTitle();
225
263
  this.setAttribute('name', this.#title.title);
226
264
  }
227
- else if (oldKey !== newKey && prevTarget instanceof parameter_1.ParameterToken) {
228
- const oldArgs = this.getArgs(oldKey, false, false);
229
- oldArgs.delete(prevTarget);
230
- this.getArgs(newKey, false, false).add(prevTarget);
231
- this.#keys.add(newKey);
232
- if (oldArgs.size === 0) {
233
- this.#keys.delete(oldKey);
265
+ /* NOT FOR BROWSER */
266
+ /**
267
+ * 当事件bubble到`parameter`时,将`oldKey`和`newKey`保存进AstEventData。
268
+ * 当继续bubble到`template`时,处理并删除`oldKey`和`newKey`。
269
+ * @implements
270
+ */
271
+ const transcludeListener = (e, data) => {
272
+ const { prevTarget } = e, { oldKey, newKey } = data;
273
+ if (typeof oldKey === 'string') {
274
+ delete data.oldKey;
275
+ delete data.newKey;
276
+ }
277
+ if (prevTarget === this.firstChild && isTemplate) {
278
+ this.#title = this.#getTitle();
279
+ this.setAttribute('name', this.#title.title);
280
+ }
281
+ else if (oldKey !== newKey && prevTarget instanceof parameter_1.ParameterToken) {
282
+ const oldArgs = this.getArgs(oldKey, false, false);
283
+ oldArgs.delete(prevTarget);
284
+ this.getArgs(newKey, false, false).add(prevTarget);
285
+ this.#keys.add(newKey);
286
+ if (oldArgs.size === 0) {
287
+ this.#keys.delete(oldKey);
288
+ }
234
289
  }
235
- }
236
- };
237
- this.addEventListener(['remove', 'insert', 'replace', 'text'], transcludeListener);
238
- }
239
- }
240
- /** @private */
241
- toString(skip) {
242
- return `{{${this.modifier}${this.type === 'magic-word'
243
- ? this.firstChild.toString(skip)
244
- + (this.length === 1 ? '' : ':')
245
- + this.childNodes.slice(1).map(child => child.toString(skip)).join('|')
246
- : super.toString(skip, '|')}}}`;
247
- }
248
- /** @private */
249
- text() {
250
- const { childNodes, length, firstChild, modifier, type, name } = this;
251
- return type === 'magic-word' && name === 'vardefine'
252
- ? ''
253
- : `{{${modifier}${type === 'magic-word'
254
- ? firstChild.text() + (length === 1 ? '' : ':') + (0, string_1.text)(childNodes.slice(1), '|')
255
- : super.text('|')}}}`;
256
- }
257
- /** @private */
258
- getAttribute(key) {
259
- switch (key) {
260
- case 'padding':
261
- return this.modifier.length + 2;
262
- case 'title':
263
- return this.#title;
264
- /* NOT FOR BROWSER */
265
- case 'keys':
266
- return this.#keys;
267
- /* NOT FOR BROWSER END */
268
- default:
269
- return super.getAttribute(key);
270
- }
271
- }
272
- /** @private */
273
- getGaps() {
274
- return 1;
275
- }
276
- /** @private */
277
- lint(start = this.getAbsoluteIndex(), re) {
278
- const errors = super.lint(start, re);
279
- if (!this.isTemplate()) {
280
- return errors;
281
- }
282
- const { type, childNodes, length } = this, rect = new rect_1.BoundingRect(this, start), invoke = type === 'magic-word';
283
- if (invoke && !this.#getTitle().valid) {
284
- errors.push((0, lint_1.generateForChild)(childNodes[1], rect, 'invalid-invoke', 'illegal module name'));
285
- }
286
- else {
287
- const child = childNodes[invoke ? 1 : 0], i = child.childNodes
288
- .findIndex(c => c.type === 'text' && (0, string_1.decodeHtml)(c.data).includes('#')), textNode = child.childNodes[i];
289
- if (textNode) {
290
- const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'useless fragment');
291
- e.fix = {
292
- range: [
293
- e.startIndex + child.getRelativeIndex(i) + textNode.data.indexOf('#'),
294
- e.endIndex,
295
- ],
296
- text: '',
297
- desc: 'remove',
298
290
  };
299
- errors.push(e);
291
+ this.addEventListener(['remove', 'insert', 'replace', 'text'], transcludeListener);
300
292
  }
301
293
  }
302
- if (invoke && length === 2) {
303
- errors.push((0, lint_1.generateForSelf)(this, rect, 'invalid-invoke', 'missing module function'));
304
- return errors;
305
- }
306
- const duplicatedArgs = this.getDuplicatedArgs()
307
- .filter(([, parameter]) => !parameter[0].querySelector('ext'));
308
- if (duplicatedArgs.length > 0) {
309
- for (const [, args] of duplicatedArgs) {
310
- errors.push(...args.map(arg => {
311
- const e = (0, lint_1.generateForChild)(arg, rect, 'no-duplicate', 'duplicated parameter');
312
- e.suggestions = [{ desc: 'remove', range: [e.startIndex - 1, e.endIndex], text: '' }];
313
- return e;
314
- }));
294
+ /** @private */
295
+ toString(skip) {
296
+ return `{{${this.modifier}${this.type === 'magic-word'
297
+ ? this.firstChild.toString(skip)
298
+ + (this.length === 1 ? '' : this.#colon)
299
+ + this.childNodes.slice(1).map(child => child.toString(skip)).join('|')
300
+ : super.toString(skip, '|')}}}`;
301
+ }
302
+ /** @private */
303
+ text() {
304
+ const { childNodes, length, firstChild, modifier, type, name } = this;
305
+ return type === 'magic-word' && name === 'vardefine'
306
+ ? ''
307
+ : `{{${modifier}${type === 'magic-word'
308
+ ? firstChild.text()
309
+ + (length === 1 ? '' : this.#colon)
310
+ + (0, string_1.text)(childNodes.slice(1), '|')
311
+ : super.text('|')}}}`;
312
+ }
313
+ /** @private */
314
+ getAttribute(key) {
315
+ switch (key) {
316
+ case 'padding':
317
+ return this.modifier.length + 2;
318
+ case 'title':
319
+ return this.#title;
320
+ case 'colon':
321
+ return this.#colon;
322
+ /* NOT FOR BROWSER */
323
+ case 'keys':
324
+ return this.#keys;
325
+ /* NOT FOR BROWSER END */
326
+ default:
327
+ return super.getAttribute(key);
315
328
  }
316
329
  }
317
- return errors;
318
- }
319
- /**
320
- * 处理匿名参数更改
321
- * @param addedToken 新增的参数
322
- */
323
- #handleAnonArgChange(addedToken) {
324
- const args = this.getAnonArgs(), added = typeof addedToken !== 'number';
325
- /* NOT FOR BROWSER */
326
- const maxAnon = String(args.length + (added ? 0 : 1));
327
- if (added) {
328
- this.#keys.add(maxAnon);
330
+ /** @private */
331
+ getGaps() {
332
+ return 1;
329
333
  }
330
- else if (!this.hasArg(maxAnon, true)) {
331
- this.#keys.delete(maxAnon);
332
- }
333
- /* NOT FOR BROWSER END */
334
- for (let i = added ? args.indexOf(addedToken) : addedToken - 1; i < args.length; i++) {
335
- const token = args[i], { name } = token, newName = String(i + 1);
336
- if (name !== newName || token === addedToken) {
337
- token.setAttribute('name', newName);
338
- this.getArgs(newName, false, false).add(token);
339
- /* NOT FOR BROWSER */
340
- if (name && token !== addedToken) {
341
- this.getArgs(name, false, false).delete(token);
334
+ /** @private */
335
+ lint(start = this.getAbsoluteIndex(), re) {
336
+ const errors = super.lint(start, re);
337
+ if (!this.isTemplate()) {
338
+ return errors;
339
+ }
340
+ const { type, childNodes, length } = this, rect = new rect_1.BoundingRect(this, start), invoke = type === 'magic-word';
341
+ if (invoke && !this.#getTitle().valid) {
342
+ errors.push((0, lint_1.generateForChild)(childNodes[1], rect, 'invalid-invoke', 'illegal module name'));
343
+ }
344
+ else {
345
+ const child = childNodes[invoke ? 1 : 0], i = child.childNodes
346
+ .findIndex(c => c.type === 'text' && (0, string_1.decodeHtml)(c.data).includes('#')), textNode = child.childNodes[i];
347
+ if (textNode) {
348
+ const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'useless fragment');
349
+ e.fix = {
350
+ range: [
351
+ e.startIndex + child.getRelativeIndex(i) + textNode.data.indexOf('#'),
352
+ e.endIndex,
353
+ ],
354
+ text: '',
355
+ desc: 'remove',
356
+ };
357
+ errors.push(e);
342
358
  }
343
359
  }
360
+ if (invoke && length === 2) {
361
+ errors.push((0, lint_1.generateForSelf)(this, rect, 'invalid-invoke', 'missing module function'));
362
+ return errors;
363
+ }
364
+ const duplicatedArgs = this.getDuplicatedArgs()
365
+ .filter(([, parameter]) => !parameter[0].querySelector('ext'));
366
+ if (duplicatedArgs.length > 0) {
367
+ for (const [, args] of duplicatedArgs) {
368
+ errors.push(...args.map(arg => {
369
+ const e = (0, lint_1.generateForChild)(arg, rect, 'no-duplicate', 'duplicated parameter');
370
+ e.suggestions = [{ desc: 'remove', range: [e.startIndex - 1, e.endIndex], text: '' }];
371
+ return e;
372
+ }));
373
+ }
374
+ }
375
+ return errors;
344
376
  }
345
- }
346
- /**
347
- * @override
348
- * @param token node to be inserted / 待插入的子节点
349
- * @param i position to be inserted at / 插入位置
350
- */
351
- insertAt(token, i = this.length) {
352
- super.insertAt(token, i);
353
- if (token.anon) {
354
- this.#handleAnonArgChange(token);
355
- }
356
- else if (token.name) {
357
- this.getArgs(token.name, false, false).add(token);
377
+ /**
378
+ * 处理匿名参数更改
379
+ * @param addedToken 新增的参数
380
+ */
381
+ #handleAnonArgChange(addedToken) {
382
+ const args = this.getAnonArgs(), added = typeof addedToken !== 'number';
358
383
  /* NOT FOR BROWSER */
359
- this.#keys.add(token.name);
360
- }
361
- return token;
362
- }
363
- /**
364
- * Get all parameters
365
- *
366
- * 获取所有参数
367
- */
368
- getAllArgs() {
369
- return this.childNodes.filter((0, debug_1.isToken)('parameter'));
370
- }
371
- /**
372
- * Get all anonymous parameters
373
- *
374
- * 获取所有匿名参数
375
- */
376
- getAnonArgs() {
377
- return this.getAllArgs().filter(({ anon }) => anon);
378
- }
379
- /**
380
- * Get parameters with the specified name
381
- *
382
- * 获取指定参数
383
- * @param key parameter name / 参数名
384
- * @param exact whether to match anonymosity / 是否匹配匿名性
385
- * @param copy whether to return a copy / 是否返回一个备份
386
- */
387
- getArgs(key, exact, copy = true) {
388
- const keyStr = String(key)
389
- .replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1');
390
- let args;
391
- if (this.#args.has(keyStr)) {
392
- args = this.#args.get(keyStr);
393
- }
394
- else {
395
- args = new Set(this.getAllArgs().filter(({ name }) => keyStr === name));
396
- this.#args.set(keyStr, args);
397
- }
398
- /* NOT FOR BROWSER */
399
- if (exact && keyStr.trim() && !isNaN(keyStr)) {
400
- args = new Set([...args].filter(({ anon }) => typeof key === 'number' === anon));
384
+ const maxAnon = String(args.length + (added ? 0 : 1));
385
+ if (added) {
386
+ this.#keys.add(maxAnon);
387
+ }
388
+ else if (!this.hasArg(maxAnon, true)) {
389
+ this.#keys.delete(maxAnon);
390
+ }
391
+ /* NOT FOR BROWSER END */
392
+ for (let i = added ? args.indexOf(addedToken) : addedToken - 1; i < args.length; i++) {
393
+ const token = args[i], { name } = token, newName = String(i + 1);
394
+ if (name !== newName || token === addedToken) {
395
+ token.setAttribute('name', newName);
396
+ this.getArgs(newName, false, false).add(token);
397
+ /* NOT FOR BROWSER */
398
+ if (name && token !== addedToken) {
399
+ this.getArgs(name, false, false).delete(token);
400
+ }
401
+ }
402
+ }
401
403
  }
402
- else if (copy) {
403
- args = new Set(args);
404
+ /**
405
+ * @override
406
+ * @param token node to be inserted / 待插入的子节点
407
+ * @param i position to be inserted at / 插入位置
408
+ */
409
+ insertAt(token, i = this.length) {
410
+ super.insertAt(token, i);
411
+ if (token.anon) {
412
+ this.#handleAnonArgChange(token);
413
+ }
414
+ else if (token.name) {
415
+ this.getArgs(token.name, false, false).add(token);
416
+ /* NOT FOR BROWSER */
417
+ this.#keys.add(token.name);
418
+ }
419
+ return token;
404
420
  }
405
- /* NOT FOR BROWSER END */
406
- return args;
407
- }
408
- /**
409
- * Get duplicated parameters
410
- *
411
- * 获取重名参数
412
- * @throws `Error` 仅用于模板
413
- */
414
- getDuplicatedArgs() {
415
- if (this.isTemplate()) {
416
- return [...this.#args].filter(([, { size }]) => size > 1).map(([key, args]) => [key, [...args]]);
417
- }
418
- throw new Error('TranscludeToken.getDuplicatedArgs method is only for template!');
419
- }
420
- /**
421
- * Get possible values of some magic words
422
- *
423
- * 对特定魔术字获取可能的取值
424
- * @throws `Error` 不是可接受的魔术字
425
- */
426
- getPossibleValues() {
427
- const { type, name, childNodes } = this;
428
- if (type === 'template') {
429
- throw new Error('TranscludeToken.getPossibleValues method is only for specific magic words!');
430
- }
431
- let start;
432
- switch (name) {
433
- case 'if':
434
- case 'ifexist':
435
- case 'ifexpr':
436
- case 'iferror':
437
- start = 2;
438
- break;
439
- case 'ifeq':
440
- start = 3;
441
- break;
442
- default:
421
+ /**
422
+ * Get all parameters
423
+ *
424
+ * 获取所有参数
425
+ */
426
+ getAllArgs() {
427
+ return this.childNodes.filter((0, debug_1.isToken)('parameter'));
428
+ }
429
+ /**
430
+ * Get all anonymous parameters
431
+ *
432
+ * 获取所有匿名参数
433
+ */
434
+ getAnonArgs() {
435
+ return this.getAllArgs().filter(({ anon }) => anon);
436
+ }
437
+ /**
438
+ * Get parameters with the specified name
439
+ *
440
+ * 获取指定参数
441
+ * @param key parameter name / 参数名
442
+ * @param exact whether to match anonymosity / 是否匹配匿名性
443
+ * @param copy whether to return a copy / 是否返回一个备份
444
+ */
445
+ getArgs(key, exact, copy = true) {
446
+ const keyStr = String(key)
447
+ .replace(/^[ \t\n\0\v]+|([^ \t\n\0\v])[ \t\n\0\v]+$/gu, '$1');
448
+ let args;
449
+ if (this.#args.has(keyStr)) {
450
+ args = this.#args.get(keyStr);
451
+ }
452
+ else {
453
+ args = new Set(this.getAllArgs().filter(({ name }) => keyStr === name));
454
+ this.#args.set(keyStr, args);
455
+ }
456
+ /* NOT FOR BROWSER */
457
+ if (exact && keyStr.trim() && !isNaN(keyStr)) {
458
+ args = new Set([...args].filter(({ anon }) => typeof key === 'number' === anon));
459
+ }
460
+ else if (copy) {
461
+ args = new Set(args);
462
+ }
463
+ /* NOT FOR BROWSER END */
464
+ return args;
465
+ }
466
+ /**
467
+ * Get duplicated parameters
468
+ *
469
+ * 获取重名参数
470
+ * @throws `Error` 仅用于模板
471
+ */
472
+ getDuplicatedArgs() {
473
+ if (this.isTemplate()) {
474
+ return [...this.#args].filter(([, { size }]) => size > 1).map(([key, args]) => [key, [...args]]);
475
+ }
476
+ throw new Error('TranscludeToken.getDuplicatedArgs method is only for template!');
477
+ }
478
+ /**
479
+ * Get possible values of some magic words
480
+ *
481
+ * 对特定魔术字获取可能的取值
482
+ * @throws `Error` 不是可接受的魔术字
483
+ */
484
+ getPossibleValues() {
485
+ const { type, name, childNodes } = this;
486
+ if (type === 'template') {
443
487
  throw new Error('TranscludeToken.getPossibleValues method is only for specific magic words!');
444
- }
445
- const queue = childNodes.slice(start, start + 2).map(({ childNodes: [, value] }) => value);
446
- for (let i = 0; i < queue.length;) {
447
- const { length, 0: first } = queue[i].childNodes.filter(child => child.text().trim());
448
- if (length === 0) {
449
- queue.splice(i, 1);
450
488
  }
451
- else if (length > 1 || first.type !== 'magic-word') {
452
- i++;
489
+ let start;
490
+ switch (name) {
491
+ case 'if':
492
+ case 'ifexist':
493
+ case 'ifexpr':
494
+ case 'iferror':
495
+ start = 2;
496
+ break;
497
+ case 'ifeq':
498
+ start = 3;
499
+ break;
500
+ default:
501
+ throw new Error('TranscludeToken.getPossibleValues method is only for specific magic words!');
453
502
  }
454
- else {
455
- try {
456
- const possibleValues = first.getPossibleValues();
457
- queue.splice(i, 1, ...possibleValues);
458
- i += possibleValues.length;
503
+ const queue = childNodes.slice(start, start + 2).map(({ childNodes: [, value] }) => value);
504
+ for (let i = 0; i < queue.length;) {
505
+ const { length, 0: first } = queue[i].childNodes.filter(child => child.text().trim());
506
+ if (length === 0) {
507
+ queue.splice(i, 1);
459
508
  }
460
- catch {
509
+ else if (length > 1 || first.type !== 'magic-word') {
461
510
  i++;
462
511
  }
512
+ else {
513
+ try {
514
+ const possibleValues = first.getPossibleValues();
515
+ queue.splice(i, 1, ...possibleValues);
516
+ i += possibleValues.length;
517
+ }
518
+ catch {
519
+ i++;
520
+ }
521
+ }
463
522
  }
523
+ return queue;
464
524
  }
465
- return queue;
466
- }
467
- /** @private */
468
- print() {
469
- const { childNodes, length, firstChild, modifier, type } = this;
470
- return `<span class="wpb-${type}">{{${(0, string_1.escape)(modifier)}${type === 'magic-word'
471
- ? firstChild.print() + (length === 1 ? '' : ':') + (0, string_1.print)(childNodes.slice(1), { sep: '|' })
472
- : (0, string_1.print)(childNodes, { sep: '|' })}}}</span>`;
473
- }
474
- /* NOT FOR BROWSER */
475
- cloneNode() {
476
- const [first, ...cloned] = this.cloneChildNodes(), config = this.getAttribute('config');
477
- return debug_1.Shadow.run(() => {
478
- // @ts-expect-error abstract class
479
- const token = new TranscludeToken(this.type === 'template' ? 'T' : `${first.text()}:`, [], config);
480
- if (this.#raw) {
481
- token.setModifier(this.modifier);
525
+ /** @private */
526
+ print() {
527
+ const { childNodes, length, firstChild, modifier, type } = this;
528
+ return `<span class="wpb-${type}">{{${(0, string_1.escape)(modifier)}${type === 'magic-word'
529
+ ? firstChild.print() + (length === 1 ? '' : this.#colon) + (0, string_1.print)(childNodes.slice(1), { sep: '|' })
530
+ : (0, string_1.print)(childNodes, { sep: '|' })}}}</span>`;
531
+ }
532
+ /* NOT FOR BROWSER */
533
+ cloneNode() {
534
+ const [first, ...cloned] = this.cloneChildNodes(), config = this.getAttribute('config');
535
+ return debug_1.Shadow.run(() => {
536
+ // @ts-expect-error abstract class
537
+ const token = new TranscludeToken(this.type === 'template' ? 'T' : first.text() + (cloned.length === 0 ? '' : this.#colon), [], config);
538
+ if (this.#raw) {
539
+ token.setModifier(this.modifier);
540
+ }
541
+ else {
542
+ token.setAttribute('modifier', this.modifier);
543
+ }
544
+ token.firstChild.safeReplaceWith(first);
545
+ if (token.length > 1) {
546
+ token.removeAt(1);
547
+ }
548
+ token.append(...cloned);
549
+ return token;
550
+ });
551
+ }
552
+ /**
553
+ * Convert to substitution
554
+ *
555
+ * 替换引用
556
+ */
557
+ subst() {
558
+ this.setModifier('subst:');
559
+ }
560
+ /**
561
+ * Convert to safe substitution
562
+ *
563
+ * 安全的替换引用
564
+ */
565
+ safesubst() {
566
+ this.setModifier('safesubst:');
567
+ }
568
+ /**
569
+ * @override
570
+ * @param i position of the child node / 移除位置
571
+ */
572
+ removeAt(i) {
573
+ const token = super.removeAt(i);
574
+ if (token.anon) {
575
+ this.#handleAnonArgChange(Number(token.name));
482
576
  }
483
577
  else {
484
- token.setAttribute('modifier', this.modifier);
485
- }
486
- token.firstChild.safeReplaceWith(first);
487
- if (this.type === 'magic-word') {
488
- token.removeAt(1);
578
+ const args = this.getArgs(token.name, false, false);
579
+ args.delete(token);
580
+ if (args.size === 0) {
581
+ this.#keys.delete(token.name);
582
+ }
489
583
  }
490
- token.append(...cloned);
491
- token.afterBuild();
492
584
  return token;
493
- });
494
- }
495
- /**
496
- * Convert to substitution
497
- *
498
- * 替换引用
499
- */
500
- subst() {
501
- this.setModifier('subst:');
502
- }
503
- /**
504
- * Convert to safe substitution
505
- *
506
- * 安全的替换引用
507
- */
508
- safesubst() {
509
- this.setModifier('safesubst:');
510
- }
511
- /**
512
- * @override
513
- * @param i position of the child node / 移除位置
514
- */
515
- removeAt(i) {
516
- const token = super.removeAt(i);
517
- if (token.anon) {
518
- this.#handleAnonArgChange(Number(token.name));
519
- }
520
- else {
521
- const args = this.getArgs(token.name, false, false);
522
- args.delete(token);
523
- if (args.size === 0) {
524
- this.#keys.delete(token.name);
525
- }
526
- }
527
- return token;
528
- }
529
- /**
530
- * Check if there is a parameter with the specified name
531
- *
532
- * 是否具有某参数
533
- * @param key parameter name / 参数名
534
- * @param exact whether to match anonymosity / 是否匹配匿名性
535
- */
536
- hasArg(key, exact) {
537
- return this.getArgs(key, exact, false).size > 0;
538
- }
539
- /**
540
- * Get the effective parameter with the specified name
541
- *
542
- * 获取生效的指定参数
543
- * @param key parameter name / 参数名
544
- * @param exact whether to match anonymosity / 是否匹配匿名性
545
- */
546
- getArg(key, exact) {
547
- return [...this.getArgs(key, exact, false)].sort((a, b) => a.compareDocumentPosition(b)).at(-1);
548
- }
549
- /**
550
- * Remove parameters with the specified name
551
- *
552
- * 移除指定参数
553
- * @param key parameter name / 参数名
554
- * @param exact whether to match anonymosity / 是否匹配匿名性
555
- */
556
- removeArg(key, exact) {
557
- debug_1.Shadow.run(() => {
558
- for (const token of this.getArgs(key, exact, false)) {
559
- this.removeChild(token);
560
- }
561
- });
562
- }
563
- /**
564
- * Get all parameter names
565
- *
566
- * 获取所有参数名
567
- */
568
- getKeys() {
569
- const args = this.getAllArgs();
570
- if (this.#keys.size === 0 && args.length > 0) {
571
- for (const { name } of args) {
572
- this.#keys.add(name);
573
- }
574
- }
575
- return [...this.#keys];
576
- }
577
- /**
578
- * Get parameter values
579
- *
580
- * 获取参数值
581
- * @param key parameter name / 参数名
582
- */
583
- getValues(key) {
584
- return [...this.getArgs(key, false, false)].map(token => token.getValue());
585
- }
586
- getValue(key) {
587
- return key === undefined
588
- ? Object.fromEntries(this.getKeys().map(k => [k, this.getValue(k)]))
589
- : this.getArg(key)?.getValue();
590
- }
591
- /**
592
- * Insert an anonymous parameter
593
- *
594
- * 插入匿名参数
595
- * @param val parameter value / 参数值
596
- */
597
- newAnonArg(val) {
598
- require('../addon/transclude');
599
- return this.newAnonArg(val);
600
- }
601
- /**
602
- * Set the parameter value
603
- *
604
- * 设置参数值
605
- * @param key parameter name / 参数名
606
- * @param value parameter value / 参数值
607
- * @throws `Error` 仅用于模板
608
- */
609
- setValue(key, value) {
610
- require('../addon/transclude');
611
- this.setValue(key, value);
612
- }
613
- /**
614
- * Convert all anonymous parameters to named ones
615
- *
616
- * 将匿名参数改写为命名参数
617
- * @throws `Error` 仅用于模板
618
- */
619
- anonToNamed() {
620
- if (!this.isTemplate()) {
621
- throw new Error('TranscludeToken.anonToNamed method is only for template!');
622
- }
623
- for (const token of this.getAnonArgs()) {
624
- token.firstChild.replaceChildren(token.name);
625
585
  }
626
- }
627
- /**
628
- * Replace the template name
629
- *
630
- * 替换模板名
631
- * @param title template name / 模板名
632
- * @throws `Error` 仅用于模板
633
- */
634
- replaceTemplate(title) {
635
- require('../addon/transclude');
636
- this.replaceTemplate(title);
637
- }
638
- /**
639
- * Replace the module name
640
- *
641
- * 替换模块名
642
- * @param title module name / 模块名
643
- * @throws `Error` 仅用于模块
644
- */
645
- replaceModule(title) {
646
- require('../addon/transclude');
647
- this.replaceModule(title);
648
- }
649
- /**
650
- * Replace the module function
651
- *
652
- * 替换模块函数
653
- * @param func module function name / 模块函数名
654
- * @throws `Error` 仅用于模块
655
- * @throws `Error` 尚未指定模块名称
656
- */
657
- replaceFunction(func) {
658
- require('../addon/transclude');
659
- this.replaceFunction(func);
660
- }
661
- /**
662
- * Count duplicated parameters
663
- *
664
- * 重复参数计数
665
- * @throws `Error` 仅用于模板
666
- */
667
- hasDuplicatedArgs() {
668
- if (this.isTemplate()) {
669
- return this.getAllArgs().length - this.getKeys().length;
670
- }
671
- throw new Error('TranscludeToken.hasDuplicatedArgs method is only for template!');
672
- }
673
- /**
674
- * Fix duplicated parameters
675
- * @description
676
- * - Only empty parameters and identical parameters are removed with `aggressive = false`.
677
- * Anonymous parameters have a higher precedence, otherwise all anonymous parameters are converted to named ones.
678
- * - Additionally, consecutive numbered parameters are treated with `aggressive = true`.
679
- *
680
- * 修复重名参数
681
- * @description
682
- * - `aggressive = false`时只移除空参数和全同参数,优先保留匿名参数,否则将所有匿名参数更改为命名。
683
- * - `aggressive = true`时还会尝试处理连续的以数字编号的参数。
684
- * @param aggressive whether to use a more risky approach / 是否使用有更大风险的修复手段
685
- */
686
- fixDuplication(aggressive) {
687
- require('../addon/transclude');
688
- return this.fixDuplication(aggressive);
689
- }
690
- /**
691
- * Escape tables inside the template
692
- *
693
- * 转义模板内的表格
694
- * @throws `Error` 转义失败
695
- */
696
- escapeTables() {
697
- require('../addon/transclude');
698
- return this.escapeTables();
699
- }
700
- /** @private */
701
- toHtmlInternal(opt) {
702
- const { type, name } = this;
703
- if (type === 'template' && !name.startsWith('Special:')) {
704
- if (this.normalizeTitle(name, 0, true, true).valid) {
705
- const title = name.replaceAll('_', ' ');
706
- return `<a href="${this.#title.getUrl()}?action=edit&redlink=1" class="new" title="${title} (page does not exist)">${title}</a>`;
707
- }
708
- const str = this.toString(true);
709
- return opt?.nowrap ? str.replaceAll('\n', ' ') : str;
710
- }
711
- return basicMagicWords.has(name) ? basicMagicWords.get(name) : '';
712
- }
713
- }
586
+ /**
587
+ * Check if there is a parameter with the specified name
588
+ *
589
+ * 是否具有某参数
590
+ * @param key parameter name / 参数名
591
+ * @param exact whether to match anonymosity / 是否匹配匿名性
592
+ */
593
+ hasArg(key, exact) {
594
+ return this.getArgs(key, exact, false).size > 0;
595
+ }
596
+ /**
597
+ * Get the effective parameter with the specified name
598
+ *
599
+ * 获取生效的指定参数
600
+ * @param key parameter name / 参数名
601
+ * @param exact whether to match anonymosity / 是否匹配匿名性
602
+ */
603
+ getArg(key, exact) {
604
+ return [...this.getArgs(key, exact, false)].sort((a, b) => a.compareDocumentPosition(b)).at(-1);
605
+ }
606
+ /**
607
+ * Remove parameters with the specified name
608
+ *
609
+ * 移除指定参数
610
+ * @param key parameter name / 参数名
611
+ * @param exact whether to match anonymosity / 是否匹配匿名性
612
+ */
613
+ removeArg(key, exact) {
614
+ debug_1.Shadow.run(() => {
615
+ for (const token of this.getArgs(key, exact, false)) {
616
+ this.removeChild(token);
617
+ }
618
+ });
619
+ }
620
+ /**
621
+ * Get all parameter names
622
+ *
623
+ * 获取所有参数名
624
+ */
625
+ getKeys() {
626
+ const args = this.getAllArgs();
627
+ if (this.#keys.size === 0 && args.length > 0) {
628
+ for (const { name } of args) {
629
+ this.#keys.add(name);
630
+ }
631
+ }
632
+ return [...this.#keys];
633
+ }
634
+ /**
635
+ * Get parameter values
636
+ *
637
+ * 获取参数值
638
+ * @param key parameter name / 参数名
639
+ */
640
+ getValues(key) {
641
+ return [...this.getArgs(key, false, false)].map(token => token.getValue());
642
+ }
643
+ getValue(key) {
644
+ return key === undefined
645
+ ? Object.fromEntries(this.getKeys().map(k => [k, this.getValue(k)]))
646
+ : this.getArg(key)?.getValue();
647
+ }
648
+ /**
649
+ * Insert an anonymous parameter
650
+ *
651
+ * 插入匿名参数
652
+ * @param val parameter value / 参数值
653
+ */
654
+ newAnonArg(val) {
655
+ require('../addon/transclude');
656
+ return this.newAnonArg(val);
657
+ }
658
+ /**
659
+ * Set the parameter value
660
+ *
661
+ * 设置参数值
662
+ * @param key parameter name / 参数名
663
+ * @param value parameter value / 参数值
664
+ * @throws `Error` 仅用于模板
665
+ */
666
+ setValue(key, value) {
667
+ require('../addon/transclude');
668
+ this.setValue(key, value);
669
+ }
670
+ /**
671
+ * Convert all anonymous parameters to named ones
672
+ *
673
+ * 将匿名参数改写为命名参数
674
+ * @throws `Error` 仅用于模板
675
+ */
676
+ anonToNamed() {
677
+ if (!this.isTemplate()) {
678
+ throw new Error('TranscludeToken.anonToNamed method is only for template!');
679
+ }
680
+ for (const token of this.getAnonArgs()) {
681
+ token.firstChild.replaceChildren(token.name);
682
+ }
683
+ }
684
+ /**
685
+ * Replace the template name
686
+ *
687
+ * 替换模板名
688
+ * @param title template name / 模板名
689
+ * @throws `Error` 仅用于模板
690
+ */
691
+ replaceTemplate(title) {
692
+ require('../addon/transclude');
693
+ this.replaceTemplate(title);
694
+ }
695
+ /**
696
+ * Replace the module name
697
+ *
698
+ * 替换模块名
699
+ * @param title module name / 模块名
700
+ * @throws `Error` 仅用于模块
701
+ */
702
+ replaceModule(title) {
703
+ require('../addon/transclude');
704
+ this.replaceModule(title);
705
+ }
706
+ /**
707
+ * Replace the module function
708
+ *
709
+ * 替换模块函数
710
+ * @param func module function name / 模块函数名
711
+ * @throws `Error` 仅用于模块
712
+ * @throws `Error` 尚未指定模块名称
713
+ */
714
+ replaceFunction(func) {
715
+ require('../addon/transclude');
716
+ this.replaceFunction(func);
717
+ }
718
+ /**
719
+ * Count duplicated parameters
720
+ *
721
+ * 重复参数计数
722
+ * @throws `Error` 仅用于模板
723
+ */
724
+ hasDuplicatedArgs() {
725
+ if (this.isTemplate()) {
726
+ return this.getAllArgs().length - this.getKeys().length;
727
+ }
728
+ throw new Error('TranscludeToken.hasDuplicatedArgs method is only for template!');
729
+ }
730
+ /**
731
+ * Fix duplicated parameters
732
+ * @description
733
+ * - Only empty parameters and identical parameters are removed with `aggressive = false`.
734
+ * Anonymous parameters have a higher precedence, otherwise all anonymous parameters are converted to named ones.
735
+ * - Additionally, consecutive numbered parameters are treated with `aggressive = true`.
736
+ *
737
+ * 修复重名参数
738
+ * @description
739
+ * - `aggressive = false`时只移除空参数和全同参数,优先保留匿名参数,否则将所有匿名参数更改为命名。
740
+ * - `aggressive = true`时还会尝试处理连续的以数字编号的参数。
741
+ * @param aggressive whether to use a more risky approach / 是否使用有更大风险的修复手段
742
+ */
743
+ fixDuplication(aggressive) {
744
+ require('../addon/transclude');
745
+ return this.fixDuplication(aggressive);
746
+ }
747
+ /**
748
+ * Escape tables inside the template
749
+ *
750
+ * 转义模板内的表格
751
+ * @throws `Error` 转义失败
752
+ */
753
+ escapeTables() {
754
+ require('../addon/transclude');
755
+ return this.escapeTables();
756
+ }
757
+ /** @private */
758
+ toHtmlInternal(opt) {
759
+ const { type, name } = this;
760
+ if (type === 'template' && !name.startsWith('Special:')) {
761
+ if (this.normalizeTitle(name, 0, { halfParsed: true, temporary: true }).valid) {
762
+ const title = name.replaceAll('_', ' ');
763
+ return `<a href="${this.#title.getUrl()}?action=edit&redlink=1" class="new" title="${title} (page does not exist)">${title}</a>`;
764
+ }
765
+ const str = this.toString(true);
766
+ return opt?.nowrap ? str.replaceAll('\n', ' ') : str;
767
+ }
768
+ return basicMagicWords.has(name) ? basicMagicWords.get(name) : '';
769
+ }
770
+ };
771
+ return TranscludeToken = _classThis;
772
+ })();
714
773
  exports.TranscludeToken = TranscludeToken;
715
774
  constants_1.classes['TranscludeToken'] = __filename;