diff --git a/.changeset/purple-suns-applaud.md b/.changeset/purple-suns-applaud.md new file mode 100644 index 000000000..b1e23fd66 --- /dev/null +++ b/.changeset/purple-suns-applaud.md @@ -0,0 +1,5 @@ +--- +'@neo4j-cypher/language-support': patch +--- + +Fix issue where syntax highlighting crashes on create constraint query diff --git a/packages/language-support/src/highlighting/syntaxColouring/syntaxColouring.ts b/packages/language-support/src/highlighting/syntaxColouring/syntaxColouring.ts index 301d1a004..bae998630 100644 --- a/packages/language-support/src/highlighting/syntaxColouring/syntaxColouring.ts +++ b/packages/language-support/src/highlighting/syntaxColouring/syntaxColouring.ts @@ -115,9 +115,12 @@ class SyntaxHighlighter extends CypherParserListener { }; exitLabelOrRelType = (ctx: LabelOrRelTypeContext) => { - const labelName = ctx.symbolicNameString().start; - - this.addToken(labelName, CypherTokenType.label, labelName.text); + // Error recovery can insert a LabelOrRelType node with no text + // See for example CREATE CONSTRAINT FOR (node) + const labelName = ctx.symbolicNameString()?.start; + if (labelName) { + this.addToken(labelName, CypherTokenType.label, labelName.text); + } }; exitLeftArrow = (ctx: LeftArrowContext) => { diff --git a/packages/language-support/src/tests/highlighting/syntaxColouring/clauses.test.ts b/packages/language-support/src/tests/highlighting/syntaxColouring/clauses.test.ts index 902cbc75b..b4954f79f 100644 --- a/packages/language-support/src/tests/highlighting/syntaxColouring/clauses.test.ts +++ b/packages/language-support/src/tests/highlighting/syntaxColouring/clauses.test.ts @@ -2121,3 +2121,83 @@ describe('Subqueries colouring', () => { ]); }); }); + +describe('CREATE colouring', () => { + test('correctly highlight broken create constraint', () => { + // is missing :Label, should not crash + expect(applySyntaxColouring('CREATE CONSTRAINT FOR (node)')).toEqual([ + { + bracketInfo: undefined, + length: 6, + position: { + line: 0, + startCharacter: 0, + startOffset: 0, + }, + token: 'CREATE', + tokenType: 'keyword', + }, + { + bracketInfo: undefined, + length: 10, + position: { + line: 0, + startCharacter: 7, + startOffset: 7, + }, + token: 'CONSTRAINT', + tokenType: 'keyword', + }, + { + bracketInfo: undefined, + length: 3, + position: { + line: 0, + startCharacter: 18, + startOffset: 18, + }, + token: 'FOR', + tokenType: 'keyword', + }, + { + bracketInfo: { + bracketLevel: 0, + bracketType: 'parenthesis', + }, + length: 1, + position: { + line: 0, + startCharacter: 22, + startOffset: 22, + }, + token: '(', + tokenType: 'bracket', + }, + { + bracketInfo: undefined, + length: 4, + position: { + line: 0, + startCharacter: 23, + startOffset: 23, + }, + token: 'node', + tokenType: 'variable', + }, + { + bracketInfo: { + bracketLevel: 0, + bracketType: 'parenthesis', + }, + length: 1, + position: { + line: 0, + startCharacter: 27, + startOffset: 27, + }, + token: ')', + tokenType: 'bracket', + }, + ]); + }); +});