wikilint 2.31.0 → 2.32.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.
package/dist/lib/lsp.js CHANGED
@@ -10,7 +10,10 @@ const base_1 = require("../base");
10
10
  const sharable_1 = require("../util/sharable");
11
11
  const lint_1 = require("../util/lint");
12
12
  const string_1 = require("../util/string");
13
+ const debug_1 = require("../util/debug");
14
+ const constants_1 = require("../util/constants");
13
15
  const index_1 = __importDefault(require("../index"));
16
+ const index_2 = require("../src/index");
14
17
  /* NOT FOR BROWSER ONLY */
15
18
  const fs_1 = __importDefault(require("fs"));
16
19
  const path_1 = __importDefault(require("path"));
@@ -19,7 +22,6 @@ const child_process_1 = require("child_process");
19
22
  const crypto_1 = require("crypto");
20
23
  const stylelint_util_1 = require("@bhsd/stylelint-util");
21
24
  const search_1 = __importDefault(require("../util/search"));
22
- const constants_1 = require("../util/constants");
23
25
  const document_1 = require("./document");
24
26
  exports.tasks = new WeakMap();
25
27
  const refTags = new Set(['ref']), referencesTags = new Set(['ref', 'references']), nameAttrs = new Set(['name', 'follow']), groupAttrs = new Set(['group']), renameTypes = new Set([
@@ -50,7 +52,7 @@ const getLinkRegex = (0, common_1.getRegex)(protocol => new RegExp(`^(?:${protoc
50
52
  const isAttr = ({ type, parentNode, length, firstChild }, style) => type === 'attr-value' && length === 1 && firstChild.type === 'text'
51
53
  && (!style
52
54
  || parentNode.name === 'style'
53
- && Boolean(document_1.cssLSP));
55
+ && Boolean((0, document_1.loadCssLSP)()));
54
56
  /**
55
57
  * Check if a token is an HTML attribute.
56
58
  * @param token
@@ -226,6 +228,54 @@ const getFixAll = (root, rule) => {
226
228
  },
227
229
  ];
228
230
  };
231
+ /**
232
+ * Partially parse wikitext.
233
+ * @param wikitext
234
+ * @param watch function to watch for changes
235
+ * @param include
236
+ * @param config
237
+ */
238
+ const partialParse = async (wikitext, watch, include, config = index_1.default.getConfig()) => {
239
+ const set = typeof setImmediate === 'function' ? setImmediate : /* istanbul ignore next */ setTimeout, { running } = debug_1.Shadow;
240
+ debug_1.Shadow.running = true;
241
+ /** restore state before exit */
242
+ const finish = () => {
243
+ debug_1.Shadow.running = running;
244
+ };
245
+ const token = new index_2.Token((0, string_1.tidy)(wikitext), config);
246
+ token.type = 'root';
247
+ let i = 0;
248
+ try {
249
+ await new Promise(resolve => {
250
+ const /** @ignore */ check = () => {
251
+ if (watch() === wikitext) {
252
+ i++;
253
+ set(parseOnce, 0);
254
+ }
255
+ else {
256
+ resolve();
257
+ }
258
+ },
259
+ /** @ignore */ parseOnce = () => {
260
+ if (i === constants_1.MAX_STAGE + 1) {
261
+ token.afterBuild();
262
+ resolve();
263
+ }
264
+ else {
265
+ token[i === constants_1.MAX_STAGE ? 'build' : 'parseOnce'](i, include);
266
+ check();
267
+ }
268
+ };
269
+ set(parseOnce, 0);
270
+ });
271
+ }
272
+ catch (e) /* istanbul ignore next */ {
273
+ finish();
274
+ throw e;
275
+ }
276
+ finish();
277
+ return token;
278
+ };
229
279
  /* NOT FOR BROWSER ONLY */
230
280
  /** @see https://www.npmjs.com/package/stylelint-config-recommended */
231
281
  const cssRules = { 'block-no-empty': null }, sources = { 'invalid-css': 'css', 'invalid-math': 'texvc' }, jsonSelector = document_1.jsonTags.map(s => `ext#${s}`).join(), scores = new Map();
@@ -380,7 +430,7 @@ class LanguageService {
380
430
  this.config ??= index_1.default.getConfig();
381
431
  this.#config = this.config;
382
432
  this.#include = this.include;
383
- const text = this.#text, root = await index_1.default.partialParse(text, () => this.#text, this.include, this.config);
433
+ const text = this.#text, root = await partialParse(text, () => this.#text, this.include, this.config);
384
434
  if (this.#checkConfig() && this.#text === text) {
385
435
  this.#done = root;
386
436
  this.#running = undefined;
@@ -418,7 +468,7 @@ class LanguageService {
418
468
  this.config ??= index_1.default.getConfig();
419
469
  this.#config = this.config;
420
470
  this.#include = this.include;
421
- const text = this.#text2, root = await index_1.default.partialParse(text, () => this.#text2, this.include, this.config);
471
+ const text = this.#text2, root = await partialParse(text, () => this.#text2, this.include, this.config);
422
472
  if (this.#checkConfig() && this.#text2 === text) {
423
473
  this.#done2 = root;
424
474
  this.#running2 = undefined;
@@ -460,7 +510,7 @@ class LanguageService {
460
510
  }
461
511
  else if (isAttr(token, true)) {
462
512
  const textDoc = new document_1.EmbeddedCSSDocument(root, token);
463
- return document_1.cssLSP.findDocumentColors(textDoc, textDoc.styleSheet);
513
+ return (0, document_1.loadCssLSP)().findDocumentColors(textDoc, textDoc.styleSheet);
464
514
  /* NOT FOR BROWSER ONLY END */
465
515
  }
466
516
  /* NOT FOR BROWSER ONLY */
@@ -488,7 +538,7 @@ class LanguageService {
488
538
  },
489
539
  range: createRange(root, start + from, start + to),
490
540
  };
491
- }).filter(Boolean);
541
+ }).filter(info => info !== false);
492
542
  });
493
543
  });
494
544
  }
@@ -536,11 +586,7 @@ class LanguageService {
536
586
  ext,
537
587
  tags,
538
588
  allTags: [...tags, 'onlyinclude', 'includeonly', 'noinclude'],
539
- functions: [
540
- Object.keys(insensitive),
541
- Array.isArray(sensitive) ? /* istanbul ignore next */ sensitive : Object.keys(sensitive),
542
- other,
543
- ].flat(2),
589
+ functions: [Object.keys(insensitive), Object.keys(sensitive), other].flat(2),
544
590
  switches: allSwitches.filter(cm_util_1.isUnderscore).map(w => `__${w}__`),
545
591
  jaSwitches: allSwitches.filter(w => !(0, cm_util_1.isUnderscore)(w)),
546
592
  protocols: protocol.split('|'),
@@ -596,7 +642,7 @@ class LanguageService {
596
642
  return getCompletion(root.querySelectorAll('arg').filter(token => token.name && token !== cur)
597
643
  .map(({ name }) => name), 'Variable', match, position);
598
644
  }
599
- const [insensitive, sensitive] = this.config.parserFunction, isOld = Array.isArray(sensitive), next = curLine.charAt(character), colon = match.startsWith(':'), str = colon ? match.slice(1).trimStart() : match;
645
+ const [insensitive, sensitive] = this.config.parserFunction, next = curLine.charAt(character), colon = match.startsWith(':'), str = colon ? match.slice(1).trimStart() : match;
600
646
  if (mt[2] === '[[') { // link
601
647
  return getCompletion(root.querySelectorAll('link,file,category,redirect-target').filter(token => token !== cur).map(({ name }) => name), 'Folder', str, position);
602
648
  }
@@ -616,7 +662,7 @@ class LanguageService {
616
662
  else if (name in insensitive) {
617
663
  name = insensitive[name];
618
664
  }
619
- else if (!isOld && name in sensitive) {
665
+ else if (name in sensitive) {
620
666
  name = sensitive[name];
621
667
  }
622
668
  return this.#getParserFunction(name.toLowerCase());
@@ -699,7 +745,8 @@ class LanguageService {
699
745
  }
700
746
  else if (isAttr(cur, true)) {
701
747
  const textDoc = new document_1.EmbeddedCSSDocument(root, cur);
702
- return document_1.cssLSP.doComplete(textDoc, position, textDoc.styleSheet).items.map((item) => ({
748
+ return (0, document_1.loadCssLSP)().doComplete(textDoc, position, textDoc.styleSheet).items
749
+ .map((item) => ({
703
750
  ...item,
704
751
  textEdit: {
705
752
  range: item.textEdit.range,
@@ -707,9 +754,13 @@ class LanguageService {
707
754
  },
708
755
  }));
709
756
  }
710
- else if (document_1.jsonLSP && type === 'ext-inner' && document_1.jsonTags.includes(cur.name)) {
757
+ else if (type === 'ext-inner' && document_1.jsonTags.includes(cur.name)) {
758
+ const jsonLSP = (0, document_1.loadJsonLSP)();
759
+ if (!jsonLSP) {
760
+ return undefined;
761
+ }
711
762
  const textDoc = new document_1.EmbeddedJSONDocument(root, cur);
712
- return (await document_1.jsonLSP.doComplete(textDoc, position, textDoc.jsonDoc))?.items;
763
+ return (await jsonLSP.doComplete(textDoc, position, textDoc.jsonDoc))?.items;
713
764
  }
714
765
  else if (type === 'ext-inner' && cur.name === 'score') {
715
766
  const lang = parentNode.getAttr('lang');
@@ -785,15 +836,18 @@ class LanguageService {
785
836
  ...suggestions ? suggestions.map(suggestion => getQuickFix(root, suggestion)) : [],
786
837
  ],
787
838
  })),
839
+ /* NOT FOR BROWSER ONLY */
840
+ stylelint = await (0, document_1.loadStylelint)(), jsonLSP = (0, document_1.loadJsonLSP)(),
841
+ /* NOT FOR BROWSER ONLY END */
788
842
  /* eslint-disable @stylistic/operator-linebreak */
789
- cssDiagnostics = await document_1.stylelint ?
843
+ cssDiagnostics = stylelint ?
790
844
  await (async () => {
791
845
  NPM: {
792
846
  const tokens = this.findStyleTokens();
793
847
  if (tokens.length === 0) {
794
848
  return [];
795
849
  }
796
- const code = tokens.map(({ type, tag, lastChild }, i) => `${type === 'ext-attr' ? 'div' : tag}#${i}{\n${(0, common_1.sanitizeInlineStyle)(lastChild.toString())}\n}`).join('\n'), cssErrors = await (0, stylelint_util_1.styleLint)((await document_1.stylelint), code, cssRules);
850
+ const code = tokens.map(({ type, tag, lastChild }, i) => `${type === 'ext-attr' ? 'div' : tag}#${i}{\n${(0, common_1.sanitizeInlineStyle)(lastChild.toString())}\n}`).join('\n'), cssErrors = await (0, stylelint_util_1.styleLint)(stylelint, code, cssRules);
797
851
  if (cssErrors.length === 0) {
798
852
  return [];
799
853
  }
@@ -830,12 +884,12 @@ class LanguageService {
830
884
  });
831
885
  }
832
886
  })() :
833
- [], jsonDiagnostics = document_1.jsonLSP ?
887
+ [], jsonDiagnostics = jsonLSP ?
834
888
  await Promise.all(root.querySelectorAll(jsonSelector).map(async ({ name, lastChild, selfClosing }) => {
835
889
  if (selfClosing) {
836
890
  return [];
837
891
  }
838
- const textDoc = new document_1.EmbeddedJSONDocument(root, lastChild), severityLevel = name === 'templatedata' ? 'error' : 'ignore', e = (await document_1.jsonLSP.doValidation(textDoc, textDoc.jsonDoc, {
892
+ const textDoc = new document_1.EmbeddedJSONDocument(root, lastChild), severityLevel = name === 'templatedata' ? 'error' : 'ignore', e = (await jsonLSP.doValidation(textDoc, textDoc.jsonDoc, {
839
893
  comments: severityLevel,
840
894
  trailingCommas: severityLevel,
841
895
  })).map((error) => ({
@@ -969,10 +1023,11 @@ class LanguageService {
969
1023
  }
970
1024
  }
971
1025
  /* NOT FOR BROWSER ONLY */
972
- if (document_1.jsonLSP) {
1026
+ const jsonLSP = (0, document_1.loadJsonLSP)();
1027
+ if (jsonLSP) {
973
1028
  for (const { selfClosing, lastChild } of root.querySelectorAll(jsonSelector)) {
974
1029
  if (!selfClosing) {
975
- const foldingRanges = document_1.jsonLSP.getFoldingRanges(new document_1.EmbeddedJSONDocument(root, lastChild));
1030
+ const foldingRanges = jsonLSP.getFoldingRanges(new document_1.EmbeddedJSONDocument(root, lastChild));
976
1031
  if (foldingRanges.length > 0) {
977
1032
  Array.prototype.push.apply(ranges, foldingRanges);
978
1033
  }
@@ -1082,7 +1137,7 @@ class LanguageService {
1082
1137
  return false;
1083
1138
  }
1084
1139
  })
1085
- .filter(Boolean);
1140
+ .filter(link => link !== false);
1086
1141
  }
1087
1142
  /**
1088
1143
  * Provide references
@@ -1238,41 +1293,43 @@ class LanguageService {
1238
1293
  }
1239
1294
  else if (isAttr(offsetNode, true)) {
1240
1295
  const textDoc = new document_1.EmbeddedCSSDocument(root, offsetNode);
1241
- return document_1.cssLSP.doHover(textDoc, position, textDoc.styleSheet) ?? undefined;
1296
+ return (0, document_1.loadCssLSP)().doHover(textDoc, position, textDoc.styleSheet) ?? undefined;
1242
1297
  }
1243
- else if (document_1.jsonLSP && type === 'ext-inner' && document_1.jsonTags.includes(name)) {
1298
+ else if (type === 'ext-inner' && document_1.jsonTags.includes(name)) {
1299
+ const jsonLSP = (0, document_1.loadJsonLSP)();
1300
+ if (!jsonLSP) {
1301
+ return undefined;
1302
+ }
1244
1303
  const textDoc = new document_1.EmbeddedJSONDocument(root, offsetNode);
1245
- return await document_1.jsonLSP.doHover(textDoc, position, textDoc.jsonDoc) ?? undefined;
1304
+ return await jsonLSP.doHover(textDoc, position, textDoc.jsonDoc) ?? undefined;
1246
1305
  }
1247
- else if (document_1.htmlData) {
1248
- if (type === 'html' && offset <= offsetNode.getRelativeIndex(0)
1249
- || type === 'html-attr-dirty' && offset === 0 && parentNode.firstChild === offsetNode) {
1250
- const token = type === 'html' ? offsetNode : parentNode.parentNode, data = document_1.htmlData.provideTags().find(({ name: n }) => n === token.name);
1251
- if (data?.description) {
1252
- const start = positionAt(root, token.getAbsoluteIndex());
1253
- return {
1254
- contents: data.description,
1255
- range: {
1256
- start,
1257
- end: {
1258
- line: start.line,
1259
- character: start.character + token.getRelativeIndex(0),
1260
- },
1306
+ else if (type === 'html' && offset <= offsetNode.getRelativeIndex(0)
1307
+ || type === 'html-attr-dirty' && offset === 0 && parentNode.firstChild === offsetNode) {
1308
+ const token = type === 'html' ? offsetNode : parentNode.parentNode, data = (0, document_1.loadHtmlData)()?.provideTags().find(({ name: n }) => n === token.name);
1309
+ if (data?.description) {
1310
+ const start = positionAt(root, token.getAbsoluteIndex());
1311
+ return {
1312
+ contents: data.description,
1313
+ range: {
1314
+ start,
1315
+ end: {
1316
+ line: start.line,
1317
+ character: start.character + token.getRelativeIndex(0),
1261
1318
  },
1262
- };
1263
- }
1319
+ },
1320
+ };
1264
1321
  }
1265
- else if (type === 'attr-key' && isHtmlAttr(parentNode)) {
1266
- const data = document_1.htmlData.provideAttributes(parentNode.tag).find(({ name: n }) => n === parentNode.name);
1267
- if (data?.description) {
1268
- return {
1269
- contents: data.description,
1270
- range: createNodeRange(offsetNode),
1271
- };
1272
- }
1322
+ }
1323
+ else if (type === 'attr-key' && isHtmlAttr(parentNode)) {
1324
+ const data = (0, document_1.loadHtmlData)()?.provideAttributes(parentNode.tag).find(({ name: n }) => n === parentNode.name);
1325
+ if (data?.description) {
1326
+ return {
1327
+ contents: data.description,
1328
+ range: createNodeRange(offsetNode),
1329
+ };
1273
1330
  }
1274
- /* NOT FOR BROWSER ONLY END */
1275
1331
  }
1332
+ /* NOT FOR BROWSER ONLY END */
1276
1333
  return info && {
1277
1334
  contents: {
1278
1335
  kind: 'markdown',
@@ -1392,10 +1449,11 @@ class LanguageService {
1392
1449
  else {
1393
1450
  return [];
1394
1451
  }
1395
- const root = await this.#queueSignature(selected);
1396
- const { viewOnly } = index_1.default;
1452
+ const root = await this.#queueSignature(selected), { viewOnly } = index_1.default;
1397
1453
  index_1.default.viewOnly = false;
1398
- root.escape();
1454
+ debug_1.Shadow.internal(() => {
1455
+ root.escape();
1456
+ }, index_1.default);
1399
1457
  index_1.default.viewOnly = viewOnly;
1400
1458
  return [
1401
1459
  {
@@ -1463,9 +1521,9 @@ class LanguageService {
1463
1521
  sections[i] = undefined;
1464
1522
  }
1465
1523
  const section = token.text().trim() || ' ', name = names.has(section)
1466
- ? new Array(names.size).fill('').map((_, i) => `${section.trim()}_${i + 2}`)
1524
+ ? Array.from({ length: names.size }, (_, i) => `${section.trim()}_${i + 2}`)
1467
1525
  .find(s => !names.has(s))
1468
- : section, container = sections.slice(0, level - 1).reverse().find(Boolean), selectionRange = {
1526
+ : section, container = sections.slice(0, level - 1).reverse().find(symbol => symbol !== undefined), selectionRange = {
1469
1527
  start: { line: top, character: left - level },
1470
1528
  end: (0, lint_1.getEndPos)(top, left, height, width + level),
1471
1529
  }, info = {
package/dist/lib/node.js CHANGED
@@ -93,7 +93,7 @@ let AstNode = (() => {
93
93
  }
94
94
  /** @private */
95
95
  getAttribute(key) {
96
- return (key === 'padding' ? 0 : this[key]);
96
+ return (key === 'padding' ? 0 : /* istanbul ignore next */ this[key]);
97
97
  }
98
98
  /** @private */
99
99
  setAttribute(key, value) {
@@ -2,15 +2,13 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.elementLike = void 0;
4
4
  const debug_1 = require("../util/debug");
5
- const selector_1 = require("../parser/selector");
5
+ const selector_1 = require("../util/selector");
6
6
  /** @ignore */
7
7
  const elementLike = (constructor) => {
8
8
  LINT: {
9
9
  class ElementLike extends constructor {
10
10
  #getCondition(selector) {
11
- return (0, selector_1.getCondition)(selector,
12
- // @ts-expect-error only AstElement
13
- this);
11
+ return (0, selector_1.getCondition)(selector, this);
14
12
  }
15
13
  getElementBy(condition) {
16
14
  const stack = [...this.childNodes].reverse();
@@ -5,7 +5,6 @@ const common_1 = require("@bhsd/common");
5
5
  const string_1 = require("../util/string");
6
6
  const onlyinclude_1 = require("../src/onlyinclude");
7
7
  const noinclude_1 = require("../src/nowiki/noinclude");
8
- const translate_1 = require("../src/tagPair/translate");
9
8
  const include_1 = require("../src/tagPair/include");
10
9
  const ext_1 = require("../src/tagPair/ext");
11
10
  const comment_1 = require("../src/nowiki/comment");
@@ -62,16 +61,17 @@ const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
62
61
  const { ext } = config;
63
62
  let newExt = ext, newConfig = config;
64
63
  if (ext.includes('translate')) {
64
+ const { TranslateToken } = require('../src/tagPair/translate');
65
+ const stack = [];
65
66
  newExt = ext.filter(e => e !== 'translate' && e !== 'tvar');
66
67
  newConfig = { ...config, ext: newExt };
67
- const stack = [];
68
68
  wikitext = wikitext.replace(/<nowiki>[\s\S]*?<\/nowiki>/giu, m => {
69
69
  stack.push(m);
70
70
  return `\0${stack.length - 1}\x7F`;
71
71
  }).replace(/<translate( nowrap)?>([\s\S]*?)<\/translate>/gu, (_, p1, p2) => {
72
72
  const l = accum.length;
73
73
  // @ts-expect-error abstract class
74
- new translate_1.TranslateToken(p1, p2 && (0, string_1.restore)(p2, stack), newConfig, accum);
74
+ new TranslateToken(p1, p2 && (0, string_1.restore)(p2, stack), newConfig, accum);
75
75
  return `\0${l}g\x7F`;
76
76
  });
77
77
  wikitext = (0, string_1.restore)(wikitext, stack);
@@ -212,26 +212,28 @@ class AttributeToken extends index_2.Token {
212
212
  }
213
213
  /* NOT FOR BROWSER ONLY */
214
214
  const rule = 'invalid-css', sError = lintConfig.getSeverity(rule), sWarn = lintConfig.getSeverity(rule, 'warn');
215
- if (document_1.cssLSP
216
- && (sError || sWarn)
215
+ if ((sError || sWarn)
217
216
  && name === 'style'
218
217
  && lastChild.length === 1 && lastChild.firstChild.type === 'text') {
219
- const root = this.getRootNode(), textDoc = new document_1.EmbeddedCSSDocument(root, lastChild);
220
- Array.prototype.push.apply(errors, document_1.cssLSP.doValidation(textDoc, textDoc.styleSheet)
221
- .filter(({ code, severity }) => code !== 'css-ruleorselectorexpected' && code !== 'emptyRules'
222
- && (severity === 1 ? sError : sWarn))
223
- .map(({ range: { start: { line, character }, end }, message, severity, code }) => ({
224
- code: code,
225
- rule,
226
- message,
227
- severity: (severity === 1 ? sError : sWarn),
228
- startLine: line,
229
- startCol: character,
230
- startIndex: root.indexFromPos(line, character),
231
- endLine: end.line,
232
- endCol: end.character,
233
- endIndex: root.indexFromPos(end.line, end.character),
234
- })));
218
+ const cssLSP = (0, document_1.loadCssLSP)();
219
+ if (cssLSP) {
220
+ const root = this.getRootNode(), textDoc = new document_1.EmbeddedCSSDocument(root, lastChild);
221
+ Array.prototype.push.apply(errors, cssLSP.doValidation(textDoc, textDoc.styleSheet)
222
+ .filter(({ code, severity }) => code !== 'css-ruleorselectorexpected' && code !== 'emptyRules'
223
+ && (severity === 1 ? sError : sWarn))
224
+ .map(({ range: { start: { line, character }, end }, message, severity, code }) => ({
225
+ code: code,
226
+ rule,
227
+ message,
228
+ severity: (severity === 1 ? sError : sWarn),
229
+ startLine: line,
230
+ startCol: character,
231
+ startIndex: root.indexFromPos(line, character),
232
+ endLine: end.line,
233
+ endCol: end.character,
234
+ endIndex: root.indexFromPos(end.line, end.character),
235
+ })));
236
+ }
235
237
  }
236
238
  /* NOT FOR BROWSER ONLY END */
237
239
  return errors;
@@ -6,6 +6,11 @@ import type { ExtToken, HtmlToken, SyntaxToken } from '../internal';
6
6
  import type { AttributeTypes } from './attribute';
7
7
  import type { TableTokens } from './table/index';
8
8
  declare type AttributesTypes = `${AttributeTypes}s`;
9
+ /**
10
+ * 将属性类型转换为单属性类型
11
+ * @param type 属性类型
12
+ */
13
+ export declare const toAttributeType: (type: AttributesTypes) => AttributeTypes;
9
14
  /**
10
15
  * attributes of extension and HTML tags
11
16
  *
@@ -3,7 +3,7 @@ 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.AttributesToken = void 0;
6
+ exports.AttributesToken = exports.toAttributeType = void 0;
7
7
  const lint_1 = require("../util/lint");
8
8
  const string_1 = require("../util/string");
9
9
  const rect_1 = require("../lib/rect");
@@ -16,11 +16,12 @@ const attribute_1 = require("./attribute");
16
16
  * @param type 属性类型
17
17
  */
18
18
  const toAttributeType = (type) => type.slice(0, -1);
19
+ exports.toAttributeType = toAttributeType;
19
20
  /**
20
21
  * 将属性类型转换为无效属性类型
21
22
  * @param type 属性类型
22
23
  */
23
- const toDirty = (type) => `${toAttributeType(type)}-dirty`;
24
+ const toDirty = (type) => `${(0, exports.toAttributeType)(type)}-dirty`;
24
25
  const wordRegex = /* #__PURE__ */ (() => {
25
26
  try {
26
27
  // eslint-disable-next-line prefer-regex-literals
@@ -65,7 +66,7 @@ class AttributesToken extends index_2.Token {
65
66
  if (/^(?:[\w:]|\0\d+t\x7F)(?:[\w:.-]|\0\d+t\x7F)*$/u.test((0, string_1.removeComment)(key).trim())) {
66
67
  const value = quoted ?? unquoted, quotes = [quoteStart, quoteEnd],
67
68
  // @ts-expect-error abstract class
68
- token = new attribute_1.AttributeToken(toAttributeType(type), name, key, equal, value, quotes, config, accum);
69
+ token = new attribute_1.AttributeToken((0, exports.toAttributeType)(type), name, key, equal, value, quotes, config, accum);
69
70
  insertDirty();
70
71
  super.insertAt(token);
71
72
  }
@@ -2,7 +2,6 @@ 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 } from '../internal';
5
- export declare const galleryParams: Set<string>, extensions: Set<string>;
6
5
  /**
7
6
  * image parameter
8
7
  *
@@ -37,7 +37,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
37
37
  return (mod && mod.__esModule) ? mod : { "default": mod };
38
38
  };
39
39
  Object.defineProperty(exports, "__esModule", { value: true });
40
- exports.ImageParameterToken = exports.extensions = exports.galleryParams = void 0;
40
+ exports.ImageParameterToken = void 0;
41
41
  const common_1 = require("@bhsd/common");
42
42
  const string_1 = require("../util/string");
43
43
  const lint_1 = require("../util/lint");
@@ -49,7 +49,6 @@ const index_2 = require("./index");
49
49
  const getUrlLikeRegex = (0, common_1.getRegex)(protocol => new RegExp(String.raw `^(?:${protocol}|//|\0\d+m\x7F)`, 'iu'));
50
50
  const getUrlRegex = (0, common_1.getRegex)(protocol => new RegExp(String.raw `^(?:(?:${protocol}|//)${string_1.extUrlCharFirst}|\0\d+m\x7F)${string_1.extUrlChar}$`, 'iu'));
51
51
  const getSyntaxRegex = (0, common_1.getRegex)(syntax => new RegExp(String.raw `^(\s*(?!\s))${syntax.replace('$1', '(.*)')}${syntax.endsWith('$1') ? '(?=$|\n)' : ''}(\s*)$`, 'u'));
52
- exports.galleryParams = new Set(['alt', 'link', 'lang', 'page', 'caption']), exports.extensions = new Set(['tiff', 'tif', 'png', 'gif', 'jpg', 'jpeg', 'webp', 'xcf', 'pdf', 'svg', 'djvu']);
53
52
  /**
54
53
  * 获取网址
55
54
  * @param link 外链
@@ -63,33 +62,34 @@ const getUrl = (link) => {
63
62
  }
64
63
  return new URL(link).href;
65
64
  };
66
- function validate(key, val, config, halfParsed, ext) {
65
+ function validate(key, val, config, extOrType, halfParsed) {
67
66
  val = (0, string_1.removeComment)(val).trim();
68
67
  let value = val.replace(key === 'link' ? /\0\d+[tq]\x7F/gu : /\0\d+t\x7F/gu, '').trim();
69
68
  switch (key) {
70
69
  case 'width':
71
70
  return !value && Boolean(val) || /^(?:\d+x?|\d*x\d+)(?:\s*px)?$/u.test(value);
72
71
  case 'link': {
72
+ const isGalleryImage = extOrType === 'gallery-image';
73
73
  if (!value) {
74
74
  return val;
75
75
  }
76
76
  else if (getUrlLikeRegex(config.protocol).test(value)) {
77
- return getUrlRegex(config.protocol).test(value) && val;
77
+ return getUrlRegex(config.protocol).test(value) ? val : isGalleryImage;
78
78
  }
79
79
  else if (value.startsWith('[[') && value.endsWith(']]')) {
80
80
  value = value.slice(2, -2);
81
81
  }
82
82
  const title = index_1.default.normalizeTitle(value, 0, false, config, { halfParsed, decode: true, selfLink: true, page: '' });
83
- return title.valid && title;
83
+ return title.valid ? title : isGalleryImage;
84
84
  }
85
85
  case 'lang':
86
- return (ext === 'svg' || ext === 'svgz') && !/[^a-z\d-]/u.test(value);
86
+ return (extOrType === 'svg' || extOrType === 'svgz') && !/[^a-z\d-]/u.test(value);
87
87
  case 'alt':
88
88
  case 'class':
89
89
  case 'manualthumb':
90
90
  return true;
91
91
  case 'page':
92
- return (ext === 'djvu' || ext === 'djv' || ext === 'pdf') && Number(value) > 0;
92
+ return (extOrType === 'djvu' || extOrType === 'djv' || extOrType === 'pdf') && Number(value) > 0;
93
93
  default:
94
94
  return Boolean(value) && !isNaN(value);
95
95
  }
@@ -139,10 +139,12 @@ let ImageParameterToken = (() => {
139
139
  return debug_1.Shadow.run(() => {
140
140
  const token = new index_2.Token(value, this.getAttribute('config'));
141
141
  token.parseOnce(0, this.getAttribute('include')).parseOnce();
142
- return /^\0\d+m\x7F/u.test(token.firstChild.toString())
143
- ? value
144
- : validate('link', value, this.getAttribute('config'));
145
- });
142
+ if (/^\0\d+m\x7F/u.test(token.firstChild.toString())) {
143
+ return value;
144
+ }
145
+ const link = validate('link', value, this.getAttribute('config'), this.parentNode?.type);
146
+ return link === true ? undefined : link;
147
+ }, index_1.default);
146
148
  }
147
149
  }
148
150
  /** @param str 图片参数 */
@@ -153,7 +155,7 @@ let ImageParameterToken = (() => {
153
155
  mt = regex.exec(str);
154
156
  return mt
155
157
  && (mt.length !== 4
156
- || validate(key, mt[2], config, true, extension) !== false);
158
+ || validate(key, mt[2], config, extension, true) !== false);
157
159
  });
158
160
  // @ts-expect-error mt already assigned
159
161
  if (param && mt) {
@@ -182,7 +184,7 @@ let ImageParameterToken = (() => {
182
184
  }
183
185
  /** @private */
184
186
  afterBuild() {
185
- if (this.parentNode?.is('gallery-image') && !exports.galleryParams.has(this.name)) {
187
+ if (this.parentNode?.is('gallery-image') && !constants_1.galleryParams.has(this.name)) {
186
188
  this.setAttribute('name', 'invalid');
187
189
  }
188
190
  super.afterBuild();
@@ -246,7 +248,7 @@ let ImageParameterToken = (() => {
246
248
  const rule = 'invalid-gallery', s = lintConfig.getSeverity(rule, 'thumb');
247
249
  if (s && !this.querySelector('arg,magic-word,template')) {
248
250
  const { valid, ns, extension, } = this.thumb;
249
- if (!valid || ns !== 6 || !exports.extensions.has(extension)) {
251
+ if (!valid || ns !== 6 || !constants_1.extensions.has(extension)) {
250
252
  errors.push((0, lint_1.generateForSelf)(this, { start }, rule, 'invalid-thumb', s));
251
253
  }
252
254
  }
package/dist/src/index.js CHANGED
@@ -109,7 +109,7 @@ class Token extends element_1.AstElement {
109
109
  }
110
110
  /** @private */
111
111
  parseOnce(n = this.#stage, include = false, tidy) {
112
- if (n < this.#stage || this.length === 0 || !this.isPlain()) {
112
+ if (n < this.#stage || this.length !== 1 || !this.isPlain()) {
113
113
  return this;
114
114
  }
115
115
  else if (this.#stage >= constants_1.MAX_STAGE) {
@@ -168,13 +168,13 @@ class Token extends element_1.AstElement {
168
168
  buildFromStr(str, type) {
169
169
  const nodes = str.split(/[\0\x7F]/u).map((s, i) => {
170
170
  if (i % 2 === 0) {
171
- return new text_1.AstText(s);
171
+ return s && new text_1.AstText(s);
172
172
  }
173
173
  else if (isNaN(s.slice(-1))) {
174
174
  return this.#accum[Number(s.slice(0, -1))];
175
175
  }
176
176
  throw new Error(`Failed to build! Unrecognized token: ${s}`);
177
- });
177
+ }).filter(node => node !== '');
178
178
  if (type === constants_1.BuildMethod.String) {
179
179
  return nodes.map(String).join('');
180
180
  }
@@ -189,7 +189,6 @@ class Token extends element_1.AstElement {
189
189
  const { length, firstChild } = this, str = firstChild?.toString();
190
190
  if (length === 1 && firstChild.type === 'text' && str.includes('\0')) {
191
191
  (0, debug_1.setChildNodes)(this, 0, 1, this.buildFromStr(str));
192
- this.normalize();
193
192
  if (this.type === 'root') {
194
193
  for (const token of this.#accum) {
195
194
  token?.build(); // eslint-disable-line @typescript-eslint/no-unnecessary-condition
@@ -462,7 +461,7 @@ class Token extends element_1.AstElement {
462
461
  }
463
462
  if (needFix && errors.some(({ fix }) => fix)) {
464
463
  // 倒序修复,跳过嵌套的修复
465
- const fixable = errors.map(({ fix }) => fix).filter(Boolean).sort(({ range: [aFrom, aTo] }, { range: [bFrom, bTo] }) => aTo === bTo ? bFrom - aFrom : bTo - aTo);
464
+ const fixable = errors.map(({ fix }) => fix).filter(fix => fix !== undefined).sort(({ range: [aFrom, aTo] }, { range: [bFrom, bTo] }) => aTo === bTo ? bFrom - aFrom : bTo - aTo);
466
465
  let i = Infinity, output = wikitext;
467
466
  for (const { range: [from, to], text: t } of fixable) {
468
467
  if (to <= i) {