@bhsd/codemirror-mediawiki 3.9.2 → 3.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +71 -11
  2. package/dist/bidi.d.ts +4 -8
  3. package/dist/bidi.js +33 -23
  4. package/dist/codemirror.js +15 -9
  5. package/dist/color.d.ts +1 -1
  6. package/dist/color.js +1 -1
  7. package/dist/config.d.ts +1 -0
  8. package/dist/config.js +1 -0
  9. package/dist/constants.d.ts +3 -2
  10. package/dist/constants.js +3 -2
  11. package/dist/css.js +9 -6
  12. package/dist/escape.d.ts +1 -1
  13. package/dist/escape.js +4 -3
  14. package/dist/fold.d.ts +2 -2
  15. package/dist/fold.js +106 -39
  16. package/dist/hover.d.ts +2 -2
  17. package/dist/hover.js +72 -69
  18. package/dist/index.d.ts +54 -16
  19. package/dist/index.js +91 -38
  20. package/dist/inlay.d.ts +1 -1
  21. package/dist/inlay.js +26 -25
  22. package/dist/javascript.js +45 -2
  23. package/dist/linter.d.ts +15 -2
  24. package/dist/linter.js +2 -2
  25. package/dist/lintsource.d.ts +15 -3
  26. package/dist/lintsource.js +13 -7
  27. package/dist/lua.d.ts +0 -2
  28. package/dist/lua.js +32 -26
  29. package/dist/main.min.js +31 -29
  30. package/dist/matchTag.js +4 -3
  31. package/dist/mediawiki.d.ts +4 -2
  32. package/dist/mediawiki.js +56 -44
  33. package/dist/mw.min.js +33 -37
  34. package/dist/mwConfig.js +2 -2
  35. package/dist/openLinks.d.ts +4 -2
  36. package/dist/openLinks.js +56 -54
  37. package/dist/ref.d.ts +1 -1
  38. package/dist/ref.js +92 -93
  39. package/dist/signature.d.ts +1 -1
  40. package/dist/signature.js +50 -49
  41. package/dist/statusBar.js +9 -8
  42. package/dist/theme.js +6 -0
  43. package/dist/token.d.ts +20 -6
  44. package/dist/token.js +26 -17
  45. package/dist/util.d.ts +17 -2
  46. package/dist/util.js +39 -1
  47. package/dist/wiki.min.js +32 -36
  48. package/i18n/en.json +2 -2
  49. package/i18n/zh-hans.json +2 -2
  50. package/i18n/zh-hant.json +2 -2
  51. package/package.json +14 -12
package/dist/token.d.ts CHANGED
@@ -18,7 +18,7 @@ declare interface Nesting extends Record<NestCount, number> {
18
18
  extName: string | false;
19
19
  extState: object | false;
20
20
  }
21
- declare interface State extends Nesting {
21
+ export interface State extends Nesting {
22
22
  readonly stack: Tokenizer[];
23
23
  readonly inHtmlTag: string[];
24
24
  tokenize: Tokenizer;
@@ -44,11 +44,12 @@ declare interface Token {
44
44
  pos: number;
45
45
  style: Style;
46
46
  }
47
- declare interface StringStream extends StringStreamBase {
47
+ export interface StringStream extends StringStreamBase {
48
48
  match(pattern: string, consume?: boolean, caseInsensitive?: boolean): true | null;
49
49
  match(pattern: RegExp, consume?: boolean): RegExpMatchArray | null;
50
50
  }
51
- export type ApiSuggestions = [string, string?][] & {
51
+ export type CompletionSectionName = 'Required' | 'Suggested' | 'Optional' | 'Deprecated';
52
+ export type ApiSuggestions<T = string[]> = [T, string?, string?, CompletionSectionName?][] & {
52
53
  description?: string;
53
54
  };
54
55
  /**
@@ -57,17 +58,17 @@ export type ApiSuggestions = [string, string?][] & {
57
58
  * @param subpage 是否为子页面
58
59
  * @param namespace 命名空间
59
60
  */
60
- export type ApiSuggest = (search: string, subpage?: boolean, namespace?: number) => ApiSuggestions | Promise<ApiSuggestions>;
61
+ export type ApiSuggest<T = string[]> = (search: string, subpage?: boolean, namespace?: number) => ApiSuggestions<T> | Promise<ApiSuggestions<T>>;
61
62
  export interface MwConfig extends MwConfigBase {
62
63
  nsid: Record<string, number>;
63
64
  variants?: string[];
64
65
  img?: Record<string, string>;
65
66
  permittedHtmlTags?: string[];
66
67
  implicitlyClosedHtmlTags?: string[];
67
- linkSuggest?: ApiSuggest;
68
+ articlePath?: string;
69
+ linkSuggest?: ApiSuggest<string>;
68
70
  paramSuggest?: ApiSuggest;
69
71
  titleParser?: (state: EditorState, node: SyntaxNode) => string | undefined;
70
- isbnParser?: (link: string) => string;
71
72
  }
72
73
  declare class MediaWikiData {
73
74
  /** 已解析的节点 */
@@ -83,6 +84,19 @@ declare class MediaWikiData {
83
84
  readonly urlProtocols: RegExp;
84
85
  constructor(tags: string[], urlProtocols: string);
85
86
  }
87
+ /**
88
+ * 是否为行首语法
89
+ * @param stream
90
+ * @param table 是否允许表格
91
+ * @param file 是否为文件
92
+ */
93
+ export declare const isSolSyntax: (stream: StringStream, table?: boolean, file?: boolean) => unknown;
94
+ /**
95
+ * 获取负向先行断言
96
+ * @param chars
97
+ * @param comment 是否仅排除注释
98
+ */
99
+ export declare const lookahead: (chars: string, comment?: boolean | State) => string;
86
100
  /** Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov */
87
101
  export declare class MediaWiki {
88
102
  readonly config: MwConfig;
package/dist/token.js CHANGED
@@ -154,7 +154,7 @@ const pop = (state) => {
154
154
  * @param table 是否允许表格
155
155
  * @param file 是否为文件
156
156
  */
157
- const isSolSyntax = (stream, table, file) => stream.sol() && (table && stream.match(/^\s*(?::+\s*)?\{\|/u, false)
157
+ export const isSolSyntax = (stream, table, file) => stream.sol() && (table && stream.match(/^\s*(?::+\s*)?\{\|/u, false)
158
158
  || stream.match(/^(?:-{4}|=)/u, false)
159
159
  || !file && /[*#;:]/u.test(stream.peek() || ''));
160
160
  /**
@@ -162,7 +162,7 @@ const isSolSyntax = (stream, table, file) => stream.sol() && (table && stream.ma
162
162
  * @param chars
163
163
  * @param comment 是否仅排除注释
164
164
  */
165
- const lookahead = (chars, comment) => {
165
+ export const lookahead = (chars, comment) => {
166
166
  const table = {
167
167
  "'": "'(?!')",
168
168
  '{': String.raw `\{(?!\{)`,
@@ -305,6 +305,11 @@ const getQuote = (stream) => {
305
305
  * @param t Tokenizer
306
306
  */
307
307
  const getEqual = (t) => t.name === 'inTemplateArgument' && t.args[0] ? '=' : '';
308
+ /**
309
+ * 转义字符类中的特殊字符
310
+ * @param chars 字符类
311
+ */
312
+ const escapeCharClass = (chars) => chars.replace(/[\]-]/gu, String.raw `\$&`);
308
313
  /**
309
314
  * 下一个字符是否为空白字符
310
315
  * @param stream StringStream
@@ -329,21 +334,21 @@ const syntaxHighlight = new Set(['syntaxhighlight', 'source', 'pre']), pageFunct
329
334
  'canonicalurle',
330
335
  'int',
331
336
  'msgnw',
332
- ]), substs = new Set(['subst', 'safesubst']), headerRegex = new RegExp(`^(?:[^&[<{~'-]|${lookahead("<{~'-")})+`, 'iu'), templateRegex = new RegExp(`^(?:[^|{}<]|${lookahead('{}<', true)})+`, 'u'), argumentRegex = new RegExp(`^(?:[^|[&:}{<~'__-]|${lookahead("}{<~'__-")})+`, 'iu'), styleRegex = new RegExp(`^(?:[^|[&}{<~'__-]|${lookahead("}{<~'__-")})+`, 'iu'), wikiRegex = new RegExp(`^(?:[^&'{[<~__:-]|${lookahead("'{[<~__-")})+`, 'iu'), tableDefinitionRegex = new RegExp(`^(?:[^&={<]|${lookahead('{<')})+`, 'iu'), tableCellRegex = /^\s*(?:[|!]|\{\{\s*![!)+-]?\s*\}\})/u, extLinkChars = "[{'<-", tableDefinitionChars = '{<', tableCellChars = "'<~__{-", htmlAttrChars = '{/', freeRegex = [false, true].map(lpar => {
337
+ ]), substs = new Set(['subst', 'safesubst']), headerRegex = new RegExp(String.raw `^(?:[^&[<{~'\-]|${lookahead("<{~'-")})+`, 'iu'), templateRegex = new RegExp(`^(?:[^|{}<]|${lookahead('{}<', true)})+`, 'u'), argumentRegex = new RegExp(String.raw `^(?:[^|[&:}{<~'__\-]|${lookahead("}{<~'__-")})+`, 'iu'), styleRegex = new RegExp(String.raw `^(?:[^|[&}{<~'__\-]|${lookahead("}{<~'__-")})+`, 'iu'), wikiRegex = new RegExp(String.raw `^(?:[^&:'{[<~__\-]|${lookahead("'{[<~__-")})+`, 'iu'), tableDefinitionRegex = new RegExp(`^(?:[^&={<]|${lookahead('{<')})+`, 'iu'), tableCellRegex = /^\s*(?:[|!]|\{\{\s*![!)\-+]?\s*\}\})/u, extLinkChars = "[{'<-", tableDefinitionChars = '{<', tableCellChars = "'<~__{-", htmlAttrChars = '{/', freeRegex = [false, true].map(lpar => {
333
338
  const punctuations = getPunctuations(lpar), source = getUrlRegex(punctuations);
334
339
  return new RegExp(`^(?:${source}|[${punctuations}]+(?=${source}))*`, 'u');
335
340
  }), indentedTableRegex = [false, true].map(isTemplate => new RegExp(String.raw `^:*\s*(?=\{${getPipe(isTemplate)})`, 'u')), tableRegex = [false, true]
336
341
  .map(isTemplate => new RegExp(String.raw `^${getPipe(isTemplate)}\s*`, 'u')), spacedTableRegex = [false, true].map(isTemplate => new RegExp(String.raw `^\s*(:+\s*)?(?=\{${getPipe(isTemplate)})`, 'u')), linkTextRegex = [false, true].map(file => {
337
342
  const chars = `]'{<${file ? '~' : '['}-`;
338
- return new RegExp(`^(?:[^&${file ? '[|' : ''}\\${chars}]|${lookahead(chars)})+`, 'iu');
343
+ return new RegExp(`^(?:[^&${file ? '[|' : ''}${escapeCharClass(chars)}]|${lookahead(chars)})+`, 'iu');
339
344
  }), linkErrorRegex = [
340
345
  new RegExp(String.raw `^(?:[<>{}]|%(?:3[ce]|[57][bd])|${lookahead('[]')})+`, 'iu'),
341
346
  new RegExp(String.raw `^(?:\}|${lookahead('[]{')})+`, 'u'),
342
347
  new RegExp(String.raw `^(?:[>}]|%(?:3[ce]|[57][bd])|${lookahead('[]{<')})+`, 'iu'),
343
- ], tableDefinitionValueRegex = ['', '='].map(equal => new RegExp(String.raw `^(?:[^\s&${tableDefinitionChars}${equal}]|${lookahead(tableDefinitionChars)})+`, 'iu')), variableRegex = [false, true].map(isDefault => new RegExp(String.raw `^(?:[^|{}<${isDefault ? "[&~'__:-" : ''}]|\}(?!\}\})|${isDefault ? lookahead("{<~'__-") : lookahead('{<', true)})+`, 'iu')), parserFunctionRegex = ['', '[&', '[&:'].map(s => getRegex(chars => new RegExp(`^(?:[^|${s}${chars}]|${lookahead(chars)})+`, 'iu'))), doubleUnderscoreRegex = {
348
+ ], tableDefinitionValueRegex = ['', '='].map(equal => new RegExp(String.raw `^(?:[^\s&${tableDefinitionChars}${equal}]|${lookahead(tableDefinitionChars)})+`, 'iu')), variableRegex = [false, true].map(isDefault => new RegExp(String.raw `^(?:[^|{}<${isDefault ? String.raw `[&~'__:\-` : ''}]|\}(?!\}\})|${isDefault ? lookahead("{<~'__-") : lookahead('{<', true)})+`, 'iu')), parserFunctionRegex = ['', '[&', '[&:'].map(s => getRegex(chars => new RegExp(`^(?:[^|${s}${escapeCharClass(chars)}]|${lookahead(chars)})+`, 'iu'))), doubleUnderscoreRegex = {
344
349
  _: /^[\p{L}\p{N}_]+?__/u,
345
350
  '_': /^[\p{L}\p{N}__]+?_{2}/u,
346
- }, getExtLinkTextRegex = getRegex(pipe => new RegExp(String.raw `^(?:[^\]&${pipe}${extLinkChars}]|${lookahead(extLinkChars)})+`, 'iu')), getExtLinkRegex = getRegex(pipe => new RegExp(`^(?:${getUrlRegex(pipe)})+`, 'u')), getTableDefinitionRegex = getRegex(s => new RegExp(`^(?:[^&${tableDefinitionChars}${s}]|${lookahead(tableDefinitionChars)})+`, 'iu')), getTableCellRegex = getRegex(s => new RegExp(`^(?:[^[&${s}${tableCellChars}]|${lookahead(tableCellChars)})+`, 'iu')), getHtmlAttrRegex = getRegex(s => new RegExp(`^(?:[^<>&${htmlAttrChars}${s}]|${lookahead(htmlAttrChars)})+`, 'u')), getHtmlAttrKeyRegex = getRegex(pipe => new RegExp(`^(?:[^<>&={/${pipe}]|${lookahead('{/')})+`, 'u')), getExtAttrRegex = getRegex(s => new RegExp(`^(?:[^>/${s}]|${lookahead('/')})+`, 'u')), getExtTagCloseRegex = getRegex(name => name === 'onlyinclude'
351
+ }, getExtLinkTextRegex = getRegex(pipe => new RegExp(String.raw `^(?:[^\]&${pipe}${escapeCharClass(extLinkChars)}]|${lookahead(extLinkChars)})+`, 'iu')), getExtLinkRegex = getRegex(pipe => new RegExp(`^(?:${getUrlRegex(pipe)})+`, 'u')), getTableDefinitionRegex = getRegex(s => new RegExp(`^(?:[^&${tableDefinitionChars}${s}]|${lookahead(tableDefinitionChars)})+`, 'iu')), getTableCellRegex = getRegex(s => new RegExp(`^(?:[^[&${s}${escapeCharClass(tableCellChars)}]|${lookahead(tableCellChars)})+`, 'iu')), getHtmlAttrRegex = getRegex(s => new RegExp(`^(?:[^<>&${htmlAttrChars}${s}]|${lookahead(htmlAttrChars)})+`, 'u')), getHtmlAttrKeyRegex = getRegex(pipe => new RegExp(`^(?:[^<>&={/${pipe}]|${lookahead('{/')})+`, 'u')), getExtAttrRegex = getRegex(s => new RegExp(`^(?:[^>/${s}]|${lookahead('/')})+`, 'u')), getExtTagCloseRegex = getRegex(name => name === 'onlyinclude'
347
352
  ? /<\/onlyinclude(?:>|$)/u
348
353
  : new RegExp(String.raw `</${name}\s*(?:>|$)`, 'iu')), getNestedRegex = getRegex(tag => new RegExp(String.raw `^(?:[^<]|<(?!${tag}(?:[\s/>]|$)))+`, 'iu'));
349
354
  /** Adapted from the original CodeMirror 5 stream parser by Pavel Astakhov */
@@ -463,15 +468,18 @@ let MediaWiki = (() => {
463
468
  this.fileRegex = new RegExp(String.raw `^(?:${Object.entries(nsid).filter(([, id]) => id === 6).map(([ns]) => ns).join('|')})\s*:`, 'iu');
464
469
  this.redirectRegex = new RegExp(String.raw `^\s*(?:${redirection.join('|')})(\s*:)?\s*(?=\[\[|$)`, 'iu');
465
470
  this.img = Object.keys(img).filter(word => !/\$1./u.test(word));
471
+ const spImgKeys = Object.keys(img).filter(word => word.startsWith('$1'));
466
472
  this.imgRegex = new RegExp(String.raw `^(?:${this.img.filter(word => word.endsWith('$1')).map(word => word.slice(0, -2))
467
- .join('|')}|(?:${this.img.filter(word => !word.endsWith('$1')).join('|')}|(?:\d+x?|\d*x\d+)\s*(?:px)?px)\s*(?=\||\]\]|$))`, 'u');
473
+ .join('|')}|(?:${this.img.filter(word => !word.endsWith('$1')).join('|')}|(?:(?:\d+x?|\d*x\d+)\s*(?:px)?(?:${spImgKeys.filter(word => img[word] === 'img_width').map(word => word.slice(2))
474
+ .join('|')}))|\d+\s*(?:${spImgKeys.filter(word => img[word] !== 'img_width').map(word => word.slice(2))
475
+ .join('|')}))\s*(?=\||\]\]|$))`, 'u');
468
476
  this.tags = [...Object.keys(tags), 'includeonly', 'noinclude', 'onlyinclude'];
469
- this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~__-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${lookahead("'{<~__-")})+`, 'iu');
477
+ this.convertRegex = new RegExp(String.raw `^(?:[^}|;&='{[<~__\-]|\}(?!-)|=(?!>)|\[(?!\[|${urlProtocols})|${lookahead("'{<~__-")})+`, 'iu');
470
478
  this.convertSemicolon = variants && new RegExp(String.raw `^;\s*(?=(?:[^;]*?=>\s*)?(?:${variants.join('|')})\s*:|(?:$|\}-))`, 'iu');
471
479
  this.convertLang = variants
472
480
  && new RegExp(String.raw `^(?:=>\s*)?(?:${variants.join('|')})\s*:`, 'iu');
473
481
  this.hasVariants = Boolean(variants?.length);
474
- this.preRegex = [false, true].map(begin => new RegExp(String.raw `^(?:[^<&-]|-${this.hasVariants ? String.raw `(?!\{)` : ''}|<(?!${begin ? '/' : ''}nowiki>))+`, 'iu'));
482
+ this.preRegex = [false, true].map(begin => new RegExp(String.raw `^(?:[^<&\-]|-${this.hasVariants ? String.raw `(?!\{)` : ''}|<(?!${begin ? '/' : ''}nowiki>))+`, 'iu'));
475
483
  this.substRegex = new RegExp(String.raw `^\s*(?:(${Object.entries(insensitive).filter(([, v]) => substs.has(v))
476
484
  .map(([k]) => k + (k.endsWith(':') ? '' : ':'))
477
485
  .join('|')})\s*)?`, 'iu');
@@ -775,7 +783,7 @@ let MediaWiki = (() => {
775
783
  stream.backUp(1);
776
784
  }
777
785
  else {
778
- stream.eatWhile(/[^\p{L}\p{N}__&'{[<~:-]/u);
786
+ stream.eatWhile(/[^\p{L}\p{N}__&'{[<\-~:]/u);
779
787
  }
780
788
  const mt = stream.match(this.urlProtocols, false);
781
789
  if (mt) {
@@ -1046,7 +1054,7 @@ let MediaWiki = (() => {
1046
1054
  return (stream, state) => {
1047
1055
  if (stream.sol()) {
1048
1056
  stream.eatSpace();
1049
- const mt = stream.match(/^(?:\||\{\{\s*!([!)+-])?\s*\}\})/u);
1057
+ const mt = stream.match(/^(?:\||\{\{\s*!([!)\-+])?\s*\}\})/u);
1050
1058
  if (mt) {
1051
1059
  if (mt[1] === '-' || !mt[1] && stream.eat('-')) {
1052
1060
  stream.match(/^-*\s*/u);
@@ -1648,7 +1656,7 @@ let MediaWiki = (() => {
1648
1656
  if (expectName
1649
1657
  && stream.match(new RegExp(`^(?:[^=|}{[<]|${lookahead('}{[<', state)})*=`, 'iu'))) {
1650
1658
  state.tokenize = this.inTemplateArgument(false, parserFunction);
1651
- return makeLocalTagStyle('templateArgumentName', state);
1659
+ return makeLocalTagStyle(parserFunction ? 'parserFunctionArgumentName' : 'templateArgumentName', state);
1652
1660
  }
1653
1661
  else if (isSolSyntax(stream) && stream.peek() !== '=') {
1654
1662
  return this.eatWikiText(tag)(stream, state);
@@ -1684,7 +1692,7 @@ let MediaWiki = (() => {
1684
1692
  if (stream.match('-{', false)) {
1685
1693
  return this.eatWikiText(style)(stream, state);
1686
1694
  }
1687
- stream.match(/^(?:(?:[^};=-]|\}(?!-)|=(?!>)|-(?!\{))+|;|=>)/u);
1695
+ stream.match(/^(?:(?:[^}\-;=]|\}(?!-)|=(?!>)|-(?!\{))+|;|=>)/u);
1688
1696
  return makeStyle(style, state);
1689
1697
  }
1690
1698
  return !isSolSyntax(stream, true) && stream.match(this.convertRegex) || space
@@ -1782,16 +1790,17 @@ let MediaWiki = (() => {
1782
1790
  // get token style
1783
1791
  stream.start = stream.pos;
1784
1792
  const char = stream.peek(), style = state.tokenize(stream, state);
1785
- if (typeof style === 'string' && style.includes(tokens.templateArgumentName)) {
1793
+ if (typeof style === 'string' && style.includes('-argument-name')) {
1794
+ const isTemplate = style.includes(tokens.templateArgumentName), argument = tokens[isTemplate ? 'template' : 'parserFunction'], argumentName = tokens[isTemplate ? 'templateArgumentName' : 'parserFunctionArgumentName'], delimiter = tokens[isTemplate ? 'templateDelimiter' : 'parserFunctionDelimiter'];
1786
1795
  for (let i = readyTokens.length - 1; i >= 0; i--) {
1787
1796
  const token = readyTokens[i];
1788
1797
  if (cmpNesting(state, token.state, true)) {
1789
- const types = typeof token.style === 'string' && token.style.split(' '), j = types && types.indexOf(tokens.template);
1798
+ const types = typeof token.style === 'string' && token.style.split(' '), j = types && types.indexOf(argument);
1790
1799
  if (j !== false && j !== -1) {
1791
- types[j] = tokens.templateArgumentName;
1800
+ types[j] = argumentName;
1792
1801
  token.style = types.join(' ');
1793
1802
  }
1794
- else if (types && types.includes(tokens.templateDelimiter)) {
1803
+ else if (types && types.includes(delimiter)) {
1795
1804
  break;
1796
1805
  }
1797
1806
  }
package/dist/util.d.ts CHANGED
@@ -1,7 +1,9 @@
1
1
  import type { EditorView, TooltipView } from '@codemirror/view';
2
- import type { Text, EditorState } from '@codemirror/state';
2
+ import type { Text, EditorState, SelectionRange } from '@codemirror/state';
3
3
  import type { SyntaxNode } from '@lezer/common';
4
4
  import type { Position } from 'vscode-languageserver-types';
5
+ import type { ConfigGetter } from '@bhsd/browser';
6
+ import type { TagName } from './config';
5
7
  /**
6
8
  * 转义HTML字符串
7
9
  * @param text 原字符串
@@ -25,18 +27,31 @@ export declare const posToIndex: (doc: Text, pos: Position) => number;
25
27
  * @param innerHTML 提示内容
26
28
  */
27
29
  export declare const createTooltipView: (view: EditorView, innerHTML: string) => TooltipView;
30
+ /**
31
+ * 获取节点对应的字符串
32
+ * @param state EditorState 实例
33
+ * @param node 语法树节点
34
+ */
35
+ export declare const sliceDoc: (state: EditorState, node: SyntaxNode | SelectionRange) => string;
28
36
  /**
29
37
  * Update the stack of opening (+) or closing (-) brackets
30
38
  * @param state
31
39
  * @param node 语法树节点
32
40
  */
33
41
  export declare const braceStackUpdate: (state: EditorState, node: SyntaxNode) => [number, number];
42
+ /**
43
+ * Find the current template name
44
+ * @param state
45
+ * @param node 语法树节点
46
+ */
47
+ export declare const findTemplateName: (state: EditorState, node: SyntaxNode) => string | null;
34
48
  /**
35
49
  * 判断节点是否包含指定类型
36
50
  * @param types 节点类型
37
51
  * @param names 指定类型
38
52
  */
39
- export declare const hasTag: (types: Set<string>, names: string | string[]) => boolean;
53
+ export declare const hasTag: (types: Set<string>, names: TagName | TagName[]) => boolean;
54
+ export declare const toConfigGetter: (configGetter?: ConfigGetter, articlePath?: string) => ConfigGetter | undefined;
40
55
  /**
41
56
  * 获取字符串开头的空白字符
42
57
  * @param str 字符串
package/dist/util.js CHANGED
@@ -36,21 +36,59 @@ export const createTooltipView = (view, innerHTML) => {
36
36
  inner.innerHTML = innerHTML;
37
37
  return { dom };
38
38
  };
39
+ /**
40
+ * 获取节点对应的字符串
41
+ * @param state EditorState 实例
42
+ * @param node 语法树节点
43
+ */
44
+ export const sliceDoc = (state, node) => state.sliceDoc(node.from, node.to);
39
45
  /**
40
46
  * Update the stack of opening (+) or closing (-) brackets
41
47
  * @param state
42
48
  * @param node 语法树节点
43
49
  */
44
50
  export const braceStackUpdate = (state, node) => {
45
- const brackets = state.sliceDoc(node.from, node.to);
51
+ const brackets = sliceDoc(state, node);
46
52
  return [brackets.split('{{').length - 1, 1 - brackets.split('}}').length];
47
53
  };
54
+ /**
55
+ * Find the current template name
56
+ * @param state
57
+ * @param node 语法树节点
58
+ */
59
+ export const findTemplateName = (state, node) => {
60
+ let stack = -1, { prevSibling } = node,
61
+ /** 可包含`_`、`:`等 */ page = '';
62
+ while (prevSibling) {
63
+ const { name } = prevSibling;
64
+ if (name.includes(tokens.templateBracket)) {
65
+ const [lbrace, rbrace] = braceStackUpdate(state, prevSibling);
66
+ stack += lbrace;
67
+ if (stack >= 0) {
68
+ break;
69
+ }
70
+ stack += rbrace;
71
+ }
72
+ else if (stack === -1 && name.includes(tokens.templateName)) {
73
+ page = sliceDoc(state, prevSibling) + page;
74
+ }
75
+ else if (page && !name.includes(tokens.comment)) {
76
+ prevSibling = null;
77
+ break;
78
+ }
79
+ ({ prevSibling } = prevSibling);
80
+ }
81
+ return prevSibling && page;
82
+ };
48
83
  /**
49
84
  * 判断节点是否包含指定类型
50
85
  * @param types 节点类型
51
86
  * @param names 指定类型
52
87
  */
53
88
  export const hasTag = (types, names) => (Array.isArray(names) ? names : [names]).some(name => types.has(name in tokens ? tokens[name] : name));
89
+ export const toConfigGetter = (configGetter, articlePath) => articlePath
90
+ ? async () => Object.assign(await (configGetter ?? wikiparse.getConfig)(), { articlePath })
91
+ : configGetter;
54
92
  /**
55
93
  * 获取字符串开头的空白字符
56
94
  * @param str 字符串