flowquery 1.0.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.
Files changed (128) hide show
  1. package/.github/workflows/npm-publish.yml +30 -0
  2. package/.github/workflows/release.yml +84 -0
  3. package/CODE_OF_CONDUCT.md +10 -0
  4. package/FlowQueryLogoIcon.png +0 -0
  5. package/LICENSE +21 -0
  6. package/README.md +113 -0
  7. package/SECURITY.md +14 -0
  8. package/SUPPORT.md +13 -0
  9. package/docs/flowquery.min.js +1 -0
  10. package/docs/index.html +105 -0
  11. package/flowquery-vscode/.vscode-test.mjs +5 -0
  12. package/flowquery-vscode/.vscodeignore +13 -0
  13. package/flowquery-vscode/LICENSE +21 -0
  14. package/flowquery-vscode/README.md +11 -0
  15. package/flowquery-vscode/demo/FlowQueryVSCodeDemo.gif +0 -0
  16. package/flowquery-vscode/eslint.config.mjs +25 -0
  17. package/flowquery-vscode/extension.js +508 -0
  18. package/flowquery-vscode/flowQueryEngine/flowquery.min.js +1 -0
  19. package/flowquery-vscode/flowquery-worker.js +66 -0
  20. package/flowquery-vscode/images/FlowQueryLogoIcon.png +0 -0
  21. package/flowquery-vscode/jsconfig.json +13 -0
  22. package/flowquery-vscode/libs/page.css +53 -0
  23. package/flowquery-vscode/libs/table.css +13 -0
  24. package/flowquery-vscode/libs/tabs.css +66 -0
  25. package/flowquery-vscode/package-lock.json +2917 -0
  26. package/flowquery-vscode/package.json +51 -0
  27. package/flowquery-vscode/test/extension.test.js +196 -0
  28. package/flowquery-vscode/test/worker.test.js +25 -0
  29. package/flowquery-vscode/vsc-extension-quickstart.md +42 -0
  30. package/jest.config.js +11 -0
  31. package/package.json +28 -0
  32. package/queries/analyze_catfacts.cql +75 -0
  33. package/queries/azure_openai_completions.cql +13 -0
  34. package/queries/azure_openai_models.cql +9 -0
  35. package/queries/mock_pipeline.cql +84 -0
  36. package/queries/openai_completions.cql +15 -0
  37. package/queries/openai_models.cql +13 -0
  38. package/queries/test.cql +6 -0
  39. package/queries/tool_inference.cql +24 -0
  40. package/queries/wisdom.cql +6 -0
  41. package/queries/wisdom_letter_histogram.cql +8 -0
  42. package/src/compute/runner.ts +65 -0
  43. package/src/index.browser.ts +11 -0
  44. package/src/index.ts +12 -0
  45. package/src/io/command_line.ts +74 -0
  46. package/src/parsing/alias.ts +23 -0
  47. package/src/parsing/alias_option.ts +5 -0
  48. package/src/parsing/ast_node.ts +153 -0
  49. package/src/parsing/base_parser.ts +92 -0
  50. package/src/parsing/components/csv.ts +9 -0
  51. package/src/parsing/components/from.ts +12 -0
  52. package/src/parsing/components/headers.ts +12 -0
  53. package/src/parsing/components/json.ts +9 -0
  54. package/src/parsing/components/null.ts +9 -0
  55. package/src/parsing/components/post.ts +9 -0
  56. package/src/parsing/components/text.ts +9 -0
  57. package/src/parsing/context.ts +48 -0
  58. package/src/parsing/data_structures/associative_array.ts +43 -0
  59. package/src/parsing/data_structures/json_array.ts +31 -0
  60. package/src/parsing/data_structures/key_value_pair.ts +37 -0
  61. package/src/parsing/data_structures/lookup.ts +40 -0
  62. package/src/parsing/data_structures/range_lookup.ts +36 -0
  63. package/src/parsing/expressions/expression.ts +142 -0
  64. package/src/parsing/expressions/f_string.ts +26 -0
  65. package/src/parsing/expressions/identifier.ts +22 -0
  66. package/src/parsing/expressions/number.ts +40 -0
  67. package/src/parsing/expressions/operator.ts +179 -0
  68. package/src/parsing/expressions/reference.ts +42 -0
  69. package/src/parsing/expressions/string.ts +34 -0
  70. package/src/parsing/functions/aggregate_function.ts +58 -0
  71. package/src/parsing/functions/avg.ts +37 -0
  72. package/src/parsing/functions/collect.ts +44 -0
  73. package/src/parsing/functions/function.ts +60 -0
  74. package/src/parsing/functions/function_factory.ts +66 -0
  75. package/src/parsing/functions/join.ts +26 -0
  76. package/src/parsing/functions/predicate_function.ts +44 -0
  77. package/src/parsing/functions/predicate_function_factory.ts +15 -0
  78. package/src/parsing/functions/predicate_sum.ts +29 -0
  79. package/src/parsing/functions/rand.ts +13 -0
  80. package/src/parsing/functions/range.ts +18 -0
  81. package/src/parsing/functions/reducer_element.ts +10 -0
  82. package/src/parsing/functions/replace.ts +19 -0
  83. package/src/parsing/functions/round.ts +17 -0
  84. package/src/parsing/functions/size.ts +17 -0
  85. package/src/parsing/functions/split.ts +26 -0
  86. package/src/parsing/functions/stringify.ts +26 -0
  87. package/src/parsing/functions/sum.ts +31 -0
  88. package/src/parsing/functions/to_json.ts +17 -0
  89. package/src/parsing/functions/value_holder.ts +13 -0
  90. package/src/parsing/logic/case.ts +26 -0
  91. package/src/parsing/logic/else.ts +12 -0
  92. package/src/parsing/logic/end.ts +9 -0
  93. package/src/parsing/logic/then.ts +12 -0
  94. package/src/parsing/logic/when.ts +12 -0
  95. package/src/parsing/operations/aggregated_return.ts +18 -0
  96. package/src/parsing/operations/aggregated_with.ts +18 -0
  97. package/src/parsing/operations/group_by.ts +124 -0
  98. package/src/parsing/operations/limit.ts +22 -0
  99. package/src/parsing/operations/load.ts +92 -0
  100. package/src/parsing/operations/operation.ts +65 -0
  101. package/src/parsing/operations/projection.ts +18 -0
  102. package/src/parsing/operations/return.ts +43 -0
  103. package/src/parsing/operations/unwind.ts +32 -0
  104. package/src/parsing/operations/where.ts +38 -0
  105. package/src/parsing/operations/with.ts +20 -0
  106. package/src/parsing/parser.ts +762 -0
  107. package/src/parsing/token_to_node.ts +91 -0
  108. package/src/tokenization/keyword.ts +43 -0
  109. package/src/tokenization/operator.ts +25 -0
  110. package/src/tokenization/string_walker.ts +194 -0
  111. package/src/tokenization/symbol.ts +15 -0
  112. package/src/tokenization/token.ts +633 -0
  113. package/src/tokenization/token_mapper.ts +53 -0
  114. package/src/tokenization/token_type.ts +15 -0
  115. package/src/tokenization/tokenizer.ts +229 -0
  116. package/src/tokenization/trie.ts +117 -0
  117. package/src/utils/object_utils.ts +17 -0
  118. package/src/utils/string_utils.ts +114 -0
  119. package/tests/compute/runner.test.ts +498 -0
  120. package/tests/parsing/context.test.ts +27 -0
  121. package/tests/parsing/expression.test.ts +40 -0
  122. package/tests/parsing/parser.test.ts +434 -0
  123. package/tests/tokenization/token_mapper.test.ts +47 -0
  124. package/tests/tokenization/tokenizer.test.ts +67 -0
  125. package/tests/tokenization/trie.test.ts +20 -0
  126. package/tsconfig.json +15 -0
  127. package/typedoc.json +16 -0
  128. package/webpack.config.js +26 -0
@@ -0,0 +1,65 @@
1
+ import Operation from "../parsing/operations/operation";
2
+ import Parser from "../parsing/parser";
3
+
4
+ /**
5
+ * Executes a FlowQuery statement and retrieves the results.
6
+ *
7
+ * The Runner class parses a FlowQuery statement into an AST and executes it,
8
+ * managing the execution flow from the first operation to the final return statement.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const runner = new Runner("WITH 1 as x RETURN x");
13
+ * await runner.run();
14
+ * console.log(runner.results); // [{ x: 1 }]
15
+ * ```
16
+ */
17
+ class Runner {
18
+ private first: Operation;
19
+ private last: Operation;
20
+
21
+ /**
22
+ * Creates a new Runner instance and parses the FlowQuery statement.
23
+ *
24
+ * @param statement - The FlowQuery statement to execute
25
+ * @throws {Error} If the statement is null, empty, or contains syntax errors
26
+ */
27
+ constructor(statement: string | null = null) {
28
+ if(statement === null || statement === "") {
29
+ throw new Error("Statement cannot be null or empty");
30
+ }
31
+ const parser = new Parser();
32
+ const ast = parser.parse(statement);
33
+ this.first = ast.firstChild() as Operation;
34
+ this.last = ast.lastChild() as Operation;
35
+ }
36
+
37
+ /**
38
+ * Executes the parsed FlowQuery statement.
39
+ *
40
+ * @returns A promise that resolves when execution completes
41
+ * @throws {Error} If an error occurs during execution
42
+ */
43
+ public async run(): Promise<void> {
44
+ return new Promise<void>(async (resolve, reject) => {
45
+ try {
46
+ await this.first.run();
47
+ await this.first.finish();
48
+ resolve();
49
+ } catch (e) {
50
+ reject(e);
51
+ }
52
+ });
53
+ }
54
+
55
+ /**
56
+ * Gets the results from the executed statement.
57
+ *
58
+ * @returns The results from the last operation (typically a RETURN statement)
59
+ */
60
+ public get results(): any {
61
+ return this.last.results;
62
+ }
63
+ }
64
+
65
+ export default Runner;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * FlowQuery - A declarative query language for data processing pipelines.
3
+ *
4
+ * This is the main entry point for the FlowQuery in-browser usage.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import {default as FlowQuery} from "./compute/runner";
10
+
11
+ export default FlowQuery;
package/src/index.ts ADDED
@@ -0,0 +1,12 @@
1
+ /**
2
+ * FlowQuery - A declarative query language for data processing pipelines.
3
+ *
4
+ * This is the main entry point for the FlowQuery command-line interface.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import CommandLine from './io/command_line';
10
+
11
+ const commandLine = new CommandLine();
12
+ commandLine.loop();
@@ -0,0 +1,74 @@
1
+ import Runner from '../compute/runner';
2
+ import * as readline from 'readline';
3
+
4
+ /**
5
+ * Interactive command-line interface for FlowQuery.
6
+ *
7
+ * Provides a REPL (Read-Eval-Print Loop) for executing FlowQuery statements
8
+ * and displaying results.
9
+ *
10
+ * @example
11
+ * ```typescript
12
+ * const cli = new CommandLine();
13
+ * cli.loop(); // Starts interactive mode
14
+ * ```
15
+ */
16
+ class CommandLine {
17
+ private rl: readline.Interface;
18
+
19
+ /**
20
+ * Creates a new CommandLine interface.
21
+ */
22
+ constructor() {
23
+ this.rl = readline.createInterface({
24
+ input: process.stdin,
25
+ output: process.stdout
26
+ });
27
+ }
28
+
29
+ /**
30
+ * Starts the interactive command loop.
31
+ *
32
+ * Prompts the user for FlowQuery statements, executes them, and displays results.
33
+ * Type "exit" to quit the loop.
34
+ */
35
+ public loop() {
36
+ console.log('Welcome to FlowQuery! Type "exit" to quit.');
37
+ this.rl.setPrompt('> ');
38
+ this.rl.prompt();
39
+
40
+ this.rl.on('line', (input: string) => {
41
+ if (input === 'exit') {
42
+ this.rl.close();
43
+ return;
44
+ }
45
+ if(input.trim() === '') {
46
+ this.rl.prompt();
47
+ return;
48
+ }
49
+ try {
50
+ const runner = new Runner(input);
51
+ const promise = runner.run();
52
+ promise.then(
53
+ () => {
54
+ console.log(runner.results);
55
+ }
56
+ );
57
+ promise.catch(
58
+ (e) => console.error(e)
59
+ );
60
+ promise.finally(
61
+ () => this.rl.prompt()
62
+ );
63
+ } catch (e) {
64
+ console.error(e);
65
+ this.rl.prompt();
66
+ }
67
+ }).on('close', () => {
68
+ console.log('Exiting FlowQuery.');
69
+ process.exit(0);
70
+ });
71
+ }
72
+ }
73
+
74
+ export default CommandLine;
@@ -0,0 +1,23 @@
1
+ import ASTNode from "./ast_node";
2
+
3
+ class Alias extends ASTNode {
4
+ private alias: string;
5
+ constructor(alias: string) {
6
+ super();
7
+ this.alias = alias;
8
+ }
9
+
10
+ public toString(): string {
11
+ return `Alias (${this.alias})`;
12
+ }
13
+
14
+ public getAlias(): string {
15
+ return this.alias;
16
+ }
17
+
18
+ public value(): string {
19
+ return this.alias;
20
+ }
21
+ }
22
+
23
+ export default Alias;
@@ -0,0 +1,5 @@
1
+ export enum AliasOption {
2
+ NOT_ALLOWED = 0,
3
+ OPTIONAL = 1,
4
+ REQUIRED = 2,
5
+ };
@@ -0,0 +1,153 @@
1
+ /**
2
+ * Represents a node in the Abstract Syntax Tree (AST).
3
+ *
4
+ * The AST is a tree representation of the parsed FlowQuery statement structure.
5
+ * Each node can have children and maintains a reference to its parent.
6
+ *
7
+ * @example
8
+ * ```typescript
9
+ * const root = new ASTNode();
10
+ * const child = new ASTNode();
11
+ * root.addChild(child);
12
+ * ```
13
+ */
14
+ class ASTNode {
15
+ protected _parent: ASTNode | null = null;
16
+ protected children: ASTNode[] = [];
17
+
18
+ /**
19
+ * Adds a child node to this node and sets the child's parent reference.
20
+ *
21
+ * @param child - The child node to add
22
+ */
23
+ public addChild(child: ASTNode): void {
24
+ child._parent = this;
25
+ this.children.push(child);
26
+ }
27
+
28
+ /**
29
+ * Returns the first child node.
30
+ *
31
+ * @returns The first child node
32
+ * @throws {Error} If the node has no children
33
+ */
34
+ public firstChild(): ASTNode {
35
+ if(this.children.length === 0) {
36
+ throw new Error('Expected child');
37
+ }
38
+ return this.children[0];
39
+ }
40
+
41
+ /**
42
+ * Returns the last child node.
43
+ *
44
+ * @returns The last child node
45
+ * @throws {Error} If the node has no children
46
+ */
47
+ public lastChild(): ASTNode {
48
+ if(this.children.length === 0) {
49
+ throw new Error('Expected child');
50
+ }
51
+ return this.children[this.children.length - 1];
52
+ }
53
+
54
+ /**
55
+ * Returns all child nodes.
56
+ *
57
+ * @returns Array of child nodes
58
+ */
59
+ public getChildren(): ASTNode[] {
60
+ return this.children;
61
+ }
62
+
63
+ /**
64
+ * Returns the number of child nodes.
65
+ *
66
+ * @returns The count of children
67
+ */
68
+ public childCount(): number {
69
+ return this.children.length;
70
+ }
71
+
72
+ /**
73
+ * Returns the value of this node. Override in subclasses to provide specific values.
74
+ *
75
+ * @returns The node's value, or null if not applicable
76
+ */
77
+ public value(): any {
78
+ return null;
79
+ }
80
+
81
+ /**
82
+ * Checks if this node represents an operator.
83
+ *
84
+ * @returns True if this is an operator node, false otherwise
85
+ */
86
+ public isOperator(): boolean {
87
+ return false;
88
+ }
89
+
90
+ /**
91
+ * Checks if this node represents an operand (the opposite of an operator).
92
+ *
93
+ * @returns True if this is an operand node, false otherwise
94
+ */
95
+ public isOperand(): boolean {
96
+ return !this.isOperator();
97
+ }
98
+
99
+ /**
100
+ * Gets the operator precedence for this node. Higher values indicate higher precedence.
101
+ *
102
+ * @returns The precedence value (0 for non-operators)
103
+ */
104
+ public get precedence(): number {
105
+ return 0;
106
+ }
107
+
108
+ /**
109
+ * Indicates whether this operator is left-associative.
110
+ *
111
+ * @returns True if left-associative, false otherwise
112
+ */
113
+ public get leftAssociative(): boolean {
114
+ return false;
115
+ }
116
+
117
+ /**
118
+ * Prints a string representation of the AST tree starting from this node.
119
+ *
120
+ * @returns A formatted string showing the tree structure
121
+ */
122
+ public print(): string {
123
+ return Array.from(this._print(0)).join('\n');
124
+ }
125
+
126
+ /**
127
+ * Generator function for recursively printing the tree structure.
128
+ *
129
+ * @param indent - The current indentation level
130
+ * @yields Lines representing each node in the tree
131
+ */
132
+ private *_print(indent: number): Generator<string> {
133
+ if(indent === 0) {
134
+ yield this.constructor.name;
135
+ } else if(indent > 0) {
136
+ yield '-'.repeat(indent) + ` ${this.toString()}`;
137
+ }
138
+ for(const child of this.children) {
139
+ yield* child._print(indent + 1);
140
+ }
141
+ }
142
+
143
+ /**
144
+ * Returns a string representation of this node. Override in subclasses for custom formatting.
145
+ *
146
+ * @returns The string representation
147
+ */
148
+ protected toString(): string {
149
+ return this.constructor.name;
150
+ }
151
+ }
152
+
153
+ export default ASTNode;
@@ -0,0 +1,92 @@
1
+ import Token from "../tokenization/token";
2
+ import Tokenizer from "../tokenization/tokenizer";
3
+
4
+ /**
5
+ * Base class for parsers providing common token manipulation functionality.
6
+ *
7
+ * This class handles tokenization and provides utility methods for navigating
8
+ * through tokens, peeking ahead, and checking token sequences.
9
+ */
10
+ class BaseParser {
11
+ private tokens: Token[] = <Token[]>[];
12
+ private tokenIndex: number = 0;
13
+
14
+ /**
15
+ * Tokenizes a statement and initializes the token array.
16
+ *
17
+ * @param statement - The input statement to tokenize
18
+ */
19
+ protected tokenize(statement: string): void {
20
+ this.tokens = new Tokenizer(statement).tokenize();
21
+ this.tokenIndex = 0;
22
+ }
23
+
24
+ /**
25
+ * Advances to the next token in the sequence.
26
+ */
27
+ protected setNextToken(): void {
28
+ this.tokenIndex++;
29
+ }
30
+
31
+ /**
32
+ * Peeks at the next token without advancing the current position.
33
+ *
34
+ * @returns The next token, or null if at the end of the token stream
35
+ */
36
+ protected peek(): Token | null {
37
+ if(this.tokenIndex + 1 >= this.tokens.length) {
38
+ return null;
39
+ }
40
+ return this.tokens[this.tokenIndex + 1];
41
+ }
42
+
43
+ /**
44
+ * Checks if a sequence of tokens appears ahead in the token stream.
45
+ *
46
+ * @param tokens - The sequence of tokens to look for
47
+ * @param skipWhitespaceAndComments - Whether to skip whitespace and comments when matching
48
+ * @returns True if the token sequence is found ahead, false otherwise
49
+ */
50
+ protected ahead(tokens: Token[], skipWhitespaceAndComments: boolean = true): boolean {
51
+ let j = 0;
52
+ for(let i=this.tokenIndex; i<this.tokens.length; i++) {
53
+ if(skipWhitespaceAndComments && this.tokens[i].isWhitespaceOrComment()) {
54
+ continue;
55
+ }
56
+ if(!this.tokens[i].equals(tokens[j])) {
57
+ return false;
58
+ }
59
+ j++;
60
+ if(j === tokens.length) {
61
+ break;
62
+ }
63
+ }
64
+ return j === tokens.length;
65
+ }
66
+
67
+ /**
68
+ * Gets the current token.
69
+ *
70
+ * @returns The current token, or EOF if at the end
71
+ */
72
+ protected get token(): Token {
73
+ if(this.tokenIndex >= this.tokens.length) {
74
+ return Token.EOF;
75
+ }
76
+ return this.tokens[this.tokenIndex];
77
+ }
78
+
79
+ /**
80
+ * Gets the previous token.
81
+ *
82
+ * @returns The previous token, or EOF if at the beginning
83
+ */
84
+ protected get previousToken(): Token {
85
+ if(this.tokenIndex - 1 < 0) {
86
+ return Token.EOF;
87
+ }
88
+ return this.tokens[this.tokenIndex - 1];
89
+ }
90
+ }
91
+
92
+ export default BaseParser;
@@ -0,0 +1,9 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ class CSV extends ASTNode {
4
+ constructor() {
5
+ super();
6
+ }
7
+ }
8
+
9
+ export default CSV;
@@ -0,0 +1,12 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ class From extends ASTNode {
4
+ constructor() {
5
+ super()
6
+ }
7
+ public value(): string {
8
+ return this.children[0].value();
9
+ }
10
+ }
11
+
12
+ export default From;
@@ -0,0 +1,12 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ class Headers extends ASTNode {
4
+ constructor() {
5
+ super()
6
+ }
7
+ public value(): object {
8
+ return this.firstChild().value() as object || {};
9
+ }
10
+ }
11
+
12
+ export default Headers;
@@ -0,0 +1,9 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ class JSON extends ASTNode {
4
+ constructor() {
5
+ super();
6
+ }
7
+ }
8
+
9
+ export default JSON;
@@ -0,0 +1,9 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ class Null extends ASTNode {
4
+ constructor() {
5
+ super();
6
+ }
7
+ }
8
+
9
+ export default Null;
@@ -0,0 +1,9 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ class Post extends ASTNode {
4
+ constructor() {
5
+ super()
6
+ }
7
+ }
8
+
9
+ export default Post;
@@ -0,0 +1,9 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ class Text extends ASTNode {
4
+ constructor() {
5
+ super();
6
+ }
7
+ }
8
+
9
+ export default Text;
@@ -0,0 +1,48 @@
1
+ import ASTNode from "./ast_node";
2
+
3
+ /**
4
+ * Maintains a stack of AST nodes to track parsing context.
5
+ *
6
+ * Used during parsing to maintain the current context and check for specific node types
7
+ * in the parsing hierarchy, which helps with context-sensitive parsing decisions.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const context = new Context();
12
+ * context.push(node);
13
+ * const hasReturn = context.containsType(Return);
14
+ * ```
15
+ */
16
+ class Context {
17
+ private stack: ASTNode[] = [];
18
+
19
+ /**
20
+ * Pushes a node onto the context stack.
21
+ *
22
+ * @param node - The AST node to push
23
+ */
24
+ public push(node: ASTNode): void {
25
+ this.stack.push(node);
26
+ }
27
+
28
+ /**
29
+ * Pops the top node from the context stack.
30
+ *
31
+ * @returns The popped node, or undefined if the stack is empty
32
+ */
33
+ public pop(): ASTNode | undefined {
34
+ return this.stack.pop();
35
+ }
36
+
37
+ /**
38
+ * Checks if the stack contains a node of the specified type.
39
+ *
40
+ * @param type - The constructor of the node type to search for
41
+ * @returns True if a node of the specified type is found in the stack, false otherwise
42
+ */
43
+ public containsType(type: new (...args: any[]) => ASTNode): boolean {
44
+ return this.stack.some((v) => v instanceof type);
45
+ }
46
+ }
47
+
48
+ export default Context;
@@ -0,0 +1,43 @@
1
+ import ASTNode from "../ast_node";
2
+ import KeyValuePair from "./key_value_pair";
3
+
4
+ /**
5
+ * Represents an associative array (object/dictionary) in the AST.
6
+ *
7
+ * Associative arrays map string keys to values, similar to JSON objects.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * // For { name: "Alice", age: 30 }
12
+ * const obj = new AssociativeArray();
13
+ * obj.addKeyValue(new KeyValuePair("name", nameExpr));
14
+ * obj.addKeyValue(new KeyValuePair("age", ageExpr));
15
+ * ```
16
+ */
17
+ class AssociativeArray extends ASTNode {
18
+ /**
19
+ * Adds a key-value pair to the associative array.
20
+ *
21
+ * @param keyValuePair - The key-value pair to add
22
+ */
23
+ public addKeyValue(keyValuePair: KeyValuePair): void {
24
+ this.addChild(keyValuePair);
25
+ }
26
+
27
+ public toString(): string {
28
+ return 'AssociativeArray';
29
+ }
30
+ private *_value(): Iterable<Record<PropertyKey, any>> {
31
+ for(const child of this.children) {
32
+ const key_value = child as KeyValuePair;
33
+ yield {
34
+ [key_value.key]: key_value._value
35
+ };
36
+ }
37
+ }
38
+ public value(): Record<string, any> {
39
+ return Object.assign({}, ...this._value());
40
+ }
41
+ }
42
+
43
+ export default AssociativeArray;
@@ -0,0 +1,31 @@
1
+ import ASTNode from "../ast_node";
2
+
3
+ /**
4
+ * Represents a JSON array in the AST.
5
+ *
6
+ * JSON arrays are ordered collections of values.
7
+ *
8
+ * @example
9
+ * ```typescript
10
+ * // For [1, 2, 3]
11
+ * const arr = new JSONArray();
12
+ * arr.addValue(new Number("1"));
13
+ * arr.addValue(new Number("2"));
14
+ * arr.addValue(new Number("3"));
15
+ * ```
16
+ */
17
+ class JSONArray extends ASTNode {
18
+ /**
19
+ * Adds a value to the array.
20
+ *
21
+ * @param value - The AST node representing the value to add
22
+ */
23
+ public addValue(value: ASTNode): void {
24
+ this.addChild(value);
25
+ }
26
+ public value(): any[] {
27
+ return this.children.map(child => child.value());
28
+ }
29
+ }
30
+
31
+ export default JSONArray;
@@ -0,0 +1,37 @@
1
+ import ASTNode from "../ast_node";
2
+ import String from "../expressions/string";
3
+
4
+ /**
5
+ * Represents a key-value pair in an associative array.
6
+ *
7
+ * Used to build object literals in FlowQuery.
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * const kvp = new KeyValuePair("name", new String("Alice"));
12
+ * ```
13
+ */
14
+ class KeyValuePair extends ASTNode {
15
+ /**
16
+ * Creates a new key-value pair.
17
+ *
18
+ * @param key - The key string
19
+ * @param value - The AST node representing the value
20
+ */
21
+ constructor(key: string, value: ASTNode) {
22
+ super();
23
+ this.addChild(new String(key));
24
+ this.addChild(value);
25
+ }
26
+ public get key(): string {
27
+ return this.children[0].value();
28
+ }
29
+ public get _value(): any {
30
+ return this.children[1].value();
31
+ }
32
+ public toString(): string {
33
+ return `KeyValuePair`;
34
+ }
35
+ }
36
+
37
+ export default KeyValuePair;