@1771technologies/lytenyte-pro 2.0.4-dev.3 → 2.0.4-dev.4
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/css/components/expression-editor.css +105 -0
- package/dist/components/column-manager/column-manager.d.ts +6 -1
- package/dist/components/column-manager/column-manager.js +23 -2
- package/dist/components/expressions-editor/(expressions)/expression.play.d.ts +4 -0
- package/dist/components/expressions-editor/(expressions)/expression.play.js +69 -0
- package/dist/components/expressions-editor/create-completion-provider.d.ts +3 -0
- package/dist/components/expressions-editor/create-completion-provider.js +161 -0
- package/dist/components/expressions-editor/create-key-down-handler.d.ts +18 -0
- package/dist/components/expressions-editor/create-key-down-handler.js +49 -0
- package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.d.ts +2 -0
- package/dist/components/expressions-editor/cursor-position/measure-cursor-at-pointer.js +56 -0
- package/dist/components/expressions-editor/cursor-position/use-cursor-position.d.ts +5 -0
- package/dist/components/expressions-editor/cursor-position/use-cursor-position.js +17 -0
- package/dist/components/expressions-editor/expression-editor.d.ts +3 -0
- package/dist/components/expressions-editor/expression-editor.js +138 -0
- package/dist/components/expressions-editor/get-indentation.d.ts +1 -0
- package/dist/components/expressions-editor/get-indentation.js +7 -0
- package/dist/components/expressions-editor/handle-completion-key-down.d.ts +2 -0
- package/dist/components/expressions-editor/handle-completion-key-down.js +22 -0
- package/dist/components/expressions-editor/handle-enter-key.d.ts +4 -0
- package/dist/components/expressions-editor/handle-enter-key.js +11 -0
- package/dist/components/expressions-editor/handle-manual-trigger.d.ts +2 -0
- package/dist/components/expressions-editor/handle-manual-trigger.js +3 -0
- package/dist/components/expressions-editor/index.d.ts +17 -0
- package/dist/components/expressions-editor/index.js +11 -0
- package/dist/components/expressions-editor/intellisence/completion-context.d.ts +16 -0
- package/dist/components/expressions-editor/intellisence/completion-context.js +7 -0
- package/dist/components/expressions-editor/intellisence/completion-item.d.ts +5 -0
- package/dist/components/expressions-editor/intellisence/completion-item.js +11 -0
- package/dist/components/expressions-editor/intellisence/completion-list.d.ts +8 -0
- package/dist/components/expressions-editor/intellisence/completion-list.js +18 -0
- package/dist/components/expressions-editor/intellisence/completion-popover.d.ts +1 -0
- package/dist/components/expressions-editor/intellisence/completion-popover.js +30 -0
- package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.d.ts +2 -0
- package/dist/components/expressions-editor/intellisence/filter-completions-by-prefix.js +6 -0
- package/dist/components/expressions-editor/intellisence/get-word-at-cursor.d.ts +2 -0
- package/dist/components/expressions-editor/intellisence/get-word-at-cursor.js +12 -0
- package/dist/components/expressions-editor/intellisence/use-complete-trigger.d.ts +13 -0
- package/dist/components/expressions-editor/intellisence/use-complete-trigger.js +41 -0
- package/dist/components/expressions-editor/intellisence/use-completions.d.ts +14 -0
- package/dist/components/expressions-editor/intellisence/use-completions.js +78 -0
- package/dist/components/expressions-editor/replace-word-at-cursor.d.ts +5 -0
- package/dist/components/expressions-editor/replace-word-at-cursor.js +7 -0
- package/dist/components/expressions-editor/token-highlighter-default.d.ts +4 -0
- package/dist/components/expressions-editor/token-highlighter-default.js +18 -0
- package/dist/components/expressions-editor/types.d.ts +47 -0
- package/dist/components/expressions-editor/types.js +1 -0
- package/dist/components/expressions-editor/use-keyboard-navigation.d.ts +10 -0
- package/dist/components/expressions-editor/use-keyboard-navigation.js +16 -0
- package/dist/components/pill-manager/container.js +55 -9
- package/dist/components/pill-manager/item.js +15 -1
- package/dist/components/select-all.js +1 -1
- package/dist/components/tree-view/root.d.ts +9 -0
- package/dist/components/tree-view/root.js +4 -2
- package/dist/data-source-client/hooks/use-flattened-groups.js +2 -2
- package/dist/expressions/compiler/compile.d.ts +3 -0
- package/dist/expressions/compiler/compile.js +4 -0
- package/dist/expressions/compiler/eval-constant.d.ts +2 -0
- package/dist/expressions/compiler/eval-constant.js +19 -0
- package/dist/expressions/compiler/is-constant.d.ts +2 -0
- package/dist/expressions/compiler/is-constant.js +6 -0
- package/dist/expressions/compiler/make-constant.d.ts +2 -0
- package/dist/expressions/compiler/make-constant.js +11 -0
- package/dist/expressions/compiler/optimize.d.ts +3 -0
- package/dist/expressions/compiler/optimize.js +47 -0
- package/dist/expressions/compiler/value-of.d.ts +2 -0
- package/dist/expressions/compiler/value-of.js +11 -0
- package/dist/expressions/errors/clamp-offset.d.ts +1 -0
- package/dist/expressions/errors/clamp-offset.js +3 -0
- package/dist/expressions/errors/expression-error.d.ts +10 -0
- package/dist/expressions/errors/expression-error.js +19 -0
- package/dist/expressions/errors/format-error.d.ts +3 -0
- package/dist/expressions/errors/format-error.js +27 -0
- package/dist/expressions/errors/get-line-end.d.ts +1 -0
- package/dist/expressions/errors/get-line-end.js +8 -0
- package/dist/expressions/errors/get-line-start.d.ts +1 -0
- package/dist/expressions/errors/get-line-start.js +8 -0
- package/dist/expressions/errors/index.d.ts +7 -0
- package/dist/expressions/errors/index.js +6 -0
- package/dist/expressions/errors/offset-to-position.d.ts +2 -0
- package/dist/expressions/errors/offset-to-position.js +17 -0
- package/dist/expressions/errors/types.d.ts +10 -0
- package/dist/expressions/errors/types.js +1 -0
- package/dist/expressions/evaluator/evaluate-binary.d.ts +4 -0
- package/dist/expressions/evaluator/evaluate-binary.js +21 -0
- package/dist/expressions/evaluator/evaluate-unary.d.ts +2 -0
- package/dist/expressions/evaluator/evaluate-unary.js +10 -0
- package/dist/expressions/evaluator/evaluate.d.ts +15 -0
- package/dist/expressions/evaluator/evaluate.js +62 -0
- package/dist/expressions/index.d.ts +5 -0
- package/dist/expressions/index.js +3 -0
- package/dist/expressions/lexer/predicates/is-alpha-numeric.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-alpha-numeric.js +5 -0
- package/dist/expressions/lexer/predicates/is-alpha.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-alpha.js +3 -0
- package/dist/expressions/lexer/predicates/is-binary-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-binary-digit.js +3 -0
- package/dist/expressions/lexer/predicates/is-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-digit.js +3 -0
- package/dist/expressions/lexer/predicates/is-hex-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-hex-digit.js +4 -0
- package/dist/expressions/lexer/predicates/is-octal-digit.d.ts +1 -0
- package/dist/expressions/lexer/predicates/is-octal-digit.js +3 -0
- package/dist/expressions/lexer/tokenize/consume-digits.d.ts +1 -0
- package/dist/expressions/lexer/tokenize/consume-digits.js +5 -0
- package/dist/expressions/lexer/tokenize/scan-identifier.d.ts +6 -0
- package/dist/expressions/lexer/tokenize/scan-identifier.js +20 -0
- package/dist/expressions/lexer/tokenize/scan-number.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-number.js +32 -0
- package/dist/expressions/lexer/tokenize/scan-operator.d.ts +6 -0
- package/dist/expressions/lexer/tokenize/scan-operator.js +71 -0
- package/dist/expressions/lexer/tokenize/scan-string-literal.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-string-literal.js +22 -0
- package/dist/expressions/lexer/tokenize/scan-string.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-string.js +98 -0
- package/dist/expressions/lexer/tokenize/scan-template-literal.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/scan-template-literal.js +51 -0
- package/dist/expressions/lexer/tokenize/tokenize.d.ts +4 -0
- package/dist/expressions/lexer/tokenize/tokenize.js +99 -0
- package/dist/expressions/lexer/types.d.ts +12 -0
- package/dist/expressions/lexer/types.js +1 -0
- package/dist/expressions/parser/parse-array-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-array-literal.js +15 -0
- package/dist/expressions/parser/parse-expression.d.ts +3 -0
- package/dist/expressions/parser/parse-expression.js +74 -0
- package/dist/expressions/parser/parse-object-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-object-literal.js +69 -0
- package/dist/expressions/parser/parse-pipe-transform.d.ts +3 -0
- package/dist/expressions/parser/parse-pipe-transform.js +26 -0
- package/dist/expressions/parser/parse-postfix.d.ts +3 -0
- package/dist/expressions/parser/parse-postfix.js +23 -0
- package/dist/expressions/parser/parse-primary.d.ts +3 -0
- package/dist/expressions/parser/parse-primary.js +35 -0
- package/dist/expressions/parser/parse-template-literal.d.ts +3 -0
- package/dist/expressions/parser/parse-template-literal.js +41 -0
- package/dist/expressions/parser/parse-unary.d.ts +3 -0
- package/dist/expressions/parser/parse-unary.js +28 -0
- package/dist/expressions/parser/parse.d.ts +3 -0
- package/dist/expressions/parser/parse.js +26 -0
- package/dist/expressions/parser/parser-context.d.ts +12 -0
- package/dist/expressions/parser/parser-context.js +14 -0
- package/dist/expressions/parser/precedence.d.ts +1 -0
- package/dist/expressions/parser/precedence.js +8 -0
- package/dist/expressions/parser/types.d.ts +97 -0
- package/dist/expressions/parser/types.js +1 -0
- package/dist/expressions/plugin.d.ts +20 -0
- package/dist/expressions/plugin.js +1 -0
- package/dist/expressions/plugins/access.d.ts +2 -0
- package/dist/expressions/plugins/access.js +138 -0
- package/dist/expressions/plugins/arrows.d.ts +2 -0
- package/dist/expressions/plugins/arrows.js +83 -0
- package/dist/expressions/plugins/booleans.d.ts +2 -0
- package/dist/expressions/plugins/booleans.js +34 -0
- package/dist/expressions/plugins/collections.d.ts +2 -0
- package/dist/expressions/plugins/collections.js +70 -0
- package/dist/expressions/plugins/comparison.d.ts +2 -0
- package/dist/expressions/plugins/comparison.js +51 -0
- package/dist/expressions/plugins/logical.d.ts +2 -0
- package/dist/expressions/plugins/logical.js +103 -0
- package/dist/expressions/plugins/membership.d.ts +2 -0
- package/dist/expressions/plugins/membership.js +71 -0
- package/dist/expressions/plugins/pipe.d.ts +2 -0
- package/dist/expressions/plugins/pipe.js +57 -0
- package/dist/expressions/plugins/resolved-identifier.d.ts +5 -0
- package/dist/expressions/plugins/resolved-identifier.js +19 -0
- package/dist/expressions/plugins/standard.d.ts +13 -0
- package/dist/expressions/plugins/standard.js +23 -0
- package/dist/expressions/plugins/strings.d.ts +2 -0
- package/dist/expressions/plugins/strings.js +44 -0
- package/dist/expressions/plugins/ternary.d.ts +2 -0
- package/dist/expressions/plugins/ternary.js +58 -0
- package/dist/expressions.d.ts +2 -0
- package/dist/expressions.js +2 -0
- package/dist/index.d.ts +1 -0
- package/package.json +11 -5
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export { Evaluator } from "./evaluator/evaluate.js";
|
|
2
|
+
export { accessPlugin, arrowsPlugin, booleansPlugin, collectionsPlugin, comparisonPlugin, logicalPlugin, membershipPlugin, pipePlugin, standardPlugins, stringsPlugin, ternaryPlugin, } from "./plugins/standard.js";
|
|
3
|
+
export { createResolvedIdentifierPlugin } from "./plugins/resolved-identifier.js";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isAlphaNumeric(ch: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isAlpha(ch: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isBinaryDigit(ch: string): ch is "0" | "1";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isDigit(ch: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isHexDigit(ch: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function isOctalDigit(ch: string): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function consumeDigits(source: string, pos: number, predicate: (ch: string) => boolean): number;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { isAlphaNumeric } from "../predicates/is-alpha-numeric.js";
|
|
2
|
+
const KEYWORDS = new Map([
|
|
3
|
+
["true", { type: "Boolean", value: "true" }],
|
|
4
|
+
["false", { type: "Boolean", value: "false" }],
|
|
5
|
+
["null", { type: "Null", value: "null" }],
|
|
6
|
+
["undefined", { type: "Undefined", value: "undefined" }],
|
|
7
|
+
["in", { type: "Operator", value: "in" }],
|
|
8
|
+
["not", { type: "Operator", value: "not" }],
|
|
9
|
+
]);
|
|
10
|
+
export function scanIdentifier(source, start) {
|
|
11
|
+
let i = start;
|
|
12
|
+
while (i < source.length && isAlphaNumeric(source[i]))
|
|
13
|
+
i++;
|
|
14
|
+
const value = source.slice(start, i);
|
|
15
|
+
const kw = KEYWORDS.get(value);
|
|
16
|
+
if (kw) {
|
|
17
|
+
return { type: kw.type, value: kw.value, end: i };
|
|
18
|
+
}
|
|
19
|
+
return { type: "Identifier", value, end: i };
|
|
20
|
+
}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { isDigit } from "../predicates/is-digit.js";
|
|
2
|
+
import { isHexDigit } from "../predicates/is-hex-digit.js";
|
|
3
|
+
import { isOctalDigit } from "../predicates/is-octal-digit.js";
|
|
4
|
+
import { isBinaryDigit } from "../predicates/is-binary-digit.js";
|
|
5
|
+
import { consumeDigits } from "./consume-digits.js";
|
|
6
|
+
export function scanNumber(source, start) {
|
|
7
|
+
const ch = source[start];
|
|
8
|
+
const next = source[start + 1];
|
|
9
|
+
let i = start;
|
|
10
|
+
if (ch === "0" && (next === "x" || next === "X")) {
|
|
11
|
+
i = consumeDigits(source, i + 2, isHexDigit);
|
|
12
|
+
}
|
|
13
|
+
else if (ch === "0" && (next === "o" || next === "O")) {
|
|
14
|
+
i = consumeDigits(source, i + 2, isOctalDigit);
|
|
15
|
+
}
|
|
16
|
+
else if (ch === "0" && (next === "b" || next === "B")) {
|
|
17
|
+
i = consumeDigits(source, i + 2, isBinaryDigit);
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
i = consumeDigits(source, i, isDigit);
|
|
21
|
+
if (i < source.length && source[i] === "." && i + 1 < source.length && isDigit(source[i + 1])) {
|
|
22
|
+
i = consumeDigits(source, i + 1, isDigit);
|
|
23
|
+
}
|
|
24
|
+
if (i < source.length && (source[i] === "e" || source[i] === "E")) {
|
|
25
|
+
i++;
|
|
26
|
+
if (i < source.length && (source[i] === "+" || source[i] === "-"))
|
|
27
|
+
i++;
|
|
28
|
+
i = consumeDigits(source, i, isDigit);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
return { value: source.slice(start, i), end: i };
|
|
32
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { ExpressionError } from "../../errors/index.js";
|
|
2
|
+
export function scanOperator(source, start) {
|
|
3
|
+
const ch = source[start];
|
|
4
|
+
const next = start + 1 < source.length ? source[start + 1] : "";
|
|
5
|
+
// Spread operator ...
|
|
6
|
+
if (ch === "." && next === "." && start + 2 < source.length && source[start + 2] === ".") {
|
|
7
|
+
return { type: "Spread", value: "...", end: start + 3 };
|
|
8
|
+
}
|
|
9
|
+
// Dot (punctuation)
|
|
10
|
+
if (ch === ".") {
|
|
11
|
+
return { type: "Punctuation", value: ".", end: start + 1 };
|
|
12
|
+
}
|
|
13
|
+
// Pipe |> or logical ||
|
|
14
|
+
if (ch === "|" && next === ">") {
|
|
15
|
+
return { type: "Pipe", value: "|>", end: start + 2 };
|
|
16
|
+
}
|
|
17
|
+
if (ch === "|" && next === "|") {
|
|
18
|
+
return { type: "Operator", value: "||", end: start + 2 };
|
|
19
|
+
}
|
|
20
|
+
// &&
|
|
21
|
+
if (ch === "&" && next === "&") {
|
|
22
|
+
return { type: "Operator", value: "&&", end: start + 2 };
|
|
23
|
+
}
|
|
24
|
+
// => (arrow)
|
|
25
|
+
if (ch === "=" && next === ">") {
|
|
26
|
+
return { type: "Arrow", value: "=>", end: start + 2 };
|
|
27
|
+
}
|
|
28
|
+
// == !=
|
|
29
|
+
if (ch === "=" && next === "=") {
|
|
30
|
+
return { type: "Operator", value: "==", end: start + 2 };
|
|
31
|
+
}
|
|
32
|
+
if (ch === "!" && next === "=") {
|
|
33
|
+
return { type: "Operator", value: "!=", end: start + 2 };
|
|
34
|
+
}
|
|
35
|
+
// ! (logical not) - must come after != check
|
|
36
|
+
if (ch === "!") {
|
|
37
|
+
return { type: "Operator", value: "!", end: start + 1 };
|
|
38
|
+
}
|
|
39
|
+
// <= >= < >
|
|
40
|
+
if (ch === "<") {
|
|
41
|
+
if (next === "=")
|
|
42
|
+
return { type: "Operator", value: "<=", end: start + 2 };
|
|
43
|
+
return { type: "Operator", value: "<", end: start + 1 };
|
|
44
|
+
}
|
|
45
|
+
if (ch === ">") {
|
|
46
|
+
if (next === "=")
|
|
47
|
+
return { type: "Operator", value: ">=", end: start + 2 };
|
|
48
|
+
return { type: "Operator", value: ">", end: start + 1 };
|
|
49
|
+
}
|
|
50
|
+
// ** (exponentiation) — must come before single *
|
|
51
|
+
if (ch === "*" && next === "*") {
|
|
52
|
+
return { type: "Operator", value: "**", end: start + 2 };
|
|
53
|
+
}
|
|
54
|
+
// ?. (optional chaining) or ?? (nullish coalescing) or ? (ternary)
|
|
55
|
+
if (ch === "?") {
|
|
56
|
+
if (next === ".")
|
|
57
|
+
return { type: "OptionalChain", value: "?.", end: start + 2 };
|
|
58
|
+
if (next === "?")
|
|
59
|
+
return { type: "NullishCoalescing", value: "??", end: start + 2 };
|
|
60
|
+
return { type: "Punctuation", value: "?", end: start + 1 };
|
|
61
|
+
}
|
|
62
|
+
// Single-character operators
|
|
63
|
+
if (ch === "+" || ch === "-" || ch === "*" || ch === "/" || ch === "%") {
|
|
64
|
+
return { type: "Operator", value: ch, end: start + 1 };
|
|
65
|
+
}
|
|
66
|
+
// Punctuation
|
|
67
|
+
if ("()[]{},:".includes(ch)) {
|
|
68
|
+
return { type: "Punctuation", value: ch, end: start + 1 };
|
|
69
|
+
}
|
|
70
|
+
throw new ExpressionError(`Unexpected character "${ch}"`, { source, start, end: start + 1 });
|
|
71
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { ExpressionError } from "../../errors/index.js";
|
|
2
|
+
export function scanStringLiteral(source, start) {
|
|
3
|
+
const quote = source[start];
|
|
4
|
+
let raw = quote;
|
|
5
|
+
let i = start + 1;
|
|
6
|
+
while (i < source.length && source[i] !== quote) {
|
|
7
|
+
if (source[i] === "\\" && i + 1 < source.length) {
|
|
8
|
+
raw += source[i] + source[i + 1];
|
|
9
|
+
i += 2;
|
|
10
|
+
}
|
|
11
|
+
else {
|
|
12
|
+
raw += source[i];
|
|
13
|
+
i++;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
if (i >= source.length) {
|
|
17
|
+
throw new ExpressionError("Unterminated string", { source, start, end: i });
|
|
18
|
+
}
|
|
19
|
+
raw += source[i];
|
|
20
|
+
i++;
|
|
21
|
+
return { raw, end: i };
|
|
22
|
+
}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { ExpressionError } from "../../errors/index.js";
|
|
2
|
+
import { isHexDigit } from "../predicates/is-hex-digit.js";
|
|
3
|
+
const MAX_CODE_POINT = 0x10ffff;
|
|
4
|
+
const HEX_CODE_POINT_SIZE = 5;
|
|
5
|
+
export function scanString(source, start) {
|
|
6
|
+
const quote = source[start];
|
|
7
|
+
let value = "";
|
|
8
|
+
let i = start + 1;
|
|
9
|
+
while (i < source.length && source[i] !== quote) {
|
|
10
|
+
if (source[i] === "\\") {
|
|
11
|
+
i++;
|
|
12
|
+
const escaped = source[i];
|
|
13
|
+
if (escaped === "n")
|
|
14
|
+
value += "\n";
|
|
15
|
+
else if (escaped === "t")
|
|
16
|
+
value += "\t";
|
|
17
|
+
else if (escaped === "r")
|
|
18
|
+
value += "\r";
|
|
19
|
+
else if (escaped === "\\")
|
|
20
|
+
value += "\\";
|
|
21
|
+
else if (escaped === "0")
|
|
22
|
+
value += "\0";
|
|
23
|
+
else if (escaped === "x") {
|
|
24
|
+
const hex = source.slice(i + 1, i + 3);
|
|
25
|
+
if (hex.length < 2 || !isHexDigit(hex[0]) || !isHexDigit(hex[1])) {
|
|
26
|
+
throw new ExpressionError("Invalid \\x escape", { source, start, end: i });
|
|
27
|
+
}
|
|
28
|
+
value += String.fromCharCode(parseInt(hex, 16));
|
|
29
|
+
i += 3;
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
else if (escaped === "u") {
|
|
33
|
+
if (source[i + 1] === "{") {
|
|
34
|
+
i += 2;
|
|
35
|
+
let hex = "";
|
|
36
|
+
while (i < source.length && source[i] !== "}" && source[i] !== quote) {
|
|
37
|
+
if (!isHexDigit(source[i])) {
|
|
38
|
+
throw new ExpressionError("Invalid \\u escape: non-hex digit", {
|
|
39
|
+
source,
|
|
40
|
+
start,
|
|
41
|
+
end: i,
|
|
42
|
+
});
|
|
43
|
+
}
|
|
44
|
+
hex += source[i];
|
|
45
|
+
i++;
|
|
46
|
+
}
|
|
47
|
+
if (i >= source.length || source[i] !== "}") {
|
|
48
|
+
throw new ExpressionError("Invalid \\u escape: missing closing brace", {
|
|
49
|
+
source,
|
|
50
|
+
start,
|
|
51
|
+
end: i,
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
if (hex.length === 0) {
|
|
55
|
+
throw new ExpressionError("Invalid \\u escape: empty code point", {
|
|
56
|
+
source,
|
|
57
|
+
start,
|
|
58
|
+
end: i,
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
const codePoint = parseInt(hex, 16);
|
|
62
|
+
if (codePoint > MAX_CODE_POINT) {
|
|
63
|
+
throw new ExpressionError("Invalid \\u escape: code point out of range", {
|
|
64
|
+
source,
|
|
65
|
+
start,
|
|
66
|
+
end: i,
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
value += String.fromCodePoint(codePoint);
|
|
70
|
+
i++;
|
|
71
|
+
continue;
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
const hex = source.slice(i + 1, i + HEX_CODE_POINT_SIZE);
|
|
75
|
+
if (hex.length < 4 || ![...hex].every(isHexDigit)) {
|
|
76
|
+
throw new ExpressionError("Invalid \\u escape", { source, start, end: i });
|
|
77
|
+
}
|
|
78
|
+
value += String.fromCharCode(parseInt(hex, 16));
|
|
79
|
+
i += HEX_CODE_POINT_SIZE;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
else {
|
|
84
|
+
value += escaped;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
else {
|
|
88
|
+
value += source[i];
|
|
89
|
+
}
|
|
90
|
+
i++;
|
|
91
|
+
}
|
|
92
|
+
if (i >= source.length) {
|
|
93
|
+
throw new ExpressionError("Unterminated string", { source, start, end: i });
|
|
94
|
+
}
|
|
95
|
+
i++;
|
|
96
|
+
// We keep the string literals in the token.
|
|
97
|
+
return { value: quote + value + quote, end: i };
|
|
98
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
import { ExpressionError } from "../../errors/index.js";
|
|
2
|
+
import { scanStringLiteral } from "./scan-string-literal.js";
|
|
3
|
+
export function scanTemplateLiteral(source, start) {
|
|
4
|
+
let raw = "`";
|
|
5
|
+
let i = start + 1;
|
|
6
|
+
while (i < source.length && source[i] !== "`") {
|
|
7
|
+
if (source[i] === "\\" && i + 1 < source.length) {
|
|
8
|
+
raw += source[i] + source[i + 1];
|
|
9
|
+
i += 2;
|
|
10
|
+
continue;
|
|
11
|
+
}
|
|
12
|
+
if (source[i] === "$" && i + 1 < source.length && source[i + 1] === "{") {
|
|
13
|
+
raw += "${";
|
|
14
|
+
i += 2;
|
|
15
|
+
let depth = 1;
|
|
16
|
+
while (i < source.length && depth > 0) {
|
|
17
|
+
const c = source[i];
|
|
18
|
+
if (c === '"' || c === "'") {
|
|
19
|
+
const result = scanStringLiteral(source, i);
|
|
20
|
+
raw += result.raw;
|
|
21
|
+
i = result.end;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (c === "`") {
|
|
25
|
+
const result = scanTemplateLiteral(source, i);
|
|
26
|
+
raw += result.raw;
|
|
27
|
+
i = result.end;
|
|
28
|
+
continue;
|
|
29
|
+
}
|
|
30
|
+
if (c === "{")
|
|
31
|
+
depth++;
|
|
32
|
+
else if (c === "}")
|
|
33
|
+
depth--;
|
|
34
|
+
if (depth > 0)
|
|
35
|
+
raw += c;
|
|
36
|
+
i++;
|
|
37
|
+
}
|
|
38
|
+
raw += "}";
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
raw += source[i];
|
|
42
|
+
i++;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
if (i >= source.length) {
|
|
46
|
+
throw new ExpressionError("Unterminated template literal", { source, start, end: i });
|
|
47
|
+
}
|
|
48
|
+
raw += "`";
|
|
49
|
+
i++;
|
|
50
|
+
return { raw, end: i };
|
|
51
|
+
}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { Token } from "../types.js";
|
|
2
|
+
import type { Plugin } from "../../plugin.js";
|
|
3
|
+
export declare function tokenizeSafe(source: string, plugins?: Plugin[], tokensizeWhitespace?: boolean): Token[];
|
|
4
|
+
export declare function tokenize(source: string, plugins?: Plugin[], tokensizeWhitespace?: boolean): Token[];
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
import { isDigit } from "../predicates/is-digit.js";
|
|
2
|
+
import { isAlpha } from "../predicates/is-alpha.js";
|
|
3
|
+
import { scanTemplateLiteral } from "./scan-template-literal.js";
|
|
4
|
+
import { scanNumber } from "./scan-number.js";
|
|
5
|
+
import { scanString } from "./scan-string.js";
|
|
6
|
+
import { scanIdentifier } from "./scan-identifier.js";
|
|
7
|
+
import { scanOperator } from "./scan-operator.js";
|
|
8
|
+
import { ExpressionError } from "../../errors/expression-error.js";
|
|
9
|
+
export function tokenizeSafe(source, plugins, tokensizeWhitespace = false) {
|
|
10
|
+
const tokens = [];
|
|
11
|
+
try {
|
|
12
|
+
let i = 0;
|
|
13
|
+
while (i < source.length) {
|
|
14
|
+
const ch = source[i];
|
|
15
|
+
if (/\s/.test(ch)) {
|
|
16
|
+
if (tokensizeWhitespace) {
|
|
17
|
+
tokens.push({
|
|
18
|
+
value: ch,
|
|
19
|
+
start: i,
|
|
20
|
+
end: i + 1,
|
|
21
|
+
type: "Whitespace",
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
i++;
|
|
25
|
+
continue;
|
|
26
|
+
}
|
|
27
|
+
const start = i;
|
|
28
|
+
let result = null;
|
|
29
|
+
if (plugins) {
|
|
30
|
+
for (const plugin of plugins) {
|
|
31
|
+
if (plugin.scan) {
|
|
32
|
+
result = plugin.scan(source, i);
|
|
33
|
+
if (result)
|
|
34
|
+
break;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
if (!result) {
|
|
39
|
+
if (isDigit(ch)) {
|
|
40
|
+
const r = scanNumber(source, i);
|
|
41
|
+
result = { type: "Number", value: r.value, end: r.end };
|
|
42
|
+
}
|
|
43
|
+
else if (ch === '"' || ch === "'") {
|
|
44
|
+
const r = scanString(source, i);
|
|
45
|
+
result = { type: "String", value: r.value, end: r.end };
|
|
46
|
+
}
|
|
47
|
+
else if (ch === "`") {
|
|
48
|
+
const r = scanTemplateLiteral(source, i);
|
|
49
|
+
result = { type: "TemplateLiteral", value: r.raw, end: r.end };
|
|
50
|
+
}
|
|
51
|
+
else if (isAlpha(ch)) {
|
|
52
|
+
result = scanIdentifier(source, i);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
result = scanOperator(source, i);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
i = result.end;
|
|
59
|
+
tokens.push({ type: result.type, value: result.value, start, end: i });
|
|
60
|
+
}
|
|
61
|
+
tokens.push({ type: "EOF", value: "", start: i, end: i });
|
|
62
|
+
}
|
|
63
|
+
catch (e) {
|
|
64
|
+
if (e instanceof ExpressionError) {
|
|
65
|
+
const error = {
|
|
66
|
+
type: "ExpressionError",
|
|
67
|
+
start: e.start,
|
|
68
|
+
end: e.end,
|
|
69
|
+
value: source.slice(e.start, e.end),
|
|
70
|
+
error: e,
|
|
71
|
+
};
|
|
72
|
+
tokens.push(error);
|
|
73
|
+
const left = source.slice(e.end);
|
|
74
|
+
if (left) {
|
|
75
|
+
const remaining = {
|
|
76
|
+
type: "Unparsed",
|
|
77
|
+
start: e.end,
|
|
78
|
+
end: source.length,
|
|
79
|
+
value: left,
|
|
80
|
+
};
|
|
81
|
+
tokens.push(remaining);
|
|
82
|
+
}
|
|
83
|
+
tokens.push({ type: "EOF", value: "", start: source.length, end: source.length });
|
|
84
|
+
return tokens;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
throw e;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return tokens;
|
|
91
|
+
}
|
|
92
|
+
export function tokenize(source, plugins, tokensizeWhitespace) {
|
|
93
|
+
const result = tokenizeSafe(source, plugins, tokensizeWhitespace);
|
|
94
|
+
if (result.at(-2)?.type === "ExpressionError")
|
|
95
|
+
throw result.at(-2).error;
|
|
96
|
+
if (result.at(-3)?.type === "ExpressionError")
|
|
97
|
+
throw result.at(-3).error;
|
|
98
|
+
return result;
|
|
99
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
export type BinaryOperator = "||" | "&&" | "==" | "!=" | "<" | ">" | "<=" | ">=" | "+" | "-" | "*" | "/" | "%" | "**" | "in" | "not";
|
|
2
|
+
export type UnaryOperator = "!" | "-" | "+";
|
|
3
|
+
export type BinaryExpressionOperator = Exclude<BinaryOperator, "not"> | "not in" | "??";
|
|
4
|
+
export type OperatorValue = BinaryOperator | UnaryOperator;
|
|
5
|
+
export type PunctuationValue = "(" | ")" | "[" | "]" | "{" | "}" | "," | "." | ":" | "?";
|
|
6
|
+
export interface Token {
|
|
7
|
+
readonly type: string;
|
|
8
|
+
readonly start: number;
|
|
9
|
+
readonly end: number;
|
|
10
|
+
readonly value: string;
|
|
11
|
+
readonly error?: unknown;
|
|
12
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { current, expect } from "./parser-context.js";
|
|
2
|
+
import { parseExpression } from "./parse-expression.js";
|
|
3
|
+
export function parseArrayLiteral(ctx) {
|
|
4
|
+
const start = expect(ctx, "Punctuation", "[").start;
|
|
5
|
+
const elements = [];
|
|
6
|
+
while (!(current(ctx).type === "Punctuation" && current(ctx).value === "]")) {
|
|
7
|
+
if (elements.length > 0)
|
|
8
|
+
expect(ctx, "Punctuation", ",");
|
|
9
|
+
if (current(ctx).type === "Punctuation" && current(ctx).value === "]")
|
|
10
|
+
break;
|
|
11
|
+
elements.push(parseExpression(ctx, 0));
|
|
12
|
+
}
|
|
13
|
+
const end = expect(ctx, "Punctuation", "]").end;
|
|
14
|
+
return { type: "ArrayLiteral", elements, start, end };
|
|
15
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
import { current, advance } from "./parser-context.js";
|
|
2
|
+
import { PRECEDENCE } from "./precedence.js";
|
|
3
|
+
import { parseUnary } from "./parse-unary.js";
|
|
4
|
+
export function parseExpression(ctx, minPrec = 0) {
|
|
5
|
+
let left = parseUnary(ctx);
|
|
6
|
+
while (true) {
|
|
7
|
+
const tok = current(ctx);
|
|
8
|
+
let prec;
|
|
9
|
+
// Core precedence (arithmetic only)
|
|
10
|
+
if (tok.type === "Operator") {
|
|
11
|
+
prec = PRECEDENCE[tok.value];
|
|
12
|
+
}
|
|
13
|
+
// Plugin precedence
|
|
14
|
+
if (prec === undefined && ctx.plugins) {
|
|
15
|
+
for (const plugin of ctx.plugins) {
|
|
16
|
+
if (plugin.infixPrecedence) {
|
|
17
|
+
prec = plugin.infixPrecedence(ctx);
|
|
18
|
+
if (prec !== undefined)
|
|
19
|
+
break;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (prec !== undefined && prec >= minPrec) {
|
|
24
|
+
// Try plugin parseInfix first (for ternary, pipe, membership, etc.)
|
|
25
|
+
if (ctx.plugins) {
|
|
26
|
+
let handled = false;
|
|
27
|
+
for (const plugin of ctx.plugins) {
|
|
28
|
+
if (plugin.parseInfix) {
|
|
29
|
+
const node = plugin.parseInfix(ctx, left, minPrec);
|
|
30
|
+
if (node) {
|
|
31
|
+
left = node;
|
|
32
|
+
handled = true;
|
|
33
|
+
break;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (handled)
|
|
38
|
+
continue;
|
|
39
|
+
}
|
|
40
|
+
// Default: standard binary expression
|
|
41
|
+
const op = advance(ctx);
|
|
42
|
+
const isRightAssoc = op.value === "**";
|
|
43
|
+
const nextMinPrec = isRightAssoc ? prec : prec + 1;
|
|
44
|
+
const right = parseExpression(ctx, nextMinPrec);
|
|
45
|
+
left = {
|
|
46
|
+
type: "BinaryExpression",
|
|
47
|
+
operator: op.value,
|
|
48
|
+
left,
|
|
49
|
+
right,
|
|
50
|
+
start: left.start,
|
|
51
|
+
end: right.end,
|
|
52
|
+
};
|
|
53
|
+
continue;
|
|
54
|
+
}
|
|
55
|
+
// No precedence — try plugin parseInfix (for things without precedence entry)
|
|
56
|
+
if (prec === undefined && ctx.plugins) {
|
|
57
|
+
let handled = false;
|
|
58
|
+
for (const plugin of ctx.plugins) {
|
|
59
|
+
if (plugin.parseInfix) {
|
|
60
|
+
const node = plugin.parseInfix(ctx, left, minPrec);
|
|
61
|
+
if (node) {
|
|
62
|
+
left = node;
|
|
63
|
+
handled = true;
|
|
64
|
+
break;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
if (handled)
|
|
69
|
+
continue;
|
|
70
|
+
}
|
|
71
|
+
break;
|
|
72
|
+
}
|
|
73
|
+
return left;
|
|
74
|
+
}
|