@revisium/formula 0.4.0 → 0.6.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.
@@ -41,7 +41,75 @@ interface FormulaContext {
41
41
  }
42
42
  type FormulaResult = number | string | boolean | null;
43
43
 
44
- type ASTNode = string | number | boolean | null | [string, ...ASTNode[]];
44
+ type ASTNode = NumberLiteral | StringLiteral | BooleanLiteral | NullLiteral | Identifier | RootPath | RelativePath | ContextToken | BinaryOp | UnaryOp | TernaryOp | CallExpression | MemberExpression | IndexExpression | WildcardExpression;
45
+ interface NumberLiteral {
46
+ type: 'NumberLiteral';
47
+ value: number;
48
+ }
49
+ interface StringLiteral {
50
+ type: 'StringLiteral';
51
+ value: string;
52
+ }
53
+ interface BooleanLiteral {
54
+ type: 'BooleanLiteral';
55
+ value: boolean;
56
+ }
57
+ interface NullLiteral {
58
+ type: 'NullLiteral';
59
+ }
60
+ interface Identifier {
61
+ type: 'Identifier';
62
+ name: string;
63
+ }
64
+ interface RootPath {
65
+ type: 'RootPath';
66
+ path: string;
67
+ }
68
+ interface RelativePath {
69
+ type: 'RelativePath';
70
+ path: string;
71
+ }
72
+ interface ContextToken {
73
+ type: 'ContextToken';
74
+ name: string;
75
+ }
76
+ interface BinaryOp {
77
+ type: 'BinaryOp';
78
+ op: string;
79
+ left: ASTNode;
80
+ right: ASTNode;
81
+ }
82
+ interface UnaryOp {
83
+ type: 'UnaryOp';
84
+ op: string;
85
+ argument: ASTNode;
86
+ }
87
+ interface TernaryOp {
88
+ type: 'TernaryOp';
89
+ condition: ASTNode;
90
+ consequent: ASTNode;
91
+ alternate: ASTNode;
92
+ }
93
+ interface CallExpression {
94
+ type: 'CallExpression';
95
+ callee: ASTNode;
96
+ arguments: ASTNode[];
97
+ }
98
+ interface MemberExpression {
99
+ type: 'MemberExpression';
100
+ object: ASTNode;
101
+ property: string;
102
+ }
103
+ interface IndexExpression {
104
+ type: 'IndexExpression';
105
+ object: ASTNode;
106
+ index: ASTNode;
107
+ }
108
+ interface WildcardExpression {
109
+ type: 'WildcardExpression';
110
+ object: ASTNode;
111
+ }
112
+
45
113
  interface ParseResult {
46
114
  ast: ASTNode;
47
115
  dependencies: string[];
@@ -86,40 +154,4 @@ type SyntaxValidationResult = {
86
154
  };
87
155
  declare function validateFormulaSyntax(expression: string): SyntaxValidationResult;
88
156
 
89
- interface XFormulaInput {
90
- version: number;
91
- expression: string;
92
- }
93
- interface SchemaProperty {
94
- type?: string;
95
- 'x-formula'?: XFormulaInput;
96
- properties?: Record<string, SchemaProperty>;
97
- items?: SchemaProperty;
98
- [key: string]: unknown;
99
- }
100
- interface JsonSchema {
101
- type?: string;
102
- properties?: Record<string, SchemaProperty>;
103
- items?: SchemaProperty;
104
- [key: string]: unknown;
105
- }
106
- interface ExtractedFormula {
107
- fieldName: string;
108
- expression: string;
109
- fieldType: string;
110
- }
111
- declare function extractSchemaFormulas(schema: JsonSchema): ExtractedFormula[];
112
-
113
- interface FormulaValidationError {
114
- field: string;
115
- error: string;
116
- position?: number;
117
- }
118
- interface SchemaValidationResult {
119
- isValid: boolean;
120
- errors: FormulaValidationError[];
121
- }
122
- declare function validateFormulaAgainstSchema(expression: string, fieldName: string, schema: JsonSchema): FormulaValidationError | null;
123
- declare function validateSchemaFormulas(schema: JsonSchema): SchemaValidationResult;
124
-
125
- export { type ASTNode as A, type EvaluateContextOptions as E, type FieldTypes as F, type InferredType as I, type JsonSchema as J, type ParseResult as P, type SyntaxValidationResult as S, type XFormula as X, evaluateWithContext as a, parseExpression as b, type ParsedExpression as c, validateFormulaSyntax as d, evaluate as e, extractSchemaFormulas as f, type ExtractedFormula as g, validateFormulaAgainstSchema as h, inferFormulaType as i, validateSchemaFormulas as j, type FormulaValidationError as k, type SchemaValidationResult as l, type FormulaMinorVersion as m, type FormulaFeature as n, type FormulaAnalysis as o, parseFormula as p, type PathSegment as q, type ParsedPath as r, type PathValidationResult as s, type FormulaContext as t, type FormulaResult as u, validateSyntax as v };
157
+ export { type ASTNode as A, type EvaluateContextOptions as E, type FieldTypes as F, type InferredType as I, type ParseResult as P, type SyntaxValidationResult as S, type XFormula as X, evaluateWithContext as a, parseExpression as b, type ParsedExpression as c, validateFormulaSyntax as d, evaluate as e, type FormulaMinorVersion as f, type FormulaFeature as g, type FormulaAnalysis as h, inferFormulaType as i, type PathSegment as j, type ParsedPath as k, type PathValidationResult as l, type FormulaContext as m, type FormulaResult as n, parseFormula as p, validateSyntax as v };
@@ -41,7 +41,75 @@ interface FormulaContext {
41
41
  }
42
42
  type FormulaResult = number | string | boolean | null;
43
43
 
44
- type ASTNode = string | number | boolean | null | [string, ...ASTNode[]];
44
+ type ASTNode = NumberLiteral | StringLiteral | BooleanLiteral | NullLiteral | Identifier | RootPath | RelativePath | ContextToken | BinaryOp | UnaryOp | TernaryOp | CallExpression | MemberExpression | IndexExpression | WildcardExpression;
45
+ interface NumberLiteral {
46
+ type: 'NumberLiteral';
47
+ value: number;
48
+ }
49
+ interface StringLiteral {
50
+ type: 'StringLiteral';
51
+ value: string;
52
+ }
53
+ interface BooleanLiteral {
54
+ type: 'BooleanLiteral';
55
+ value: boolean;
56
+ }
57
+ interface NullLiteral {
58
+ type: 'NullLiteral';
59
+ }
60
+ interface Identifier {
61
+ type: 'Identifier';
62
+ name: string;
63
+ }
64
+ interface RootPath {
65
+ type: 'RootPath';
66
+ path: string;
67
+ }
68
+ interface RelativePath {
69
+ type: 'RelativePath';
70
+ path: string;
71
+ }
72
+ interface ContextToken {
73
+ type: 'ContextToken';
74
+ name: string;
75
+ }
76
+ interface BinaryOp {
77
+ type: 'BinaryOp';
78
+ op: string;
79
+ left: ASTNode;
80
+ right: ASTNode;
81
+ }
82
+ interface UnaryOp {
83
+ type: 'UnaryOp';
84
+ op: string;
85
+ argument: ASTNode;
86
+ }
87
+ interface TernaryOp {
88
+ type: 'TernaryOp';
89
+ condition: ASTNode;
90
+ consequent: ASTNode;
91
+ alternate: ASTNode;
92
+ }
93
+ interface CallExpression {
94
+ type: 'CallExpression';
95
+ callee: ASTNode;
96
+ arguments: ASTNode[];
97
+ }
98
+ interface MemberExpression {
99
+ type: 'MemberExpression';
100
+ object: ASTNode;
101
+ property: string;
102
+ }
103
+ interface IndexExpression {
104
+ type: 'IndexExpression';
105
+ object: ASTNode;
106
+ index: ASTNode;
107
+ }
108
+ interface WildcardExpression {
109
+ type: 'WildcardExpression';
110
+ object: ASTNode;
111
+ }
112
+
45
113
  interface ParseResult {
46
114
  ast: ASTNode;
47
115
  dependencies: string[];
@@ -86,40 +154,4 @@ type SyntaxValidationResult = {
86
154
  };
87
155
  declare function validateFormulaSyntax(expression: string): SyntaxValidationResult;
88
156
 
89
- interface XFormulaInput {
90
- version: number;
91
- expression: string;
92
- }
93
- interface SchemaProperty {
94
- type?: string;
95
- 'x-formula'?: XFormulaInput;
96
- properties?: Record<string, SchemaProperty>;
97
- items?: SchemaProperty;
98
- [key: string]: unknown;
99
- }
100
- interface JsonSchema {
101
- type?: string;
102
- properties?: Record<string, SchemaProperty>;
103
- items?: SchemaProperty;
104
- [key: string]: unknown;
105
- }
106
- interface ExtractedFormula {
107
- fieldName: string;
108
- expression: string;
109
- fieldType: string;
110
- }
111
- declare function extractSchemaFormulas(schema: JsonSchema): ExtractedFormula[];
112
-
113
- interface FormulaValidationError {
114
- field: string;
115
- error: string;
116
- position?: number;
117
- }
118
- interface SchemaValidationResult {
119
- isValid: boolean;
120
- errors: FormulaValidationError[];
121
- }
122
- declare function validateFormulaAgainstSchema(expression: string, fieldName: string, schema: JsonSchema): FormulaValidationError | null;
123
- declare function validateSchemaFormulas(schema: JsonSchema): SchemaValidationResult;
124
-
125
- export { type ASTNode as A, type EvaluateContextOptions as E, type FieldTypes as F, type InferredType as I, type JsonSchema as J, type ParseResult as P, type SyntaxValidationResult as S, type XFormula as X, evaluateWithContext as a, parseExpression as b, type ParsedExpression as c, validateFormulaSyntax as d, evaluate as e, extractSchemaFormulas as f, type ExtractedFormula as g, validateFormulaAgainstSchema as h, inferFormulaType as i, validateSchemaFormulas as j, type FormulaValidationError as k, type SchemaValidationResult as l, type FormulaMinorVersion as m, type FormulaFeature as n, type FormulaAnalysis as o, parseFormula as p, type PathSegment as q, type ParsedPath as r, type PathValidationResult as s, type FormulaContext as t, type FormulaResult as u, validateSyntax as v };
157
+ export { type ASTNode as A, type EvaluateContextOptions as E, type FieldTypes as F, type InferredType as I, type ParseResult as P, type SyntaxValidationResult as S, type XFormula as X, evaluateWithContext as a, parseExpression as b, type ParsedExpression as c, validateFormulaSyntax as d, evaluate as e, type FormulaMinorVersion as f, type FormulaFeature as g, type FormulaAnalysis as h, inferFormulaType as i, type PathSegment as j, type ParsedPath as k, type PathValidationResult as l, type FormulaContext as m, type FormulaResult as n, parseFormula as p, validateSyntax as v };
package/dist/index.cjs CHANGED
@@ -1,61 +1,143 @@
1
1
  'use strict';
2
2
 
3
- var chunkAGBOCJGV_cjs = require('./chunk-AGBOCJGV.cjs');
4
- require('./chunk-Q7SFCCGT.cjs');
3
+ var chunkGOMUE724_cjs = require('./chunk-GOMUE724.cjs');
5
4
 
5
+ // src/dependency-graph.ts
6
+ function buildDependencyGraph(dependencies) {
7
+ const nodes = /* @__PURE__ */ new Set();
8
+ const edges = /* @__PURE__ */ new Map();
9
+ for (const [node, deps] of Object.entries(dependencies)) {
10
+ nodes.add(node);
11
+ edges.set(node, new Set(deps));
12
+ for (const dep of deps) {
13
+ nodes.add(dep);
14
+ }
15
+ }
16
+ return { nodes, edges };
17
+ }
18
+ function detectCircularDependencies(graph) {
19
+ const visited = /* @__PURE__ */ new Set();
20
+ const recursionStack = /* @__PURE__ */ new Set();
21
+ const path = [];
22
+ for (const node of graph.nodes) {
23
+ if (!visited.has(node)) {
24
+ const cycle = dfsVisit(node, graph, visited, recursionStack, path);
25
+ if (cycle) {
26
+ return { hasCircular: true, cycle };
27
+ }
28
+ }
29
+ }
30
+ return { hasCircular: false, cycle: null };
31
+ }
32
+ function dfsVisit(node, graph, visited, recursionStack, path) {
33
+ visited.add(node);
34
+ recursionStack.add(node);
35
+ path.push(node);
36
+ const deps = graph.edges.get(node);
37
+ if (deps) {
38
+ for (const dep of deps) {
39
+ if (!visited.has(dep)) {
40
+ const cycle = dfsVisit(dep, graph, visited, recursionStack, path);
41
+ if (cycle) {
42
+ return cycle;
43
+ }
44
+ } else if (recursionStack.has(dep)) {
45
+ const cycleStart = path.indexOf(dep);
46
+ return [...path.slice(cycleStart), dep];
47
+ }
48
+ }
49
+ }
50
+ path.pop();
51
+ recursionStack.delete(node);
52
+ return null;
53
+ }
54
+ function getTopologicalOrder(graph) {
55
+ const circularCheck = detectCircularDependencies(graph);
56
+ if (circularCheck.hasCircular && circularCheck.cycle) {
57
+ return {
58
+ success: false,
59
+ order: [],
60
+ error: `Circular dependency detected: ${circularCheck.cycle.join(" -> ")}`
61
+ };
62
+ }
63
+ const inDegree = initializeInDegree(graph);
64
+ const queue = findZeroInDegreeNodes(inDegree);
65
+ const order = processQueue(queue, graph, inDegree);
66
+ order.reverse();
67
+ return { success: true, order };
68
+ }
69
+ function initializeInDegree(graph) {
70
+ const inDegree = /* @__PURE__ */ new Map();
71
+ for (const node of graph.nodes) {
72
+ inDegree.set(node, 0);
73
+ }
74
+ for (const deps of graph.edges.values()) {
75
+ for (const dep of deps) {
76
+ inDegree.set(dep, (inDegree.get(dep) ?? 0) + 1);
77
+ }
78
+ }
79
+ return inDegree;
80
+ }
81
+ function findZeroInDegreeNodes(inDegree) {
82
+ const result = [];
83
+ for (const [node, degree] of inDegree) {
84
+ if (degree === 0) {
85
+ result.push(node);
86
+ }
87
+ }
88
+ return result;
89
+ }
90
+ function processQueue(queue, graph, inDegree) {
91
+ const order = [];
92
+ let head = 0;
93
+ while (head < queue.length) {
94
+ const node = queue[head];
95
+ head++;
96
+ order.push(node);
97
+ const deps = graph.edges.get(node);
98
+ if (deps) {
99
+ for (const dep of deps) {
100
+ const newDegree = (inDegree.get(dep) ?? 0) - 1;
101
+ inDegree.set(dep, newDegree);
102
+ if (newDegree === 0) {
103
+ queue.push(dep);
104
+ }
105
+ }
106
+ }
107
+ }
108
+ return order;
109
+ }
6
110
 
7
-
8
- Object.defineProperty(exports, "buildDependencyGraph", {
9
- enumerable: true,
10
- get: function () { return chunkAGBOCJGV_cjs.buildDependencyGraph; }
11
- });
12
- Object.defineProperty(exports, "detectCircularDependencies", {
13
- enumerable: true,
14
- get: function () { return chunkAGBOCJGV_cjs.detectCircularDependencies; }
15
- });
16
111
  Object.defineProperty(exports, "evaluate", {
17
112
  enumerable: true,
18
- get: function () { return chunkAGBOCJGV_cjs.evaluate; }
113
+ get: function () { return chunkGOMUE724_cjs.evaluate; }
19
114
  });
20
115
  Object.defineProperty(exports, "evaluateWithContext", {
21
116
  enumerable: true,
22
- get: function () { return chunkAGBOCJGV_cjs.evaluateWithContext; }
23
- });
24
- Object.defineProperty(exports, "extractSchemaFormulas", {
25
- enumerable: true,
26
- get: function () { return chunkAGBOCJGV_cjs.extractSchemaFormulas; }
27
- });
28
- Object.defineProperty(exports, "getTopologicalOrder", {
29
- enumerable: true,
30
- get: function () { return chunkAGBOCJGV_cjs.getTopologicalOrder; }
117
+ get: function () { return chunkGOMUE724_cjs.evaluateWithContext; }
31
118
  });
32
119
  Object.defineProperty(exports, "inferFormulaType", {
33
120
  enumerable: true,
34
- get: function () { return chunkAGBOCJGV_cjs.inferFormulaType; }
121
+ get: function () { return chunkGOMUE724_cjs.inferFormulaType; }
35
122
  });
36
123
  Object.defineProperty(exports, "parseExpression", {
37
124
  enumerable: true,
38
- get: function () { return chunkAGBOCJGV_cjs.parseExpression; }
125
+ get: function () { return chunkGOMUE724_cjs.parseExpression; }
39
126
  });
40
127
  Object.defineProperty(exports, "parseFormula", {
41
128
  enumerable: true,
42
- get: function () { return chunkAGBOCJGV_cjs.parseFormula; }
43
- });
44
- Object.defineProperty(exports, "validateFormulaAgainstSchema", {
45
- enumerable: true,
46
- get: function () { return chunkAGBOCJGV_cjs.validateFormulaAgainstSchema; }
129
+ get: function () { return chunkGOMUE724_cjs.parseFormula; }
47
130
  });
48
131
  Object.defineProperty(exports, "validateFormulaSyntax", {
49
132
  enumerable: true,
50
- get: function () { return chunkAGBOCJGV_cjs.validateFormulaSyntax; }
51
- });
52
- Object.defineProperty(exports, "validateSchemaFormulas", {
53
- enumerable: true,
54
- get: function () { return chunkAGBOCJGV_cjs.validateSchemaFormulas; }
133
+ get: function () { return chunkGOMUE724_cjs.validateFormulaSyntax; }
55
134
  });
56
135
  Object.defineProperty(exports, "validateSyntax", {
57
136
  enumerable: true,
58
- get: function () { return chunkAGBOCJGV_cjs.validateSyntax; }
137
+ get: function () { return chunkGOMUE724_cjs.validateSyntax; }
59
138
  });
139
+ exports.buildDependencyGraph = buildDependencyGraph;
140
+ exports.detectCircularDependencies = detectCircularDependencies;
141
+ exports.getTopologicalOrder = getTopologicalOrder;
60
142
  //# sourceMappingURL=index.cjs.map
61
143
  //# sourceMappingURL=index.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.cjs"}
1
+ {"version":3,"sources":["../src/dependency-graph.ts"],"names":[],"mappings":";;;;;AA8BO,SAAS,qBACd,YAAA,EACiB;AACjB,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAY;AAC9B,EAAA,MAAM,KAAA,uBAAY,GAAA,EAAyB;AAE3C,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,IAAI,KAAK,MAAA,CAAO,OAAA,CAAQ,YAAY,CAAA,EAAG;AACvD,IAAA,KAAA,CAAM,IAAI,IAAI,CAAA;AACd,IAAA,KAAA,CAAM,GAAA,CAAI,IAAA,EAAM,IAAI,GAAA,CAAI,IAAI,CAAC,CAAA;AAE7B,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,KAAA,CAAM,IAAI,GAAG,CAAA;AAAA,IACf;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,OAAO,KAAA,EAAM;AACxB;AAYO,SAAS,2BACd,KAAA,EAC0B;AAC1B,EAAA,MAAM,OAAA,uBAAc,GAAA,EAAY;AAChC,EAAA,MAAM,cAAA,uBAAqB,GAAA,EAAY;AACvC,EAAA,MAAM,OAAiB,EAAC;AAExB,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC9B,IAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,IAAI,CAAA,EAAG;AACtB,MAAA,MAAM,QAAQ,QAAA,CAAS,IAAA,EAAM,KAAA,EAAO,OAAA,EAAS,gBAAgB,IAAI,CAAA;AACjE,MAAA,IAAI,KAAA,EAAO;AACT,QAAA,OAAO,EAAE,WAAA,EAAa,IAAA,EAAM,KAAA,EAAM;AAAA,MACpC;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,EAAE,WAAA,EAAa,KAAA,EAAO,KAAA,EAAO,IAAA,EAAK;AAC3C;AAEA,SAAS,QAAA,CACP,IAAA,EACA,KAAA,EACA,OAAA,EACA,gBACA,IAAA,EACiB;AACjB,EAAA,OAAA,CAAQ,IAAI,IAAI,CAAA;AAChB,EAAA,cAAA,CAAe,IAAI,IAAI,CAAA;AACvB,EAAA,IAAA,CAAK,KAAK,IAAI,CAAA;AAEd,EAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,GAAA,CAAI,IAAI,CAAA;AACjC,EAAA,IAAI,IAAA,EAAM;AACR,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,IAAI,CAAC,OAAA,CAAQ,GAAA,CAAI,GAAG,CAAA,EAAG;AACrB,QAAA,MAAM,QAAQ,QAAA,CAAS,GAAA,EAAK,KAAA,EAAO,OAAA,EAAS,gBAAgB,IAAI,CAAA;AAChE,QAAA,IAAI,KAAA,EAAO;AACT,UAAA,OAAO,KAAA;AAAA,QACT;AAAA,MACF,CAAA,MAAA,IAAW,cAAA,CAAe,GAAA,CAAI,GAAG,CAAA,EAAG;AAClC,QAAA,MAAM,UAAA,GAAa,IAAA,CAAK,OAAA,CAAQ,GAAG,CAAA;AACnC,QAAA,OAAO,CAAC,GAAG,IAAA,CAAK,KAAA,CAAM,UAAU,GAAG,GAAG,CAAA;AAAA,MACxC;AAAA,IACF;AAAA,EACF;AAEA,EAAA,IAAA,CAAK,GAAA,EAAI;AACT,EAAA,cAAA,CAAe,OAAO,IAAI,CAAA;AAC1B,EAAA,OAAO,IAAA;AACT;AAYO,SAAS,oBACd,KAAA,EACwB;AACxB,EAAA,MAAM,aAAA,GAAgB,2BAA2B,KAAK,CAAA;AACtD,EAAA,IAAI,aAAA,CAAc,WAAA,IAAe,aAAA,CAAc,KAAA,EAAO;AACpD,IAAA,OAAO;AAAA,MACL,OAAA,EAAS,KAAA;AAAA,MACT,OAAO,EAAC;AAAA,MACR,OAAO,CAAA,8BAAA,EAAiC,aAAA,CAAc,KAAA,CAAM,IAAA,CAAK,MAAM,CAAC,CAAA;AAAA,KAC1E;AAAA,EACF;AAEA,EAAA,MAAM,QAAA,GAAW,mBAAmB,KAAK,CAAA;AACzC,EAAA,MAAM,KAAA,GAAQ,sBAAsB,QAAQ,CAAA;AAC5C,EAAA,MAAM,KAAA,GAAQ,YAAA,CAAa,KAAA,EAAO,KAAA,EAAO,QAAQ,CAAA;AAEjD,EAAA,KAAA,CAAM,OAAA,EAAQ;AACd,EAAA,OAAO,EAAE,OAAA,EAAS,IAAA,EAAM,KAAA,EAAM;AAChC;AAEA,SAAS,mBAAmB,KAAA,EAA6C;AACvE,EAAA,MAAM,QAAA,uBAAe,GAAA,EAAoB;AAEzC,EAAA,KAAA,MAAW,IAAA,IAAQ,MAAM,KAAA,EAAO;AAC9B,IAAA,QAAA,CAAS,GAAA,CAAI,MAAM,CAAC,CAAA;AAAA,EACtB;AAEA,EAAA,KAAA,MAAW,IAAA,IAAQ,KAAA,CAAM,KAAA,CAAM,MAAA,EAAO,EAAG;AACvC,IAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,MAAA,QAAA,CAAS,IAAI,GAAA,EAAA,CAAM,QAAA,CAAS,IAAI,GAAG,CAAA,IAAK,KAAK,CAAC,CAAA;AAAA,IAChD;AAAA,EACF;AAEA,EAAA,OAAO,QAAA;AACT;AAEA,SAAS,sBAAsB,QAAA,EAAyC;AACtE,EAAA,MAAM,SAAmB,EAAC;AAC1B,EAAA,KAAA,MAAW,CAAC,IAAA,EAAM,MAAM,CAAA,IAAK,QAAA,EAAU;AACrC,IAAA,IAAI,WAAW,CAAA,EAAG;AAChB,MAAA,MAAA,CAAO,KAAK,IAAI,CAAA;AAAA,IAClB;AAAA,EACF;AACA,EAAA,OAAO,MAAA;AACT;AAEA,SAAS,YAAA,CACP,KAAA,EACA,KAAA,EACA,QAAA,EACU;AACV,EAAA,MAAM,QAAkB,EAAC;AACzB,EAAA,IAAI,IAAA,GAAO,CAAA;AAEX,EAAA,OAAO,IAAA,GAAO,MAAM,MAAA,EAAQ;AAC1B,IAAA,MAAM,IAAA,GAAO,MAAM,IAAI,CAAA;AACvB,IAAA,IAAA,EAAA;AACA,IAAA,KAAA,CAAM,KAAK,IAAI,CAAA;AAEf,IAAA,MAAM,IAAA,GAAO,KAAA,CAAM,KAAA,CAAM,GAAA,CAAI,IAAI,CAAA;AACjC,IAAA,IAAI,IAAA,EAAM;AACR,MAAA,KAAA,MAAW,OAAO,IAAA,EAAM;AACtB,QAAA,MAAM,SAAA,GAAA,CAAa,QAAA,CAAS,GAAA,CAAI,GAAG,KAAK,CAAA,IAAK,CAAA;AAC7C,QAAA,QAAA,CAAS,GAAA,CAAI,KAAK,SAAS,CAAA;AAC3B,QAAA,IAAI,cAAc,CAAA,EAAG;AACnB,UAAA,KAAA,CAAM,KAAK,GAAG,CAAA;AAAA,QAChB;AAAA,MACF;AAAA,IACF;AAAA,EACF;AAEA,EAAA,OAAO,KAAA;AACT","file":"index.cjs","sourcesContent":["export interface DependencyGraph {\n nodes: Set<string>;\n edges: Map<string, Set<string>>;\n}\n\nexport interface CircularDependencyResult {\n hasCircular: boolean;\n cycle: string[] | null;\n}\n\nexport interface TopologicalOrderResult {\n success: boolean;\n order: string[];\n error?: string;\n}\n\n/**\n * Build a dependency graph from a dependencies map\n *\n * @param dependencies - Map of node names to their dependencies\n * @returns Dependency graph with nodes and edges\n *\n * @example\n * const graph = buildDependencyGraph({\n * tax: ['price'],\n * total: ['price', 'tax']\n * });\n * // graph.edges.get('tax') = Set(['price'])\n * // graph.edges.get('total') = Set(['price', 'tax'])\n */\nexport function buildDependencyGraph(\n dependencies: Record<string, string[]>,\n): DependencyGraph {\n const nodes = new Set<string>();\n const edges = new Map<string, Set<string>>();\n\n for (const [node, deps] of Object.entries(dependencies)) {\n nodes.add(node);\n edges.set(node, new Set(deps));\n\n for (const dep of deps) {\n nodes.add(dep);\n }\n }\n\n return { nodes, edges };\n}\n\n/**\n * Detect first circular dependency in a dependency graph\n *\n * @param graph - Dependency graph\n * @returns Result with detected cycle (null if no cycle)\n *\n * @example\n * detectCircularDependencies(graph)\n * // { hasCircular: true, cycle: ['a', 'b', 'c', 'a'] }\n */\nexport function detectCircularDependencies(\n graph: DependencyGraph,\n): CircularDependencyResult {\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n const path: string[] = [];\n\n for (const node of graph.nodes) {\n if (!visited.has(node)) {\n const cycle = dfsVisit(node, graph, visited, recursionStack, path);\n if (cycle) {\n return { hasCircular: true, cycle };\n }\n }\n }\n\n return { hasCircular: false, cycle: null };\n}\n\nfunction dfsVisit(\n node: string,\n graph: DependencyGraph,\n visited: Set<string>,\n recursionStack: Set<string>,\n path: string[],\n): string[] | null {\n visited.add(node);\n recursionStack.add(node);\n path.push(node);\n\n const deps = graph.edges.get(node);\n if (deps) {\n for (const dep of deps) {\n if (!visited.has(dep)) {\n const cycle = dfsVisit(dep, graph, visited, recursionStack, path);\n if (cycle) {\n return cycle;\n }\n } else if (recursionStack.has(dep)) {\n const cycleStart = path.indexOf(dep);\n return [...path.slice(cycleStart), dep];\n }\n }\n }\n\n path.pop();\n recursionStack.delete(node);\n return null;\n}\n\n/**\n * Get topological order for formula evaluation\n *\n * @param graph - Dependency graph\n * @returns Ordered list of field names for evaluation\n *\n * @example\n * getTopologicalOrder(graph)\n * // { success: true, order: ['price', 'tax', 'total'] }\n */\nexport function getTopologicalOrder(\n graph: DependencyGraph,\n): TopologicalOrderResult {\n const circularCheck = detectCircularDependencies(graph);\n if (circularCheck.hasCircular && circularCheck.cycle) {\n return {\n success: false,\n order: [],\n error: `Circular dependency detected: ${circularCheck.cycle.join(' -> ')}`,\n };\n }\n\n const inDegree = initializeInDegree(graph);\n const queue = findZeroInDegreeNodes(inDegree);\n const order = processQueue(queue, graph, inDegree);\n\n order.reverse();\n return { success: true, order };\n}\n\nfunction initializeInDegree(graph: DependencyGraph): Map<string, number> {\n const inDegree = new Map<string, number>();\n\n for (const node of graph.nodes) {\n inDegree.set(node, 0);\n }\n\n for (const deps of graph.edges.values()) {\n for (const dep of deps) {\n inDegree.set(dep, (inDegree.get(dep) ?? 0) + 1);\n }\n }\n\n return inDegree;\n}\n\nfunction findZeroInDegreeNodes(inDegree: Map<string, number>): string[] {\n const result: string[] = [];\n for (const [node, degree] of inDegree) {\n if (degree === 0) {\n result.push(node);\n }\n }\n return result;\n}\n\nfunction processQueue(\n queue: string[],\n graph: DependencyGraph,\n inDegree: Map<string, number>,\n): string[] {\n const order: string[] = [];\n let head = 0;\n\n while (head < queue.length) {\n const node = queue[head]!;\n head++;\n order.push(node);\n\n const deps = graph.edges.get(node);\n if (deps) {\n for (const dep of deps) {\n const newDegree = (inDegree.get(dep) ?? 0) - 1;\n inDegree.set(dep, newDegree);\n if (newDegree === 0) {\n queue.push(dep);\n }\n }\n }\n }\n\n return order;\n}\n"]}
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ASTNode, E as EvaluateContextOptions, g as ExtractedFormula, F as FieldTypes, o as FormulaAnalysis, t as FormulaContext, n as FormulaFeature, m as FormulaMinorVersion, u as FormulaResult, k as FormulaValidationError, I as InferredType, J as JsonSchema, P as ParseResult, c as ParsedExpression, r as ParsedPath, q as PathSegment, s as PathValidationResult, l as SchemaValidationResult, S as SyntaxValidationResult, X as XFormula, e as evaluate, a as evaluateWithContext, f as extractSchemaFormulas, i as inferFormulaType, b as parseExpression, p as parseFormula, h as validateFormulaAgainstSchema, d as validateFormulaSyntax, j as validateSchemaFormulas, v as validateSyntax } from './index-JZFJ9oT6.cjs';
1
+ export { A as ASTNode, E as EvaluateContextOptions, F as FieldTypes, h as FormulaAnalysis, m as FormulaContext, g as FormulaFeature, f as FormulaMinorVersion, n as FormulaResult, I as InferredType, P as ParseResult, c as ParsedExpression, k as ParsedPath, j as PathSegment, l as PathValidationResult, S as SyntaxValidationResult, X as XFormula, e as evaluate, a as evaluateWithContext, i as inferFormulaType, b as parseExpression, p as parseFormula, d as validateFormulaSyntax, v as validateSyntax } from './index-PFKKFfeI.cjs';
2
2
 
3
3
  interface DependencyGraph {
4
4
  nodes: Set<string>;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- export { A as ASTNode, E as EvaluateContextOptions, g as ExtractedFormula, F as FieldTypes, o as FormulaAnalysis, t as FormulaContext, n as FormulaFeature, m as FormulaMinorVersion, u as FormulaResult, k as FormulaValidationError, I as InferredType, J as JsonSchema, P as ParseResult, c as ParsedExpression, r as ParsedPath, q as PathSegment, s as PathValidationResult, l as SchemaValidationResult, S as SyntaxValidationResult, X as XFormula, e as evaluate, a as evaluateWithContext, f as extractSchemaFormulas, i as inferFormulaType, b as parseExpression, p as parseFormula, h as validateFormulaAgainstSchema, d as validateFormulaSyntax, j as validateSchemaFormulas, v as validateSyntax } from './index-JZFJ9oT6.js';
1
+ export { A as ASTNode, E as EvaluateContextOptions, F as FieldTypes, h as FormulaAnalysis, m as FormulaContext, g as FormulaFeature, f as FormulaMinorVersion, n as FormulaResult, I as InferredType, P as ParseResult, c as ParsedExpression, k as ParsedPath, j as PathSegment, l as PathValidationResult, S as SyntaxValidationResult, X as XFormula, e as evaluate, a as evaluateWithContext, i as inferFormulaType, b as parseExpression, p as parseFormula, d as validateFormulaSyntax, v as validateSyntax } from './index-PFKKFfeI.js';
2
2
 
3
3
  interface DependencyGraph {
4
4
  nodes: Set<string>;
package/dist/index.js CHANGED
@@ -1,4 +1,111 @@
1
- export { buildDependencyGraph, detectCircularDependencies, evaluate, evaluateWithContext, extractSchemaFormulas, getTopologicalOrder, inferFormulaType, parseExpression, parseFormula, validateFormulaAgainstSchema, validateFormulaSyntax, validateSchemaFormulas, validateSyntax } from './chunk-FDIJPOVQ.js';
2
- import './chunk-PZ5AY32C.js';
1
+ export { evaluate, evaluateWithContext, inferFormulaType, parseExpression, parseFormula, validateFormulaSyntax, validateSyntax } from './chunk-LFEHEGBL.js';
2
+
3
+ // src/dependency-graph.ts
4
+ function buildDependencyGraph(dependencies) {
5
+ const nodes = /* @__PURE__ */ new Set();
6
+ const edges = /* @__PURE__ */ new Map();
7
+ for (const [node, deps] of Object.entries(dependencies)) {
8
+ nodes.add(node);
9
+ edges.set(node, new Set(deps));
10
+ for (const dep of deps) {
11
+ nodes.add(dep);
12
+ }
13
+ }
14
+ return { nodes, edges };
15
+ }
16
+ function detectCircularDependencies(graph) {
17
+ const visited = /* @__PURE__ */ new Set();
18
+ const recursionStack = /* @__PURE__ */ new Set();
19
+ const path = [];
20
+ for (const node of graph.nodes) {
21
+ if (!visited.has(node)) {
22
+ const cycle = dfsVisit(node, graph, visited, recursionStack, path);
23
+ if (cycle) {
24
+ return { hasCircular: true, cycle };
25
+ }
26
+ }
27
+ }
28
+ return { hasCircular: false, cycle: null };
29
+ }
30
+ function dfsVisit(node, graph, visited, recursionStack, path) {
31
+ visited.add(node);
32
+ recursionStack.add(node);
33
+ path.push(node);
34
+ const deps = graph.edges.get(node);
35
+ if (deps) {
36
+ for (const dep of deps) {
37
+ if (!visited.has(dep)) {
38
+ const cycle = dfsVisit(dep, graph, visited, recursionStack, path);
39
+ if (cycle) {
40
+ return cycle;
41
+ }
42
+ } else if (recursionStack.has(dep)) {
43
+ const cycleStart = path.indexOf(dep);
44
+ return [...path.slice(cycleStart), dep];
45
+ }
46
+ }
47
+ }
48
+ path.pop();
49
+ recursionStack.delete(node);
50
+ return null;
51
+ }
52
+ function getTopologicalOrder(graph) {
53
+ const circularCheck = detectCircularDependencies(graph);
54
+ if (circularCheck.hasCircular && circularCheck.cycle) {
55
+ return {
56
+ success: false,
57
+ order: [],
58
+ error: `Circular dependency detected: ${circularCheck.cycle.join(" -> ")}`
59
+ };
60
+ }
61
+ const inDegree = initializeInDegree(graph);
62
+ const queue = findZeroInDegreeNodes(inDegree);
63
+ const order = processQueue(queue, graph, inDegree);
64
+ order.reverse();
65
+ return { success: true, order };
66
+ }
67
+ function initializeInDegree(graph) {
68
+ const inDegree = /* @__PURE__ */ new Map();
69
+ for (const node of graph.nodes) {
70
+ inDegree.set(node, 0);
71
+ }
72
+ for (const deps of graph.edges.values()) {
73
+ for (const dep of deps) {
74
+ inDegree.set(dep, (inDegree.get(dep) ?? 0) + 1);
75
+ }
76
+ }
77
+ return inDegree;
78
+ }
79
+ function findZeroInDegreeNodes(inDegree) {
80
+ const result = [];
81
+ for (const [node, degree] of inDegree) {
82
+ if (degree === 0) {
83
+ result.push(node);
84
+ }
85
+ }
86
+ return result;
87
+ }
88
+ function processQueue(queue, graph, inDegree) {
89
+ const order = [];
90
+ let head = 0;
91
+ while (head < queue.length) {
92
+ const node = queue[head];
93
+ head++;
94
+ order.push(node);
95
+ const deps = graph.edges.get(node);
96
+ if (deps) {
97
+ for (const dep of deps) {
98
+ const newDegree = (inDegree.get(dep) ?? 0) - 1;
99
+ inDegree.set(dep, newDegree);
100
+ if (newDegree === 0) {
101
+ queue.push(dep);
102
+ }
103
+ }
104
+ }
105
+ }
106
+ return order;
107
+ }
108
+
109
+ export { buildDependencyGraph, detectCircularDependencies, getTopologicalOrder };
3
110
  //# sourceMappingURL=index.js.map
4
111
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":[],"names":[],"mappings":"","file":"index.js"}
1
+ {"version":3,"sources":["../src/dependency-graph.ts"],"names":[],"mappings":"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","file":"index.js","sourcesContent":["export interface DependencyGraph {\n nodes: Set<string>;\n edges: Map<string, Set<string>>;\n}\n\nexport interface CircularDependencyResult {\n hasCircular: boolean;\n cycle: string[] | null;\n}\n\nexport interface TopologicalOrderResult {\n success: boolean;\n order: string[];\n error?: string;\n}\n\n/**\n * Build a dependency graph from a dependencies map\n *\n * @param dependencies - Map of node names to their dependencies\n * @returns Dependency graph with nodes and edges\n *\n * @example\n * const graph = buildDependencyGraph({\n * tax: ['price'],\n * total: ['price', 'tax']\n * });\n * // graph.edges.get('tax') = Set(['price'])\n * // graph.edges.get('total') = Set(['price', 'tax'])\n */\nexport function buildDependencyGraph(\n dependencies: Record<string, string[]>,\n): DependencyGraph {\n const nodes = new Set<string>();\n const edges = new Map<string, Set<string>>();\n\n for (const [node, deps] of Object.entries(dependencies)) {\n nodes.add(node);\n edges.set(node, new Set(deps));\n\n for (const dep of deps) {\n nodes.add(dep);\n }\n }\n\n return { nodes, edges };\n}\n\n/**\n * Detect first circular dependency in a dependency graph\n *\n * @param graph - Dependency graph\n * @returns Result with detected cycle (null if no cycle)\n *\n * @example\n * detectCircularDependencies(graph)\n * // { hasCircular: true, cycle: ['a', 'b', 'c', 'a'] }\n */\nexport function detectCircularDependencies(\n graph: DependencyGraph,\n): CircularDependencyResult {\n const visited = new Set<string>();\n const recursionStack = new Set<string>();\n const path: string[] = [];\n\n for (const node of graph.nodes) {\n if (!visited.has(node)) {\n const cycle = dfsVisit(node, graph, visited, recursionStack, path);\n if (cycle) {\n return { hasCircular: true, cycle };\n }\n }\n }\n\n return { hasCircular: false, cycle: null };\n}\n\nfunction dfsVisit(\n node: string,\n graph: DependencyGraph,\n visited: Set<string>,\n recursionStack: Set<string>,\n path: string[],\n): string[] | null {\n visited.add(node);\n recursionStack.add(node);\n path.push(node);\n\n const deps = graph.edges.get(node);\n if (deps) {\n for (const dep of deps) {\n if (!visited.has(dep)) {\n const cycle = dfsVisit(dep, graph, visited, recursionStack, path);\n if (cycle) {\n return cycle;\n }\n } else if (recursionStack.has(dep)) {\n const cycleStart = path.indexOf(dep);\n return [...path.slice(cycleStart), dep];\n }\n }\n }\n\n path.pop();\n recursionStack.delete(node);\n return null;\n}\n\n/**\n * Get topological order for formula evaluation\n *\n * @param graph - Dependency graph\n * @returns Ordered list of field names for evaluation\n *\n * @example\n * getTopologicalOrder(graph)\n * // { success: true, order: ['price', 'tax', 'total'] }\n */\nexport function getTopologicalOrder(\n graph: DependencyGraph,\n): TopologicalOrderResult {\n const circularCheck = detectCircularDependencies(graph);\n if (circularCheck.hasCircular && circularCheck.cycle) {\n return {\n success: false,\n order: [],\n error: `Circular dependency detected: ${circularCheck.cycle.join(' -> ')}`,\n };\n }\n\n const inDegree = initializeInDegree(graph);\n const queue = findZeroInDegreeNodes(inDegree);\n const order = processQueue(queue, graph, inDegree);\n\n order.reverse();\n return { success: true, order };\n}\n\nfunction initializeInDegree(graph: DependencyGraph): Map<string, number> {\n const inDegree = new Map<string, number>();\n\n for (const node of graph.nodes) {\n inDegree.set(node, 0);\n }\n\n for (const deps of graph.edges.values()) {\n for (const dep of deps) {\n inDegree.set(dep, (inDegree.get(dep) ?? 0) + 1);\n }\n }\n\n return inDegree;\n}\n\nfunction findZeroInDegreeNodes(inDegree: Map<string, number>): string[] {\n const result: string[] = [];\n for (const [node, degree] of inDegree) {\n if (degree === 0) {\n result.push(node);\n }\n }\n return result;\n}\n\nfunction processQueue(\n queue: string[],\n graph: DependencyGraph,\n inDegree: Map<string, number>,\n): string[] {\n const order: string[] = [];\n let head = 0;\n\n while (head < queue.length) {\n const node = queue[head]!;\n head++;\n order.push(node);\n\n const deps = graph.edges.get(node);\n if (deps) {\n for (const dep of deps) {\n const newDegree = (inDegree.get(dep) ?? 0) - 1;\n inDegree.set(dep, newDegree);\n if (newDegree === 0) {\n queue.push(dep);\n }\n }\n }\n }\n\n return order;\n}\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@revisium/formula",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Formula expression parser and evaluator for Revisium",
5
5
  "keywords": [
6
6
  "formula",
@@ -104,6 +104,6 @@
104
104
  "access": "public"
105
105
  },
106
106
  "dependencies": {
107
- "subscript": "^9.2.0"
107
+ "ohm-js": "^17.3.0"
108
108
  }
109
109
  }