react-dsl-editor 0.4.3 → 0.4.5
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/dist/index.d.ts +14 -4
- package/dist/react-dsl-editor.js +132 -76
- package/package.json +1 -1
package/dist/index.d.ts
CHANGED
|
@@ -28,7 +28,7 @@ export declare interface DSL<T extends string> {
|
|
|
28
28
|
errors: DSLError[];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
export declare function DslEditor<T extends string>({ code, onChange, onParsed, grammar, wrap, tooltipProps, suggestions: clientSuggestions, className, syntaxColors, ...textareaProps }: {
|
|
31
|
+
export declare function DslEditor<T extends string>({ code, onChange, onParsed, grammar, wrap, tooltipProps, suggestions: clientSuggestions, validate, className, syntaxColors, ...textareaProps }: {
|
|
32
32
|
code: string;
|
|
33
33
|
onChange: (text: string) => void;
|
|
34
34
|
onParsed?: (dsl: DSL<T>) => void;
|
|
@@ -36,6 +36,7 @@ export declare function DslEditor<T extends string>({ code, onChange, onParsed,
|
|
|
36
36
|
wrap?: boolean;
|
|
37
37
|
className?: string;
|
|
38
38
|
tooltipProps?: HTMLAttributes<HTMLElement>;
|
|
39
|
+
validate?: (node: T, text: string) => string | undefined;
|
|
39
40
|
suggestions?: (node: CSTNode<T>) => string[] | undefined;
|
|
40
41
|
syntaxColors?: SyntaxColorsProvider;
|
|
41
42
|
} & Omit<TextareaHTMLAttributes<HTMLTextAreaElement>, 'wrap' | 'onChange'>): JSX.Element;
|
|
@@ -45,7 +46,6 @@ export declare interface DSLError {
|
|
|
45
46
|
expected?: string[];
|
|
46
47
|
start: number;
|
|
47
48
|
end: number;
|
|
48
|
-
depth: number;
|
|
49
49
|
}
|
|
50
50
|
|
|
51
51
|
export declare class DSLParser<T extends string> {
|
|
@@ -54,6 +54,8 @@ export declare class DSLParser<T extends string> {
|
|
|
54
54
|
private _parseStrict;
|
|
55
55
|
parseStrict(input: string): ParserSuccess<T> | undefined;
|
|
56
56
|
parse(input: string): DSL<T>;
|
|
57
|
+
protected validate(node: T, text: string): string | undefined;
|
|
58
|
+
private validateCST;
|
|
57
59
|
}
|
|
58
60
|
|
|
59
61
|
export declare const eof: GrammarNode<never>;
|
|
@@ -64,7 +66,10 @@ export declare type FaultToleranceMode = 'skip-parser' | 'skip-input' | 'fuzzy-m
|
|
|
64
66
|
|
|
65
67
|
export declare interface GrammarNode<T extends string = never> {
|
|
66
68
|
type: T;
|
|
67
|
-
suggestions():
|
|
69
|
+
suggestions(): {
|
|
70
|
+
text: string;
|
|
71
|
+
node: GrammarNode<T>;
|
|
72
|
+
}[];
|
|
68
73
|
parse(text: string, context: ParserContext<T>): ParserResult<T>;
|
|
69
74
|
children: GrammarNode<T>[];
|
|
70
75
|
meta?: Record<string, unknown>;
|
|
@@ -82,7 +87,7 @@ export declare function nodeName<T extends string>(node: {
|
|
|
82
87
|
grammar: GrammarNode<T>;
|
|
83
88
|
}): T | undefined;
|
|
84
89
|
|
|
85
|
-
export declare type NodeTypes<T> = _NodeTypes<T
|
|
90
|
+
export declare type NodeTypes<T> = _NodeTypes<T>;
|
|
86
91
|
|
|
87
92
|
declare type _NodeTypes<T> = T extends GrammarNode<infer U> ? U : never;
|
|
88
93
|
|
|
@@ -137,6 +142,11 @@ declare const themes: {
|
|
|
137
142
|
readonly dark: string[];
|
|
138
143
|
};
|
|
139
144
|
|
|
145
|
+
export declare interface ValidationError<T extends string> {
|
|
146
|
+
node: CSTNode<T>;
|
|
147
|
+
message: string;
|
|
148
|
+
}
|
|
149
|
+
|
|
140
150
|
export declare function visit<T extends string, V = string>(parserResult: ParserSuccess<T>, type: T[], extractor?: (node: ParserSuccess<T>) => V): V[];
|
|
141
151
|
|
|
142
152
|
export declare function visitPredicate<T extends string, V = string>(parserResult: ParserSuccess<T>, filter: (v: ParserSuccess<T>) => boolean, extractor?: (node: ParserSuccess<T>) => V): V[];
|
package/dist/react-dsl-editor.js
CHANGED
|
@@ -830,9 +830,12 @@ function indexOf(o, h, g = 0) {
|
|
|
830
830
|
}
|
|
831
831
|
function pattern(o) {
|
|
832
832
|
let h = new import_randexp.default(o);
|
|
833
|
-
h.randInt = (o) => o;
|
|
833
|
+
h.randInt = (o) => o, h.defaultRange.subtract(-Infinity, Infinity);
|
|
834
834
|
function g() {
|
|
835
|
-
return t$1(t$3(0, 10), t$2(() => h.gen()), n$1())
|
|
835
|
+
return t$1(t$3(0, 10), t$2(() => h.gen()), n$1(), t$2((o) => ({
|
|
836
|
+
node: _,
|
|
837
|
+
text: o
|
|
838
|
+
})));
|
|
836
839
|
}
|
|
837
840
|
let _ = {
|
|
838
841
|
type: "pattern",
|
|
@@ -890,7 +893,7 @@ function repeat(o, h = 1, g = 1e3) {
|
|
|
890
893
|
x += y.text.length, S.push(y);
|
|
891
894
|
}
|
|
892
895
|
let w = C < h ? error({
|
|
893
|
-
expected: o.suggestions(),
|
|
896
|
+
expected: o.suggestions().map((o) => o.text),
|
|
894
897
|
got: v,
|
|
895
898
|
grammar: _,
|
|
896
899
|
offset: x,
|
|
@@ -938,7 +941,7 @@ function sequence(...o) {
|
|
|
938
941
|
let h = [];
|
|
939
942
|
for (let g of o) {
|
|
940
943
|
let o = g.suggestions();
|
|
941
|
-
|
|
944
|
+
h.push(...o.filter((o) => o.text !== ""));
|
|
942
945
|
}
|
|
943
946
|
return h;
|
|
944
947
|
},
|
|
@@ -1003,10 +1006,16 @@ function topError(o) {
|
|
|
1003
1006
|
message: o.expected.map((o) => JSON.stringify(o)).join(" or ") + ` expected, but got ${JSON.stringify(o.got)} (${pathToString(o.path)})`,
|
|
1004
1007
|
expected: o.expected,
|
|
1005
1008
|
start: o.offset,
|
|
1006
|
-
end: o.offset + Math.max(1, o.got.length)
|
|
1007
|
-
depth: 1
|
|
1009
|
+
end: o.offset + Math.max(1, o.got.length)
|
|
1008
1010
|
}];
|
|
1009
1011
|
}
|
|
1012
|
+
function validationErrors(o) {
|
|
1013
|
+
return o.map((o) => ({
|
|
1014
|
+
start: o.node.offset,
|
|
1015
|
+
end: o.node.end,
|
|
1016
|
+
message: o.message
|
|
1017
|
+
}));
|
|
1018
|
+
}
|
|
1010
1019
|
var DSLParser = class {
|
|
1011
1020
|
grammar;
|
|
1012
1021
|
constructor(o) {
|
|
@@ -1020,7 +1029,7 @@ var DSLParser = class {
|
|
|
1020
1029
|
return h.length < v.length && (h = v), error({
|
|
1021
1030
|
grammar: _,
|
|
1022
1031
|
offset: 0,
|
|
1023
|
-
expected: _.suggestions(),
|
|
1032
|
+
expected: _.suggestions().map((o) => o.text),
|
|
1024
1033
|
got: o,
|
|
1025
1034
|
path: v
|
|
1026
1035
|
});
|
|
@@ -1044,9 +1053,25 @@ var DSLParser = class {
|
|
|
1044
1053
|
terminals: _,
|
|
1045
1054
|
result: h,
|
|
1046
1055
|
strictResult: isParserSuccess(h) ? h : void 0,
|
|
1047
|
-
errors: [
|
|
1056
|
+
errors: [
|
|
1057
|
+
...topError(h),
|
|
1058
|
+
...topError(h.errorLabel),
|
|
1059
|
+
...validationErrors(this.validateCST(g))
|
|
1060
|
+
]
|
|
1048
1061
|
};
|
|
1049
1062
|
}
|
|
1063
|
+
validate(o, h) {}
|
|
1064
|
+
validateCST(o) {
|
|
1065
|
+
let h = t$1(o.children ?? [], t((o) => this.validateCST(o))), g = nodeName(o);
|
|
1066
|
+
if (g) {
|
|
1067
|
+
let _ = this.validate(g, o.text);
|
|
1068
|
+
_ && h.push({
|
|
1069
|
+
node: o,
|
|
1070
|
+
message: _
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
return h;
|
|
1074
|
+
}
|
|
1050
1075
|
};
|
|
1051
1076
|
function visit(o, h, g = (o) => o.text) {
|
|
1052
1077
|
return visitPredicate(o, (o) => {
|
|
@@ -1067,15 +1092,16 @@ function getSuggestions(o, h, g = () => void 0) {
|
|
|
1067
1092
|
}));
|
|
1068
1093
|
}
|
|
1069
1094
|
return o.grammar.suggestions().map((h) => ({
|
|
1070
|
-
node: o,
|
|
1071
|
-
suggestion: h
|
|
1095
|
+
node: _.find((o) => o.grammar === h.node) ?? o,
|
|
1096
|
+
suggestion: h.text
|
|
1072
1097
|
}));
|
|
1073
1098
|
}));
|
|
1074
1099
|
return t$1(v, t((o) => {
|
|
1075
1100
|
let g = o.node.text.substring(0, h - o.node.offset);
|
|
1076
1101
|
return o.suggestion.startsWith(g) && o.suggestion.trim().length > 0 ? [{
|
|
1077
1102
|
suggestion: o.suggestion,
|
|
1078
|
-
prefix: g
|
|
1103
|
+
prefix: g,
|
|
1104
|
+
node: o.node
|
|
1079
1105
|
}] : [];
|
|
1080
1106
|
}), n((o) => o.suggestion));
|
|
1081
1107
|
}
|
|
@@ -1271,84 +1297,114 @@ function SuggestionsMenu({ suggestions: o, onSelect: h, style: g, selectedIndex:
|
|
|
1271
1297
|
}, g))
|
|
1272
1298
|
});
|
|
1273
1299
|
}
|
|
1274
|
-
function
|
|
1275
|
-
|
|
1300
|
+
function getCursorCoordinates(o) {
|
|
1301
|
+
return o?.getCursorPosition?.() ?? {
|
|
1302
|
+
top: 0,
|
|
1303
|
+
left: 0
|
|
1304
|
+
};
|
|
1305
|
+
}
|
|
1306
|
+
function DslEditor({ code: o, onChange: h, onParsed: v, grammar: S, wrap: T = !1, tooltipProps: E = { style: { backgroundColor: "darkGray" } }, suggestions: D, validate: O, className: k = DslEditor.name, syntaxColors: A = defaultSyntaxColors("light"),...j }) {
|
|
1307
|
+
let [M, N] = useState([]), [F, I] = useState(), [L, R] = useState({
|
|
1276
1308
|
top: 0,
|
|
1277
1309
|
left: 0,
|
|
1310
|
+
cursorPosition: !1,
|
|
1278
1311
|
visible: !1
|
|
1279
|
-
}), [
|
|
1280
|
-
let h =
|
|
1281
|
-
return
|
|
1282
|
-
}, [D]),
|
|
1283
|
-
|
|
1284
|
-
}, [
|
|
1312
|
+
}), [z, B] = useState(0), [V, H] = useState(""), U = useRef(null), W = useRef(null), G = useRef(null), K = useRef(null), q = useCallback((o) => {
|
|
1313
|
+
let h = U.current?.selectionStart ?? 0, g = getSuggestions(o, h, D);
|
|
1314
|
+
return N(g), g;
|
|
1315
|
+
}, [D]), J = useCallback(() => {
|
|
1316
|
+
F && H(U.current?.value?.substring(0, U.current?.selectionStart ?? 0) ?? "");
|
|
1317
|
+
}, [F]);
|
|
1285
1318
|
useEffect(() => {
|
|
1286
|
-
let h = new DSLParser
|
|
1287
|
-
|
|
1319
|
+
let h = (O ? new class extends DSLParser {
|
|
1320
|
+
constructor() {
|
|
1321
|
+
super(S);
|
|
1322
|
+
}
|
|
1323
|
+
validate(o, h) {
|
|
1324
|
+
return O(o, h);
|
|
1325
|
+
}
|
|
1326
|
+
}() : new DSLParser(S)).parse(o);
|
|
1327
|
+
I(h), v?.(h), q(h.cst), H(o.substring(0, U.current?.selectionStart ?? 0));
|
|
1288
1328
|
}, [
|
|
1289
1329
|
o,
|
|
1290
1330
|
v,
|
|
1291
1331
|
S,
|
|
1292
|
-
|
|
1332
|
+
q,
|
|
1333
|
+
O
|
|
1293
1334
|
]);
|
|
1294
|
-
let
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1335
|
+
let Y = useCallback((g) => {
|
|
1336
|
+
if (!U.current || !F?.cst) return;
|
|
1337
|
+
let { selectionStart: _, selectionEnd: v } = U.current, { prefix: y } = g;
|
|
1338
|
+
if (_ === v) {
|
|
1339
|
+
let _ = o.substring(0, g.node.offset) + g.suggestion + o.substring(g.node.end);
|
|
1340
|
+
h(_);
|
|
1341
|
+
} else {
|
|
1342
|
+
let b = o.substring(0, _ - y.length) + g.suggestion + o.substring(v);
|
|
1343
|
+
h(b);
|
|
1344
|
+
}
|
|
1345
|
+
setTimeout(() => {
|
|
1346
|
+
U.current && (U.current.focus(), U.current.selectionStart = U.current.selectionEnd = _ - y.length + g.suggestion.length);
|
|
1347
|
+
}, 0), R((o) => ({
|
|
1303
1348
|
...o,
|
|
1304
1349
|
visible: !1
|
|
1305
1350
|
}));
|
|
1306
|
-
}, [
|
|
1351
|
+
}, [
|
|
1352
|
+
o,
|
|
1353
|
+
h,
|
|
1354
|
+
F?.cst
|
|
1355
|
+
]), X = useMemo(() => ({
|
|
1307
1356
|
ArrowDown() {
|
|
1308
|
-
|
|
1357
|
+
B((o) => (o + 1) % M.length);
|
|
1309
1358
|
},
|
|
1310
1359
|
ArrowUp() {
|
|
1311
|
-
|
|
1360
|
+
B((o) => (o - 1 + M.length) % M.length);
|
|
1312
1361
|
},
|
|
1313
1362
|
Enter() {
|
|
1314
|
-
|
|
1363
|
+
M[z] && Y(M[z]);
|
|
1315
1364
|
},
|
|
1316
1365
|
Escape() {
|
|
1317
|
-
|
|
1366
|
+
R((o) => ({
|
|
1318
1367
|
...o,
|
|
1319
1368
|
visible: !1
|
|
1320
1369
|
}));
|
|
1321
1370
|
}
|
|
1322
1371
|
}), [
|
|
1323
1372
|
Y,
|
|
1324
|
-
|
|
1325
|
-
|
|
1373
|
+
z,
|
|
1374
|
+
M
|
|
1326
1375
|
]), Z = useMemo(() => ({ CtrlSpace() {
|
|
1327
|
-
if (!
|
|
1328
|
-
let o =
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
left: g
|
|
1376
|
+
if (!F?.cst) return;
|
|
1377
|
+
let o = q(F?.cst);
|
|
1378
|
+
e(o) || R({
|
|
1379
|
+
cursorPosition: !0,
|
|
1380
|
+
visible: !1,
|
|
1381
|
+
top: 0,
|
|
1382
|
+
left: 0
|
|
1335
1383
|
});
|
|
1336
|
-
} }), [
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1384
|
+
} }), [F?.cst, q]);
|
|
1385
|
+
useEffect(() => {
|
|
1386
|
+
if (L.cursorPosition) {
|
|
1387
|
+
let { top: o, left: h } = getCursorCoordinates(W.current);
|
|
1388
|
+
B(0), R({
|
|
1389
|
+
cursorPosition: !1,
|
|
1390
|
+
visible: !0,
|
|
1391
|
+
top: o,
|
|
1392
|
+
left: h
|
|
1393
|
+
});
|
|
1394
|
+
}
|
|
1395
|
+
}, [L.cursorPosition]);
|
|
1396
|
+
let Q = useCallback((o) => {
|
|
1397
|
+
let h = (L.visible ? X : Z)[shortcutName(o)];
|
|
1342
1398
|
h && (o.preventDefault(), h());
|
|
1343
1399
|
}, [
|
|
1344
|
-
|
|
1400
|
+
L.visible,
|
|
1345
1401
|
X,
|
|
1346
1402
|
Z
|
|
1347
1403
|
]), $ = useCallback((o) => {
|
|
1348
|
-
h(o.target.value),
|
|
1404
|
+
h(o.target.value), R((o) => ({
|
|
1349
1405
|
...o,
|
|
1350
1406
|
visible: !1
|
|
1351
|
-
})),
|
|
1407
|
+
})), H(o.target.value.substring(0, o.target.selectionStart));
|
|
1352
1408
|
}, [h]);
|
|
1353
1409
|
return /* @__PURE__ */ jsx("div", {
|
|
1354
1410
|
style: {
|
|
@@ -1358,7 +1414,7 @@ function DslEditor({ code: o, onChange: h, onParsed: v, grammar: S, wrap: T = !1
|
|
|
1358
1414
|
width: "100%",
|
|
1359
1415
|
height: "100%"
|
|
1360
1416
|
},
|
|
1361
|
-
className:
|
|
1417
|
+
className: k,
|
|
1362
1418
|
children: /* @__PURE__ */ jsxs("div", {
|
|
1363
1419
|
style: {
|
|
1364
1420
|
position: "relative",
|
|
@@ -1367,44 +1423,44 @@ function DslEditor({ code: o, onChange: h, onParsed: v, grammar: S, wrap: T = !1
|
|
|
1367
1423
|
},
|
|
1368
1424
|
children: [
|
|
1369
1425
|
/* @__PURE__ */ jsx("textarea", {
|
|
1370
|
-
ref:
|
|
1426
|
+
ref: U,
|
|
1371
1427
|
spellCheck: !1,
|
|
1372
1428
|
wrap: T ? "soft" : "off",
|
|
1373
1429
|
style: textStyle,
|
|
1374
1430
|
value: o,
|
|
1375
|
-
onSelect:
|
|
1431
|
+
onSelect: J,
|
|
1376
1432
|
onChange: $,
|
|
1377
|
-
onScroll: useSyncScroll(
|
|
1433
|
+
onScroll: useSyncScroll(G, K),
|
|
1378
1434
|
onKeyDown: Q,
|
|
1379
|
-
...
|
|
1435
|
+
...j
|
|
1380
1436
|
}),
|
|
1381
|
-
|
|
1382
|
-
cstRoot:
|
|
1383
|
-
ref:
|
|
1437
|
+
F && /* @__PURE__ */ jsx(SyntaxHighlighter, {
|
|
1438
|
+
cstRoot: F.cst,
|
|
1439
|
+
ref: G,
|
|
1384
1440
|
wrap: T,
|
|
1385
|
-
syntaxColors:
|
|
1441
|
+
syntaxColors: A
|
|
1386
1442
|
}),
|
|
1387
|
-
!e(
|
|
1388
|
-
ref:
|
|
1389
|
-
errors:
|
|
1443
|
+
!e(F?.errors ?? []) && /* @__PURE__ */ jsx(ErrorHighlighter, {
|
|
1444
|
+
ref: K,
|
|
1445
|
+
errors: F?.errors ?? [],
|
|
1390
1446
|
tooltipProps: E,
|
|
1391
1447
|
wrap: T,
|
|
1392
1448
|
children: o
|
|
1393
1449
|
}),
|
|
1394
|
-
/* @__PURE__ */ jsx(CursorPosition, {
|
|
1395
|
-
ref:
|
|
1396
|
-
text:
|
|
1450
|
+
L.cursorPosition && /* @__PURE__ */ jsx(CursorPosition, {
|
|
1451
|
+
ref: W,
|
|
1452
|
+
text: V,
|
|
1397
1453
|
wrap: T
|
|
1398
1454
|
}),
|
|
1399
|
-
|
|
1400
|
-
suggestions:
|
|
1455
|
+
L.visible && /* @__PURE__ */ jsx(SuggestionsMenu, {
|
|
1456
|
+
suggestions: M,
|
|
1401
1457
|
onSelect: Y,
|
|
1402
1458
|
style: {
|
|
1403
|
-
top:
|
|
1404
|
-
left:
|
|
1459
|
+
top: L.top,
|
|
1460
|
+
left: L.left
|
|
1405
1461
|
},
|
|
1406
|
-
selectedIndex:
|
|
1407
|
-
onHover:
|
|
1462
|
+
selectedIndex: z,
|
|
1463
|
+
onHover: B
|
|
1408
1464
|
})
|
|
1409
1465
|
]
|
|
1410
1466
|
})
|