@neo4j-cypher/language-server 2.0.0-next.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/package.json ADDED
@@ -0,0 +1,48 @@
1
+ {
2
+ "name": "@neo4j-cypher/language-server",
3
+ "description": "Cypher Language Server",
4
+ "author": "Neo4j Inc.",
5
+ "license": "Apache-2.0",
6
+ "files": [
7
+ "./dist/cypher-language-server.js",
8
+ "./src",
9
+ "package.json",
10
+ "README.md",
11
+ "LICENSE.md",
12
+ "CHANGELOG.md"
13
+ ],
14
+ "keywords": [
15
+ "neo4j",
16
+ "cypher",
17
+ "language server"
18
+ ],
19
+ "version": "2.0.0-next.0",
20
+ "main": "./dist/cypher-language-server.js",
21
+ "types": "src/server.ts",
22
+ "repository": {
23
+ "type": "git",
24
+ "url": "git://github.com/neo4j/cypher-language-support.git"
25
+ },
26
+ "bugs": {
27
+ "url": "https://github.com/neo4j/cypher-language-support/issues"
28
+ },
29
+ "engineStrict": true,
30
+ "engines": {
31
+ "node": ">=18.18.2"
32
+ },
33
+ "dependencies": {
34
+ "@neo4j-cypher/language-support": "2.0.0-next.0",
35
+ "neo4j-driver": "^5.3.0",
36
+ "vscode-languageserver": "^8.1.0",
37
+ "vscode-languageserver-textdocument": "^1.0.8"
38
+ },
39
+ "scripts": {
40
+ "build": "tsc -b && npm run bundle",
41
+ "bundle": "esbuild ./src/server.ts --bundle --format=cjs --platform=node --outfile=dist/cypher-language-server.js",
42
+ "clean": "rm -rf dist",
43
+ "watch": "tsc -b -w"
44
+ },
45
+ "devDependencies": {
46
+ "esbuild": "^0.19.4"
47
+ }
48
+ }
@@ -0,0 +1,34 @@
1
+ import {
2
+ Position,
3
+ TextDocumentPositionParams,
4
+ TextDocuments,
5
+ } from 'vscode-languageserver/node';
6
+
7
+ import { Range } from 'vscode-languageserver-types';
8
+
9
+ import { autocomplete } from '@neo4j-cypher/language-support';
10
+ import { Neo4jSchemaPoller } from '@neo4j-cypher/schema-poller';
11
+ import { TextDocument } from 'vscode-languageserver-textdocument';
12
+
13
+ export function doAutoCompletion(
14
+ documents: TextDocuments<TextDocument>,
15
+ neo4j: Neo4jSchemaPoller,
16
+ ) {
17
+ return (textDocumentPosition: TextDocumentPositionParams) => {
18
+ const textDocument = documents.get(textDocumentPosition.textDocument.uri);
19
+ if (textDocument === undefined) return [];
20
+
21
+ const position: Position = textDocumentPosition.position;
22
+ const range: Range = {
23
+ // TODO Nacho: We are parsing from the begining of the file.
24
+ // Do we need to parse from the begining of the current query?
25
+ start: Position.create(0, 0),
26
+ end: position,
27
+ };
28
+
29
+ return autocomplete(
30
+ textDocument.getText(range),
31
+ neo4j.metadata?.dbSchema ?? {},
32
+ );
33
+ };
34
+ }
package/src/server.ts ADDED
@@ -0,0 +1,124 @@
1
+ import {
2
+ createConnection,
3
+ DidChangeConfigurationNotification,
4
+ InitializeResult,
5
+ ProposedFeatures,
6
+ SemanticTokensRegistrationOptions,
7
+ SemanticTokensRegistrationType,
8
+ TextDocuments,
9
+ TextDocumentSyncKind,
10
+ } from 'vscode-languageserver/node';
11
+
12
+ import { TextDocument } from 'vscode-languageserver-textdocument';
13
+
14
+ import {
15
+ syntaxColouringLegend,
16
+ validateSyntax,
17
+ } from '@neo4j-cypher/language-support';
18
+ import { Neo4jSchemaPoller } from '@neo4j-cypher/schema-poller';
19
+ import { doAutoCompletion } from './autocompletion';
20
+ import { doSignatureHelp } from './signatureHelp';
21
+ import { applySyntaxColouringForDocument } from './syntaxColouring';
22
+ import { Neo4jSettings } from './types';
23
+
24
+ const connection = createConnection(ProposedFeatures.all);
25
+
26
+ // Create a simple text document manager.
27
+ const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
28
+
29
+ const neo4jSdk = new Neo4jSchemaPoller();
30
+
31
+ connection.onInitialize(() => {
32
+ const result: InitializeResult = {
33
+ capabilities: {
34
+ textDocumentSync: TextDocumentSyncKind.Full,
35
+ // Tell the client what features does the server support
36
+ completionProvider: {
37
+ resolveProvider: false,
38
+ triggerCharacters: ['.'],
39
+ },
40
+ semanticTokensProvider: {
41
+ documentSelector: null,
42
+ legend: syntaxColouringLegend,
43
+ range: false,
44
+ full: {
45
+ delta: false,
46
+ },
47
+ },
48
+ signatureHelpProvider: {
49
+ triggerCharacters: ['(', ',', ')'],
50
+ },
51
+ },
52
+ };
53
+
54
+ return result;
55
+ });
56
+
57
+ connection.onInitialized(() => {
58
+ void connection.client.register(DidChangeConfigurationNotification.type, {
59
+ section: 'neo4j',
60
+ });
61
+
62
+ const registrationOptions: SemanticTokensRegistrationOptions = {
63
+ documentSelector: null,
64
+ legend: syntaxColouringLegend,
65
+ range: false,
66
+ full: {
67
+ delta: false,
68
+ },
69
+ };
70
+ void connection.client.register(
71
+ SemanticTokensRegistrationType.type,
72
+ registrationOptions,
73
+ );
74
+ });
75
+
76
+ // Trigger the syntactic errors highlighting on every document change
77
+ documents.onDidChangeContent((change) => {
78
+ const document = change.document;
79
+ const diagnostics = validateSyntax(
80
+ document.getText(),
81
+ neo4jSdk.metadata?.dbSchema ?? {},
82
+ );
83
+ void connection.sendDiagnostics({
84
+ uri: document.uri,
85
+ diagnostics: diagnostics,
86
+ });
87
+ });
88
+
89
+ // Trigger the syntax colouring
90
+ connection.languages.semanticTokens.on(
91
+ applySyntaxColouringForDocument(documents),
92
+ );
93
+
94
+ // Trigger the signature help, providing info about functions / procedures
95
+ connection.onSignatureHelp(doSignatureHelp(documents, neo4jSdk));
96
+ // Trigger the auto completion
97
+ connection.onCompletion(doAutoCompletion(documents, neo4jSdk));
98
+
99
+ connection.onDidChangeConfiguration(
100
+ (params: { settings: { neo4j: Neo4jSettings } }) => {
101
+ neo4jSdk.disconnect();
102
+
103
+ const neo4jConfig = params.settings.neo4j;
104
+ if (
105
+ neo4jSdk.connection === undefined &&
106
+ neo4jConfig.connect &&
107
+ neo4jConfig.password &&
108
+ neo4jConfig.URL &&
109
+ neo4jConfig.user
110
+ ) {
111
+ void neo4jSdk.persistentConnect(
112
+ neo4jConfig.URL,
113
+ {
114
+ username: neo4jConfig.user,
115
+ password: neo4jConfig.password,
116
+ },
117
+ { appName: 'cypher-language-server' },
118
+ );
119
+ }
120
+ },
121
+ );
122
+
123
+ documents.listen(connection);
124
+ connection.listen();
@@ -0,0 +1,39 @@
1
+ import { signatureHelp } from '@neo4j-cypher/language-support';
2
+ import {
3
+ Position,
4
+ Range,
5
+ SignatureHelp,
6
+ SignatureHelpParams,
7
+ TextDocuments,
8
+ } from 'vscode-languageserver/node';
9
+
10
+ import { Neo4jSchemaPoller } from '@neo4j-cypher/schema-poller';
11
+ import { TextDocument } from 'vscode-languageserver-textdocument';
12
+
13
+ export const emptyResult: SignatureHelp = {
14
+ signatures: [],
15
+ activeSignature: undefined,
16
+ activeParameter: undefined,
17
+ };
18
+
19
+ export function doSignatureHelp(
20
+ documents: TextDocuments<TextDocument>,
21
+ neo4j: Neo4jSchemaPoller,
22
+ ) {
23
+ return (params: SignatureHelpParams) => {
24
+ const textDocument = documents.get(params.textDocument.uri);
25
+ const endOfTriggerHelp = params.context?.triggerCharacter === ')';
26
+ if (textDocument === undefined || endOfTriggerHelp) return emptyResult;
27
+
28
+ const position = params.position;
29
+ const range: Range = {
30
+ start: Position.create(0, 0),
31
+ end: position,
32
+ };
33
+
34
+ return signatureHelp(
35
+ textDocument.getText(range),
36
+ neo4j.metadata?.dbSchema ?? {},
37
+ );
38
+ };
39
+ }
@@ -0,0 +1,39 @@
1
+ import {
2
+ applySyntaxColouring,
3
+ mapCypherToSemanticTokenIndex,
4
+ } from '@neo4j-cypher/language-support';
5
+ import {
6
+ SemanticTokensBuilder,
7
+ SemanticTokensParams,
8
+ TextDocument,
9
+ TextDocuments,
10
+ } from 'vscode-languageserver';
11
+
12
+ export function applySyntaxColouringForDocument(
13
+ documents: TextDocuments<TextDocument>,
14
+ ) {
15
+ return (params: SemanticTokensParams) => {
16
+ const textDocument = documents.get(params.textDocument.uri);
17
+ if (textDocument === undefined) return { data: [] };
18
+
19
+ const tokens = applySyntaxColouring(textDocument.getText());
20
+
21
+ const builder = new SemanticTokensBuilder();
22
+
23
+ tokens.forEach((token) => {
24
+ const tokenColour = mapCypherToSemanticTokenIndex(token.tokenType);
25
+
26
+ if (tokenColour !== undefined) {
27
+ builder.push(
28
+ token.position.line,
29
+ token.position.startCharacter,
30
+ token.length,
31
+ tokenColour,
32
+ 0,
33
+ );
34
+ }
35
+ });
36
+ const results = builder.build();
37
+ return results;
38
+ };
39
+ }
package/src/types.ts ADDED
@@ -0,0 +1,10 @@
1
+ // These settings are defined in the package.json
2
+ export type Neo4jSettings = {
3
+ trace: {
4
+ server: 'off' | 'messages' | 'verbose';
5
+ };
6
+ connect?: boolean;
7
+ password?: string;
8
+ URL?: string;
9
+ user?: string;
10
+ };