Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

@neo4j-cypher/react-codemirror

Package Overview
Dependencies
Maintainers
0
Versions
140
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@neo4j-cypher/react-codemirror - npm Package Compare versions

Comparing version 2.0.0-canary-cbfc75e to 2.0.0-canary-db9f594

dist/constants.d.ts

40

CHANGELOG.md
# @neo4j-cypher/react-codemirror
## 2.0.0-next.12
### Patch Changes
- dcbe67d: Expose moveFocusOnTab property on the CypherEditor component to conditionally disable tab keymappings
- e9621c8: Re-export language support from react codemirror
- Updated dependencies [2e72ac8]
- @neo4j-cypher/language-support@2.0.0-next.9
## 2.0.0-next.11
### Patch Changes
- Updated dependencies [05663bd]
- @neo4j-cypher/language-support@2.0.0-next.8
## 2.0.0-next.10
### Patch Changes
- bb7e9d3: Simplify detection and handling of value prop updates
## 2.0.0-next.9
### Patch Changes
- fbd5f7e: allow signature help panel to render below editor when there's not enough space above it
- 09dfae2: Add an ariaLabel prop to CypherEditor
- 7154e94: Fix bug causing debouncing to override value
- 62c152f: execute single line query on enter by default
- cbfc75e: Fix a bug causing debounced value updates to get cancelled erroneously
- 04ae35e: Set initial latestDispatchedValue and flush debounced changes onExecute
Add tests for debounce behaviour
- Updated dependencies [3661e9d]
- Updated dependencies [b76af58]
- Updated dependencies [21699b7]
- Updated dependencies [6afc0e3]
- Updated dependencies [39b924d]
- @neo4j-cypher/language-support@2.0.0-next.7
## 2.0.0-next.8

@@ -4,0 +44,0 @@

12

dist/CypherEditor.d.ts

@@ -138,5 +138,14 @@ import { EditorState, Extension } from '@codemirror/state';

/**
* String value to assign to the aria-label attribute of the editor
* String value to assign to the aria-label attribute of the editor.
*/
ariaLabel?: string;
/**
* Whether keybindings for inserting indents with the Tab key should be disabled.
*
* true will not create keybindings for inserting indents.
* false will create keybindings for inserting indents.
*
* @default false
*/
moveFocusOnTab?: boolean;
}

@@ -160,3 +169,2 @@ type CypherEditorState = {

private schemaRef;
private latestDispatchedValue;
/**

@@ -163,0 +171,0 @@ * Focus the editor

23

dist/CypherEditor.js

@@ -7,2 +7,3 @@ import { jsx as _jsx } from "react/jsx-runtime";

import { Component, createRef } from 'react';
import { DEBOUNCE_TIME } from './constants';
import { replaceHistory, replMode as historyNavigation, } from './historyNavigation';

@@ -13,3 +14,3 @@ import { cypher } from './lang-cypher/langCypher';

import { getThemeExtension } from './themes';
const executeKeybinding = (onExecute, newLineOnEnter) => {
const executeKeybinding = (onExecute, newLineOnEnter, flush) => {
const keybindings = {

@@ -37,2 +38,3 @@ 'Shift-Enter': {

if (doc.trim() !== '') {
flush?.();
onExecute(doc);

@@ -55,2 +57,3 @@ }

if (doc.trim() !== '') {
flush?.();
onExecute(doc);

@@ -92,3 +95,2 @@ }

schemaRef = createRef();
latestDispatchedValue;
/**

@@ -135,8 +137,8 @@ * Focus the editor

newLineOnEnter: false,
moveFocusOnTab: false,
};
debouncedOnChange = this.props.onChange
? debounce(((value, viewUpdate) => {
this.latestDispatchedValue = value;
this.props.onChange(value, viewUpdate);
}), 200)
}), DEBOUNCE_TIME)
: undefined;

@@ -176,7 +178,7 @@ componentDidMount() {

keyBindingCompartment.of(keymap.of([
...executeKeybinding(onExecute, newLineOnEnter),
...executeKeybinding(onExecute, newLineOnEnter, () => this.debouncedOnChange?.flush()),
...extraKeybindings,
])),
historyNavigation(this.props),
basicNeo4jSetup(),
basicNeo4jSetup(this.props),
themeCompartment.of(themeExtension),

@@ -222,5 +224,6 @@ changeListener,

const currentCmValue = this.editorView.current.state?.doc.toString() ?? '';
if (this.props.value !== undefined &&
this.props.value !== this.latestDispatchedValue) {
this.debouncedOnChange?.cancel();
if (this.props.value !== undefined && // If the component becomes uncontolled, we just leave the value as is
this.props.value !== prevProps.value && // The value prop has changed, we need to update the editor
this.props.value !== currentCmValue // No need to dispatch an update if the value is the same
) {
this.editorView.current.dispatch({

@@ -266,3 +269,3 @@ changes: {

effects: keyBindingCompartment.reconfigure(keymap.of([
...executeKeybinding(this.props.onExecute, this.props.newLineOnEnter),
...executeKeybinding(this.props.onExecute, this.props.newLineOnEnter, () => this.debouncedOnChange?.flush()),
...this.props.extraKeybindings,

@@ -269,0 +272,0 @@ ])),

import { jsx as _jsx } from "react/jsx-runtime";
/* eslint-disable @typescript-eslint/unbound-method */
import { testData } from '@neo4j-cypher/language-support';

@@ -41,2 +42,20 @@ import { expect, test } from '@playwright/experimental-ct-react';

});
test('get completions when typing in controlled component', async ({ mount, page, }) => {
let value = '';
const onChange = (val) => {
value = val;
void component.update(_jsx(CypherEditor, { value: val, onChange: onChange }));
};
const component = await mount(_jsx(CypherEditor, { value: value, onChange: onChange }));
const textField = page.getByRole('textbox');
await textField.fill('RETU');
await page.waitForTimeout(500); // wait for debounce
await expect(page.locator('.cm-tooltip-autocomplete').getByText('RETURN')).toBeVisible();
// We need to wait for the editor to realise there is a completion open
// so that it does not just indent with tab key
await page.waitForTimeout(500);
await textField.press('Tab');
await expect(page.locator('.cm-tooltip-autocomplete')).not.toBeVisible();
await expect(component).toContainText('RETURN');
});
test('can complete labels', async ({ mount, page }) => {

@@ -52,2 +71,14 @@ const component = await mount(_jsx(CypherEditor, { schema: {

});
test('can complete properties with backticks', async ({ mount, page }) => {
const component = await mount(_jsx(CypherEditor, { schema: {
propertyKeys: ['foo bar'],
} }));
const textField = page.getByRole('textbox');
await textField.fill('MATCH (n) RETURN n.foo');
await textField.press('Escape');
await textField.press('Control+ ');
await page.locator('.cm-tooltip-autocomplete').getByText('foo bar').click();
await expect(page.locator('.cm-tooltip-autocomplete')).not.toBeVisible();
await expect(component).toContainText('MATCH (n) RETURN n.`foo bar`');
});
test('can update dbschema', async ({ mount, page }) => {

@@ -199,9 +230,2 @@ const component = await mount(_jsx(CypherEditor, { schema: {

});
test('does not signature help information on auto-completion if flag not enabled explicitly', async ({ page, mount, }) => {
await mount(_jsx(CypherEditor, { schema: testData.mockSchema }));
const textField = page.getByRole('textbox');
await textField.fill('CALL apoc.periodic.');
await expect(page.locator('.cm-tooltip-autocomplete')).toBeVisible();
await expect(page.locator('.cm-completionInfo')).not.toBeVisible();
});
test('does not signature help information on auto-completion if docs and signature are empty', async ({ page, mount, }) => {

@@ -208,0 +232,0 @@ await mount(_jsx(CypherEditor, { schema: testData.mockSchema, featureFlags: {

@@ -24,3 +24,5 @@ import { jsx as _jsx } from "react/jsx-runtime";

const textField = page.getByRole('textbox');
await textField.fill('');
await textField.fill('RETURN 12');
await expect(textField).toHaveText('RETURN 12');
// editor update is debounced, retry wait for debounced

@@ -30,6 +32,2 @@ await expect(() => {

}).toPass({ intervals: [300, 300, 1000] });
await page.keyboard.type('34');
await expect(() => {
expect(editorValueCopy).toBe('RETURN 12');
}).toPass({ intervals: [300, 300, 1000] });
});

@@ -36,0 +34,0 @@ test('can complete RETURN', async ({ page, mount }) => {

import { jsx as _jsx } from "react/jsx-runtime";
/* eslint-disable @typescript-eslint/unbound-method */
import { testData } from '@neo4j-cypher/language-support';

@@ -6,2 +7,3 @@ import { expect, test } from '@playwright/experimental-ct-react';

test.use({ viewport: { width: 1000, height: 500 } });
const importCsvProc = testData.mockSchema.procedures['apoc.import.csv'];
function testTooltip(tooltip, expectations) {

@@ -42,4 +44,5 @@ const includes = expectations.includes ?? [];

includes: [
'nodes :: LIST<MAP>',
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
testData.mockSchema.procedures['apoc.import.csv'].argumentDescription[0]
.description,
testData.mockSchema.procedures['apoc.import.csv'].description,
],

@@ -54,4 +57,4 @@ });

includes: [
'nodes :: LIST<MAP>',
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
importCsvProc.argumentDescription[0].description,
importCsvProc.description,
],

@@ -66,4 +69,4 @@ });

includes: [
'rels :: LIST<MAP>',
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
importCsvProc.argumentDescription[1].description,
importCsvProc.description,
],

@@ -78,4 +81,4 @@ });

includes: [
'rels :: LIST<MAP>',
'Imports `NODE` and `RELATIONSHIP` values with the given labels and types from the provided CSV file',
importCsvProc.argumentDescription[1].description,
importCsvProc.description,
],

@@ -82,0 +85,0 @@ });

@@ -1,4 +0,4 @@

export { CypherParser, _internalFeatureFlags, } from '@neo4j-cypher/language-support';
export * as LanguageSupport from '@neo4j-cypher/language-support';
export { CypherEditor } from './CypherEditor';
export { cypher } from './lang-cypher/langCypher';
export { darkThemeConstants, lightThemeConstants } from './themes';

@@ -1,2 +0,2 @@

export { CypherParser, _internalFeatureFlags, } from '@neo4j-cypher/language-support';
export * as LanguageSupport from '@neo4j-cypher/language-support';
export { CypherEditor } from './CypherEditor';

@@ -3,0 +3,0 @@ export { cypher } from './lang-cypher/langCypher';

@@ -45,5 +45,5 @@ import { snippet, } from '@codemirror/autocomplete';

export const cypherAutocomplete = (config) => (context) => {
const textUntilCursor = context.state.doc.toString().slice(0, context.pos);
const documentText = context.state.doc.toString();
const triggerCharacters = ['.', ':', '{', '$', ')'];
const lastCharacter = textUntilCursor.slice(-1);
const lastCharacter = documentText.at(context.pos - 1);
const lastWord = context.matchBefore(/\w*/);

@@ -58,59 +58,41 @@ const inWord = lastWord.from !== lastWord.to;

}
const options = autocomplete(textUntilCursor, config.schema ?? {}, undefined, context.explicit);
if (config.featureFlags.signatureInfoOnAutoCompletions) {
return {
from: context.matchBefore(/(\w|\$)*$/).from,
options: options.map((o) => {
let maybeInfo = {};
let emptyInfo = true;
const newDiv = document.createElement('div');
if (o.signature) {
const header = document.createElement('p');
header.setAttribute('class', 'cm-completionInfo-signature');
header.textContent = o.signature;
if (header.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(header);
}
const options = autocomplete(documentText, config.schema ?? {}, context.pos, context.explicit);
return {
from: context.matchBefore(/(\w|\$)*$/).from,
options: options.map((o) => {
let maybeInfo = {};
let emptyInfo = true;
const newDiv = document.createElement('div');
if (o.signature) {
const header = document.createElement('p');
header.setAttribute('class', 'cm-completionInfo-signature');
header.textContent = o.signature;
if (header.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(header);
}
if (o.documentation) {
const paragraph = document.createElement('p');
paragraph.textContent = getDocString(o.documentation);
if (paragraph.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(paragraph);
}
}
if (o.documentation) {
const paragraph = document.createElement('p');
paragraph.textContent = getDocString(o.documentation);
if (paragraph.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(paragraph);
}
if (!emptyInfo) {
maybeInfo = {
info: () => Promise.resolve(newDiv),
};
}
const deprecated = o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ??
false;
// The negative boost moves the deprecation down the list
// so we offer the user the completions that are
// deprecated the last
const maybeDeprecated = deprecated
? { boost: -99, deprecated: true }
: {};
return {
label: o.label,
type: completionKindToCodemirrorIcon(o.kind),
apply: o.kind === CompletionItemKind.Snippet
? // codemirror requires an empty snippet space to be able to tab out of the completion
snippet((o.insertText ?? o.label) + '${}')
: undefined,
detail: o.detail,
...maybeDeprecated,
...maybeInfo,
}
if (!emptyInfo) {
maybeInfo = {
info: () => Promise.resolve(newDiv),
};
}),
};
}
else {
return {
from: context.matchBefore(/(\w|\$)*$/).from,
options: options.map((o) => ({
label: o.label,
}
const deprecated = o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ?? false;
// The negative boost moves the deprecation down the list
// so we offer the user the completions that are
// deprecated the last
const maybeDeprecated = deprecated
? { boost: -99, deprecated: true }
: {};
return {
label: o.insertText ? o.insertText : o.label,
displayLabel: o.label,
type: completionKindToCodemirrorIcon(o.kind),

@@ -122,6 +104,8 @@ apply: o.kind === CompletionItemKind.Snippet

detail: o.detail,
})),
};
}
...maybeDeprecated,
...maybeInfo,
};
}),
};
};
//# sourceMappingURL=autocomplete.js.map
import { tags } from '@lezer/highlight';
import { applySyntaxColouring, CypherTokenType, } from '@neo4j-cypher/language-support';
import { expect, test } from 'vitest';
import { tokenTypeToStyleTag } from './constants';

@@ -4,0 +5,0 @@ const cypherQueryWithAllTokenTypes = `MATCH (variable :Label)-[:REL_TYPE]->()

@@ -79,2 +79,5 @@ import { HighlightStyle, syntaxHighlighting, } from '@codemirror/language';

},
'& .cm-signature-help-panel-arg-description': {
padding: '5px',
},
'& .cm-signature-help-panel-description': {

@@ -81,0 +84,0 @@ padding: '5px',

@@ -7,3 +7,2 @@ import { LanguageSupport } from '@codemirror/language';

featureFlags?: {
signatureInfoOnAutoCompletions?: boolean;
consoleCommands?: boolean;

@@ -10,0 +9,0 @@ };

import { StateField } from '@codemirror/state';
import { showTooltip } from '@codemirror/view';
import { signatureHelp } from '@neo4j-cypher/language-support';
import { MarkupContent, } from 'vscode-languageserver-types';
import { getDocString } from './utils';

@@ -25,7 +26,10 @@ function getTriggerCharacter(query, caretPosition) {

signatureLabel.className = 'cm-signature-help-panel-name';
signatureLabel.appendChild(document.createTextNode(`${signature.label}(`));
const methodName = signature.label.slice(0, signature.label.indexOf('('));
const returnType = signature.label.slice(signature.label.indexOf(')') + 1);
signatureLabel.appendChild(document.createTextNode(`${methodName}(`));
let currentParamDescription = undefined;
parameters.forEach((param, index) => {
if (typeof param.documentation === 'string') {
if (typeof param.label === 'string') {
const span = document.createElement('span');
span.appendChild(document.createTextNode(param.documentation));
span.appendChild(document.createTextNode(param.label));
if (index !== parameters.length - 1) {

@@ -36,2 +40,6 @@ span.appendChild(document.createTextNode(', '));

span.className = 'cm-signature-help-panel-current-argument';
const paramDoc = param.documentation;
currentParamDescription = MarkupContent.is(paramDoc)
? paramDoc.value
: paramDoc;
}

@@ -42,2 +50,3 @@ signatureLabel.appendChild(span);

signatureLabel.appendChild(document.createTextNode(')'));
signatureLabel.appendChild(document.createTextNode(returnType));
contents.appendChild(signatureLabel);

@@ -47,6 +56,12 @@ const separator = document.createElement('div');

contents.appendChild(separator);
const description = document.createElement('div');
description.className = 'cm-signature-help-panel-description';
description.appendChild(document.createTextNode(doc));
contents.appendChild(description);
if (currentParamDescription !== undefined) {
const argDescription = document.createElement('div');
argDescription.className = 'cm-signature-help-panel-arg-description';
argDescription.appendChild(document.createTextNode(currentParamDescription));
contents.appendChild(argDescription);
}
const methodDescription = document.createElement('div');
methodDescription.className = 'cm-signature-help-panel-description';
methodDescription.appendChild(document.createTextNode(doc));
contents.appendChild(methodDescription);
return { dom };

@@ -53,0 +68,0 @@ };

@@ -5,5 +5,3 @@ import { linter } from '@codemirror/lint';

import workerpool from 'workerpool';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore ignore: https://v3.vitejs.dev/guide/features.html#import-with-query-suffixes
import WorkerURL from './lintWorker?url&worker';
import WorkerURL from './lintWorker?worker&url';
const pool = workerpool.pool(WorkerURL, {

@@ -41,4 +39,3 @@ minWorkers: 2,

const statements = parse.statementsParsing;
const anySyntacticError = statements.filter((statement) => statement.diagnostics.length !== 0)
.length > 0;
const anySyntacticError = statements.some((statement) => statement.syntaxErrors.length !== 0);
if (anySyntacticError) {

@@ -45,0 +42,0 @@ return [];

import { tokens } from '@neo4j-ndl/base';
import { expect, test } from 'vitest';
import { tokens as tokensCopy } from './ndlTokensCopy';

@@ -3,0 +4,0 @@ /*

import { Extension } from '@codemirror/state';
export declare const basicNeo4jSetup: () => Extension[];
type SetupProps = {
moveFocusOnTab?: boolean;
};
export declare const basicNeo4jSetup: ({ moveFocusOnTab, }: SetupProps) => Extension[];
export {};

@@ -27,3 +27,3 @@ import { acceptCompletion, autocompletion, clearSnippet, closeBrackets, closeBracketsKeymap, closeCompletion, completionKeymap, nextSnippetField, prevSnippetField, snippetKeymap, } from '@codemirror/autocomplete';

};
export const basicNeo4jSetup = () => {
export const basicNeo4jSetup = ({ moveFocusOnTab = false, }) => {
const keymaps = [

@@ -37,18 +37,18 @@ closeBracketsKeymap,

lintKeymap,
{
].flat();
if (!moveFocusOnTab) {
keymaps.push({
key: 'Tab',
preventDefault: true,
run: acceptCompletion,
},
{
}, {
key: 'Tab',
preventDefault: true,
run: insertTab,
},
{
}, {
key: 'Shift-Tab',
preventDefault: true,
run: indentLess,
},
].flat();
});
}
const extensions = [];

@@ -55,0 +55,0 @@ extensions.push(highlightSpecialChars());

@@ -20,3 +20,3 @@ {

],
"version": "2.0.0-canary-cbfc75e",
"version": "2.0.0-canary-db9f594",
"main": "./dist/index.js",

@@ -29,3 +29,3 @@ "types": "./dist/index.d.ts",

"clean": "rm -rf dist",
"test": "jest",
"test": "vitest run",
"test:e2e": "playwright test -c playwright-ct.config.ts",

@@ -53,6 +53,6 @@ "test:e2e-ui": "playwright test -c playwright-ct.config.ts --ui",

"@codemirror/state": "^6.4.1",
"@codemirror/view": "^6.28.4",
"@codemirror/view": "^6.29.1",
"@lezer/common": "^1.0.2",
"@lezer/highlight": "^1.1.3",
"@neo4j-cypher/language-support": "2.0.0-canary-cbfc75e",
"@neo4j-cypher/language-support": "2.0.0-canary-db9f594",
"@types/prismjs": "^1.26.3",

@@ -69,13 +69,15 @@ "@types/workerpool": "^6.4.7",

"@neo4j-ndl/base": "^1.10.1",
"@playwright/experimental-ct-react": "^1.39.0",
"@playwright/test": "^1.36.2",
"@playwright/experimental-ct-react": "^1.45.3",
"@playwright/test": "^1.45.3",
"@types/lodash.debounce": "^4.0.9",
"@types/react": "^18.0.28",
"@vitejs/plugin-react": "^3.1.0",
"@vitejs/plugin-react": "^4.3.1",
"concurrently": "^8.2.1",
"esbuild": "^0.19.4",
"jsdom": "^24.1.1",
"lodash": "^4.17.21",
"playwright": "^1.36.2",
"playwright": "^1.45.3",
"react": "^18.2.0",
"typescript": "^4.9.5"
"typescript": "^4.9.5",
"vite": "^5.3.5"
},

@@ -82,0 +84,0 @@ "peerDependencies": {

@@ -1,7 +0,4 @@

export {
CypherParser,
_internalFeatureFlags,
} from '@neo4j-cypher/language-support';
export * as LanguageSupport from '@neo4j-cypher/language-support';
export { CypherEditor } from './CypherEditor';
export { cypher } from './lang-cypher/langCypher';
export { darkThemeConstants, lightThemeConstants } from './themes';

@@ -60,6 +60,6 @@ import {

(config) => (context) => {
const textUntilCursor = context.state.doc.toString().slice(0, context.pos);
const documentText = context.state.doc.toString();
const triggerCharacters = ['.', ':', '{', '$', ')'];
const lastCharacter = textUntilCursor.slice(-1);
const lastCharacter = documentText.at(context.pos - 1);

@@ -81,69 +81,51 @@ const lastWord = context.matchBefore(/\w*/);

const options = autocomplete(
textUntilCursor,
documentText,
config.schema ?? {},
undefined,
context.pos,
context.explicit,
);
if (config.featureFlags.signatureInfoOnAutoCompletions) {
return {
from: context.matchBefore(/(\w|\$)*$/).from,
options: options.map((o) => {
let maybeInfo = {};
let emptyInfo = true;
const newDiv = document.createElement('div');
return {
from: context.matchBefore(/(\w|\$)*$/).from,
options: options.map((o) => {
let maybeInfo = {};
let emptyInfo = true;
const newDiv = document.createElement('div');
if (o.signature) {
const header = document.createElement('p');
header.setAttribute('class', 'cm-completionInfo-signature');
header.textContent = o.signature;
if (header.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(header);
}
if (o.signature) {
const header = document.createElement('p');
header.setAttribute('class', 'cm-completionInfo-signature');
header.textContent = o.signature;
if (header.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(header);
}
}
if (o.documentation) {
const paragraph = document.createElement('p');
paragraph.textContent = getDocString(o.documentation);
if (paragraph.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(paragraph);
}
if (o.documentation) {
const paragraph = document.createElement('p');
paragraph.textContent = getDocString(o.documentation);
if (paragraph.textContent.length > 0) {
emptyInfo = false;
newDiv.appendChild(paragraph);
}
}
if (!emptyInfo) {
maybeInfo = {
info: () => Promise.resolve(newDiv),
};
}
const deprecated =
o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ??
false;
// The negative boost moves the deprecation down the list
// so we offer the user the completions that are
// deprecated the last
const maybeDeprecated = deprecated
? { boost: -99, deprecated: true }
: {};
if (!emptyInfo) {
maybeInfo = {
info: () => Promise.resolve(newDiv),
};
}
const deprecated =
o.tags?.find((tag) => tag === CompletionItemTag.Deprecated) ?? false;
// The negative boost moves the deprecation down the list
// so we offer the user the completions that are
// deprecated the last
const maybeDeprecated = deprecated
? { boost: -99, deprecated: true }
: {};
return {
label: o.label,
type: completionKindToCodemirrorIcon(o.kind),
apply:
o.kind === CompletionItemKind.Snippet
? // codemirror requires an empty snippet space to be able to tab out of the completion
snippet((o.insertText ?? o.label) + '${}')
: undefined,
detail: o.detail,
...maybeDeprecated,
...maybeInfo,
};
}),
};
} else {
return {
from: context.matchBefore(/(\w|\$)*$/).from,
options: options.map((o) => ({
label: o.label,
return {
label: o.insertText ? o.insertText : o.label,
displayLabel: o.label,
type: completionKindToCodemirrorIcon(o.kind),

@@ -156,5 +138,7 @@ apply:

detail: o.detail,
})),
};
}
...maybeDeprecated,
...maybeInfo,
};
}),
};
};

@@ -6,2 +6,3 @@ import { tags } from '@lezer/highlight';

} from '@neo4j-cypher/language-support';
import { expect, test } from 'vitest';
import { tokenTypeToStyleTag } from './constants';

@@ -8,0 +9,0 @@

@@ -124,2 +124,5 @@ import {

},
'& .cm-signature-help-panel-arg-description': {
padding: '5px',
},
'& .cm-signature-help-panel-description': {

@@ -126,0 +129,0 @@ padding: '5px',

@@ -25,3 +25,2 @@ import { autocompletion } from '@codemirror/autocomplete';

featureFlags?: {
signatureInfoOnAutoCompletions?: boolean;
consoleCommands?: boolean;

@@ -28,0 +27,0 @@ };

import { EditorState, StateField } from '@codemirror/state';
import { showTooltip, Tooltip } from '@codemirror/view';
import { signatureHelp } from '@neo4j-cypher/language-support';
import { SignatureInformation } from 'vscode-languageserver-types';
import {
MarkupContent,
SignatureInformation,
} from 'vscode-languageserver-types';
import { CypherConfig } from './langCypher';

@@ -41,8 +44,11 @@ import { getDocString } from './utils';

signatureLabel.className = 'cm-signature-help-panel-name';
signatureLabel.appendChild(document.createTextNode(`${signature.label}(`));
const methodName = signature.label.slice(0, signature.label.indexOf('('));
const returnType = signature.label.slice(signature.label.indexOf(')') + 1);
signatureLabel.appendChild(document.createTextNode(`${methodName}(`));
let currentParamDescription: string | undefined = undefined;
parameters.forEach((param, index) => {
if (typeof param.documentation === 'string') {
if (typeof param.label === 'string') {
const span = document.createElement('span');
span.appendChild(document.createTextNode(param.documentation));
span.appendChild(document.createTextNode(param.label));
if (index !== parameters.length - 1) {

@@ -54,2 +60,6 @@ span.appendChild(document.createTextNode(', '));

span.className = 'cm-signature-help-panel-current-argument';
const paramDoc = param.documentation;
currentParamDescription = MarkupContent.is(paramDoc)
? paramDoc.value
: paramDoc;
}

@@ -61,2 +71,3 @@ signatureLabel.appendChild(span);

signatureLabel.appendChild(document.createTextNode(')'));
signatureLabel.appendChild(document.createTextNode(returnType));

@@ -70,8 +81,15 @@ contents.appendChild(signatureLabel);

const description = document.createElement('div');
description.className = 'cm-signature-help-panel-description';
description.appendChild(document.createTextNode(doc));
if (currentParamDescription !== undefined) {
const argDescription = document.createElement('div');
argDescription.className = 'cm-signature-help-panel-arg-description';
argDescription.appendChild(
document.createTextNode(currentParamDescription),
);
contents.appendChild(argDescription);
}
const methodDescription = document.createElement('div');
methodDescription.className = 'cm-signature-help-panel-description';
methodDescription.appendChild(document.createTextNode(doc));
contents.appendChild(methodDescription);
contents.appendChild(description);
return { dom };

@@ -78,0 +96,0 @@ };

@@ -8,8 +8,5 @@ import { Diagnostic, linter } from '@codemirror/lint';

import type { LinterTask, LintWorker } from './lintWorker';
import WorkerURL from './lintWorker?worker&url';
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
// @ts-ignore ignore: https://v3.vitejs.dev/guide/features.html#import-with-query-suffixes
import WorkerURL from './lintWorker?url&worker';
const pool = workerpool.pool(WorkerURL as string, {
const pool = workerpool.pool(WorkerURL, {
minWorkers: 2,

@@ -61,5 +58,5 @@ workerOpts: { type: 'module' },

const anySyntacticError =
statements.filter((statement) => statement.diagnostics.length !== 0)
.length > 0;
const anySyntacticError = statements.some(
(statement) => statement.syntaxErrors.length !== 0,
);

@@ -66,0 +63,0 @@ if (anySyntacticError) {

import { tokens } from '@neo4j-ndl/base';
import { expect, test } from 'vitest';
import { tokens as tokensCopy } from './ndlTokensCopy';

@@ -3,0 +4,0 @@

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc