New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

@neo4j-cypher/react-codemirror

Package Overview
Dependencies
Maintainers
2
Versions
149
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-d329252 to 2.0.0-canary-d7e0e1a

dist/e2e_tests/helpers.spec.d.ts

9

CHANGELOG.md
# @neo4j-cypher/react-codemirror
## 2.0.0-next.16
### Patch Changes
- Updated dependencies [84a12fc]
- Updated dependencies [d329252]
- Updated dependencies [b0e419e]
- @neo4j-cypher/language-support@2.0.0-next.13
## 2.0.0-next.15

@@ -4,0 +13,0 @@

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

});
test('can complete YIELD clauses without manual trigger', async ({ page, mount }) => {
const component = await mount(_jsx(CypherEditor, { schema: {
procedures: testData.mockSchema.procedures,
} }));
const textField = page.getByRole('textbox');
await textField.fill('CALL dbms.components() YIELD ');
await page.locator('.cm-tooltip-autocomplete').getByText('edition').click();
await expect(page.locator('.cm-tooltip-autocomplete')).not.toBeVisible();
await expect(component).toContainText('CALL dbms.components() YIELD edition');
});
test('automatic yield trigger is not case sensitive', async ({ page, mount }) => {
const component = await mount(_jsx(CypherEditor, { schema: {
procedures: testData.mockSchema.procedures,
} }));
const textField = page.getByRole('textbox');
await textField.fill('CALL dbms.components() yIeLd ');
await page.locator('.cm-tooltip-autocomplete').getByText('edition').click();
await expect(page.locator('.cm-tooltip-autocomplete')).not.toBeVisible();
await expect(component).toContainText('CALL dbms.components() yIeLd edition');
});
test('can complete functions', async ({ page, mount }) => {

@@ -110,0 +130,0 @@ const component = await mount(_jsx(CypherEditor, { schema: {

3

dist/e2e_tests/debounce.spec.js

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

});
test('onExecute updates should override debounce updates', async ({ mount, page, }) => {
// TODO Fix this test
test.fixme('onExecute updates should override debounce updates', async ({ mount, page }) => {
const editorPage = new CypherEditorPage(page);

@@ -24,0 +25,0 @@ let value = '';

@@ -11,3 +11,4 @@ import type { Locator, Page } from 'playwright/test';

checkWarningMessage(queryChunk: string, expectedMsg: string): Promise<void>;
checkNoNotificationMessage(type: 'error' | 'warning'): Promise<void>;
private checkNotificationMessage;
}

@@ -45,2 +45,11 @@ import { expect } from '@playwright/experimental-ct-react';

}
async checkNoNotificationMessage(type) {
await this.page.waitForTimeout(3000);
await expect(this.page.locator('.cm-lintRange-' + type)).toHaveCount(0, {
timeout: 3000,
});
await expect(this.page.locator('.cm-lintPoint-' + type)).toHaveCount(0, {
timeout: 3000,
});
}
async checkNotificationMessage(type, queryChunk, expectedMsg) {

@@ -47,0 +56,0 @@ await expect(this.page.locator('.cm-lintRange-' + type).last()).toBeVisible({ timeout: 3000 });

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

await expect(component).toContainText('MATCH (n:Person) RETRN m');
await editorPage.checkErrorMessage('RETRN', 'Unexpected token. Did you mean RETURN?');
await editorPage.checkErrorMessage('RETRN', `Invalid input 'RETRN': expected a graph pattern, 'FOREACH', ',', 'ORDER BY', 'CALL', 'CREATE', 'LOAD CSV', 'DELETE', 'DETACH', 'FINISH', 'INSERT', 'LIMIT', 'MATCH', 'MERGE', 'NODETACH', 'OFFSET', 'OPTIONAL', 'REMOVE', 'RETURN', 'SET', 'SKIP', 'UNION', 'UNWIND', 'USE', 'USING', 'WHERE', 'WITH' or <EOF>`);
await editorPage

@@ -53,0 +53,0 @@ .getEditor()

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

await editorPage.getEditor().fill('METCH (n) RETURN n');
await editorPage.checkErrorMessage('METCH', 'Unrecognized keyword. Did you mean MATCH?');
await editorPage.checkErrorMessage('METCH', `Invalid input 'METCH': expected 'FOREACH', 'ALTER', 'ORDER BY', 'CALL', 'USING PERIODIC COMMIT', 'CREATE', 'LOAD CSV', 'START DATABASE', 'STOP DATABASE', 'DEALLOCATE', 'DELETE', 'DENY', 'DETACH', 'DROP', 'DRYRUN', 'FINISH', 'GRANT', 'INSERT', 'LIMIT', 'MATCH', 'MERGE', 'NODETACH', 'OFFSET', 'OPTIONAL', 'REALLOCATE', 'REMOVE', 'RENAME', 'RETURN', 'REVOKE', 'ENABLE SERVER', 'SET', 'SHOW', 'SKIP', 'TERMINATE', 'UNWIND', 'USE' or 'WITH'`);
});

@@ -30,4 +30,10 @@ test('Syntactic errors are surfaced', async ({ page, mount }) => {

await mount(_jsx(CypherEditor, { value: query }));
await editorPage.checkErrorMessage('METCH', 'Unrecognized keyword. Did you mean MATCH?');
await editorPage.checkErrorMessage('METCH', `Invalid input 'METCH': expected 'FOREACH', 'ALTER', 'ORDER BY', 'CALL', 'USING PERIODIC COMMIT', 'CREATE', 'LOAD CSV', 'START DATABASE', 'STOP DATABASE', 'DEALLOCATE', 'DELETE', 'DENY', 'DETACH', 'DROP', 'DRYRUN', 'FINISH', 'GRANT', 'INSERT', 'LIMIT', 'MATCH', 'MERGE', 'NODETACH', 'OFFSET', 'OPTIONAL', 'REALLOCATE', 'REMOVE', 'RENAME', 'RETURN', 'REVOKE', 'ENABLE SERVER', 'SET', 'SHOW', 'SKIP', 'TERMINATE', 'UNWIND', 'USE' or 'WITH'`);
});
test('Does not trigger syntax errors for backticked parameters in parameter creation', async ({ page, mount, }) => {
const editorPage = new CypherEditorPage(page);
const query = ':param x => "abc"';
await mount(_jsx(CypherEditor, { value: query }));
await editorPage.checkNoNotificationMessage('error');
});
test('Errors for undefined labels are surfaced', async ({ page, mount }) => {

@@ -89,3 +95,3 @@ const editorPage = new CypherEditorPage(page);

});
test('Strikethroughs are shown for deprecated functions', async ({ page, mount }) => {
test('Strikethroughs are shown for deprecated functions', async ({ page, mount, }) => {
const editorPage = new CypherEditorPage(page);

@@ -95,5 +101,5 @@ const query = `RETURN id()`;

await expect(editorPage.page.locator('.cm-deprecated-element').last()).toBeVisible({ timeout: 3000 });
await editorPage.checkWarningMessage('id', "Function id is deprecated.");
await editorPage.checkWarningMessage('id', 'Function id is deprecated.');
});
test('Strikethroughs are shown for deprecated procedures', async ({ page, mount }) => {
test('Strikethroughs are shown for deprecated procedures', async ({ page, mount, }) => {
const editorPage = new CypherEditorPage(page);

@@ -103,4 +109,4 @@ const query = `CALL apoc.create.uuids()`;

await expect(editorPage.page.locator('.cm-deprecated-element').last()).toBeVisible({ timeout: 3000 });
await editorPage.checkWarningMessage('apoc.create.uuids', "Procedure apoc.create.uuids is deprecated.");
await editorPage.checkWarningMessage('apoc.create.uuids', 'Procedure apoc.create.uuids is deprecated.');
});
//# sourceMappingURL=syntaxValidation.spec.js.map
import { snippet, } from '@codemirror/autocomplete';
import { autocomplete } from '@neo4j-cypher/language-support';
import { autocomplete, shouldAutoCompleteYield, } from '@neo4j-cypher/language-support';
import { CompletionItemKind, CompletionItemTag, } from 'vscode-languageserver-types';

@@ -46,7 +46,12 @@ import { getDocString } from './utils';

const documentText = context.state.doc.toString();
const offset = context.pos;
const triggerCharacters = ['.', ':', '{', '$', ')'];
const lastCharacter = documentText.at(context.pos - 1);
const lastCharacter = documentText.at(offset - 1);
const yieldTriggered = shouldAutoCompleteYield(documentText, offset);
const lastWord = context.matchBefore(/\w*/);
const inWord = lastWord.from !== lastWord.to;
const shouldTriggerCompletion = inWord || context.explicit || triggerCharacters.includes(lastCharacter);
const shouldTriggerCompletion = inWord ||
context.explicit ||
triggerCharacters.includes(lastCharacter) ||
yieldTriggered;
if (config.useLightVersion && !context.explicit) {

@@ -60,3 +65,3 @@ return null;

// TODO This is a temporary hack because completions are not working well
documentText.slice(0, context.pos), config.schema ?? {}, context.pos, context.explicit);
documentText.slice(0, offset), config.schema ?? {}, offset, context.explicit);
return {

@@ -63,0 +68,0 @@ from: context.matchBefore(/(\w|\$)*$/).from,

@@ -35,2 +35,4 @@ import type { Facet } from '@codemirror/state';

number: NodeType;
setting: NodeType;
settingValue: NodeType;
};

@@ -37,0 +39,0 @@ export type PrismSpecificTokenType = 'class-name' | 'identifier' | 'string' | 'relationship' | 'boolean' | 'number';

@@ -40,2 +40,4 @@ import { languageDataProp } from '@codemirror/language';

number: NodeType.define({ id: 28, name: 'numberLiteral' }),
setting: NodeType.define({ id: 29, name: 'setting' }),
settingValue: NodeType.define({ id: 30, name: 'settingValue' }),
});

@@ -64,4 +66,6 @@ export const tokenTypeToStyleTag = {

consoleCommand: tags.macroName,
setting: tags.attributeName,
settingValue: tags.attributeValue,
};
export const parserAdapterNodeSet = (nodes) => new NodeSet(Object.values(nodes)).extend(styleTags(tokenTypeToStyleTag));
//# sourceMappingURL=constants.js.map
import { autocompletion } from '@codemirror/autocomplete';
import { defineLanguageFacet, Language, LanguageSupport, } from '@codemirror/language';
import { _internalFeatureFlags, } from '@neo4j-cypher/language-support';
import { completionStyles, cypherAutocomplete } from './autocomplete';
import { ParserAdapter } from './parser-adapter';
import { signatureHelpTooltip } from './signatureHelp';
import { cypherLinter, semanticAnalysisLinter } from './syntaxValidation';
import { cypherLinter } from './syntaxValidation';
const facet = defineLanguageFacet({

@@ -13,7 +12,2 @@ commentTokens: { block: { open: '/*', close: '*/' }, line: '//' },

export function cypher(config) {
const featureFlags = config.featureFlags;
// We allow to override the consoleCommands feature flag
if (featureFlags.consoleCommands !== undefined) {
_internalFeatureFlags.consoleCommands = featureFlags.consoleCommands;
}
const parserAdapter = new ParserAdapter(facet, config);

@@ -27,3 +21,2 @@ const cypherLanguage = new Language(facet, parserAdapter, [], 'cypher');

cypherLinter(config),
semanticAnalysisLinter(config),
signatureHelpTooltip(config),

@@ -30,0 +23,0 @@ ]);

@@ -1,8 +0,11 @@

import { validateSemantics } from '@neo4j-cypher/language-support';
import { DbSchema } from '@neo4j-cypher/language-support';
import workerpool from 'workerpool';
type LinterArgs = Parameters<typeof validateSemantics>;
export type LinterTask = workerpool.Promise<ReturnType<typeof validateSemantics>>;
declare function lintCypherQuery(query: string, dbSchema: DbSchema, featureFlags?: {
consoleCommands?: boolean;
}): import("@neo4j-cypher/language-support").SyntaxDiagnostic[];
type LinterArgs = Parameters<typeof lintCypherQuery>;
export type LinterTask = workerpool.Promise<ReturnType<typeof lintCypherQuery>>;
export type LintWorker = {
validateSemantics: (...args: LinterArgs) => LinterTask;
lintCypherQuery: (...args: LinterArgs) => LinterTask;
};
export {};

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

import { validateSemantics } from '@neo4j-cypher/language-support';
import { lintCypherQuery as _lintCypherQuery, _internalFeatureFlags, } from '@neo4j-cypher/language-support';
import workerpool from 'workerpool';
workerpool.worker({ validateSemantics });
function lintCypherQuery(query, dbSchema, featureFlags = {}) {
// We allow to override the consoleCommands feature flag
if (featureFlags.consoleCommands !== undefined) {
_internalFeatureFlags.consoleCommands = featureFlags.consoleCommands;
}
return _lintCypherQuery(query, dbSchema);
}
workerpool.worker({ lintCypherQuery });
//# sourceMappingURL=lintWorker.js.map
import { Extension } from '@codemirror/state';
import type { CypherConfig } from './langCypher';
export declare const cypherLinter: (config: CypherConfig) => Extension;
export declare const semanticAnalysisLinter: (config: CypherConfig) => Extension;
export declare const cleanupWorkers: () => void;
import { linter } from '@codemirror/lint';
import { parserWrapper, validateSyntax } from '@neo4j-cypher/language-support';
import { DiagnosticSeverity, DiagnosticTag } from 'vscode-languageserver-types';

@@ -12,3 +11,3 @@ import workerpool from 'workerpool';

let lastSemanticJob;
export const cypherLinter = (config) => linter((view) => {
export const cypherLinter = (config) => linter(async (view) => {
if (!config.lint) {

@@ -18,27 +17,5 @@ return [];

const query = view.state.doc.toString();
const syntaxErrors = validateSyntax(query, config.schema ?? {});
return syntaxErrors.map((diagnostic) => ({
from: diagnostic.offsets.start,
to: diagnostic.offsets.end,
severity: diagnostic.severity === DiagnosticSeverity.Error
? 'error'
: 'warning',
message: diagnostic.message,
}));
});
export const semanticAnalysisLinter = (config) => linter(async (view) => {
if (!config.lint) {
return [];
}
const query = view.state.doc.toString();
if (query.length === 0) {
return [];
}
// we want to avoid the ANTLR4 reparse in the worker thread, this should hit our main thread cache
const parse = parserWrapper.parse(query);
const statements = parse.statementsParsing;
const anySyntacticError = statements.some((statement) => statement.syntaxErrors.length !== 0);
if (anySyntacticError) {
return [];
}
try {

@@ -49,3 +26,3 @@ if (lastSemanticJob !== undefined && !lastSemanticJob.resolved) {

const proxyWorker = (await pool.proxy());
lastSemanticJob = proxyWorker.validateSemantics(query, config.schema ?? {});
lastSemanticJob = proxyWorker.lintCypherQuery(query, config.schema ?? {}, config.featureFlags ?? {});
const result = await lastSemanticJob;

@@ -52,0 +29,0 @@ const a = result.map((diagnostic) => {

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

],
"version": "2.0.0-canary-d329252",
"version": "2.0.0-canary-d7e0e1a",
"main": "./dist/index.js",

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

"@lezer/highlight": "^1.1.3",
"@neo4j-cypher/language-support": "2.0.0-canary-d329252",
"@neo4j-cypher/language-support": "2.0.0-canary-d7e0e1a",
"@types/prismjs": "^1.26.3",

@@ -58,0 +58,0 @@ "@types/workerpool": "^6.4.7",

@@ -62,2 +62,12 @@ import { expect } from '@playwright/experimental-ct-react';

async checkNoNotificationMessage(type: 'error' | 'warning') {
await this.page.waitForTimeout(3000);
await expect(this.page.locator('.cm-lintRange-' + type)).toHaveCount(0, {
timeout: 3000,
});
await expect(this.page.locator('.cm-lintPoint-' + type)).toHaveCount(0, {
timeout: 3000,
});
}
private async checkNotificationMessage(

@@ -64,0 +74,0 @@ type: 'error' | 'warning',

@@ -6,4 +6,7 @@ import {

} from '@codemirror/autocomplete';
import { autocomplete } from '@neo4j-cypher/language-support';
import {
autocomplete,
shouldAutoCompleteYield,
} from '@neo4j-cypher/language-support';
import {
CompletionItemKind,

@@ -62,6 +65,6 @@ CompletionItemTag,

const documentText = context.state.doc.toString();
const offset = context.pos;
const triggerCharacters = ['.', ':', '{', '$', ')'];
const lastCharacter = documentText.at(context.pos - 1);
const lastCharacter = documentText.at(offset - 1);
const yieldTriggered = shouldAutoCompleteYield(documentText, offset);
const lastWord = context.matchBefore(/\w*/);

@@ -71,3 +74,6 @@ const inWord = lastWord.from !== lastWord.to;

const shouldTriggerCompletion =
inWord || context.explicit || triggerCharacters.includes(lastCharacter);
inWord ||
context.explicit ||
triggerCharacters.includes(lastCharacter) ||
yieldTriggered;

@@ -84,5 +90,5 @@ if (config.useLightVersion && !context.explicit) {

// TODO This is a temporary hack because completions are not working well
documentText.slice(0, context.pos),
documentText.slice(0, offset),
config.schema ?? {},
context.pos,
offset,
context.explicit,

@@ -89,0 +95,0 @@ );

@@ -43,2 +43,4 @@ import { languageDataProp } from '@codemirror/language';

number: NodeType.define({ id: 28, name: 'numberLiteral' }),
setting: NodeType.define({ id: 29, name: 'setting' }),
settingValue: NodeType.define({ id: 30, name: 'settingValue' }),
});

@@ -82,2 +84,4 @@

consoleCommand: tags.macroName,
setting: tags.attributeName,
settingValue: tags.attributeValue,
};

@@ -84,0 +88,0 @@

@@ -7,10 +7,7 @@ import { autocompletion } from '@codemirror/autocomplete';

} from '@codemirror/language';
import {
_internalFeatureFlags,
type DbSchema,
} from '@neo4j-cypher/language-support';
import { type DbSchema } from '@neo4j-cypher/language-support';
import { completionStyles, cypherAutocomplete } from './autocomplete';
import { ParserAdapter } from './parser-adapter';
import { signatureHelpTooltip } from './signatureHelp';
import { cypherLinter, semanticAnalysisLinter } from './syntaxValidation';
import { cypherLinter } from './syntaxValidation';

@@ -34,8 +31,2 @@ const facet = defineLanguageFacet({

export function cypher(config: CypherConfig) {
const featureFlags = config.featureFlags;
// We allow to override the consoleCommands feature flag
if (featureFlags.consoleCommands !== undefined) {
_internalFeatureFlags.consoleCommands = featureFlags.consoleCommands;
}
const parserAdapter = new ParserAdapter(facet, config);

@@ -51,5 +42,4 @@

cypherLinter(config),
semanticAnalysisLinter(config),
signatureHelpTooltip(config),
]);
}

@@ -1,14 +0,28 @@

import { validateSemantics } from '@neo4j-cypher/language-support';
import {
DbSchema,
lintCypherQuery as _lintCypherQuery,
_internalFeatureFlags,
} from '@neo4j-cypher/language-support';
import workerpool from 'workerpool';
workerpool.worker({ validateSemantics });
function lintCypherQuery(
query: string,
dbSchema: DbSchema,
featureFlags: { consoleCommands?: boolean } = {},
) {
// We allow to override the consoleCommands feature flag
if (featureFlags.consoleCommands !== undefined) {
_internalFeatureFlags.consoleCommands = featureFlags.consoleCommands;
}
return _lintCypherQuery(query, dbSchema);
}
type LinterArgs = Parameters<typeof validateSemantics>;
workerpool.worker({ lintCypherQuery });
export type LinterTask = workerpool.Promise<
ReturnType<typeof validateSemantics>
>;
type LinterArgs = Parameters<typeof lintCypherQuery>;
export type LinterTask = workerpool.Promise<ReturnType<typeof lintCypherQuery>>;
export type LintWorker = {
validateSemantics: (...args: LinterArgs) => LinterTask;
lintCypherQuery: (...args: LinterArgs) => LinterTask;
};
import { Diagnostic, linter } from '@codemirror/lint';
import { Extension } from '@codemirror/state';
import { parserWrapper, validateSyntax } from '@neo4j-cypher/language-support';
import { DiagnosticSeverity, DiagnosticTag } from 'vscode-languageserver-types';

@@ -19,26 +18,2 @@ import workerpool from 'workerpool';

export const cypherLinter: (config: CypherConfig) => Extension = (config) =>
linter((view) => {
if (!config.lint) {
return [];
}
const query = view.state.doc.toString();
const syntaxErrors = validateSyntax(query, config.schema ?? {});
return syntaxErrors.map(
(diagnostic): Diagnostic => ({
from: diagnostic.offsets.start,
to: diagnostic.offsets.end,
severity:
diagnostic.severity === DiagnosticSeverity.Error
? 'error'
: 'warning',
message: diagnostic.message,
}),
);
});
export const semanticAnalysisLinter: (config: CypherConfig) => Extension = (
config,
) =>
linter(async (view) => {

@@ -48,3 +23,2 @@ if (!config.lint) {

}
const query = view.state.doc.toString();

@@ -55,14 +29,2 @@ if (query.length === 0) {

// we want to avoid the ANTLR4 reparse in the worker thread, this should hit our main thread cache
const parse = parserWrapper.parse(query);
const statements = parse.statementsParsing;
const anySyntacticError = statements.some(
(statement) => statement.syntaxErrors.length !== 0,
);
if (anySyntacticError) {
return [];
}
try {

@@ -74,5 +36,6 @@ if (lastSemanticJob !== undefined && !lastSemanticJob.resolved) {

const proxyWorker = (await pool.proxy()) as unknown as LintWorker;
lastSemanticJob = proxyWorker.validateSemantics(
lastSemanticJob = proxyWorker.lintCypherQuery(
query,
config.schema ?? {},
config.featureFlags ?? {},
);

@@ -79,0 +42,0 @@ const result = await lastSemanticJob;

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