Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapts procedure registry to depend on the cypher version #331

Merged
merged 37 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
34f2bb8
Altered semantic analysis to use default/query-specified version if a…
anderson4j Jan 13, 2025
1f76037
Merge branch 'main' of https://github.com/neo4j/cypher-language-suppo…
anderson4j Jan 13, 2025
d1d0a48
added tests
anderson4j Jan 15, 2025
d79e282
small refactor, fix defaultLanguage to be more like data according to…
anderson4j Jan 16, 2025
b9fc356
added changeset
anderson4j Jan 16, 2025
d653261
Adds some minor nits
ncordon Jan 21, 2025
33fd518
Adds versioned procedure registry
ncordon Jan 21, 2025
e58d2e5
Updates the semantic analysis to use different procedure registries d…
ncordon Jan 22, 2025
44c0b32
Adds tests for procedures / functions dependant on cypher versions
ncordon Jan 22, 2025
6e7e5c6
Adds tests for completions and signature help being cypher version de…
ncordon Jan 22, 2025
ff25f9e
Makes project compile
ncordon Jan 22, 2025
fbdf5bb
Fixes e2e tests
ncordon Jan 23, 2025
7cacbcb
Merge branch 'main' into polling-versioned-procs-fns
ncordon Jan 23, 2025
9d29a4b
Adds integration test to check the poller and VSCode extension can us…
ncordon Jan 23, 2025
ee324f9
Merge remote-tracking branch 'origin/polling-versioned-procs-fns' int…
ncordon Jan 23, 2025
6c98b22
Fixes e2e test
ncordon Jan 23, 2025
07f20b7
Self review
ncordon Jan 23, 2025
f3b41a1
Adds feature flag to the codemirror wiring
ncordon Jan 24, 2025
662b643
Fixes feature flag
ncordon Jan 26, 2025
cbda4a1
Adds more tests for codemirror
ncordon Jan 26, 2025
ef228ad
Merge remote-tracking branch 'origin/main' into polling-versioned-pro…
ncordon Jan 28, 2025
f18041e
Updates semantic analysis and removes exports
ncordon Jan 28, 2025
d2704ec
Addresses pr review comments
ncordon Jan 29, 2025
f2313a1
Merge branch 'main' into polling-versioned-procs-fns
ncordon Jan 29, 2025
d6d9547
Sets the env variable with cross-env
ncordon Jan 29, 2025
74f5ecb
Updates only needed resolver
ncordon Jan 29, 2025
cacf7a4
Widens timeout
ncordon Jan 30, 2025
fb785f4
Widens timeout even more
ncordon Jan 30, 2025
bdaa8f7
Removes helpers test
ncordon Jan 30, 2025
811d70a
Merge remote-tracking branch 'origin/main' into polling-versioned-pro…
ncordon Jan 30, 2025
3a10389
Forces update
ncordon Jan 30, 2025
f6ba2ef
Increases another timeout
ncordon Jan 31, 2025
b3a8b8b
Gates the test to have the test.only
ncordon Jan 31, 2025
8e00f98
Tries widening all timeouts
ncordon Jan 31, 2025
ee2cd18
Cleans up
ncordon Jan 31, 2025
aa7c1a3
Removes non needed force
ncordon Feb 4, 2025
04430fa
Merge remote-tracking branch 'origin/main' into polling-versioned-pro…
ncordon Feb 4, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
"devDependencies": {
"@changesets/cli": "^2.27.8",
"@typescript-eslint/eslint-plugin": "^7.8.0",
"cross-env": "^7.0.3",
"eslint": "^8.32.0",
"eslint-config-prettier": "^8.6.0",
"husky": "^8.0.0",
Expand Down
21 changes: 20 additions & 1 deletion packages/language-server/src/lintWorker.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,25 @@
import { lintCypherQuery } from '@neo4j-cypher/language-support';
import {
DbSchema,
lintCypherQuery as _lintCypherQuery,
_internalFeatureFlags,
} from '@neo4j-cypher/language-support';
import workerpool from 'workerpool';

function lintCypherQuery(
query: string,
dbSchema: DbSchema,
featureFlags: { consoleCommands?: boolean; cypher25?: boolean } = {},
) {
// We allow to override the consoleCommands feature flag
if (featureFlags.consoleCommands !== undefined) {
_internalFeatureFlags.consoleCommands = featureFlags.consoleCommands;
}
if (featureFlags.cypher25 !== undefined) {
_internalFeatureFlags.cypher25 = featureFlags.cypher25;
}
Comment on lines +17 to +19
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We need to pass the feature flags to the lint worker because the _internalFeatureFlags variable from the outside lives in another thread

return _lintCypherQuery(query, dbSchema);
}

workerpool.worker({ lintCypherQuery });

type LinterArgs = Parameters<typeof lintCypherQuery>;
Expand Down
7 changes: 6 additions & 1 deletion packages/language-server/src/linting.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { _internalFeatureFlags } from '@neo4j-cypher/language-support';
import { Neo4jSchemaPoller } from '@neo4j-cypher/schema-poller';
import debounce from 'lodash.debounce';
import { join } from 'path';
Expand Down Expand Up @@ -31,7 +32,11 @@ async function rawLintDocument(
}

const proxyWorker = (await pool.proxy()) as unknown as LintWorker;
lastSemanticJob = proxyWorker.lintCypherQuery(query, dbSchema);
lastSemanticJob = proxyWorker.lintCypherQuery(
query,
dbSchema,
_internalFeatureFlags,
);
const result = await lastSemanticJob;

sendDiagnostics(result);
Expand Down
9 changes: 8 additions & 1 deletion packages/language-server/src/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,21 @@ import {

import { TextDocument } from 'vscode-languageserver-textdocument';

import { syntaxColouringLegend } from '@neo4j-cypher/language-support';
import {
syntaxColouringLegend,
_internalFeatureFlags,
} from '@neo4j-cypher/language-support';
import { Neo4jSchemaPoller } from '@neo4j-cypher/schema-poller';
import { doAutoCompletion } from './autocompletion';
import { cleanupWorkers, lintDocument } from './linting';
import { doSignatureHelp } from './signatureHelp';
import { applySyntaxColouringForDocument } from './syntaxColouring';
import { Neo4jSettings } from './types';

if (process.env.CYPHER_25 === 'true') {
_internalFeatureFlags.cypher25 = true;
}
Comment on lines +26 to +28
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so we can set the feature flag in the language server from the vscode extension


const connection = createConnection(ProposedFeatures.all);

// Create a simple text document manager.
Expand Down
2 changes: 1 addition & 1 deletion packages/language-support/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@
"vscode-languageserver-types": "^3.17.3"
},
"scripts": {
"gen-parser": "antlr4 -Dlanguage=TypeScript -visitor src/antlr-grammar/CypherCmdLexer.g4 src/antlr-grammar/CypherCmdParser.g4 -o src/generated-parser/ -Xexact-output-dir",
"gen-parser": "cross-env ANTLR4_TOOLS_ANTLR_VERSION=4.13.2 antlr4 -Dlanguage=TypeScript -visitor src/antlr-grammar/CypherCmdLexer.g4 src/antlr-grammar/CypherCmdParser.g4 -o src/generated-parser/ -Xexact-output-dir",
"build": "npm run gen-parser && concurrently 'npm:build-types' 'npm:build-esm' 'npm:build-commonjs'",
"build-types": "tsc --emitDeclarationOnly --outDir dist/types",
"build-esm": "esbuild ./src/index.ts --bundle --format=esm --sourcemap --outfile=dist/esm/index.mjs",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import CypherParser, {
import {
findParent,
findPreviousNonSpace,
resolveCypherVersion,
rulesDefiningVariables,
} from '../helpers';
import {
Expand All @@ -27,7 +28,12 @@ import {
import { getMethodName, ParsedStatement } from '../parserWrapper';

import { _internalFeatureFlags } from '../featureFlags';
import { CompletionItem, Neo4jFunction, Neo4jProcedure } from '../types';
import {
CompletionItem,
CypherVersion,
Neo4jFunction,
Neo4jProcedure,
} from '../types';

const uniq = <T>(arr: T[]) => Array.from(new Set(arr));

Expand Down Expand Up @@ -94,9 +100,12 @@ const reltypeCompletions = (dbSchema: DbSchema) =>
const procedureReturnCompletions = (
procedureName: string,
dbSchema: DbSchema,
cypherVersion: CypherVersion,
): CompletionItem[] => {
return (
dbSchema?.procedures?.[procedureName]?.returnDescription?.map((x) => {
dbSchema.procedures?.[cypherVersion]?.[
procedureName
]?.returnDescription?.map((x) => {
return { label: x.name, kind: CompletionItemKind.Variable };
}) ?? []
);
Expand All @@ -106,23 +115,25 @@ const functionNameCompletions = (
candidateRule: CandidateRule,
tokens: Token[],
dbSchema: DbSchema,
cypherVersion: CypherVersion,
): CompletionItem[] =>
namespacedCompletion(
candidateRule,
tokens,
dbSchema?.functions ?? {},
dbSchema.functions?.[cypherVersion] ?? {},
'function',
);

const procedureNameCompletions = (
candidateRule: CandidateRule,
tokens: Token[],
dbSchema: DbSchema,
cypherVersion: CypherVersion,
): CompletionItem[] =>
namespacedCompletion(
candidateRule,
tokens,
dbSchema?.procedures ?? {},
dbSchema.procedures?.[cypherVersion] ?? {},
'procedure',
);

Expand Down Expand Up @@ -430,6 +441,10 @@ export function completionCoreCompletion(
caretToken: Token,
manualTrigger = false,
): CompletionItem[] {
const cypherVersion = resolveCypherVersion(
parsingResult.cypherVersion,
dbSchema,
);
const parser = parsingResult.parser;
const tokens = parsingResult.tokens;

Expand Down Expand Up @@ -536,18 +551,30 @@ export function completionCoreCompletion(
callContext.procedureResultItem_list().map((a) => a.getText()),
);
const name = getMethodName(procedureNameCtx);
return procedureReturnCompletions(name, dbSchema).filter(
(a) => !existingYieldItems.has(a?.label),
);
return procedureReturnCompletions(
name,
dbSchema,
cypherVersion,
).filter((a) => !existingYieldItems.has(a?.label));
}
}

if (ruleNumber === CypherParser.RULE_functionName) {
return functionNameCompletions(candidateRule, tokens, dbSchema);
return functionNameCompletions(
candidateRule,
tokens,
dbSchema,
cypherVersion,
);
}

if (ruleNumber === CypherParser.RULE_procedureName) {
return procedureNameCompletions(candidateRule, tokens, dbSchema);
return procedureNameCompletions(
candidateRule,
tokens,
dbSchema,
cypherVersion,
);
}

if (ruleNumber === CypherParser.RULE_parameter) {
Expand Down Expand Up @@ -769,7 +796,7 @@ function completeAliasName({
) {
return [
...parameterSuggestions,
...(dbSchema?.aliasNames ?? []).map((aliasName) => ({
...(dbSchema.aliasNames ?? []).map((aliasName) => ({
label: aliasName,
kind: CompletionItemKind.Value,
insertText: backtickDbNameIfNeeded(aliasName),
Expand Down Expand Up @@ -834,7 +861,7 @@ function completeSymbolicName({
if (rulesThatAcceptExistingUsers.some((rule) => ruleList.includes(rule))) {
const result = [
...parameterSuggestions,
...(dbSchema?.userNames ?? []).map((userName) => ({
...(dbSchema.userNames ?? []).map((userName) => ({
label: userName,
kind: CompletionItemKind.Value,
})),
Expand All @@ -852,7 +879,7 @@ function completeSymbolicName({
if (rulesThatAcceptExistingRoles.some((rule) => ruleList.includes(rule))) {
return [
...parameterSuggestions,
...(dbSchema?.roleNames ?? []).map((roleName) => ({
...(dbSchema.roleNames ?? []).map((roleName) => ({
label: roleName,
kind: CompletionItemKind.Value,
})),
Expand Down
7 changes: 5 additions & 2 deletions packages/language-support/src/dbSchema.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
import { CypherVersion, Neo4jFunction, Neo4jProcedure } from './types';

export type Registry<T> = Record<string, T>;
type ScopedRegistry<T> = Partial<Record<CypherVersion, Registry<T>>>;

export interface DbSchema {
labels?: string[];
relationshipTypes?: string[];
Expand All @@ -9,7 +12,7 @@ export interface DbSchema {
roleNames?: string[];
parameters?: Record<string, unknown>;
propertyKeys?: string[];
procedures?: Record<string, Neo4jProcedure>;
functions?: Record<string, Neo4jFunction>;
procedures?: ScopedRegistry<Neo4jProcedure>;
functions?: ScopedRegistry<Neo4jFunction>;
defaultLanguage?: CypherVersion;
}
2 changes: 2 additions & 0 deletions packages/language-support/src/featureFlags.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
interface FeatureFlags {
consoleCommands: boolean;
cypher25: boolean;
}

export const _internalFeatureFlags: FeatureFlags = {
Expand All @@ -11,4 +12,5 @@ export const _internalFeatureFlags: FeatureFlags = {
it's own cache and preference on if console commands are enabled or not.
*/
consoleCommands: false,
cypher25: false,
};
2 changes: 1 addition & 1 deletion packages/language-support/src/formatting/formatting.ts
Original file line number Diff line number Diff line change
Expand Up @@ -399,7 +399,7 @@ export function formatQuery(
): string | FormattingResultWithCursor {
const { tree, tokens } = getParseTreeAndTokens(query);
const visitor = new TreePrintVisitor(tokens);

tokens.fill();

if (cursorPosition === undefined) return visitor.format(tree);
Expand Down
Loading