wikiparser-node 1.40.0 → 1.42.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 (66) hide show
  1. package/README.md +55 -7
  2. package/bundle/bundle-es8.min.js +27 -27
  3. package/bundle/bundle-lsp.min.js +29 -29
  4. package/bundle/bundle.min.js +19 -19
  5. package/config/.schema.json +5 -0
  6. package/config/default.json +1 -1
  7. package/config/enwiki.json +3 -2
  8. package/config/jawiki.json +6 -5
  9. package/config/llwiki.json +2 -1
  10. package/config/minimum.json +1 -1
  11. package/config/moegirl.json +2 -1
  12. package/config/zhwiki.json +3 -2
  13. package/dist/addon/attribute.js +1 -1
  14. package/dist/addon/transclude.js +1 -3
  15. package/dist/base.d.mts +5 -3
  16. package/dist/base.d.ts +5 -3
  17. package/dist/bin/config.js +11 -10
  18. package/dist/index.js +1 -2
  19. package/dist/lib/element.d.ts +3 -8
  20. package/dist/lib/element.js +2 -26
  21. package/dist/lib/lintConfig.js +30 -23
  22. package/dist/lib/lsp.d.ts +2 -0
  23. package/dist/lib/lsp.js +8 -20
  24. package/dist/lib/node.d.ts +2 -0
  25. package/dist/lib/node.js +0 -7
  26. package/dist/lib/range.d.ts +0 -7
  27. package/dist/lib/range.js +5 -14
  28. package/dist/lib/text.js +4 -6
  29. package/dist/map.d.ts +66 -0
  30. package/dist/map.js +2 -0
  31. package/dist/mixin/attributesParent.d.ts +4 -3
  32. package/dist/mixin/elementLike.d.ts +13 -0
  33. package/dist/mixin/elementLike.js +66 -53
  34. package/dist/parser/selector.js +3 -3
  35. package/dist/render/extension.js +139 -8
  36. package/dist/render/html.js +72 -3
  37. package/dist/render/magicWords.js +6 -3
  38. package/dist/src/attribute.d.ts +2 -2
  39. package/dist/src/attribute.js +18 -14
  40. package/dist/src/attributes.d.ts +3 -3
  41. package/dist/src/attributes.js +35 -19
  42. package/dist/src/extLink.js +5 -4
  43. package/dist/src/heading.js +11 -3
  44. package/dist/src/index.js +3 -4
  45. package/dist/src/link/base.js +2 -4
  46. package/dist/src/link/file.js +5 -5
  47. package/dist/src/link/galleryImage.js +1 -3
  48. package/dist/src/magicLink.js +6 -5
  49. package/dist/src/multiLine/gallery.js +2 -3
  50. package/dist/src/nowiki/doubleUnderscore.d.ts +1 -0
  51. package/dist/src/nowiki/doubleUnderscore.js +4 -1
  52. package/dist/src/nowiki/quote.js +1 -3
  53. package/dist/src/parameter.js +5 -2
  54. package/dist/src/table/td.d.ts +2 -2
  55. package/dist/src/table/td.js +1 -1
  56. package/dist/src/tag/html.js +29 -12
  57. package/dist/src/tagPair/ext.js +4 -1
  58. package/dist/src/tagPair/translate.d.ts +1 -1
  59. package/dist/src/tagPair/translate.js +1 -1
  60. package/dist/util/debug.js +5 -7
  61. package/dist/util/html.js +3 -11
  62. package/dist/util/sharable.js +2 -0
  63. package/dist/util/sharable.mjs +3 -1
  64. package/extensions/dist/base.js +1 -1
  65. package/extensions/dist/env.js +34 -0
  66. package/package.json +19 -20
@@ -150,7 +150,7 @@ function urlFunction(config, args, local) {
150
150
  title.ns = 6;
151
151
  title.fragment = undefined;
152
152
  }
153
- const link = title.getUrl(config.testArticlePath), protocol = link.startsWith('//') ? 'https:' : '';
153
+ const { articlePath, server = '' } = config, path = articlePath && (/^\/(?!\/)/u.test(articlePath) ? server : '') + articlePath, link = title.getUrl(path), protocol = link.startsWith('//') ? 'https:' : '';
154
154
  try {
155
155
  const url = new URL(protocol + link);
156
156
  url.search = query ? `?${query.replaceAll(/\s/gu, '_')}` : '';
@@ -159,12 +159,15 @@ function urlFunction(config, args, local) {
159
159
  catch (e) {
160
160
  if (local) {
161
161
  title.fragment = undefined;
162
- return title.getUrl(config.testArticlePath) + (query ? `?${query}` : '');
162
+ return title.getUrl(path) + (query ? `?${query}` : '');
163
163
  }
164
164
  throw e;
165
165
  }
166
166
  }
167
- const parseUrl = ({ testServer = '', articlePath = testServer }) => {
167
+ const parseUrl = ({ server = '', articlePath = '' }) => {
168
+ if (/^\/(?!\/)/u.test(articlePath)) {
169
+ articlePath = server + articlePath;
170
+ }
168
171
  let offset = 0;
169
172
  if (articlePath.startsWith('//')) {
170
173
  offset = 6;
@@ -39,7 +39,7 @@ export declare abstract class AttributeToken extends Token {
39
39
  get balanced(): boolean;
40
40
  set balanced(value: boolean);
41
41
  /** attribute value / 属性值 */
42
- get value(): string | true;
42
+ get value(): string;
43
43
  set value(value: string | true);
44
44
  /**
45
45
  * @param type 标签类型
@@ -55,7 +55,7 @@ export declare abstract class AttributeToken extends Token {
55
55
  *
56
56
  * 获取属性值
57
57
  */
58
- getValue(): string | true;
58
+ getValue(): string;
59
59
  cloneNode(): this;
60
60
  /**
61
61
  * Close the quote
@@ -231,7 +231,7 @@ let AttributeToken = (() => {
231
231
  && !parentNode?.hasAttr('itemscope')) {
232
232
  /* PRINT ONLY */
233
233
  if (start === undefined) {
234
- return true;
234
+ return 2;
235
235
  }
236
236
  /* PRINT ONLY END */
237
237
  LINT: {
@@ -245,10 +245,10 @@ let AttributeToken = (() => {
245
245
  }
246
246
  }
247
247
  }
248
- else if (name === 'style' && typeof value === 'string' && insecureStyle.test(value)) {
248
+ else if (name === 'style' && insecureStyle.test(value)) {
249
249
  /* PRINT ONLY */
250
250
  if (start === undefined) {
251
- return true;
251
+ return 1;
252
252
  }
253
253
  /* PRINT ONLY END */
254
254
  LINT: {
@@ -257,10 +257,10 @@ let AttributeToken = (() => {
257
257
  return s && (0, lint_1.generateForChild)(lastChild, rect, rule, 'insecure-style', s);
258
258
  }
259
259
  }
260
- else if (name === 'tabindex' && typeof value === 'string' && value !== '0') {
260
+ else if (name === 'tabindex' && value !== '0') {
261
261
  /* PRINT ONLY */
262
262
  if (start === undefined) {
263
- return true;
263
+ return 2;
264
264
  }
265
265
  /* PRINT ONLY END */
266
266
  LINT: {
@@ -277,14 +277,14 @@ let AttributeToken = (() => {
277
277
  }
278
278
  }
279
279
  }
280
- else if (typeof value === 'string' && ((/^xmlns:[\w:.-]+$/u.test(name) || urlAttrs.has(name)) && evil.test(value)
280
+ else if ((/^xmlns:[\w:.-]+$/u.test(name) || urlAttrs.has(name)) && evil.test(value)
281
281
  || simple
282
- && (name === 'href' || tag === 'img' && name === 'src')
282
+ && (name === 'href' || type === 'ext-attr' && tag === 'img' && name === 'src')
283
283
  && !new RegExp(String.raw `^(?:${this.getAttribute('config').protocol}|//)\S+$`, 'iu')
284
- .test(value))) {
284
+ .test(value)) {
285
285
  /* PRINT ONLY */
286
286
  if (start === undefined) {
287
- return true;
287
+ return 2;
288
288
  }
289
289
  /* PRINT ONLY END */
290
290
  LINT: {
@@ -293,11 +293,11 @@ let AttributeToken = (() => {
293
293
  }
294
294
  }
295
295
  else if (simple && type !== 'ext-attr') {
296
- const data = (0, lint_1.provideValues)(tag, name), v = String(value).toLowerCase();
296
+ const data = (0, lint_1.provideValues)(tag, name), v = value.toLowerCase();
297
297
  if (data.length > 0 && data.every(n => n !== v)) {
298
298
  /* PRINT ONLY */
299
299
  if (start === undefined) {
300
- return true;
300
+ return 2;
301
301
  }
302
302
  /* PRINT ONLY END */
303
303
  LINT: {
@@ -363,7 +363,7 @@ let AttributeToken = (() => {
363
363
  * 获取属性值
364
364
  */
365
365
  getValue() {
366
- return this.#equal ? this.lastChild.text().trim() : this.type === 'ext-attr' || '';
366
+ return this.#equal ? this.lastChild.text().replace(/[\t\r\n ]+/gu, ' ').trim() : '';
367
367
  }
368
368
  /** @private */
369
369
  escape() {
@@ -380,7 +380,7 @@ let AttributeToken = (() => {
380
380
  return this.#quotes;
381
381
  }
382
382
  /* NOT FOR BROWSER END */
383
- return key === 'invalid' ? this.#lint() : super.getAttribute(key);
383
+ return key === 'invalid' ? Boolean(this.#lint()) : super.getAttribute(key);
384
384
  }
385
385
  /** @private */
386
386
  print() {
@@ -464,9 +464,13 @@ let AttributeToken = (() => {
464
464
  /** @private */
465
465
  toHtmlInternal() {
466
466
  const { type, name, tag, lastChild } = this;
467
- if (type === 'ext-attr' && sharable_1.extAttrs[tag]?.has(name) || this.#lint()) {
467
+ if (type === 'ext-attr' && sharable_1.extAttrs[tag]?.has(name)) {
468
468
  return '';
469
469
  }
470
+ const linted = this.#lint();
471
+ if (linted) {
472
+ return linted === 1 ? 'style="/* insecure input */"' : '';
473
+ }
470
474
  const value = lastChild.toHtmlInternal().trim();
471
475
  if (name === 'id' && !value) {
472
476
  return '';
@@ -32,7 +32,7 @@ export declare abstract class AttributesToken extends Token {
32
32
  abstract get previousElementSibling(): SyntaxToken | undefined;
33
33
  get type(): AttributesTypes;
34
34
  /** all attributes / 全部属性 */
35
- get attributes(): Record<string, string | true>;
35
+ get attributes(): Record<string, string>;
36
36
  set attributes(attrs: Record<string, string | true>);
37
37
  /** class attribute in string / 以字符串表示的class属性 */
38
38
  get className(): string;
@@ -78,7 +78,7 @@ export declare abstract class AttributesToken extends Token {
78
78
  * 获取指定属性
79
79
  * @param key attribute name / 属性键
80
80
  */
81
- getAttr(key: string): string | true | undefined;
81
+ getAttr(key: string): string | undefined;
82
82
  /**
83
83
  * Sanitize invalid attributes
84
84
  *
@@ -115,7 +115,7 @@ export declare abstract class AttributesToken extends Token {
115
115
  *
116
116
  * 获取全部属性
117
117
  */
118
- getAttrs(): Record<string, string | true>;
118
+ getAttrs(): Record<string, string>;
119
119
  /**
120
120
  * Remove an attribute
121
121
  *
@@ -82,6 +82,17 @@ const required = new Map([
82
82
  ['section', [['begin', 'end']]],
83
83
  ['templatestyles', ['src']],
84
84
  ]);
85
+ /* NOT FOR BROWSER */
86
+ /**
87
+ * 处理不显示的`<ref>`
88
+ * @param token 不显示的节点
89
+ */
90
+ const renderRefs = (token) => {
91
+ for (const ref of token.querySelectorAll('ext#ref')) {
92
+ ref.toHtmlInternal();
93
+ }
94
+ };
95
+ /* NOT FOR BROWSER END */
85
96
  /**
86
97
  * attributes of extension and HTML tags
87
98
  *
@@ -120,8 +131,7 @@ let AttributesToken = (() => {
120
131
  }
121
132
  /** class attribute in string / 以字符串表示的class属性 */
122
133
  get className() {
123
- const attr = this.getAttr('class');
124
- return typeof attr === 'string' ? attr : '';
134
+ return this.getAttr('class') || '';
125
135
  }
126
136
  set className(className) {
127
137
  this.setAttr('class', className || false);
@@ -151,8 +161,7 @@ let AttributesToken = (() => {
151
161
  }
152
162
  /** id attribute / id属性 */
153
163
  get id() {
154
- const attr = this.getAttr('id');
155
- return typeof attr === 'string' ? attr : '';
164
+ return this.getAttr('id') || '';
156
165
  }
157
166
  set id(id) {
158
167
  this.setAttr('id', id || false);
@@ -263,7 +272,7 @@ let AttributesToken = (() => {
263
272
  /** @private */
264
273
  lint(start = this.getAbsoluteIndex(), re) {
265
274
  LINT: {
266
- const errors = super.lint(start, re), { parentNode, childNodes, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'no-duplicate', 'required-attr'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
275
+ const errors = super.lint(start, re), { parentNode, childNodes, type, name: tag } = this, attrs = new Map(), duplicated = new Set(), rect = new rect_1.BoundingRect(this, start), rules = ['no-ignored', 'required-attr', 'no-duplicate'], { lintConfig } = index_1.default, { computeEditInfo, fix } = lintConfig, s = ['closingTag', 'invalidAttributes', 'nonWordAttributes']
267
276
  .map(k => lintConfig.getSeverity(rules[0], k));
268
277
  if (s[0] && this.#lint()) {
269
278
  const e = (0, lint_1.generateForSelf)(this, rect, rules[0], 'attributes-of-closing-tag', s[0]);
@@ -299,28 +308,22 @@ let AttributesToken = (() => {
299
308
  }
300
309
  }
301
310
  if (type === 'ext-attrs' && required.has(tag)) {
302
- const severity = lintConfig.getSeverity(rules[2], tag);
311
+ const severity = lintConfig.getSeverity(rules[1], tag);
303
312
  if (severity) {
304
313
  for (const key of required.get(tag)) {
305
- const keys = typeof key === 'string' ? [key] : key, missing = keys.every(k => {
306
- const value = this.getAttr(k);
307
- return value === true || !value;
308
- });
309
- if (missing) {
310
- errors.push((0, lint_1.generateForSelf)(this, rect, rules[2], index_1.default.msg('required-attribute', keys.join('/')), severity));
314
+ const keys = typeof key === 'string' ? [key] : key;
315
+ if (!keys.some(k => this.getAttr(k))) {
316
+ errors.push((0, lint_1.generateForSelf)(this, rect, rules[1], index_1.default.msg('required-attribute', keys.join('/')), severity));
311
317
  }
312
318
  }
313
319
  }
314
320
  }
315
- const severity = lintConfig.getSeverity(rules[1], 'attribute');
321
+ const severity = lintConfig.getSeverity(rules[2], 'attribute');
316
322
  if (severity && duplicated.size > 0) {
317
323
  for (const key of duplicated) {
318
- const pairs = attrs.get(key).map(attr => {
319
- const value = attr.getValue();
320
- return [attr, value === true ? '' : value];
321
- });
324
+ const pairs = attrs.get(key).map(attr => [attr, attr.getValue()]);
322
325
  Array.prototype.push.apply(errors, pairs.map(([attr, value], i) => {
323
- const e = (0, lint_1.generateForChild)(attr, rect, rules[1], index_1.default.msg('duplicate-attribute', key), severity);
326
+ const e = (0, lint_1.generateForChild)(attr, rect, rules[2], index_1.default.msg('duplicate-attribute', key), severity);
324
327
  if (computeEditInfo || fix) {
325
328
  const remove = (0, lint_1.fixByRemove)(e);
326
329
  if (!value || pairs.slice(0, i).some(([, v]) => v === value)) {
@@ -488,7 +491,20 @@ let AttributesToken = (() => {
488
491
  }
489
492
  /** @private */
490
493
  toHtmlInternal() {
491
- const map = new Map(this.childNodes.filter(child => child instanceof attribute_1.AttributeToken).map(child => [child.name, child])), output = map.size === 0 ? '' : (0, html_1.html)([...map.values()], ' ', { removeBlank: true });
494
+ const map = new Map();
495
+ for (const child of this.childNodes) {
496
+ if (child instanceof attribute_1.AttributeToken) {
497
+ const last = map.get(child.name);
498
+ if (last) {
499
+ renderRefs(last);
500
+ }
501
+ map.set(child.name, child);
502
+ }
503
+ else {
504
+ renderRefs(child);
505
+ }
506
+ }
507
+ const output = map.size === 0 ? '' : (0, html_1.html)([...map.values()], ' ', { removeBlank: true });
492
508
  return output && ` ${output}`;
493
509
  }
494
510
  /* c8 ignore start */
@@ -217,26 +217,27 @@ let ExtLinkToken = (() => {
217
217
  /** @private */
218
218
  toHtmlInternal(opt) {
219
219
  const { length, lastChild } = this;
220
- let innerText, href;
220
+ let innerText, linkType, href;
221
221
  if (length > 1) {
222
222
  lastChild.normalize();
223
223
  const { childNodes } = lastChild, i = childNodes.findIndex(child => child.is('link')
224
- || child.is('file')
225
- && child.getValue('link')?.trim() !== '');
224
+ || child.is('file') && child.getValue('link')?.trim() !== '');
226
225
  if (i !== -1) {
227
226
  const after = childNodes.slice(i);
228
227
  this.insertAdjacent(after, 1);
229
228
  }
230
229
  innerText = lastChild.toHtmlInternal(opt);
230
+ linkType = 'text';
231
231
  }
232
232
  else {
233
233
  ({ innerText } = this);
234
+ linkType = 'autonumber';
234
235
  }
235
236
  try {
236
237
  ({ href } = this.getUrl());
237
238
  }
238
239
  catch { }
239
- return `<a rel="nofollow" class="external"${href === undefined ? '' : ` href="${href}"`}>${innerText}</a>`;
240
+ return `<a rel="nofollow" class="external ${linkType}"${href === undefined ? '' : ` href="${href}"`}>${innerText}</a>`;
240
241
  }
241
242
  /**
242
243
  * Get the URL
@@ -67,12 +67,15 @@ let HeadingToken = (() => {
67
67
  let _classThis;
68
68
  let _classSuper = index_2.Token;
69
69
  let _instanceExtraInitializers = [];
70
+ let _getRenderedId_decorators;
70
71
  let _toHtmlInternal_decorators;
71
72
  var HeadingToken = class extends _classSuper {
72
73
  static { _classThis = this; }
73
74
  static {
74
75
  const _metadata = typeof Symbol === "function" && Symbol.metadata ? Object.create(_classSuper[Symbol.metadata] ?? null) : void 0;
76
+ _getRenderedId_decorators = [(0, cached_1.cached)()];
75
77
  _toHtmlInternal_decorators = [(0, cached_1.cached)()];
78
+ __esDecorate(this, null, _getRenderedId_decorators, { kind: "method", name: "getRenderedId", static: false, private: false, access: { has: obj => "getRenderedId" in obj, get: obj => obj.getRenderedId }, metadata: _metadata }, null, _instanceExtraInitializers);
76
79
  __esDecorate(this, null, _toHtmlInternal_decorators, { kind: "method", name: "toHtmlInternal", static: false, private: false, access: { has: obj => "toHtmlInternal" in obj, get: obj => obj.toHtmlInternal }, metadata: _metadata }, null, _instanceExtraInitializers);
77
80
  __esDecorate(null, _classDescriptor = { value: _classThis }, _classDecorators, { kind: "class", name: _classThis.name, metadata: _metadata }, null, _classExtraInitializers);
78
81
  HeadingToken = _classThis = _classDescriptor.value;
@@ -296,9 +299,9 @@ let HeadingToken = (() => {
296
299
  return (0, html_1.getId)(this.firstChild[expand ? 'expand' : 'cloneNode']());
297
300
  }
298
301
  /** @private */
299
- toHtmlInternal() {
302
+ getRenderedId() {
300
303
  let id = this.#getId();
301
- const { level, firstChild } = this, lcId = id.toLowerCase(), headings = constants_1.states.get(this.getRootNode())?.headings;
304
+ const lcId = id.toLowerCase(), headings = constants_1.states.get(this.getRootNode())?.headings;
302
305
  if (headings?.has(lcId)) {
303
306
  let i = 2;
304
307
  for (; headings.has(`${lcId}_${i}`); i++) {
@@ -310,7 +313,12 @@ let HeadingToken = (() => {
310
313
  else {
311
314
  headings?.add(lcId);
312
315
  }
313
- return `<div class="mw-heading mw-heading${level}"><h${level} id="${(0, string_1.sanitizeId)(id)}">${firstChild.toHtmlInternal().trim()}</h${level}></div>`;
316
+ return (0, string_1.sanitizeId)(id);
317
+ }
318
+ /** @private */
319
+ toHtmlInternal() {
320
+ const { level, firstChild } = this;
321
+ return `${this.tocData ?? ''}<div class="mw-heading mw-heading${level}"><h${level} id="${this.getRenderedId()}">${firstChild.toHtmlInternal().trim()}</h${level}></div>`;
314
322
  }
315
323
  /**
316
324
  * Get the section led by this heading
package/dist/src/index.js CHANGED
@@ -532,9 +532,8 @@ let Token = (() => {
532
532
  }
533
533
  /** @private */
534
534
  inTableAttrs() {
535
- return this.isInside('table-attrs') && (this.closest('table-attrs,arg,parameter')?.is('table-attrs')
536
- ? 2
537
- : 1);
535
+ return this.isInside('table-attrs')
536
+ && (this.closest('table-attrs,arg,parameter')?.is('table-attrs') ? 2 : 1);
538
537
  }
539
538
  /** @private */
540
539
  inHtmlAttrs() {
@@ -555,7 +554,7 @@ let Token = (() => {
555
554
  }
556
555
  else {
557
556
  const value = cat.getValue();
558
- if (value && value !== true) {
557
+ if (value) {
559
558
  key = `#${value}`;
560
559
  }
561
560
  }
@@ -326,9 +326,7 @@ let LinkBaseToken = (() => {
326
326
  }
327
327
  /** @private */
328
328
  toHtmlInternal(opt) {
329
- if (this.is('link')
330
- || this.is('redirect-target')
331
- || this.is('category')) {
329
+ if (this.is('link') || this.is('redirect-target') || this.is('category')) {
332
330
  const { link, length, lastChild, type, pageName } = this;
333
331
  let attr;
334
332
  if (type === 'link' && link.title === pageName && !link.fragment) {
@@ -336,7 +334,7 @@ let LinkBaseToken = (() => {
336
334
  }
337
335
  else {
338
336
  const title = link.getTitleAttr();
339
- attr = `${link.interwiki && 'class="extiw" '}href="${link.getUrl()}"${title && ` title="${title}"`}`;
337
+ attr = `${link.interwiki && 'class="extiw" '}href="${link.getUrl()}"${link.ns === -2 ? ' class="internal"' : ''}${title && ` title="${title}"`}`;
340
338
  }
341
339
  return `<a ${attr}>${type === 'link' && length > 1
342
340
  ? lastChild.toHtmlInternal({
@@ -501,13 +501,13 @@ let FileToken = (() => {
501
501
  /* c8 ignore stop */
502
502
  /** @private */
503
503
  toHtmlInternal(opt) {
504
- const { link, width, height, type } = this, file = this.getAttribute('title'), fr = this.getFrame(), manual = fr instanceof title_1.Title, visibleCaption = manual || fr === 'thumbnail' || fr === 'framed' || type === 'gallery-image', caption = this.getArg('caption')?.toHtmlInternal({
504
+ const { link, width, height, type } = this, file = this.getAttribute('title'), fr = this.getFrame(), manual = fr instanceof title_1.Title, framed = fr === 'framed', visibleCaption = manual || framed || fr === 'thumbnail' || type === 'gallery-image', caption = this.getArg('caption')?.toHtmlInternal({
505
505
  ...opt,
506
506
  nowrap: true,
507
507
  }) ?? '', titleFromCaption = visibleCaption && type !== 'gallery-image' ? '' : (0, string_1.sanitizeAlt)(caption), hasLink = manual || link !== file, title = titleFromCaption || (hasLink && typeof link !== 'string' ? link.getTitleAttr() : ''), titleAttr = title && ` title="${title}"`, alt = (0, string_1.sanitizeAlt)(this.getArg('alt')?.toHtmlInternal({
508
508
  ...opt,
509
509
  nowrap: true,
510
- })) ?? titleFromCaption, horiz = this.getHorizAlign() ?? '', vert = this.getVertAlign() ?? '', className = `${horiz ? `mw-halign-${horiz}` : vert && `mw-valign-${vert}`}${this.getValue('border') ? ' mw-image-border' : ''} ${(0, string_1.sanitizeAlt)(this.getValue('class')) ?? ''}`.trim(), classAttr = className && ` class="${className}"`, hasWidth = isInteger(width), hasHeight = isInteger(height);
510
+ })) ?? titleFromCaption, horiz = this.getHorizAlign() ?? '', vert = this.getVertAlign() ?? '', hasWidth = isInteger(width), hasHeight = isInteger(height), className = `${manual || framed || hasWidth || hasHeight ? '' : 'mw-default-size '}${horiz ? `mw-halign-${horiz}` : vert && `mw-valign-${vert}`}${this.getValue('border') ? ' mw-image-border' : ''} ${(0, string_1.sanitizeAlt)(this.getValue('class')) ?? ''}`.trim(), classAttr = className && ` class="${className}"`;
511
511
  let src;
512
512
  try {
513
513
  src = manual ? fr.getFileUrl() : file.getFileUrl(hasWidth && Number(width), hasHeight && Number(height));
@@ -523,10 +523,10 @@ let FileToken = (() => {
523
523
  if (link === file) {
524
524
  const lang = this.getValue('lang'), page = this.getValue('page');
525
525
  if (lang) {
526
- href += `?lang=${lang}`;
526
+ href += `?lang=${(0, string_1.sanitizeId)(lang)}`;
527
527
  }
528
528
  else if (page) {
529
- href += `?page=${page}`;
529
+ href += `?page=${(0, string_1.sanitizeId)(page)}`;
530
530
  }
531
531
  }
532
532
  }
@@ -540,7 +540,7 @@ let FileToken = (() => {
540
540
  ? `<figure${classAttr} typeof="mw:File${fr ? `/${manual ? 'Thumb' : frame.get(fr)}` : ''}">${a}<figcaption>${caption}</figcaption></figure>`
541
541
  : `<span${classAttr}>${a}</span>`;
542
542
  }
543
- const parent = this.parentNode, mode = parent?.parentNode?.getAttr('mode'), nolines = typeof mode === 'string' && mode.toLowerCase() === 'nolines', padding = nolines ? 0 : 30;
543
+ const parent = this.parentNode, nolines = parent?.parentNode?.getAttr('mode')?.toLowerCase() === 'nolines', padding = nolines ? 0 : 30;
544
544
  return `\t<li class="gallerybox" style="width: ${Number(width) + padding + 5}px">\n\t\t<div class="thumb" style="width: ${Number(width) + padding}px${nolines ? '' : `; height: ${Number(height) + padding}px`}"><span>${a}</span></div>\n\t\t<div class="gallerytext">${parent?.parentNode?.hasAttr('showfilename')
545
545
  ? `<a href="${file.getUrl()}" class="galleryfilename galleryfilename-truncate" title="${file.title}">${file.main}</a>\n`
546
546
  : ''}${caption}</div>\n\t</li>`;
@@ -144,9 +144,7 @@ let GalleryImageToken = (() => {
144
144
  * @param i position to be inserted at / 插入位置
145
145
  */
146
146
  insertAt(child, i) {
147
- if (this.type === 'gallery-image'
148
- && child.is('image-parameter')
149
- && !constants_1.galleryParams.has(child.name)) {
147
+ if (this.type === 'gallery-image' && child.is('image-parameter') && !constants_1.galleryParams.has(child.name)) {
150
148
  child.setAttribute('name', 'invalid');
151
149
  }
152
150
  return super.insertAt(child, i);
@@ -246,7 +246,7 @@ let MagicLinkToken = (() => {
246
246
  .getUrl(articlePath)
247
247
  : new URL(link.startsWith('RFC')
248
248
  ? `https://datatracker.ietf.org/doc/html/rfc${link.slice(4)}`
249
- : `https://pubmed.ncbi.nlm.nih.gov/${link.slice(5)}`);
249
+ : `https://www.ncbi.nlm.nih.gov/pubmed/${link.slice(5)}?dopt=Abstract`);
250
250
  }
251
251
  }
252
252
  /* PRINT ONLY */
@@ -300,10 +300,11 @@ let MagicLinkToken = (() => {
300
300
  url = this.getUrl();
301
301
  }
302
302
  catch { }
303
- const attrs = type === 'free-ext-link' || type === 'ext-link-url'
304
- ? ` rel="nofollow" class="external${type === 'free-ext-link' ? ' free' : ''}"${typeof url === 'object' ? ` href="${url.href}"` : ''}`
305
- : (protocol === 'ISBN' ? '' : ' class="external" rel="nofollow"')
306
- + (url === undefined ? '' : ` href="${typeof url === 'string' ? url : url.href}"`);
303
+ const isISBN = protocol === 'ISBN', attrs = type === 'free-ext-link' || type === 'ext-link-url'
304
+ ? ` rel="nofollow" class="external free"${typeof url === 'object' ? ` href="${url.href}"` : ''}`
305
+ : (isISBN ? '' : ` class="external mw-magiclink-${protocol.toLowerCase()}" rel="nofollow"`)
306
+ + (url === undefined ? '' : ` href="${typeof url === 'string' ? url : url.href}"`)
307
+ + (isISBN ? ' class="internal mw-magiclink-isbn"' : '');
307
308
  return `<a${attrs}>${innerText}</a>`;
308
309
  }
309
310
  };
@@ -176,7 +176,7 @@ let GalleryToken = (() => {
176
176
  */
177
177
  #getSize(key) {
178
178
  LSP: {
179
- const widths = this.parentNode?.getAttr(key), mt = typeof widths === 'string' && /^(\d+)\s*(?:px)?$/u.exec(widths)?.[1];
179
+ const widths = this.parentNode?.getAttr(key), mt = widths && /^(\d+)\s*(?:px)?$/u.exec(widths)?.[1];
180
180
  return mt && Number(mt) || 120;
181
181
  }
182
182
  }
@@ -208,8 +208,7 @@ let GalleryToken = (() => {
208
208
  throw new SyntaxError(`Invalid file name: ${file}`);
209
209
  }
210
210
  insertAt(token, i = this.length) {
211
- if (!debug_1.Shadow.running
212
- && (typeof token === 'string' ? token.trim() : !token.is('gallery-image'))) {
211
+ if (!debug_1.Shadow.running && (typeof token === 'string' ? token.trim() : !token.is('gallery-image'))) {
213
212
  throw new RangeError('Please do not insert invisible content into <gallery>!');
214
213
  }
215
214
  return super.insertAt(token, i);
@@ -20,4 +20,5 @@ export declare abstract class DoubleUnderscoreToken extends NowikiBaseToken {
20
20
  */
21
21
  constructor(word: string, sensitive: boolean, fullWidth: boolean, config: Config, accum?: Token[]);
22
22
  cloneNode(): this;
23
+ toHtmlInternal(): string;
23
24
  }
@@ -49,7 +49,7 @@ const syntax_1 = require("../../mixin/syntax");
49
49
  * 状态开关
50
50
  */
51
51
  let DoubleUnderscoreToken = (() => {
52
- let _classDecorators = [(0, syntax_1.syntax)(), (0, hidden_1.hiddenToken)(), (0, padded_1.padded)('__')];
52
+ let _classDecorators = [(0, syntax_1.syntax)(), (0, hidden_1.hiddenToken)(true, false), (0, padded_1.padded)('__')];
53
53
  let _classDescriptor;
54
54
  let _classExtraInitializers = [];
55
55
  let _classThis;
@@ -101,6 +101,9 @@ let DoubleUnderscoreToken = (() => {
101
101
  // @ts-expect-error abstract class
102
102
  return debug_1.Shadow.run(() => new DoubleUnderscoreToken(this.innerText, this.#sensitive, this.#fullWidth, this.getAttribute('config')));
103
103
  }
104
+ toHtmlInternal() {
105
+ return this.tocData ?? '';
106
+ }
104
107
  };
105
108
  return DoubleUnderscoreToken = _classThis;
106
109
  })();
@@ -113,9 +113,7 @@ let QuoteToken = (() => {
113
113
  /** @private */
114
114
  text() {
115
115
  const { parentNode, innerText } = this;
116
- return parentNode?.is('image-parameter') && parentNode.name !== 'caption'
117
- ? ''
118
- : innerText;
116
+ return parentNode?.is('image-parameter') && parentNode.name !== 'caption' ? '' : innerText;
119
117
  }
120
118
  /** @private */
121
119
  lint(start = this.getAbsoluteIndex()) {
@@ -236,8 +236,11 @@ let ParameterToken = (() => {
236
236
  * 获取参数值
237
237
  */
238
238
  getValue() {
239
- const value = (0, string_1.removeCommentLine)(this.lastChild.text());
240
- return this.anon && this.parentNode?.isTemplate() !== false ? value : value.trim();
239
+ const { parentNode, lastChild, anon, name } = this, value = (0, string_1.removeCommentLine)(lastChild.text());
240
+ return anon && parentNode?.isTemplate() !== false
241
+ || name === '2' && parentNode?.type === 'magic-word' && parentNode.name === 'tag'
242
+ ? value
243
+ : value.trim();
241
244
  }
242
245
  /**
243
246
  * Set the parameter value
@@ -8,9 +8,9 @@ export interface TdSpanAttrs {
8
8
  rowspan?: number;
9
9
  colspan?: number;
10
10
  }
11
- declare type TdAttrGetter<T extends string> = T extends keyof TdSpanAttrs ? number : string | true | undefined;
11
+ declare type TdAttrGetter<T extends string> = T extends keyof TdSpanAttrs ? number : string | undefined;
12
12
  declare type TdAttrSetter<T extends string> = T extends keyof TdSpanAttrs ? number : string | boolean;
13
- export type TdAttrs = Record<string, string | true> & TdSpanAttrs;
13
+ export type TdAttrs = Record<string, string> & TdSpanAttrs;
14
14
  /**
15
15
  * `<td>`, `<th>` or `<caption>`
16
16
  *
@@ -258,7 +258,7 @@ let TdToken = (() => {
258
258
  key = (0, string_1.trimLc)(key);
259
259
  /* NOT FOR BROWSER END */
260
260
  const value = super.getAttr(key);
261
- return (key === 'rowspan' || key === 'colspan' ? parseInt(value) || 1 : value);
261
+ return (key === 'rowspan' || key === 'colspan' ? parseInt(value || '') || 1 : value);
262
262
  }
263
263
  }
264
264
  /** @private */