@neo4j-cypher/react-codemirror 2.0.0-alpha.0 → 2.0.0-next.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +7 -0
- package/LICENSE.md +201 -0
- package/README.md +24 -4
- package/dist/{index.cjs → cjs/index.cjs} +187 -62
- package/dist/cjs/index.cjs.map +7 -0
- package/{esm → dist/esm}/index.mjs +196 -64
- package/dist/esm/index.mjs.map +7 -0
- package/dist/types/CypherEditor.d.ts +118 -0
- package/dist/types/e2e_tests/auto-completion.spec.d.ts +1 -0
- package/dist/types/e2e_tests/e2e-utils.d.ts +12 -0
- package/dist/types/e2e_tests/extra-keybindings.spec.d.ts +1 -0
- package/dist/types/e2e_tests/history-navigation.spec.d.ts +1 -0
- package/dist/types/e2e_tests/mock-data.d.ts +3779 -0
- package/dist/types/e2e_tests/performance-test.spec.d.ts +1 -0
- package/dist/types/e2e_tests/sanity-checks.spec.d.ts +1 -0
- package/dist/types/e2e_tests/syntax-highlighting.spec.d.ts +1 -0
- package/dist/types/e2e_tests/syntax-validation.spec.d.ts +1 -0
- package/dist/types/icons.d.ts +2 -0
- package/dist/types/index.d.ts +5 -0
- package/dist/types/lang-cypher/ParserAdapter.d.ts +14 -0
- package/dist/types/lang-cypher/autocomplete.d.ts +3 -0
- package/dist/types/lang-cypher/constants.d.ts +31 -0
- package/dist/types/lang-cypher/contants.test.d.ts +1 -0
- package/dist/types/lang-cypher/create-cypher-theme.d.ts +26 -0
- package/dist/types/lang-cypher/lang-cypher.d.ts +7 -0
- package/dist/types/lang-cypher/syntax-validation.d.ts +3 -0
- package/dist/types/lang-cypher/theme-icons.d.ts +7 -0
- package/dist/types/ndl-tokens-copy.d.ts +379 -0
- package/dist/types/ndl-tokens-copy.test.d.ts +1 -0
- package/dist/types/neo4j-setup.d.ts +2 -0
- package/dist/types/repl-mode.d.ts +8 -0
- package/dist/types/themes.d.ts +11 -0
- package/dist/types/tsconfig.tsbuildinfo +1 -0
- package/package.json +48 -15
- package/src/CypherEditor.tsx +316 -0
- package/src/e2e_tests/auto-completion.spec.tsx +232 -0
- package/src/e2e_tests/e2e-utils.ts +75 -0
- package/src/e2e_tests/extra-keybindings.spec.tsx +57 -0
- package/src/e2e_tests/history-navigation.spec.tsx +144 -0
- package/src/e2e_tests/mock-data.ts +4310 -0
- package/src/e2e_tests/performance-test.spec.tsx +71 -0
- package/src/e2e_tests/sanity-checks.spec.tsx +87 -0
- package/src/e2e_tests/syntax-highlighting.spec.tsx +198 -0
- package/src/e2e_tests/syntax-validation.spec.tsx +157 -0
- package/src/icons.ts +87 -0
- package/src/index.ts +5 -0
- package/src/lang-cypher/ParserAdapter.ts +92 -0
- package/src/lang-cypher/autocomplete.ts +65 -0
- package/src/lang-cypher/constants.ts +61 -0
- package/src/lang-cypher/contants.test.ts +104 -0
- package/src/lang-cypher/create-cypher-theme.ts +207 -0
- package/src/lang-cypher/lang-cypher.ts +32 -0
- package/src/lang-cypher/syntax-validation.ts +24 -0
- package/src/lang-cypher/theme-icons.ts +27 -0
- package/src/ndl-tokens-copy.test.ts +11 -0
- package/src/ndl-tokens-copy.ts +379 -0
- package/src/neo4j-setup.tsx +129 -0
- package/src/repl-mode.ts +214 -0
- package/src/themes.ts +130 -0
|
@@ -3,9 +3,17 @@ import { CypherParser, parse } from "@neo4j-cypher/language-support";
|
|
|
3
3
|
import * as ReactCodemirror from "@uiw/react-codemirror";
|
|
4
4
|
|
|
5
5
|
// src/CypherEditor.tsx
|
|
6
|
-
import {
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
import {
|
|
7
|
+
Annotation,
|
|
8
|
+
Compartment,
|
|
9
|
+
EditorState as EditorState2
|
|
10
|
+
} from "@codemirror/state";
|
|
11
|
+
import {
|
|
12
|
+
EditorView as EditorView4,
|
|
13
|
+
keymap as keymap3,
|
|
14
|
+
lineNumbers
|
|
15
|
+
} from "@codemirror/view";
|
|
16
|
+
import { Component, createRef } from "react";
|
|
9
17
|
|
|
10
18
|
// src/lang-cypher/lang-cypher.ts
|
|
11
19
|
import {
|
|
@@ -47,8 +55,7 @@ var completionKindToCodemirrorIcon = (c) => {
|
|
|
47
55
|
};
|
|
48
56
|
return map[c];
|
|
49
57
|
};
|
|
50
|
-
var
|
|
51
|
-
var cypherAutocomplete = (schema) => (context) => {
|
|
58
|
+
var cypherAutocomplete = (config) => (context) => {
|
|
52
59
|
const textUntilCursor = context.state.doc.toString().slice(0, context.pos);
|
|
53
60
|
const triggerCharacters = [".", ":", "{", "$"];
|
|
54
61
|
const lastCharacter = textUntilCursor.slice(-1);
|
|
@@ -58,7 +65,7 @@ var cypherAutocomplete = (schema) => (context) => {
|
|
|
58
65
|
if (!shouldTriggerCompletion) {
|
|
59
66
|
return null;
|
|
60
67
|
}
|
|
61
|
-
const options = autocomplete(textUntilCursor, schema ??
|
|
68
|
+
const options = autocomplete(textUntilCursor, config.schema ?? {});
|
|
62
69
|
return {
|
|
63
70
|
from: context.matchBefore(/(\w|\$)*$/).from,
|
|
64
71
|
options: options.map((o) => ({
|
|
@@ -202,17 +209,18 @@ var ParserAdapter = class extends Parser {
|
|
|
202
209
|
import { linter } from "@codemirror/lint";
|
|
203
210
|
import { validateSyntax } from "@neo4j-cypher/language-support";
|
|
204
211
|
import { DiagnosticSeverity } from "vscode-languageserver-types";
|
|
205
|
-
var cypherLinter = (
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
212
|
+
var cypherLinter = (config) => linter((view) => {
|
|
213
|
+
if (!config.lint) {
|
|
214
|
+
return [];
|
|
215
|
+
}
|
|
216
|
+
return validateSyntax(view.state.doc.toString(), config.schema).map(
|
|
217
|
+
(diagnostic) => ({
|
|
209
218
|
from: diagnostic.offsets.start,
|
|
210
219
|
to: diagnostic.offsets.end,
|
|
211
220
|
severity: diagnostic.severity === DiagnosticSeverity.Error ? "error" : "warning",
|
|
212
221
|
message: diagnostic.message
|
|
213
|
-
})
|
|
214
|
-
|
|
215
|
-
return diagnostics;
|
|
222
|
+
})
|
|
223
|
+
);
|
|
216
224
|
});
|
|
217
225
|
|
|
218
226
|
// src/lang-cypher/lang-cypher.ts
|
|
@@ -222,12 +230,12 @@ var facet = defineLanguageFacet({
|
|
|
222
230
|
});
|
|
223
231
|
var parserAdapter = new ParserAdapter(facet);
|
|
224
232
|
var cypherLanguage = new Language(facet, parserAdapter, [], "cypher");
|
|
225
|
-
function cypher(
|
|
233
|
+
function cypher(config) {
|
|
226
234
|
return new LanguageSupport(cypherLanguage, [
|
|
227
235
|
cypherLanguage.data.of({
|
|
228
|
-
autocomplete: cypherAutocomplete(
|
|
236
|
+
autocomplete: cypherAutocomplete(config)
|
|
229
237
|
}),
|
|
230
|
-
|
|
238
|
+
cypherLinter(config)
|
|
231
239
|
]);
|
|
232
240
|
}
|
|
233
241
|
|
|
@@ -262,7 +270,6 @@ import {
|
|
|
262
270
|
EditorView,
|
|
263
271
|
highlightSpecialChars,
|
|
264
272
|
keymap,
|
|
265
|
-
lineNumbers,
|
|
266
273
|
rectangularSelection
|
|
267
274
|
} from "@codemirror/view";
|
|
268
275
|
import { lintKeymap } from "@codemirror/lint";
|
|
@@ -346,7 +353,7 @@ var insertTab = (cmd) => {
|
|
|
346
353
|
}
|
|
347
354
|
return true;
|
|
348
355
|
};
|
|
349
|
-
var basicNeo4jSetup = (
|
|
356
|
+
var basicNeo4jSetup = () => {
|
|
350
357
|
const keymaps = [
|
|
351
358
|
closeBracketsKeymap,
|
|
352
359
|
defaultKeymap,
|
|
@@ -372,16 +379,6 @@ var basicNeo4jSetup = (prompt) => {
|
|
|
372
379
|
}
|
|
373
380
|
].flat();
|
|
374
381
|
const extensions = [];
|
|
375
|
-
extensions.push(
|
|
376
|
-
lineNumbers({
|
|
377
|
-
formatNumber(a, state) {
|
|
378
|
-
if (state.doc.lines === 1 && prompt !== void 0) {
|
|
379
|
-
return prompt;
|
|
380
|
-
}
|
|
381
|
-
return a.toString();
|
|
382
|
-
}
|
|
383
|
-
})
|
|
384
|
-
);
|
|
385
382
|
extensions.push(highlightSpecialChars());
|
|
386
383
|
extensions.push(history());
|
|
387
384
|
extensions.push(drawSelection());
|
|
@@ -396,6 +393,7 @@ var basicNeo4jSetup = (prompt) => {
|
|
|
396
393
|
extensions.push(
|
|
397
394
|
autocompletion({
|
|
398
395
|
icons: false,
|
|
396
|
+
interactionDelay: 5,
|
|
399
397
|
addToOptions: [
|
|
400
398
|
{
|
|
401
399
|
render(completion, state) {
|
|
@@ -538,8 +536,7 @@ var replMode = ({
|
|
|
538
536
|
onExecute?.(doc);
|
|
539
537
|
onNewHistoryEntry?.(doc);
|
|
540
538
|
view.dispatch({
|
|
541
|
-
effects: pushToHistory.of(doc)
|
|
542
|
-
changes: { from: 0, to: view.state.doc.length, insert: "" }
|
|
539
|
+
effects: pushToHistory.of(doc)
|
|
543
540
|
});
|
|
544
541
|
}
|
|
545
542
|
return true;
|
|
@@ -1286,45 +1283,179 @@ function getThemeExtension(theme, inheritBgColor) {
|
|
|
1286
1283
|
|
|
1287
1284
|
// src/CypherEditor.tsx
|
|
1288
1285
|
import { jsx } from "react/jsx-runtime";
|
|
1289
|
-
var
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1286
|
+
var themeCompartment = new Compartment();
|
|
1287
|
+
var keyBindingCompartment = new Compartment();
|
|
1288
|
+
var ExternalEdit = Annotation.define();
|
|
1289
|
+
var CypherEditor = class extends Component {
|
|
1290
|
+
/**
|
|
1291
|
+
* The codemirror editor container.
|
|
1292
|
+
*/
|
|
1293
|
+
editorContainer = createRef();
|
|
1294
|
+
/**
|
|
1295
|
+
* The codemirror editor state.
|
|
1296
|
+
*/
|
|
1297
|
+
editorState = createRef();
|
|
1298
|
+
/**
|
|
1299
|
+
* The codemirror editor view.
|
|
1300
|
+
*/
|
|
1301
|
+
editorView = createRef();
|
|
1302
|
+
schemaRef = createRef();
|
|
1303
|
+
/**
|
|
1304
|
+
* Focus the editor
|
|
1305
|
+
*/
|
|
1306
|
+
focus() {
|
|
1307
|
+
this.editorView.current?.focus();
|
|
1308
|
+
}
|
|
1309
|
+
/**
|
|
1310
|
+
* Move the cursor to the supplied position.
|
|
1311
|
+
* For example, to move the cursor to the end of the editor, use `value.length`
|
|
1312
|
+
*/
|
|
1313
|
+
updateCursorPosition(position) {
|
|
1314
|
+
this.editorView.current?.dispatch({
|
|
1315
|
+
selection: { anchor: position, head: position }
|
|
1316
|
+
});
|
|
1317
|
+
}
|
|
1318
|
+
/**
|
|
1319
|
+
* Externally set the editor value and focus the editor.
|
|
1320
|
+
*/
|
|
1321
|
+
setValueAndFocus(value = "") {
|
|
1322
|
+
const currentCmValue = this.editorView.current.state?.doc.toString() ?? "";
|
|
1323
|
+
this.editorView.current.dispatch({
|
|
1324
|
+
changes: {
|
|
1325
|
+
from: 0,
|
|
1326
|
+
to: currentCmValue.length,
|
|
1327
|
+
insert: value
|
|
1328
|
+
},
|
|
1329
|
+
selection: { anchor: value.length, head: value.length }
|
|
1330
|
+
});
|
|
1331
|
+
this.editorView.current?.focus();
|
|
1332
|
+
}
|
|
1333
|
+
static defaultProps = {
|
|
1334
|
+
lint: true,
|
|
1335
|
+
schema: {},
|
|
1336
|
+
overrideThemeBackgroundColor: false,
|
|
1337
|
+
lineWrap: false,
|
|
1338
|
+
extraKeybindings: [],
|
|
1339
|
+
initialHistory: [],
|
|
1340
|
+
theme: "light"
|
|
1341
|
+
};
|
|
1342
|
+
componentDidMount() {
|
|
1343
|
+
const {
|
|
1344
|
+
theme,
|
|
1345
|
+
onExecute,
|
|
1346
|
+
initialHistory,
|
|
1347
|
+
onNewHistoryEntry,
|
|
1348
|
+
extraKeybindings,
|
|
1349
|
+
lineWrap,
|
|
1350
|
+
overrideThemeBackgroundColor,
|
|
1351
|
+
schema,
|
|
1352
|
+
lint,
|
|
1353
|
+
onChange
|
|
1354
|
+
} = this.props;
|
|
1355
|
+
this.schemaRef.current = { schema, lint };
|
|
1356
|
+
const maybeReplMode = onExecute ? replMode({
|
|
1357
|
+
onExecute,
|
|
1358
|
+
initialHistory,
|
|
1359
|
+
onNewHistoryEntry
|
|
1360
|
+
}) : [];
|
|
1361
|
+
const themeExtension = getThemeExtension(
|
|
1362
|
+
theme,
|
|
1363
|
+
overrideThemeBackgroundColor
|
|
1364
|
+
);
|
|
1365
|
+
const changeListener = onChange ? [
|
|
1366
|
+
EditorView4.updateListener.of((upt) => {
|
|
1367
|
+
const wasUserEdit = !upt.transactions.some(
|
|
1368
|
+
(tr) => tr.annotation(ExternalEdit)
|
|
1369
|
+
);
|
|
1370
|
+
if (upt.docChanged && wasUserEdit) {
|
|
1371
|
+
const doc = upt.state.doc;
|
|
1372
|
+
const value = doc.toString();
|
|
1373
|
+
onChange(value, upt);
|
|
1374
|
+
}
|
|
1375
|
+
})
|
|
1376
|
+
] : [];
|
|
1377
|
+
this.editorState.current = EditorState2.create({
|
|
1314
1378
|
extensions: [
|
|
1315
|
-
cypher({ lint, schema }),
|
|
1316
|
-
keymap3.of(extraKeybindings),
|
|
1317
1379
|
maybeReplMode,
|
|
1318
|
-
basicNeo4jSetup(
|
|
1380
|
+
basicNeo4jSetup(),
|
|
1381
|
+
themeCompartment.of(themeExtension),
|
|
1382
|
+
changeListener,
|
|
1383
|
+
cypher(this.schemaRef.current),
|
|
1384
|
+
keyBindingCompartment.of(keymap3.of(extraKeybindings)),
|
|
1319
1385
|
lineWrap ? EditorView4.lineWrapping : [],
|
|
1320
|
-
|
|
1386
|
+
lineNumbers({
|
|
1387
|
+
formatNumber: (a, state) => {
|
|
1388
|
+
if (state.doc.lines === 1 && this.props.prompt !== void 0) {
|
|
1389
|
+
return this.props.prompt;
|
|
1390
|
+
}
|
|
1391
|
+
return a.toString();
|
|
1392
|
+
}
|
|
1393
|
+
})
|
|
1321
1394
|
],
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1395
|
+
doc: this.props.value
|
|
1396
|
+
});
|
|
1397
|
+
this.editorView.current = new EditorView4({
|
|
1398
|
+
state: this.editorState.current,
|
|
1399
|
+
parent: this.editorContainer.current
|
|
1400
|
+
});
|
|
1401
|
+
if (this.props.autofocus) {
|
|
1402
|
+
this.focus();
|
|
1403
|
+
if (this.props.value) {
|
|
1404
|
+
this.updateCursorPosition(this.props.value.length);
|
|
1405
|
+
}
|
|
1325
1406
|
}
|
|
1326
|
-
|
|
1327
|
-
|
|
1407
|
+
}
|
|
1408
|
+
componentDidUpdate(prevProps) {
|
|
1409
|
+
if (!this.editorView.current) {
|
|
1410
|
+
return;
|
|
1411
|
+
}
|
|
1412
|
+
const currentCmValue = this.editorView.current.state?.doc.toString() ?? "";
|
|
1413
|
+
if (this.props.value !== void 0 && currentCmValue !== this.props.value) {
|
|
1414
|
+
this.editorView.current.dispatch({
|
|
1415
|
+
changes: {
|
|
1416
|
+
from: 0,
|
|
1417
|
+
to: currentCmValue.length,
|
|
1418
|
+
insert: this.props.value ?? ""
|
|
1419
|
+
},
|
|
1420
|
+
annotations: [ExternalEdit.of(true)]
|
|
1421
|
+
});
|
|
1422
|
+
}
|
|
1423
|
+
const didChangeTheme = prevProps.theme !== this.props.theme || prevProps.overrideThemeBackgroundColor !== this.props.overrideThemeBackgroundColor;
|
|
1424
|
+
if (didChangeTheme) {
|
|
1425
|
+
this.editorView.current.dispatch({
|
|
1426
|
+
effects: themeCompartment.reconfigure(
|
|
1427
|
+
getThemeExtension(
|
|
1428
|
+
this.props.theme,
|
|
1429
|
+
this.props.overrideThemeBackgroundColor
|
|
1430
|
+
)
|
|
1431
|
+
)
|
|
1432
|
+
});
|
|
1433
|
+
}
|
|
1434
|
+
if (prevProps.extraKeybindings !== this.props.extraKeybindings) {
|
|
1435
|
+
this.editorView.current.dispatch({
|
|
1436
|
+
effects: keyBindingCompartment.reconfigure(
|
|
1437
|
+
keymap3.of(this.props.extraKeybindings)
|
|
1438
|
+
)
|
|
1439
|
+
});
|
|
1440
|
+
}
|
|
1441
|
+
this.schemaRef.current.schema = this.props.schema;
|
|
1442
|
+
this.schemaRef.current.lint = this.props.lint;
|
|
1443
|
+
}
|
|
1444
|
+
componentWillUnmount() {
|
|
1445
|
+
this.editorView.current?.destroy();
|
|
1446
|
+
}
|
|
1447
|
+
render() {
|
|
1448
|
+
const { className, theme } = this.props;
|
|
1449
|
+
const themeClass = typeof theme === "string" ? `cm-theme-${theme}` : "cm-theme";
|
|
1450
|
+
return /* @__PURE__ */ jsx(
|
|
1451
|
+
"div",
|
|
1452
|
+
{
|
|
1453
|
+
ref: this.editorContainer,
|
|
1454
|
+
className: `${themeClass}${className ? ` ${className}` : ""}`
|
|
1455
|
+
}
|
|
1456
|
+
);
|
|
1457
|
+
}
|
|
1458
|
+
};
|
|
1328
1459
|
export {
|
|
1329
1460
|
CypherEditor,
|
|
1330
1461
|
CypherParser,
|
|
@@ -1334,3 +1465,4 @@ export {
|
|
|
1334
1465
|
lightThemeConstants,
|
|
1335
1466
|
parse
|
|
1336
1467
|
};
|
|
1468
|
+
//# sourceMappingURL=index.mjs.map
|