@bpmn-io/feel-analyzer 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/README.md +102 -0
- package/dist/FeelAnalyzer.d.ts +59 -0
- package/dist/FeelAnalyzer.d.ts.map +1 -0
- package/dist/analyzers/inputs.d.ts +10 -0
- package/dist/analyzers/inputs.d.ts.map +1 -0
- package/dist/analyzers/utils.d.ts +62 -0
- package/dist/analyzers/utils.d.ts.map +1 -0
- package/dist/feel-analyzer-backup.d.ts +1 -0
- package/dist/feel-analyzer-backup.d.ts.map +1 -0
- package/dist/feel-analyzer.d.ts +15 -0
- package/dist/feel-analyzer.d.ts.map +1 -0
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +639 -0
- package/dist/index.js.map +1 -0
- package/dist/types.d.ts +56 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/utils/create-context.d.ts +4 -0
- package/dist/utils/create-context.d.ts.map +1 -0
- package/package.json +73 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Camunda Services GmbH
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
# FEEL Analyzer
|
|
2
|
+
|
|
3
|
+
> A library for analyzing FEEL (Friendly Enough Expression Language) expressions.
|
|
4
|
+
|
|
5
|
+
[](https://github.com/bpmn-io/feel-analyzer/actions?query=workflow%3ACI)
|
|
6
|
+
|
|
7
|
+
## Installation
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install @bpmn-io/feel-analyzer
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
## Usage
|
|
14
|
+
|
|
15
|
+
To get started, create a `FeelAnalyzer` instance:
|
|
16
|
+
|
|
17
|
+
```javascript
|
|
18
|
+
import { FeelAnalyzer } from '@bpmn-io/feel-analyzer';
|
|
19
|
+
|
|
20
|
+
const analyzer = new FeelAnalyzer();
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
Analyze a FEEL expression to extract input variables:
|
|
24
|
+
|
|
25
|
+
```javascript
|
|
26
|
+
const result = analyzer.analyzeExpression('x + y');
|
|
27
|
+
|
|
28
|
+
console.log(result.valid); // true
|
|
29
|
+
console.log(result.inputs);
|
|
30
|
+
// [
|
|
31
|
+
// { name: 'x' },
|
|
32
|
+
// { name: 'y' }
|
|
33
|
+
// ]
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Configure the FEEL dialect (expression or unary tests):
|
|
37
|
+
|
|
38
|
+
```javascript
|
|
39
|
+
const analyzer = new FeelAnalyzer({
|
|
40
|
+
dialect: 'unaryTests' // defaults to 'expression'
|
|
41
|
+
});
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Builtins
|
|
45
|
+
|
|
46
|
+
You can provide `builtins` and `reservedNameBuiltins` to exclude built-in names from input detection. Use [`@camunda/feel-builtins`](https://github.com/camunda/feel-builtins) to supply these:
|
|
47
|
+
|
|
48
|
+
```javascript
|
|
49
|
+
import { FeelAnalyzer } from '@bpmn-io/feel-analyzer';
|
|
50
|
+
import { builtins, reservedNameBuiltins } from '@camunda/feel-builtins';
|
|
51
|
+
|
|
52
|
+
const analyzer = new FeelAnalyzer({
|
|
53
|
+
dialect: 'expression',
|
|
54
|
+
parserDialect: 'camunda',
|
|
55
|
+
builtins,
|
|
56
|
+
reservedNameBuiltins
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
const result = analyzer.analyzeExpression('sum(orders.amount) > 100');
|
|
60
|
+
|
|
61
|
+
console.log(result.inputs);
|
|
62
|
+
// [
|
|
63
|
+
// {
|
|
64
|
+
// name: 'orders',
|
|
65
|
+
// type: 'List',
|
|
66
|
+
// entries: [
|
|
67
|
+
// { name: 'amount' }
|
|
68
|
+
// ]
|
|
69
|
+
// }
|
|
70
|
+
// ]
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
### Input Variables
|
|
74
|
+
|
|
75
|
+
The analyzer extracts input variables with type information, including nested structures. The data model is aligned with [variable-resolver](https://github.com/bpmn-io/variable-resolver):
|
|
76
|
+
|
|
77
|
+
```javascript
|
|
78
|
+
const result = analyzer.analyzeExpression('person.name = "John" and scores[1] > 10');
|
|
79
|
+
|
|
80
|
+
console.log(result.inputs);
|
|
81
|
+
// [
|
|
82
|
+
// {
|
|
83
|
+
// name: 'person',
|
|
84
|
+
// type: 'Context',
|
|
85
|
+
// entries: [
|
|
86
|
+
// { name: 'name' }
|
|
87
|
+
// ]
|
|
88
|
+
// },
|
|
89
|
+
// {
|
|
90
|
+
// name: 'scores',
|
|
91
|
+
// type: 'List'
|
|
92
|
+
// }
|
|
93
|
+
// ]
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Related
|
|
97
|
+
|
|
98
|
+
- [@bpmn-io/lezer-feel](https://github.com/bpmn-io/lezer-feel) - FEEL language definition for the [Lezer](https://lezer.codemirror.net/) parser system
|
|
99
|
+
|
|
100
|
+
## License
|
|
101
|
+
|
|
102
|
+
MIT
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
import { AnalysisOptions, AnalysisResult } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Analyzer for FEEL expressions
|
|
4
|
+
*/
|
|
5
|
+
export declare class FeelAnalyzer {
|
|
6
|
+
/**
|
|
7
|
+
* Analyze a FEEL expression
|
|
8
|
+
*
|
|
9
|
+
* @param expression - The FEEL expression to analyze
|
|
10
|
+
* @param options - Optional analysis configuration
|
|
11
|
+
* @returns Analysis result
|
|
12
|
+
*/
|
|
13
|
+
analyze(expression: string, options?: AnalysisOptions): AnalysisResult;
|
|
14
|
+
/**
|
|
15
|
+
* Get configured parser based on options
|
|
16
|
+
*/
|
|
17
|
+
private getConfiguredParser;
|
|
18
|
+
/**
|
|
19
|
+
* Extract built-in function names from builtins array
|
|
20
|
+
*/
|
|
21
|
+
private getBuiltinNames;
|
|
22
|
+
/**
|
|
23
|
+
* Strip backticks from identifier names
|
|
24
|
+
*/
|
|
25
|
+
private stripBackticks;
|
|
26
|
+
/**
|
|
27
|
+
* Extract needed input variables from the AST
|
|
28
|
+
*/
|
|
29
|
+
private extractNeededInputs;
|
|
30
|
+
/**
|
|
31
|
+
* Helper to collect path parts from a PathExpression node
|
|
32
|
+
*/
|
|
33
|
+
private collectPathPartsFromNode;
|
|
34
|
+
/**
|
|
35
|
+
* Extract expected input types from the AST
|
|
36
|
+
*/
|
|
37
|
+
private extractInputTypes;
|
|
38
|
+
/**
|
|
39
|
+
* Track item property accesses in filter expressions
|
|
40
|
+
*/
|
|
41
|
+
private trackFilterItemProperties;
|
|
42
|
+
/**
|
|
43
|
+
* Infer type from comparison with literals
|
|
44
|
+
*/
|
|
45
|
+
private inferTypeFromComparison;
|
|
46
|
+
/**
|
|
47
|
+
* Extract output type information from the AST
|
|
48
|
+
*/
|
|
49
|
+
private extractOutputType;
|
|
50
|
+
/**
|
|
51
|
+
* Analyze the output type of a specific node
|
|
52
|
+
*/
|
|
53
|
+
private analyzeNodeOutputType;
|
|
54
|
+
/**
|
|
55
|
+
* Infer type from a runtime value
|
|
56
|
+
*/
|
|
57
|
+
private inferTypeFromValue;
|
|
58
|
+
}
|
|
59
|
+
//# sourceMappingURL=FeelAnalyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FeelAnalyzer.d.ts","sourceRoot":"","sources":["../src/FeelAnalyzer.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,eAAe,EACf,cAAc,EAIf,MAAM,YAAY,CAAC;AAKpB;;GAEG;AACH,qBAAa,YAAY;IAEvB;;;;;;OAMG;IACH,OAAO,CAAC,UAAU,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,eAAe,GAAG,cAAc;IA+CtE;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAkC3B;;OAEG;IACH,OAAO,CAAC,eAAe;IAQvB;;OAEG;IACH,OAAO,CAAC,cAAc;IAItB;;OAEG;IACH,OAAO,CAAC,mBAAmB;IAoc3B;;OAEG;IACH,OAAO,CAAC,wBAAwB;IAmBhC;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAyXzB;;OAEG;IACH,OAAO,CAAC,yBAAyB;IA2EjC;;OAEG;IACH,OAAO,CAAC,uBAAuB;IAgC/B;;OAEG;IACH,OAAO,CAAC,iBAAiB;IAgBzB;;OAEG;IACH,OAAO,CAAC,qBAAqB;IAqI7B;;OAEG;IACH,OAAO,CAAC,kBAAkB;CAmB3B"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { SyntaxNode } from '@lezer/common';
|
|
2
|
+
import type { InputVariable } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Analyze an AST to extract input variables and infer their types.
|
|
5
|
+
*/
|
|
6
|
+
export declare function analyzeForInputs(node: SyntaxNode, source: string, builtinNames: Set<string>): {
|
|
7
|
+
inputs: InputVariable[];
|
|
8
|
+
hasErrors: boolean;
|
|
9
|
+
};
|
|
10
|
+
//# sourceMappingURL=inputs.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inputs.d.ts","sourceRoot":"","sources":["../../src/analyzers/inputs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AA8e9C;;GAEG;AACH,wBAAgB,gBAAgB,CAC5B,IAAI,EAAE,UAAU,EAChB,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,GAAG,CAAC,MAAM,CAAC,GAC1B;IAAE,MAAM,EAAE,aAAa,EAAE,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,CAejD"}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import type { SyntaxNode } from '@lezer/common';
|
|
2
|
+
import type { InputVariable } from '../types';
|
|
3
|
+
/**
|
|
4
|
+
* Strip backticks from identifier names
|
|
5
|
+
*/
|
|
6
|
+
export declare function stripBackticks(text: string): string;
|
|
7
|
+
/**
|
|
8
|
+
* Read the source text of a node, stripping backticks
|
|
9
|
+
*/
|
|
10
|
+
export declare function nodeText(node: SyntaxNode, source: string): string;
|
|
11
|
+
/**
|
|
12
|
+
* Check if a variable is defined in any active scope
|
|
13
|
+
*/
|
|
14
|
+
export declare function isInScope(varName: string, scopes: Set<string>[]): boolean;
|
|
15
|
+
/**
|
|
16
|
+
* Execute `fn` with a new scope pushed onto the scope stack,
|
|
17
|
+
* then pop it automatically. Returns the created scope so callers
|
|
18
|
+
* can add names to it during processing.
|
|
19
|
+
*/
|
|
20
|
+
export declare function withScope<T>(scopes: Set<string>[], initialNames: Iterable<string>, fn: (scope: Set<string>) => T): T;
|
|
21
|
+
/**
|
|
22
|
+
* Iterate over direct children of a node
|
|
23
|
+
*/
|
|
24
|
+
export declare function forEachChild(node: SyntaxNode, callback: (child: SyntaxNode) => void): void;
|
|
25
|
+
/**
|
|
26
|
+
* Collect path parts from a PathExpression node (e.g. `a.b.c` → ['a', 'b', 'c'])
|
|
27
|
+
*/
|
|
28
|
+
export declare function collectPathParts(node: SyntaxNode, source: string): string[];
|
|
29
|
+
/**
|
|
30
|
+
* Check if a PathExpression node has a Context as its base
|
|
31
|
+
*/
|
|
32
|
+
export declare function hasContextBase(node: SyntaxNode): boolean;
|
|
33
|
+
/**
|
|
34
|
+
* Extract key names from a Context node
|
|
35
|
+
*/
|
|
36
|
+
export declare function extractContextKeys(contextNode: SyntaxNode, source: string): string[];
|
|
37
|
+
/**
|
|
38
|
+
* Collect iteration variable names from a ForExpression or QuantifiedExpression
|
|
39
|
+
*/
|
|
40
|
+
export declare function collectIterationVariables(node: SyntaxNode, source: string): string[];
|
|
41
|
+
/**
|
|
42
|
+
* Collect formal parameter names from a FunctionDefinition
|
|
43
|
+
*/
|
|
44
|
+
export declare function collectFunctionParameters(node: SyntaxNode, source: string): string[];
|
|
45
|
+
/**
|
|
46
|
+
* Find a variable by name in an InputVariable array
|
|
47
|
+
*/
|
|
48
|
+
export declare function findVariable(variables: InputVariable[], name: string): InputVariable | undefined;
|
|
49
|
+
/**
|
|
50
|
+
* Find a variable by name, or create and insert it if missing
|
|
51
|
+
*/
|
|
52
|
+
export declare function findOrCreateVariable(variables: InputVariable[], name: string): InputVariable;
|
|
53
|
+
/**
|
|
54
|
+
* Build nested context entries from a dot path (e.g. ['a', 'b', 'c']).
|
|
55
|
+
* Creates intermediate context nodes as needed.
|
|
56
|
+
*/
|
|
57
|
+
export declare function buildNestedEntries(variables: InputVariable[], pathParts: string[]): void;
|
|
58
|
+
/**
|
|
59
|
+
* Sort entries recursively for deterministic output
|
|
60
|
+
*/
|
|
61
|
+
export declare function sortEntries(variable: InputVariable): void;
|
|
62
|
+
//# sourceMappingURL=utils.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../src/analyzers/utils.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,eAAe,CAAC;AAEhD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAE9C;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAEnD;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAEjE;AAID;;GAEG;AACH,wBAAgB,SAAS,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,GAAG,OAAO,CAEzE;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EACvB,MAAM,EAAE,GAAG,CAAC,MAAM,CAAC,EAAE,EACrB,YAAY,EAAE,QAAQ,CAAC,MAAM,CAAC,EAC9B,EAAE,EAAE,CAAC,KAAK,EAAE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAC9B,CAAC,CAMH;AAID;;GAEG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,GAAG,IAAI,CAM1F;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAU3E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAMxD;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAWpF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAYpF;AAED;;GAEG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,EAAE,UAAU,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,EAAE,CAYpF;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS,CAEhG;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,SAAS,EAAE,aAAa,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,aAAa,CAO5F;AAED;;;GAGG;AACH,wBAAgB,kBAAkB,CAC9B,SAAS,EAAE,aAAa,EAAE,EAC1B,SAAS,EAAE,MAAM,EAAE,GACpB,IAAI,CAgCN;AAED;;GAEG;AACH,wBAAgB,WAAW,CAAC,QAAQ,EAAE,aAAa,GAAG,IAAI,CAOzD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
//# sourceMappingURL=feel-analyzer-backup.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feel-analyzer-backup.d.ts","sourceRoot":"","sources":["../src/feel-analyzer-backup.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { parser } from '@bpmn-io/lezer-feel';
|
|
2
|
+
import type { AnalysisResult, Builtin } from './types';
|
|
3
|
+
export interface FeelAnalyzerOptions {
|
|
4
|
+
dialect: 'expression' | 'unaryTests';
|
|
5
|
+
parserDialect: undefined | 'camunda';
|
|
6
|
+
builtins: Builtin[];
|
|
7
|
+
reservedNameBuiltins: Builtin[];
|
|
8
|
+
}
|
|
9
|
+
export declare class FeelAnalyzer {
|
|
10
|
+
builtinNames: string[];
|
|
11
|
+
parser: typeof parser;
|
|
12
|
+
constructor(options?: Partial<FeelAnalyzerOptions>);
|
|
13
|
+
analyzeExpression(expression: string): AnalysisResult;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=feel-analyzer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"feel-analyzer.d.ts","sourceRoot":"","sources":["../src/feel-analyzer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAkB,MAAM,qBAAqB,CAAC;AAE7D,OAAO,KAAK,EAAE,cAAc,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAKvD,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,YAAY,GAAG,YAAY,CAAC;IACrC,aAAa,EAAE,SAAS,GAAG,SAAS,CAAC;IACrC,QAAQ,EAAE,OAAO,EAAE,CAAC;IACpB,oBAAoB,EAAE,OAAO,EAAE,CAAC;CACjC;AAED,qBAAa,YAAY;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,MAAM,EAAE,OAAO,MAAM,CAAC;gBAEV,OAAO,GAAE,OAAO,CAAC,mBAAmB,CAAM;IActD,iBAAiB,CAAC,UAAU,EAAE,MAAM,GAAG,cAAc;CAUtD"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAE/C,YAAY,EAAE,mBAAmB,EAAE,MAAM,iBAAiB,CAAC;AAC3D,YAAY,EAAE,OAAO,EAAE,cAAc,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,639 @@
|
|
|
1
|
+
import { trackVariables, parser } from '@bpmn-io/lezer-feel';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Strip backticks from identifier names
|
|
5
|
+
*/
|
|
6
|
+
function stripBackticks(text) {
|
|
7
|
+
return text.replace(/^`|`$/g, '');
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Read the source text of a node, stripping backticks
|
|
11
|
+
*/
|
|
12
|
+
function nodeText(node, source) {
|
|
13
|
+
return stripBackticks(source.substring(node.from, node.to));
|
|
14
|
+
}
|
|
15
|
+
// --- Scope helpers ---
|
|
16
|
+
/**
|
|
17
|
+
* Check if a variable is defined in any active scope
|
|
18
|
+
*/
|
|
19
|
+
function isInScope(varName, scopes) {
|
|
20
|
+
return scopes.some((scope) => scope.has(varName));
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Execute `fn` with a new scope pushed onto the scope stack,
|
|
24
|
+
* then pop it automatically. Returns the created scope so callers
|
|
25
|
+
* can add names to it during processing.
|
|
26
|
+
*/
|
|
27
|
+
function withScope(scopes, initialNames, fn) {
|
|
28
|
+
const scope = new Set(initialNames);
|
|
29
|
+
scopes.push(scope);
|
|
30
|
+
const result = fn(scope);
|
|
31
|
+
scopes.pop();
|
|
32
|
+
return result;
|
|
33
|
+
}
|
|
34
|
+
// --- AST traversal helpers ---
|
|
35
|
+
/**
|
|
36
|
+
* Iterate over direct children of a node
|
|
37
|
+
*/
|
|
38
|
+
function forEachChild(node, callback) {
|
|
39
|
+
let child = node.firstChild;
|
|
40
|
+
while (child) {
|
|
41
|
+
callback(child);
|
|
42
|
+
child = child.nextSibling;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Collect path parts from a PathExpression node (e.g. `a.b.c` → ['a', 'b', 'c'])
|
|
47
|
+
*/
|
|
48
|
+
function collectPathParts(node, source) {
|
|
49
|
+
const parts = [];
|
|
50
|
+
forEachChild(node, (child) => {
|
|
51
|
+
if (child.name === 'PathExpression') {
|
|
52
|
+
parts.push(...collectPathParts(child, source));
|
|
53
|
+
}
|
|
54
|
+
else if (child.name === 'VariableName') {
|
|
55
|
+
parts.push(nodeText(child, source));
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
return parts;
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Check if a PathExpression node has a Context as its base
|
|
62
|
+
*/
|
|
63
|
+
function hasContextBase(node) {
|
|
64
|
+
const firstChild = node.firstChild;
|
|
65
|
+
if (!firstChild)
|
|
66
|
+
return false;
|
|
67
|
+
if (firstChild.name === 'Context')
|
|
68
|
+
return true;
|
|
69
|
+
if (firstChild.name === 'PathExpression')
|
|
70
|
+
return hasContextBase(firstChild);
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Extract key names from a Context node
|
|
75
|
+
*/
|
|
76
|
+
function extractContextKeys(contextNode, source) {
|
|
77
|
+
const keys = [];
|
|
78
|
+
forEachChild(contextNode, (child) => {
|
|
79
|
+
if (child.name === 'ContextEntry') {
|
|
80
|
+
const keyName = child.getChild('Key')?.getChild('Name');
|
|
81
|
+
if (keyName) {
|
|
82
|
+
keys.push(nodeText(keyName, source));
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
return keys;
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* Collect iteration variable names from a ForExpression or QuantifiedExpression
|
|
90
|
+
*/
|
|
91
|
+
function collectIterationVariables(node, source) {
|
|
92
|
+
const vars = [];
|
|
93
|
+
const inExpressions = node.getChild('InExpressions');
|
|
94
|
+
if (inExpressions) {
|
|
95
|
+
forEachChild(inExpressions, (child) => {
|
|
96
|
+
if (child.name === 'InExpression') {
|
|
97
|
+
const id = child.getChild('Name')?.getChild('Identifier');
|
|
98
|
+
if (id)
|
|
99
|
+
vars.push(source.substring(id.from, id.to));
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
return vars;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* Collect formal parameter names from a FunctionDefinition
|
|
107
|
+
*/
|
|
108
|
+
function collectFunctionParameters(node, source) {
|
|
109
|
+
const params = [];
|
|
110
|
+
const formalParams = node.getChild('FormalParameters');
|
|
111
|
+
if (formalParams) {
|
|
112
|
+
forEachChild(formalParams, (child) => {
|
|
113
|
+
if (child.name === 'FormalParameter') {
|
|
114
|
+
const id = child.getChild('ParameterName')?.getChild('Name')?.getChild('Identifier');
|
|
115
|
+
if (id)
|
|
116
|
+
params.push(source.substring(id.from, id.to));
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
return params;
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Find a variable by name in an InputVariable array
|
|
124
|
+
*/
|
|
125
|
+
function findVariable(variables, name) {
|
|
126
|
+
return variables.find((v) => v.name === name);
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Find a variable by name, or create and insert it if missing
|
|
130
|
+
*/
|
|
131
|
+
function findOrCreateVariable(variables, name) {
|
|
132
|
+
let variable = findVariable(variables, name);
|
|
133
|
+
if (!variable) {
|
|
134
|
+
variable = { name };
|
|
135
|
+
variables.push(variable);
|
|
136
|
+
}
|
|
137
|
+
return variable;
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Build nested context entries from a dot path (e.g. ['a', 'b', 'c']).
|
|
141
|
+
* Creates intermediate context nodes as needed.
|
|
142
|
+
*/
|
|
143
|
+
function buildNestedEntries(variables, pathParts) {
|
|
144
|
+
const rootVar = findOrCreateVariable(variables, pathParts[0]);
|
|
145
|
+
if (pathParts.length <= 1)
|
|
146
|
+
return;
|
|
147
|
+
if (!rootVar.type) {
|
|
148
|
+
rootVar.type = 'Context';
|
|
149
|
+
rootVar.entries = rootVar.entries || [];
|
|
150
|
+
}
|
|
151
|
+
if (rootVar.type !== 'Context')
|
|
152
|
+
return;
|
|
153
|
+
let currentLevel = rootVar.entries;
|
|
154
|
+
for (let i = 1; i < pathParts.length; i++) {
|
|
155
|
+
const part = pathParts[i];
|
|
156
|
+
const isLast = i === pathParts.length - 1;
|
|
157
|
+
let entry = findVariable(currentLevel, part);
|
|
158
|
+
if (!entry) {
|
|
159
|
+
entry = isLast
|
|
160
|
+
? { name: part }
|
|
161
|
+
: { name: part, type: 'Context', entries: [] };
|
|
162
|
+
currentLevel.push(entry);
|
|
163
|
+
}
|
|
164
|
+
else if (!isLast && !entry.type) {
|
|
165
|
+
entry.type = 'Context';
|
|
166
|
+
entry.entries = entry.entries || [];
|
|
167
|
+
}
|
|
168
|
+
if (!isLast) {
|
|
169
|
+
entry.entries = entry.entries || [];
|
|
170
|
+
currentLevel = entry.entries;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
/**
|
|
175
|
+
* Sort entries recursively for deterministic output
|
|
176
|
+
*/
|
|
177
|
+
function sortEntries(variable) {
|
|
178
|
+
if (variable.entries) {
|
|
179
|
+
variable.entries.sort((a, b) => a.name.localeCompare(b.name));
|
|
180
|
+
for (const entry of variable.entries) {
|
|
181
|
+
sortEntries(entry);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
const ITERATION_KEYWORDS = new Set(['for', 'return', 'some', 'every', 'InExpressions', 'satisfies']);
|
|
187
|
+
/**
|
|
188
|
+
* Walk the AST collecting all external variable references (inputs).
|
|
189
|
+
* Local scopes (context keys, iteration vars, function params) are tracked
|
|
190
|
+
* so that locally-defined names are excluded from the result.
|
|
191
|
+
*/
|
|
192
|
+
function extractInputNames(node, source, builtinNames) {
|
|
193
|
+
const inputs = new Set();
|
|
194
|
+
const localScopes = [new Set()];
|
|
195
|
+
let hasErrors = false;
|
|
196
|
+
function isExternal(name, filterCtx) {
|
|
197
|
+
return !isInScope(name, localScopes)
|
|
198
|
+
&& !builtinNames.has(name)
|
|
199
|
+
&& !(filterCtx !== 'none' && name === 'item');
|
|
200
|
+
}
|
|
201
|
+
const collectInputs = (node, filterCtx = 'none') => {
|
|
202
|
+
const { name: nodeName } = node;
|
|
203
|
+
if (node.type.isError) {
|
|
204
|
+
hasErrors = true;
|
|
205
|
+
return;
|
|
206
|
+
}
|
|
207
|
+
if (nodeName === 'FunctionInvocation') {
|
|
208
|
+
const funcNameNode = node.getChild('VariableName');
|
|
209
|
+
if (funcNameNode) {
|
|
210
|
+
const funcName = nodeText(funcNameNode, source);
|
|
211
|
+
if (isExternal(funcName, filterCtx)) {
|
|
212
|
+
inputs.add(funcName);
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
forEachChild(node, (child) => {
|
|
216
|
+
if (child.name !== 'VariableName' && child.name !== '(' && child.name !== ')') {
|
|
217
|
+
collectInputs(child, filterCtx);
|
|
218
|
+
}
|
|
219
|
+
});
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
if (nodeName === 'PathExpression') {
|
|
223
|
+
if (hasContextBase(node)) {
|
|
224
|
+
forEachChild(node, (child) => collectInputs(child, filterCtx));
|
|
225
|
+
}
|
|
226
|
+
else {
|
|
227
|
+
const pathParts = collectPathParts(node, source);
|
|
228
|
+
if (pathParts.length > 0 && isExternal(pathParts[0], filterCtx)) {
|
|
229
|
+
inputs.add(pathParts.join('.'));
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
if (nodeName === 'VariableName'
|
|
235
|
+
&& node.parent?.name !== 'PathExpression'
|
|
236
|
+
&& node.parent?.name !== 'FunctionInvocation') {
|
|
237
|
+
const varName = nodeText(node, source);
|
|
238
|
+
const isImplicitFilterProp = filterCtx === 'variable-list' && varName !== 'item';
|
|
239
|
+
if (isExternal(varName, filterCtx) && !isImplicitFilterProp) {
|
|
240
|
+
inputs.add(varName);
|
|
241
|
+
}
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
if (nodeName === 'Context' && node.parent?.name !== 'List') {
|
|
245
|
+
withScope(localScopes, [], (scope) => {
|
|
246
|
+
forEachChild(node, (child) => {
|
|
247
|
+
if (child.name === 'ContextEntry') {
|
|
248
|
+
forEachChild(child, (entryChild) => {
|
|
249
|
+
if (entryChild.name !== 'Key')
|
|
250
|
+
collectInputs(entryChild, filterCtx);
|
|
251
|
+
});
|
|
252
|
+
const keyName = child.getChild('Key')?.getChild('Name');
|
|
253
|
+
if (keyName)
|
|
254
|
+
scope.add(nodeText(keyName, source));
|
|
255
|
+
}
|
|
256
|
+
});
|
|
257
|
+
});
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
if (nodeName === 'FilterExpression') {
|
|
261
|
+
let newFilterCtx = 'none';
|
|
262
|
+
const scopeNames = ['item'];
|
|
263
|
+
const listNode = node.getChild('List');
|
|
264
|
+
if (listNode) {
|
|
265
|
+
forEachChild(listNode, (child) => {
|
|
266
|
+
if (child.name === 'Context') {
|
|
267
|
+
scopeNames.push(...extractContextKeys(child, source));
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
newFilterCtx = 'list-literal';
|
|
271
|
+
}
|
|
272
|
+
else {
|
|
273
|
+
forEachChild(node, (child) => {
|
|
274
|
+
if (child.name === 'VariableName') {
|
|
275
|
+
collectInputs(child, 'none');
|
|
276
|
+
newFilterCtx = 'variable-list';
|
|
277
|
+
}
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
withScope(localScopes, scopeNames, () => {
|
|
281
|
+
forEachChild(node, (child) => {
|
|
282
|
+
if (child.name === 'Comparison' || child.name === 'Expression') {
|
|
283
|
+
collectInputs(child, newFilterCtx);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
});
|
|
287
|
+
return;
|
|
288
|
+
}
|
|
289
|
+
if (nodeName === 'ForExpression' || nodeName === 'QuantifiedExpression') {
|
|
290
|
+
const iterVars = collectIterationVariables(node, source);
|
|
291
|
+
const inExp = node.getChild('InExpressions');
|
|
292
|
+
if (inExp) {
|
|
293
|
+
forEachChild(inExp, (child) => {
|
|
294
|
+
if (child.name === 'InExpression') {
|
|
295
|
+
forEachChild(child, (innerChild) => {
|
|
296
|
+
if (innerChild.name !== 'Name' && innerChild.name !== 'in' && innerChild.name !== 'Identifier') {
|
|
297
|
+
collectInputs(innerChild, filterCtx);
|
|
298
|
+
}
|
|
299
|
+
});
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
}
|
|
303
|
+
withScope(localScopes, iterVars, () => {
|
|
304
|
+
forEachChild(node, (child) => {
|
|
305
|
+
if (!ITERATION_KEYWORDS.has(child.name)) {
|
|
306
|
+
collectInputs(child, 'none');
|
|
307
|
+
}
|
|
308
|
+
});
|
|
309
|
+
});
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (nodeName === 'FunctionDefinition') {
|
|
313
|
+
const params = collectFunctionParameters(node, source);
|
|
314
|
+
withScope(localScopes, params, () => {
|
|
315
|
+
if (hasErrors)
|
|
316
|
+
return;
|
|
317
|
+
const body = node.getChild('FunctionBody');
|
|
318
|
+
if (body)
|
|
319
|
+
collectInputs(body, 'none');
|
|
320
|
+
});
|
|
321
|
+
return;
|
|
322
|
+
}
|
|
323
|
+
forEachChild(node, (child) => collectInputs(child, filterCtx));
|
|
324
|
+
};
|
|
325
|
+
collectInputs(node);
|
|
326
|
+
return {
|
|
327
|
+
inputs: Array.from(inputs).sort(),
|
|
328
|
+
hasErrors,
|
|
329
|
+
};
|
|
330
|
+
}
|
|
331
|
+
/**
|
|
332
|
+
* Initialize input variables based on collected variable names.
|
|
333
|
+
* Dotted paths like "a.b.c" create nested context structures.
|
|
334
|
+
*/
|
|
335
|
+
function initializeInputVariables(collectedInputs) {
|
|
336
|
+
const variables = [];
|
|
337
|
+
for (const input of collectedInputs) {
|
|
338
|
+
buildNestedEntries(variables, input.split('.'));
|
|
339
|
+
}
|
|
340
|
+
return variables;
|
|
341
|
+
}
|
|
342
|
+
/**
|
|
343
|
+
* Check whether a node or its nested ArithmeticExpression children
|
|
344
|
+
* contain string or number literals.
|
|
345
|
+
*/
|
|
346
|
+
function checkLiteralsInNode(node) {
|
|
347
|
+
let hasString = false;
|
|
348
|
+
let hasNumber = false;
|
|
349
|
+
forEachChild(node, (child) => {
|
|
350
|
+
if (child.name === 'StringLiteral')
|
|
351
|
+
hasString = true;
|
|
352
|
+
else if (child.name === 'NumericLiteral')
|
|
353
|
+
hasNumber = true;
|
|
354
|
+
else if (child.name === 'ArithmeticExpression') {
|
|
355
|
+
const nested = checkLiteralsInNode(child);
|
|
356
|
+
hasString = hasString || nested.hasString;
|
|
357
|
+
hasNumber = hasNumber || nested.hasNumber;
|
|
358
|
+
}
|
|
359
|
+
});
|
|
360
|
+
return { hasString, hasNumber };
|
|
361
|
+
}
|
|
362
|
+
/**
|
|
363
|
+
* Infer a type for all variable references inside a node.
|
|
364
|
+
* Used when surrounding context (e.g. arithmetic with a number literal)
|
|
365
|
+
* implies the type of unknown variables.
|
|
366
|
+
*/
|
|
367
|
+
function inferTypeForVariablesInNode(node, source, inputs, localScopes, inferredType) {
|
|
368
|
+
if (node.name === 'VariableName' && node.parent?.name !== 'PathExpression') {
|
|
369
|
+
const varName = nodeText(node, source);
|
|
370
|
+
const variable = findVariable(inputs, varName);
|
|
371
|
+
if (!isInScope(varName, localScopes) && variable && !variable.type) {
|
|
372
|
+
variable.type = inferredType;
|
|
373
|
+
}
|
|
374
|
+
}
|
|
375
|
+
else if (node.name === 'PathExpression') {
|
|
376
|
+
const pathParts = collectPathParts(node, source);
|
|
377
|
+
if (pathParts.length > 0) {
|
|
378
|
+
const rootVar = pathParts[0];
|
|
379
|
+
const variable = findVariable(inputs, rootVar);
|
|
380
|
+
if (!isInScope(rootVar, localScopes) && variable && !variable.type) {
|
|
381
|
+
variable.type = inferredType;
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
else {
|
|
386
|
+
forEachChild(node, (child) => {
|
|
387
|
+
inferTypeForVariablesInNode(child, source, inputs, localScopes, inferredType);
|
|
388
|
+
});
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Track which properties are accessed on `item` inside a filter expression
|
|
393
|
+
* and record them as entries on the list variable.
|
|
394
|
+
*/
|
|
395
|
+
function trackFilterItemProperties(node, source, listVarName, inputs, localScopes) {
|
|
396
|
+
const listVar = listVarName ? findVariable(inputs, listVarName) : null;
|
|
397
|
+
if (!listVar)
|
|
398
|
+
return;
|
|
399
|
+
const visit = (node) => {
|
|
400
|
+
if (listVar.type !== 'List')
|
|
401
|
+
return;
|
|
402
|
+
if (node.name === 'PathExpression') {
|
|
403
|
+
const pathParts = [];
|
|
404
|
+
forEachChild(node, (child) => {
|
|
405
|
+
if (child.name === 'VariableName') {
|
|
406
|
+
pathParts.push(nodeText(child, source));
|
|
407
|
+
}
|
|
408
|
+
});
|
|
409
|
+
// `item.prop` → record 'prop' as an item entry
|
|
410
|
+
if (pathParts.length > 1 && pathParts[0] === 'item') {
|
|
411
|
+
const entries = listVar.entries || [];
|
|
412
|
+
for (let i = 1; i < pathParts.length; i++) {
|
|
413
|
+
if (!findVariable(entries, pathParts[i])) {
|
|
414
|
+
entries.push({ name: pathParts[i] });
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
listVar.entries = entries;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
else if (node.name === 'VariableName') {
|
|
421
|
+
const varName = nodeText(node, source);
|
|
422
|
+
// Standalone variable inside filter (not `item`, not local) → item entry
|
|
423
|
+
if (!isInScope(varName, localScopes) && varName !== 'item' && node.parent?.name !== 'PathExpression') {
|
|
424
|
+
const entries = listVar.entries || [];
|
|
425
|
+
if (!findVariable(entries, varName)) {
|
|
426
|
+
entries.push({ name: varName });
|
|
427
|
+
}
|
|
428
|
+
listVar.entries = entries;
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
forEachChild(node, visit);
|
|
432
|
+
};
|
|
433
|
+
visit(node);
|
|
434
|
+
}
|
|
435
|
+
/**
|
|
436
|
+
* Infer type of a variable from a direct comparison with a literal
|
|
437
|
+
* (e.g. `x > 5` → x is Number, `name = "foo"` → name is String).
|
|
438
|
+
*/
|
|
439
|
+
function inferTypeFromComparison(varNode, literalNode, source, inputs, localScopes) {
|
|
440
|
+
if (varNode.name !== 'VariableName')
|
|
441
|
+
return;
|
|
442
|
+
const varName = nodeText(varNode, source);
|
|
443
|
+
const variable = findVariable(inputs, varName);
|
|
444
|
+
if (isInScope(varName, localScopes) || !variable)
|
|
445
|
+
return;
|
|
446
|
+
if (variable.type)
|
|
447
|
+
return;
|
|
448
|
+
const literalTypeMap = {
|
|
449
|
+
NumericLiteral: 'Number',
|
|
450
|
+
StringLiteral: 'String',
|
|
451
|
+
BooleanLiteral: 'Boolean',
|
|
452
|
+
};
|
|
453
|
+
const inferred = literalTypeMap[literalNode.name];
|
|
454
|
+
if (inferred)
|
|
455
|
+
variable.type = inferred;
|
|
456
|
+
}
|
|
457
|
+
/**
|
|
458
|
+
* Recursively walk the AST to infer types for known input variables.
|
|
459
|
+
*/
|
|
460
|
+
function inferTypes(node, source, inputs, localScopes, filterCtx = 'none') {
|
|
461
|
+
const { name: nodeName } = node;
|
|
462
|
+
if (nodeName === 'PathExpression') {
|
|
463
|
+
const first = node.firstChild;
|
|
464
|
+
if (first?.name === 'Context' || first?.name === 'PathExpression') {
|
|
465
|
+
inferTypes(first, source, inputs, localScopes, filterCtx);
|
|
466
|
+
return;
|
|
467
|
+
}
|
|
468
|
+
const pathParts = collectPathParts(node, source);
|
|
469
|
+
if (pathParts.length > 0) {
|
|
470
|
+
const rootVar = pathParts[0];
|
|
471
|
+
if (!isInScope(rootVar, localScopes) && !(filterCtx !== 'none' && rootVar === 'item') && findVariable(inputs, rootVar)) {
|
|
472
|
+
buildNestedEntries(inputs, pathParts);
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
return;
|
|
476
|
+
}
|
|
477
|
+
if (nodeName === 'Context' && node.parent?.name !== 'List') {
|
|
478
|
+
withScope(localScopes, [], (scope) => {
|
|
479
|
+
forEachChild(node, (child) => {
|
|
480
|
+
if (child.name === 'ContextEntry') {
|
|
481
|
+
forEachChild(child, (innerChild) => {
|
|
482
|
+
if (innerChild.name !== 'Key') {
|
|
483
|
+
inferTypes(innerChild, source, inputs, localScopes, filterCtx);
|
|
484
|
+
}
|
|
485
|
+
});
|
|
486
|
+
const keyName = child.getChild('Key')?.getChild('Name');
|
|
487
|
+
if (keyName)
|
|
488
|
+
scope.add(nodeText(keyName, source));
|
|
489
|
+
}
|
|
490
|
+
});
|
|
491
|
+
});
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
if (nodeName === 'FilterExpression') {
|
|
495
|
+
let newFilterCtx = 'none';
|
|
496
|
+
let listVarName = null;
|
|
497
|
+
const scopeNames = ['item'];
|
|
498
|
+
const listNode = node.getChild('List');
|
|
499
|
+
if (listNode) {
|
|
500
|
+
forEachChild(listNode, (child) => {
|
|
501
|
+
if (child.name === 'Context') {
|
|
502
|
+
scopeNames.push(...extractContextKeys(child, source));
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
newFilterCtx = 'list-literal';
|
|
506
|
+
}
|
|
507
|
+
else {
|
|
508
|
+
forEachChild(node, (child) => {
|
|
509
|
+
if (child.name === 'VariableName') {
|
|
510
|
+
listVarName = nodeText(child, source);
|
|
511
|
+
const variable = findVariable(inputs, listVarName);
|
|
512
|
+
if (!isInScope(listVarName, localScopes) && variable) {
|
|
513
|
+
if (!variable.type) {
|
|
514
|
+
variable.type = 'List';
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
newFilterCtx = 'variable-list';
|
|
518
|
+
}
|
|
519
|
+
});
|
|
520
|
+
}
|
|
521
|
+
withScope(localScopes, scopeNames, () => {
|
|
522
|
+
forEachChild(node, (child) => {
|
|
523
|
+
if (child.name === 'Comparison' || child.name === 'Expression') {
|
|
524
|
+
trackFilterItemProperties(child, source, listVarName, inputs, localScopes);
|
|
525
|
+
inferTypes(child, source, inputs, localScopes, newFilterCtx);
|
|
526
|
+
}
|
|
527
|
+
});
|
|
528
|
+
});
|
|
529
|
+
return;
|
|
530
|
+
}
|
|
531
|
+
if (nodeName === 'Comparison') {
|
|
532
|
+
const operands = [];
|
|
533
|
+
forEachChild(node, (child) => {
|
|
534
|
+
if (child.name !== 'CompareOp')
|
|
535
|
+
operands.push(child);
|
|
536
|
+
});
|
|
537
|
+
if (operands.length === 2) {
|
|
538
|
+
inferTypeFromComparison(operands[0], operands[1], source, inputs, localScopes);
|
|
539
|
+
inferTypeFromComparison(operands[1], operands[0], source, inputs, localScopes);
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
if (nodeName === 'ArithmeticExpression') {
|
|
543
|
+
const { hasString, hasNumber } = checkLiteralsInNode(node);
|
|
544
|
+
const inferredType = hasString && !hasNumber ? 'String'
|
|
545
|
+
: !hasString && hasNumber ? 'Number'
|
|
546
|
+
: null;
|
|
547
|
+
if (inferredType) {
|
|
548
|
+
inferTypeForVariablesInNode(node, source, inputs, localScopes, inferredType);
|
|
549
|
+
}
|
|
550
|
+
forEachChild(node, (child) => {
|
|
551
|
+
if (!['ArithmeticExpression', 'ArithOp', 'NumericLiteral', 'StringLiteral'].includes(child.name)) {
|
|
552
|
+
inferTypes(child, source, inputs, localScopes, filterCtx);
|
|
553
|
+
}
|
|
554
|
+
});
|
|
555
|
+
return;
|
|
556
|
+
}
|
|
557
|
+
if (nodeName === 'ForExpression' || nodeName === 'QuantifiedExpression') {
|
|
558
|
+
const iterVars = collectIterationVariables(node, source);
|
|
559
|
+
const inExp = node.getChild('InExpressions');
|
|
560
|
+
if (inExp) {
|
|
561
|
+
forEachChild(inExp, (child) => {
|
|
562
|
+
if (child.name === 'InExpression') {
|
|
563
|
+
forEachChild(child, (innerChild) => {
|
|
564
|
+
if (!['Name', 'in', 'Identifier'].includes(innerChild.name)) {
|
|
565
|
+
inferTypes(innerChild, source, inputs, localScopes, filterCtx);
|
|
566
|
+
}
|
|
567
|
+
});
|
|
568
|
+
}
|
|
569
|
+
});
|
|
570
|
+
}
|
|
571
|
+
withScope(localScopes, iterVars, () => {
|
|
572
|
+
forEachChild(node, (child) => {
|
|
573
|
+
if (!ITERATION_KEYWORDS.has(child.name)) {
|
|
574
|
+
inferTypes(child, source, inputs, localScopes, 'none');
|
|
575
|
+
}
|
|
576
|
+
});
|
|
577
|
+
});
|
|
578
|
+
return;
|
|
579
|
+
}
|
|
580
|
+
if (nodeName === 'FunctionDefinition') {
|
|
581
|
+
const params = collectFunctionParameters(node, source);
|
|
582
|
+
withScope(localScopes, params, () => {
|
|
583
|
+
const body = node.getChild('FunctionBody');
|
|
584
|
+
if (body)
|
|
585
|
+
inferTypes(body, source, inputs, localScopes, 'none');
|
|
586
|
+
});
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
forEachChild(node, (child) => {
|
|
590
|
+
inferTypes(child, source, inputs, localScopes, filterCtx);
|
|
591
|
+
});
|
|
592
|
+
}
|
|
593
|
+
/**
|
|
594
|
+
* Analyze an AST to extract input variables and infer their types.
|
|
595
|
+
*/
|
|
596
|
+
function analyzeForInputs(node, source, builtinNames) {
|
|
597
|
+
const { inputs: collectedInputs, hasErrors } = extractInputNames(node, source, builtinNames);
|
|
598
|
+
const inputs = initializeInputVariables(collectedInputs);
|
|
599
|
+
const localScopes = [new Set()];
|
|
600
|
+
inferTypes(node, source, inputs, localScopes);
|
|
601
|
+
// Sort entries for deterministic output
|
|
602
|
+
for (const variable of inputs) {
|
|
603
|
+
sortEntries(variable);
|
|
604
|
+
}
|
|
605
|
+
inputs.sort((a, b) => a.name.localeCompare(b.name));
|
|
606
|
+
return { inputs, hasErrors };
|
|
607
|
+
}
|
|
608
|
+
|
|
609
|
+
function createContext(variables) {
|
|
610
|
+
return variables.reduce((context, variable) => {
|
|
611
|
+
context[variable.name] = () => { };
|
|
612
|
+
return context;
|
|
613
|
+
}, {});
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
class FeelAnalyzer {
|
|
617
|
+
constructor(options = {}) {
|
|
618
|
+
this.builtinNames = options.builtins?.map((builtin) => builtin.name) ?? [];
|
|
619
|
+
const config = {
|
|
620
|
+
top: options.dialect === 'unaryTests' ? 'UnaryTests' : 'Expression',
|
|
621
|
+
dialect: options.parserDialect,
|
|
622
|
+
};
|
|
623
|
+
if (options.reservedNameBuiltins && options.reservedNameBuiltins.length > 0) {
|
|
624
|
+
config.contextTracker = trackVariables(createContext(options.reservedNameBuiltins));
|
|
625
|
+
}
|
|
626
|
+
this.parser = parser.configure(config);
|
|
627
|
+
}
|
|
628
|
+
analyzeExpression(expression) {
|
|
629
|
+
const tree = this.parser.parse(expression);
|
|
630
|
+
const { inputs, hasErrors } = analyzeForInputs(tree.topNode, expression, new Set(this.builtinNames));
|
|
631
|
+
return {
|
|
632
|
+
valid: !hasErrors,
|
|
633
|
+
inputs,
|
|
634
|
+
};
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
export { FeelAnalyzer };
|
|
639
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../src/analyzers/utils.ts","../src/analyzers/inputs.ts","../src/utils/create-context.ts","../src/feel-analyzer.ts"],"sourcesContent":[null,null,null,null],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Built-in function definition
|
|
3
|
+
*/
|
|
4
|
+
export interface Builtin {
|
|
5
|
+
/**
|
|
6
|
+
* Function name
|
|
7
|
+
*/
|
|
8
|
+
name: string;
|
|
9
|
+
/**
|
|
10
|
+
* Function type
|
|
11
|
+
*/
|
|
12
|
+
type?: 'function';
|
|
13
|
+
/**
|
|
14
|
+
* Function parameters
|
|
15
|
+
*/
|
|
16
|
+
params?: Array<{
|
|
17
|
+
name: string;
|
|
18
|
+
}>;
|
|
19
|
+
/**
|
|
20
|
+
* Function documentation
|
|
21
|
+
*/
|
|
22
|
+
info?: string;
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Input variable information - describes an input variable and its structure.
|
|
26
|
+
* Aligned with the variable-resolver data model.
|
|
27
|
+
*/
|
|
28
|
+
export interface InputVariable {
|
|
29
|
+
/**
|
|
30
|
+
* The variable name
|
|
31
|
+
*/
|
|
32
|
+
name: string;
|
|
33
|
+
/**
|
|
34
|
+
* The expected type (e.g. 'Context', 'List', 'Number', 'String', 'Boolean').
|
|
35
|
+
* Omitted when the type cannot be inferred.
|
|
36
|
+
*/
|
|
37
|
+
type?: string;
|
|
38
|
+
/**
|
|
39
|
+
* For context or list inputs, nested entries describing the structure
|
|
40
|
+
*/
|
|
41
|
+
entries?: InputVariable[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Result of analyzing a FEEL expression
|
|
45
|
+
*/
|
|
46
|
+
export interface AnalysisResult {
|
|
47
|
+
/**
|
|
48
|
+
* Whether the expression is valid
|
|
49
|
+
*/
|
|
50
|
+
valid: boolean;
|
|
51
|
+
/**
|
|
52
|
+
* Input variables needed by the expression
|
|
53
|
+
*/
|
|
54
|
+
inputs?: InputVariable[];
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,WAAW,OAAO;IAEtB;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;OAEG;IACH,IAAI,CAAC,EAAE,UAAU,CAAC;IAElB;;OAEG;IACH,MAAM,CAAC,EAAE,KAAK,CAAC;QACb,IAAI,EAAE,MAAM,CAAC;KACd,CAAC,CAAC;IAEH;;OAEG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;GAGG;AACH,MAAM,WAAW,aAAa;IAE5B;;OAEG;IACH,IAAI,EAAE,MAAM,CAAC;IAEb;;;OAGG;IACH,IAAI,CAAC,EAAE,MAAM,CAAC;IAEd;;OAEG;IACH,OAAO,CAAC,EAAE,aAAa,EAAE,CAAC;CAC3B;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAE7B;;OAEG;IACH,KAAK,EAAE,OAAO,CAAC;IAEf;;OAEG;IACH,MAAM,CAAC,EAAE,aAAa,EAAE,CAAC;CAC1B"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create-context.d.ts","sourceRoot":"","sources":["../../src/utils/create-context.ts"],"names":[],"mappings":"AAAA,wBAAgB,aAAa,CAAC,SAAS,EAAE;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,EAAE,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CASpF"}
|
package/package.json
ADDED
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@bpmn-io/feel-analyzer",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Static FEEL expression analyzer",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"sideEffects": false,
|
|
8
|
+
"main": "./dist/index.js",
|
|
9
|
+
"module": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"import": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist",
|
|
19
|
+
"package.json"
|
|
20
|
+
],
|
|
21
|
+
"scripts": {
|
|
22
|
+
"all": "run-s lint test build",
|
|
23
|
+
"lint": "eslint .",
|
|
24
|
+
"test": "mocha --node-option import=tsx test/**/*.spec.ts",
|
|
25
|
+
"build": "rollup -c",
|
|
26
|
+
"prepare": "npm run build"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"@bpmn-io/lezer-feel": "^2.1.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@rollup/plugin-node-resolve": "^16.0.3",
|
|
33
|
+
"@rollup/plugin-typescript": "^12.3.0",
|
|
34
|
+
"@types/chai": "^5.2.3",
|
|
35
|
+
"@types/mocha": "^10.0.10",
|
|
36
|
+
"chai": "^6.2.2",
|
|
37
|
+
"eslint": "^9.39.2",
|
|
38
|
+
"eslint-plugin-bpmn-io": "^2.2.0",
|
|
39
|
+
"mocha": "^11.7.5",
|
|
40
|
+
"npm-run-all2": "^8.0.4",
|
|
41
|
+
"rollup": "^4.57.1",
|
|
42
|
+
"tslib": "^2.8.1",
|
|
43
|
+
"tsx": "^4.21.0",
|
|
44
|
+
"typescript": "^5.9.3",
|
|
45
|
+
"typescript-eslint": "^8.54.0"
|
|
46
|
+
},
|
|
47
|
+
"engines": {
|
|
48
|
+
"node": ">= 20"
|
|
49
|
+
},
|
|
50
|
+
"repository": {
|
|
51
|
+
"type": "git",
|
|
52
|
+
"url": "git+https://github.com/bpmn-io/feel-analyzer.git"
|
|
53
|
+
},
|
|
54
|
+
"homepage": "https://github.com/bpmn-io/feel-analyzer#readme",
|
|
55
|
+
"bugs": {
|
|
56
|
+
"url": "https://github.com/bpmn-io/feel-analyzer/issues"
|
|
57
|
+
},
|
|
58
|
+
"author": {
|
|
59
|
+
"name": "Simon Steinrücken",
|
|
60
|
+
"url": "https://github.com/Buckwich"
|
|
61
|
+
},
|
|
62
|
+
"contributors": [
|
|
63
|
+
{
|
|
64
|
+
"name": "bpmn.io contributors",
|
|
65
|
+
"url": "https://github.com/bpmn-io"
|
|
66
|
+
}
|
|
67
|
+
],
|
|
68
|
+
"keywords": [
|
|
69
|
+
"feel",
|
|
70
|
+
"bpmn-io",
|
|
71
|
+
"analyzer"
|
|
72
|
+
]
|
|
73
|
+
}
|