@neo4j-cypher/language-server 2.0.0-next.21 → 2.0.0-next.23

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/server.js CHANGED
@@ -9,9 +9,6 @@ const formatting_1 = require("./formatting");
9
9
  const linting_1 = require("./linting");
10
10
  const signatureHelp_1 = require("./signatureHelp");
11
11
  const syntaxColouring_1 = require("./syntaxColouring");
12
- if (process.env.CYPHER_25 === 'true') {
13
- language_support_1._internalFeatureFlags.cypher25 = true;
14
- }
15
12
  const connection = (0, node_1.createConnection)(node_1.ProposedFeatures.all);
16
13
  let settings = undefined;
17
14
  // Create a simple text document manager.
@@ -24,7 +21,7 @@ async function lintSingleDocument(document) {
24
21
  uri: document.uri,
25
22
  diagnostics,
26
23
  });
27
- }, neo4jSchemaPoller);
24
+ }, neo4jSchemaPoller, settings?.features?.useVersionedLinters);
28
25
  }
29
26
  else {
30
27
  void connection.sendDiagnostics({
@@ -87,6 +84,14 @@ connection.languages.semanticTokens.on((0, syntaxColouring_1.applySyntaxColourin
87
84
  connection.onSignatureHelp((0, signatureHelp_1.doSignatureHelp)(documents, neo4jSchemaPoller));
88
85
  // Trigger the auto completion
89
86
  connection.onCompletion((0, autocompletion_1.doAutoCompletion)(documents, neo4jSchemaPoller));
87
+ connection.onNotification('updateLintWorker', (linterSettings) => {
88
+ const lintWorkerPath = linterSettings.lintWorkerPath;
89
+ const linterVersion = linterSettings.linterVersion;
90
+ void (async () => {
91
+ await (0, linting_1.setLintWorker)(lintWorkerPath, linterVersion);
92
+ relintAllDocuments();
93
+ })();
94
+ });
90
95
  connection.onNotification('connectionUpdated', (connectionSettings) => {
91
96
  changeConnection(connectionSettings);
92
97
  neo4jSchemaPoller.events.once('schemaFetched', relintAllDocuments);
@@ -105,7 +110,7 @@ connection.onNotification('connectionDisconnected', () => {
105
110
  documents.listen(connection);
106
111
  connection.listen();
107
112
  connection.onExit(() => {
108
- (0, linting_1.cleanupWorkers)();
113
+ void (0, linting_1.cleanupWorkers)();
109
114
  });
110
115
  const changeConnection = (connectionSettings) => {
111
116
  disconnect();
package/package.json CHANGED
@@ -16,7 +16,7 @@
16
16
  "cypher",
17
17
  "language server"
18
18
  ],
19
- "version": "2.0.0-next.21",
19
+ "version": "2.0.0-next.23",
20
20
  "main": "./dist/server.js",
21
21
  "types": "src/server.ts",
22
22
  "repository": {
@@ -28,7 +28,7 @@
28
28
  },
29
29
  "engineStrict": true,
30
30
  "engines": {
31
- "node": ">=18.18.2"
31
+ "node": ">=22.15.0"
32
32
  },
33
33
  "bin": {
34
34
  "cypher-language-server": "./dist/cypher-language-server"
@@ -39,16 +39,20 @@
39
39
  "vscode-languageserver": "^8.1.0",
40
40
  "vscode-languageserver-textdocument": "^1.0.8",
41
41
  "workerpool": "^9.0.4",
42
- "@neo4j-cypher/language-support": "2.0.0-next.20",
43
- "@neo4j-cypher/query-tools": "2.0.0-next.20"
42
+ "axios": "^1.9.0",
43
+ "@neo4j-cypher/language-support": "2.0.0-next.22",
44
+ "@neo4j-cypher/lint-worker": "0.1.0-next.0",
45
+ "@neo4j-cypher/query-tools": "2.0.0-next.22"
44
46
  },
45
47
  "devDependencies": {
46
- "@types/lodash.debounce": "^4.0.9"
48
+ "@types/lodash.debounce": "^4.0.9",
49
+ "copyfiles": "^2.4.1"
47
50
  },
48
51
  "scripts": {
49
- "build": "tsc -b && pnpm bundle && pnpm make-executable && pnpm bundle-worker",
52
+ "build": "tsc -b && pnpm bundle && pnpm make-executable && pnpm copy-lint-worker",
53
+ "copy-lint-worker": "copyfiles -u 4 ../lint-worker/dist/cjs/lintWorker.cjs dist/",
50
54
  "bundle": "esbuild ./src/server.ts --bundle --format=cjs --platform=node --outfile=dist/cypher-language-server.js --minify --conditions=require",
51
- "bundle-worker": "esbuild ./src/lintWorker.ts --bundle --format=cjs --platform=node --conditions=require --outfile=dist/lintWorker.js --minify",
55
+ "dev": "tsc --watch",
52
56
  "make-executable": "cd dist && echo '#!/usr/bin/env node' > cypher-language-server && cat cypher-language-server.js >> cypher-language-server",
53
57
  "clean": "rm -rf {dist,tsconfig.tsbuildinfo}"
54
58
  }
package/src/formatting.ts CHANGED
@@ -16,7 +16,7 @@ export const formatDocument = (
16
16
  }
17
17
 
18
18
  const text = document.getText();
19
- const formattedText = formatQuery(text);
19
+ const formattedText = formatQuery(text).formattedQuery;
20
20
 
21
21
  if (text === formattedText) {
22
22
  return [];
package/src/linting.ts CHANGED
@@ -1,23 +1,52 @@
1
- import { _internalFeatureFlags } from '@neo4j-cypher/language-support';
1
+ import {
2
+ _internalFeatureFlags,
3
+ clampUnsafePositions,
4
+ parserWrapper,
5
+ } from '@neo4j-cypher/language-support';
2
6
  import { Neo4jSchemaPoller } from '@neo4j-cypher/query-tools';
3
7
  import debounce from 'lodash.debounce';
4
8
  import { join } from 'path';
5
9
  import { Diagnostic } from 'vscode-languageserver';
6
10
  import { TextDocument } from 'vscode-languageserver-textdocument';
7
11
  import workerpool from 'workerpool';
8
- import { LinterTask, LintWorker } from './lintWorker';
12
+ import {
13
+ convertDbSchema,
14
+ LinterTask,
15
+ LintWorker,
16
+ } from '@neo4j-cypher/lint-worker';
9
17
 
10
- const pool = workerpool.pool(join(__dirname, 'lintWorker.js'), {
18
+ const defaultWorkerPath = join(__dirname, 'lintWorker.cjs');
19
+
20
+ let pool = workerpool.pool(defaultWorkerPath, {
11
21
  minWorkers: 2,
12
22
  workerTerminateTimeout: 2000,
13
23
  });
14
-
24
+ export let workerPath = defaultWorkerPath;
25
+ let linterVersion: string | undefined = undefined;
15
26
  let lastSemanticJob: LinterTask | undefined;
16
27
 
28
+ /**Sets the lintworker to the one specified by the given path, reverting to default if the path is undefined */
29
+ export async function setLintWorker(
30
+ lintWorkerPath: string | undefined,
31
+ linter: string | undefined,
32
+ ) {
33
+ lintWorkerPath = lintWorkerPath ? lintWorkerPath : defaultWorkerPath;
34
+ if (lintWorkerPath !== workerPath) {
35
+ await cleanupWorkers();
36
+ workerPath = lintWorkerPath;
37
+ linterVersion = linter;
38
+ pool = workerpool.pool(workerPath, {
39
+ minWorkers: 2,
40
+ workerTerminateTimeout: 2000,
41
+ });
42
+ }
43
+ }
44
+
17
45
  async function rawLintDocument(
18
46
  document: TextDocument,
19
47
  sendDiagnostics: (diagnostics: Diagnostic[]) => void,
20
48
  neo4j: Neo4jSchemaPoller,
49
+ versionedLinters: boolean,
21
50
  ) {
22
51
  const query = document.getText();
23
52
  if (query.length === 0) {
@@ -32,14 +61,33 @@ async function rawLintDocument(
32
61
  }
33
62
 
34
63
  const proxyWorker = (await pool.proxy()) as unknown as LintWorker;
64
+
65
+ const fixedDbSchema = versionedLinters
66
+ ? convertDbSchema(dbSchema, linterVersion)
67
+ : dbSchema;
35
68
  lastSemanticJob = proxyWorker.lintCypherQuery(
36
69
  query,
37
- dbSchema,
70
+ fixedDbSchema,
38
71
  _internalFeatureFlags,
39
72
  );
73
+
40
74
  const result = await lastSemanticJob;
41
75
 
42
- sendDiagnostics(result);
76
+ //marks the entire text if any position is negative
77
+ const positionSafeResult = clampUnsafePositions(
78
+ result.diagnostics,
79
+ document,
80
+ );
81
+
82
+ // Pass the computed symbol tables to the parser
83
+ if (result.symbolTables) {
84
+ parserWrapper.setSymbolsInfo({
85
+ query,
86
+ symbolTables: result.symbolTables,
87
+ });
88
+ }
89
+
90
+ sendDiagnostics(positionSafeResult);
43
91
  } catch (err) {
44
92
  if (!(err instanceof workerpool.Promise.CancellationError)) {
45
93
  console.error(err);
@@ -56,6 +104,6 @@ export const lintDocument: typeof rawLintDocument = debounce(
56
104
  },
57
105
  );
58
106
 
59
- export const cleanupWorkers = () => {
60
- void pool.terminate();
107
+ export const cleanupWorkers = async () => {
108
+ await pool.terminate();
61
109
  };
package/src/server.ts CHANGED
@@ -11,27 +11,20 @@ import {
11
11
  } from 'vscode-languageserver/node';
12
12
 
13
13
  import { TextDocument } from 'vscode-languageserver-textdocument';
14
-
15
- import {
16
- _internalFeatureFlags,
17
- syntaxColouringLegend,
18
- } from '@neo4j-cypher/language-support';
14
+ import { syntaxColouringLegend } from '@neo4j-cypher/language-support';
19
15
  import { Neo4jSchemaPoller } from '@neo4j-cypher/query-tools';
20
16
  import { doAutoCompletion } from './autocompletion';
21
17
  import { formatDocument } from './formatting';
22
- import { cleanupWorkers, lintDocument } from './linting';
18
+ import { cleanupWorkers, lintDocument, setLintWorker } from './linting';
23
19
  import { doSignatureHelp } from './signatureHelp';
24
20
  import { applySyntaxColouringForDocument } from './syntaxColouring';
25
21
  import {
22
+ LintWorkerSettings,
26
23
  Neo4jConnectionSettings,
27
24
  Neo4jParameters,
28
25
  Neo4jSettings,
29
26
  } from './types';
30
27
 
31
- if (process.env.CYPHER_25 === 'true') {
32
- _internalFeatureFlags.cypher25 = true;
33
- }
34
-
35
28
  const connection = createConnection(ProposedFeatures.all);
36
29
  let settings: Neo4jSettings | undefined = undefined;
37
30
 
@@ -50,6 +43,7 @@ async function lintSingleDocument(document: TextDocument): Promise<void> {
50
43
  });
51
44
  },
52
45
  neo4jSchemaPoller,
46
+ settings?.features?.useVersionedLinters,
53
47
  );
54
48
  } else {
55
49
  void connection.sendDiagnostics({
@@ -127,6 +121,19 @@ connection.onSignatureHelp(doSignatureHelp(documents, neo4jSchemaPoller));
127
121
  // Trigger the auto completion
128
122
  connection.onCompletion(doAutoCompletion(documents, neo4jSchemaPoller));
129
123
 
124
+ connection.onNotification(
125
+ 'updateLintWorker',
126
+ (linterSettings: LintWorkerSettings) => {
127
+ const lintWorkerPath = linterSettings.lintWorkerPath;
128
+ const linterVersion = linterSettings.linterVersion;
129
+
130
+ void (async () => {
131
+ await setLintWorker(lintWorkerPath, linterVersion);
132
+ relintAllDocuments();
133
+ })();
134
+ },
135
+ );
136
+
130
137
  connection.onNotification(
131
138
  'connectionUpdated',
132
139
  (connectionSettings: Neo4jConnectionSettings) => {
@@ -154,7 +161,7 @@ documents.listen(connection);
154
161
  connection.listen();
155
162
 
156
163
  connection.onExit(() => {
157
- cleanupWorkers();
164
+ void cleanupWorkers();
158
165
  });
159
166
 
160
167
  const changeConnection = (connectionSettings: Neo4jConnectionSettings) => {
package/src/types.ts CHANGED
@@ -7,11 +7,16 @@ export type Neo4jConnectionSettings = {
7
7
  database?: string;
8
8
  };
9
9
 
10
+ export type LintWorkerSettings = {
11
+ lintWorkerPath: string;
12
+ linterVersion: string;
13
+ };
14
+
10
15
  export type Neo4jSettings = {
11
16
  trace: {
12
17
  server: 'off' | 'messages' | 'verbose';
13
18
  };
14
- features: { linting: boolean };
19
+ features: { linting: boolean; useVersionedLinters?: boolean };
15
20
  };
16
21
 
17
22
  export type Neo4jParameters = Record<string, unknown>;
package/src/lintWorker.ts DELETED
@@ -1,31 +0,0 @@
1
- import {
2
- DbSchema,
3
- lintCypherQuery as _lintCypherQuery,
4
- _internalFeatureFlags,
5
- } from '@neo4j-cypher/language-support';
6
- import workerpool from 'workerpool';
7
-
8
- function lintCypherQuery(
9
- query: string,
10
- dbSchema: DbSchema,
11
- featureFlags: { consoleCommands?: boolean; cypher25?: boolean } = {},
12
- ) {
13
- // We allow to override the consoleCommands feature flag
14
- if (featureFlags.consoleCommands !== undefined) {
15
- _internalFeatureFlags.consoleCommands = featureFlags.consoleCommands;
16
- }
17
- if (featureFlags.cypher25 !== undefined) {
18
- _internalFeatureFlags.cypher25 = featureFlags.cypher25;
19
- }
20
- return _lintCypherQuery(query, dbSchema);
21
- }
22
-
23
- workerpool.worker({ lintCypherQuery });
24
-
25
- type LinterArgs = Parameters<typeof lintCypherQuery>;
26
-
27
- export type LinterTask = workerpool.Promise<ReturnType<typeof lintCypherQuery>>;
28
-
29
- export type LintWorker = {
30
- lintCypherQuery: (...args: LinterArgs) => LinterTask;
31
- };