wikiparser-node 1.20.1 → 1.20.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -227,7 +227,7 @@ index_2.Token.prototype.toHtml = /** @implements */ function () {
227
227
  const openMatch = openRegex.test(line), closeMatch = closeRegex.test(line);
228
228
  if (openMatch || closeMatch) {
229
229
  const blockquote = /<(\/?)blockquote[\s>](?!.*<\/?blockquote[\s>])/iu.exec(line)?.[1];
230
- inBlockquote = blockquote === undefined ? inBlockquote : blockquote === '';
230
+ inBlockquote = blockquote === undefined ? inBlockquote : !blockquote;
231
231
  pendingPTag = false;
232
232
  output += closeParagraph();
233
233
  inBlockElem = !closeMatch;
@@ -116,7 +116,6 @@ exports.default = async (site, url, force, internal) => {
116
116
  ...ns.map(([id, canonical]) => [canonical.toLowerCase(), Number(id)]),
117
117
  ...namespacealiases.filter(({ id }) => filterGadget(id)).map(({ id, alias }) => [alias.toLowerCase(), id]),
118
118
  ]),
119
- functionHook: [...functionhooks.map(s => s.toLowerCase()), 'msgnw'],
120
119
  articlePath: articlepath,
121
120
  };
122
121
  config.doubleUnderscore[0] = [];
@@ -124,6 +123,9 @@ exports.default = async (site, url, force, internal) => {
124
123
  Object.assign(config.parserFunction[0], (0, cm_1.getConfig)(magicwords, ({ name }) => name === 'msgnw'));
125
124
  config.parserFunction[2] = getAliases(magicwords, new Set(['msg', 'raw']));
126
125
  config.parserFunction[3] = getAliases(magicwords, new Set(['subst', 'safesubst']));
126
+ if (!mwConfig.functionHooks) {
127
+ Object.assign(config, { functionHook: [...functionhooks.map(s => s.toLowerCase()), 'msgnw'] });
128
+ }
127
129
  if (!mwConfig.variableIDs) {
128
130
  const { query: { variables } } = await (await fetch(`${url}/api.php?${new URLSearchParams({ ...params, siprop: 'variables' }).toString()}`)).json();
129
131
  Object.assign(config, { variable: [...new Set([...variables, '='])] });
package/dist/index.js CHANGED
@@ -26,17 +26,20 @@ const rootRequire = (file, dir) => require(path_1.default.isAbsolute(file)
26
26
  ? /* istanbul ignore next */ file
27
27
  : path_1.default.join('..', file.includes('/') ? '' : dir, file));
28
28
  /* NOT FOR BROWSER ONLY END */
29
+ /* PRINT ONLY */
30
+ let viewOnly = false;
31
+ /* PRINT ONLY END */
29
32
  /* NOT FOR BROWSER */
30
33
  const promises = [Promise.resolve()];
31
34
  /^(zh|en)\s*:/diu; // eslint-disable-line @typescript-eslint/no-unused-expressions
32
35
  const getInterwikiRegex = (0, common_1.getRegex)(interwiki => new RegExp(String.raw `^(${interwiki.join('|')})\s*:`, 'diu'));
33
- let viewOnly = false, redirectMap = new redirectMap_1.RedirectMap();
36
+ let redirectMap = new redirectMap_1.RedirectMap();
34
37
  /* NOT FOR BROWSER END */
35
38
  const Parser = {
36
39
  config: 'default',
37
40
  i18n: undefined,
38
41
  rules: base_1.rules,
39
- /* NOT FOR BROWSER */
42
+ /* PRINT ONLY */
40
43
  /** @implements */
41
44
  get viewOnly() {
42
45
  return viewOnly;
@@ -47,6 +50,8 @@ const Parser = {
47
50
  }
48
51
  viewOnly = value;
49
52
  },
53
+ /* PRINT ONLY END */
54
+ /* NOT FOR BROWSER */
50
55
  /** @implements */
51
56
  get redirects() {
52
57
  return redirectMap;
@@ -251,7 +256,7 @@ const Parser = {
251
256
  LSP: { // eslint-disable-line no-unused-labels
252
257
  const mod = require('./lib/lsp');
253
258
  const { LanguageService, tasks } = mod;
254
- Parser.viewOnly = true;
259
+ this.viewOnly = true;
255
260
  return tasks.get(uri) ?? new LanguageService(uri);
256
261
  }
257
262
  },
@@ -314,8 +319,8 @@ const Parser = {
314
319
  catch { }
315
320
  }
316
321
  for (const [name, filePath] of entries) {
317
- if (name in globalThis) { // eslint-disable-line es-x/no-global-this
318
- // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access, es-x/no-global-this
322
+ if (name in globalThis) {
323
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-member-access
319
324
  Object.assign(globalThis, { [name]: require(filePath)[name] });
320
325
  }
321
326
  }
@@ -104,7 +104,7 @@ let AstElement = (() => {
104
104
  }
105
105
  /** invisible / 不可见 */
106
106
  get hidden() {
107
- return this.text() === '';
107
+ return !this.text();
108
108
  }
109
109
  /** height of the inner / 内部高度 */
110
110
  get clientHeight() {
package/dist/lib/lsp.js CHANGED
@@ -489,7 +489,7 @@ class LanguageService {
489
489
  if (!this.#completionConfig || this.#completionConfig[1] !== this.config) {
490
490
  this.config ??= index_1.default.getConfig();
491
491
  const { nsid, ext, html, parserFunction: [insensitive, sensitive, ...other], doubleUnderscore, protocol, img, } = this.config, tags = new Set([ext, html].flat(2));
492
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
492
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
493
493
  /(?:<\/?(\w*)|(\{{2,4}|\[\[)\s*([^|{}<>[\]\s][^|{}<>[\]#]*)?|(__(?:(?!__)[\p{L}\p{N}_])*)|(?<!\[)\[([a-z:/]*)|\[\[\s*(?:file|image)\s*:[^[\]{}<>]+\|([^[\]{}<>|=]*)|<(\w+)(?:\s(?:[^<>{}|=\s]+(?:\s*=\s*(?:[^\s"']\S*|(["']).*?\8))?(?=\s))*)?\s(\w*))$/iu;
494
494
  const re = new RegExp('(?:' // eslint-disable-line prefer-template
495
495
  + String.raw `<(\/?\w*)` // tag
package/dist/lib/node.js CHANGED
@@ -7,11 +7,13 @@ exports.AstNode = void 0;
7
7
  /* eslint-disable @typescript-eslint/no-base-to-string */
8
8
  const lint_1 = require("../util/lint");
9
9
  const debug_1 = require("../util/debug");
10
+ /* PRINT ONLY */
11
+ const index_1 = __importDefault(require("../index"));
12
+ /* PRINT ONLY END */
10
13
  /* NOT FOR BROWSER */
11
14
  const strict_1 = __importDefault(require("assert/strict"));
12
15
  const events_1 = require("events");
13
16
  const constants_1 = require("../util/constants");
14
- const index_1 = __importDefault(require("../index"));
15
17
  /**
16
18
  * Node-like
17
19
  *
@@ -97,7 +99,7 @@ class AstNode {
97
99
  return true;
98
100
  }
99
101
  let { nextSibling } = this;
100
- while (nextSibling?.type === 'text' && nextSibling.data.trim() === '') {
102
+ while (nextSibling?.type === 'text' && !nextSibling.data.trim()) {
101
103
  ({ nextSibling } = nextSibling);
102
104
  }
103
105
  return nextSibling === undefined && parentNode.eof;
package/dist/lib/text.js CHANGED
@@ -52,10 +52,10 @@ const debug_1 = require("../util/debug");
52
52
  const readOnly_1 = require("../mixin/readOnly");
53
53
  /* NOT FOR BROWSER END */
54
54
  const sp = String.raw `[${string_1.zs}\t]*`, source = String.raw `<\s*(?:/\s*)?([a-z]\w*)|\{+|\}+|\[{2,}|\[(?![^[]*?\])|((?:^|\])[^[]*?)\]+|(?:rfc|pmid)(?=[-::]?${sp}\d)|isbn(?=[-::]?${sp}(?:\d(?:${sp}|-)){6})`;
55
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
55
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
56
56
  /<\s*(?:\/\s*)?([a-z]\w*)|\{+|\}+|\[{2,}|\[(?![^[]*?\])|((?:^|\])[^[]*?)\]+|https?[:/]\/+/giu;
57
57
  const errorSyntax = new RegExp(String.raw `${source}|https?[:/]/+`, 'giu');
58
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
58
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
59
59
  /^https?:\/\/(?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])[^[\]<>"\t\n\p{Zs}]*\.(?:gif|png|jpg|jpeg)$/iu;
60
60
  const errorSyntaxUrl = new RegExp(source, 'giu'), noLinkTypes = new Set(['attr-value', 'ext-link-text', 'link-text']), regexes = {
61
61
  '[': /[[\]]/u,
@@ -126,7 +126,7 @@ const errorSyntaxUrl = new RegExp(source, 'giu'), noLinkTypes = new Set(['attr-v
126
126
  ]);
127
127
  let wordRegex;
128
128
  try {
129
- // eslint-disable-next-line prefer-regex-literals, es-x/no-regexp-unicode-property-escapes
129
+ // eslint-disable-next-line prefer-regex-literals
130
130
  wordRegex = new RegExp(String.raw `[\p{L}\p{N}_]`, 'u');
131
131
  }
132
132
  catch /* istanbul ignore next */ {
@@ -211,6 +211,7 @@ let AstText = (() => {
211
211
  isHtmlAttrVal = true;
212
212
  }
213
213
  else if (tag === 'ref' && (grandName === 'name' || grandName === 'extends' || grandName === 'follow')
214
+ || grandName === 'group' && (tag === 'ref' || tag === 'references')
214
215
  || tag === 'choose' && (grandName === 'before' || grandName === 'after')) {
215
216
  return [];
216
217
  }
@@ -226,7 +227,7 @@ let AstText = (() => {
226
227
  return [];
227
228
  }
228
229
  errorRegex.lastIndex = 0;
229
- const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), tags = new Set([
230
+ const errors = [], nextType = nextSibling?.type, nextName = nextSibling?.name, previousType = previousSibling?.type, root = this.getRootNode(), rootStr = root.toString(), { ext, html, variants } = root.getAttribute('config'), { top, left } = root.posFromIndex(start), tags = new Set([
230
231
  'onlyinclude',
231
232
  'noinclude',
232
233
  'includeonly',
@@ -245,7 +246,8 @@ let AstText = (() => {
245
246
  error = error.slice(length);
246
247
  }
247
248
  error = error.toLowerCase();
248
- const { 0: char, length } = error, magicLink = char === 'r' || char === 'p' || char === 'i';
249
+ const [char] = error, magicLink = char === 'r' || char === 'p' || char === 'i';
250
+ let { length } = error;
249
251
  if (char === '<' && !tags.has(tag.toLowerCase())
250
252
  || char === '[' && type === 'ext-link-text' && (/&(?:rbrack|#93|#x5[Dd];);/u.test(data.slice(index + 1))
251
253
  || nextSibling?.is('ext') && nextName === 'nowiki'
@@ -256,12 +258,14 @@ let AstText = (() => {
256
258
  else if (char === ']' && (index || length > 1)) {
257
259
  errorRegex.lastIndex--;
258
260
  }
259
- const startIndex = start + index, endIndex = startIndex + length, nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1], severity = length > 1 && !(char === '<' && (/^<\s/u.test(error) || !/[\s/>]/u.test(nextChar ?? '') || disallowedTags.has(tag))
261
+ let startIndex = start + index, endIndex = startIndex + length;
262
+ const nextChar = rootStr[endIndex], previousChar = rootStr[startIndex - 1];
263
+ let severity = length > 1 && !(char === '<' && (/^<\s/u.test(error) || !/[\s/>]/u.test(nextChar ?? '') || disallowedTags.has(tag))
260
264
  || isHtmlAttrVal && (char === '[' || char === ']')
261
265
  || magicLink && type === 'parameter-value'
262
266
  || /^(?:rfc|pmid|isbn)$/iu.test(error))
263
- || char === '{' && (nextChar === char || previousChar === '-')
264
- || char === '}' && (previousChar === char || nextChar === '-')
267
+ || char === '{' && (nextChar === char || previousChar === '-' && variants.length > 0)
268
+ || char === '}' && (previousChar === char || nextChar === '-' && variants.length > 0)
265
269
  || char === '[' && (type === 'ext-link-text' || nextType === 'free-ext-link' && !data.slice(index + 1).trim())
266
270
  || char === ']' && previousType === 'free-ext-link'
267
271
  && !data.slice(0, index).includes(']')
@@ -288,9 +292,26 @@ let AstText = (() => {
288
292
  if (magicLink) {
289
293
  error = error.toUpperCase();
290
294
  }
295
+ else if (error === '{' && previousChar === '-' && severity === 'error') {
296
+ severity = 'warning';
297
+ if (index > 0) {
298
+ error = '-{';
299
+ index--;
300
+ startIndex--;
301
+ length = 2;
302
+ }
303
+ }
304
+ else if (error === '}' && nextChar === '-' && severity === 'error') {
305
+ severity = 'warning';
306
+ if (index < data.length - 1) {
307
+ error = '}-';
308
+ endIndex++;
309
+ length = 2;
310
+ }
311
+ }
291
312
  const pos = this.posFromIndex(index), { line: startLine, character: startCol } = (0, lint_1.getEndPos)(top, left, pos.top + 1, pos.left), e = {
292
313
  rule: ruleMap[char],
293
- message: index_1.default.msg('lonely "$1"', magicLink || char === 'h' ? error : char),
314
+ message: index_1.default.msg('lonely "$1"', magicLink || char === 'h' || error === '-{' || error === '}-' ? error : char),
294
315
  severity,
295
316
  startIndex,
296
317
  endIndex,
@@ -480,7 +501,6 @@ let AstText = (() => {
480
501
  }
481
502
  }
482
503
  else if (mt && nextSibling.type === 'category') {
483
- // eslint-disable-next-line es-x/no-string-prototype-trimstart-trimend
484
504
  const trimmed = this.data.trimEnd();
485
505
  if (this.data !== trimmed) {
486
506
  const { length } = trimmed;
@@ -501,7 +521,6 @@ let AstText = (() => {
501
521
  }
502
522
  }
503
523
  else {
504
- // eslint-disable-next-line es-x/no-string-prototype-trimstart-trimend
505
524
  this.#setData(this.data.trimEnd());
506
525
  }
507
526
  for (const space of spaces) {
package/dist/lib/title.js CHANGED
@@ -88,7 +88,6 @@ class Title {
88
88
  }
89
89
  catch { }
90
90
  }
91
- // eslint-disable-next-line es-x/no-string-prototype-trimstart-trimend
92
91
  this.#fragment = (0, string_1.decodeHtml)(fragment).replace(/[_ ]+/gu, ' ').trimEnd()
93
92
  .replaceAll(' ', '_');
94
93
  }
@@ -15,7 +15,7 @@ const constants_1 = require("../util/constants");
15
15
  * @param inFile 是否在图链中
16
16
  */
17
17
  const parseExternalLinks = (wikitext, config, accum, inFile) => {
18
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
18
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
19
19
  /\[((?:ftp:\/\/|\/\/)(?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])[^[\]<>"\t\n\p{Zs}]*(?=[[\]<>"\t\p{Zs}]|\0\d))(\p{Zs}*(?!\p{Zs}))([^\]\n]*)\]/giu;
20
20
  config.regexExternalLinks ??= new RegExp(String.raw `\[(\0\d+f\x7F|(?:(?:${config.protocol}|//)${string_1.extUrlCharFirst}|\0\d+m\x7F)${string_1.extUrlChar}(?=[[\]<>"\t${string_1.zs}]|\0\d))([${string_1.zs}]*(?![${string_1.zs}]))([^\]\x01-\x08\x0A-\x1F\uFFFD]*)\]`, 'giu');
21
21
  return wikitext.replace(config.regexExternalLinks, (_, url, space, text) => {
@@ -16,7 +16,7 @@ const space = String.raw `[${string_1.zs}\t]|&nbsp;|&#0*160;|&#x0*a0;`, sp = `(?
16
16
  const parseMagicLinks = (wikitext, config, accum) => {
17
17
  if (!config.regexMagicLinks) {
18
18
  try {
19
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
19
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
20
20
  /(^|[^\p{L}\p{N}_])(?:(?:ftp:\/\/|http:\/\/)((?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])[^[\]<>"\0\t\n\p{Zs}]*)|(?:rfc|pmid)[\p{Zs}\t]+\d+\b|isbn[\p{Zs}\t]+(?:97[89][\p{Zs}\t-]?)?(?:\d[\p{Zs}\t-]?){9}[\dx]\b)/giu;
21
21
  config.regexMagicLinks = new RegExp(String.raw `(^|[^\p{L}\p{N}_])(?:(?:${config.protocol})(${string_1.extUrlCharFirst}${string_1.extUrlChar})|${magicLinkPattern})`, 'giu');
22
22
  }
@@ -143,11 +143,11 @@ const matches = (token, step, scope, has) => {
143
143
  case ':header':
144
144
  return type === 'heading';
145
145
  case ':hidden':
146
- return token.text() === '';
146
+ return !token.text();
147
147
  case ':visible':
148
- return token.text() !== '';
148
+ return Boolean(token.text());
149
149
  case ':only-whitespace':
150
- return token.text().trim() === '';
150
+ return !token.text().trim();
151
151
  case ':any-link':
152
152
  return type === 'link'
153
153
  || type === 'redirect-target'
@@ -158,7 +158,7 @@ const matches = (token, step, scope, has) => {
158
158
  case ':local-link':
159
159
  return (type === 'link' || type === 'file' || type === 'gallery-image')
160
160
  && attributes.link instanceof title_1.Title
161
- && attributes.link.title === '';
161
+ && !attributes.link.title;
162
162
  case ':invalid':
163
163
  return attributes.invalid;
164
164
  case ':valid':
@@ -380,7 +380,7 @@ const checkToken = (selector, scope, has) => (token) => {
380
380
  };
381
381
  while (mt) {
382
382
  let { 0: syntax, index } = mt;
383
- if (syntax.trim() === '') {
383
+ if (!syntax.trim()) {
384
384
  index += syntax.length;
385
385
  const char = sanitized[index];
386
386
  syntax = grouping.has(char) ? char : '';
package/dist/src/arg.js CHANGED
@@ -142,13 +142,6 @@ let ArgToken = (() => {
142
142
  /** @private */
143
143
  lint(start = this.getAbsoluteIndex(), re) {
144
144
  const { childNodes: [argName, argDefault, ...rest] } = this;
145
- if (!this.getAttribute('include')) {
146
- const e = (0, lint_1.generateForSelf)(this, { start }, 'no-arg', 'unexpected template argument');
147
- if (argDefault) {
148
- e.suggestions = [{ range: [start, e.endIndex], text: argDefault.text(), desc: 'expand' }];
149
- }
150
- return [e];
151
- }
152
145
  argName.setAttribute('aIndex', start + 3);
153
146
  const errors = argName.lint(start + 3, re);
154
147
  if (argDefault) {
@@ -172,6 +165,13 @@ let ArgToken = (() => {
172
165
  return e;
173
166
  }));
174
167
  }
168
+ if (!this.getAttribute('include')) {
169
+ const e = (0, lint_1.generateForSelf)(this, { start }, 'no-arg', 'unexpected template argument', 'warning');
170
+ if (argDefault) {
171
+ e.suggestions = [{ range: [start, e.endIndex], text: argDefault.text(), desc: 'expand' }];
172
+ }
173
+ errors.push(e);
174
+ }
175
175
  return errors;
176
176
  }
177
177
  /** @private */
@@ -28,7 +28,7 @@ const toAttributeType = (type) => type.slice(0, -1);
28
28
  const toDirty = (type) => `${toAttributeType(type)}-dirty`;
29
29
  let wordRegex;
30
30
  try {
31
- // eslint-disable-next-line prefer-regex-literals, es-x/no-regexp-unicode-property-escapes
31
+ // eslint-disable-next-line prefer-regex-literals
32
32
  wordRegex = new RegExp(String.raw `[\p{L}\p{N}]`, 'u');
33
33
  }
34
34
  catch /* istanbul ignore next */ {
@@ -182,7 +182,6 @@ let ExtLinkToken = (() => {
182
182
  && length > 1
183
183
  && (firstChild?.type === 'text' || firstChild?.type === 'converter')
184
184
  // 都替换成`<`肯定不对,但无妨
185
- // eslint-disable-next-line es-x/no-regexp-unicode-property-escapes
186
185
  && /^[^[\]<>"\0-\x1F\x7F\p{Zs}\uFFFD]/u
187
186
  .test(lastChild.text().replace(/&[lg]t;/u, '<'))) {
188
187
  this.#space = ' ';
package/dist/src/html.js CHANGED
@@ -43,10 +43,12 @@ const debug_1 = require("../util/debug");
43
43
  const rect_1 = require("../lib/rect");
44
44
  const attributesParent_1 = require("../mixin/attributesParent");
45
45
  const index_1 = require("./index");
46
+ /* PRINT ONLY */
47
+ const index_2 = __importDefault(require("../index"));
48
+ /* PRINT ONLY END */
46
49
  /* NOT FOR BROWSER */
47
50
  const constants_1 = require("../util/constants");
48
51
  const fixed_1 = require("../mixin/fixed");
49
- const index_2 = __importDefault(require("../index"));
50
52
  const magicWords = new Set(['if', 'ifeq', 'ifexpr', 'ifexist', 'iferror', 'switch']), formattingTags = new Set([
51
53
  'b',
52
54
  'big',
@@ -15,7 +15,7 @@ const constants_1 = require("../util/constants");
15
15
  /* NOT FOR BROWSER END */
16
16
  /^(?:ftp:\/\/|\/\/|\0\d+m\x7F)/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
17
17
  const getUrlLikeRegex = (0, common_1.getRegex)(protocol => new RegExp(String.raw `^(?:${protocol}|//|\0\d+m\x7F)`, 'iu'));
18
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
18
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
19
19
  /^(?:(?:ftp:\/\/|\/\/)(?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])|\0\d+m\x7F)[^[\]<>"\0\t\n\p{Zs}]*$/iu;
20
20
  const getUrlRegex = (0, common_1.getRegex)(protocol => new RegExp(String.raw `^(?:(?:${protocol}|//)${string_1.extUrlCharFirst}|\0\d+m\x7F)${string_1.extUrlChar}$`, 'iu'));
21
21
  /* eslint-disable @typescript-eslint/no-unused-expressions */
@@ -233,7 +233,7 @@ let LinkBaseToken = (() => {
233
233
  }
234
234
  }
235
235
  if (fragment !== undefined && !isLink(type)) {
236
- const e = (0, lint_1.generateForChild)(target, rect, 'no-ignored', 'useless fragment'), j = target.childNodes.findIndex(c => c.type === 'text' && c.data.includes('#')), textNode = target.childNodes[j];
236
+ const e = (0, lint_1.generateForChild)(target, rect, 'no-ignored', 'useless fragment', 'warning'), j = target.childNodes.findIndex(c => c.type === 'text' && c.data.includes('#')), textNode = target.childNodes[j];
237
237
  if (textNode) {
238
238
  e.fix = {
239
239
  range: [
@@ -14,13 +14,12 @@ const string_1 = require("../../util/string");
14
14
  const debug_1 = require("../../util/debug");
15
15
  const constants_1 = require("../../util/constants");
16
16
  const title_1 = require("../../lib/title");
17
- /* NOT FOR BROWSER END */
18
17
  const frame = new Map([
19
18
  ['manualthumb', 'Thumb'],
20
19
  ['frameless', 'Frameless'],
21
20
  ['framed', 'Frame'],
22
21
  ['thumbnail', 'Thumb'],
23
- ]), 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']);
22
+ ]), 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']);
24
23
  /**
25
24
  * a more sophisticated string-explode function
26
25
  * @param str string to be exploded
@@ -45,6 +44,15 @@ const explode = (str) => {
45
44
  exploded.push(str.slice(lastIndex));
46
45
  return exploded;
47
46
  };
47
+ /**
48
+ * filter out the image parameters that are not of the specified type
49
+ * @param args image parameter tokens
50
+ * @param types token types to be filtered
51
+ */
52
+ const filterArgs = (args, types) => args.filter(({ childNodes }) => {
53
+ const visibleNodes = childNodes.filter(node => node.text().trim());
54
+ return visibleNodes.length !== 1 || !types.has(visibleNodes[0].type);
55
+ });
48
56
  /**
49
57
  * image
50
58
  *
@@ -125,10 +133,7 @@ class FileToken extends base_1.LinkBaseToken {
125
133
  }
126
134
  /** @private */
127
135
  lint(start = this.getAbsoluteIndex(), re) {
128
- const errors = super.lint(start, re), args = this.getAllArgs().filter(({ childNodes }) => {
129
- const visibleNodes = childNodes.filter(node => node.text().trim());
130
- return visibleNodes.length !== 1 || visibleNodes[0].type !== 'arg';
131
- }), keys = [...new Set(args.map(({ name }) => name))], frameKeys = keys.filter(key => frame.has(key)), horizAlignKeys = keys.filter(key => horizAlign.has(key)), vertAlignKeys = keys.filter(key => vertAlign.has(key)), [fr] = frameKeys, unscaled = fr === 'framed' || fr === 'manualthumb', rect = new rect_1.BoundingRect(this, start);
136
+ const errors = super.lint(start, re), args = filterArgs(this.getAllArgs(), argTypes), keys = [...new Set(args.map(({ name }) => name))], frameKeys = keys.filter(key => frame.has(key)), horizAlignKeys = keys.filter(key => horizAlign.has(key)), vertAlignKeys = keys.filter(key => vertAlign.has(key)), [fr] = frameKeys, unscaled = fr === 'framed' || fr === 'manualthumb', rect = new rect_1.BoundingRect(this, start);
132
137
  if (this.closest('ext-link-text')
133
138
  && this.getValue('link')?.trim() !== '') {
134
139
  errors.push((0, lint_1.generateForSelf)(this, rect, 'nested-link', 'internal link in an external link'));
@@ -152,8 +157,8 @@ class FileToken extends base_1.LinkBaseToken {
152
157
  * @param p1 替换$1
153
158
  * @param severity 错误等级
154
159
  */
155
- const generate = (msg, p1, severity) => (arg) => {
156
- const e = (0, lint_1.generateForChild)(arg, rect, 'no-duplicate', index_1.default.msg(`${msg} image $1 parameter`, p1), severity);
160
+ const generate = (msg, p1, severity = true) => (arg) => {
161
+ const isError = typeof severity === 'function' ? severity(arg) : severity, e = (0, lint_1.generateForChild)(arg, rect, 'no-duplicate', index_1.default.msg(`${msg} image $1 parameter`, p1), isError ? 'error' : 'warning');
157
162
  e.suggestions = [{ desc: 'remove', range: [e.startIndex - 1, e.endIndex], text: '' }];
158
163
  return e;
159
164
  };
@@ -162,15 +167,21 @@ class FileToken extends base_1.LinkBaseToken {
162
167
  if (key === 'invalid' || key === 'width' && unscaled) {
163
168
  continue;
164
169
  }
170
+ const isCaption = key === 'caption';
165
171
  let relevantArgs = args.filter(({ name }) => name === key);
166
- if (key === 'caption') {
172
+ if (isCaption) {
167
173
  relevantArgs = [
168
174
  ...relevantArgs.slice(0, -1).filter(arg => arg.text()),
169
175
  ...relevantArgs.slice(-1),
170
176
  ];
171
177
  }
172
178
  if (relevantArgs.length > 1) {
173
- errors.push(...relevantArgs.map(generate('duplicated', key, key === 'caption' && extension && !extensions.has(extension) ? 'warning' : 'error')));
179
+ let severity = !isCaption || !extension || extensions.has(extension);
180
+ if (isCaption && severity) {
181
+ const plainArgs = filterArgs(relevantArgs, transclusion);
182
+ severity = plainArgs.length > 1 && ((arg) => plainArgs.includes(arg));
183
+ }
184
+ errors.push(...relevantArgs.map(generate('duplicated', key, severity)));
174
185
  }
175
186
  }
176
187
  if (frameKeys.length > 1) {
@@ -50,15 +50,15 @@ const constants_1 = require("../util/constants");
50
50
  const html_1 = require("../util/html");
51
51
  const syntax_1 = require("../mixin/syntax");
52
52
  const space = String.raw `(?:[${string_1.zs}\t]|&nbsp;|&#0*160;|&#[xX]0*[aA]0;)`;
53
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
53
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
54
54
  /(?:[\p{Zs}\t]|&nbsp;|&#0*160;|&#[xX]0*[aA]0;)+/gu;
55
55
  const spaceRegex = new RegExp(`${space}+`, 'gu');
56
56
  /* NOT FOR BROWSER */
57
57
  const spdash = String.raw `(?:[\p{Zs}\t-]|&nbsp;|&#0*160;|&#[xX]0*[aA]0;)`;
58
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
58
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
59
59
  /^(ISBN)[\p{Zs}\t]+(?:97[89][\p{Zs}\t-]?)?(?:\d[\p{Zs}\t-]?){9}[\dxX]$/u;
60
60
  const isbnPattern = new RegExp(String.raw `^(ISBN)${space}+(?:97[89]${spdash}?)?(?:\d${spdash}?){9}[\dxX]$`, 'u');
61
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
61
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
62
62
  /^(RFC|PMID)[\p{Zs}\t]+\d+$/u;
63
63
  const rfcPattern = new RegExp(String.raw `^(RFC|PMID)${space}+\d+$`, 'u');
64
64
  /^(ftp:\/\/|\/\/)/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
@@ -47,7 +47,7 @@ const constants_1 = require("../util/constants");
47
47
  const fixed_1 = require("../mixin/fixed");
48
48
  const index_2 = __importDefault(require("../index"));
49
49
  /* NOT FOR BROWSER END */
50
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions, es-x/no-regexp-unicode-property-escapes
50
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
51
51
  /https?:\/\/(?:\[[\da-f:.]+\]|[^[\]<>"\t\n\p{Zs}])[^[\]<>"\0\t\n\p{Zs}]*$/iu;
52
52
  const linkRegex = new RegExp(`https?://${string_1.extUrlCharFirst}${string_1.extUrlChar}$`, 'iu');
53
53
  /**
@@ -584,7 +584,7 @@ class TableToken extends trBase_1.TrBaseToken {
584
584
  ...opt,
585
585
  nowrap: true,
586
586
  };
587
- return `${[this, ...tr].flatMap(filter) // eslint-disable-line es-x/no-array-prototype-flat
587
+ return `${[this, ...tr].flatMap(filter)
588
588
  .map(token => token.toHtmlInternal(newOpt).trim())
589
589
  .join(' ')}<table${childNodes[1].toHtmlInternal()}>${opt?.nowrap ? ' ' : '\n'}<tbody>${super.toHtmlInternal(opt)}${(0, html_1.html)(tr, '', opt)}</tbody></table>`;
590
590
  }
@@ -212,8 +212,8 @@ let TranscludeToken = (() => {
212
212
  }
213
213
  const magicWord = lcModifier.slice(0, -1).toLowerCase(), isRaw = raw.includes(magicWord), isSubst = subst.includes(magicWord);
214
214
  if (this.#raw && isRaw
215
- || !this.#raw && (isSubst || modifier === '')
216
- || (debug_1.Shadow.running || this.length > 1) && (isRaw || isSubst || modifier === '')) {
215
+ || !this.#raw && (isSubst || !modifier)
216
+ || (debug_1.Shadow.running || this.length > 1) && (isRaw || isSubst || !modifier)) {
217
217
  this.setAttribute('modifier', modifier);
218
218
  this.#raw = isRaw;
219
219
  return Boolean(modifier);
@@ -344,7 +344,7 @@ let TranscludeToken = (() => {
344
344
  const child = childNodes[invoke ? 1 : 0], i = child.childNodes
345
345
  .findIndex(c => c.type === 'text' && (0, string_1.decodeHtml)(c.data).includes('#')), textNode = child.childNodes[i];
346
346
  if (textNode) {
347
- const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'useless fragment');
347
+ const e = (0, lint_1.generateForChild)(child, rect, 'no-ignored', 'useless fragment', 'warning');
348
348
  e.fix = {
349
349
  range: [
350
350
  e.startIndex + child.getRelativeIndex(i) + textNode.data.indexOf('#'),
package/dist/util/lint.js CHANGED
@@ -54,8 +54,9 @@ exports.generateForSelf = factory((_, startIndex, startLine, startCol) => ({ sta
54
54
  */
55
55
  const cache = (store, compute, update) => {
56
56
  if (store
57
- && store[0] === debug_1.Shadow.rev
58
- && index_1.default.viewOnly) {
57
+ /* PRINT ONLY */
58
+ && index_1.default.viewOnly
59
+ && store[0] === debug_1.Shadow.rev) {
59
60
  return store[1];
60
61
  }
61
62
  const result = compute();
@@ -1,6 +1,6 @@
1
1
  (() => {
2
2
  var _a;
3
- const version = '1.20.1', 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.20.3', 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://testingcf.jsdelivr.net/npm/wikiparser-node@${version}`;
6
6
  const workerJS = () => {
package/i18n/zh-hans.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "additional \"|\" in a table cell": "表格单元格中多余的\"|\"",
5
5
  "additional \"|\" in the link text": "链接文本中多余的\"|\"",
6
6
  "attributes of a closing tag": "位于闭合标签的属性",
7
- "bold": "粗体单引号",
7
+ "bold apostrophes": "粗体单引号",
8
8
  "bold in section header": "段落标题中的粗体",
9
9
  "conflicting image $1 parameter": "冲突的图片$1参数",
10
10
  "containing invalid attribute": "包含无效属性",
@@ -35,7 +35,7 @@
35
35
  "invalid parameter of <$1>": "<$1>的无效参数",
36
36
  "invalid self-closing tag": "无效自封闭标签",
37
37
  "invisible content inside triple braces": "三重括号内的不可见部分",
38
- "italic": "斜体单引号",
38
+ "italic apostrophes": "斜体单引号",
39
39
  "lonely \"$1\"": "孤立的\"$1\"",
40
40
  "missing module function": "缺少模块函数",
41
41
  "nonzero tabindex": "不为0的tabindex",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wikiparser-node",
3
- "version": "1.20.1",
3
+ "version": "1.20.3",
4
4
  "description": "A Node.js parser for MediaWiki markup with AST",
5
5
  "keywords": [
6
6
  "mediawiki",
@@ -78,7 +78,7 @@
78
78
  ]
79
79
  },
80
80
  "dependencies": {
81
- "@bhsd/common": "^0.9.3",
81
+ "@bhsd/common": "^0.10.0",
82
82
  "vscode-languageserver-types": "^3.17.5"
83
83
  },
84
84
  "optionalDependencies": {
@@ -86,7 +86,7 @@
86
86
  "color-name": "^2.0.0",
87
87
  "entities": "^6.0.0",
88
88
  "mathjax": "^3.2.2",
89
- "stylelint": "^16.14.1",
89
+ "stylelint": "^16.19.1",
90
90
  "vscode-css-languageservice": "^6.3.4",
91
91
  "vscode-html-languageservice": "^5.3.3",
92
92
  "vscode-json-languageservice": "^5.4.4"
@@ -105,7 +105,6 @@
105
105
  "color-rgba": "^3.0.0",
106
106
  "esbuild": "^0.25.2",
107
107
  "eslint": "^8.57.1",
108
- "eslint-plugin-es-x": "^8.4.1",
109
108
  "eslint-plugin-eslint-comments": "^3.2.0",
110
109
  "eslint-plugin-jsdoc": "^50.6.3",
111
110
  "eslint-plugin-json-es": "^1.6.0",
@@ -118,7 +117,6 @@
118
117
  "mocha": "^11.1.0",
119
118
  "monaco-editor": "^0.52.2",
120
119
  "nyc": "^17.1.0",
121
- "stylelint-config-recommended": "^15.0.0",
122
120
  "typescript": "^5.8.2",
123
121
  "v8r": "^4.2.1",
124
122
  "vscode-languageserver-textdocument": "^1.0.12"