@neo4j-cypher/react-codemirror 2.0.0-next.33 → 2.0.0-next.34
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/CHANGELOG.md +12 -0
- package/dist/src/CypherEditor.d.ts +15 -1
- package/dist/src/CypherEditor.js +65 -1
- package/dist/src/CypherEditor.js.map +1 -1
- package/dist/src/lang-cypher/autocomplete.js +5 -2
- package/dist/src/lang-cypher/autocomplete.js.map +1 -1
- package/dist/src/lang-cypher/contants.test.js +2 -2
- package/dist/src/lang-cypher/contants.test.js.map +1 -1
- package/dist/src/lang-cypher/langCypher.d.ts +2 -1
- package/dist/src/lang-cypher/langCypher.js.map +1 -1
- package/dist/src/lang-cypher/lintWorker.mjs +151 -149
- package/dist/src/lang-cypher/parser-adapter.js +1 -2
- package/dist/src/lang-cypher/parser-adapter.js.map +1 -1
- package/dist/src/lang-cypher/signatureHelp.js +1 -2
- package/dist/src/lang-cypher/signatureHelp.js.map +1 -1
- package/dist/src/lang-cypher/syntaxValidation.js +1 -2
- package/dist/src/lang-cypher/syntaxValidation.js.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
- package/src/CypherEditor.tsx +86 -1
- package/src/lang-cypher/autocomplete.ts +6 -7
- package/src/lang-cypher/contants.test.ts +2 -2
- package/src/lang-cypher/langCypher.ts +5 -1
- package/src/lang-cypher/lintWorker.mjs +151 -149
- package/src/lang-cypher/parser-adapter.ts +2 -5
- package/src/lang-cypher/signatureHelp.ts +5 -2
- package/src/lang-cypher/syntaxValidation.ts +1 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@neo4j-cypher/react-codemirror",
|
|
3
|
-
"version": "2.0.0-next.
|
|
3
|
+
"version": "2.0.0-next.34",
|
|
4
4
|
"keywords": [
|
|
5
5
|
"codemirror",
|
|
6
6
|
"codemirror 6",
|
|
@@ -47,13 +47,13 @@
|
|
|
47
47
|
"style-mod": "^4.1.2",
|
|
48
48
|
"vscode-languageserver-types": "^3.17.3",
|
|
49
49
|
"workerpool": "^9.3.3",
|
|
50
|
-
"@neo4j-cypher/language-support": "2.0.0-next.
|
|
51
|
-
"@neo4j-cypher/lint-worker": "1.10.1-next.
|
|
50
|
+
"@neo4j-cypher/language-support": "2.0.0-next.31",
|
|
51
|
+
"@neo4j-cypher/lint-worker": "1.10.1-next.8"
|
|
52
52
|
},
|
|
53
53
|
"devDependencies": {
|
|
54
54
|
"@neo4j-ndl/base": "^3.2.10",
|
|
55
|
-
"@playwright/experimental-ct-react": "^1.
|
|
56
|
-
"@playwright/test": "^1.
|
|
55
|
+
"@playwright/experimental-ct-react": "^1.55.1",
|
|
56
|
+
"@playwright/test": "^1.55.1",
|
|
57
57
|
"@types/lodash.debounce": "^4.0.9",
|
|
58
58
|
"@types/react": "^18.0.28",
|
|
59
59
|
"@types/react-dom": "^18.0.11",
|
|
@@ -61,7 +61,7 @@
|
|
|
61
61
|
"copyfiles": "^2.4.1",
|
|
62
62
|
"jsdom": "^24.1.1",
|
|
63
63
|
"lodash": "^4.17.21",
|
|
64
|
-
"playwright": "^1.
|
|
64
|
+
"playwright": "^1.55.1",
|
|
65
65
|
"react": "^18.2.0",
|
|
66
66
|
"react-dom": "^18.2.0",
|
|
67
67
|
"vite": "^4.5.10"
|
package/src/CypherEditor.tsx
CHANGED
|
@@ -13,7 +13,11 @@ import {
|
|
|
13
13
|
placeholder,
|
|
14
14
|
ViewUpdate,
|
|
15
15
|
} from '@codemirror/view';
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
formatQuery,
|
|
18
|
+
CypherLanguageService,
|
|
19
|
+
type DbSchema,
|
|
20
|
+
} from '@neo4j-cypher/language-support';
|
|
17
21
|
import debounce from 'lodash.debounce';
|
|
18
22
|
import { Component, createRef } from 'react';
|
|
19
23
|
import { DEBOUNCE_TIME } from './constants';
|
|
@@ -26,6 +30,8 @@ import { cleanupWorkers } from './lang-cypher/syntaxValidation';
|
|
|
26
30
|
import { basicNeo4jSetup } from './neo4jSetup';
|
|
27
31
|
import { getThemeExtension } from './themes';
|
|
28
32
|
import { richClipboardCopier } from './richClipboardCopier';
|
|
33
|
+
import { LintWorker } from '@neo4j-cypher/lint-worker';
|
|
34
|
+
import workerpool from 'workerpool';
|
|
29
35
|
|
|
30
36
|
type DomEventHandlers = Parameters<typeof EditorView.domEventHandlers>[0];
|
|
31
37
|
export interface CypherEditorProps {
|
|
@@ -275,11 +281,72 @@ const formatLineNumber =
|
|
|
275
281
|
type CypherEditorState = { cypherSupportEnabled: boolean };
|
|
276
282
|
|
|
277
283
|
const ExternalEdit = Annotation.define<boolean>();
|
|
284
|
+
const WorkerURL = new URL('./lang-cypher/lintWorker.mjs', import.meta.url)
|
|
285
|
+
.pathname;
|
|
286
|
+
|
|
287
|
+
class CodemirrorSymbolFetcher {
|
|
288
|
+
constructor(languageService: CypherLanguageService) {
|
|
289
|
+
this.languageService = languageService;
|
|
290
|
+
}
|
|
291
|
+
private languageService: CypherLanguageService;
|
|
292
|
+
private processing = false;
|
|
293
|
+
private nextJob: {
|
|
294
|
+
query: string;
|
|
295
|
+
schema: DbSchema;
|
|
296
|
+
};
|
|
297
|
+
private symbolTablePool = workerpool.pool(WorkerURL, {
|
|
298
|
+
minWorkers: 1,
|
|
299
|
+
workerOpts: { type: 'module' },
|
|
300
|
+
workerTerminateTimeout: 2000,
|
|
301
|
+
});
|
|
302
|
+
|
|
303
|
+
public queueSymbolJob(query: string, schema: DbSchema) {
|
|
304
|
+
this.nextJob = { query, schema };
|
|
305
|
+
if (!this.processing) {
|
|
306
|
+
void this.processJobQueue();
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public terminate() {
|
|
311
|
+
this.nextJob = undefined;
|
|
312
|
+
void this.symbolTablePool.terminate();
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
private async processJobQueue() {
|
|
316
|
+
this.processing = true;
|
|
317
|
+
while (this.nextJob) {
|
|
318
|
+
try {
|
|
319
|
+
const proxyWorker =
|
|
320
|
+
(await this.symbolTablePool.proxy()) as unknown as LintWorker;
|
|
321
|
+
const query = this.nextJob.query;
|
|
322
|
+
const dbSchema = this.nextJob.schema;
|
|
323
|
+
this.nextJob = undefined;
|
|
324
|
+
|
|
325
|
+
const result = await proxyWorker.lintCypherQuery(query, dbSchema);
|
|
326
|
+
|
|
327
|
+
if (result.symbolTables) {
|
|
328
|
+
this.languageService.setSymbolsInfo({
|
|
329
|
+
query,
|
|
330
|
+
symbolTables: result.symbolTables,
|
|
331
|
+
});
|
|
332
|
+
}
|
|
333
|
+
} catch (err) {
|
|
334
|
+
//eslint-disable-next-line
|
|
335
|
+
console.log('Symbol table calculation failed ' + String(err));
|
|
336
|
+
}
|
|
337
|
+
}
|
|
338
|
+
this.processing = false;
|
|
339
|
+
}
|
|
340
|
+
}
|
|
278
341
|
|
|
279
342
|
export class CypherEditor extends Component<
|
|
280
343
|
CypherEditorProps,
|
|
281
344
|
CypherEditorState
|
|
282
345
|
> {
|
|
346
|
+
/**
|
|
347
|
+
* The symbol fetcher object used to fetch the current symbol table on document changes
|
|
348
|
+
*/
|
|
349
|
+
symbolFetcher: CodemirrorSymbolFetcher;
|
|
283
350
|
/**
|
|
284
351
|
* The codemirror editor container.
|
|
285
352
|
*/
|
|
@@ -379,6 +446,7 @@ export class CypherEditor extends Component<
|
|
|
379
446
|
} = this.props;
|
|
380
447
|
|
|
381
448
|
this.schemaRef.current = {
|
|
449
|
+
languageService: new CypherLanguageService(),
|
|
382
450
|
schema,
|
|
383
451
|
lint,
|
|
384
452
|
showSignatureTooltipBelow,
|
|
@@ -394,6 +462,10 @@ export class CypherEditor extends Component<
|
|
|
394
462
|
},
|
|
395
463
|
};
|
|
396
464
|
|
|
465
|
+
this.symbolFetcher = new CodemirrorSymbolFetcher(
|
|
466
|
+
this.schemaRef.current.languageService,
|
|
467
|
+
);
|
|
468
|
+
|
|
397
469
|
const themeExtension = getThemeExtension(
|
|
398
470
|
theme,
|
|
399
471
|
overrideThemeBackgroundColor,
|
|
@@ -402,6 +474,12 @@ export class CypherEditor extends Component<
|
|
|
402
474
|
const changeListener = this.debouncedOnChange
|
|
403
475
|
? [
|
|
404
476
|
EditorView.updateListener.of((upt: ViewUpdate) => {
|
|
477
|
+
if (upt.docChanged) {
|
|
478
|
+
this.symbolFetcher.queueSymbolJob(
|
|
479
|
+
upt.state.doc.toString(),
|
|
480
|
+
this.schemaRef.current.schema,
|
|
481
|
+
);
|
|
482
|
+
}
|
|
405
483
|
const wasUserEdit = !upt.transactions.some((tr) =>
|
|
406
484
|
tr.annotation(ExternalEdit),
|
|
407
485
|
);
|
|
@@ -452,6 +530,12 @@ export class CypherEditor extends Component<
|
|
|
452
530
|
'aria-label': this.props.ariaLabel,
|
|
453
531
|
})
|
|
454
532
|
: [],
|
|
533
|
+
!this.props.moveFocusOnTab
|
|
534
|
+
? EditorView.contentAttributes.of({
|
|
535
|
+
'aria-description':
|
|
536
|
+
'Press Escape to leave the editor and continue tabbing through the page',
|
|
537
|
+
})
|
|
538
|
+
: [],
|
|
455
539
|
],
|
|
456
540
|
doc: this.props.value,
|
|
457
541
|
});
|
|
@@ -592,6 +676,7 @@ export class CypherEditor extends Component<
|
|
|
592
676
|
|
|
593
677
|
componentWillUnmount(): void {
|
|
594
678
|
this.editorView.current?.destroy();
|
|
679
|
+
this.symbolFetcher?.terminate();
|
|
595
680
|
cleanupWorkers();
|
|
596
681
|
}
|
|
597
682
|
|
|
@@ -3,10 +3,7 @@ import {
|
|
|
3
3
|
CompletionSource,
|
|
4
4
|
snippet,
|
|
5
5
|
} from '@codemirror/autocomplete';
|
|
6
|
-
import {
|
|
7
|
-
autocomplete,
|
|
8
|
-
shouldAutoCompleteYield,
|
|
9
|
-
} from '@neo4j-cypher/language-support';
|
|
6
|
+
import { shouldAutoCompleteYield } from '@neo4j-cypher/language-support';
|
|
10
7
|
import {
|
|
11
8
|
CompletionItemKind,
|
|
12
9
|
CompletionItemTag,
|
|
@@ -81,11 +78,13 @@ export const cypherAutocomplete: (config: CypherConfig) => CompletionSource =
|
|
|
81
78
|
return null;
|
|
82
79
|
}
|
|
83
80
|
|
|
84
|
-
const options = autocomplete(
|
|
81
|
+
const options = config.languageService.autocomplete(
|
|
85
82
|
documentText,
|
|
86
83
|
config.schema ?? {},
|
|
87
|
-
|
|
88
|
-
|
|
84
|
+
{
|
|
85
|
+
caretPosition: offset,
|
|
86
|
+
manual: context.explicit,
|
|
87
|
+
},
|
|
89
88
|
);
|
|
90
89
|
|
|
91
90
|
return {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { tags } from '@lezer/highlight';
|
|
2
2
|
import {
|
|
3
|
-
|
|
3
|
+
highlightSyntax,
|
|
4
4
|
CypherTokenType,
|
|
5
5
|
} from '@neo4j-cypher/language-support';
|
|
6
6
|
import { expect, test } from 'vitest';
|
|
@@ -14,7 +14,7 @@ WHERE variable.property = "String"
|
|
|
14
14
|
RETURN variable;`;
|
|
15
15
|
|
|
16
16
|
test('correctly parses all cypher token types to style tags', () => {
|
|
17
|
-
const tokens =
|
|
17
|
+
const tokens = highlightSyntax(cypherQueryWithAllTokenTypes);
|
|
18
18
|
const tokenTypes = tokens.map((token) => token.tokenType);
|
|
19
19
|
expect(tokenTypes).toEqual([
|
|
20
20
|
'keyword',
|
|
@@ -4,7 +4,10 @@ import {
|
|
|
4
4
|
Language,
|
|
5
5
|
LanguageSupport,
|
|
6
6
|
} from '@codemirror/language';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
CypherLanguageService,
|
|
9
|
+
type DbSchema,
|
|
10
|
+
} from '@neo4j-cypher/language-support';
|
|
8
11
|
import { completionStyles, cypherAutocomplete } from './autocomplete';
|
|
9
12
|
import { ParserAdapter } from './parser-adapter';
|
|
10
13
|
import { signatureHelpTooltip } from './signatureHelp';
|
|
@@ -16,6 +19,7 @@ const facet = defineLanguageFacet({
|
|
|
16
19
|
});
|
|
17
20
|
|
|
18
21
|
export type CypherConfig = {
|
|
22
|
+
languageService: CypherLanguageService;
|
|
19
23
|
lint?: boolean;
|
|
20
24
|
showSignatureTooltipBelow?: boolean;
|
|
21
25
|
featureFlags?: {
|