@bhsd/codemirror-mediawiki 3.10.2 → 3.11.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/mwConfig.js CHANGED
@@ -1,84 +1,16 @@
1
- // ../browser/dist/index.js
2
- var CDN = "https://testingcf.jsdelivr.net";
3
- var getObject = (key) => JSON.parse(String(localStorage.getItem(key)));
4
- var setObject = (key, value) => {
5
- localStorage.setItem(key, JSON.stringify(value));
6
- };
7
-
8
- // ../cm-util/dist/index.mjs
9
- var otherParserFunctions = /* @__PURE__ */ new Set(["msg", "raw", "subst", "safesubst"]);
10
- var isUnderscore = (s) => !/^_{2}.+_{2}$/u.test(s);
11
- var cleanAliases = (aliases) => {
12
- for (const key in aliases) {
13
- if (/^[^##].*:$/u.test(key)) {
14
- delete aliases[key];
15
- }
16
- }
17
- };
18
- var getConfig = (magicWords, rule, flip) => {
19
- const words = magicWords.filter(rule);
20
- return Object.fromEntries(
21
- (flip === void 0 ? words : words.filter(({ "case-sensitive": i }) => i !== flip)).flatMap(({ aliases, name: n, "case-sensitive": i }) => aliases.map((alias) => ({
22
- alias: (i ? alias : alias.toLowerCase()).replace(/:$/u, ""),
23
- name: n
24
- }))).map(({ alias, name: n }) => [alias, n])
25
- );
26
- };
27
- var getParserConfig = (minConfig, mwConfig) => {
28
- const {
29
- tags,
30
- doubleUnderscore,
31
- urlProtocols,
32
- functionSynonyms,
33
- variableIDs,
34
- functionHooks,
35
- redirection
36
- } = mwConfig, [insensitive, sensitive] = functionSynonyms, behaviorSwitch = doubleUnderscore.map(
37
- (obj, i) => Object.entries(obj).map(([k, v]) => [
38
- isUnderscore(k) ? k.slice(2, -2) : k,
39
- i && typeof v === "string" ? v.toUpperCase() : v
40
- ])
41
- );
42
- cleanAliases(insensitive);
43
- cleanAliases(sensitive);
44
- for (const [k, v] of Object.entries(insensitive)) {
45
- if (k in sensitive) {
46
- delete insensitive[k];
47
- } else {
48
- insensitive[k] = v.toLowerCase();
49
- }
50
- }
51
- return {
52
- ...minConfig,
53
- ext: Object.keys(tags),
54
- parserFunction: [{ ...insensitive }, { ...sensitive, "=": "=" }, [], []],
55
- doubleUnderscore: [
56
- ...behaviorSwitch.map(
57
- (entries) => entries.filter(([k]) => isUnderscore(k)).map(([k]) => k)
58
- ),
59
- ...behaviorSwitch.map(Object.fromEntries)
60
- ],
61
- protocol: urlProtocols.replace(/\|\\?\/\\?\/$|\\(?=[:/])/gu, ""),
62
- ...variableIDs && { variable: [.../* @__PURE__ */ new Set([...variableIDs, "="])] },
63
- ...functionHooks && { functionHook: [.../* @__PURE__ */ new Set([...functionHooks.map((s) => s.toLowerCase()), "msgnw"])] },
64
- ...redirection && { redirection: redirection.map((s) => s.toLowerCase()) }
65
- };
66
- };
67
- var getVariants = (variants) => {
68
- var _a;
69
- return (_a = variants == null ? void 0 : variants.map(({ code }) => code)) != null ? _a : [];
70
- };
71
- var getKeywords = (magicwords, web) => ({
72
- img: Object.fromEntries(
73
- magicwords.filter(({ name: n }) => n.startsWith("img_") && n !== "img_lossy").flatMap(({ name: n, aliases }) => {
74
- const k = web ? n : n.slice(4).replace(/_/gu, "-");
75
- return (n === "img_alt" ? aliases.filter((alias) => alias.includes("$1")) : aliases).map((alias) => [alias, k]);
76
- })
77
- ),
78
- redirection: magicwords.find(({ name: n }) => n === "redirect").aliases.map((s) => s.toLowerCase())
79
- });
1
+ // mw/config.ts
2
+ import { CDN, setObject, getObject } from "@bhsd/browser";
3
+ import {
4
+ cleanAliases,
5
+ getParserConfig as getParserConfigBase,
6
+ getConfig,
7
+ getVariants,
8
+ getKeywords,
9
+ otherParserFunctions
10
+ } from "@bhsd/cm-util";
80
11
 
81
12
  // src/static.ts
13
+ import { isUnderscore } from "@bhsd/cm-util";
82
14
  var getStaticMwConfig = ({
83
15
  variable,
84
16
  parserFunction: [p0, p1, ...p2],
@@ -199,14 +131,14 @@ var getMwConfig = async (modes) => {
199
131
  setObject("InPageEditMwConfig", ALL_SETTINGS_CACHE);
200
132
  return { ...config, nsid };
201
133
  };
202
- var getParserConfig2 = (minConfig, mwConfig) => {
134
+ var getParserConfig = (minConfig, mwConfig) => {
203
135
  let config = getObject("wikilintConfig");
204
136
  if (config) {
205
137
  return config;
206
138
  }
207
139
  const { nsid, variants, functionSynonyms, img } = mwConfig, [insensitive] = functionSynonyms;
208
140
  config = {
209
- ...getParserConfig(minConfig, mwConfig),
141
+ ...getParserConfigBase(minConfig, mwConfig),
210
142
  namespaces: mw.config.get("wgFormattedNamespaces"),
211
143
  nsid,
212
144
  variants,
@@ -228,5 +160,5 @@ var getParserConfig2 = (minConfig, mwConfig) => {
228
160
  };
229
161
  export {
230
162
  getMwConfig,
231
- getParserConfig2 as getParserConfig
163
+ getParserConfig
232
164
  };
package/dist/openLinks.js CHANGED
@@ -48,7 +48,7 @@ export const mouseEventListener = (e, view, isbnParser, titleParser) => {
48
48
  if (node.name.includes(tokens.linkToSection)) {
49
49
  node = node.prevSibling;
50
50
  }
51
- else if (!hasTag(new Set(node.name.split('_')), tags)) {
51
+ else if (node.to === position && !hasTag(new Set(node.name.split('_')), tags)) {
52
52
  node = tree.resolve(position, 1);
53
53
  }
54
54
  const { name, from, to } = node;
package/dist/ref.js CHANGED
@@ -72,7 +72,7 @@ export default (articlePath) => (cm) => {
72
72
  return [
73
73
  hoverTooltip(async (view, pos, side) => {
74
74
  const { state } = view, node = ensureSyntaxTree(state, pos)?.resolve(pos, side);
75
- if (node && node.name.includes('-exttag-')) {
75
+ if (node?.name.includes('-exttag-')) {
76
76
  const tag = getTag(state, node);
77
77
  if (tag && needHover(state, tag)) {
78
78
  const { doc } = state, ref = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), base.CDN)?.provideDefinition(doc.toString(), indexToPos(doc, tag.first.to));
@@ -1,6 +1,9 @@
1
1
  import type { Extension } from '@codemirror/state';
2
- import type { SignatureHelp } from 'vscode-languageserver-types';
2
+ import type { SignatureHelp as SignatureHelpBase, SignatureInformation } from 'vscode-languageserver-types';
3
3
  import type { CodeMirror6 } from './codemirror';
4
+ interface SignatureHelp extends Omit<SignatureHelpBase, 'signatures'> {
5
+ signatures: SignatureInformation[] | string[];
6
+ }
4
7
  /**
5
8
  * @ignore
6
9
  * @test
package/dist/signature.js CHANGED
@@ -1,8 +1,9 @@
1
1
  import { EditorView, showTooltip } from '@codemirror/view';
2
2
  import { StateField, StateEffect } from '@codemirror/state';
3
+ import { syntaxTree } from '@codemirror/language';
3
4
  import { getLSP } from '@bhsd/browser';
4
5
  import { base } from './constants.js';
5
- import { createTooltipView, indexToPos, escHTML, toConfigGetter, } from './util.js';
6
+ import { createTooltipView, indexToPos, escHTML, toConfigGetter, findTemplateName, isTemplate, } from './util.js';
6
7
  const stateEffect = StateEffect.define(), field = StateField.define({
7
8
  create() {
8
9
  return undefined;
@@ -24,8 +25,12 @@ const stateEffect = StateEffect.define(), field = StateField.define({
24
25
  * @ignore
25
26
  * @test
26
27
  */
27
- export const getSignatureHelp = ({ signatures, activeParameter: active }) => signatures.map(({ label, parameters, activeParameter = active }) => {
28
- const safeLabel = escHTML(label);
28
+ export const getSignatureHelp = ({ signatures, activeParameter: active }) => signatures.map(signature => {
29
+ if (typeof signature === 'string') {
30
+ const safeLabel = escHTML(signature), pipe = safeLabel.indexOf('|'), equal = safeLabel.indexOf('=', pipe);
31
+ return `${safeLabel.slice(0, pipe)}|<b>${safeLabel.slice(pipe + 1, equal)}</b>${safeLabel.slice(equal)}`;
32
+ }
33
+ const { label, parameters, activeParameter = active } = signature, safeLabel = escHTML(label);
29
34
  if (activeParameter < 0 || activeParameter >= parameters.length) {
30
35
  return safeLabel;
31
36
  }
@@ -46,22 +51,42 @@ export default (articlePath) => (cm) => {
46
51
  return;
47
52
  }
48
53
  (async () => {
54
+ let signatureHelp = await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), base.CDN)?.provideSignatureHelp(text, indexToPos(doc, cursor));
55
+ if (!signatureHelp && typeof cm.langConfig?.templateSignature === 'function') {
56
+ const tree = syntaxTree(state);
57
+ let node = tree.resolve(cursor, -1);
58
+ if (node.to === cursor && !isTemplate(node)) {
59
+ node = tree.resolve(cursor, 1);
60
+ }
61
+ if (isTemplate(node)) {
62
+ const [templateName, parameterName] = findTemplateName(state, node), tooltip = cm.langConfig.templateSignature(templateName, parameterName);
63
+ if (tooltip) {
64
+ signatureHelp = { signatures: [tooltip] };
65
+ }
66
+ }
67
+ }
49
68
  view.dispatch({
50
- effects: stateEffect.of({
51
- text,
52
- cursor,
53
- signatureHelp: await getLSP(view, false, toConfigGetter(cm.getWikiConfig, articlePath), base.CDN)?.provideSignatureHelp(text, indexToPos(doc, cursor)),
54
- }),
69
+ effects: stateEffect.of({ text, cursor, signatureHelp }),
55
70
  });
56
71
  })();
57
72
  }
58
73
  }),
74
+ EditorView.domEventHandlers({
75
+ keydown({ key }, view) {
76
+ if (key === 'Escape') {
77
+ const { doc, selection: { main: { head } } } = view.state;
78
+ view.dispatch({
79
+ effects: stateEffect.of({ text: doc.toString(), cursor: head }),
80
+ });
81
+ }
82
+ },
83
+ }),
59
84
  showTooltip.from(field, (value) => {
60
85
  if (!value) {
61
86
  return null;
62
87
  }
63
88
  const { cursor, signatureHelp } = value;
64
- return signatureHelp && signatureHelp.signatures.length > 0
89
+ return signatureHelp?.signatures.length
65
90
  ? {
66
91
  pos: cursor,
67
92
  above: true,
package/dist/token.d.ts CHANGED
@@ -70,6 +70,7 @@ export interface MwConfig extends MwConfigBase {
70
70
  linkSuggest?: ApiSuggest<string>;
71
71
  paramSuggest?: ApiSuggest;
72
72
  titleParser?: (state: EditorState, node: SyntaxNode) => string | undefined;
73
+ templateSignature?: (templateName: string | null, parameterName: string) => string | undefined;
73
74
  }
74
75
  declare class MediaWikiData {
75
76
  /** 已解析的节点 */
package/dist/util.d.ts CHANGED
@@ -45,12 +45,17 @@ export declare const sliceDoc: (state: EditorState, node: SyntaxNode | Selection
45
45
  */
46
46
  export declare const braceStackUpdate: (state: EditorState, node: SyntaxNode) => [number, number];
47
47
  /**
48
- * Find the current template name
48
+ * Check if the node is a template parameter value
49
+ * @param node 语法树节点
50
+ */
51
+ export declare const isTemplate: (node: SyntaxNode) => boolean;
52
+ /**
53
+ * Find the current template name and parameter name
49
54
  * @param state
50
55
  * @param node 语法树节点
51
56
  * @test
52
57
  */
53
- export declare const findTemplateName: (state: EditorState, node: SyntaxNode) => string | null;
58
+ export declare const findTemplateName: (state: EditorState, node: SyntaxNode) => [string | null, string];
54
59
  /**
55
60
  * 判断节点是否包含指定类型
56
61
  * @param types 节点类型
package/dist/util.js CHANGED
@@ -57,17 +57,26 @@ export const braceStackUpdate = (state, node) => {
57
57
  return [brackets.split('{{').length - 1, 1 - brackets.split('}}').length];
58
58
  };
59
59
  /**
60
- * Find the current template name
60
+ * Check if the node is a template parameter value
61
+ * @param node 语法树节点
62
+ */
63
+ export const isTemplate = (node) => node.name.split('_').includes(tokens.template);
64
+ /**
65
+ * Find the current template name and parameter name
61
66
  * @param state
62
67
  * @param node 语法树节点
63
68
  * @test
64
69
  */
65
70
  export const findTemplateName = (state, node) => {
66
71
  let stack = -1, { prevSibling } = node,
67
- /** 可包含`_`、`:`等 */ page = '';
72
+ /** 可包含`_`、`:`等 */ page = '', parameter = '', need = isTemplate(node);
68
73
  while (prevSibling) {
69
74
  const { name } = prevSibling;
70
75
  if (name.includes(tokens.templateBracket)) {
76
+ if (need && parameter) {
77
+ need = false;
78
+ parameter = '';
79
+ }
71
80
  const [lbrace, rbrace] = braceStackUpdate(state, prevSibling);
72
81
  stack += lbrace;
73
82
  if (stack >= 0) {
@@ -75,8 +84,22 @@ export const findTemplateName = (state, node) => {
75
84
  }
76
85
  stack += rbrace;
77
86
  }
78
- else if (stack === -1 && name.includes(tokens.templateName)) {
79
- page = sliceDoc(state, prevSibling) + page;
87
+ else if (stack === -1) {
88
+ if (name.includes(tokens.templateName)) {
89
+ page = sliceDoc(state, prevSibling) + page;
90
+ }
91
+ else if (need) {
92
+ if (name.includes(tokens.templateDelimiter)) {
93
+ need = false;
94
+ }
95
+ else if (name.includes(tokens.templateArgumentName)) {
96
+ parameter = sliceDoc(state, prevSibling) + parameter;
97
+ }
98
+ else if (parameter && !name.includes(tokens.comment)) {
99
+ need = false;
100
+ parameter = '';
101
+ }
102
+ }
80
103
  }
81
104
  else if (page && !name.includes(tokens.comment)) {
82
105
  prevSibling = null;
@@ -84,7 +107,7 @@ export const findTemplateName = (state, node) => {
84
107
  }
85
108
  ({ prevSibling } = prevSibling);
86
109
  }
87
- return prevSibling && page;
110
+ return [prevSibling && page, parameter];
88
111
  };
89
112
  /**
90
113
  * 判断节点是否包含指定类型
package/dist/vue.d.ts CHANGED
@@ -1,3 +1,4 @@
1
1
  import { LanguageSupport } from '@codemirror/language';
2
- declare const _default: () => LanguageSupport;
2
+ import type { CodeMirror6 } from './codemirror';
3
+ declare const _default: (_?: unknown, cm?: CodeMirror6) => LanguageSupport;
3
4
  export default _default;
package/dist/vue.js CHANGED
@@ -3,12 +3,13 @@ import { htmlLanguage, htmlCompletionSource } from '@codemirror/lang-html';
3
3
  import { javascript } from '@codemirror/lang-javascript';
4
4
  import { LanguageSupport } from '@codemirror/language';
5
5
  import { cssCompletion } from './css.js';
6
- import { jsCompletion } from './javascript.js';
7
- export default () => vue({
6
+ import { jsCompletion, markGlobalsPlugin } from './javascript.js';
7
+ export default (_, cm) => vue({
8
8
  base: new LanguageSupport(htmlLanguage, [
9
9
  htmlLanguage.data.of({ autocomplete: htmlCompletionSource }),
10
10
  javascript().support,
11
11
  jsCompletion,
12
12
  cssCompletion(),
13
+ markGlobalsPlugin(cm),
13
14
  ]),
14
15
  });