wikiparser-node 1.28.1 → 1.29.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/README.md +0 -2
  2. package/bundle/bundle-es8.min.js +25 -25
  3. package/bundle/bundle-lsp.min.js +30 -30
  4. package/bundle/bundle.min.js +24 -24
  5. package/data/ext/ThirdPartyNotices.txt +33 -0
  6. package/data/ext/mapframe.json +489 -2
  7. package/dist/addon/magicWords.js +132 -0
  8. package/dist/addon/table.js +4 -4
  9. package/dist/addon/token.js +37 -126
  10. package/dist/addon/transclude.js +24 -30
  11. package/dist/base.d.mts +4 -2
  12. package/dist/base.d.ts +4 -2
  13. package/dist/base.js +1 -0
  14. package/dist/base.mjs +2 -1
  15. package/dist/bin/config.js +1 -1
  16. package/dist/index.d.ts +2 -1
  17. package/dist/index.js +27 -5
  18. package/dist/lib/document.d.ts +23 -7
  19. package/dist/lib/document.js +7 -27
  20. package/dist/lib/element.js +1 -1
  21. package/dist/lib/lintConfig.js +2 -0
  22. package/dist/lib/lsp.d.ts +1 -12
  23. package/dist/lib/lsp.js +41 -78
  24. package/dist/lib/node.js +25 -25
  25. package/dist/lib/range.js +2 -2
  26. package/dist/lib/title.d.ts +3 -1
  27. package/dist/lib/title.js +54 -33
  28. package/dist/mixin/elementLike.js +14 -9
  29. package/dist/parser/commentAndExt.js +30 -26
  30. package/dist/parser/links.js +4 -3
  31. package/dist/parser/redirect.js +1 -1
  32. package/dist/parser/selector.js +7 -9
  33. package/dist/src/arg.js +4 -6
  34. package/dist/src/attribute.js +36 -8
  35. package/dist/src/attributes.js +1 -1
  36. package/dist/src/converter.js +6 -3
  37. package/dist/src/converterRule.js +4 -6
  38. package/dist/src/extLink.js +3 -4
  39. package/dist/src/heading.js +1 -2
  40. package/dist/src/imageParameter.d.ts +4 -1
  41. package/dist/src/imageParameter.js +30 -7
  42. package/dist/src/index.d.ts +8 -0
  43. package/dist/src/index.js +21 -29
  44. package/dist/src/link/base.js +6 -8
  45. package/dist/src/link/file.js +9 -10
  46. package/dist/src/link/galleryImage.js +1 -1
  47. package/dist/src/link/redirectTarget.js +1 -1
  48. package/dist/src/magicLink.js +1 -2
  49. package/dist/src/multiLine/gallery.js +2 -2
  50. package/dist/src/multiLine/imagemap.js +3 -4
  51. package/dist/src/multiLine/paramTag.js +2 -2
  52. package/dist/src/nowiki/doubleUnderscore.js +1 -3
  53. package/dist/src/nowiki/index.js +58 -4
  54. package/dist/src/onlyinclude.js +2 -1
  55. package/dist/src/parameter.js +4 -6
  56. package/dist/src/redirect.js +2 -2
  57. package/dist/src/table/base.js +1 -2
  58. package/dist/src/table/index.js +3 -6
  59. package/dist/src/table/td.d.ts +2 -3
  60. package/dist/src/table/td.js +6 -6
  61. package/dist/src/table/trBase.js +1 -1
  62. package/dist/src/tag/html.js +3 -4
  63. package/dist/src/tag/tvar.js +1 -2
  64. package/dist/src/tagPair/ext.js +2 -2
  65. package/dist/src/tagPair/include.js +2 -2
  66. package/dist/src/tagPair/translate.js +2 -2
  67. package/dist/src/transclude.js +5 -5
  68. package/dist/util/constants.js +4 -1
  69. package/dist/util/debug.js +1 -1
  70. package/dist/util/html.js +13 -10
  71. package/dist/util/search.js +16 -0
  72. package/dist/util/sharable.js +27 -3
  73. package/dist/util/sharable.mjs +28 -4
  74. package/extensions/dist/base.js +1 -1
  75. package/i18n/en.json +2 -0
  76. package/i18n/zh-hans.json +2 -0
  77. package/i18n/zh-hant.json +2 -0
  78. package/package.json +6 -4
  79. package/data/ext/maplink.json +0 -4
@@ -15,40 +15,12 @@ const include_1 = require("../src/tagPair/include");
15
15
  const ext_1 = require("../src/tagPair/ext");
16
16
  const html_1 = require("../src/tag/html");
17
17
  const attributes_1 = require("../src/attributes");
18
+ const magicWords_1 = require("./magicWords");
18
19
  const blockElems = 'table|h1|h2|h3|h4|h5|h6|pre|p|ul|ol|dl', antiBlockElems = 'td|th', solvedMagicWords = new Set([
19
20
  'if',
20
21
  'ifeq',
21
22
  'ifexist',
22
23
  'switch',
23
- ]), expandedMagicWords = new Set([
24
- 'currentmonth',
25
- 'currentmonth1',
26
- 'currentmonthname',
27
- 'currentmonthnamegen',
28
- 'currentmonthabbrev',
29
- 'currentday',
30
- 'currentday2',
31
- 'currentdayname',
32
- 'currentyear',
33
- 'currenttime',
34
- 'currenthour',
35
- 'currentweek',
36
- 'currentdow',
37
- 'currenttimestamp',
38
- 'localmonth',
39
- 'localmonth1',
40
- 'localmonthname',
41
- 'localmonthnamegen',
42
- 'localmonthabbrev',
43
- 'localday',
44
- 'localday2',
45
- 'localdayname',
46
- 'localyear',
47
- 'localtime',
48
- 'localhour',
49
- 'localweek',
50
- 'localdow',
51
- 'localtimestamp',
52
24
  ]);
53
25
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
54
26
  /<(?:table|\/(?:td|th)|\/?(?:tr|caption|dt|dd|li))\b/iu;
@@ -85,6 +57,7 @@ const parseIf = (accum, prev, effective) => {
85
57
  /**
86
58
  * 展开模板
87
59
  * @param wikitext
60
+ * @param page 页面名称
88
61
  * @param config
89
62
  * @param include
90
63
  * @param context 模板调用环境
@@ -92,9 +65,10 @@ const parseIf = (accum, prev, effective) => {
92
65
  * @param accum
93
66
  * @param stack 模板调用栈
94
67
  */
95
- const expand = (wikitext, config, include, context, now = index_1.default.now ?? new Date(), accum = [], stack = []) => {
68
+ const expand = (wikitext, page, config, include, context, now = index_1.default.now ?? new Date(), accum = [], stack = []) => {
96
69
  const n = accum.length, token = new index_2.Token(wikitext, { ...config, inExt: true }, accum);
97
70
  token.type = 'root';
71
+ token.pageName = page;
98
72
  token.parseOnce(0, include);
99
73
  if (context !== false) {
100
74
  token.setText((0, string_1.removeCommentLine)(token.firstChild.toString(), true));
@@ -109,7 +83,7 @@ const expand = (wikitext, config, include, context, now = index_1.default.now ??
109
83
  continue;
110
84
  }
111
85
  const expanded = data.replace(/([^\x7F]?)\0(\d+)t\x7F/gu, (m, prev, i) => {
112
- const target = accum[i], { type, name, length, firstChild: f } = target;
86
+ const target = accum[i], { type, name, length, firstChild: f, childNodes } = target, isTemplate = type === 'template', args = childNodes.slice(1);
113
87
  if (type === 'arg') {
114
88
  const arg = (0, string_1.removeCommentLine)(f.toString()).trim();
115
89
  if (/\0\d+t\x7F/u.test(arg)) {
@@ -125,30 +99,29 @@ const expand = (wikitext, config, include, context, now = index_1.default.now ??
125
99
  accum[accum.indexOf(context.getArg(arg).lastChild)] = undefined;
126
100
  return prev + context.getValue(arg);
127
101
  }
128
- else if (type === 'template') {
102
+ else if (isTemplate || name === 'int') {
129
103
  if (context === false) {
130
104
  return m;
131
105
  }
132
- const c = target.getAttribute('config'), { title, valid } = index_1.default.normalizeTitle((0, string_1.removeComment)(f.toString()), 10, include, c, { halfParsed: true, temporary: true });
106
+ const nameToken = isTemplate ? f : args[0], key = (0, string_1.removeComment)(nameToken.toString()), fallback = isTemplate ? m : `${prev}⧼${key}⧽`, { title, valid } = index_1.default.normalizeTitle((isTemplate ? '' : 'MediaWiki:') + key, 10, include, config, { halfParsed: true, temporary: true, page });
133
107
  if (!valid) {
134
108
  // @ts-expect-error sparse array
135
109
  accum[accum.indexOf(target)] = undefined;
136
110
  // @ts-expect-error sparse array
137
111
  accum[accum.indexOf(f)] = undefined;
138
- return prev + target.toString();
112
+ return isTemplate ? prev + target.toString() : fallback;
139
113
  }
140
114
  else if (!index_1.default.templates.has(title)) {
141
115
  if (index_1.default.templateDir === undefined) {
142
- return m;
116
+ return fallback;
143
117
  }
144
118
  else if (!path_1.default.isAbsolute(index_1.default.templateDir)) {
145
119
  index_1.default.templateDir = path_1.default.join(__dirname, '..', '..', index_1.default.templateDir);
146
120
  }
147
- const file = fs_1.default.readdirSync(index_1.default.templateDir, { withFileTypes: true })
121
+ const file = fs_1.default.readdirSync(index_1.default.templateDir, { withFileTypes: true, recursive: true })
148
122
  .filter(dirent => dirent.isFile())
149
- .find(({ name: fl }) => {
150
- const t = fl.replace(/\.(?:wiki|txt)$/iu, '')
151
- .replaceAll('꞉', ':');
123
+ .find(({ name: fl, parentPath }) => {
124
+ const t = path_1.default.relative(index_1.default.templateDir, path_1.default.join(parentPath, fl.replace(/\.(?:wiki|txt)$/iu, ''))).replaceAll('꞉', ':');
152
125
  try {
153
126
  return decodeURIComponent(t) === title;
154
127
  }
@@ -157,90 +130,26 @@ const expand = (wikitext, config, include, context, now = index_1.default.now ??
157
130
  }
158
131
  });
159
132
  if (!file) {
160
- return m;
133
+ return fallback;
161
134
  }
162
135
  index_1.default.templates.set(title, fs_1.default.readFileSync(path_1.default.join(file.parentPath, file.name), 'utf8'));
163
136
  }
164
137
  else if (stack.includes(title)) {
165
138
  return `${prev}<span class="error">Template loop detected: [[${title}]]</span>`;
166
139
  }
167
- return implicitNewLine(expand(index_1.default.templates.get(title), config, true, target, now, accum, [...stack, title]).toString(), prev);
140
+ let template = index_1.default.templates.get(title);
141
+ if (!isTemplate) {
142
+ for (let j = 1; j < args.length; j++) {
143
+ template = template.replaceAll(`$${j}`, (0, string_1.removeComment)(args[j].toString()));
144
+ }
145
+ }
146
+ return implicitNewLine(expand(template, title, config, true, target, now, accum, [...stack, title]).toString(), prev);
168
147
  }
169
148
  else if (index_1.default.functionHooks.has(name)) {
170
149
  return context === false ? m : index_1.default.functionHooks.get(name)(target, context || undefined);
171
150
  }
172
- else if (expandedMagicWords.has(name)) {
173
- if (context === false) {
174
- return m;
175
- }
176
- switch (name) {
177
- case 'currentyear':
178
- return `${prev}${now.getUTCFullYear()}`;
179
- case 'currentmonth':
180
- return prev + String(now.getUTCMonth() + 1).padStart(2, '0');
181
- case 'currentmonth1':
182
- return `${prev}${now.getUTCMonth() + 1}`;
183
- case 'currentmonthname':
184
- case 'currentmonthnamegen':
185
- return prev + now.toLocaleString('default', { month: 'long', timeZone: 'UTC' });
186
- case 'currentmonthabbrev':
187
- return prev + now.toLocaleString('default', { month: 'short', timeZone: 'UTC' });
188
- case 'currentday':
189
- return `${prev}${now.getUTCDate()}`;
190
- case 'currentday2':
191
- return prev + String(now.getUTCDate()).padStart(2, '0');
192
- case 'currentdow':
193
- return `${prev}${now.getUTCDay()}`;
194
- case 'currentdayname':
195
- return prev + now.toLocaleString('default', { weekday: 'long', timeZone: 'UTC' });
196
- case 'currenttime':
197
- return `${prev}${String(now.getUTCHours()).padStart(2, '0')}:${String(now.getUTCMinutes()).padStart(2, '0')}`;
198
- case 'currenthour':
199
- return prev + String(now.getUTCHours()).padStart(2, '0');
200
- case 'currentweek': {
201
- const firstDay = new Date(Date.UTC(now.getUTCFullYear(), 0, 1));
202
- return `${prev}${Math.ceil((now.getTime() - firstDay.getTime()) / 1e3 / 60 / 60 / 24 / 7)}`;
203
- }
204
- case 'currenttimestamp':
205
- return prev + now.toISOString().slice(0, 19)
206
- .replace(/[-:T]/gu, '');
207
- case 'localyear':
208
- return `${prev}${now.getFullYear()}`;
209
- case 'localmonth':
210
- return prev + String(now.getMonth() + 1).padStart(2, '0');
211
- case 'localmonth1':
212
- return `${prev}${now.getMonth() + 1}`;
213
- case 'localmonthname':
214
- case 'localmonthnamegen':
215
- return prev + now.toLocaleString('default', { month: 'long' });
216
- case 'localmonthabbrev':
217
- return prev + now.toLocaleString('default', { month: 'short' });
218
- case 'localday':
219
- return `${prev}${now.getDate()}`;
220
- case 'localday2':
221
- return prev + String(now.getDate()).padStart(2, '0');
222
- case 'localdow':
223
- return `${prev}${now.getDay()}`;
224
- case 'localdayname':
225
- return prev + now.toLocaleString('default', { weekday: 'long' });
226
- case 'localtime':
227
- return `${prev}${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}`;
228
- case 'localhour':
229
- return prev + String(now.getHours()).padStart(2, '0');
230
- case 'localweek': {
231
- const firstDay = new Date(now.getFullYear(), 0, 1);
232
- return `${prev}${Math.ceil((now.getTime() - firstDay.getTime()) / 1e3 / 60 / 60 / 24 / 7)}`;
233
- }
234
- case 'localtimestamp':
235
- return prev
236
- + String(now.getFullYear())
237
- + String(now.getMonth() + 1).padStart(2, '0')
238
- + String(now.getDate()).padStart(2, '0')
239
- + String(now.getHours()).padStart(2, '0')
240
- + String(now.getMinutes()).padStart(2, '0')
241
- + String(now.getSeconds()).padStart(2, '0');
242
- // no default
243
- }
151
+ else if (magicWords_1.expandedMagicWords.has(name)) {
152
+ return context === false ? m : `${prev}${(0, magicWords_1.expandMagicWord)(name, now, config, args)}`;
244
153
  }
245
154
  else if (!solvedMagicWords.has(name)) {
246
155
  return m;
@@ -248,18 +157,17 @@ const expand = (wikitext, config, include, context, now = index_1.default.now ??
248
157
  else if (length < 3 || name === 'ifeq' && length === 3) {
249
158
  return prev;
250
159
  }
251
- const c = target.childNodes, var1 = (0, string_1.decodeHtml)(c[1].value), var2 = (0, string_1.decodeHtml)(c[2].value), known = !/\0\d+t\x7F/u.test(var1);
160
+ const var1 = (0, string_1.decodeHtml)(args[0].value), var2 = (0, string_1.decodeHtml)(args[1].value), known = !/\0\d+t\x7F/u.test(var1);
252
161
  if (known && (name === 'if' || name === 'ifexist')) {
253
162
  let bool = Boolean(var1);
254
163
  if (name === 'ifexist') {
255
- const { valid, interwiki } = index_1.default
256
- .normalizeTitle(var1, 0, include, config, { halfParsed: true, temporary: true });
164
+ const { valid, interwiki } = index_1.default.normalizeTitle(var1, 0, include, config, { halfParsed: true, temporary: true, page: '' });
257
165
  bool = valid && !interwiki;
258
166
  }
259
- return parseIf(accum, prev, c[bool ? 2 : 3]);
167
+ return parseIf(accum, prev, args[bool ? 1 : 2]);
260
168
  }
261
169
  else if (known && name === 'ifeq' && !/\0\d+t\x7F/u.test(var2)) {
262
- return parseIf(accum, prev, c[cmp(var1, var2) ? 3 : 4]);
170
+ return parseIf(accum, prev, args[cmp(var1, var2) ? 2 : 3]);
263
171
  }
264
172
  else if (known && name === 'switch') {
265
173
  let defaultVal = '', j = 2,
@@ -269,7 +177,7 @@ const expand = (wikitext, config, include, context, now = index_1.default.now ??
269
177
  */
270
178
  found = 0, transclusion = false, defaultParam;
271
179
  for (; j < length; j++) {
272
- const { anon, value, lastChild, name: option } = c[j];
180
+ const { anon, value, lastChild, name: option } = args[j - 1];
273
181
  transclusion = /\0\d+t\x7F/u.test(anon ? value : option);
274
182
  if (anon) {
275
183
  if (j === length - 1) { // 位于最后的匿名参数是默认值
@@ -317,19 +225,24 @@ const expand = (wikitext, config, include, context, now = index_1.default.now ??
317
225
  }
318
226
  return token;
319
227
  };
228
+ /**
229
+ * 展开指定节点的模板
230
+ * @param token 目标节点
231
+ * @param context 模板调用环境
232
+ */
233
+ const expandToken = (token, context) => expand(token.toString(), token.pageName, token.getAttribute('config'), token.getAttribute('include'), context);
320
234
  index_2.Token.prototype.expand = /** @implements */ function () {
321
- return debug_1.Shadow.run(() => expand(this.toString(), this.getAttribute('config'), this.getAttribute('include')).parse());
235
+ return debug_1.Shadow.run(() => expandToken(this).parse());
322
236
  };
323
237
  index_2.Token.prototype.solveConst = /** @implements */ function () {
324
- return debug_1.Shadow.run(() => expand(this.toString(), this.getAttribute('config'), this.getAttribute('include'), false).parse());
238
+ return debug_1.Shadow.run(() => expandToken(this, false).parse());
325
239
  };
326
240
  index_2.Token.prototype.toHtml = /** @implements */ function () {
327
241
  const { viewOnly } = index_1.default;
328
242
  let html;
329
243
  if (this.type === 'root') {
330
244
  index_1.default.viewOnly = true;
331
- const expanded = debug_1.Shadow.run(() => expand(this.toString(), this.getAttribute('config'), this.getAttribute('include'))
332
- .parse(undefined, false, true));
245
+ const expanded = debug_1.Shadow.run(() => expandToken(this).parse(undefined, false, true));
333
246
  index_1.default.viewOnly = false;
334
247
  constants_1.states.set(expanded, { headings: new Set() });
335
248
  const lines = expanded.toHtmlInternal().split('\n');
@@ -406,10 +319,8 @@ index_2.Token.prototype.toHtml = /** @implements */ function () {
406
319
  return html;
407
320
  };
408
321
  index_2.Token.prototype.createComment = /** @implements */ function (data = '') {
409
- const config = this.getAttribute('config');
410
- return debug_1.Shadow.run(
411
322
  // @ts-expect-error abstract class
412
- () => new comment_1.CommentToken(data.replaceAll('-->', '--&gt;'), true, config));
323
+ return debug_1.Shadow.run(() => new comment_1.CommentToken(data.replaceAll('-->', '--&gt;'), true, this.getAttribute('config')));
413
324
  };
414
325
  index_2.Token.prototype.createElement = /** @implements */ function (tagName, { selfClosing, closing } = {}) {
415
326
  const config = this.getAttribute('config'), include = this.getAttribute('include');
@@ -15,9 +15,9 @@ const atom_1 = require("../src/atom");
15
15
  transclude_1.TranscludeToken.prototype.newAnonArg =
16
16
  /** @implements */
17
17
  function (val) {
18
- const config = this.getAttribute('config'), { childNodes } = index_1.default.parse(val, this.getAttribute('include'), undefined, config),
18
+ const { childNodes } = index_1.default.parseWithRef(val, this), token = debug_1.Shadow.run(
19
19
  // @ts-expect-error abstract class
20
- token = debug_1.Shadow.run(() => new parameter_1.ParameterToken(undefined, undefined, config));
20
+ () => new parameter_1.ParameterToken(undefined, undefined, this.getAttribute('config')));
21
21
  token.lastChild.concat(childNodes); // eslint-disable-line unicorn/prefer-spread
22
22
  return this.insertAt(token);
23
23
  };
@@ -33,9 +33,9 @@ transclude_1.TranscludeToken.prototype.setValue =
33
33
  arg.setValue(value);
34
34
  return;
35
35
  }
36
- const include = this.getAttribute('include'), config = this.getAttribute('config'), k = index_1.default.parse(key, include, undefined, config), v = index_1.default.parse(value, include, undefined, config),
36
+ const k = index_1.default.parseWithRef(key, this), v = index_1.default.parseWithRef(value, this), token = debug_1.Shadow.run(
37
37
  // @ts-expect-error abstract class
38
- token = debug_1.Shadow.run(() => new parameter_1.ParameterToken(undefined, undefined, config));
38
+ () => new parameter_1.ParameterToken(undefined, undefined, this.getAttribute('config')));
39
39
  token.firstChild.safeAppend(k.childNodes);
40
40
  token.lastChild.concat(v.childNodes); // eslint-disable-line unicorn/prefer-spread
41
41
  this.insertAt(token);
@@ -43,50 +43,46 @@ transclude_1.TranscludeToken.prototype.setValue =
43
43
  transclude_1.TranscludeToken.prototype.replaceTemplate =
44
44
  /** @implements */
45
45
  function (title) {
46
+ const { type, firstChild } = this;
46
47
  /* istanbul ignore if */
47
- if (this.type === 'magic-word') {
48
+ if (type === 'magic-word') {
48
49
  throw new Error('TranscludeToken.replaceTemplate method is only for templates!');
49
50
  }
50
- const { childNodes } = index_1.default
51
- .parse(title, this.getAttribute('include'), 2, this.getAttribute('config'));
52
- this.firstChild.safeReplaceChildren(childNodes);
51
+ const { childNodes } = index_1.default.parseWithRef(title, this, 2);
52
+ firstChild.safeReplaceChildren(childNodes);
53
53
  };
54
54
  transclude_1.TranscludeToken.prototype.replaceModule =
55
55
  /** @implements */
56
56
  function (title) {
57
+ const { type, name, length, childNodes: [, mod] } = this;
57
58
  /* istanbul ignore if */
58
- if (this.type !== 'magic-word' || this.name !== 'invoke') {
59
+ if (type !== 'magic-word' || name !== 'invoke') {
59
60
  throw new Error('TranscludeToken.replaceModule method is only for modules!');
60
61
  }
61
- const config = this.getAttribute('config');
62
- if (this.length === 1) {
63
- index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-module', config, [], {
64
- 'Stage-1': ':', '!ExtToken': '',
65
- })));
62
+ else if (length === 1) {
63
+ index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-module', this.getAttribute('config'), [], { 'Stage-1': ':', '!ExtToken': '' })));
66
64
  return;
67
65
  }
68
- const { childNodes } = index_1.default.parse(title, this.getAttribute('include'), 2, config);
69
- this.childNodes[1].safeReplaceChildren(childNodes);
66
+ const { childNodes } = index_1.default.parseWithRef(title, this, 2);
67
+ mod.safeReplaceChildren(childNodes);
70
68
  };
71
69
  transclude_1.TranscludeToken.prototype.replaceFunction =
72
70
  /** @implements */
73
71
  function (func) {
72
+ const { type, name, length, childNodes: [, , fun] } = this;
74
73
  /* istanbul ignore next */
75
- if (this.type !== 'magic-word' || this.name !== 'invoke') {
74
+ if (type !== 'magic-word' || name !== 'invoke') {
76
75
  throw new Error('TranscludeToken.replaceModule method is only for modules!');
77
76
  }
78
- else if (this.length < 2) {
77
+ else if (length < 2) {
79
78
  throw new Error('No module name specified!');
80
79
  }
81
- const config = this.getAttribute('config');
82
- if (this.length === 2) {
83
- index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-function', config, [], {
84
- 'Stage-1': ':', '!ExtToken': '',
85
- })));
80
+ else if (length === 2) {
81
+ index_2.Token.prototype.insertAt.call(this, debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'invoke-function', this.getAttribute('config'), [], { 'Stage-1': ':', '!ExtToken': '' })));
86
82
  return;
87
83
  }
88
- const { childNodes } = index_1.default.parse(func, this.getAttribute('include'), 2, config);
89
- this.childNodes[2].safeReplaceChildren(childNodes);
84
+ const { childNodes } = index_1.default.parseWithRef(func, this, 2);
85
+ fun.safeReplaceChildren(childNodes);
90
86
  };
91
87
  transclude_1.TranscludeToken.prototype.fixDuplication =
92
88
  /** @implements */
@@ -157,8 +153,7 @@ transclude_1.TranscludeToken.prototype.fixDuplication =
157
153
  if (remaining > 1) {
158
154
  index_1.default.error(`${this.type === 'template'
159
155
  ? this.name
160
- : this.normalizeTitle(this.childNodes[1].text(), 828, { temporary: true })
161
- .title} still has ${remaining} duplicated ${key} parameters:\n${[...this.getArgs(key)].map(arg => {
156
+ : this.normalizeTitle(`Module:${this.childNodes[1].text()}`, 828, { temporary: true, page: '' }).title} still has ${remaining} duplicated ${key} parameters:\n${[...this.getArgs(key)].map(arg => {
162
157
  const { top, left } = arg.getBoundingClientRect();
163
158
  return `Line ${String(top)} Column ${String(left)}`;
164
159
  }).join('\n')}`);
@@ -173,14 +168,13 @@ transclude_1.TranscludeToken.prototype.escapeTables =
173
168
  if (!/\n[^\S\n]*(?::+[^\S\n]*)?\{\|/u.test(this.text())) {
174
169
  return this;
175
170
  }
176
- const stripped = this.toString().slice(2, -2), include = this.getAttribute('include'), config = this.getAttribute('config'), parsed = index_1.default.parse(stripped, include, 4, config);
171
+ const stripped = this.toString().slice(2, -2), parsed = index_1.default.parseWithRef(stripped, this, 4);
177
172
  for (const table of parsed.childNodes) {
178
173
  if (table.is('table')) {
179
174
  table.escape();
180
175
  }
181
176
  }
182
- const { firstChild, length } = index_1.default
183
- .parse(`{{${parsed.toString()}}}`, include, undefined, config);
177
+ const { firstChild, length } = index_1.default.parseWithRef(`{{${parsed.toString()}}}`, this);
184
178
  /* istanbul ignore if */
185
179
  if (length !== 1 || !(firstChild instanceof transclude_1.TranscludeToken)) {
186
180
  throw new Error('Failed to escape tables!');
package/dist/base.d.mts CHANGED
@@ -47,7 +47,7 @@ export declare const stages: {
47
47
  'list-range': number;
48
48
  };
49
49
  export type Stage = keyof typeof stages;
50
- export declare const rules: readonly ["bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css"];
50
+ export declare const rules: readonly ["bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css", "invalid-math"];
51
51
  export declare namespace LintError {
52
52
  type Severity = 'error' | 'warning';
53
53
  type Rule = typeof rules[number];
@@ -332,8 +332,10 @@ export interface Parser {
332
332
  * 解析wikitext
333
333
  * @param include whether to be transcluded / 是否嵌入
334
334
  * @param maxStage max stage for parsing / 最大解析层级
335
+ * @param page page name / 页面名称
335
336
  */
336
- parse(wikitext: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config): Token;
337
+ parse(wikitext: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config, page?: string): Token;
338
+ parse(wikitext: string, page: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config): Token;
337
339
  /**
338
340
  * Create a language server
339
341
  *
package/dist/base.d.ts CHANGED
@@ -47,7 +47,7 @@ export declare const stages: {
47
47
  'list-range': number;
48
48
  };
49
49
  export type Stage = keyof typeof stages;
50
- export declare const rules: readonly ["bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css"];
50
+ export declare const rules: readonly ["bold-header", "format-leakage", "fostered-content", "h1", "illegal-attr", "insecure-style", "invalid-gallery", "invalid-imagemap", "invalid-invoke", "invalid-isbn", "invalid-url", "lonely-apos", "lonely-bracket", "lonely-http", "nested-link", "no-arg", "no-duplicate", "no-ignored", "obsolete-attr", "obsolete-tag", "parsing-order", "pipe-like", "table-layout", "tag-like", "unbalanced-header", "unclosed-comment", "unclosed-quote", "unclosed-table", "unescaped", "unknown-page", "unmatched-tag", "unterminated-url", "url-encoding", "var-anchor", "void-ext", "invalid-css", "invalid-math"];
51
51
  export declare namespace LintError {
52
52
  type Severity = 'error' | 'warning';
53
53
  type Rule = typeof rules[number];
@@ -332,8 +332,10 @@ export interface Parser {
332
332
  * 解析wikitext
333
333
  * @param include whether to be transcluded / 是否嵌入
334
334
  * @param maxStage max stage for parsing / 最大解析层级
335
+ * @param page page name / 页面名称
335
336
  */
336
- parse(wikitext: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config): Token;
337
+ parse(wikitext: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config, page?: string): Token;
338
+ parse(wikitext: string, page: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config): Token;
337
339
  /**
338
340
  * Create a language server
339
341
  *
package/dist/base.js CHANGED
@@ -71,6 +71,7 @@ exports.rules = (() => {
71
71
  'void-ext',
72
72
  /* NOT FOR BROWSER ONLY */
73
73
  'invalid-css',
74
+ 'invalid-math',
74
75
  ];
75
76
  Object.freeze(arr);
76
77
  return arr;
package/dist/base.mjs CHANGED
@@ -67,7 +67,8 @@ const rules = /* @__PURE__ */ (() => {
67
67
  "var-anchor",
68
68
  "void-ext",
69
69
  /* NOT FOR BROWSER ONLY */
70
- "invalid-css"
70
+ "invalid-css",
71
+ "invalid-math"
71
72
  ];
72
73
  Object.freeze(arr);
73
74
  return arr;
@@ -77,7 +77,7 @@ const mw = {
77
77
  },
78
78
  },
79
79
  };
80
- const pkg = "wikiparser-node", version = "1.28.1";
80
+ const pkg = "wikiparser-node", version = "1.29.0";
81
81
  let mwConfig;
82
82
  /**
83
83
  * Get the parser configuration for a Wikimedia Foundation project.
package/dist/index.d.ts CHANGED
@@ -35,7 +35,8 @@ declare interface Parser extends ParserBase {
35
35
  * @param include whether to be transcluded / 是否嵌入
36
36
  */
37
37
  normalizeTitle(title: string, defaultNs?: number, include?: boolean, config?: Config): Title;
38
- parse(wikitext: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config): Token;
38
+ parse(wikitext: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config, page?: string): Token;
39
+ parse(wikitext: string, page: string, include?: boolean, maxStage?: number | Stage | Stage[], config?: Config): Token;
39
40
  /**
40
41
  * Create a language server
41
42
  *
package/dist/index.js CHANGED
@@ -167,6 +167,7 @@ const Parser = {
167
167
  titleObj = debug_1.Shadow.run(() => {
168
168
  const root = new Token(title, config);
169
169
  root.type = 'root';
170
+ root.pageName = opt?.page;
170
171
  root.parseOnce(0, include).parseOnce();
171
172
  const t = new Title(root.toString(), defaultNs, config, opt);
172
173
  root.build();
@@ -192,8 +193,23 @@ const Parser = {
192
193
  return titleObj;
193
194
  },
194
195
  /** @implements */
195
- parse(wikitext, include, maxStage = constants_1.MAX_STAGE, config = Parser.getConfig()) {
196
+ parse(wikitext, includeOrPage, maxStageOrInclude, configOrStage, pageOrConfig) {
196
197
  wikitext = (0, string_1.tidy)(wikitext);
198
+ let include, maxStage, config, page;
199
+ if (typeof includeOrPage === 'string') {
200
+ include = Boolean(maxStageOrInclude);
201
+ maxStage = configOrStage;
202
+ config = pageOrConfig;
203
+ page = includeOrPage;
204
+ }
205
+ else {
206
+ include = Boolean(includeOrPage);
207
+ maxStage = maxStageOrInclude;
208
+ config = configOrStage;
209
+ page = pageOrConfig;
210
+ }
211
+ maxStage ??= constants_1.MAX_STAGE;
212
+ config ??= this.getConfig();
197
213
  let types;
198
214
  LINT: { // eslint-disable-line no-unused-labels
199
215
  if (typeof maxStage !== 'number') {
@@ -205,6 +221,7 @@ const Parser = {
205
221
  const root = debug_1.Shadow.run(() => {
206
222
  const token = new Token(wikitext, config);
207
223
  token.type = 'root';
224
+ token.pageName = page;
208
225
  try {
209
226
  return token.parse(maxStage, include);
210
227
  /* NOT FOR BROWSER ONLY */
@@ -219,7 +236,7 @@ const Parser = {
219
236
  }
220
237
  fs_1.default.writeFileSync(file, stage === constants_1.MAX_STAGE ? wikitext : token.toString());
221
238
  fs_1.default.writeFileSync(`${file}.err`, e.stack);
222
- fs_1.default.writeFileSync(`${file}.json`, JSON.stringify({ stage, include, config }, null, '\t'));
239
+ fs_1.default.writeFileSync(`${file}.json`, JSON.stringify({ stage, include, config, page }, null, '\t'));
223
240
  }
224
241
  throw e;
225
242
  }
@@ -238,8 +255,8 @@ const Parser = {
238
255
  proc = 'printing';
239
256
  }
240
257
  if (restored !== wikitext) {
241
- const { 0: cur, length } = promises;
242
- promises.unshift((async () => {
258
+ const { length } = promises, cur = promises[length - 1];
259
+ promises.push((async () => {
243
260
  await cur;
244
261
  this.error(`Original wikitext is altered when ${proc}!`);
245
262
  return (0, diff_1.diff)(wikitext, restored, length);
@@ -250,6 +267,10 @@ const Parser = {
250
267
  return root;
251
268
  },
252
269
  /** @implements */
270
+ parseWithRef(wikitext, ref, maxStage, include = ref.getAttribute('include')) {
271
+ return this.parse(wikitext, include, maxStage, ref.getAttribute('config'), ref.pageName);
272
+ },
273
+ /** @implements */
253
274
  async partialParse(wikitext, watch, include, config = Parser.getConfig()) {
254
275
  LSP: { // eslint-disable-line no-unused-labels
255
276
  const { Token } = require('./src/index');
@@ -399,10 +420,11 @@ const Parser = {
399
420
  throw new RangeError(`找不到对应时间戳的错误记录:${date}`);
400
421
  }
401
422
  const file = path_1.default.join(__dirname, '..', 'errors', main), wikitext = fs_1.default.readFileSync(file, 'utf8');
402
- const { stage, include, config } = require(`${file}.json`), { Token } = require('./src/index');
423
+ const { stage, include, config, page } = require(`${file}.json`), { Token } = require('./src/index');
403
424
  debug_1.Shadow.run(() => {
404
425
  const halfParsed = stage < constants_1.MAX_STAGE, token = new Token(halfParsed ? wikitext : (0, string_1.tidy)(wikitext), config);
405
426
  token.type = 'root';
427
+ token.pageName = page;
406
428
  if (halfParsed) {
407
429
  token.setAttribute('stage', stage);
408
430
  token.parseOnce(stage, include);
@@ -3,14 +3,30 @@ import type { TextDocument } from 'vscode-languageserver-textdocument';
3
3
  import type { JSONDocument } from 'vscode-json-languageservice';
4
4
  import type { Stylesheet } from 'vscode-css-languageservice';
5
5
  import type { Token } from '../internal';
6
- declare interface Jax {
7
- tex2mml(tex: string): string;
6
+ export interface TexvcLocation {
7
+ offset: number;
8
+ line: number;
9
+ column: number;
8
10
  }
9
- /**
10
- * Load MathJax
11
- * @param id MathJax module ID
12
- */
13
- export declare const loadMathJax: (id?: string) => Promise<Jax> | undefined;
11
+ declare interface Texvcjs {
12
+ check(input: string, options?: {
13
+ usemhchem?: boolean;
14
+ }): {
15
+ status: '+';
16
+ } | {
17
+ status: 'C';
18
+ } | {
19
+ status: 'F' | 'S';
20
+ error: {
21
+ message: string;
22
+ location: {
23
+ start: TexvcLocation;
24
+ end: TexvcLocation;
25
+ };
26
+ };
27
+ };
28
+ }
29
+ export declare const texvcjs: Texvcjs | undefined;
14
30
  export declare const jsonTags: string[];
15
31
  export declare const jsonLSP: import("vscode-json-languageservice").LanguageService | undefined;
16
32
  export declare const cssLSP: import("vscode-css-languageservice").LanguageService | undefined;