@neo4j-cypher/react-codemirror 2.0.0-next.4 → 2.0.0-next.41

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 (186) hide show
  1. package/CHANGELOG.md +370 -0
  2. package/README.md +3 -2
  3. package/dist/src/CypherEditor.d.ts +245 -0
  4. package/dist/src/CypherEditor.js +513 -0
  5. package/dist/src/CypherEditor.js.map +1 -0
  6. package/dist/src/CypherEditor.test.js +162 -0
  7. package/dist/src/CypherEditor.test.js.map +1 -0
  8. package/dist/src/constants.d.ts +1 -0
  9. package/dist/src/constants.js +2 -0
  10. package/dist/src/constants.js.map +1 -0
  11. package/dist/src/diffView.d.ts +13 -0
  12. package/dist/src/diffView.js +11 -0
  13. package/dist/src/diffView.js.map +1 -0
  14. package/dist/src/e2e_tests/autoCompletion.spec.js +334 -0
  15. package/dist/src/e2e_tests/autoCompletion.spec.js.map +1 -0
  16. package/dist/src/e2e_tests/configuration.spec.js +83 -0
  17. package/dist/src/e2e_tests/configuration.spec.js.map +1 -0
  18. package/dist/src/e2e_tests/debounce.spec.js +66 -0
  19. package/dist/src/e2e_tests/debounce.spec.js.map +1 -0
  20. package/dist/{types/e2e_tests/e2e-utils.d.ts → src/e2e_tests/e2eUtils.d.ts} +2 -0
  21. package/dist/src/e2e_tests/e2eUtils.js +79 -0
  22. package/dist/src/e2e_tests/e2eUtils.js.map +1 -0
  23. package/dist/src/e2e_tests/extraKeybindings.spec.js +43 -0
  24. package/dist/src/e2e_tests/extraKeybindings.spec.js.map +1 -0
  25. package/dist/src/e2e_tests/historyNavigation.spec.js +227 -0
  26. package/dist/src/e2e_tests/historyNavigation.spec.js.map +1 -0
  27. package/dist/src/e2e_tests/performanceTest.spec.d.ts +6 -0
  28. package/dist/src/e2e_tests/performanceTest.spec.js +97 -0
  29. package/dist/src/e2e_tests/performanceTest.spec.js.map +1 -0
  30. package/dist/src/e2e_tests/sanityChecks.spec.js +64 -0
  31. package/dist/src/e2e_tests/sanityChecks.spec.js.map +1 -0
  32. package/dist/src/e2e_tests/signatureHelp.spec.js +226 -0
  33. package/dist/src/e2e_tests/signatureHelp.spec.js.map +1 -0
  34. package/dist/src/e2e_tests/snippets.spec.js +14 -0
  35. package/dist/src/e2e_tests/snippets.spec.js.map +1 -0
  36. package/dist/src/e2e_tests/syntaxHighlighting.spec.d.ts +1 -0
  37. package/dist/src/e2e_tests/syntaxHighlighting.spec.js +90 -0
  38. package/dist/src/e2e_tests/syntaxHighlighting.spec.js.map +1 -0
  39. package/dist/src/e2e_tests/syntaxValidation.spec.d.ts +1 -0
  40. package/dist/src/e2e_tests/syntaxValidation.spec.js +129 -0
  41. package/dist/src/e2e_tests/syntaxValidation.spec.js.map +1 -0
  42. package/dist/src/editorActions.d.ts +17 -0
  43. package/dist/src/editorActions.js +259 -0
  44. package/dist/src/editorActions.js.map +1 -0
  45. package/dist/{types/history-navigation.d.ts → src/historyNavigation.d.ts} +1 -1
  46. package/dist/src/historyNavigation.js +163 -0
  47. package/dist/src/historyNavigation.js.map +1 -0
  48. package/dist/src/hostCallbacks.d.ts +9 -0
  49. package/dist/src/hostCallbacks.js +2 -0
  50. package/dist/src/hostCallbacks.js.map +1 -0
  51. package/dist/{types → src}/icons.d.ts +1 -1
  52. package/dist/src/icons.js +62 -0
  53. package/dist/src/icons.js.map +1 -0
  54. package/dist/src/index.d.ts +6 -0
  55. package/dist/src/index.js +5 -0
  56. package/dist/src/index.js.map +1 -0
  57. package/dist/src/inlinePanel.d.ts +27 -0
  58. package/dist/src/inlinePanel.js +86 -0
  59. package/dist/src/inlinePanel.js.map +1 -0
  60. package/dist/src/lang-cypher/autocomplete.d.ts +6 -0
  61. package/dist/src/lang-cypher/autocomplete.js +116 -0
  62. package/dist/src/lang-cypher/autocomplete.js.map +1 -0
  63. package/dist/{types → src}/lang-cypher/constants.d.ts +15 -2
  64. package/dist/src/lang-cypher/constants.js +74 -0
  65. package/dist/src/lang-cypher/constants.js.map +1 -0
  66. package/dist/src/lang-cypher/contants.test.d.ts +1 -0
  67. package/dist/src/lang-cypher/contants.test.js +103 -0
  68. package/dist/src/lang-cypher/contants.test.js.map +1 -0
  69. package/dist/{types/lang-cypher/create-cypher-theme.d.ts → src/lang-cypher/createCypherTheme.d.ts} +14 -3
  70. package/dist/src/lang-cypher/createCypherTheme.js +202 -0
  71. package/dist/src/lang-cypher/createCypherTheme.js.map +1 -0
  72. package/dist/src/lang-cypher/langCypher.d.ts +15 -0
  73. package/dist/src/lang-cypher/langCypher.js +23 -0
  74. package/dist/src/lang-cypher/langCypher.js.map +1 -0
  75. package/dist/src/lang-cypher/lintWorker.mjs +2039 -0
  76. package/dist/src/lang-cypher/parser-adapter.d.ts +21 -0
  77. package/dist/src/lang-cypher/parser-adapter.js +115 -0
  78. package/dist/src/lang-cypher/parser-adapter.js.map +1 -0
  79. package/dist/src/lang-cypher/prism-global.d.ts +1 -0
  80. package/dist/src/lang-cypher/prism-global.js +7 -0
  81. package/dist/src/lang-cypher/prism-global.js.map +1 -0
  82. package/dist/src/lang-cypher/signatureHelp.d.ts +4 -0
  83. package/dist/src/lang-cypher/signatureHelp.js +108 -0
  84. package/dist/src/lang-cypher/signatureHelp.js.map +1 -0
  85. package/dist/src/lang-cypher/syntaxValidation.d.ts +4 -0
  86. package/dist/src/lang-cypher/syntaxValidation.js +65 -0
  87. package/dist/src/lang-cypher/syntaxValidation.js.map +1 -0
  88. package/dist/src/lang-cypher/themeIcons.js +22 -0
  89. package/dist/src/lang-cypher/themeIcons.js.map +1 -0
  90. package/dist/src/lang-cypher/utils.d.ts +2 -0
  91. package/dist/src/lang-cypher/utils.js +10 -0
  92. package/dist/src/lang-cypher/utils.js.map +1 -0
  93. package/dist/src/ndlTokensCopy.d.ts +570 -0
  94. package/dist/src/ndlTokensCopy.js +571 -0
  95. package/dist/src/ndlTokensCopy.js.map +1 -0
  96. package/dist/src/ndlTokensCopy.test.d.ts +1 -0
  97. package/dist/src/ndlTokensCopy.test.js +12 -0
  98. package/dist/src/ndlTokensCopy.test.js.map +1 -0
  99. package/dist/src/neo4jSetup.d.ts +6 -0
  100. package/dist/src/neo4jSetup.js +120 -0
  101. package/dist/src/neo4jSetup.js.map +1 -0
  102. package/dist/src/richClipboardCopier.d.ts +4 -0
  103. package/dist/src/richClipboardCopier.js +78 -0
  104. package/dist/src/richClipboardCopier.js.map +1 -0
  105. package/dist/src/richClipboardCopier.test.d.ts +1 -0
  106. package/dist/src/richClipboardCopier.test.js +53 -0
  107. package/dist/src/richClipboardCopier.test.js.map +1 -0
  108. package/dist/src/themes.d.ts +5 -0
  109. package/dist/src/themes.js +107 -0
  110. package/dist/src/themes.js.map +1 -0
  111. package/dist/tsconfig.tsbuildinfo +1 -0
  112. package/package.json +64 -62
  113. package/src/CypherEditor.test.tsx +211 -0
  114. package/src/CypherEditor.tsx +586 -59
  115. package/src/constants.ts +1 -0
  116. package/src/diffView.ts +24 -0
  117. package/src/e2e_tests/autoCompletion.spec.tsx +576 -0
  118. package/src/e2e_tests/configuration.spec.tsx +111 -0
  119. package/src/e2e_tests/debounce.spec.tsx +102 -0
  120. package/src/e2e_tests/{e2e-utils.ts → e2eUtils.ts} +41 -3
  121. package/src/e2e_tests/{extra-keybindings.spec.tsx → extraKeybindings.spec.tsx} +1 -3
  122. package/src/e2e_tests/{history-navigation.spec.tsx → historyNavigation.spec.tsx} +138 -19
  123. package/src/e2e_tests/performanceTest.spec.tsx +163 -0
  124. package/src/e2e_tests/{sanity-checks.spec.tsx → sanityChecks.spec.tsx} +28 -20
  125. package/src/e2e_tests/signatureHelp.spec.tsx +442 -0
  126. package/src/e2e_tests/snippets.spec.tsx +19 -0
  127. package/src/e2e_tests/{syntax-highlighting.spec.tsx → syntaxHighlighting.spec.tsx} +26 -24
  128. package/src/e2e_tests/syntaxValidation.spec.tsx +252 -0
  129. package/src/editorActions.ts +334 -0
  130. package/src/{history-navigation.ts → historyNavigation.ts} +6 -4
  131. package/src/hostCallbacks.ts +9 -0
  132. package/src/icons.ts +3 -0
  133. package/src/index.ts +4 -2
  134. package/src/inlinePanel.ts +140 -0
  135. package/src/lang-cypher/autocomplete.ts +96 -19
  136. package/src/lang-cypher/constants.ts +35 -2
  137. package/src/lang-cypher/contants.test.ts +7 -3
  138. package/src/lang-cypher/{create-cypher-theme.ts → createCypherTheme.ts} +97 -33
  139. package/src/lang-cypher/langCypher.ts +44 -0
  140. package/src/lang-cypher/lintWorker.mjs +2039 -0
  141. package/src/lang-cypher/parser-adapter.ts +146 -0
  142. package/src/lang-cypher/prism-global.ts +7 -0
  143. package/src/lang-cypher/signatureHelp.ts +154 -0
  144. package/src/lang-cypher/syntaxValidation.ts +81 -0
  145. package/src/lang-cypher/utils.ts +9 -0
  146. package/src/{ndl-tokens-copy.test.ts → ndlTokensCopy.test.ts} +2 -1
  147. package/src/ndlTokensCopy.ts +570 -0
  148. package/src/{neo4j-setup.tsx → neo4jSetup.tsx} +79 -18
  149. package/src/richClipboardCopier.test.ts +67 -0
  150. package/src/richClipboardCopier.ts +99 -0
  151. package/src/themes.ts +63 -71
  152. package/src/viteEnv.d.ts +1 -0
  153. package/dist/cjs/index.cjs +0 -1441
  154. package/dist/cjs/index.cjs.map +0 -7
  155. package/dist/esm/index.mjs +0 -1464
  156. package/dist/esm/index.mjs.map +0 -7
  157. package/dist/types/CypherEditor.d.ts +0 -113
  158. package/dist/types/e2e_tests/mock-data.d.ts +0 -3779
  159. package/dist/types/index.d.ts +0 -4
  160. package/dist/types/lang-cypher/ParserAdapter.d.ts +0 -14
  161. package/dist/types/lang-cypher/autocomplete.d.ts +0 -3
  162. package/dist/types/lang-cypher/lang-cypher.d.ts +0 -7
  163. package/dist/types/lang-cypher/syntax-validation.d.ts +0 -3
  164. package/dist/types/ndl-tokens-copy.d.ts +0 -379
  165. package/dist/types/neo4j-setup.d.ts +0 -2
  166. package/dist/types/themes.d.ts +0 -11
  167. package/dist/types/tsconfig.tsbuildinfo +0 -1
  168. package/src/e2e_tests/auto-completion.spec.tsx +0 -232
  169. package/src/e2e_tests/mock-data.ts +0 -4310
  170. package/src/e2e_tests/performance-test.spec.tsx +0 -71
  171. package/src/e2e_tests/syntax-validation.spec.tsx +0 -156
  172. package/src/lang-cypher/ParserAdapter.ts +0 -92
  173. package/src/lang-cypher/lang-cypher.ts +0 -32
  174. package/src/lang-cypher/syntax-validation.ts +0 -24
  175. package/src/ndl-tokens-copy.ts +0 -379
  176. /package/dist/{types/e2e_tests/auto-completion.spec.d.ts → src/CypherEditor.test.d.ts} +0 -0
  177. /package/dist/{types/e2e_tests/extra-keybindings.spec.d.ts → src/e2e_tests/autoCompletion.spec.d.ts} +0 -0
  178. /package/dist/{types/e2e_tests/history-navigation.spec.d.ts → src/e2e_tests/configuration.spec.d.ts} +0 -0
  179. /package/dist/{types/e2e_tests/performance-test.spec.d.ts → src/e2e_tests/debounce.spec.d.ts} +0 -0
  180. /package/dist/{types/e2e_tests/sanity-checks.spec.d.ts → src/e2e_tests/extraKeybindings.spec.d.ts} +0 -0
  181. /package/dist/{types/e2e_tests/syntax-highlighting.spec.d.ts → src/e2e_tests/historyNavigation.spec.d.ts} +0 -0
  182. /package/dist/{types/e2e_tests/syntax-validation.spec.d.ts → src/e2e_tests/sanityChecks.spec.d.ts} +0 -0
  183. /package/dist/{types/lang-cypher/contants.test.d.ts → src/e2e_tests/signatureHelp.spec.d.ts} +0 -0
  184. /package/dist/{types/ndl-tokens-copy.test.d.ts → src/e2e_tests/snippets.spec.d.ts} +0 -0
  185. /package/dist/{types/lang-cypher/theme-icons.d.ts → src/lang-cypher/themeIcons.d.ts} +0 -0
  186. /package/src/lang-cypher/{theme-icons.ts → themeIcons.ts} +0 -0
@@ -0,0 +1,146 @@
1
+ import type { Facet } from '@codemirror/state';
2
+ import type { Input, NodeType, PartialParse } from '@lezer/common';
3
+ import { Parser, Tree } from '@lezer/common';
4
+ import type { ParsedCypherToken } from '@neo4j-cypher/language-support';
5
+
6
+ import Prism from 'prismjs';
7
+ import type { CodemirrorParseTokenType } from './constants';
8
+ import { cypherTokenTypeToNode, parserAdapterNodeSet } from './constants';
9
+ // Must come before prism-cypher: it publishes the global `Prism` that the
10
+ // component script assigns onto.
11
+ import './prism-global.js';
12
+ // This import will load the cypher support in prisma
13
+ import 'prismjs/components/prism-cypher';
14
+ import type { CypherConfig } from './langCypher';
15
+
16
+ const DEFAULT_NODE_GROUP_SIZE = 4;
17
+ Prism.manual = true;
18
+
19
+ export class ParserAdapter extends Parser {
20
+ cypherTokenTypeToNode: Record<CodemirrorParseTokenType, NodeType>;
21
+
22
+ constructor(
23
+ facet: Facet<unknown>,
24
+ private config: CypherConfig,
25
+ ) {
26
+ super();
27
+ this.cypherTokenTypeToNode = cypherTokenTypeToNode(facet);
28
+ }
29
+
30
+ createParse(input: Input): PartialParse {
31
+ return this.startParse(input);
32
+ }
33
+
34
+ /* There are more arguments, but since we don't do any incremental parsing, they are not useful */
35
+ startParse(input: string | Input): PartialParse {
36
+ const document =
37
+ typeof input === 'string' ? input : input.read(0, input.length);
38
+
39
+ const tree = this.buildTree(document);
40
+
41
+ return {
42
+ stoppedAt: input.length,
43
+ parsedPos: input.length,
44
+ stopAt: () => {
45
+ return undefined;
46
+ },
47
+ advance: () => tree,
48
+ };
49
+ }
50
+
51
+ private buildTree(document: string) {
52
+ const parse = this.config.useLightVersion
53
+ ? this.prismParse(document)
54
+ : this.antlrParse(document);
55
+
56
+ if (parse.tokens.length === 0) {
57
+ return this.createEmptyTree(document);
58
+ }
59
+
60
+ const buffer =
61
+ parse.type === 'prism'
62
+ ? this.createBufferForPrismTokens(parse.tokens)
63
+ : this.createBufferForAntlrTokens(parse.tokens);
64
+
65
+ this.addTopNodeToBuffer(buffer, document);
66
+
67
+ return Tree.build({
68
+ buffer: buffer.flat(),
69
+ nodeSet: parserAdapterNodeSet(this.cypherTokenTypeToNode),
70
+ topID: this.cypherTokenTypeToNode.topNode.id,
71
+ });
72
+ }
73
+
74
+ private antlrParse(document: string) {
75
+ const startTime = performance.now();
76
+ const tokens = this.config.languageService.highlightSyntax(document);
77
+ const timeTaken = performance.now() - startTime;
78
+ if (timeTaken > 300) {
79
+ this.config.setUseLightVersion?.(true);
80
+ }
81
+ return { type: 'antlr' as const, tokens };
82
+ }
83
+
84
+ private prismParse(document: string) {
85
+ if (document.length === 0) {
86
+ this.config.setUseLightVersion?.(false);
87
+ }
88
+ const tokens = Prism.tokenize(document, Prism.languages.cypher);
89
+ return {
90
+ type: 'prism' as const,
91
+ tokens,
92
+ };
93
+ }
94
+ private createBufferForAntlrTokens(tokens: ParsedCypherToken[]) {
95
+ return tokens.map((token) => {
96
+ const nodeTypeId = this.cypherTokenTypeToNode[token.tokenType].id;
97
+ const startOffset = token.position.startOffset;
98
+ const endOffset = token.position.startOffset + token.length;
99
+
100
+ return [nodeTypeId, startOffset, endOffset, DEFAULT_NODE_GROUP_SIZE];
101
+ });
102
+ }
103
+
104
+ private createBufferForPrismTokens(tokens: (string | Prism.Token)[]) {
105
+ let totalOffset = 0;
106
+ return tokens.map((token) => {
107
+ const tokenType = (
108
+ typeof token === 'string' ? 'variable' : token.type
109
+ ) as CodemirrorParseTokenType;
110
+
111
+ const nodeTypeId = this.cypherTokenTypeToNode[tokenType].id;
112
+ const startOffset = totalOffset;
113
+ const endOffset = startOffset + token.length;
114
+ totalOffset = endOffset;
115
+
116
+ return [nodeTypeId, startOffset, endOffset, DEFAULT_NODE_GROUP_SIZE];
117
+ });
118
+ }
119
+
120
+ private createEmptyTree(document: string) {
121
+ return Tree.build({
122
+ buffer: [
123
+ this.cypherTokenTypeToNode.topNode.id,
124
+ 0,
125
+ document.length,
126
+ DEFAULT_NODE_GROUP_SIZE,
127
+ ],
128
+ nodeSet: parserAdapterNodeSet(this.cypherTokenTypeToNode),
129
+ topID: this.cypherTokenTypeToNode.topNode.id,
130
+ });
131
+ }
132
+
133
+ private addTopNodeToBuffer(buffer: number[][], document: string) {
134
+ const id = this.cypherTokenTypeToNode.topNode.id;
135
+ const startOffset = 0;
136
+ const endOffset = document.length;
137
+ const totalBufferLength = buffer.length * DEFAULT_NODE_GROUP_SIZE;
138
+
139
+ buffer.push([
140
+ id,
141
+ startOffset,
142
+ endOffset,
143
+ totalBufferLength + DEFAULT_NODE_GROUP_SIZE,
144
+ ]);
145
+ }
146
+ }
@@ -0,0 +1,7 @@
1
+ import Prism from 'prismjs';
2
+
3
+ // `prismjs/components/prism-cypher` (used in parser-adapter) is a plain script that mutates the global
4
+ // `Prism`. Bundlers keep prismjs' CJS core lazy and may evaluate the component
5
+ // before the core has run, so force the core to initialise (and publish the
6
+ // global) from a module that is imported first.
7
+ (globalThis as { Prism?: typeof Prism }).Prism = Prism;
@@ -0,0 +1,154 @@
1
+ import type { EditorState } from '@codemirror/state';
2
+ import { StateField } from '@codemirror/state';
3
+ import type { Tooltip } from '@codemirror/view';
4
+ import { showTooltip } from '@codemirror/view';
5
+ import type { SignatureInformation } from 'vscode-languageserver-types';
6
+ import { MarkupContent } from 'vscode-languageserver-types';
7
+ import type { CypherConfig } from './langCypher';
8
+ import { getDocString } from './utils';
9
+
10
+ function getTriggerCharacter(query: string, caretPosition: number) {
11
+ let i = caretPosition - 1;
12
+ let triggerCharacter = query.at(i);
13
+
14
+ // Discard all space characters. Note that a space can be more than just a ' '
15
+ while (/\s/.test(triggerCharacter) && i > 0) {
16
+ i -= 1;
17
+ triggerCharacter = query.at(i);
18
+ }
19
+
20
+ return triggerCharacter;
21
+ }
22
+
23
+ const createSignatureHelpElement =
24
+ ({
25
+ signature,
26
+ activeParameter,
27
+ }: {
28
+ signature: SignatureInformation;
29
+ activeParameter: number;
30
+ }) =>
31
+ () => {
32
+ const parameters = signature.parameters;
33
+ const doc = getDocString(signature.documentation);
34
+ const dom = document.createElement('div');
35
+ dom.className = 'cm-signature-help-panel';
36
+
37
+ const contents = document.createElement('div');
38
+ contents.className = 'cm-signature-help-panel-contents';
39
+ dom.appendChild(contents);
40
+
41
+ const signatureLabel = document.createElement('div');
42
+ signatureLabel.className = 'cm-signature-help-panel-name';
43
+ const methodName = signature.label.slice(0, signature.label.indexOf('('));
44
+ const returnType = signature.label.slice(signature.label.indexOf(')') + 1);
45
+ signatureLabel.appendChild(document.createTextNode(`${methodName}(`));
46
+ let currentParamDescription: string | undefined = undefined;
47
+
48
+ parameters.forEach((param, index) => {
49
+ if (typeof param.label === 'string') {
50
+ const span = document.createElement('span');
51
+ span.appendChild(document.createTextNode(param.label));
52
+ if (index !== parameters.length - 1) {
53
+ span.appendChild(document.createTextNode(', '));
54
+ }
55
+
56
+ if (index === activeParameter) {
57
+ span.className = 'cm-signature-help-panel-current-argument';
58
+ const paramDoc = param.documentation;
59
+ currentParamDescription = MarkupContent.is(paramDoc)
60
+ ? paramDoc.value
61
+ : paramDoc;
62
+ }
63
+ signatureLabel.appendChild(span);
64
+ }
65
+ });
66
+
67
+ signatureLabel.appendChild(document.createTextNode(')'));
68
+ signatureLabel.appendChild(document.createTextNode(returnType));
69
+
70
+ contents.appendChild(signatureLabel);
71
+
72
+ const separator = document.createElement('div');
73
+ separator.className = 'cm-signature-help-panel-separator';
74
+
75
+ contents.appendChild(separator);
76
+
77
+ if (currentParamDescription !== undefined) {
78
+ const argDescription = document.createElement('div');
79
+ argDescription.className = 'cm-signature-help-panel-arg-description';
80
+ argDescription.appendChild(
81
+ document.createTextNode(currentParamDescription),
82
+ );
83
+ contents.appendChild(argDescription);
84
+ }
85
+ const methodDescription = document.createElement('div');
86
+ methodDescription.className = 'cm-signature-help-panel-description';
87
+ methodDescription.appendChild(document.createTextNode(doc));
88
+ contents.appendChild(methodDescription);
89
+
90
+ return { dom };
91
+ };
92
+
93
+ function getSignatureHelpTooltip(
94
+ state: EditorState,
95
+ config: CypherConfig,
96
+ ): Tooltip[] {
97
+ let result: Tooltip[] = [];
98
+ const schema = config.schema;
99
+ const ranges = state.selection.ranges;
100
+ const range = ranges.at(0);
101
+
102
+ if (schema && ranges.length === 1 && range.from === range.to) {
103
+ const caretPosition = range.from;
104
+ const query = state.doc.toString();
105
+
106
+ const triggerCharacter = getTriggerCharacter(query, caretPosition);
107
+
108
+ if (triggerCharacter === '(' || triggerCharacter === ',') {
109
+ const signatureHelpInfo = config.languageService.getSignatureHelp(
110
+ query,
111
+ schema,
112
+ { caretPosition },
113
+ );
114
+ const activeSignature = signatureHelpInfo.activeSignature;
115
+ const signatures = signatureHelpInfo.signatures;
116
+ const activeParameter = signatureHelpInfo.activeParameter;
117
+
118
+ if (
119
+ activeSignature !== undefined &&
120
+ activeSignature >= 0 &&
121
+ activeSignature < signatures.length &&
122
+ signatures[activeSignature].documentation !== undefined
123
+ ) {
124
+ const signature = signatures[activeSignature];
125
+ const showSignatureTooltipBelow =
126
+ config.showSignatureTooltipBelow ?? true;
127
+
128
+ result = [
129
+ {
130
+ pos: caretPosition,
131
+ above: !showSignatureTooltipBelow,
132
+ arrow: true,
133
+ create: createSignatureHelpElement({ signature, activeParameter }),
134
+ },
135
+ ];
136
+ }
137
+ }
138
+ }
139
+
140
+ return result;
141
+ }
142
+
143
+ export function signatureHelpTooltip(config: CypherConfig) {
144
+ return StateField.define<readonly Tooltip[]>({
145
+ create: (state) => getSignatureHelpTooltip(state, config),
146
+
147
+ update(tooltips, tr) {
148
+ if (!tr.docChanged && !tr.selection) return tooltips;
149
+ return getSignatureHelpTooltip(tr.state, config);
150
+ },
151
+
152
+ provide: (f) => showTooltip.computeN([f], (state) => state.field(f)),
153
+ });
154
+ }
@@ -0,0 +1,81 @@
1
+ import type { Diagnostic } from '@codemirror/lint';
2
+ import { linter } from '@codemirror/lint';
3
+ import type { Extension } from '@codemirror/state';
4
+ import { DiagnosticSeverity, DiagnosticTag } from 'vscode-languageserver-types';
5
+ import workerpool from 'workerpool';
6
+ import type { CypherConfig } from './langCypher';
7
+ import type { LintWorker } from '@neo4j-cypher/lint-worker';
8
+ import { isNotParamError } from '@neo4j-cypher/language-support';
9
+
10
+ const WorkerURL = new URL('./lintWorker.mjs', import.meta.url).pathname;
11
+
12
+ const pool = workerpool.pool(WorkerURL, {
13
+ minWorkers: 1,
14
+ workerOpts: { type: 'module' },
15
+ workerTerminateTimeout: 2000,
16
+ });
17
+
18
+ export const cypherLinter: (config: CypherConfig) => Extension = (config) =>
19
+ linter(async (view) => {
20
+ if (!config.lint) {
21
+ return [];
22
+ }
23
+ const query = view.state.doc.toString();
24
+ if (query.length === 0) {
25
+ return [];
26
+ }
27
+
28
+ try {
29
+ if (pool.stats().busyWorkers > 0) {
30
+ await pool.terminate(true);
31
+ }
32
+
33
+ const proxyWorker = (await pool.proxy()) as unknown as LintWorker;
34
+ const result = await proxyWorker.lintCypherQuery(
35
+ query,
36
+ config.schema ?? {},
37
+ config.featureFlags ?? {},
38
+ );
39
+
40
+ if (result.symbolTables) {
41
+ config.languageService.setSymbolsInfo({
42
+ query,
43
+ symbolTables: result.symbolTables,
44
+ });
45
+ }
46
+
47
+ const a: Diagnostic[] = result.diagnostics.map((diagnostic) => {
48
+ return {
49
+ from: diagnostic.offsets.start >= 0 ? diagnostic.offsets.start : 0,
50
+ to:
51
+ diagnostic.offsets.end >= 0 ? diagnostic.offsets.end : query.length,
52
+ severity:
53
+ diagnostic.severity === DiagnosticSeverity.Error
54
+ ? 'error'
55
+ : 'warning',
56
+ message: diagnostic.message,
57
+ ...(diagnostic.tags !== undefined &&
58
+ diagnostic.tags.includes(DiagnosticTag.Deprecated)
59
+ ? { markClass: 'cm-deprecated-element' }
60
+ : {}),
61
+ };
62
+ });
63
+ if (!config.schema?.databaseNames?.length) {
64
+ return a.filter(isNotParamError);
65
+ }
66
+ return a;
67
+ } catch (err) {
68
+ if (err instanceof Error) {
69
+ if (!err.message.includes('Worker terminated')) {
70
+ console.error(String(err) + ' ' + query);
71
+ }
72
+ } else {
73
+ console.error(JSON.stringify(err));
74
+ }
75
+ }
76
+ return [];
77
+ });
78
+
79
+ export const cleanupWorkers = () => {
80
+ void pool.terminate();
81
+ };
@@ -0,0 +1,9 @@
1
+ import { MarkupContent } from 'vscode-languageserver-types';
2
+
3
+ export function getDocString(result: string | MarkupContent): string {
4
+ if (MarkupContent.is(result)) {
5
+ return result.value;
6
+ } else {
7
+ return result;
8
+ }
9
+ }
@@ -1,5 +1,6 @@
1
1
  import { tokens } from '@neo4j-ndl/base';
2
- import { tokens as tokensCopy } from './ndl-tokens-copy';
2
+ import { expect, test } from 'vitest';
3
+ import { tokens as tokensCopy } from './ndlTokensCopy';
3
4
 
4
5
  /*
5
6
  * Needle has some odd package configuration that made playwright stop working