@1771technologies/lytenyte-pro 2.0.4-dev.3 → 2.1.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/README.md +54 -11
- package/css/components/expression-editor.css +106 -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/create-completion-provider.d.ts +10 -0
- package/dist/components/expressions-editor/create-completion-provider.js +391 -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 +33 -0
- package/dist/components/expressions-editor/expression-editor.d.ts +3 -0
- package/dist/components/expressions-editor/expression-editor.js +158 -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 +18 -0
- package/dist/components/expressions-editor/index.js +11 -0
- package/dist/components/expressions-editor/intellisence/completion-context.d.ts +17 -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 +47 -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 +20 -0
- package/dist/components/expressions-editor/types.d.ts +48 -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 +37 -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 +7 -0
- package/dist/expressions/index.js +5 -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 +101 -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/date-identifier.d.ts +4 -0
- package/dist/expressions/plugins/date-identifier.js +29 -0
- package/dist/expressions/plugins/date-literal.d.ts +2 -0
- package/dist/expressions/plugins/date-literal.js +71 -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/quoted-identifier.d.ts +2 -0
- package/dist/expressions/plugins/quoted-identifier.js +35 -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 +15 -0
- package/dist/expressions/plugins/standard.js +27 -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 +12 -5
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
import { getLineStart } from "./get-line-start.js";
|
|
3
|
+
import { getLineEnd } from "./get-line-end.js";
|
|
4
|
+
import { offsetToPosition } from "./offset-to-position.js";
|
|
5
|
+
/** Format an error message with source context, caret display, and position info. */
|
|
6
|
+
export function formatError(message, location, suggestion) {
|
|
7
|
+
const { source } = location;
|
|
8
|
+
const start = clampOffset(source, location.start);
|
|
9
|
+
const rawEnd = clampOffset(source, location.end);
|
|
10
|
+
const end = Math.max(start + 1, rawEnd);
|
|
11
|
+
const startPos = offsetToPosition(source, start);
|
|
12
|
+
const lineStart = getLineStart(source, start);
|
|
13
|
+
const lineEnd = getLineEnd(source, start);
|
|
14
|
+
const lineText = source.slice(lineStart, lineEnd);
|
|
15
|
+
const caretStart = start - lineStart;
|
|
16
|
+
const caretEnd = Math.min(end, lineEnd);
|
|
17
|
+
const caretLength = Math.max(1, caretEnd - start);
|
|
18
|
+
const gutter = `${startPos.line} | `;
|
|
19
|
+
const padding = " ".repeat(gutter.length + caretStart);
|
|
20
|
+
const carets = "^".repeat(caretLength);
|
|
21
|
+
let result = `${message}\n\n${gutter}${lineText}\n${padding}${carets}`;
|
|
22
|
+
if (suggestion) {
|
|
23
|
+
result += ` Did you mean "${suggestion}"?`;
|
|
24
|
+
}
|
|
25
|
+
result += `\n\nat line ${startPos.line}, column ${startPos.column} (offset ${start}-${end})`;
|
|
26
|
+
return result;
|
|
27
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getLineEnd(source: string, offset: number): number;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
const NEWLINE_CODE = 10;
|
|
3
|
+
export function getLineEnd(source, offset) {
|
|
4
|
+
let index = clampOffset(source, offset);
|
|
5
|
+
while (index < source.length && source.charCodeAt(index) !== NEWLINE_CODE)
|
|
6
|
+
index++;
|
|
7
|
+
return index;
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function getLineStart(source: string, offset: number): number;
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
const NEWLINE_CODE = 10;
|
|
3
|
+
export function getLineStart(source, offset) {
|
|
4
|
+
let index = clampOffset(source, offset);
|
|
5
|
+
while (index > 0 && source.charCodeAt(index - 1) !== NEWLINE_CODE)
|
|
6
|
+
index--;
|
|
7
|
+
return index;
|
|
8
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { SourcePosition, ErrorLocation } from "./types.js";
|
|
2
|
+
export { clampOffset } from "./clamp-offset.js";
|
|
3
|
+
export { getLineStart } from "./get-line-start.js";
|
|
4
|
+
export { getLineEnd } from "./get-line-end.js";
|
|
5
|
+
export { offsetToPosition } from "./offset-to-position.js";
|
|
6
|
+
export { formatError } from "./format-error.js";
|
|
7
|
+
export { ExpressionError } from "./expression-error.js";
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
export { getLineStart } from "./get-line-start.js";
|
|
3
|
+
export { getLineEnd } from "./get-line-end.js";
|
|
4
|
+
export { offsetToPosition } from "./offset-to-position.js";
|
|
5
|
+
export { formatError } from "./format-error.js";
|
|
6
|
+
export { ExpressionError } from "./expression-error.js";
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { clampOffset } from "./clamp-offset.js";
|
|
2
|
+
const NEWLINE_CODE = 10;
|
|
3
|
+
export function offsetToPosition(source, offset) {
|
|
4
|
+
const safeOffset = clampOffset(source, offset);
|
|
5
|
+
let line = 1;
|
|
6
|
+
let column = 1;
|
|
7
|
+
for (let index = 0; index < safeOffset; index++) {
|
|
8
|
+
if (source.charCodeAt(index) === NEWLINE_CODE) {
|
|
9
|
+
line++;
|
|
10
|
+
column = 1;
|
|
11
|
+
}
|
|
12
|
+
else {
|
|
13
|
+
column++;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return { line, column, offset: safeOffset };
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { BinaryExpression } from "../parser/types.js";
|
|
2
|
+
import type { Plugin } from "../plugin.js";
|
|
3
|
+
import type { RunOptions } from "./evaluate.js";
|
|
4
|
+
export declare function evaluateBinary(node: BinaryExpression, context: Record<string, unknown>, depth: number, plugins?: Plugin[], options?: RunOptions): unknown;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { evaluateNode } from "./evaluate.js";
|
|
2
|
+
export function evaluateBinary(node, context, depth, plugins, options) {
|
|
3
|
+
const left = evaluateNode(node.left, context, depth + 1, plugins, options);
|
|
4
|
+
const right = evaluateNode(node.right, context, depth + 1, plugins, options);
|
|
5
|
+
switch (node.operator) {
|
|
6
|
+
case "+":
|
|
7
|
+
return left + right;
|
|
8
|
+
case "-":
|
|
9
|
+
return left - right;
|
|
10
|
+
case "*":
|
|
11
|
+
return left * right;
|
|
12
|
+
case "/":
|
|
13
|
+
return left / right;
|
|
14
|
+
case "%":
|
|
15
|
+
return left % right;
|
|
16
|
+
case "**":
|
|
17
|
+
return left ** right;
|
|
18
|
+
default:
|
|
19
|
+
throw new Error(`Unknown binary operator: ${node.operator}`);
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { ASTNode } from "../parser/types.js";
|
|
2
|
+
import type { Token } from "../lexer/types.js";
|
|
3
|
+
import type { Plugin } from "../plugin.js";
|
|
4
|
+
export interface RunOptions {
|
|
5
|
+
undefinedIdentifierFallback?: unknown;
|
|
6
|
+
}
|
|
7
|
+
export declare class Evaluator {
|
|
8
|
+
private plugins?;
|
|
9
|
+
constructor(plugins?: Plugin[]);
|
|
10
|
+
run: (input: string | ASTNode, context?: Record<string, unknown>, options?: RunOptions) => unknown;
|
|
11
|
+
ast: (input: string) => ASTNode;
|
|
12
|
+
tokens: (input: string, tokensizeWhitespace?: boolean) => Token[];
|
|
13
|
+
tokensSafe: (input: string, tokensizeWhitespace?: boolean) => Token[];
|
|
14
|
+
}
|
|
15
|
+
export declare function evaluateNode(node: ASTNode, context: Record<string, unknown>, depth: number, plugins?: Plugin[], options?: RunOptions): unknown;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { parse } from "../parser/parse.js";
|
|
2
|
+
import { compile } from "../compiler/compile.js";
|
|
3
|
+
import { tokenize, tokenizeSafe } from "../lexer/tokenize/tokenize.js";
|
|
4
|
+
import { evaluateBinary } from "./evaluate-binary.js";
|
|
5
|
+
import { evaluateUnary } from "./evaluate-unary.js";
|
|
6
|
+
const MAX_DEPTH = 1000;
|
|
7
|
+
export class Evaluator {
|
|
8
|
+
plugins;
|
|
9
|
+
constructor(plugins) {
|
|
10
|
+
this.plugins = plugins;
|
|
11
|
+
}
|
|
12
|
+
run = (input, context = {}, options) => {
|
|
13
|
+
const node = typeof input === "string" ? compile(parse(input, 0, this.plugins), this.plugins) : input;
|
|
14
|
+
return evaluateNode(node, context, 0, this.plugins, options);
|
|
15
|
+
};
|
|
16
|
+
ast = (input) => {
|
|
17
|
+
return compile(parse(input, 0, this.plugins), this.plugins);
|
|
18
|
+
};
|
|
19
|
+
tokens = (input, tokensizeWhitespace) => {
|
|
20
|
+
return tokenize(input, this.plugins, tokensizeWhitespace);
|
|
21
|
+
};
|
|
22
|
+
tokensSafe = (input, tokensizeWhitespace) => {
|
|
23
|
+
return tokenizeSafe(input, this.plugins, tokensizeWhitespace);
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
export function evaluateNode(node, context, depth, plugins, options) {
|
|
27
|
+
if (depth > MAX_DEPTH) {
|
|
28
|
+
throw new Error("Maximum evaluation depth exceeded");
|
|
29
|
+
}
|
|
30
|
+
// Try plugin evaluation first
|
|
31
|
+
if (plugins) {
|
|
32
|
+
const evalFn = (n, ctx) => evaluateNode(n, ctx, depth + 1, plugins, options);
|
|
33
|
+
for (const plugin of plugins) {
|
|
34
|
+
if (plugin.evaluate) {
|
|
35
|
+
const result = plugin.evaluate(node, context, evalFn);
|
|
36
|
+
if (result !== null)
|
|
37
|
+
return result.value;
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
// Core built-in evaluation
|
|
42
|
+
switch (node.type) {
|
|
43
|
+
case "NumberLiteral":
|
|
44
|
+
return node.value;
|
|
45
|
+
case "Identifier": {
|
|
46
|
+
if (!(node.name in context)) {
|
|
47
|
+
if (options && "undefinedIdentifierFallback" in options)
|
|
48
|
+
return options.undefinedIdentifierFallback;
|
|
49
|
+
throw new Error(`Identifier "${node.name}" is not defined`);
|
|
50
|
+
}
|
|
51
|
+
return context[node.name];
|
|
52
|
+
}
|
|
53
|
+
case "BinaryExpression":
|
|
54
|
+
return evaluateBinary(node, context, depth, plugins, options);
|
|
55
|
+
case "UnaryExpression":
|
|
56
|
+
return evaluateUnary(node.operator, evaluateNode(node.operand, context, depth + 1, plugins, options));
|
|
57
|
+
case "SpreadElement":
|
|
58
|
+
throw new Error("Unexpected spread element outside of array literal");
|
|
59
|
+
default:
|
|
60
|
+
throw new Error(`Unknown node type: ${node.type}`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { Evaluator } from "./evaluator/evaluate.js";
|
|
2
|
+
export type { Plugin, EvalFn } from "./plugin.js";
|
|
3
|
+
export type { Token } from "./lexer/types.js";
|
|
4
|
+
export { accessPlugin, arrowsPlugin, booleansPlugin, collectionsPlugin, comparisonPlugin, logicalPlugin, membershipPlugin, pipePlugin, standardPlugins, stringsPlugin, ternaryPlugin, quotedIdentifierPlugin, } from "./plugins/standard.js";
|
|
5
|
+
export { createResolvedIdentifierPlugin } from "./plugins/resolved-identifier.js";
|
|
6
|
+
export { dateLiteralPlugin } from "./plugins/date-literal.js";
|
|
7
|
+
export { createDateIdentifierPlugin } from "./plugins/date-identifier.js";
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Evaluator } from "./evaluator/evaluate.js";
|
|
2
|
+
export { accessPlugin, arrowsPlugin, booleansPlugin, collectionsPlugin, comparisonPlugin, logicalPlugin, membershipPlugin, pipePlugin, standardPlugins, stringsPlugin, ternaryPlugin, quotedIdentifierPlugin, } from "./plugins/standard.js";
|
|
3
|
+
export { createResolvedIdentifierPlugin } from "./plugins/resolved-identifier.js";
|
|
4
|
+
export { dateLiteralPlugin } from "./plugins/date-literal.js";
|
|
5
|
+
export { createDateIdentifierPlugin } from "./plugins/date-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
|
+
}
|