From 03bf322ae6f38fceea400775cb6da891f8048fce Mon Sep 17 00:00:00 2001 From: Isak Date: Thu, 3 Apr 2025 14:15:04 +0200 Subject: [PATCH 1/7] fixes backticking for params, refactors backticking functions to a single one + testing --- .../completionCoreCompletions.ts | 41 +++++----- .../parameterCompletions.test.ts | 75 +++++++++++++++++++ 2 files changed, 99 insertions(+), 17 deletions(-) diff --git a/packages/language-support/src/autocompletion/completionCoreCompletions.ts b/packages/language-support/src/autocompletion/completionCoreCompletions.ts index 1ac7031e1..ba589fe2f 100644 --- a/packages/language-support/src/autocompletion/completionCoreCompletions.ts +++ b/packages/language-support/src/autocompletion/completionCoreCompletions.ts @@ -41,20 +41,27 @@ const uniq = (arr: T[]) => Array.from(new Set(arr)); const versions = () => _internalFeatureFlags.cypher25 ? cypherVersionNumbers : ['5']; -export function backtickIfNeeded(e: string): string | undefined { - if (e == null || e == '') { - return undefined; - } else if (/[^\p{L}\p{N}_]/u.test(e) || /[^\p{L}_]/u.test(e[0])) { - return `\`${e}\``; - } else { - return undefined; - } -} +type BacktickVariant = 'label' | 'propertyKey' | 'relType' | 'dbName' | 'param'; -function backtickDbNameIfNeeded(e: string): string | undefined { +export function backtickIfNeeded( + e: string, + variant: BacktickVariant, +): string | undefined { if (e == null || e == '') { return undefined; - } else if (/[^\p{L}\p{N}_.]/u.test(e) || /[^\p{L}_]/u.test(e[0])) { + } else if ( + (variant === 'label' || + variant === 'propertyKey' || + variant === 'relType') && + (/[^\p{L}\p{N}_]/u.test(e) || /[^\p{L}_]/u.test(e[0])) + ) { + return `\`${e}\``; + } else if ( + variant === 'dbName' && + (/[^\p{L}\p{N}_.]/u.test(e) || /[^\p{L}_]/u.test(e[0])) + ) { + return `\`${e}\``; + } else if (variant === 'param' && /[^\p{L}\p{N}_]/u.test(e)) { return `\`${e}\``; } else { return undefined; @@ -81,7 +88,7 @@ const cypherVersionCompletions = () => const labelCompletions = (dbSchema: DbSchema) => dbSchema.labels?.map((labelName) => { - const backtickedName = backtickIfNeeded(labelName); + const backtickedName = backtickIfNeeded(labelName, 'label'); const maybeInsertText = backtickedName ? { insertText: backtickedName } : {}; @@ -96,7 +103,7 @@ const labelCompletions = (dbSchema: DbSchema) => const reltypeCompletions = (dbSchema: DbSchema) => dbSchema.relationshipTypes?.map((relType) => { - const backtickedName = backtickIfNeeded(relType); + const backtickedName = backtickIfNeeded(relType, 'relType'); const maybeInsertText = backtickedName ? { insertText: backtickedName } : {}; @@ -342,7 +349,7 @@ const parameterCompletions = ( isExpectedParameterType(expectedType, paramType), ) .map(([paramName]) => { - const backtickedName = backtickIfNeeded(paramName); + const backtickedName = backtickIfNeeded(paramName, 'param'); let maybeInsertText = backtickedName ? { insertText: `$${backtickedName}` } : {}; @@ -370,7 +377,7 @@ const parameterCompletions = ( const propertyKeyCompletions = (dbInfo: DbSchema): CompletionItem[] => dbInfo.propertyKeys?.map((propertyKey) => { - const backtickedName = backtickIfNeeded(propertyKey); + const backtickedName = backtickIfNeeded(propertyKey, 'propertyKey'); const maybeInsertText = backtickedName ? { insertText: backtickedName } : {}; @@ -841,7 +848,7 @@ function completeAliasName({ ) ) { return (dbSchema.aliasNames ?? []).map((aliasName) => { - const backtickedName = backtickDbNameIfNeeded(aliasName); + const backtickedName = backtickIfNeeded(aliasName, 'dbName'); const maybeInsertText = backtickedName ? { insertText: backtickedName } : {}; @@ -857,7 +864,7 @@ function completeAliasName({ return (dbSchema.databaseNames ?? []) .concat(dbSchema.aliasNames ?? []) .map((databaseName) => { - const backtickedName = backtickDbNameIfNeeded(databaseName); + const backtickedName = backtickIfNeeded(databaseName, 'dbName'); const maybeInsertText = backtickedName ? { insertText: backtickedName } : {}; diff --git a/packages/language-support/src/tests/autocompletion/parameterCompletions.test.ts b/packages/language-support/src/tests/autocompletion/parameterCompletions.test.ts index 1c2ea5239..2a0f24990 100644 --- a/packages/language-support/src/tests/autocompletion/parameterCompletions.test.ts +++ b/packages/language-support/src/tests/autocompletion/parameterCompletions.test.ts @@ -7,6 +7,9 @@ describe('Completes parameters outside of databases, roles, user names', () => { const dbSchema: DbSchema = { parameters: { stringParam: 'something', + '@param': 'wow', + 'param.1': 5000, + '100param': 'great', intParam: 1337, mapParam: { property: 'value', @@ -41,6 +44,21 @@ describe('Completes parameters outside of databases, roles, user names', () => { kind: CompletionItemKind.Variable, insertText: '`some param`', }, + { + label: '$@param', + kind: CompletionItemKind.Variable, + insertText: '`@param`', + }, + { + label: '$100param', + kind: CompletionItemKind.Variable, + insertText: '100param', + }, + { + label: '$param.1', + kind: CompletionItemKind.Variable, + insertText: '`param.1`', + }, ], }); }); @@ -68,6 +86,20 @@ describe('Completes parameters outside of databases, roles, user names', () => { kind: CompletionItemKind.Variable, insertText: '$`some param`', }, + { + label: '$@param', + kind: CompletionItemKind.Variable, + insertText: '$`@param`', + }, + { + label: '$100param', + kind: CompletionItemKind.Variable, + }, + { + label: '$param.1', + kind: CompletionItemKind.Variable, + insertText: '$`param.1`', + }, ], }); }); @@ -86,6 +118,20 @@ describe('Completes parameters outside of databases, roles, user names', () => { kind: CompletionItemKind.Variable, insertText: '$`some param`', }, + { + label: '$@param', + kind: CompletionItemKind.Variable, + insertText: '$`@param`', + }, + { + label: '$100param', + kind: CompletionItemKind.Variable, + }, + { + label: '$param.1', + kind: CompletionItemKind.Variable, + insertText: '$`param.1`', + }, ], }); }); @@ -116,6 +162,21 @@ describe('Completes parameters outside of databases, roles, user names', () => { kind: CompletionItemKind.Variable, insertText: '`some param`', }, + { + label: '$@param', + kind: CompletionItemKind.Variable, + insertText: '`@param`', + }, + { + label: '$100param', + kind: CompletionItemKind.Variable, + insertText: '100param', + }, + { + label: '$param.1', + kind: CompletionItemKind.Variable, + insertText: '`param.1`', + }, ], }); }); @@ -134,6 +195,20 @@ describe('Completes parameters outside of databases, roles, user names', () => { kind: CompletionItemKind.Variable, insertText: '$`some param`', }, + { + label: '$@param', + kind: CompletionItemKind.Variable, + insertText: '$`@param`', + }, + { + label: '$100param', + kind: CompletionItemKind.Variable, + }, + { + label: '$param.1', + kind: CompletionItemKind.Variable, + insertText: '$`param.1`', + }, ], }); }); From bed1bcf620fdb898e3a1a888cb94b9460aaf2102 Mon Sep 17 00:00:00 2001 From: Isak Date: Thu, 3 Apr 2025 14:26:57 +0200 Subject: [PATCH 2/7] update vite dependency --- package-lock.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4a791d60..19c8788a3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -20006,9 +20006,9 @@ } }, "node_modules/vite": { - "version": "4.5.11", - "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.11.tgz", - "integrity": "sha512-4mVdhLkZ0vpqZLGJhNm+X1n7juqXApEMGlUXcOQawA45UmpxivOYaMBkI/Js3FlBsNA8hCgEnX5X04moFitSGw==", + "version": "4.5.12", + "resolved": "https://registry.npmjs.org/vite/-/vite-4.5.12.tgz", + "integrity": "sha512-qrMwavANtSz91nDy3zEiUHMtL09x0mniQsSMvDkNxuCBM1W5vriJ22hEmwTth6DhLSWsZnHBT0yHFAQXt6efGA==", "dependencies": { "esbuild": "^0.18.10", "postcss": "^8.4.27", From ebe85a0e05b744ffabb662278ad98eeec3a1b027 Mon Sep 17 00:00:00 2001 From: Isak Date: Mon, 7 Apr 2025 14:17:25 +0200 Subject: [PATCH 3/7] adjusts dbName check --- .../src/autocompletion/completionCoreCompletions.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/language-support/src/autocompletion/completionCoreCompletions.ts b/packages/language-support/src/autocompletion/completionCoreCompletions.ts index ba589fe2f..1dcee6a29 100644 --- a/packages/language-support/src/autocompletion/completionCoreCompletions.ts +++ b/packages/language-support/src/autocompletion/completionCoreCompletions.ts @@ -58,7 +58,9 @@ export function backtickIfNeeded( return `\`${e}\``; } else if ( variant === 'dbName' && - (/[^\p{L}\p{N}_.]/u.test(e) || /[^\p{L}_]/u.test(e[0])) + (/[^\p{L}\p{N}_.]/u.test(e) || + /[^\p{L}_]/u.test(e[0]) || + /[^\p{L}_]/u.test(e[e.length - 1])) ) { return `\`${e}\``; } else if (variant === 'param' && /[^\p{L}\p{N}_]/u.test(e)) { From 67967b4a08b6de204d6e40b9d05700a483510b9a Mon Sep 17 00:00:00 2001 From: Isak Date: Mon, 7 Apr 2025 14:22:47 +0200 Subject: [PATCH 4/7] Adds changeset --- .changeset/poor-toys-change.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/poor-toys-change.md diff --git a/.changeset/poor-toys-change.md b/.changeset/poor-toys-change.md new file mode 100644 index 000000000..f54194df0 --- /dev/null +++ b/.changeset/poor-toys-change.md @@ -0,0 +1,5 @@ +--- +'@neo4j-cypher/language-support': patch +--- + +Fixes backticking of parameters and dbNames/aliases From bd6f8954a61b821671b6b41df6cd6e4d227a2590 Mon Sep 17 00:00:00 2001 From: Isak Date: Mon, 7 Apr 2025 14:58:56 +0200 Subject: [PATCH 5/7] fixes so backticks are not inserted if final letter is a number --- .../src/autocompletion/completionCoreCompletions.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/language-support/src/autocompletion/completionCoreCompletions.ts b/packages/language-support/src/autocompletion/completionCoreCompletions.ts index 1dcee6a29..3b6953796 100644 --- a/packages/language-support/src/autocompletion/completionCoreCompletions.ts +++ b/packages/language-support/src/autocompletion/completionCoreCompletions.ts @@ -60,7 +60,7 @@ export function backtickIfNeeded( variant === 'dbName' && (/[^\p{L}\p{N}_.]/u.test(e) || /[^\p{L}_]/u.test(e[0]) || - /[^\p{L}_]/u.test(e[e.length - 1])) + /[^\p{L}\p{N}_]/u.test(e[e.length - 1])) ) { return `\`${e}\``; } else if (variant === 'param' && /[^\p{L}\p{N}_]/u.test(e)) { From b9561dcec3b6b0984ed08498933677dcc32a6e8b Mon Sep 17 00:00:00 2001 From: Isak Date: Tue, 8 Apr 2025 09:50:48 +0200 Subject: [PATCH 6/7] fixes e[e.length-1] -> e.at(-1) and expands dbname/aliasname testing for odd starts/endings --- .../completionCoreCompletions.ts | 8 ++-- .../databasenameCompletion.test.ts | 46 +++++++++++++++++++ 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/packages/language-support/src/autocompletion/completionCoreCompletions.ts b/packages/language-support/src/autocompletion/completionCoreCompletions.ts index 3b6953796..7f481e4ae 100644 --- a/packages/language-support/src/autocompletion/completionCoreCompletions.ts +++ b/packages/language-support/src/autocompletion/completionCoreCompletions.ts @@ -60,7 +60,7 @@ export function backtickIfNeeded( variant === 'dbName' && (/[^\p{L}\p{N}_.]/u.test(e) || /[^\p{L}_]/u.test(e[0]) || - /[^\p{L}\p{N}_]/u.test(e[e.length - 1])) + /[^\p{L}\p{N}_]/u.test(e.at(-1))) ) { return `\`${e}\``; } else if (variant === 'param' && /[^\p{L}\p{N}_]/u.test(e)) { @@ -688,22 +688,24 @@ export function completionCoreCompletion( } if (ruleNumber === CypherParser.RULE_symbolicAliasName) { - return completeAliasName({ + const aliasCompletion = completeAliasName({ candidateRule, dbSchema, tokens, parsingResult, }); + return aliasCompletion; } if (ruleNumber === CypherParser.RULE_commandNameExpression) { - return completeSymbolicName({ + const symbolicCompletions = completeSymbolicName({ candidateRule, dbSchema, previousToken, tokens, parsingResult, }); + return symbolicCompletions; } if (ruleNumber === CypherParser.RULE_labelExpression1) { diff --git a/packages/language-support/src/tests/autocompletion/databasenameCompletion.test.ts b/packages/language-support/src/tests/autocompletion/databasenameCompletion.test.ts index 84f53f70b..32d98cd74 100644 --- a/packages/language-support/src/tests/autocompletion/databasenameCompletion.test.ts +++ b/packages/language-support/src/tests/autocompletion/databasenameCompletion.test.ts @@ -10,6 +10,8 @@ describe('Can complete database names', () => { 'movies', 'financial reports', 'neo4j_server', + 'periodEnd.', + 'dashEnd-', ], aliasNames: [ 'myMovies', @@ -17,6 +19,10 @@ describe('Can complete database names', () => { 'a.b.c.d', 'panama papers1', 'office-db', + 'periodAlias.', + 'dashAlias-', + 'db@', + '1db', ], parameters: { param1: 'something', @@ -55,6 +61,26 @@ describe('Can complete database names', () => { kind: CompletionItemKind.Variable, insertText: '$`param 4`', }, + { + label: 'periodEnd.', + kind: CompletionItemKind.Value, + insertText: '`periodEnd.`', + }, + { + label: 'dashEnd-', + kind: CompletionItemKind.Value, + insertText: '`dashEnd-`', + }, + { + label: 'periodAlias.', + kind: CompletionItemKind.Value, + insertText: '`periodAlias.`', + }, + { + label: 'dashAlias-', + kind: CompletionItemKind.Value, + insertText: '`dashAlias-`', + }, ], }); }); @@ -81,6 +107,26 @@ describe('Can complete database names', () => { kind: CompletionItemKind.Variable, insertText: '$`param 4`', }, + { + label: 'periodAlias.', + kind: CompletionItemKind.Value, + insertText: '`periodAlias.`', + }, + { + label: 'dashAlias-', + kind: CompletionItemKind.Value, + insertText: '`dashAlias-`', + }, + { + label: 'db@', + kind: CompletionItemKind.Value, + insertText: '`db@`', + }, + { + label: '1db', + kind: CompletionItemKind.Value, + insertText: '`1db`', + }, ], }); }); From ece928e748fcd6d5127554c4202025fa9926803b Mon Sep 17 00:00:00 2001 From: Isak Date: Tue, 8 Apr 2025 14:20:30 +0200 Subject: [PATCH 7/7] fixes minor change from debugging --- .../src/autocompletion/completionCoreCompletions.ts | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/packages/language-support/src/autocompletion/completionCoreCompletions.ts b/packages/language-support/src/autocompletion/completionCoreCompletions.ts index 7f481e4ae..a60749676 100644 --- a/packages/language-support/src/autocompletion/completionCoreCompletions.ts +++ b/packages/language-support/src/autocompletion/completionCoreCompletions.ts @@ -688,24 +688,22 @@ export function completionCoreCompletion( } if (ruleNumber === CypherParser.RULE_symbolicAliasName) { - const aliasCompletion = completeAliasName({ + return completeAliasName({ candidateRule, dbSchema, tokens, parsingResult, }); - return aliasCompletion; } if (ruleNumber === CypherParser.RULE_commandNameExpression) { - const symbolicCompletions = completeSymbolicName({ + return completeSymbolicName({ candidateRule, dbSchema, previousToken, tokens, parsingResult, }); - return symbolicCompletions; } if (ruleNumber === CypherParser.RULE_labelExpression1) {