wikiparser-node 1.28.0 → 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 (83) 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/config/default.json +15 -16
  6. package/config/jawiki.json +15 -16
  7. package/data/ext/ThirdPartyNotices.txt +33 -0
  8. package/data/ext/mapframe.json +489 -2
  9. package/dist/addon/magicWords.js +132 -0
  10. package/dist/addon/table.js +4 -4
  11. package/dist/addon/token.js +37 -126
  12. package/dist/addon/transclude.js +24 -30
  13. package/dist/base.d.mts +4 -2
  14. package/dist/base.d.ts +4 -2
  15. package/dist/base.js +2 -0
  16. package/dist/base.mjs +3 -1
  17. package/dist/bin/config.js +11 -11
  18. package/dist/index.d.ts +2 -1
  19. package/dist/index.js +27 -5
  20. package/dist/lib/document.d.ts +23 -7
  21. package/dist/lib/document.js +7 -27
  22. package/dist/lib/element.js +1 -1
  23. package/dist/lib/lintConfig.js +4 -0
  24. package/dist/lib/lsp.d.ts +1 -12
  25. package/dist/lib/lsp.js +45 -79
  26. package/dist/lib/node.js +25 -25
  27. package/dist/lib/range.js +2 -2
  28. package/dist/lib/title.d.ts +3 -1
  29. package/dist/lib/title.js +54 -33
  30. package/dist/mixin/elementLike.js +14 -9
  31. package/dist/parser/commentAndExt.js +34 -27
  32. package/dist/parser/hrAndDoubleUnderscore.js +9 -8
  33. package/dist/parser/links.js +4 -3
  34. package/dist/parser/redirect.js +1 -1
  35. package/dist/parser/selector.js +7 -9
  36. package/dist/src/arg.js +6 -9
  37. package/dist/src/attribute.js +37 -8
  38. package/dist/src/attributes.js +1 -1
  39. package/dist/src/converter.js +6 -3
  40. package/dist/src/converterRule.js +4 -6
  41. package/dist/src/extLink.js +3 -4
  42. package/dist/src/heading.js +1 -2
  43. package/dist/src/imageParameter.d.ts +4 -1
  44. package/dist/src/imageParameter.js +79 -26
  45. package/dist/src/index.d.ts +8 -0
  46. package/dist/src/index.js +21 -29
  47. package/dist/src/link/base.js +6 -8
  48. package/dist/src/link/file.js +10 -14
  49. package/dist/src/link/galleryImage.js +1 -1
  50. package/dist/src/link/redirectTarget.js +1 -1
  51. package/dist/src/magicLink.js +13 -3
  52. package/dist/src/multiLine/gallery.js +2 -2
  53. package/dist/src/multiLine/imagemap.js +3 -4
  54. package/dist/src/multiLine/paramTag.js +2 -2
  55. package/dist/src/nowiki/doubleUnderscore.d.ts +2 -1
  56. package/dist/src/nowiki/doubleUnderscore.js +9 -5
  57. package/dist/src/nowiki/index.js +58 -4
  58. package/dist/src/onlyinclude.js +2 -1
  59. package/dist/src/parameter.js +4 -6
  60. package/dist/src/redirect.js +2 -2
  61. package/dist/src/table/base.js +1 -2
  62. package/dist/src/table/index.js +3 -6
  63. package/dist/src/table/td.d.ts +2 -3
  64. package/dist/src/table/td.js +6 -6
  65. package/dist/src/table/trBase.js +1 -1
  66. package/dist/src/tag/html.js +3 -4
  67. package/dist/src/tag/tvar.js +1 -2
  68. package/dist/src/tagPair/ext.js +12 -5
  69. package/dist/src/tagPair/include.js +2 -2
  70. package/dist/src/tagPair/translate.js +2 -2
  71. package/dist/src/transclude.js +5 -5
  72. package/dist/util/constants.js +4 -1
  73. package/dist/util/debug.js +1 -1
  74. package/dist/util/html.js +13 -10
  75. package/dist/util/search.js +16 -0
  76. package/dist/util/sharable.js +27 -3
  77. package/dist/util/sharable.mjs +28 -4
  78. package/extensions/dist/base.js +1 -1
  79. package/i18n/en.json +4 -0
  80. package/i18n/zh-hans.json +4 -0
  81. package/i18n/zh-hant.json +4 -0
  82. package/package.json +9 -7
  83. package/data/ext/maplink.json +0 -4
@@ -2,7 +2,7 @@ import { Token } from './index';
2
2
  import type { LintError, Config } from '../base';
3
3
  import type { Title } from '../lib/title';
4
4
  import type { AtomToken, FileToken, AstNodes, AstText } from '../internal';
5
- export declare const galleryParams: Set<string>;
5
+ export declare const galleryParams: Set<string>, extensions: Set<string>;
6
6
  /**
7
7
  * image parameter
8
8
  *
@@ -18,9 +18,12 @@ export declare abstract class ImageParameterToken extends Token {
18
18
  abstract get nextElementSibling(): this | undefined;
19
19
  abstract get previousElementSibling(): AtomToken | this | undefined;
20
20
  get type(): 'image-parameter';
21
+ /** thumbnail / 缩略图 */
22
+ get thumb(): Title | undefined;
21
23
  /** image link / 图片链接 */
22
24
  get link(): string | Title | undefined;
23
25
  set link(value: string);
26
+ set thumb(value: string);
24
27
  /** parameter value / 参数值 */
25
28
  get value(): string | true;
26
29
  set value(value: string | true);
@@ -3,16 +3,14 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.ImageParameterToken = exports.galleryParams = void 0;
6
+ exports.ImageParameterToken = exports.extensions = exports.galleryParams = void 0;
7
7
  const common_1 = require("@bhsd/common");
8
8
  const string_1 = require("../util/string");
9
9
  const lint_1 = require("../util/lint");
10
10
  const constants_1 = require("../util/constants");
11
+ const debug_1 = require("../util/debug");
11
12
  const index_1 = __importDefault(require("../index"));
12
13
  const index_2 = require("./index");
13
- /* NOT FOR BROWSER */
14
- const debug_1 = require("../util/debug");
15
- /* NOT FOR BROWSER END */
16
14
  /^(?:ftp:\/\/|\/\/|\0\d+m\x7F)/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
17
15
  const getUrlLikeRegex = (0, common_1.getRegex)(protocol => new RegExp(String.raw `^(?:${protocol}|//|\0\d+m\x7F)`, 'iu'));
18
16
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
@@ -23,7 +21,20 @@ const getUrlRegex = (0, common_1.getRegex)(protocol => new RegExp(String.raw `^(
23
21
  /^(\s*(?!\s))(.*)px(\s*)$/u;
24
22
  /* eslint-enable @typescript-eslint/no-unused-expressions */
25
23
  const getSyntaxRegex = (0, common_1.getRegex)(syntax => new RegExp(String.raw `^(\s*(?!\s))${syntax.replace('$1', '(.*)')}${syntax.endsWith('$1') ? '(?=$|\n)' : ''}(\s*)$`, 'u'));
26
- exports.galleryParams = new Set(['alt', 'link', 'lang', 'page', 'caption']);
24
+ exports.galleryParams = new Set(['alt', 'link', 'lang', 'page', 'caption']), exports.extensions = new Set(['tiff', 'tif', 'png', 'gif', 'jpg', 'jpeg', 'webp', 'xcf', 'pdf', 'svg', 'djvu']);
25
+ /**
26
+ * 获取网址
27
+ * @param link 外链
28
+ */
29
+ const getUrl = (link) => {
30
+ if (!link) {
31
+ return link;
32
+ }
33
+ else if (link.startsWith('//')) {
34
+ link = `https:${link}`;
35
+ }
36
+ return new URL(link).href;
37
+ };
27
38
  function validate(key, val, config, halfParsed, ext) {
28
39
  val = (0, string_1.removeComment)(val).trim();
29
40
  let value = val.replace(key === 'link' ? /\0\d+[tq]\x7F/gu : /\0\d+t\x7F/gu, '').trim();
@@ -40,7 +51,7 @@ function validate(key, val, config, halfParsed, ext) {
40
51
  else if (value.startsWith('[[') && value.endsWith(']]')) {
41
52
  value = value.slice(2, -2);
42
53
  }
43
- const title = index_1.default.normalizeTitle(value, 0, false, config, { halfParsed, decode: true, selfLink: true });
54
+ const title = index_1.default.normalizeTitle(value, 0, false, config, { halfParsed, decode: true, selfLink: true, page: '' });
44
55
  return title.valid && title;
45
56
  }
46
57
  case 'lang':
@@ -68,9 +79,27 @@ class ImageParameterToken extends index_2.Token {
68
79
  get type() {
69
80
  return 'image-parameter';
70
81
  }
82
+ /** thumbnail / 缩略图 */
83
+ get thumb() {
84
+ LINT: return this.name === 'manualthumb' // eslint-disable-line no-unused-labels
85
+ ? this.normalizeTitle(`File:${super.text().trim()}`, 6, { page: '' })
86
+ : undefined;
87
+ }
71
88
  /** image link / 图片链接 */
72
89
  get link() {
73
- return this.name === 'link' ? validate('link', super.text(), this.getAttribute('config')) : undefined;
90
+ LINT: { // eslint-disable-line no-unused-labels
91
+ if (this.name !== 'link') {
92
+ return undefined;
93
+ }
94
+ const value = super.text().trim();
95
+ return debug_1.Shadow.run(() => {
96
+ const token = new index_2.Token(value, this.getAttribute('config'));
97
+ token.parseOnce(0, this.getAttribute('include')).parseOnce();
98
+ return /^\0\d+m\x7F/u.test(token.toString())
99
+ ? value
100
+ : validate('link', value, this.getAttribute('config'));
101
+ });
102
+ }
74
103
  }
75
104
  /* NOT FOR BROWSER */
76
105
  set link(value) {
@@ -78,6 +107,11 @@ class ImageParameterToken extends index_2.Token {
78
107
  this.setValue(value);
79
108
  }
80
109
  }
110
+ set thumb(value) {
111
+ if (this.name === 'manualthumb') {
112
+ this.setValue(value);
113
+ }
114
+ }
81
115
  /** parameter value / 参数值 */
82
116
  get value() {
83
117
  return this.getValue();
@@ -93,7 +127,7 @@ class ImageParameterToken extends index_2.Token {
93
127
  const [width, height = ''] = size.split('x');
94
128
  return { width, height };
95
129
  }
96
- const token = index_1.default.parse(size, false, 2, this.getAttribute('config')), i = token.childNodes.findIndex(({ type, data }) => type === 'text' && data.includes('x'));
130
+ const token = index_1.default.parseWithRef(size, this, 2, false), i = token.childNodes.findIndex(({ type, data }) => type === 'text' && data.includes('x'));
97
131
  if (i === -1) {
98
132
  return { width: size, height: '' };
99
133
  }
@@ -211,14 +245,39 @@ class ImageParameterToken extends index_2.Token {
211
245
  errors.push(e);
212
246
  }
213
247
  }
214
- else if (typeof link === 'object' && link.encoded) {
215
- const rule = 'url-encoding', s = lintConfig.getSeverity(rule, 'file');
216
- if (s) {
217
- const e = (0, lint_1.generateForSelf)(this, { start }, rule, 'unnecessary-encoding', s);
218
- if (computeEditInfo || fix) {
219
- e.fix = (0, lint_1.fixByDecode)(e, this);
248
+ else if (name === 'link') {
249
+ if (typeof link === 'string') {
250
+ const rule = 'invalid-url', s = lintConfig.getSeverity(rule);
251
+ if (s && !this.querySelector('magic-word')) {
252
+ try {
253
+ getUrl(link);
254
+ }
255
+ catch {
256
+ errors.push((0, lint_1.generateForSelf)(this, { start }, rule, 'invalid-url', s));
257
+ }
258
+ }
259
+ }
260
+ else if (link.encoded) {
261
+ const rule = 'url-encoding', s = lintConfig.getSeverity(rule, 'file');
262
+ if (s) {
263
+ const e = (0, lint_1.generateForSelf)(this, { start }, rule, 'unnecessary-encoding', s);
264
+ if (computeEditInfo || fix) {
265
+ e.fix = (0, lint_1.fixByDecode)(e, this);
266
+ }
267
+ errors.push(e);
268
+ }
269
+ }
270
+ }
271
+ else if (name === 'manualthumb') {
272
+ const rule = 'invalid-gallery', s = lintConfig.getSeverity(rule, 'thumb');
273
+ if (s && !this.querySelector('arg,magic-word,template')) {
274
+ const { valid, ns, extension,
275
+ /* NOT FOR BROWSER */
276
+ interwiki, } = this.thumb;
277
+ if (!valid || ns !== 6 || !exports.extensions.has(extension)
278
+ || interwiki) {
279
+ errors.push((0, lint_1.generateForSelf)(this, { start }, rule, 'invalid-thumb', s));
220
280
  }
221
- errors.push(e);
222
281
  }
223
282
  }
224
283
  return errors;
@@ -246,10 +305,10 @@ class ImageParameterToken extends index_2.Token {
246
305
  }
247
306
  /* NOT FOR BROWSER */
248
307
  cloneNode() {
249
- const cloned = this.cloneChildNodes(), config = this.getAttribute('config');
308
+ const cloned = this.cloneChildNodes();
250
309
  return debug_1.Shadow.run(() => {
251
310
  // @ts-expect-error abstract class
252
- const token = new ImageParameterToken(this.#syntax.replace('$1', '1'), this.#extension, config);
311
+ const token = new ImageParameterToken(this.#syntax.replace('$1', '1'), this.#extension, this.getAttribute('config'));
253
312
  token.safeReplaceChildren(cloned);
254
313
  return token;
255
314
  });
@@ -281,7 +340,7 @@ class ImageParameterToken extends index_2.Token {
281
340
  this.typeError('setValue', type);
282
341
  }
283
342
  else if (value !== true) {
284
- const include = this.getAttribute('include'), config = this.getAttribute('config'), { childNodes } = index_1.default.parse(value, include, name === 'caption' ? undefined : 5, config);
343
+ const { childNodes } = index_1.default.parseWithRef(value, this, name === 'caption' ? undefined : 5);
285
344
  this.safeReplaceChildren(childNodes);
286
345
  }
287
346
  }
@@ -293,17 +352,11 @@ class ImageParameterToken extends index_2.Token {
293
352
  * @since v1.11.0
294
353
  */
295
354
  getUrl(articlePath) {
296
- let { link } = this;
355
+ const { link } = this;
297
356
  if (!link) {
298
357
  return link;
299
358
  }
300
- else if (typeof link !== 'string') {
301
- return link.getUrl(articlePath);
302
- }
303
- else if (link.startsWith('//')) {
304
- link = `https:${link}`;
305
- }
306
- return new URL(link).href;
359
+ return typeof link === 'string' ? getUrl(link) : link.getUrl(articlePath);
307
360
  }
308
361
  }
309
362
  exports.ImageParameterToken = ImageParameterToken;
@@ -20,6 +20,14 @@ export declare class Token extends AstElement {
20
20
  #private;
21
21
  get type(): TokenTypes;
22
22
  set type(value: TokenTypes);
23
+ /**
24
+ * page name
25
+ *
26
+ * 页面名称
27
+ * @since v1.29.0
28
+ */
29
+ get pageName(): string | undefined;
30
+ set pageName(value: string | undefined);
23
31
  /** @class */
24
32
  constructor(wikitext?: string, config?: Parser.Config, accum?: Token[], acceptable?: WikiParserAcceptable);
25
33
  /**
package/dist/src/index.js CHANGED
@@ -96,10 +96,6 @@ const ranges_1 = require("../lib/ranges");
96
96
  const range_1 = require("../lib/range");
97
97
  const readOnly_1 = require("../mixin/readOnly");
98
98
  const cached_1 = require("../mixin/cached");
99
- /* NOT FOR BROWSER END */
100
- /* NOT FOR BROWSER ONLY */
101
- const document_1 = require("../lib/document");
102
- const lsp_1 = require("../lib/lsp");
103
99
  const lintSelectors = ['category', 'html-attr#id,ext-attr#id,table-attr#id'];
104
100
  /* NOT FOR BROWSER */
105
101
  /**
@@ -158,6 +154,7 @@ let Token = (() => {
158
154
  #include;
159
155
  #built = false;
160
156
  #string;
157
+ #pageName;
161
158
  /* NOT FOR BROWSER */
162
159
  #acceptable;
163
160
  #protectedChildren = new ranges_1.Ranges();
@@ -189,6 +186,24 @@ let Token = (() => {
189
186
  /* NOT FOR BROWSER END */
190
187
  this.#type = value;
191
188
  }
189
+ /**
190
+ * page name
191
+ *
192
+ * 页面名称
193
+ * @since v1.29.0
194
+ */
195
+ get pageName() {
196
+ return this.getRootNode().#pageName;
197
+ }
198
+ set pageName(value) {
199
+ if (value) {
200
+ const title = this.normalizeTitle(value, 0, { temporary: true, page: '' });
201
+ this.#pageName = title.valid ? title.title : undefined;
202
+ }
203
+ else {
204
+ this.#pageName = value === '' ? '' : undefined;
205
+ }
206
+ }
192
207
  /** @class */
193
208
  constructor(wikitext, config = index_1.default.getConfig(), accum = [], acceptable) {
194
209
  super();
@@ -370,7 +385,7 @@ let Token = (() => {
370
385
  */
371
386
  #parseLinks(tidy) {
372
387
  const { parseLinks } = require('../parser/links');
373
- this.setText(parseLinks(this.firstChild.toString(), this.#config, this.#accum, tidy));
388
+ this.setText(parseLinks(this.firstChild.toString(), this.#config, this.#accum, this.pageName, tidy));
374
389
  }
375
390
  /**
376
391
  * 解析单引号
@@ -508,7 +523,7 @@ let Token = (() => {
508
523
  }
509
524
  /** @private */
510
525
  normalizeTitle(title, defaultNs = 0, opt) {
511
- return index_1.default.normalizeTitle(title, defaultNs, this.#include, this.#config, opt);
526
+ return index_1.default.normalizeTitle(title, defaultNs, this.getAttribute('include'), this.#config, { page: this.pageName, ...opt });
512
527
  }
513
528
  /** @private */
514
529
  inTableAttrs() {
@@ -619,29 +634,6 @@ let Token = (() => {
619
634
  delete e.suggestions;
620
635
  }
621
636
  }
622
- /* NOT FOR BROWSER ONLY */
623
- }
624
- else if ((0, lsp_1.isAttr)(this, true)) {
625
- const rule = 'invalid-css', s = lintConfig.getSeverity(rule), sWarn = lintConfig.getSeverity(rule, 'warn');
626
- if (s || sWarn) {
627
- const root = this.getRootNode(), textDoc = new document_1.EmbeddedCSSDocument(root, this);
628
- errors.push(...document_1.cssLSP.doValidation(textDoc, textDoc.styleSheet)
629
- .filter(({ code, severity }) => code !== 'css-ruleorselectorexpected' && code !== 'emptyRules'
630
- && (severity === 1 ? s : sWarn))
631
- .map(({ range: { start: { line, character }, end }, message, severity, code }) => ({
632
- code: code,
633
- rule,
634
- message,
635
- severity: (severity === 1 ? s : sWarn),
636
- startLine: line,
637
- startCol: character,
638
- startIndex: root.indexFromPos(line, character),
639
- endLine: end.line,
640
- endCol: end.character,
641
- endIndex: root.indexFromPos(end.line, end.character),
642
- })));
643
- }
644
- /* NOT FOR BROWSER ONLY END */
645
637
  }
646
638
  return errors;
647
639
  }
@@ -292,9 +292,7 @@ let LinkBaseToken = (() => {
292
292
  * @param link link target / 链接目标
293
293
  */
294
294
  setTarget(link) {
295
- const config = this.getAttribute('config'), { childNodes } = index_1.default.parse(link, this.getAttribute('include'), 2, config), token = debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'link-target', config, [], {
296
- 'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '',
297
- }));
295
+ const { childNodes } = index_1.default.parseWithRef(link, this, 2), token = debug_1.Shadow.run(() => new atom_1.AtomToken(undefined, 'link-target', this.getAttribute('config'), [], { 'Stage-2': ':', '!ExtToken': '', '!HeadingToken': '' }));
298
296
  token.safeAppend(childNodes);
299
297
  this.firstChild.safeReplaceWith(token);
300
298
  }
@@ -318,13 +316,13 @@ let LinkBaseToken = (() => {
318
316
  * @param linkStr link text / 链接显示文字
319
317
  */
320
318
  setLinkText(linkStr) {
319
+ const { childNodes, lastChild, length } = this;
321
320
  if (linkStr === undefined) {
322
- this.childNodes[1]?.remove();
321
+ childNodes[1]?.remove();
323
322
  return;
324
323
  }
325
- const root = index_1.default
326
- .parse(linkStr, this.getAttribute('include'), undefined, this.getAttribute('config'));
327
- if (this.length === 1) {
324
+ const root = index_1.default.parseWithRef(linkStr, this);
325
+ if (length === 1) {
328
326
  root.type = 'link-text';
329
327
  root.setAttribute('acceptable', {
330
328
  'Stage-5': ':', QuoteToken: ':', ConverterToken: ':',
@@ -332,7 +330,7 @@ let LinkBaseToken = (() => {
332
330
  this.insertAt(root);
333
331
  }
334
332
  else {
335
- this.lastChild.safeReplaceChildren(root.childNodes);
333
+ lastChild.safeReplaceChildren(root.childNodes);
336
334
  }
337
335
  }
338
336
  /** @private */
@@ -54,7 +54,7 @@ const frame = new Map([
54
54
  ['frameless', 'Frameless'],
55
55
  ['framed', 'Frame'],
56
56
  ['thumbnail', 'Thumb'],
57
- ]), argTypes = new Set(['arg']), transclusion = new Set(['template', 'magic-word']), horizAlign = new Set(['left', 'right', 'center', 'none']), vertAlign = new Set(['baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom']), extensions = new Set(['tiff', 'tif', 'png', 'gif', 'jpg', 'jpeg', 'webp', 'xcf', 'pdf', 'svg', 'djvu']);
57
+ ]), argTypes = new Set(['arg']), transclusion = new Set(['template', 'magic-word']), horizAlign = new Set(['left', 'right', 'center', 'none']), vertAlign = new Set(['baseline', 'sub', 'super', 'top', 'text-top', 'middle', 'bottom', 'text-bottom']);
58
58
  /**
59
59
  * a more sophisticated string-explode function
60
60
  * @param str string to be exploded
@@ -84,10 +84,7 @@ const explode = (str) => {
84
84
  * @param args image parameter tokens
85
85
  * @param types token types to be filtered
86
86
  */
87
- const filterArgs = (args, types) => args.filter(({ childNodes }) => {
88
- const visibleNodes = childNodes.filter(node => node.text().trim());
89
- return visibleNodes.length !== 1 || !types.has(visibleNodes[0].type);
90
- });
87
+ const filterArgs = (args, types) => args.filter(({ childNodes }) => !childNodes.some(node => node.text().trim() && types.has(node.type)));
91
88
  /**
92
89
  * image
93
90
  *
@@ -190,7 +187,7 @@ let FileToken = (() => {
190
187
  interwiki, } = this.getAttribute('title'), { firstChild } = this;
191
188
  let rule = 'nested-link', s = lintConfig.getSeverity(rule, 'file');
192
189
  if (s
193
- && extensions.has(extension)
190
+ && imageParameter_1.extensions.has(extension)
194
191
  && this.closest('ext-link-text')
195
192
  && this.getValue('link')?.trim() !== '') {
196
193
  const e = (0, lint_1.generateForSelf)(this, rect, rule, 'link-in-extlink', s);
@@ -266,22 +263,22 @@ let FileToken = (() => {
266
263
  ];
267
264
  }
268
265
  if (relevantArgs.length > 1) {
269
- let severity = !isCaption || !extension || extensions.has(extension);
266
+ let severity = !isCaption || !extension || imageParameter_1.extensions.has(extension);
270
267
  if (isCaption && severity) {
271
268
  const plainArgs = filterArgs(relevantArgs, transclusion);
272
269
  severity = plainArgs.length > 1 && ((arg) => plainArgs.includes(arg));
273
270
  }
274
- errors.push(...generate(relevantArgs, 'duplicate', key, severity));
271
+ Array.prototype.push.apply(errors, generate(relevantArgs, 'duplicate', key, severity));
275
272
  }
276
273
  }
277
274
  if (frameKeys.length > 1) {
278
- errors.push(...generate(args.filter(({ name }) => frame.has(name)), 'conflicting', 'frame'));
275
+ Array.prototype.push.apply(errors, generate(args.filter(({ name }) => frame.has(name)), 'conflicting', 'frame'));
279
276
  }
280
277
  if (horizAlignKeys.length > 1) {
281
- errors.push(...generate(args.filter(({ name }) => horizAlign.has(name)), 'conflicting', 'horizontal-alignment'));
278
+ Array.prototype.push.apply(errors, generate(args.filter(({ name }) => horizAlign.has(name)), 'conflicting', 'horizontal-alignment'));
282
279
  }
283
280
  if (vertAlignKeys.length > 1) {
284
- errors.push(...generate(args.filter(({ name }) => vertAlign.has(name)), 'conflicting', 'vertical-alignment'));
281
+ Array.prototype.push.apply(errors, generate(args.filter(({ name }) => vertAlign.has(name)), 'conflicting', 'vertical-alignment'));
285
282
  }
286
283
  return errors;
287
284
  }
@@ -379,7 +376,7 @@ let FileToken = (() => {
379
376
  */
380
377
  getFrame() {
381
378
  const [arg] = this.getFrameArgs(), val = arg?.name;
382
- return val === 'manualthumb' ? this.normalizeTitle(arg.getValue(), 6) : val;
379
+ return val === 'manualthumb' ? arg.thumb : val;
383
380
  }
384
381
  /**
385
382
  * Get the effective image horizontal alignment parameter value
@@ -468,8 +465,7 @@ let FileToken = (() => {
468
465
  // @ts-expect-error abstract class
469
466
  new imageParameter_1.ImageParameterToken(syntax.replace('$1', key === 'width' ? '1' : ''), this.extension, config));
470
467
  if (free) {
471
- const { childNodes } = index_1.default
472
- .parse(value, this.getAttribute('include'), undefined, config);
468
+ const { childNodes } = index_1.default.parseWithRef(value, this);
473
469
  parameter.safeReplaceChildren(childNodes);
474
470
  }
475
471
  this.insertAt(parameter);
@@ -109,7 +109,7 @@ let GalleryImageToken = (() => {
109
109
  /** @private */
110
110
  getTitle(temporary) {
111
111
  const imagemap = this.type === 'imagemap-image';
112
- return this.normalizeTitle(this.firstChild.toString(), imagemap ? 0 : 6, { halfParsed: true, temporary, decode: !imagemap });
112
+ return this.normalizeTitle(this.firstChild.toString(), imagemap ? 0 : 6, { halfParsed: true, temporary, decode: !imagemap, page: '' });
113
113
  }
114
114
  /** 判定无效的图片 */
115
115
  #lint() {
@@ -50,7 +50,7 @@ class RedirectTargetToken extends base_1.LinkBaseToken {
50
50
  }
51
51
  /** @private */
52
52
  getTitle() {
53
- return this.normalizeTitle(this.firstChild.toString(), 0, { halfParsed: true, decode: true });
53
+ return this.normalizeTitle(this.firstChild.toString(), 0, { halfParsed: true, decode: true, page: '' });
54
54
  }
55
55
  /** @private */
56
56
  lint(start = this.getAbsoluteIndex()) {
@@ -188,7 +188,18 @@ let MagicLinkToken = (() => {
188
188
  }
189
189
  return errors;
190
190
  }
191
- const pipe = type === 'ext-link-url', rule = 'unterminated-url', severity = lintConfig.getSeverity(rule, pipe ? 'pipe' : 'punctuation');
191
+ let rule = 'invalid-url', severity = lintConfig.getSeverity(rule);
192
+ if (severity && !this.querySelector('magic-word')) {
193
+ try {
194
+ this.getUrl();
195
+ }
196
+ catch {
197
+ errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'invalid-url', severity));
198
+ }
199
+ }
200
+ const pipe = type === 'ext-link-url';
201
+ rule = 'unterminated-url';
202
+ severity = lintConfig.getSeverity(rule, pipe ? 'pipe' : 'punctuation');
192
203
  if (severity) {
193
204
  const regex = pipe ? /\|/u : /[,;。:!?()]+/u, child = childNodes.find((c) => c.type === 'text' && regex.test(c.data));
194
205
  if (child) {
@@ -266,8 +277,7 @@ let MagicLinkToken = (() => {
266
277
  * @param url URL containing the protocol / 含协议的网址
267
278
  */
268
279
  setTarget(url) {
269
- const { childNodes } = index_1.default
270
- .parse(url, this.getAttribute('include'), 2, this.getAttribute('config'));
280
+ const { childNodes } = index_1.default.parseWithRef(url, this, 2);
271
281
  this.safeReplaceChildren(childNodes);
272
282
  }
273
283
  /**
@@ -124,7 +124,7 @@ let GalleryToken = (() => {
124
124
  * @param file 文件名
125
125
  */
126
126
  #checkFile(file) {
127
- return this.normalizeTitle(file, 6, { halfParsed: true, temporary: true, decode: true }).valid;
127
+ return this.normalizeTitle(file, 6, { halfParsed: true, temporary: true, decode: true, page: '' }).valid;
128
128
  }
129
129
  /** @private */
130
130
  lint(start = this.getAbsoluteIndex(), re) {
@@ -165,7 +165,7 @@ let GalleryToken = (() => {
165
165
  else if (type !== 'noinclude' && type !== 'text') {
166
166
  const childErrors = child.lint(start, re);
167
167
  if (childErrors.length > 0) {
168
- errors.push(...childErrors);
168
+ Array.prototype.push.apply(errors, childErrors);
169
169
  }
170
170
  }
171
171
  start += length + 1;
@@ -89,7 +89,7 @@ let ImagemapToken = (() => {
89
89
  else if (first) {
90
90
  const pipe = line.indexOf('|'), file = pipe === -1 ? line : line.slice(0, pipe), { valid, ns,
91
91
  /* NOT FOR BROWSER */
92
- interwiki, } = this.normalizeTitle(file, 0, { halfParsed: true, temporary: true });
92
+ interwiki, } = this.normalizeTitle(file, 0, { halfParsed: true, temporary: true, page: '' });
93
93
  if (valid
94
94
  && !interwiki
95
95
  && ns === 6) {
@@ -111,8 +111,7 @@ let ImagemapToken = (() => {
111
111
  const i = line.indexOf('['), substr = line.slice(i), mtIn = /^\[\[([^|]+)(?:\|([^\]]*))?\]\][\w\s]*$/u
112
112
  .exec(substr);
113
113
  if (mtIn) {
114
- if (this.normalizeTitle(mtIn[1], 0, { halfParsed: true, temporary: true, selfLink: true })
115
- .valid) {
114
+ if (this.normalizeTitle(mtIn[1], 0, { halfParsed: true, temporary: true, selfLink: true, page: '' }).valid) {
116
115
  // @ts-expect-error abstract class
117
116
  super.insertAt(new imagemapLink_1.ImagemapLinkToken(line.slice(0, i), mtIn.slice(1), substr.slice(substr.indexOf(']]') + 2), config, accum));
118
117
  continue;
@@ -140,7 +139,7 @@ let ImagemapToken = (() => {
140
139
  const errors = super.lint(start, re), rect = new rect_1.BoundingRect(this, start), { childNodes, image } = this, rule = 'invalid-imagemap', { lintConfig } = index_1.default, s = lintConfig.getSeverity(rule, image ? 'link' : 'image');
141
140
  if (s) {
142
141
  if (image) {
143
- errors.push(...childNodes.filter(child => {
142
+ Array.prototype.push.apply(errors, childNodes.filter(child => {
144
143
  const str = child.toString().trim();
145
144
  return child.is('noinclude')
146
145
  && str && !str.startsWith('#');
@@ -71,7 +71,7 @@ let ParamTagToken = (() => {
71
71
  });
72
72
  __runInitializers(this, _instanceExtraInitializers);
73
73
  if (wikitext) {
74
- this.append(...wikitext.split('\n')
74
+ this.safeAppend(wikitext.split('\n')
75
75
  .map(line => acceptable ? line : (0, commentAndExt_1.parseCommentAndExt)(line, config, accum, include))
76
76
  // @ts-expect-error abstract class
77
77
  .map((line) => new paramLine_1.ParamLineToken(line, config, accum, {
@@ -108,7 +108,7 @@ let ParamTagToken = (() => {
108
108
  else {
109
109
  const childErrors = child.lint(start, false);
110
110
  if (childErrors.length > 0) {
111
- errors.push(...childErrors);
111
+ Array.prototype.push.apply(errors, childErrors);
112
112
  }
113
113
  }
114
114
  }
@@ -13,7 +13,8 @@ export declare abstract class DoubleUnderscoreToken extends NowikiBaseToken {
13
13
  /**
14
14
  * @param word 状态开关名
15
15
  * @param sensitive 是否固定大小写
16
+ * @param fullWidth 是否为全角下划线
16
17
  */
17
- constructor(word: string, sensitive: boolean, config: Config, accum?: Token[]);
18
+ constructor(word: string, sensitive: boolean, fullWidth: boolean, config: Config, accum?: Token[]);
18
19
  cloneNode(): this;
19
20
  }
@@ -63,6 +63,7 @@ let DoubleUnderscoreToken = (() => {
63
63
  if (_metadata) Object.defineProperty(_classThis, Symbol.metadata, { enumerable: true, configurable: true, writable: true, value: _metadata });
64
64
  __runInitializers(_classThis, _classExtraInitializers);
65
65
  }
66
+ #fullWidth;
66
67
  /* NOT FOR BROWSER */
67
68
  #sensitive;
68
69
  /* NOT FOR BROWSER END */
@@ -72,28 +73,31 @@ let DoubleUnderscoreToken = (() => {
72
73
  /**
73
74
  * @param word 状态开关名
74
75
  * @param sensitive 是否固定大小写
76
+ * @param fullWidth 是否为全角下划线
75
77
  */
76
- constructor(word, sensitive, config, accum) {
78
+ constructor(word, sensitive, fullWidth, config, accum) {
77
79
  super(word, config, accum);
78
80
  const lc = word.toLowerCase(), { doubleUnderscore: [, , iAlias, sAlias] } = config;
79
81
  this.setAttribute('name', (sensitive ? sAlias?.[word]?.toLowerCase() : iAlias?.[lc]) ?? lc);
82
+ this.#fullWidth = fullWidth;
80
83
  /* NOT FOR BROWSER */
81
84
  this.#sensitive = sensitive;
82
85
  this.setAttribute('pattern', new RegExp(`^${word}$`, sensitive ? 'u' : 'iu'));
83
86
  }
84
87
  /** @private */
85
88
  toString() {
86
- return `__${this.innerText}__`;
89
+ const underscore = this.#fullWidth ? '__' : '__';
90
+ return underscore + this.innerText + underscore;
87
91
  }
88
92
  /** @private */
89
93
  print() {
90
- return super.print({ pre: '__', post: '__' });
94
+ const underscore = this.#fullWidth ? '__' : '__';
95
+ return super.print({ pre: underscore, post: underscore });
91
96
  }
92
97
  /* NOT FOR BROWSER */
93
98
  cloneNode() {
94
- const config = this.getAttribute('config');
95
99
  // @ts-expect-error abstract class
96
- return debug_1.Shadow.run(() => new DoubleUnderscoreToken(this.innerText, this.#sensitive, config));
100
+ return debug_1.Shadow.run(() => new DoubleUnderscoreToken(this.innerText, this.#sensitive, this.#fullWidth, this.getAttribute('config')));
97
101
  }
98
102
  };
99
103
  return DoubleUnderscoreToken = _classThis;