wikiparser-node 1.43.0 → 1.44.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 (43) hide show
  1. package/README.md +10 -7
  2. package/bundle/bundle-es8.min.js +40 -31
  3. package/bundle/bundle-lsp.min.js +35 -26
  4. package/bundle/bundle.min.js +22 -22
  5. package/config/default.json +31 -0
  6. package/config/moegirl.json +39 -1
  7. package/dist/base.d.mts +4 -4
  8. package/dist/base.d.ts +4 -4
  9. package/dist/base.js +1 -0
  10. package/dist/base.mjs +1 -0
  11. package/dist/bin/config.js +6 -5
  12. package/dist/index.js +8 -5
  13. package/dist/lib/document.d.ts +17 -14
  14. package/dist/lib/lintConfig.js +4 -1
  15. package/dist/lib/title.d.ts +4 -1
  16. package/dist/lib/title.js +5 -1
  17. package/dist/mixin/attributesParent.js +1 -1
  18. package/dist/parser/converter.js +1 -1
  19. package/dist/render/extension.js +30 -24
  20. package/dist/render/magicWords.js +1 -1
  21. package/dist/render/math.js +31 -0
  22. package/dist/render/syntaxhighlight.js +3 -0
  23. package/dist/src/attributes.d.ts +1 -0
  24. package/dist/src/attributes.js +27 -3
  25. package/dist/src/converterFlags.js +10 -5
  26. package/dist/src/converterRule.js +2 -2
  27. package/dist/src/imageParameter.d.ts +4 -3
  28. package/dist/src/imageParameter.js +15 -7
  29. package/dist/src/link/file.d.ts +5 -4
  30. package/dist/src/link/file.js +12 -9
  31. package/dist/src/nowiki/index.d.ts +1 -0
  32. package/dist/src/nowiki/index.js +40 -28
  33. package/dist/src/tagPair/ext.d.ts +1 -0
  34. package/dist/src/tagPair/ext.js +36 -3
  35. package/dist/src/transclude.js +1 -1
  36. package/dist/util/search.js +24 -6
  37. package/dist/util/string.js +7 -1
  38. package/extensions/dist/base.js +1 -1
  39. package/extensions/dist/codejar.js +1 -1
  40. package/i18n/en.json +7 -0
  41. package/i18n/zh-hans.json +7 -0
  42. package/i18n/zh-hant.json +7 -0
  43. package/package.json +19 -12
@@ -39,6 +39,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
40
  exports.ConverterFlagsToken = void 0;
41
41
  const lint_1 = require("../util/lint");
42
+ const string_1 = require("../util/string");
42
43
  const rect_1 = require("../lib/rect");
43
44
  const gapped_1 = require("../mixin/gapped");
44
45
  const noEscape_1 = require("../mixin/noEscape");
@@ -128,27 +129,31 @@ let ConverterFlagsToken = (() => {
128
129
  getUnknownFlags() {
129
130
  return new Set(this.#flags.filter(flag => /\{{3}[^{}]+\}{3}/u.test(flag)));
130
131
  }
132
+ /** 从解析设置中获取语言变体 */
133
+ #getVariants() {
134
+ return new Set((0, string_1.toLowerCase)(this.getAttribute('config').variants));
135
+ }
131
136
  /**
132
137
  * Get language coversion flags that specify a language variant
133
138
  *
134
139
  * 获取指定语言变体的转换标记
135
140
  */
136
141
  getVariantFlags() {
137
- const variants = new Set(this.getAttribute('config').variants);
138
- return new Set(this.#flags.filter(flag => variants.has(flag)));
142
+ const variants = this.#getVariants();
143
+ return new Set((0, string_1.toLowerCase)(this.#flags).filter(flag => variants.has(flag)));
139
144
  }
140
145
  /** @private */
141
146
  isInvalidFlag(flag, variant, unknown) {
142
147
  /* PRINT ONLY */
143
148
  PRINT: if (typeof flag === 'object') {
144
- const variants = new Set(this.getAttribute('config').variants);
149
+ const variants = this.#getVariants();
145
150
  flag = flag.text().trim();
146
- variant = this.#flags.some(f => variants.has(f)) ? variants : new Set();
151
+ variant = this.#flags.some(f => variants.has(f.toLowerCase())) ? variants : new Set();
147
152
  unknown = this.getUnknownFlags();
148
153
  }
149
154
  /* PRINT ONLY END */
150
155
  return Boolean(flag)
151
- && !variant.has(flag)
156
+ && !variant.has(flag.toLowerCase())
152
157
  && !unknown.has(flag)
153
158
  && (variant.size > 0 || !definedFlags.has(flag));
154
159
  }
@@ -93,7 +93,7 @@ let ConverterRuleToken = (() => {
93
93
  /* PRINT ONLY */
94
94
  /** language variant / 语言变体 */
95
95
  get variant() {
96
- LSP: return this.childNodes[this.length - 2]?.text().trim().toLowerCase() ?? '';
96
+ LSP: return this.childNodes[this.length - 2]?.text().trim() ?? '';
97
97
  }
98
98
  /* PRINT ONLY END */
99
99
  /* NOT FOR BROWSER */
@@ -149,7 +149,7 @@ let ConverterRuleToken = (() => {
149
149
  });
150
150
  __runInitializers(this, _instanceExtraInitializers);
151
151
  const i = rule.indexOf(':'), j = rule.slice(0, i).indexOf('=>'), v = j === -1 ? rule.slice(0, i) : rule.slice(j + 2, i);
152
- if (hasColon && config.variants.includes(v.trim().toLowerCase())) {
152
+ if (hasColon && config.variants.includes(v.trim())) {
153
153
  super.insertAt(new atom_1.AtomToken(v, 'converter-rule-variant', config, accum));
154
154
  super.insertAt(getRuleFromTo(rule.slice(i + 1), 'to', config, accum));
155
155
  if (j !== -1) {
@@ -1,7 +1,8 @@
1
1
  import { Token } from './index';
2
- import type { LintError, Config, TokenTypes } from '../base';
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 type GalleryImageTypes = 'gallery-image' | 'imagemap-image';
5
6
  /**
6
7
  * image parameter
7
8
  *
@@ -49,9 +50,9 @@ export declare abstract class ImageParameterToken extends Token {
49
50
  /**
50
51
  * @param str 图片参数
51
52
  * @param extension 文件扩展名
52
- * @param type 父节点类型
53
+ * @param type 图库节点类型
53
54
  */
54
- constructor(str: string, extension: string | undefined, type: TokenTypes | undefined, config: Config, accum?: Token[]);
55
+ constructor(str: string, extension: string | undefined, type: GalleryImageTypes | undefined, config: Config, accum?: Token[]);
55
56
  /**
56
57
  * Get the parameter value
57
58
  *
@@ -69,7 +69,7 @@ const getUrl = (link) => {
69
69
  }
70
70
  return new URL(link).href;
71
71
  };
72
- function validate(key, val, config, extOrType, halfParsed) {
72
+ function validate(key, val, config, extOrType, halfParsed, accum) {
73
73
  val = (0, string_1.removeComment)(val).trim();
74
74
  let value = val.replace(key === 'link' ? /\0\d+[tq]\x7F/gu : /\0\d+t\x7F/gu, '').trim();
75
75
  switch (key) {
@@ -77,6 +77,7 @@ function validate(key, val, config, extOrType, halfParsed) {
77
77
  return !value && Boolean(val) || /^(?:\d+x?|\d*x\d+)(?:\s*px)?$/u.test(value);
78
78
  case 'link': {
79
79
  const isGalleryImage = extOrType === 'gallery-image';
80
+ let nowiki = true;
80
81
  if (!value) {
81
82
  return val;
82
83
  }
@@ -85,8 +86,9 @@ function validate(key, val, config, extOrType, halfParsed) {
85
86
  }
86
87
  else if (value.startsWith('[[') && value.endsWith(']]')) {
87
88
  value = value.slice(2, -2);
89
+ nowiki = false;
88
90
  }
89
- const title = index_1.default.normalizeTitle(value, 0, false, config, { halfParsed, decode: true, selfLink: true, page: '' });
91
+ const title = index_1.default.normalizeTitle(value, 0, false, config, { halfParsed, decode: true, selfLink: true, page: '', nowiki }, accum);
90
92
  return title.valid ? title : isGalleryImage;
91
93
  }
92
94
  case 'lang':
@@ -147,12 +149,12 @@ let ImageParameterToken = (() => {
147
149
  }
148
150
  const value = super.text().trim();
149
151
  return debug_1.Shadow.run(() => {
150
- const config = this.getAttribute('config'), token = new index_2.Token(value, config);
152
+ const config = this.getAttribute('config'), accum = [], token = new index_2.Token(value, config, accum);
151
153
  token.parseOnce(0, this.getAttribute('include')).parseOnce();
152
154
  if (/^\0\d+m\x7F/u.test(token.firstChild.toString())) {
153
155
  return value;
154
156
  }
155
- const link = validate('link', value, config, this.parentNode?.type);
157
+ const link = validate('link', value, config, this.parentNode?.type, undefined, accum);
156
158
  return link === true ? undefined : link;
157
159
  }, index_1.default);
158
160
  }
@@ -226,7 +228,7 @@ let ImageParameterToken = (() => {
226
228
  /**
227
229
  * @param str 图片参数
228
230
  * @param extension 文件扩展名
229
- * @param type 父节点类型
231
+ * @param type 图库节点类型
230
232
  */
231
233
  constructor(str, extension, type, config, accum) {
232
234
  let mt;
@@ -235,7 +237,7 @@ let ImageParameterToken = (() => {
235
237
  mt = regex.exec(str);
236
238
  return mt
237
239
  && (mt.length !== 4
238
- || validate(key, mt[2], config, key === 'link' ? type : extension, true) !== false);
240
+ || validate(key, mt[2], config, key === 'link' ? type : extension, true, accum) !== false);
239
241
  });
240
242
  // @ts-expect-error mt already assigned
241
243
  if (param && mt) {
@@ -373,7 +375,13 @@ let ImageParameterToken = (() => {
373
375
  * 获取参数值
374
376
  */
375
377
  getValue() {
376
- LINT: return this.name === 'invalid' ? this.text() : this.#isVoid() || super.text();
378
+ LINT: {
379
+ const { name, childNodes } = this;
380
+ if (name === 'link') {
381
+ return (0, string_1.text)(childNodes.map(child => child.is('ext') && child.name === 'nowiki' ? child.innerText ?? '' : child));
382
+ }
383
+ return name === 'invalid' ? this.text() : this.#isVoid() || super.text();
384
+ }
377
385
  }
378
386
  /** @private */
379
387
  print() {
@@ -1,6 +1,7 @@
1
1
  import { LinkBaseToken } from './base';
2
2
  import { ImageParameterToken } from '../imageParameter';
3
- import type { TokenTypes, Config, LintError, AST } from '../../base';
3
+ import type { Config, LintError, AST } from '../../base';
4
+ import type { GalleryImageTypes } from '../imageParameter';
4
5
  import type { Token, AtomToken } from '../../internal';
5
6
  import { Title } from '../../lib/title';
6
7
  /**
@@ -15,7 +16,7 @@ export declare abstract class FileToken extends LinkBaseToken {
15
16
  abstract get lastChild(): AtomToken | ImageParameterToken;
16
17
  abstract get children(): [AtomToken, ...ImageParameterToken[]];
17
18
  abstract get lastElementChild(): AtomToken | ImageParameterToken;
18
- get type(): 'file' | 'gallery-image' | 'imagemap-image';
19
+ get type(): 'file' | GalleryImageTypes;
19
20
  /**
20
21
  * file extension
21
22
  *
@@ -45,9 +46,9 @@ export declare abstract class FileToken extends LinkBaseToken {
45
46
  * @param link 文件名
46
47
  * @param text 图片参数
47
48
  * @param delimiter `|`
48
- * @param type 节点类型
49
+ * @param type 图库节点类型
49
50
  */
50
- constructor(link: string, text?: string, config?: Config, accum?: Token[], delimiter?: string, type?: TokenTypes);
51
+ constructor(link: string, text?: string, config?: Config, accum?: Token[], delimiter?: string, type?: GalleryImageTypes);
51
52
  /**
52
53
  * Get all image parameter tokens
53
54
  *
@@ -49,6 +49,7 @@ const string_1 = require("../../util/string");
49
49
  const debug_1 = require("../../util/debug");
50
50
  const title_1 = require("../../lib/title");
51
51
  const cached_1 = require("../../mixin/cached");
52
+ const extension_1 = require("../../render/extension");
52
53
  const frame = new Map([
53
54
  ['manualthumb', 'Thumb'],
54
55
  ['frameless', 'Frameless'],
@@ -173,7 +174,7 @@ let FileToken = (() => {
173
174
  * @param link 文件名
174
175
  * @param text 图片参数
175
176
  * @param delimiter `|`
176
- * @param type 节点类型
177
+ * @param type 图库节点类型
177
178
  */
178
179
  constructor(link, text, config, accum = [], delimiter = '|', type) {
179
180
  super(link, undefined, config, accum, delimiter);
@@ -500,13 +501,13 @@ let FileToken = (() => {
500
501
  /* c8 ignore stop */
501
502
  /** @private */
502
503
  toHtmlInternal(opt) {
503
- 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({
504
+ const { link, width, height, type, parentNode } = this, file = this.getAttribute('title'), fr = this.getFrame(), manual = fr instanceof title_1.Title, isThumb = manual || fr === 'thumbnail', framed = fr === 'framed', visibleCaption = isThumb || framed || type === 'gallery-image', caption = this.getArg('caption')?.toHtmlInternal({
504
505
  ...opt,
505
506
  nowrap: true,
506
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({
507
508
  ...opt,
508
509
  nowrap: true,
509
- })) ?? 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}"`;
510
+ })) ?? titleFromCaption, horiz = this.getHorizAlign() ?? '', vert = this.getVertAlign() ?? '', gallery = type === 'gallery-image' && parentNode?.parentNode, mode = gallery && gallery.getAttr('mode')?.toLowerCase(), nolines = mode === 'nolines', slideshow = mode === 'slideshow', packed = extension_1.packedModes.has(mode), hasWidth = isInteger(width) && !packed, hasHeight = !nolines && !slideshow && 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}"`;
510
511
  let src;
511
512
  try {
512
513
  src = manual ? fr.getFileUrl() : file.getFileUrl(hasWidth && Number(width), hasHeight && Number(height));
@@ -514,7 +515,7 @@ let FileToken = (() => {
514
515
  catch {
515
516
  return '';
516
517
  }
517
- const img = `<img${alt && ` alt="${alt}"`} src="${src}" decoding="async" class="mw-file-element"${hasWidth ? ` width="${width}"` : ''}${hasHeight ? ` height="${height}"` : ''}>`;
518
+ const img = `<img${alt || this.hasArg('alt') ? ` alt="${alt}"` : ''}${isThumb && hasLink ? ` resource="${file.getUrl()}"` : ''} src="${src}" decoding="async"${hasWidth ? ` width="${width}"` : ''}${hasHeight ? ` height="${height}"` : ''} class="mw-file-element"${nolines || slideshow ? ` style="max-height: ${height}px"` : ''}>`;
518
519
  let href = '';
519
520
  if (link) {
520
521
  try {
@@ -534,15 +535,17 @@ let FileToken = (() => {
534
535
  const a = link
535
536
  ? `<a${href && ` href="${href}"`}${hasLink ? '' : ' class="mw-file-description"'}${titleAttr}${typeof link === 'string' ? ' rel="nofollow"' : ''}>${img}</a>`
536
537
  : `<span${titleAttr}>${img}</span>`;
537
- if (type !== 'gallery-image') {
538
+ if (gallery === false) {
538
539
  return horiz || visibleCaption
539
540
  ? `<figure${classAttr} typeof="mw:File${fr ? `/${manual ? 'Thumb' : frame.get(fr)}` : ''}">${a}<figcaption>${caption}</figcaption></figure>`
540
541
  : `<span${classAttr}>${a}</span>`;
541
542
  }
542
- const parent = this.parentNode, nolines = parent?.parentNode?.getAttr('mode')?.toLowerCase() === 'nolines', padding = nolines ? 0 : 30;
543
- 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')
544
- ? `<a href="${file.getUrl()}" class="galleryfilename galleryfilename-truncate" title="${file.title}">${file.main}</a>\n`
545
- : ''}${caption}</div>\n\t</li>`;
543
+ const padding = nolines ? 0 : 30, overlay = packed && mode !== 'packed';
544
+ return `\t\t<li class="gallerybox"${packed ? '' : ` style="width: ${Number(width) + padding + 5}px"`}>\n\t\t\t<div class="thumb"${packed
545
+ ? ''
546
+ : ` style="width: ${Number(width) + padding}px;${nolines || slideshow ? '' : ` height: ${Number(height) + padding}px;`}"`}><span>${a}</span></div>\n\t\t\t${overlay ? '<div class="gallerytextwrapper">' : ''}<div class="gallerytext">${gallery?.hasAttr('showfilename')
547
+ ? `<a href="${file.getUrl()}" class="galleryfilename galleryfilename-truncate" title="${(0, string_1.sanitizeId)(file.title)}">${file.main}</a>\n`
548
+ : ''}${caption}</div>${overlay ? '\n\t\t\t</div>' : ''}\n\t\t</li>`;
546
549
  }
547
550
  };
548
551
  })();
@@ -1,6 +1,7 @@
1
1
  import { NowikiBaseToken } from './base';
2
2
  import type { LintError } from '../../base';
3
3
  import type { AttributesToken, ExtToken, AstNodes } from '../../internal';
4
+ import type { TexvcReport } from '../../lib/document';
4
5
  /**
5
6
  * text-only token inside an extension tag
6
7
  *
@@ -46,9 +46,7 @@ class NowikiToken extends base_1.NowikiBaseToken {
46
46
  /** @private */
47
47
  lint(start = this.getAbsoluteIndex()) {
48
48
  LINT: {
49
- const { name, innerText,
50
- /* NOT FOR BROWSER ONLY */
51
- previousSibling, } = this, { lintConfig } = index_1.default;
49
+ const { name, innerText } = this, { lintConfig } = index_1.default;
52
50
  let rule = 'void-ext', s = lintConfig.getSeverity(rule, name);
53
51
  if (s && this.#lint()) {
54
52
  const e = (0, lint_1.generateForSelf)(this, { start }, rule, index_1.default.msg('nothing-in', name), s);
@@ -84,31 +82,9 @@ class NowikiToken extends base_1.NowikiBaseToken {
84
82
  rule = 'invalid-math';
85
83
  s = lintConfig.getSeverity(rule);
86
84
  if (s && constants_2.mathTags.has(name)) {
87
- const texvcjs = (0, document_1.loadTexvcjs)();
88
- if (texvcjs) {
89
- const isChem = name !== 'math', display = previousSibling?.getAttr('display') ?? 'block';
90
- let tex = innerText, n = 0;
91
- if (isChem) {
92
- tex = String.raw `\ce{${tex}}`;
93
- n = 4;
94
- }
95
- switch (display) {
96
- case 'block':
97
- tex = String.raw `{\displaystyle ${tex}}`;
98
- n += 15;
99
- break;
100
- case 'inline':
101
- tex = String.raw `{\textstyle ${tex}}`;
102
- n += 12;
103
- break;
104
- case 'linebreak':
105
- tex = String.raw `\[ ${tex} \]`;
106
- n += 3;
107
- // no default
108
- }
109
- const result = texvcjs.check(tex, {
110
- usemhchem: isChem || Boolean(previousSibling?.hasAttr('chem')),
111
- });
85
+ const report = this.texvcCheck();
86
+ if (report) {
87
+ const [result, n] = report;
112
88
  if (result.status === '+') {
113
89
  return [];
114
90
  }
@@ -133,6 +109,42 @@ class NowikiToken extends base_1.NowikiBaseToken {
133
109
  return key === 'invalid' ? this.#lint() : super.getAttribute(key);
134
110
  }
135
111
  /* PRINT ONLY END */
112
+ /* NOT FOR BROWSER ONLY */
113
+ /** @private */
114
+ texvcCheck() {
115
+ const texvcjs = (0, document_1.loadTexvcjs)();
116
+ if (!texvcjs) {
117
+ return undefined;
118
+ }
119
+ let tex = this.innerText, n = 0;
120
+ if (this.name !== 'math') {
121
+ tex = String.raw `\ce{${tex}}`;
122
+ n = 4;
123
+ }
124
+ switch (this.previousSibling?.getAttr('display') ?? 'block') {
125
+ case 'block':
126
+ tex = String.raw `{\displaystyle ${tex}}`;
127
+ n += 15;
128
+ break;
129
+ case 'inline':
130
+ tex = String.raw `{\textstyle ${tex}}`;
131
+ n += 12;
132
+ break;
133
+ case 'linebreak':
134
+ tex = String.raw `\[ ${tex} \]`;
135
+ n += 3;
136
+ // no default
137
+ }
138
+ return [
139
+ texvcjs.check(tex, {
140
+ usemathrm: true,
141
+ usemhchem: this.name !== 'math' || Boolean(this.previousSibling?.hasAttr('chem')),
142
+ }),
143
+ n,
144
+ tex,
145
+ ];
146
+ }
147
+ /* NOT FOR BROWSER ONLY END */
136
148
  /* NOT FOR BROWSER */
137
149
  /** @private */
138
150
  safeReplaceChildren(elements) {
@@ -1,3 +1,4 @@
1
+ import { BoundingRect } from '../../lib/rect';
1
2
  import Parser from '../../index';
2
3
  import { Token } from '../index';
3
4
  import { TagPairToken } from './index';
@@ -49,6 +49,7 @@ const attributes_1 = require("../attributes");
49
49
  const debug_1 = require("../../util/debug");
50
50
  const constants_1 = require("../../util/constants");
51
51
  const cached_1 = require("../../mixin/cached");
52
+ const nonVoidExt = new Set(['dynamicpagelist', 'templatedata', 'rss']);
52
53
  /**
53
54
  * extension tag
54
55
  *
@@ -214,16 +215,35 @@ let ExtToken = (() => {
214
215
  this.seal('closed', true);
215
216
  }
216
217
  /** @private */
218
+ lintRef(rect, severity) {
219
+ LINT: {
220
+ const refName = this.getAttr('name'), text = this.innerText?.trim();
221
+ let msg = '';
222
+ if (this.closest('ext#references')) {
223
+ if (!refName) {
224
+ msg = 'no-named-in-references';
225
+ }
226
+ else if (!text) {
227
+ msg = 'no-empty-in-references';
228
+ }
229
+ }
230
+ else if (!refName && !text) {
231
+ msg = this.hasAttr('details') ? 'ref-details' : 'ref-no-name';
232
+ }
233
+ return msg && (rect ? (0, lint_1.generateForSelf)(this, rect, 'invalid-ref', msg, severity) : msg);
234
+ }
235
+ }
236
+ /** @private */
217
237
  lint(start = this.getAbsoluteIndex(), re) {
218
238
  LINT: {
219
- const errors = super.lint(start, re), { lintConfig } = index_1.default, rect = new rect_1.BoundingRect(this, start);
220
- if (this.name !== 'nowiki') {
239
+ const errors = super.lint(start, re), { name } = this, { lintConfig } = index_1.default, rect = new rect_1.BoundingRect(this, start);
240
+ if (name !== 'nowiki') {
221
241
  const s = this.inHtmlAttrs(), rule = 'parsing-order', severity = s && lintConfig.getSeverity(rule, s === 2 ? 'ext' : 'templateInTable');
222
242
  if (severity) {
223
243
  errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'ext-in-html', severity));
224
244
  }
225
245
  }
226
- if (this.name === 'ref') {
246
+ if (name === 'ref') {
227
247
  let rule = 'var-anchor', s = lintConfig.getSeverity(rule, 'ref');
228
248
  if (s && this.closest('heading-title')) {
229
249
  errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'variable-anchor', s));
@@ -233,6 +253,19 @@ let ExtToken = (() => {
233
253
  if (s && this.closest('link-text,ext-link-text')) {
234
254
  errors.push((0, lint_1.generateForSelf)(this, rect, rule, 'ref-in-link', s));
235
255
  }
256
+ s = lintConfig.getSeverity('invalid-ref');
257
+ if (s) {
258
+ const e = this.lintRef(rect, s);
259
+ if (e) {
260
+ errors.push(e);
261
+ }
262
+ }
263
+ }
264
+ else {
265
+ const rule = 'void-ext', s = lintConfig.getSeverity(rule, name);
266
+ if (s && nonVoidExt.has(name) && !this.innerText) {
267
+ errors.push((0, lint_1.generateForSelf)(this, { start }, rule, index_1.default.msg('no-empty', name), s));
268
+ }
236
269
  }
237
270
  return errors;
238
271
  }
@@ -871,7 +871,7 @@ let TranscludeToken = (() => {
871
871
  if (type === 'template' && !name.startsWith('Special:')) {
872
872
  if (this.normalizeTitle(name, 0, { halfParsed: true, temporary: true }).valid) {
873
873
  const title = name.replaceAll('_', ' ');
874
- return `<a href="${this.#title.getUrl()}?action=edit&redlink=1" class="new" title="${title} (page does not exist)">${title}</a>`;
874
+ return `<a href="${this.#title.getUrl()}?action=edit&redlink=1" class="new" title="${(0, string_1.sanitizeId)(title)} (page does not exist)">${title}</a>`;
875
875
  }
876
876
  const str = this.text();
877
877
  return opt?.nowrap ? str.replaceAll('\n', ' ') : str;
@@ -1,16 +1,34 @@
1
1
  "use strict";
2
- var __importDefault = (this && this.__importDefault) || function (mod) {
3
- return (mod && mod.__esModule) ? mod : { "default": mod };
4
- };
5
2
  Object.defineProperty(exports, "__esModule", { value: true });
6
- const binary_search_1 = __importDefault(require("binary-search"));
7
3
  /**
8
4
  * 二分法查找索引
9
5
  * @param haystack 数组
10
6
  * @param needle 目标值
11
7
  * @param comparator 比较函数
8
+ * @author The Dark Sky Company, LLC <support@darkskyapp.com>
9
+ * @license CC0-1.0
10
+ * @see https://github.com/darkskyapp/binary-search/blob/master/index.js
12
11
  */
13
12
  exports.default = (haystack, needle, comparator) => {
14
- const found = (0, binary_search_1.default)(haystack, needle, comparator);
15
- return found < 0 ? ~found : found; // eslint-disable-line no-bitwise
13
+ let low = 0, high = haystack.length - 1;
14
+ while (low <= high) {
15
+ // The naive `low + high >>> 1` could fail for array lengths > 2**31
16
+ // because `>>>` converts its operands to int32. `low + (high - low >>> 1)`
17
+ // works for array lengths <= 2**32-1 which is also Javascript's max array
18
+ // length.
19
+ const mid = low + (high - low >>> 1), // eslint-disable-line no-bitwise
20
+ cmp = comparator(haystack[mid], needle);
21
+ if (cmp < 0) {
22
+ low = mid + 1;
23
+ }
24
+ else if (cmp > 0) {
25
+ high = mid - 1;
26
+ }
27
+ else {
28
+ // Key found.
29
+ return mid;
30
+ }
31
+ }
32
+ // Key not found.
33
+ return low;
16
34
  };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isInterwiki = exports.removeCommentLine = exports.newline = exports.sanitizeAlt = exports.sanitizeId = exports.sanitizeAttr = exports.sanitize = exports.normalizeSpace = exports.encode = exports.noWrap = exports.escapeRegExp = exports.print = exports.escape = exports.replaceEntities = exports.decodeNumber = exports.decodeHtml = exports.decodeHtmlBasic = exports.text = exports.removeComment = exports.tidy = exports.trimLc = exports.extUrlChar = exports.extUrlCharFirst = exports.zs = void 0;
3
+ exports.isInterwiki = exports.removeCommentLine = exports.newline = exports.sanitizeAlt = exports.sanitizeId = exports.sanitizeAttr = exports.sanitize = exports.normalizeSpace = exports.encode = exports.noWrap = exports.escapeRegExp = exports.print = exports.escape = exports.replaceEntities = exports.toLowerCase = exports.decodeNumber = exports.decodeHtml = exports.decodeHtmlBasic = exports.text = exports.removeComment = exports.tidy = exports.trimLc = exports.extUrlChar = exports.extUrlCharFirst = exports.zs = void 0;
4
4
  exports.restore = restore;
5
5
  /* NOT FOR BROWSER */
6
6
  const common_1 = require("@bhsd/common");
@@ -71,6 +71,12 @@ const decodeHtml = (str) => {
71
71
  exports.decodeHtml = decodeHtml;
72
72
  /** decode numbered HTML entities */
73
73
  exports.decodeNumber = factory(/&#(\d+|x[\da-f]+);/giu, (_, code) => String.fromCodePoint(Number((/^x/iu.test(code) ? '0' : '') + code)));
74
+ /**
75
+ * Convert an array of strings to lowercase
76
+ * @param str array of strings
77
+ */
78
+ const toLowerCase = (str) => str.map(s => s.toLowerCase());
79
+ exports.toLowerCase = toLowerCase;
74
80
  /* PRINT ONLY */
75
81
  const entities = {
76
82
  '&': 'amp',
@@ -1,6 +1,6 @@
1
1
  (() => {
2
2
  var _a;
3
- const version = '1.43.0', src = (_a = document.currentScript) === null || _a === void 0 ? void 0 : _a.src, file = /\/extensions\/dist\/base\.(?:min\.)?js$/u, CDN = src && file.test(src)
3
+ const version = '1.44.0', src = (_a = document.currentScript) === null || _a === void 0 ? void 0 : _a.src, file = /\/extensions\/dist\/base\.(?:min\.)?js$/u, CDN = src && file.test(src)
4
4
  ? src.replace(file, '')
5
5
  : `https://fastly.jsdelivr.net/npm/wikiparser-node@${version}`;
6
6
  const workerJS = () => {
@@ -1,6 +1,6 @@
1
1
  (() => {
2
2
  const codejar = (async () => {
3
- const { CodeJar } = 'CodeJar' in globalThis
3
+ const { CodeJar } = Object.hasOwn(globalThis, 'CodeJar')
4
4
  ? globalThis
5
5
  : await import('https://fastly.jsdelivr.net/npm/codejar-async');
6
6
  return (textbox, include, linenums) => {
package/i18n/en.json CHANGED
@@ -34,6 +34,7 @@
34
34
  "in-url": "$1 in URL",
35
35
  "inconsistent-table": "inconsistent table layout",
36
36
  "insecure-style": "insecure style",
37
+ "int-name": "name cannot be a simple integer",
37
38
  "invalid-attribute": "element containing an invalid attribute name",
38
39
  "invalid-category": "invalid category name",
39
40
  "invalid-content": "invalid content in <$1>",
@@ -55,6 +56,9 @@
55
56
  "missing-extension": "missing file extension",
56
57
  "missing-function": "missing Scribunto module function name",
57
58
  "newline": null,
59
+ "no-empty": "<$1> should not be empty",
60
+ "no-empty-in-references": "<ref> tag defined in <references> has no content",
61
+ "no-named-in-references": "<ref> tag defined in <references> has no name attribute",
58
62
  "no-self-closing": "no self-closing",
59
63
  "nonzero-tabindex": "nonzero tabindex",
60
64
  "nothing-in": "nothing should be in <$1>",
@@ -65,7 +69,10 @@
65
69
  "pipe-in-link": "additional \"|\" in the link text",
66
70
  "pipe-in-table": "additional \"|\" in a table cell",
67
71
  "redirect-like": "redirect-like syntax in a list item",
72
+ "ref-details": "a <ref> tag with details must contain content or point to a parent reference by name",
73
+ "ref-follow": "a <ref follow> tag that is the continuation of a previous one cannot be named individually or have details",
68
74
  "ref-in-link": "<ref> in an internal or external link",
75
+ "ref-no-name": "<ref> with no name must have content",
69
76
  "remove": null,
70
77
  "required-attribute": "required $1 attribute is missing",
71
78
  "template-in-link": "template in an internal link target",
package/i18n/zh-hans.json CHANGED
@@ -33,6 +33,7 @@
33
33
  "imagemap-without-image": "没有图像的<imagemap>",
34
34
  "in-url": "URL中的$1",
35
35
  "inconsistent-table": "不一致的表格布局",
36
+ "int-name": "name不能是单纯整数",
36
37
  "insecure-style": "不安全的样式",
37
38
  "invalid-attribute": "包含无效属性名称的元素",
38
39
  "invalid-category": "无效的分类名",
@@ -55,6 +56,9 @@
55
56
  "missing-extension": "缺少文件扩展名",
56
57
  "missing-function": "缺少Scribunto模块函数名",
57
58
  "newline": "换行",
59
+ "no-empty": "<$1>不应为空",
60
+ "no-empty-in-references": "<references>内定义的<ref>标签没有内容",
61
+ "no-named-in-references": "<references>内定义的<ref>标签没有设置name属性",
58
62
  "no-self-closing": "移除自封闭",
59
63
  "nonzero-tabindex": "非零的tabindex",
60
64
  "nothing-in": "<$1>不应有任何内容",
@@ -65,7 +69,10 @@
65
69
  "pipe-in-link": "链接文本中的额外\"|\"",
66
70
  "pipe-in-table": "表格单元格中的额外\"|\"",
67
71
  "redirect-like": "列表项中的疑似重定向语法",
72
+ "ref-details": "带有详细信息的<ref>标签必须包含内容或通过名称指向父级参考",
73
+ "ref-follow": "作为前一个标签的延续的<ref follow>标签不能被单独命名或包含详细信息",
68
74
  "ref-in-link": "内部或外部链接中的<ref>",
75
+ "ref-no-name": "没有name的<ref>必须有内容",
69
76
  "remove": "移除",
70
77
  "required-attribute": "缺少必需的$1属性",
71
78
  "template-in-link": "内部链接目标中的模板",
package/i18n/zh-hant.json CHANGED
@@ -33,6 +33,7 @@
33
33
  "imagemap-without-image": "<imagemap>沒有圖片",
34
34
  "in-url": "URL中有$1",
35
35
  "inconsistent-table": "表格版面不一致",
36
+ "int-name": "name屬性不能使用數字",
36
37
  "insecure-style": "不安全的樣式",
37
38
  "invalid-attribute": "包含無效屬性名稱的元素",
38
39
  "invalid-category": "無效的分類名",
@@ -55,6 +56,9 @@
55
56
  "missing-extension": "缺少副檔名",
56
57
  "missing-function": "缺少Scribunto模組函式名稱",
57
58
  "newline": "換行",
59
+ "no-empty": "<$1>不應為空",
60
+ "no-empty-in-references": "<references>內定義的<ref>標籤沒有內容",
61
+ "no-named-in-references": "<references> 中定義的 <ref> 沒有設定 name 屬性",
58
62
  "no-self-closing": "移除自封閉",
59
63
  "nonzero-tabindex": "非零的tabindex",
60
64
  "nothing-in": "<$1>不應有任何內容",
@@ -65,7 +69,10 @@
65
69
  "pipe-in-link": "連結文字有額外的\"|\"字元",
66
70
  "pipe-in-table": "表格儲存格有額外的\"|\"字元",
67
71
  "redirect-like": "列表項中的疑似重新導向語法",
72
+ "ref-details": "一個帶有詳細資訊的 <ref> 標籤必須包含內容、或透過名稱指向父級參考",
73
+ "ref-follow": "作為前一個延續的 <ref follow> 標籤,不能單獨命名或包含詳細資訊",
68
74
  "ref-in-link": "內部或外部連結裡的<ref>",
75
+ "ref-no-name": "沒有名稱的<ref>必須要有內容",
69
76
  "remove": "移除",
70
77
  "required-attribute": "缺少必需的$1屬性",
71
78
  "template-in-link": "內部連結目標中的模板",