@flexiberry/berrycore 0.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/LICENSE +21 -0
- package/dist/adapter/cli-adapter.d.ts +37 -0
- package/dist/adapter/cli-adapter.js +119 -0
- package/dist/berry-core.d.ts +108 -0
- package/dist/berry-core.js +258 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.js +18 -0
- package/dist/interpreter/environment.d.ts +45 -0
- package/dist/interpreter/environment.js +96 -0
- package/dist/interpreter/errors.d.ts +16 -0
- package/dist/interpreter/errors.js +27 -0
- package/dist/interpreter/interpreter.d.ts +111 -0
- package/dist/interpreter/interpreter.js +682 -0
- package/dist/interpreter/interpreter.types.d.ts +182 -0
- package/dist/interpreter/interpreter.types.js +73 -0
- package/dist/parser/ast/ast.engine.d.ts +103 -0
- package/dist/parser/ast/ast.engine.js +526 -0
- package/dist/parser/ast/ast.types.d.ts +242 -0
- package/dist/parser/ast/ast.types.js +37 -0
- package/dist/parser/formatter/formatter.d.ts +44 -0
- package/dist/parser/formatter/formatter.js +214 -0
- package/dist/parser/tokenizer/reader/grammer/api.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/api.grammer.js +102 -0
- package/dist/parser/tokenizer/reader/grammer/capture.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/capture.grammer.js +21 -0
- package/dist/parser/tokenizer/reader/grammer/check.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/check.grammer.js +21 -0
- package/dist/parser/tokenizer/reader/grammer/comment.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/comment.grammer.js +13 -0
- package/dist/parser/tokenizer/reader/grammer/conditions.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/conditions.grammer.js +68 -0
- package/dist/parser/tokenizer/reader/grammer/input.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/input.grammer.js +17 -0
- package/dist/parser/tokenizer/reader/grammer/keyvalue.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/keyvalue.grammer.js +240 -0
- package/dist/parser/tokenizer/reader/grammer/link.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/link.grammer.js +17 -0
- package/dist/parser/tokenizer/reader/grammer/params.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/params.grammer.js +21 -0
- package/dist/parser/tokenizer/reader/grammer/step.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/step.grammer.js +25 -0
- package/dist/parser/tokenizer/reader/grammer/task.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/task.grammer.js +17 -0
- package/dist/parser/tokenizer/reader/grammer/var.grammer.d.ts +2 -0
- package/dist/parser/tokenizer/reader/grammer/var.grammer.js +47 -0
- package/dist/parser/tokenizer/reader/lexer.engine.d.ts +43 -0
- package/dist/parser/tokenizer/reader/lexer.engine.js +178 -0
- package/dist/parser/tokenizer/reader/lexer.types.d.ts +18 -0
- package/dist/parser/tokenizer/reader/lexer.types.js +1 -0
- package/dist/parser/tokenizer/token.d.ts +13 -0
- package/dist/parser/tokenizer/token.js +13 -0
- package/dist/parser/tokenizer/tokenType.d.ts +58 -0
- package/dist/parser/tokenizer/tokenType.js +64 -0
- package/dist/script/format-util.d.ts +33 -0
- package/dist/script/format-util.js +94 -0
- package/dist/script/postman.util.d.ts +88 -0
- package/dist/script/postman.util.js +176 -0
- package/dist/script/swagger.util.d.ts +80 -0
- package/dist/script/swagger.util.js +202 -0
- package/dist/util/store-util.d.ts +5 -0
- package/dist/util/store-util.js +22 -0
- package/package.json +25 -0
- package/readme.md +107 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Environment — Scoped Variable Store
|
|
3
|
+
*
|
|
4
|
+
* Maintains a chain of scopes: global → task → step.
|
|
5
|
+
* Each scope is a Map<string, RuntimeValue>.
|
|
6
|
+
* Lookup walks up the parent chain.
|
|
7
|
+
*/
|
|
8
|
+
import { VariableNotFoundError } from "./errors.js";
|
|
9
|
+
export class Environment {
|
|
10
|
+
store = new Map();
|
|
11
|
+
parent;
|
|
12
|
+
constructor(parent = null) {
|
|
13
|
+
this.parent = parent;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Declare a new variable in this scope.
|
|
17
|
+
* Overwrites if it already exists in this scope.
|
|
18
|
+
*/
|
|
19
|
+
declare(name, value) {
|
|
20
|
+
this.store.set(name, value);
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Look up a variable, walking up the scope chain.
|
|
24
|
+
* Throws VariableNotFoundError if not found in any scope.
|
|
25
|
+
*/
|
|
26
|
+
lookup(name) {
|
|
27
|
+
if (this.store.has(name)) {
|
|
28
|
+
return this.store.get(name);
|
|
29
|
+
}
|
|
30
|
+
if (this.parent) {
|
|
31
|
+
return this.parent.lookup(name);
|
|
32
|
+
}
|
|
33
|
+
throw new VariableNotFoundError(name);
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Try to look up a variable without throwing.
|
|
37
|
+
* Returns undefined if not found.
|
|
38
|
+
*/
|
|
39
|
+
tryLookup(name) {
|
|
40
|
+
if (this.store.has(name)) {
|
|
41
|
+
return this.store.get(name);
|
|
42
|
+
}
|
|
43
|
+
if (this.parent) {
|
|
44
|
+
return this.parent.tryLookup(name);
|
|
45
|
+
}
|
|
46
|
+
return undefined;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Assign a value to an existing variable in the nearest scope.
|
|
50
|
+
* If not found, declares it in this scope.
|
|
51
|
+
*/
|
|
52
|
+
assign(name, value) {
|
|
53
|
+
if (this.store.has(name)) {
|
|
54
|
+
this.store.set(name, value);
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (this.parent) {
|
|
58
|
+
try {
|
|
59
|
+
this.parent.lookup(name); // check if exists in parent
|
|
60
|
+
this.parent.assign(name, value);
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
// not in parent, declare locally
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
this.store.set(name, value);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Create a child scope inheriting from this environment.
|
|
71
|
+
*/
|
|
72
|
+
createChild() {
|
|
73
|
+
return new Environment(this);
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Get all variables in this scope (not parents).
|
|
77
|
+
*/
|
|
78
|
+
getOwnEntries() {
|
|
79
|
+
return this.store;
|
|
80
|
+
}
|
|
81
|
+
/**
|
|
82
|
+
* Get all variables including parent scopes (closest wins).
|
|
83
|
+
*/
|
|
84
|
+
getAllEntries() {
|
|
85
|
+
const merged = new Map();
|
|
86
|
+
if (this.parent) {
|
|
87
|
+
for (const [k, v] of this.parent.getAllEntries()) {
|
|
88
|
+
merged.set(k, v);
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
for (const [k, v] of this.store) {
|
|
92
|
+
merged.set(k, v);
|
|
93
|
+
}
|
|
94
|
+
return merged;
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interpreter Errors
|
|
3
|
+
*
|
|
4
|
+
* Strongly typed error classes with source position info.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RuntimeError extends Error {
|
|
7
|
+
readonly line: number;
|
|
8
|
+
readonly column: number;
|
|
9
|
+
constructor(message: string, line?: number, column?: number);
|
|
10
|
+
}
|
|
11
|
+
export declare class VariableNotFoundError extends RuntimeError {
|
|
12
|
+
constructor(name: string, line?: number, column?: number);
|
|
13
|
+
}
|
|
14
|
+
export declare class ApiNotFoundError extends RuntimeError {
|
|
15
|
+
constructor(name: string, line?: number, column?: number);
|
|
16
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Interpreter Errors
|
|
3
|
+
*
|
|
4
|
+
* Strongly typed error classes with source position info.
|
|
5
|
+
*/
|
|
6
|
+
export class RuntimeError extends Error {
|
|
7
|
+
line;
|
|
8
|
+
column;
|
|
9
|
+
constructor(message, line = 0, column = 0) {
|
|
10
|
+
super(`[RuntimeError at ${line}:${column}] ${message}`);
|
|
11
|
+
this.name = "RuntimeError";
|
|
12
|
+
this.line = line;
|
|
13
|
+
this.column = column;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
export class VariableNotFoundError extends RuntimeError {
|
|
17
|
+
constructor(name, line = 0, column = 0) {
|
|
18
|
+
super(`Variable '${name}' is not defined`, line, column);
|
|
19
|
+
this.name = "VariableNotFoundError";
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class ApiNotFoundError extends RuntimeError {
|
|
23
|
+
constructor(name, line = 0, column = 0) {
|
|
24
|
+
super(`API '${name}' is not defined`, line, column);
|
|
25
|
+
this.name = "ApiNotFoundError";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Berry Interpreter
|
|
3
|
+
*
|
|
4
|
+
* Walks the ProgramNode AST and executes the Berry program.
|
|
5
|
+
* Uses the Visitor pattern — one visit* method per AST node type.
|
|
6
|
+
*
|
|
7
|
+
* Architecture rules:
|
|
8
|
+
* - Interpreter only walks AST — no parsing, no tokenizing
|
|
9
|
+
* - Maintains environment for variable scoping
|
|
10
|
+
* - Emits typed events for status reporting
|
|
11
|
+
* - Uses IOAdapter for user input (CLI or UI)
|
|
12
|
+
*/
|
|
13
|
+
export interface FetchResponse {
|
|
14
|
+
readonly status: number;
|
|
15
|
+
readonly data: any;
|
|
16
|
+
readonly headers: Record<string, string>;
|
|
17
|
+
}
|
|
18
|
+
import { ProgramNode, KeyValuePairNode } from "../parser/ast/ast.types.js";
|
|
19
|
+
import { InterpreterEvent, EventListener, ExecutionCommand, ExecutionState, IOAdapter, TaskResult } from "./interpreter.types.js";
|
|
20
|
+
import { Environment } from "./environment.js";
|
|
21
|
+
export interface InterpreterOptions {
|
|
22
|
+
/** Timeout in ms for API calls (default: 30000) */
|
|
23
|
+
readonly apiTimeout: number;
|
|
24
|
+
/** Whether to continue on step failure (default: true) */
|
|
25
|
+
readonly continueOnError: boolean;
|
|
26
|
+
/** Dry run — don't make actual API calls (default: false) */
|
|
27
|
+
readonly dryRun: boolean;
|
|
28
|
+
/** Injected row of data for Input statements */
|
|
29
|
+
readonly inputRow?: Record<string, string>;
|
|
30
|
+
/** Provider for decrypting encrypted variables */
|
|
31
|
+
readonly decryptionProvider?: (encrypted: string) => Promise<string> | string;
|
|
32
|
+
}
|
|
33
|
+
interface ApiDefinition {
|
|
34
|
+
readonly method: string;
|
|
35
|
+
readonly name: string;
|
|
36
|
+
readonly title: string | null;
|
|
37
|
+
readonly url: string | null;
|
|
38
|
+
readonly headers: ReadonlyArray<KeyValuePairNode>;
|
|
39
|
+
readonly bodyType: string | null;
|
|
40
|
+
readonly bodyContent: string | null;
|
|
41
|
+
}
|
|
42
|
+
export declare class Interpreter {
|
|
43
|
+
private readonly ast;
|
|
44
|
+
private readonly options;
|
|
45
|
+
private readonly globalEnv;
|
|
46
|
+
private readonly apiRegistry;
|
|
47
|
+
private readonly listeners;
|
|
48
|
+
private ioAdapter;
|
|
49
|
+
private state;
|
|
50
|
+
private pendingCommand;
|
|
51
|
+
private pauseResolver;
|
|
52
|
+
/** Check if killed — bypasses TS narrowing since state changes async */
|
|
53
|
+
private isKilled;
|
|
54
|
+
constructor(ast: ProgramNode, options?: Partial<InterpreterOptions>);
|
|
55
|
+
/** Register an event listener */
|
|
56
|
+
on<E extends InterpreterEvent>(event: E, listener: EventListener<E>): Interpreter;
|
|
57
|
+
/** Set the IO adapter for user input, output, and execution control */
|
|
58
|
+
setIOAdapter(adapter: IOAdapter): Interpreter;
|
|
59
|
+
/**
|
|
60
|
+
* Send an execution command to the interpreter.
|
|
61
|
+
* Can be called externally (from adapter, UI, or programmatically).
|
|
62
|
+
*/
|
|
63
|
+
sendCommand(command: ExecutionCommand): void;
|
|
64
|
+
/** Get the current execution state */
|
|
65
|
+
getState(): ExecutionState;
|
|
66
|
+
/** Kill execution and clean up all resources */
|
|
67
|
+
kill(): void;
|
|
68
|
+
/** Execute the entire program */
|
|
69
|
+
execute(): Promise<TaskResult[]>;
|
|
70
|
+
private visitVarDeclaration;
|
|
71
|
+
private visitApiBlock;
|
|
72
|
+
private visitTask;
|
|
73
|
+
private visitStep;
|
|
74
|
+
private callApi;
|
|
75
|
+
private resolveParams;
|
|
76
|
+
private processCapture;
|
|
77
|
+
private processCheck;
|
|
78
|
+
private evaluateCondition;
|
|
79
|
+
private compareValues;
|
|
80
|
+
private resolveValue;
|
|
81
|
+
/**
|
|
82
|
+
* Resolve a dot-separated path from response data.
|
|
83
|
+
* e.g., "response.id" → data.id
|
|
84
|
+
*/
|
|
85
|
+
private resolveResponsePath;
|
|
86
|
+
/**
|
|
87
|
+
* Replace {{varName}} placeholders with values from the variable map.
|
|
88
|
+
*/
|
|
89
|
+
private interpolate;
|
|
90
|
+
private emit;
|
|
91
|
+
private emitSync;
|
|
92
|
+
private defaultDecryptionProvider;
|
|
93
|
+
/** Push a log line through the IO adapter (if set and supports logging) */
|
|
94
|
+
private pushLog;
|
|
95
|
+
/** Block execution while state is Paused */
|
|
96
|
+
private waitIfPaused;
|
|
97
|
+
/** Emit a state change event */
|
|
98
|
+
private emitStateChanged;
|
|
99
|
+
/**
|
|
100
|
+
* Clean up all resources.
|
|
101
|
+
* Called on kill — clears environment, registry, listeners, adapter.
|
|
102
|
+
*/
|
|
103
|
+
private cleanup;
|
|
104
|
+
/** Get the global environment (for inspection/testing) */
|
|
105
|
+
getEnvironment(): Environment;
|
|
106
|
+
/** Get the API registry (for inspection/testing) */
|
|
107
|
+
getApiRegistry(): ReadonlyMap<string, ApiDefinition>;
|
|
108
|
+
/** Prompt the user for input via the IOAdapter */
|
|
109
|
+
promptUser(message: string): Promise<string>;
|
|
110
|
+
}
|
|
111
|
+
export {};
|