wikiparser-node 1.16.5 → 1.16.6

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.
@@ -303,6 +303,7 @@ class AstElement extends node_1.AstNode {
303
303
  acc += self.getAttribute('padding');
304
304
  for (let i = 0; acc <= index && i < childNodes.length; i++) {
305
305
  const cur = childNodes[i], { nextSibling } = cur, str = cur.toString(), l = str.length;
306
+ cur.setAttribute('aIndex', acc);
306
307
  acc += l;
307
308
  // 优先选择靠前的非文本兄弟节点,但永不进入假节点
308
309
  if (acc > index
package/dist/lib/lsp.js CHANGED
@@ -172,18 +172,24 @@ const getSectionEnd = (section, lines, line) => {
172
172
  /** VSCode-style language service */
173
173
  class LanguageService {
174
174
  #text;
175
+ #text2;
175
176
  #running;
177
+ #running2;
176
178
  #done;
179
+ #done2;
177
180
  #config;
181
+ #config2;
178
182
  #completionConfig;
179
- #signature;
180
183
  /** @private */
181
184
  data;
182
185
  /** @param uri 任务标识 */
183
186
  constructor(uri) {
184
187
  exports.tasks.set(uri, this);
185
188
  /* NOT FOR BROWSER ONLY */
186
- this.data = require(path.join('..', '..', 'data', 'signatures'));
189
+ Object.defineProperty(this, 'data', {
190
+ value: require(path.join('..', '..', 'data', 'signatures')),
191
+ enumerable: false,
192
+ });
187
193
  }
188
194
  /** @implements */
189
195
  destroy() {
@@ -193,7 +199,7 @@ class LanguageService {
193
199
  * 提交解析任务
194
200
  * @param text 源代码
195
201
  * @description
196
- * - 总是更新`text`以便`parse`完成时可以判断是否需要重新解析
202
+ * - 总是更新`#text`以便`#parse`完成时可以判断是否需要重新解析
197
203
  * - 如果已有进行中或已完成的解析,则返回该解析的结果
198
204
  * - 否则开始新的解析
199
205
  */
@@ -209,7 +215,7 @@ class LanguageService {
209
215
  /**
210
216
  * 执行解析
211
217
  * @description
212
- * - 完成后会检查`text`是否已更新,如果是则重新解析
218
+ * - 完成后会检查`#text`是否已更新,如果是则重新解析
213
219
  * - 总是返回最新的解析结果
214
220
  */
215
221
  async #parse() {
@@ -227,14 +233,41 @@ class LanguageService {
227
233
  return this.#running;
228
234
  }
229
235
  /**
230
- * 检查是否为签名语言服务器
231
- * @throws `Error` 是签名语言服务器
236
+ * 提交签名解析任务
237
+ * @param text 源代码
238
+ * @description
239
+ * - 总是更新`#text2`以便`#parseSignature`完成时可以判断是否需要重新解析
240
+ * - 如果已有进行中或已完成的解析,则返回该解析的结果
241
+ * - 否则开始新的解析
242
+ */
243
+ async #queueSignature(text) {
244
+ text = (0, string_1.tidy)(text);
245
+ if (this.#text2 === text && this.#config2 === index_1.default.config && !this.#running2) {
246
+ return this.#done2;
247
+ }
248
+ this.#text2 = text;
249
+ this.#running2 ??= this.#parseSignature(); // 不要提交多个解析任务
250
+ return this.#running2;
251
+ }
252
+ /**
253
+ * 执行签名解析
254
+ * @description
255
+ * - 完成后会检查`#text2`是否已更新,如果是则重新解析
256
+ * - 总是返回最新的解析结果
232
257
  */
233
- #checkSignature() {
234
- /* istanbul ignore if */
235
- if (this.#signature) {
236
- throw new Error('This is a signature language server!');
258
+ async #parseSignature() {
259
+ const config = index_1.default.getConfig();
260
+ this.#config2 = index_1.default.config;
261
+ const text = this.#text2, root = await index_1.default.partialParse(text, () => this.#text2, true, config);
262
+ if (this.#text2 === text && this.#config2 === index_1.default.config) {
263
+ this.#done2 = root;
264
+ this.#running2 = undefined;
265
+ return root;
237
266
  }
267
+ /* istanbul ignore next */
268
+ this.#running2 = this.#parseSignature();
269
+ /* istanbul ignore next */
270
+ return this.#running2;
238
271
  }
239
272
  /**
240
273
  * Provide color decorators
@@ -245,9 +278,8 @@ class LanguageService {
245
278
  * @param hsl whether HSL colors are treated / 是否允许HSL颜色
246
279
  */
247
280
  async provideDocumentColors(rgba, text, hsl = true) {
248
- this.#checkSignature();
249
281
  const root = await this.#queue(text);
250
- return root.querySelectorAll('attr-value,parameter-value,arg-default')
282
+ return root.querySelectorAll('attr-value,parameter-value,arg-default').reverse()
251
283
  .flatMap(({ type, childNodes }) => {
252
284
  if (type !== 'attr-value' && !isPlain(childNodes)) {
253
285
  return [];
@@ -336,7 +368,6 @@ class LanguageService {
336
368
  * @param position 位置
337
369
  */
338
370
  async provideCompletionItems(text, position) {
339
- this.#checkSignature();
340
371
  const { re, allTags, functions, switches, protocols, params, tags, ext } = this.#prepareCompletionConfig(), { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], mt = re.exec(curLine?.slice(0, character) ?? '');
341
372
  if (mt?.[1] !== undefined) { // tag
342
373
  const closing = mt[1].startsWith('/');
@@ -448,7 +479,6 @@ class LanguageService {
448
479
  * @param warning whether to include warnings / 是否包含警告
449
480
  */
450
481
  async provideDiagnostics(text, warning = true) {
451
- this.#checkSignature();
452
482
  const root = await this.#queue(text), errors = root.lint();
453
483
  return (warning ? errors : errors.filter(({ severity }) => severity === 'error'))
454
484
  .map(({ startLine, startCol, endLine, endCol, severity, rule, message, fix, suggestions }) => ({
@@ -474,34 +504,36 @@ class LanguageService {
474
504
  * @param text source Wikitext / 源代码
475
505
  */
476
506
  async provideFoldingRanges(text) {
477
- this.#checkSignature();
478
507
  const root = await this.#queue(text), { length } = root.getLines(), ranges = [], levels = new Array(6), tokens = root.querySelectorAll('heading-title,table,template,magic-word');
479
508
  for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
480
509
  token.getRelativeIndex();
481
510
  }
482
511
  for (const token of tokens) {
483
- const { top, height } = token.getBoundingClientRect();
484
- if (token.type === 'heading-title') {
485
- const { level } = token.parentNode;
486
- for (let i = level - 1; i < 6; i++) {
487
- const startLine = levels[i];
488
- if (startLine !== undefined && startLine < top - 1) {
489
- ranges.push({
490
- startLine,
491
- endLine: top - 1,
492
- kind: 'region',
493
- });
512
+ const { offsetHeight } = token;
513
+ if (token.type === 'heading-title' || offsetHeight > 2) {
514
+ const { top } = token.getBoundingClientRect();
515
+ if (token.type === 'heading-title') {
516
+ const { level } = token.parentNode;
517
+ for (let i = level - 1; i < 6; i++) {
518
+ const startLine = levels[i];
519
+ if (startLine !== undefined && startLine < top - 1) {
520
+ ranges.push({
521
+ startLine,
522
+ endLine: top - 1,
523
+ kind: 'region',
524
+ });
525
+ }
526
+ levels[i] = undefined;
494
527
  }
495
- levels[i] = undefined;
528
+ levels[level - 1] = top + offsetHeight - 1; // 从标题的最后一行开始折叠
529
+ }
530
+ else {
531
+ ranges.push({
532
+ startLine: top, // 从表格或模板的第一行开始折叠
533
+ endLine: top + offsetHeight - 2,
534
+ kind: 'region',
535
+ });
496
536
  }
497
- levels[level - 1] = top + height - 1; // 从标题的最后一行开始折叠
498
- }
499
- else if (height > 2) {
500
- ranges.push({
501
- startLine: top, // 从表格或模板的第一行开始折叠
502
- endLine: top + height - 2,
503
- kind: 'region',
504
- });
505
537
  }
506
538
  }
507
539
  for (const startLine of levels) {
@@ -522,13 +554,13 @@ class LanguageService {
522
554
  * @param text source Wikitext / 源代码
523
555
  */
524
556
  async provideLinks(text) {
525
- this.#checkSignature();
526
557
  /^(?:http:\/\/|\/\/)/iu; // eslint-disable-line @typescript-eslint/no-unused-expressions
527
558
  const { articlePath, protocol } = index_1.default.getConfig(), absolute = articlePath?.includes('//'), protocolRegex = new RegExp(`^(?:${protocol}|//)`, 'iu');
528
559
  return (await this.#queue(text))
529
- .querySelectorAll(`magic-link,ext-link-url,free-ext-link,attr-value,image-parameter#link${absolute ? ',link-target,template-name,invoke-module' : ''}`).reverse()
560
+ .querySelectorAll(`magic-link,ext-link-url,free-ext-link,attr-value,image-parameter#link${absolute ? ',link-target,template-name,invoke-module' : ''}`)
561
+ .reverse()
530
562
  .map((token) => {
531
- const { type, parentNode, firstChild, lastChild, childNodes } = token, { name, tag } = parentNode;
563
+ const { type, parentNode, firstChild, lastChild, childNodes, length } = token, { name, tag } = parentNode;
532
564
  if (!(type !== 'attr-value'
533
565
  || name === 'src' && ['templatestyles', 'img'].includes(tag)
534
566
  || name === 'cite' && ['blockquote', 'del', 'ins', 'q'].includes(tag))
@@ -536,7 +568,9 @@ class LanguageService {
536
568
  return false;
537
569
  }
538
570
  let target = childNodes.filter((node) => node.type === 'text')
539
- .map(({ data }) => data).join('').trim();
571
+ .map(({ data }) => data)
572
+ .join('')
573
+ .trim();
540
574
  if (!target) {
541
575
  return false;
542
576
  }
@@ -583,7 +617,7 @@ class LanguageService {
583
617
  }
584
618
  target = new URL(target).href;
585
619
  if (type === 'image-parameter') {
586
- const { top, left, height, width } = lastChild.getBoundingClientRect(), rect = firstChild.getBoundingClientRect();
620
+ const rect = firstChild.getBoundingClientRect(), { top, left, height, width } = length === 1 ? rect : lastChild.getBoundingClientRect();
587
621
  return {
588
622
  range: {
589
623
  start: { line: rect.top, character: rect.left },
@@ -597,7 +631,8 @@ class LanguageService {
597
631
  catch {
598
632
  return false;
599
633
  }
600
- }).filter(Boolean);
634
+ })
635
+ .filter(Boolean);
601
636
  }
602
637
  /**
603
638
  * Provide references
@@ -607,7 +642,6 @@ class LanguageService {
607
642
  * @param position 位置
608
643
  */
609
644
  async provideReferences(text, position) {
610
- this.#checkSignature();
611
645
  const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, position), element = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, node = offset === 0 && (element.type === 'ext-attr-dirty' || element.type === 'html-attr-dirty')
612
646
  ? element.parentNode.parentNode
613
647
  : element, { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
@@ -616,7 +650,7 @@ class LanguageService {
616
650
  }
617
651
  const name = getName(node), refs = root.querySelectorAll(type === 'heading-title' ? 'heading' : type).filter(token => type === 'attr-value'
618
652
  ? getRefName(token) === refName || getRefGroup(token) === refGroup
619
- : getName(token) === name).map((token) => ({
653
+ : getName(token) === name).reverse().map((token) => ({
620
654
  range: createNodeRange(token.type === 'parameter-key' ? token.parentNode : token),
621
655
  }));
622
656
  return refs.length === 0 ? undefined : refs;
@@ -629,7 +663,6 @@ class LanguageService {
629
663
  * @param position 位置
630
664
  */
631
665
  async provideDefinition(text, position) {
632
- this.#checkSignature();
633
666
  const root = await this.#queue(text), node = root.elementFromPoint(position.character, position.line), ext = node.is('ext') && node.name === 'ref'
634
667
  ? node
635
668
  : node.closest('ext#ref'), refName = getRefTagAttr(ext, 'name');
@@ -638,7 +671,7 @@ class LanguageService {
638
671
  }
639
672
  const refGroup = getRefTagAttr(ext, 'group'), refs = root.querySelectorAll('ext#ref').filter(token => token.innerText
640
673
  && getRefTagAttr(token, 'name') === refName
641
- && getRefTagAttr(token, 'group') === refGroup).map(({ lastChild }) => ({
674
+ && getRefTagAttr(token, 'group') === refGroup).reverse().map(({ lastChild }) => ({
642
675
  range: createNodeRange(lastChild),
643
676
  }));
644
677
  return refs.length === 0 ? undefined : refs;
@@ -651,7 +684,6 @@ class LanguageService {
651
684
  * @param position 位置
652
685
  */
653
686
  async resolveRenameLocation(text, position) {
654
- this.#checkSignature();
655
687
  const root = await this.#queue(text), node = root.elementFromPoint(position.character, position.line), { type } = node, refName = getRefName(node), refGroup = getRefGroup(node);
656
688
  return !refName && !refGroup && (!renameTypes.has(type)
657
689
  || type === 'parameter-key' && /^[1-9]\d*$/u.test(node.parentNode.name)
@@ -668,7 +700,6 @@ class LanguageService {
668
700
  * @param newName new name / 新名称
669
701
  */
670
702
  async provideRenameEdits(text, position, newName) {
671
- this.#checkSignature();
672
703
  const root = await this.#queue(text), node = root.elementFromPoint(position.character, position.line), { type } = node, refName = getRefName(node), refNameGroup = refName && getRefTagAttr(node.parentNode.parentNode, 'group'), refGroup = getRefGroup(node), name = getName(node), refs = root.querySelectorAll(type).filter(token => {
673
704
  const { type: t } = token.parentNode;
674
705
  if (type === 'link-target' && t !== 'link' && t !== 'redirect-target') {
@@ -684,7 +715,7 @@ class LanguageService {
684
715
  ? undefined
685
716
  : {
686
717
  changes: {
687
- '': refs.map((ref) => ({
718
+ '': refs.reverse().map((ref) => ({
688
719
  range: createNodeRange(ref),
689
720
  newText: newName,
690
721
  })),
@@ -711,7 +742,6 @@ class LanguageService {
711
742
  if (!this.data) {
712
743
  return undefined;
713
744
  }
714
- this.#checkSignature();
715
745
  const root = await this.#queue(text), { offsetNode, offset } = caretPositionFromWord(root, position), token = offsetNode.type === 'text' ? offsetNode.parentNode : offsetNode, { type, parentNode, length, name } = token;
716
746
  let info, f, range;
717
747
  if (token.is('double-underscore') && offset > 0) {
@@ -760,13 +790,8 @@ class LanguageService {
760
790
  /* istanbul ignore next */
761
791
  if (!this.data) {
762
792
  return undefined;
763
- // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
764
793
  }
765
- else if (this.#text !== undefined && !this.#signature) {
766
- throw new Error('This is a regular language server!');
767
- }
768
- this.#signature = true;
769
- const { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], { lastChild } = await this.#queue(`${curLine.slice(0, character + /^[^{}<]*/u.exec(curLine.slice(character))[0].length)}}}`);
794
+ const { line, character } = position, curLine = text.split(/\r?\n/u, line + 1)[line], { lastChild } = await this.#queueSignature(`${curLine.slice(0, character + /^[^{}<]*/u.exec(curLine.slice(character))[0].length)}}}`);
770
795
  if (!lastChild.is('magic-word') || lastChild.length === 1) {
771
796
  return undefined;
772
797
  }
@@ -809,12 +834,12 @@ class LanguageService {
809
834
  * @param text source Wikitext / 源代码
810
835
  */
811
836
  async provideInlayHints(text) {
812
- this.#checkSignature();
813
837
  const hints = [], root = await this.#queue(text);
814
- for (const template of root.querySelectorAll('template,magic-word#invoke')) {
815
- const { type, childNodes } = template;
838
+ for (const token of root.querySelectorAll('template,magic-word#invoke').reverse()) {
839
+ const { type, childNodes } = token;
816
840
  hints.push(...childNodes.slice(type === 'template' ? 1 : 3).filter(({ anon }) => anon)
817
- .reverse().map((parameter) => ({
841
+ .reverse()
842
+ .map((parameter) => ({
818
843
  position: positionAt(root, parameter.getAbsoluteIndex()),
819
844
  label: `${parameter.name}=`,
820
845
  kind: 2,
@@ -848,40 +873,36 @@ class LanguageService {
848
873
  * @param text source Wikitext / 源代码
849
874
  */
850
875
  async provideDocumentSymbols(text) {
851
- this.#checkSignature();
852
876
  const root = await this.#queue(text), lines = root.getLines(), { length } = lines, symbols = [], names = new Set(), sections = new Array(6), tokens = root.querySelectorAll('heading-title');
853
877
  for (const token of [...tokens].reverse()) { // 提高 getBoundingClientRect 的性能
854
878
  token.getRelativeIndex();
855
879
  }
856
880
  for (const token of tokens) {
857
- const { top, height, left, width } = token.getBoundingClientRect();
858
- if (token.type === 'heading-title') {
859
- const { level } = token.parentNode;
860
- for (let i = level - 1; i < 6; i++) {
861
- getSectionEnd(sections[i], lines, top - 1);
862
- sections[i] = undefined;
863
- }
864
- const section = token.text().trim() || ' ', name = names.has(section)
865
- ? new Array(names.size).fill('').map((_, i) => `${section.trim()}_${i + 2}`)
866
- .find(s => !names.has(s))
867
- : section, container = sections.slice(0, level - 1).reverse().find(Boolean), selectionRange = {
868
- start: { line: top, character: left - level },
869
- end: (0, lint_1.getEndPos)(top, left, height, width + level),
870
- }, info = {
871
- name,
872
- kind: 15,
873
- range: { start: selectionRange.start },
874
- selectionRange,
875
- };
876
- names.add(name);
877
- sections[level - 1] = info;
878
- if (container) {
879
- container.children ??= [];
880
- container.children.push(info);
881
- }
882
- else {
883
- symbols.push(info);
884
- }
881
+ const { top, height, left, width } = token.getBoundingClientRect(), { level } = token.parentNode;
882
+ for (let i = level - 1; i < 6; i++) {
883
+ getSectionEnd(sections[i], lines, top - 1);
884
+ sections[i] = undefined;
885
+ }
886
+ const section = token.text().trim() || ' ', name = names.has(section)
887
+ ? new Array(names.size).fill('').map((_, i) => `${section.trim()}_${i + 2}`)
888
+ .find(s => !names.has(s))
889
+ : section, container = sections.slice(0, level - 1).reverse().find(Boolean), selectionRange = {
890
+ start: { line: top, character: left - level },
891
+ end: (0, lint_1.getEndPos)(top, left, height, width + level),
892
+ }, info = {
893
+ name,
894
+ kind: 15,
895
+ range: { start: selectionRange.start },
896
+ selectionRange,
897
+ };
898
+ names.add(name);
899
+ sections[level - 1] = info;
900
+ if (container) {
901
+ container.children ??= [];
902
+ container.children.push(info);
903
+ }
904
+ else {
905
+ symbols.push(info);
885
906
  }
886
907
  }
887
908
  for (const section of sections) {
@@ -13,7 +13,24 @@ const closes = {
13
13
  '{': String.raw `\}{2,}|\|`,
14
14
  '-': String.raw `\}-`,
15
15
  '[': String.raw `\]\]`,
16
- }, openBraces = String.raw `|\{{2,}`, marks = new Map([['!', '!'], ['!!', '+'], ['(!', '{'], ['!)', '}'], ['!-', '-'], ['=', '~'], ['server', 'm']]), re = /\{\{\s*([^\s\0<>[\]{}|_#&%:.]+)\s*\}\}(?!\})/gu;
16
+ }, openBraces = String.raw `|\{{2,}`, marks = new Map([['!', '!'], ['!!', '+'], ['(!', '{'], ['!)', '}'], ['!-', '-'], ['=', '~'], ['server', 'm']]);
17
+ /**
18
+ * 获取模板或魔术字对应的字符
19
+ * @param s 模板或魔术字名
20
+ */
21
+ const getSymbol = (s) => {
22
+ const name = (0, string_1.removeComment)(s).trim().toLowerCase();
23
+ if (marks.has(name)) {
24
+ return marks.get(name); // 标记{{!}}等
25
+ }
26
+ else if (/^(?:filepath|(?:full|canonical)urle?):./u.test(name)) {
27
+ return 'm';
28
+ }
29
+ else if (/^#vardefine:./u.test(name)) {
30
+ return 'n';
31
+ }
32
+ return 't';
33
+ };
17
34
  /**
18
35
  * 解析花括号
19
36
  * @param wikitext
@@ -22,11 +39,32 @@ const closes = {
22
39
  * @throws TranscludeToken.constructor()
23
40
  */
24
41
  const parseBraces = (wikitext, config, accum) => {
25
- const source = String.raw `${config.excludes?.includes('heading') ? '' : String.raw `^((?:\0\d+[cno]\x7F)*)={1,6}|`}\[\[|-\{(?!\{)`, { parserFunction: [, , , subst] } = config, stack = [];
26
- wikitext = wikitext.replace(re, (m, p1) => {
27
- // @ts-expect-error abstract class
28
- new transclude_1.TranscludeToken(m.slice(2, -2), [], config, accum);
29
- return `\0${accum.length - 2}${marks.get(p1.toLowerCase()) ?? 't'}\x7F`;
42
+ const source = String.raw `${config.excludes?.includes('heading') ? '' : String.raw `^((?:\0\d+[cno]\x7F)*)={1,6}|`}\[\[|-\{(?!\{)`, { parserFunction: [, , , subst] } = config, stack = [], linkStack = [];
43
+ /**
44
+ * 恢复内链
45
+ * @param s 不含内链的字符串
46
+ */
47
+ const restore = (s) => s.replace(/\0(\d+)\x7F/gu, (_, p1) => linkStack[p1]);
48
+ wikitext = wikitext.replace(/\{\{([^\n{}[]*)\}\}(?!\})|\[\[[^\n[\]{]*\]\]/gu, (m, p1) => {
49
+ if (p1 !== undefined) {
50
+ try {
51
+ const { length } = accum, parts = p1.split('|');
52
+ // @ts-expect-error abstract class
53
+ new transclude_1.TranscludeToken(parts[0], parts.slice(1).map(part => {
54
+ const i = part.indexOf('=');
55
+ return i === -1 ? [part] : [part.slice(0, i), part.slice(i + 1)];
56
+ }), config, accum);
57
+ return `\0${length}${getSymbol(parts[0])}\x7F`;
58
+ }
59
+ catch (e) {
60
+ /* istanbul ignore if */
61
+ if (!(e instanceof SyntaxError) || e.message !== 'Invalid template name') {
62
+ throw e;
63
+ }
64
+ }
65
+ }
66
+ linkStack.push(m);
67
+ return `\0${linkStack.length - 1}\x7F`;
30
68
  });
31
69
  const lastBraces = wikitext.lastIndexOf('}}') - wikitext.length;
32
70
  let moreBraces = lastBraces + wikitext.length !== -1;
@@ -47,7 +85,7 @@ const parseBraces = (wikitext, config, accum) => {
47
85
  * @param text wikitext全文
48
86
  */
49
87
  const push = (text) => {
50
- parts[parts.length - 1].push(text.slice(topPos, curIndex));
88
+ parts[parts.length - 1].push(restore(text.slice(topPos, curIndex)));
51
89
  };
52
90
  if (syntax === ']]' || syntax === '}-') { // 情形1:闭合内链或转换
53
91
  lastIndex = curIndex + 2;
@@ -61,6 +99,7 @@ const parseBraces = (wikitext, config, accum) => {
61
99
  if (rmt) {
62
100
  wikitext = `${wikitext.slice(0, index)}\0${accum.length}h\x7F${wikitext.slice(curIndex)}`;
63
101
  lastIndex = index + 4 + String(accum.length).length;
102
+ rmt[2] = restore(rmt[2]);
64
103
  // @ts-expect-error abstract class
65
104
  new heading_1.HeadingToken(rmt[1].length, rmt.slice(2), config, accum);
66
105
  }
@@ -94,16 +133,7 @@ const parseBraces = (wikitext, config, accum) => {
94
133
  try {
95
134
  // @ts-expect-error abstract class
96
135
  new transclude_1.TranscludeToken(parts[0][0], parts.slice(1), config, accum);
97
- const name = (0, string_1.removeComment)(parts[0][0]).trim();
98
- if (marks.has(name.toLowerCase())) {
99
- ch = marks.get(name.toLowerCase()); // 标记{{!}}等
100
- }
101
- else if (/^(?:filepath|(?:full|canonical)urle?):./iu.test(name)) {
102
- ch = 'm';
103
- }
104
- else if (/^#vardefine:./iu.test(name)) {
105
- ch = 'n';
106
- }
136
+ ch = getSymbol(parts[0][0]);
107
137
  }
108
138
  catch (e) {
109
139
  /* istanbul ignore else */
@@ -149,7 +179,7 @@ const parseBraces = (wikitext, config, accum) => {
149
179
  regex.lastIndex = lastIndex;
150
180
  mt = regex.exec(wikitext);
151
181
  }
152
- return wikitext;
182
+ return restore(wikitext);
153
183
  };
154
184
  exports.parseBraces = parseBraces;
155
185
  constants_1.parsers['parseBraces'] = __filename;
@@ -9,7 +9,24 @@ const comment_1 = require("../src/nowiki/comment");
9
9
  /* NOT FOR BROWSER */
10
10
  const constants_1 = require("../util/constants");
11
11
  /* NOT FOR BROWSER END */
12
- const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft;
12
+ const onlyincludeLeft = '<onlyinclude>', onlyincludeRight = '</onlyinclude>', { length } = onlyincludeLeft, regexInclude = new WeakMap(), regexNoinclude = new WeakMap();
13
+ /**
14
+ * 获取正则表达式
15
+ * @param ext 扩展标签
16
+ * @param includeOnly 是否嵌入
17
+ */
18
+ const getRegex = (ext, includeOnly) => {
19
+ const regex = includeOnly ? regexInclude : regexNoinclude;
20
+ if (regex.has(ext)) {
21
+ return regex.get(ext);
22
+ }
23
+ const noincludeRegex = includeOnly ? 'includeonly' : '(?:no|only)include', includeRegex = includeOnly ? 'noinclude' : 'includeonly';
24
+ // eslint-disable-next-line @typescript-eslint/no-unused-expressions
25
+ /<!--[\s\S]*?(?:-->|$)|<foo(?:\s[^>]*)?\/?>|<\/foo\s*>|<(bar)(\s[^>]*?)?(?:\/>|>([\s\S]*?)<\/(\1\s*)>)|<(baz)(\s[^>]*?)?(?:\/>|>([\s\S]*?)(?:<\/(baz\s*)>|$))/giu;
26
+ const re = new RegExp(String.raw `<!--[\s\S]*?(?:-->|$)|<${noincludeRegex}(?:\s[^>]*)?/?>|</${noincludeRegex}\s*>|<(${ext.join('|')})(\s[^>]*?)?(?:/>|>([\s\S]*?)</(\1\s*)>)|<(${includeRegex})(\s[^>]*?)?(?:/>|>([\s\S]*?)(?:</(${includeRegex}\s*)>|$))`, 'giu');
27
+ regex.set(ext, re);
28
+ return re;
29
+ };
13
30
  /**
14
31
  * 更新`<onlyinclude>`和`</onlyinclude>`的位置
15
32
  * @param wikitext
@@ -55,11 +72,7 @@ const parseCommentAndExt = (wikitext, config, accum, includeOnly) => {
55
72
  return str;
56
73
  }
57
74
  }
58
- const ext = config.ext.join('|'), noincludeRegex = includeOnly ? 'includeonly' : '(?:no|only)include', includeRegex = includeOnly ? 'noinclude' : 'includeonly';
59
- // eslint-disable-next-line @typescript-eslint/no-unused-expressions
60
- /<!--[\s\S]*?(?:-->|$)|<foo(?:\s[^>]*)?\/?>|<\/foo\s*>|<(bar)(\s[^>]*?)?(?:\/>|>([\s\S]*?)<\/(\1\s*)>)|<(baz)(\s[^>]*?)?(?:\/>|>([\s\S]*?)(?:<\/(baz\s*)>|$))/giu;
61
- const /** Never cached due to the possibility of nested extension tags */ regex = new RegExp(String.raw `<!--[\s\S]*?(?:-->|$)|<${noincludeRegex}(?:\s[^>]*)?/?>|</${noincludeRegex}\s*>|<(${ext})(\s[^>]*?)?(?:/>|>([\s\S]*?)</(\1\s*)>)|<(${includeRegex})(\s[^>]*?)?(?:/>|>([\s\S]*?)(?:</(${includeRegex}\s*)>|$))`, 'giu');
62
- return wikitext.replace(regex, (substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
75
+ return wikitext.replace(getRegex(config.ext, includeOnly), (substr, name, attr, inner, closing, include, includeAttr, includeInner, includeClosing) => {
63
76
  const l = accum.length;
64
77
  let ch = 'n';
65
78
  if (name) {
@@ -575,7 +575,8 @@ class TableToken extends trBase_1.TrBaseToken {
575
575
  const filter = (token) => token.childNodes.filter((0, debug_1.isToken)('table-inter'));
576
576
  const { childNodes } = this, tr = childNodes.filter((0, debug_1.isToken)('tr')), newOpt = { ...opt, nowrap: true };
577
577
  return `${[this, ...tr].flatMap(filter) // eslint-disable-line es-x/no-array-prototype-flat
578
- .map(token => token.toHtmlInternal(newOpt).trim()).join(' ')}<table${childNodes[1].toHtmlInternal()}>${opt?.nowrap ? ' ' : '\n'}<tbody>${super.toHtmlInternal(opt)}${(0, html_1.html)(tr, '', opt)}</tbody></table>`;
578
+ .map(token => token.toHtmlInternal(newOpt).trim())
579
+ .join(' ')}<table${childNodes[1].toHtmlInternal()}>${opt?.nowrap ? ' ' : '\n'}<tbody>${super.toHtmlInternal(opt)}${(0, html_1.html)(tr, '', opt)}</tbody></table>`;
579
580
  }
580
581
  }
581
582
  exports.TableToken = TableToken;
@@ -158,7 +158,9 @@ let TdToken = (() => {
158
158
  const str = previousSibling.lastChild.toString();
159
159
  result.escape ||= esc;
160
160
  result.correction = str.includes('\n') && debug_1.Shadow.run(() => new index_2.Token(str, this.getAttribute('config'))
161
- .parseOnce(0, this.getAttribute('include')).parseOnce().parseOnce()
161
+ .parseOnce(0, this.getAttribute('include'))
162
+ .parseOnce()
163
+ .parseOnce()
162
164
  .toString()
163
165
  .includes('\n'));
164
166
  if (subtype === 'th' && result.subtype !== 'th') {
@@ -1,6 +1,6 @@
1
1
  (() => {
2
2
  var _a;
3
- const version = '1.16.5', 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.16.6', 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 = () => {
@@ -18,11 +18,8 @@ const workerJS = () => {
18
18
  }
19
19
  return root;
20
20
  };
21
- const getLSP = (qid, signature) => {
22
- let id = Math.floor(qid);
23
- if (signature) {
24
- id += 0.5;
25
- }
21
+ const getLSP = (qid) => {
22
+ const id = Math.floor(qid);
26
23
  if (lsps.has(id)) {
27
24
  return lsps.get(id);
28
25
  }
@@ -85,13 +82,10 @@ const workerJS = () => {
85
82
  break;
86
83
  case 'destroy':
87
84
  getLSP(qid).destroy();
88
- getLSP(qid, true).destroy();
89
85
  lsps.delete(qid);
90
- lsps.delete(qid + 0.5);
91
86
  break;
92
87
  case 'data':
93
88
  getLSP(qid).data = wikitext;
94
- getLSP(qid, true).data = wikitext;
95
89
  break;
96
90
  case 'colorPresentations':
97
91
  postMessage([qid, getLSP(qid).provideColorPresentations(wikitext)]);
@@ -148,7 +142,7 @@ const workerJS = () => {
148
142
  break;
149
143
  case 'signatureHelp':
150
144
  (async () => {
151
- postMessage([qid, await getLSP(qid, true).provideSignatureHelp(wikitext, include), wikitext]);
145
+ postMessage([qid, await getLSP(qid).provideSignatureHelp(wikitext, include), wikitext]);
152
146
  })();
153
147
  break;
154
148
  case 'inlayHints':
@@ -9,7 +9,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
9
9
  });
10
10
  };
11
11
  var _a;
12
- const version = '1.16.5', src = (_a = document.currentScript) === null || _a === void 0 ? void 0 : _a.src, file = /\/extensions\/dist\/base\.(?:min\.)?js$/u, CDN = src && file.test(src)
12
+ const version = '1.16.6', src = (_a = document.currentScript) === null || _a === void 0 ? void 0 : _a.src, file = /\/extensions\/dist\/base\.(?:min\.)?js$/u, CDN = src && file.test(src)
13
13
  ? src.replace(file, '')
14
14
  : `https://testingcf.jsdelivr.net/npm/wikiparser-node@${version}`;
15
15
  const workerJS = () => {
@@ -27,11 +27,8 @@ const workerJS = () => {
27
27
  }
28
28
  return root;
29
29
  };
30
- const getLSP = (qid, signature) => {
31
- let id = Math.floor(qid);
32
- if (signature) {
33
- id += 0.5;
34
- }
30
+ const getLSP = (qid) => {
31
+ const id = Math.floor(qid);
35
32
  if (lsps.has(id)) {
36
33
  return lsps.get(id);
37
34
  }
@@ -94,13 +91,10 @@ const workerJS = () => {
94
91
  break;
95
92
  case 'destroy':
96
93
  getLSP(qid).destroy();
97
- getLSP(qid, true).destroy();
98
94
  lsps.delete(qid);
99
- lsps.delete(qid + 0.5);
100
95
  break;
101
96
  case 'data':
102
97
  getLSP(qid).data = wikitext;
103
- getLSP(qid, true).data = wikitext;
104
98
  break;
105
99
  case 'colorPresentations':
106
100
  postMessage([qid, getLSP(qid).provideColorPresentations(wikitext)]);
@@ -157,7 +151,7 @@ const workerJS = () => {
157
151
  break;
158
152
  case 'signatureHelp':
159
153
  (() => __awaiter(void 0, void 0, void 0, function* () {
160
- postMessage([qid, yield getLSP(qid, true).provideSignatureHelp(wikitext, include), wikitext]);
154
+ postMessage([qid, yield getLSP(qid).provideSignatureHelp(wikitext, include), wikitext]);
161
155
  }))();
162
156
  break;
163
157
  case 'inlayHints':