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