@the-trybe/formula-engine 1.0.1 → 1.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +122 -2
- package/dist/formula-engine.d.ts +6 -2
- package/dist/formula-engine.js +20 -5
- package/dist/index.d.ts +1 -1
- package/dist/index.js +1 -1
- package/dist/types.d.ts +8 -0
- package/dist/types.js +1 -1
- package/package.json +3 -2
- package/src/evaluateAll-rounding.test.ts +608 -0
- package/src/formula-engine.ts +22 -4
- package/src/index.ts +1 -0
- package/src/types.ts +13 -0
package/README.md
CHANGED
|
@@ -88,6 +88,118 @@ const results = engine.evaluateAll(formulas, context);
|
|
|
88
88
|
console.log(results.results.get('total')?.value.toString()); // "540"
|
|
89
89
|
```
|
|
90
90
|
|
|
91
|
+
### Formula Definition Options
|
|
92
|
+
|
|
93
|
+
Each formula in `evaluateAll()` supports additional configuration options:
|
|
94
|
+
|
|
95
|
+
```typescript
|
|
96
|
+
interface FormulaDefinition {
|
|
97
|
+
id: string; // Unique identifier for the formula
|
|
98
|
+
expression: string; // The expression to evaluate
|
|
99
|
+
dependencies?: string[]; // Explicit dependencies (auto-detected if omitted)
|
|
100
|
+
rounding?: RoundingConfig; // Rounding configuration for the result
|
|
101
|
+
onError?: ErrorBehavior; // How to handle evaluation errors
|
|
102
|
+
defaultValue?: unknown; // Default value when using onError: 'DEFAULT'
|
|
103
|
+
metadata?: Record<string, unknown>; // Custom metadata (not used by engine)
|
|
104
|
+
}
|
|
105
|
+
```
|
|
106
|
+
|
|
107
|
+
#### Default Intermediate Rounding
|
|
108
|
+
|
|
109
|
+
For financial calculations, configure `defaultRounding` in the engine to automatically round all intermediate values in `evaluateAll()`:
|
|
110
|
+
|
|
111
|
+
```typescript
|
|
112
|
+
const engine = new FormulaEngine({
|
|
113
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
const formulas = [
|
|
117
|
+
{ id: 'subtotal', expression: '$quantity * $unitPrice' },
|
|
118
|
+
{ id: 'tax', expression: '$subtotal * 0.0825' }, // Uses rounded subtotal
|
|
119
|
+
{ id: 'total', expression: '$subtotal + $tax' },
|
|
120
|
+
];
|
|
121
|
+
|
|
122
|
+
const results = engine.evaluateAll(formulas, {
|
|
123
|
+
variables: { quantity: 3, unitPrice: 10.33 }
|
|
124
|
+
});
|
|
125
|
+
|
|
126
|
+
// subtotal = 30.99 (auto-rounded)
|
|
127
|
+
// tax = 2.56 (auto-rounded, calculated from rounded subtotal)
|
|
128
|
+
// total = 33.55
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
This ensures intermediate values are rounded before being used in dependent formulas, which is critical for financial/accounting calculations.
|
|
132
|
+
|
|
133
|
+
#### Disabling Intermediate Rounding
|
|
134
|
+
|
|
135
|
+
To disable the default intermediate rounding for specific batch evaluations, use the `disableIntermediateRounding` option:
|
|
136
|
+
|
|
137
|
+
```typescript
|
|
138
|
+
const results = engine.evaluateAll(formulas, context, {
|
|
139
|
+
disableIntermediateRounding: true
|
|
140
|
+
});
|
|
141
|
+
// Raw unrounded values will propagate through dependencies
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
#### Per-Formula Rounding Override
|
|
145
|
+
|
|
146
|
+
Individual formulas can override the default rounding with their own `rounding` configuration:
|
|
147
|
+
|
|
148
|
+
```typescript
|
|
149
|
+
const engine = new FormulaEngine({
|
|
150
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
151
|
+
});
|
|
152
|
+
|
|
153
|
+
const formulas = [
|
|
154
|
+
// Override: use 4 decimal places for exchange rate
|
|
155
|
+
{ id: 'rate', expression: '1 / 3', rounding: { mode: 'HALF_UP', precision: 4 } },
|
|
156
|
+
// Uses default 2 decimal rounding
|
|
157
|
+
{ id: 'amount', expression: '1000 * $rate' },
|
|
158
|
+
];
|
|
159
|
+
|
|
160
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
161
|
+
// rate = 0.3333 (4 decimals from per-formula config)
|
|
162
|
+
// amount = 333.30 (2 decimals from default config)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
**Rounding Modes:**
|
|
166
|
+
- `HALF_UP` - Round towards nearest neighbor, ties round up (standard rounding)
|
|
167
|
+
- `HALF_DOWN` - Round towards nearest neighbor, ties round down
|
|
168
|
+
- `FLOOR` - Round towards negative infinity
|
|
169
|
+
- `CEIL` - Round towards positive infinity
|
|
170
|
+
- `NONE` - No rounding applied
|
|
171
|
+
|
|
172
|
+
#### Error Handling Behavior
|
|
173
|
+
|
|
174
|
+
Control how errors are handled during batch evaluation:
|
|
175
|
+
|
|
176
|
+
```typescript
|
|
177
|
+
const formulas = [
|
|
178
|
+
{
|
|
179
|
+
id: 'ratio',
|
|
180
|
+
expression: '$a / $b',
|
|
181
|
+
onError: { type: 'ZERO' } // Return 0 on division by zero
|
|
182
|
+
},
|
|
183
|
+
{
|
|
184
|
+
id: 'result',
|
|
185
|
+
expression: '$ratio * 100', // Can continue with 0
|
|
186
|
+
},
|
|
187
|
+
];
|
|
188
|
+
|
|
189
|
+
const results = engine.evaluateAll(formulas, {
|
|
190
|
+
variables: { a: 10, b: 0 }
|
|
191
|
+
});
|
|
192
|
+
// ratio = 0 (instead of error)
|
|
193
|
+
// result = 0
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
**Error Behavior Types:**
|
|
197
|
+
- `THROW` - Propagate the error (default)
|
|
198
|
+
- `NULL` - Use `null` as the result
|
|
199
|
+
- `ZERO` - Use `0` as the result
|
|
200
|
+
- `DEFAULT` - Use `defaultValue` from the formula definition
|
|
201
|
+
- `SKIP` - Skip this formula (result is `undefined`)
|
|
202
|
+
|
|
91
203
|
### Decimal Precision
|
|
92
204
|
|
|
93
205
|
JavaScript floating-point math has precision issues:
|
|
@@ -296,6 +408,14 @@ const engine = new FormulaEngine({
|
|
|
296
408
|
divisionScale: 10, // Decimal places for division
|
|
297
409
|
},
|
|
298
410
|
|
|
411
|
+
// Default rounding for evaluateAll() intermediate values
|
|
412
|
+
// When set, all formula results in batch evaluation are rounded
|
|
413
|
+
// before being used in dependent formulas
|
|
414
|
+
defaultRounding: {
|
|
415
|
+
mode: 'HALF_UP', // Rounding mode
|
|
416
|
+
precision: 2, // Decimal places (e.g., 2 for currency)
|
|
417
|
+
},
|
|
418
|
+
|
|
299
419
|
// Security limits
|
|
300
420
|
security: {
|
|
301
421
|
maxExpressionLength: 10000,
|
|
@@ -349,8 +469,8 @@ class FormulaEngine {
|
|
|
349
469
|
// Evaluate single expression
|
|
350
470
|
evaluate(expression: string, context: EvaluationContext): EvaluationResult;
|
|
351
471
|
|
|
352
|
-
// Evaluate all formulas in order
|
|
353
|
-
evaluateAll(formulas: FormulaDefinition[], context: EvaluationContext): EvaluationResultSet;
|
|
472
|
+
// Evaluate all formulas in order (with optional rounding options)
|
|
473
|
+
evaluateAll(formulas: FormulaDefinition[], context: EvaluationContext, options?: EvaluateAllOptions): EvaluationResultSet;
|
|
354
474
|
|
|
355
475
|
// Register custom function
|
|
356
476
|
registerFunction(definition: FunctionDefinition): void;
|
package/dist/formula-engine.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FormulaEngineConfig, FormulaDefinition, EvaluationContext, EvaluationResult, EvaluationResultSet, ValidationResult, FunctionDefinition, ASTNode, CacheStats, DependencyGraph as IDependencyGraph } from './types';
|
|
1
|
+
import { FormulaEngineConfig, FormulaDefinition, EvaluationContext, EvaluationResult, EvaluationResultSet, EvaluateAllOptions, ValidationResult, FunctionDefinition, ASTNode, CacheStats, DependencyGraph as IDependencyGraph } from './types';
|
|
2
2
|
import { DecimalUtils, Decimal } from './decimal-utils';
|
|
3
3
|
export declare class FormulaEngine {
|
|
4
4
|
private config;
|
|
@@ -39,8 +39,12 @@ export declare class FormulaEngine {
|
|
|
39
39
|
evaluate(expression: string, context: EvaluationContext): EvaluationResult;
|
|
40
40
|
/**
|
|
41
41
|
* Evaluate all formulas in dependency order
|
|
42
|
+
*
|
|
43
|
+
* @param formulas - Array of formula definitions to evaluate
|
|
44
|
+
* @param context - Evaluation context with variables
|
|
45
|
+
* @param options - Optional configuration for batch evaluation
|
|
42
46
|
*/
|
|
43
|
-
evaluateAll(formulas: FormulaDefinition[], context: EvaluationContext): EvaluationResultSet;
|
|
47
|
+
evaluateAll(formulas: FormulaDefinition[], context: EvaluationContext, options?: EvaluateAllOptions): EvaluationResultSet;
|
|
44
48
|
/**
|
|
45
49
|
* Register a custom function
|
|
46
50
|
*/
|
package/dist/formula-engine.js
CHANGED
|
@@ -140,8 +140,12 @@ class FormulaEngine {
|
|
|
140
140
|
}
|
|
141
141
|
/**
|
|
142
142
|
* Evaluate all formulas in dependency order
|
|
143
|
+
*
|
|
144
|
+
* @param formulas - Array of formula definitions to evaluate
|
|
145
|
+
* @param context - Evaluation context with variables
|
|
146
|
+
* @param options - Optional configuration for batch evaluation
|
|
143
147
|
*/
|
|
144
|
-
evaluateAll(formulas, context) {
|
|
148
|
+
evaluateAll(formulas, context, options) {
|
|
145
149
|
const startTime = Date.now();
|
|
146
150
|
const results = new Map();
|
|
147
151
|
const errors = [];
|
|
@@ -164,6 +168,10 @@ class FormulaEngine {
|
|
|
164
168
|
for (const formula of formulas) {
|
|
165
169
|
formulaMap.set(formula.id, formula);
|
|
166
170
|
}
|
|
171
|
+
// Determine if intermediate rounding should be applied
|
|
172
|
+
const applyIntermediateRounding = this.config.defaultRounding &&
|
|
173
|
+
this.config.defaultRounding.mode !== 'NONE' &&
|
|
174
|
+
!options?.disableIntermediateRounding;
|
|
167
175
|
// Evaluate in order, merging results into context
|
|
168
176
|
const workingContext = this.normalizeContext(context);
|
|
169
177
|
for (const formulaId of evaluationOrder) {
|
|
@@ -172,10 +180,17 @@ class FormulaEngine {
|
|
|
172
180
|
continue;
|
|
173
181
|
try {
|
|
174
182
|
const result = this.evaluator.evaluate(formula.expression, workingContext);
|
|
175
|
-
// Apply rounding
|
|
183
|
+
// Apply rounding: per-formula config takes precedence, then defaultRounding
|
|
176
184
|
let value = result.value;
|
|
177
|
-
if (
|
|
178
|
-
|
|
185
|
+
if (this.isDecimal(value)) {
|
|
186
|
+
if (formula.rounding) {
|
|
187
|
+
// Per-formula rounding always takes precedence
|
|
188
|
+
value = this.applyRounding(value, formula.rounding);
|
|
189
|
+
}
|
|
190
|
+
else if (applyIntermediateRounding) {
|
|
191
|
+
// Apply default rounding to intermediate values
|
|
192
|
+
value = this.applyRounding(value, this.config.defaultRounding);
|
|
193
|
+
}
|
|
179
194
|
}
|
|
180
195
|
// Handle errors based on formula config
|
|
181
196
|
if (!result.success && formula.onError) {
|
|
@@ -352,4 +367,4 @@ class FormulaEngine {
|
|
|
352
367
|
}
|
|
353
368
|
}
|
|
354
369
|
exports.FormulaEngine = FormulaEngine;
|
|
355
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybXVsYS1lbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZm9ybXVsYS1lbmdpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBWUEscUNBQWtDO0FBQ2xDLDJDQUF3QztBQUN4QyxpRUFBNkQ7QUFDN0QseURBQTZFO0FBQzdFLG1EQUF3RDtBQUN4RCwyQ0FBcUQ7QUFDckQscUNBS2tCO0FBRWxCLE1BQWEsYUFBYTtJQWV4QixZQUFZLE1BQTRCO1FBTnhDLFNBQVM7UUFDRCxhQUFRLEdBQXlCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDM0Msb0JBQWUsR0FBNkIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN0RCxjQUFTLEdBQVcsQ0FBQyxDQUFDO1FBQ3RCLGdCQUFXLEdBQVcsQ0FBQyxDQUFDO1FBRzlCLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixXQUFXLEVBQUUsSUFBSTtZQUNqQixZQUFZLEVBQUUsSUFBSTtZQUNsQixVQUFVLEVBQUUsSUFBSTtZQUNoQixHQUFHLE1BQU07U0FDVixDQUFDO1FBRUYsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLDRCQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUEsa0NBQXNCLEVBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxlQUFNLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSwwQ0FBbUIsRUFBRSxDQUFDO1FBQ3JELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSx5Q0FBc0IsRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxxQkFBUyxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFL0UsNENB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WSxJQUFJLElBQUksQ0FBQztZQUMvRCxLQUFLLE1BQU07Z0JBQ1QsT0FBTyxTQUFTLENBQUM7WUFDbkIsS0FBSyxPQUFPLENBQUM7WUFDYjtnQkFDRSxNQUFNLE1BQU0sQ0FBQztRQUNqQixDQUFDO0lBQ0gsQ0FBQztJQUVPLGVBQWU7UUFDckIsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxZQUFZLElBQUksSUFBSSxDQUFDO1FBQ2pELElBQUksSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLElBQUksT0FBTyxFQUFFLENBQUM7WUFDbEMscURBQXFEO1lBQ3JELE1BQU0sUUFBUSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsT0FBTyxHQUFHLEdBQUcsQ0FBQyxDQUFDO1lBQzFDLE1BQU0sSUFBSSxHQUFHLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLEtBQUssQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDakUsS0FBSyxNQUFNLEdBQUcsSUFBSSxJQUFJLEVBQUUsQ0FBQztnQkFDdkIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUM7Z0JBQzFCLElBQUksQ0FBQyxlQUFlLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25DLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBcFpELHNDQW9aQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEZvcm11bGFFbmdpbmVDb25maWcsXG4gIEZvcm11bGFEZWZpbml0aW9uLFxuICBFdmFsdWF0aW9uQ29udGV4dCxcbiAgRXZhbHVhdGlvblJlc3VsdCxcbiAgRXZhbHVhdGlvblJlc3VsdFNldCxcbiAgVmFsaWRhdGlvblJlc3VsdCxcbiAgRnVuY3Rpb25EZWZpbml0aW9uLFxuICBBU1ROb2RlLFxuICBDYWNoZVN0YXRzLFxuICBEZXBlbmRlbmN5R3JhcGggYXMgSURlcGVuZGVuY3lHcmFwaCxcbn0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBQYXJzZXIgfSBmcm9tICcuL3BhcnNlcic7XG5pbXBvcnQgeyBFdmFsdWF0b3IgfSBmcm9tICcuL2V2YWx1YXRvcic7XG5pbXBvcnQgeyBEZXBlbmRlbmN5RXh0cmFjdG9yIH0gZnJvbSAnLi9kZXBlbmRlbmN5LWV4dHJhY3Rvcic7XG5pbXBvcnQgeyBEZXBlbmRlbmN5R3JhcGgsIERlcGVuZGVuY3lHcmFwaEJ1aWxkZXIgfSBmcm9tICcuL2RlcGVuZGVuY3ktZ3JhcGgnO1xuaW1wb3J0IHsgRGVjaW1hbFV0aWxzLCBEZWNpbWFsIH0gZnJvbSAnLi9kZWNpbWFsLXV0aWxzJztcbmltcG9ydCB7IGNyZWF0ZUJ1aWx0SW5GdW5jdGlvbnMgfSBmcm9tICcuL2Z1bmN0aW9ucyc7XG5pbXBvcnQge1xuICBGb3JtdWxhRW5naW5lRXJyb3IsXG4gIEdlbmVyYWxGb3JtdWxhRXJyb3IsXG4gIER1cGxpY2F0ZUZvcm11bGFFcnJvcixcbiAgTWF4RXhwcmVzc2lvbkxlbmd0aEVycm9yLFxufSBmcm9tICcuL2Vycm9ycyc7XG5cbmV4cG9ydCBjbGFzcyBGb3JtdWxhRW5naW5lIHtcbiAgcHJpdmF0ZSBjb25maWc6IEZvcm11bGFFbmdpbmVDb25maWc7XG4gIHByaXZhdGUgcGFyc2VyOiBQYXJzZXI7XG4gIHByaXZhdGUgZXZhbHVhdG9yOiBFdmFsdWF0b3I7XG4gIHByaXZhdGUgZGVwZW5kZW5jeUV4dHJhY3RvcjogRGVwZW5kZW5jeUV4dHJhY3RvcjtcbiAgcHJpdmF0ZSBncmFwaEJ1aWxkZXI6IERlcGVuZGVuY3lHcmFwaEJ1aWxkZXI7XG4gIHByaXZhdGUgZGVjaW1hbFV0aWxzOiBEZWNpbWFsVXRpbHM7XG4gIHByaXZhdGUgZnVuY3Rpb25zOiBNYXA8c3RyaW5nLCBGdW5jdGlvbkRlZmluaXRpb24+O1xuXG4gIC8vIENhY2hlc1xuICBwcml2YXRlIGFzdENhY2hlOiBNYXA8c3RyaW5nLCBBU1ROb2RlPiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBkZXBlbmRlbmN5Q2FjaGU6IE1hcDxzdHJpbmcsIFNldDxzdHJpbmc+PiA9IG5ldyBNYXAoKTtcbiAgcHJpdmF0ZSBjYWNoZUhpdHM6IG51bWJlciA9IDA7XG4gIHByaXZhdGUgY2FjaGVNaXNzZXM6IG51bWJlciA9IDA7XG5cbiAgY29uc3RydWN0b3IoY29uZmlnPzogRm9ybXVsYUVuZ2luZUNvbmZpZykge1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgZW5hYmxlQ2FjaGU6IHRydWUsXG4gICAgICBtYXhDYWNoZVNpemU6IDEwMDAsXG4gICAgICBzdHJpY3RNb2RlOiB0cnVlLFxuICAgICAgLi4uY29uZmlnLFxuICAgIH07XG5cbiAgICB0aGlzLmRlY2ltYWxVdGlscyA9IG5ldyBEZWNpbWFsVXRpbHModGhpcy5jb25maWcuZGVjaW1hbCk7XG4gICAgdGhpcy5mdW5jdGlvbnMgPSBjcmVhdGVCdWlsdEluRnVuY3Rpb25zKHRoaXMuZGVjaW1hbFV0aWxzKTtcbiAgICB0aGlzLnBhcnNlciA9IG5ldyBQYXJzZXIoKTtcbiAgICB0aGlzLmRlcGVuZGVuY3lFeHRyYWN0b3IgPSBuZXcgRGVwZW5kZW5jeUV4dHJhY3RvcigpO1xuICAgIHRoaXMuZ3JhcGhCdWlsZGVyID0gbmV3IERlcGVuZGVuY3lHcmFwaEJ1aWxkZXIoKTtcbiAgICB0aGlzLmV2YWx1YXRvciA9IG5ldyBFdmFsdWF0b3IodGhpcy5kZWNpbWFsVXRpbHMsIHRoaXMuZnVuY3Rpb25zLCB0aGlzLmNvbmZpZyk7XG5cbiAgICAvLyBSZWdpc3RlciBhbnkgY3VzdG9tIGZ1bmN0aW9ucyBmcm9tIGNvbmZpZ1xuICAgIGlmICh0aGlzLmNvbmZpZy5mdW5jdGlvbnMpIHtcbiAgICAgIGZvciAoY29uc3QgZm4gb2YgdGhpcy5jb25maWcuZnVuY3Rpb25zKSB7XG4gICAgICAgIHRoaXMucmVnaXN0ZXJGdW5jdGlvbihmbik7XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFBhcnNlIGFuIGV4cHJlc3Npb24gaW50byBhbiBBU1RcbiAgICovXG4gIHBhcnNlKGV4cHJlc3Npb246IHN0cmluZyk6IEFTVE5vZGUge1xuICAgIHRoaXMuY2hlY2tFeHByZXNzaW9uTGVuZ3RoKGV4cHJlc3Npb24pO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUNhY2hlKSB7XG4gICAgICBjb25zdCBjYWNoZWQgPSB0aGlzLmFzdENhY2hlLmdldChleHByZXNzaW9uKTtcbiAgICAgIGlmIChjYWNoZWQpIHtcbiAgICAgICAgdGhpcy5jYWNoZUhpdHMrKztcbiAgICAgICAgcmV0dXJuIGNhY2hlZDtcbiAgICAgIH1cbiAgICAgIHRoaXMuY2FjaGVNaXNzZXMrKztcbiAgICB9XG5cbiAgICBjb25zdCBhc3QgPSB0aGlzLnBhcnNlci5wYXJzZShleHByZXNzaW9uKTtcblxuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgdGhpcy5tYXliZUV2aWN0Q2FjaGUoKTtcbiAgICAgIHRoaXMuYXN0Q2FjaGUuc2V0KGV4cHJlc3Npb24sIGFzdCk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGFzdDtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWN0IHZhcmlhYmxlIGRlcGVuZGVuY2llcyBmcm9tIGFuIGV4cHJlc3Npb25cbiAgICovXG4gIGV4dHJhY3REZXBlbmRlbmNpZXMoZXhwcmVzc2lvbjogc3RyaW5nKTogU2V0PHN0cmluZz4ge1xuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgY29uc3QgY2FjaGVkID0gdGhpcy5kZXBlbmRlbmN5Q2FjaGUuZ2V0KGV4cHJlc3Npb24pO1xuICAgICAgaWYgKGNhY2hlZCkge1xuICAgICAgICByZXR1cm4gbmV3IFNldChjYWNoZWQpO1xuICAgICAgfVxuICAgIH1cblxuICAgIGNvbnN0IGRlcHMgPSB0aGlzLmRlcGVuZGVuY3lFeHRyYWN0b3IuZXh0cmFjdChleHByZXNzaW9uKTtcblxuICAgIGlmICh0aGlzLmNvbmZpZy5lbmFibGVDYWNoZSkge1xuICAgICAgdGhpcy5kZXBlbmRlbmN5Q2FjaGUuc2V0KGV4cHJlc3Npb24sIG5ldyBTZXQoZGVwcykpO1xuICAgIH1cblxuICAgIHJldHVybiBkZXBzO1xuICB9XG5cbiAgLyoqXG4gICAqIEJ1aWxkIGEgZGVwZW5kZW5jeSBncmFwaCBmcm9tIGZvcm11bGEgZGVmaW5pdGlvbnNcbiAgICovXG4gIGJ1aWxkRGVwZW5kZW5jeUdyYXBoKGZvcm11bGFzOiBGb3JtdWxhRGVmaW5pdGlvbltdKTogSURlcGVuZGVuY3lHcmFwaCB7XG4gICAgcmV0dXJuIHRoaXMuZ3JhcGhCdWlsZGVyLmJ1aWxkKGZvcm11bGFzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGV2YWx1YXRpb24gb3JkZXIgZm9yIGZvcm11bGFzXG4gICAqL1xuICBnZXRFdmFsdWF0aW9uT3JkZXIoZm9ybXVsYXM6IEZvcm11bGFEZWZpbml0aW9uW10pOiBzdHJpbmdbXSB7XG4gICAgcmV0dXJuIHRoaXMuZ3JhcGhCdWlsZGVyLmdldEV2YWx1YXRpb25PcmRlcihmb3JtdWxhcyk7XG4gIH1cblxuICAvKipcbiAgICogVmFsaWRhdGUgZm9ybXVsYXMgd2l0aG91dCBldmFsdWF0aW5nXG4gICAqL1xuICB2YWxpZGF0ZShmb3JtdWxhczogRm9ybXVsYURlZmluaXRpb25bXSk6IFZhbGlkYXRpb25SZXN1bHQge1xuICAgIGNvbnN0IGVycm9yczogRm9ybXVsYUVuZ2luZUVycm9yW10gPSBbXTtcbiAgICBjb25zdCB3YXJuaW5nczogc3RyaW5nW10gPSBbXTtcblxuICAgIC8vIENoZWNrIGZvciBkdXBsaWNhdGUgSURzXG4gICAgY29uc3QgaWRzID0gbmV3IFNldDxzdHJpbmc+KCk7XG4gICAgZm9yIChjb25zdCBmb3JtdWxhIG9mIGZvcm11bGFzKSB7XG4gICAgICBpZiAoaWRzLmhhcyhmb3JtdWxhLmlkKSkge1xuICAgICAgICBlcnJvcnMucHVzaChuZXcgRHVwbGljYXRlRm9ybXVsYUVycm9yKGZvcm11bGEuaWQpKTtcbiAgICAgIH1cbiAgICAgIGlkcy5hZGQoZm9ybXVsYS5pZCk7XG4gICAgfVxuXG4gICAgLy8gVHJ5IHRvIHBhcnNlIGFsbCBleHByZXNzaW9uc1xuICAgIGZvciAoY29uc3QgZm9ybXVsYSBvZiBmb3JtdWxhcykge1xuICAgICAgdHJ5IHtcbiAgICAgICAgdGhpcy5wYXJzZShmb3JtdWxhLmV4cHJlc3Npb24pO1xuICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRm9ybXVsYUVuZ2luZUVycm9yKSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2goZXJyb3IpO1xuICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgIGVycm9ycy5wdXNoKG5ldyBHZW5lcmFsRm9ybXVsYUVycm9yKFN0cmluZyhlcnJvcikpKTtcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEJ1aWxkIGRlcGVuZGVuY3kgZ3JhcGggYW5kIGNoZWNrIGZvciBjeWNsZXNcbiAgICBsZXQgZGVwZW5kZW5jeUdyYXBoOiBJRGVwZW5kZW5jeUdyYXBoID0gbmV3IERlcGVuZGVuY3lHcmFwaCgpO1xuICAgIGxldCBldmFsdWF0aW9uT3JkZXI6IHN0cmluZ1tdID0gW107XG5cbiAgICB0cnkge1xuICAgICAgZGVwZW5kZW5jeUdyYXBoID0gdGhpcy5idWlsZERlcGVuZGVuY3lHcmFwaChmb3JtdWxhcyk7XG4gICAgICBldmFsdWF0aW9uT3JkZXIgPSBkZXBlbmRlbmN5R3JhcGgudG9wb2xvZ2ljYWxTb3J0KCk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIGlmIChlcnJvciBpbnN0YW5jZW9mIEZvcm11bGFFbmdpbmVFcnJvcikge1xuICAgICAgICBlcnJvcnMucHVzaChlcnJvcik7XG4gICAgICB9XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIHZhbGlkOiBlcnJvcnMubGVuZ3RoID09PSAwLFxuICAgICAgZXJyb3JzLFxuICAgICAgd2FybmluZ3MsXG4gICAgICBkZXBlbmRlbmN5R3JhcGgsXG4gICAgICBldmFsdWF0aW9uT3JkZXIsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBhIHNpbmdsZSBleHByZXNzaW9uXG4gICAqL1xuICBldmFsdWF0ZShleHByZXNzaW9uOiBzdHJpbmcsIGNvbnRleHQ6IEV2YWx1YXRpb25Db250ZXh0KTogRXZhbHVhdGlvblJlc3VsdCB7XG4gICAgdGhpcy5jaGVja0V4cHJlc3Npb25MZW5ndGgoZXhwcmVzc2lvbik7XG4gICAgY29uc3Qgbm9ybWFsaXplZENvbnRleHQgPSB0aGlzLm5vcm1hbGl6ZUNvbnRleHQoY29udGV4dCk7XG4gICAgcmV0dXJuIHRoaXMuZXZhbHVhdG9yLmV2YWx1YXRlKGV4cHJlc3Npb24sIG5vcm1hbGl6ZWRDb250ZXh0KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFdmFsdWF0ZSBhbGwgZm9ybXVsYXMgaW4gZGVwZW5kZW5jeSBvcmRlclxuICAgKi9cbiAgZXZhbHVhdGVBbGwoXG4gICAgZm9ybXVsYXM6IEZvcm11bGFEZWZpbml0aW9uW10sXG4gICAgY29udGV4dDogRXZhbHVhdGlvbkNvbnRleHRcbiAgKTogRXZhbHVhdGlvblJlc3VsdFNldCB7XG4gICAgY29uc3Qgc3RhcnRUaW1lID0gRGF0ZS5ub3coKTtcbiAgICBjb25zdCByZXN1bHRzID0gbmV3IE1hcDxzdHJpbmcsIEV2YWx1YXRpb25SZXN1bHQ+KCk7XG4gICAgY29uc3QgZXJyb3JzOiBFcnJvcltdID0gW107XG5cbiAgICAvLyBHZXQgZXZhbHVhdGlvbiBvcmRlclxuICAgIGxldCBldmFsdWF0aW9uT3JkZXI6IHN0cmluZ1tdO1xuICAgIHRyeSB7XG4gICAgICBldmFsdWF0aW9uT3JkZXIgPSB0aGlzLmdldEV2YWx1YXRpb25PcmRlcihmb3JtdWxhcyk7XG4gICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIHJlc3VsdHMsXG4gICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICBlcnJvcnM6IFtlcnJvciBhcyBFcnJvcl0sXG4gICAgICAgIHRvdGFsRXhlY3V0aW9uVGltZU1zOiBEYXRlLm5vdygpIC0gc3RhcnRUaW1lLFxuICAgICAgICBldmFsdWF0aW9uT3JkZXI6IFtdLFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBDcmVhdGUgYSBtYXAgb2YgZm9ybXVsYXMgYnkgSURcbiAgICBjb25zdCBmb3JtdWxhTWFwID0gbmV3IE1hcDxzdHJpbmcsIEZvcm11bGFEZWZpbml0aW9uPigpO1xuICAgIGZvciAoY29uc3QgZm9ybXVsYSBvZiBmb3JtdWxhcykge1xuICAgICAgZm9ybXVsYU1hcC5zZXQoZm9ybXVsYS5pZCwgZm9ybXVsYSk7XG4gICAgfVxuXG4gICAgLy8gRXZhbHVhdGUgaW4gb3JkZXIsIG1lcmdpbmcgcmVzdWx0cyBpbnRvIGNvbnRleHRcbiAgICBjb25zdCB3b3JraW5nQ29udGV4dDogRXZhbHVhdGlvbkNvbnRleHQgPSB0aGlzLm5vcm1hbGl6ZUNvbnRleHQoY29udGV4dCk7XG5cbiAgICBmb3IgKGNvbnN0IGZvcm11bGFJZCBvZiBldmFsdWF0aW9uT3JkZXIpIHtcbiAgICAgIGNvbnN0IGZvcm11bGEgPSBmb3JtdWxhTWFwLmdldChmb3JtdWxhSWQpO1xuICAgICAgaWYgKCFmb3JtdWxhKSBjb250aW51ZTtcblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzdWx0ID0gdGhpcy5ldmFsdWF0b3IuZXZhbHVhdGUoZm9ybXVsYS5leHByZXNzaW9uLCB3b3JraW5nQ29udGV4dCk7XG5cbiAgICAgICAgLy8gQXBwbHkgcm91bmRpbmcgaWYgY29uZmlndXJlZFxuICAgICAgICBsZXQgdmFsdWUgPSByZXN1bHQudmFsdWU7XG4gICAgICAgIGlmIChmb3JtdWxhLnJvdW5kaW5nICYmIHRoaXMuaXNEZWNpbWFsKHZhbHVlKSkge1xuICAgICAgICAgIHZhbHVlID0gdGhpcy5hcHBseVJvdW5kaW5nKHZhbHVlIGFzIERlY2ltYWwsIGZvcm11bGEucm91bmRpbmcpO1xuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIGVycm9ycyBiYXNlZCBvbiBmb3JtdWxhIGNvbmZpZ1xuICAgICAgICBpZiAoIXJlc3VsdC5zdWNjZXNzICYmIGZvcm11bGEub25FcnJvcikge1xuICAgICAgICAgIHZhbHVlID0gdGhpcy5oYW5kbGVFcnJvcihmb3JtdWxhLCByZXN1bHQuZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVzdWx0cy5zZXQoZm9ybXVsYUlkLCB7XG4gICAgICAgICAgLi4ucmVzdWx0LFxuICAgICAgICAgIHZhbHVlLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBNZXJnZSByZXN1bHQgaW50byBjb250ZXh0IGZvciBzdWJzZXF1ZW50IGZvcm11bGFzXG4gICAgICAgIHdvcmtpbmdDb250ZXh0LnZhcmlhYmxlc1tmb3JtdWxhSWRdID0gdmFsdWU7XG5cbiAgICAgICAgaWYgKCFyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIGVycm9ycy5wdXNoKHJlc3VsdC5lcnJvciEpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBldmFsUmVzdWx0OiBFdmFsdWF0aW9uUmVzdWx0ID0ge1xuICAgICAgICAgIHZhbHVlOiBudWxsLFxuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIGVycm9yOiBlcnJvciBhcyBFcnJvcixcbiAgICAgICAgICBleGVjdXRpb25UaW1lTXM6IDAsXG4gICAgICAgICAgYWNjZXNzZWRWYXJpYWJsZXM6IG5ldyBTZXQoKSxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBIYW5kbGUgZXJyb3IgYmFzZWQgb24gZm9ybXVsYSBjb25maWdcbiAgICAgICAgaWYgKGZvcm11bGEub25FcnJvcikge1xuICAgICAgICAgIGV2YWxSZXN1bHQudmFsdWUgPSB0aGlzLmhhbmRsZUVycm9yKGZvcm11bGEsIGVycm9yIGFzIEVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlc3VsdHMuc2V0KGZvcm11bGFJZCwgZXZhbFJlc3VsdCk7XG4gICAgICAgIGVycm9ycy5wdXNoKGVycm9yIGFzIEVycm9yKTtcblxuICAgICAgICAvLyBTdGlsbCBhZGQgdG8gY29udGV4dCAoYXMgbnVsbCBvciBkZWZhdWx0IHZhbHVlKSBzbyBkZXBlbmRlbnQgZm9ybXVsYXMgY2FuIHByb2NlZWRcbiAgICAgICAgd29ya2luZ0NvbnRleHQudmFyaWFibGVzW2Zvcm11bGFJZF0gPSBldmFsUmVzdWx0LnZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICByZXN1bHRzLFxuICAgICAgc3VjY2VzczogZXJyb3JzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGVycm9ycyxcbiAgICAgIHRvdGFsRXhlY3V0aW9uVGltZU1zOiBEYXRlLm5vdygpIC0gc3RhcnRUaW1lLFxuICAgICAgZXZhbHVhdGlvbk9yZGVyLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXIgYSBjdXN0b20gZnVuY3Rpb25cbiAgICovXG4gIHJlZ2lzdGVyRnVuY3Rpb24oZGVmaW5pdGlvbjogRnVuY3Rpb25EZWZpbml0aW9uKTogdm9pZCB7XG4gICAgY29uc3QgbmFtZSA9IGRlZmluaXRpb24ubmFtZS50b1VwcGVyQ2FzZSgpO1xuICAgIHRoaXMuZnVuY3Rpb25zLnNldChuYW1lLCBkZWZpbml0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBtdWx0aXBsZSBjdXN0b20gZnVuY3Rpb25zXG4gICAqL1xuICByZWdpc3RlckZ1bmN0aW9ucyhkZWZpbml0aW9uczogRnVuY3Rpb25EZWZpbml0aW9uW10pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGRlZmluaXRpb24gb2YgZGVmaW5pdGlvbnMpIHtcbiAgICAgIHRoaXMucmVnaXN0ZXJGdW5jdGlvbihkZWZpbml0aW9uKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHJlZ2lzdGVyZWQgZnVuY3Rpb24gbmFtZXNcbiAgICovXG4gIGdldFJlZ2lzdGVyZWRGdW5jdGlvbnMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMuZnVuY3Rpb25zLmtleXMoKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgdGhlIEFTVCBjYWNoZVxuICAgKi9cbiAgY2xlYXJDYWNoZSgpOiB2b2lkIHtcbiAgICB0aGlzLmFzdENhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5kZXBlbmRlbmN5Q2FjaGUuY2xlYXIoKTtcbiAgICB0aGlzLmNhY2hlSGl0cyA9IDA7XG4gICAgdGhpcy5jYWNoZU1pc3NlcyA9IDA7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGNhY2hlIHN0YXRpc3RpY3NcbiAgICovXG4gIGdldENhY2hlU3RhdHMoKTogQ2FjaGVTdGF0cyB7XG4gICAgY29uc3QgdG90YWwgPSB0aGlzLmNhY2hlSGl0cyArIHRoaXMuY2FjaGVNaXNzZXM7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpemU6IHRoaXMuYXN0Q2FjaGUuc2l6ZSxcbiAgICAgIGhpdHM6IHRoaXMuY2FjaGVIaXRzLFxuICAgICAgbWlzc2VzOiB0aGlzLmNhY2hlTWlzc2VzLFxuICAgICAgaGl0UmF0ZTogdG90YWwgPiAwID8gdGhpcy5jYWNoZUhpdHMgLyB0b3RhbCA6IDAsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGRlY2ltYWwgdXRpbGl0aWVzIGluc3RhbmNlXG4gICAqL1xuICBnZXREZWNpbWFsVXRpbHMoKTogRGVjaW1hbFV0aWxzIHtcbiAgICByZXR1cm4gdGhpcy5kZWNpbWFsVXRpbHM7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgRGVjaW1hbCBmcm9tIGEgdmFsdWVcbiAgICovXG4gIGNyZWF0ZURlY2ltYWwodmFsdWU6IHN0cmluZyB8IG51bWJlcik6IERlY2ltYWwge1xuICAgIHJldHVybiB0aGlzLmRlY2ltYWxVdGlscy5mcm9tKHZhbHVlKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gUHJpdmF0ZSBtZXRob2RzXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICBwcml2YXRlIGNoZWNrRXhwcmVzc2lvbkxlbmd0aChleHByZXNzaW9uOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBtYXhMZW5ndGggPSB0aGlzLmNvbmZpZy5zZWN1cml0eT8ubWF4RXhwcmVzc2lvbkxlbmd0aCA/PyAxMDAwMDtcbiAgICBpZiAoZXhwcmVzc2lvbi5sZW5ndGggPiBtYXhMZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBNYXhFeHByZXNzaW9uTGVuZ3RoRXJyb3IoZXhwcmVzc2lvbi5sZW5ndGgsIG1heExlbmd0aCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVDb250ZXh0KGNvbnRleHQ6IEV2YWx1YXRpb25Db250ZXh0KTogRXZhbHVhdGlvbkNvbnRleHQge1xuICAgIC8vIERlZXAgY29weSBhbmQgY29udmVydCBudW1lcmljIHZhbHVlcyB0byBEZWNpbWFsIGlmIGF1dG9Db252ZXJ0RmxvYXRzIGlzIGVuYWJsZWRcbiAgICBjb25zdCBhdXRvQ29udmVydCA9IHRoaXMuY29uZmlnLmRlY2ltYWw/LmF1dG9Db252ZXJ0RmxvYXRzID8/IHRydWU7XG5cbiAgICBpZiAoIWF1dG9Db252ZXJ0KSB7XG4gICAgICByZXR1cm4geyAuLi5jb250ZXh0IH07XG4gICAgfVxuXG4gICAgY29uc3Qgbm9ybWFsaXplZFZhcmlhYmxlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhjb250ZXh0LnZhcmlhYmxlcykpIHtcbiAgICAgIG5vcm1hbGl6ZWRWYXJpYWJsZXNba2V5XSA9IHRoaXMuY29udmVydFZhbHVlKHZhbHVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uY29udGV4dCxcbiAgICAgIHZhcmlhYmxlczogbm9ybWFsaXplZFZhcmlhYmxlcyxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBjb252ZXJ0VmFsdWUodmFsdWU6IHVua25vd24pOiB1bmtub3duIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyAmJiAhaXNOYU4odmFsdWUpICYmIGlzRmluaXRlKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIHRoaXMuZGVjaW1hbFV0aWxzLmZyb20odmFsdWUpO1xuICAgIH1cbiAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiB2YWx1ZS5tYXAodiA9PiB0aGlzLmNvbnZlcnRWYWx1ZSh2KSk7XG4gICAgfVxuICAgIGlmICh2YWx1ZSAhPT0gbnVsbCAmJiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XG4gICAgICBjb25zdCBjb252ZXJ0ZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YWx1ZSkpIHtcbiAgICAgICAgY29udmVydGVkW2tdID0gdGhpcy5jb252ZXJ0VmFsdWUodik7XG4gICAgICB9XG4gICAgICByZXR1cm4gY29udmVydGVkO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICBwcml2YXRlIGlzRGVjaW1hbCh2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIERlY2ltYWw7XG4gIH1cblxuICBwcml2YXRlIGFwcGx5Um91bmRpbmcoXG4gICAgdmFsdWU6IERlY2ltYWwsXG4gICAgY29uZmlnOiB7IG1vZGU6IHN0cmluZzsgcHJlY2lzaW9uOiBudW1iZXIgfVxuICApOiBEZWNpbWFsIHtcbiAgICBpZiAoY29uZmlnLm1vZGUgPT09ICdOT05FJykge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5kZWNpbWFsVXRpbHMucm91bmQodmFsdWUsIGNvbmZpZy5wcmVjaXNpb24sIGNvbmZpZy5tb2RlIGFzIGFueSk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUVycm9yKGZvcm11bGE6IEZvcm11bGFEZWZpbml0aW9uLCBfZXJyb3I/OiBFcnJvcik6IHVua25vd24ge1xuICAgIGNvbnN0IGJlaGF2aW9yID0gZm9ybXVsYS5vbkVycm9yO1xuICAgIGlmICghYmVoYXZpb3IpIHJldHVybiBudWxsO1xuXG4gICAgc3dpdGNoIChiZWhhdmlvci50eXBlKSB7XG4gICAgICBjYXNlICdOVUxMJzpcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICBjYXNlICdaRVJPJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVjaW1hbFV0aWxzLnplcm8oKTtcbiAgICAgIGNhc2UgJ0RFRkFVTFQnOlxuICAgICAgICByZXR1cm4gYmVoYXZpb3IuZGVmYXVsdFZhbHVlID8/IGZvcm11bGEuZGVmYXVsdFZhbHVlID8/IG51bGw7XG4gICAgICBjYXNlICdTS0lQJzpcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIGNhc2UgJ1RIUk9XJzpcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IF9lcnJvcjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG1heWJlRXZpY3RDYWNoZSgpOiB2b2lkIHtcbiAgICBjb25zdCBtYXhTaXplID0gdGhpcy5jb25maWcubWF4Q2FjaGVTaXplID8/IDEwMDA7XG4gICAgaWYgKHRoaXMuYXN0Q2FjaGUuc2l6ZSA+PSBtYXhTaXplKSB7XG4gICAgICAvLyBTaW1wbGUgRklGTyBldmljdGlvbiAtIHJlbW92ZSBmaXJzdCAxMCUgb2YgZW50cmllc1xuICAgICAgY29uc3QgdG9SZW1vdmUgPSBNYXRoLmNlaWwobWF4U2l6ZSAqIDAuMSk7XG4gICAgICBjb25zdCBrZXlzID0gQXJyYXkuZnJvbSh0aGlzLmFzdENhY2hlLmtleXMoKSkuc2xpY2UoMCwgdG9SZW1vdmUpO1xuICAgICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgICB0aGlzLmFzdENhY2hlLmRlbGV0ZShrZXkpO1xuICAgICAgICB0aGlzLmRlcGVuZGVuY3lDYWNoZS5kZWxldGUoa2V5KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
|
370
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZm9ybXVsYS1lbmdpbmUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvZm9ybXVsYS1lbmdpbmUudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBYUEscUNBQWtDO0FBQ2xDLDJDQUF3QztBQUN4QyxpRUFBNkQ7QUFDN0QseURBQTZFO0FBQzdFLG1EQUF3RDtBQUN4RCwyQ0FBcUQ7QUFDckQscUNBS2tCO0FBRWxCLE1BQWEsYUFBYTtJQWV4QixZQUFZLE1BQTRCO1FBTnhDLFNBQVM7UUFDRCxhQUFRLEdBQXlCLElBQUksR0FBRyxFQUFFLENBQUM7UUFDM0Msb0JBQWUsR0FBNkIsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUN0RCxjQUFTLEdBQVcsQ0FBQyxDQUFDO1FBQ3RCLGdCQUFXLEdBQVcsQ0FBQyxDQUFDO1FBRzlCLElBQUksQ0FBQyxNQUFNLEdBQUc7WUFDWixXQUFXLEVBQUUsSUFBSTtZQUNqQixZQUFZLEVBQUUsSUFBSTtZQUNsQixVQUFVLEVBQUUsSUFBSTtZQUNoQixHQUFHLE1BQU07U0FDVixDQUFDO1FBRUYsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLDRCQUFZLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsU0FBUyxHQUFHLElBQUEsa0NBQXNCLEVBQUMsSUFBSSxDQUFDLFlBQVksQ0FBQyxDQUFDO1FBQzNELElBQUksQ0FBQyxNQUFNLEdBQUcsSUFBSSxlQUFNLEVBQUUsQ0FBQztRQUMzQixJQUFJLENBQUMsbUJBQW1CLEdBQUcsSUFBSSwwQ0FBbUIsRUFBRSxDQUFDO1FBQ3JELElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSx5Q0FBc0IsRUFBRSxDQUFDO1FBQ2pELElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxxQkFBUyxDQUFDLElBQUksQ0FBQyxZQUFZLEVBQUUsSUFBSSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFFL0UsNENB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LENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQ25DLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztDQUNGO0FBcmFELHNDQXFhQyIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7XG4gIEZvcm11bGFFbmdpbmVDb25maWcsXG4gIEZvcm11bGFEZWZpbml0aW9uLFxuICBFdmFsdWF0aW9uQ29udGV4dCxcbiAgRXZhbHVhdGlvblJlc3VsdCxcbiAgRXZhbHVhdGlvblJlc3VsdFNldCxcbiAgRXZhbHVhdGVBbGxPcHRpb25zLFxuICBWYWxpZGF0aW9uUmVzdWx0LFxuICBGdW5jdGlvbkRlZmluaXRpb24sXG4gIEFTVE5vZGUsXG4gIENhY2hlU3RhdHMsXG4gIERlcGVuZGVuY3lHcmFwaCBhcyBJRGVwZW5kZW5jeUdyYXBoLFxufSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IFBhcnNlciB9IGZyb20gJy4vcGFyc2VyJztcbmltcG9ydCB7IEV2YWx1YXRvciB9IGZyb20gJy4vZXZhbHVhdG9yJztcbmltcG9ydCB7IERlcGVuZGVuY3lFeHRyYWN0b3IgfSBmcm9tICcuL2RlcGVuZGVuY3ktZXh0cmFjdG9yJztcbmltcG9ydCB7IERlcGVuZGVuY3lHcmFwaCwgRGVwZW5kZW5jeUdyYXBoQnVpbGRlciB9IGZyb20gJy4vZGVwZW5kZW5jeS1ncmFwaCc7XG5pbXBvcnQgeyBEZWNpbWFsVXRpbHMsIERlY2ltYWwgfSBmcm9tICcuL2RlY2ltYWwtdXRpbHMnO1xuaW1wb3J0IHsgY3JlYXRlQnVpbHRJbkZ1bmN0aW9ucyB9IGZyb20gJy4vZnVuY3Rpb25zJztcbmltcG9ydCB7XG4gIEZvcm11bGFFbmdpbmVFcnJvcixcbiAgR2VuZXJhbEZvcm11bGFFcnJvcixcbiAgRHVwbGljYXRlRm9ybXVsYUVycm9yLFxuICBNYXhFeHByZXNzaW9uTGVuZ3RoRXJyb3IsXG59IGZyb20gJy4vZXJyb3JzJztcblxuZXhwb3J0IGNsYXNzIEZvcm11bGFFbmdpbmUge1xuICBwcml2YXRlIGNvbmZpZzogRm9ybXVsYUVuZ2luZUNvbmZpZztcbiAgcHJpdmF0ZSBwYXJzZXI6IFBhcnNlcjtcbiAgcHJpdmF0ZSBldmFsdWF0b3I6IEV2YWx1YXRvcjtcbiAgcHJpdmF0ZSBkZXBlbmRlbmN5RXh0cmFjdG9yOiBEZXBlbmRlbmN5RXh0cmFjdG9yO1xuICBwcml2YXRlIGdyYXBoQnVpbGRlcjogRGVwZW5kZW5jeUdyYXBoQnVpbGRlcjtcbiAgcHJpdmF0ZSBkZWNpbWFsVXRpbHM6IERlY2ltYWxVdGlscztcbiAgcHJpdmF0ZSBmdW5jdGlvbnM6IE1hcDxzdHJpbmcsIEZ1bmN0aW9uRGVmaW5pdGlvbj47XG5cbiAgLy8gQ2FjaGVzXG4gIHByaXZhdGUgYXN0Q2FjaGU6IE1hcDxzdHJpbmcsIEFTVE5vZGU+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIGRlcGVuZGVuY3lDYWNoZTogTWFwPHN0cmluZywgU2V0PHN0cmluZz4+ID0gbmV3IE1hcCgpO1xuICBwcml2YXRlIGNhY2hlSGl0czogbnVtYmVyID0gMDtcbiAgcHJpdmF0ZSBjYWNoZU1pc3NlczogbnVtYmVyID0gMDtcblxuICBjb25zdHJ1Y3Rvcihjb25maWc/OiBGb3JtdWxhRW5naW5lQ29uZmlnKSB7XG4gICAgdGhpcy5jb25maWcgPSB7XG4gICAgICBlbmFibGVDYWNoZTogdHJ1ZSxcbiAgICAgIG1heENhY2hlU2l6ZTogMTAwMCxcbiAgICAgIHN0cmljdE1vZGU6IHRydWUsXG4gICAgICAuLi5jb25maWcsXG4gICAgfTtcblxuICAgIHRoaXMuZGVjaW1hbFV0aWxzID0gbmV3IERlY2ltYWxVdGlscyh0aGlzLmNvbmZpZy5kZWNpbWFsKTtcbiAgICB0aGlzLmZ1bmN0aW9ucyA9IGNyZWF0ZUJ1aWx0SW5GdW5jdGlvbnModGhpcy5kZWNpbWFsVXRpbHMpO1xuICAgIHRoaXMucGFyc2VyID0gbmV3IFBhcnNlcigpO1xuICAgIHRoaXMuZGVwZW5kZW5jeUV4dHJhY3RvciA9IG5ldyBEZXBlbmRlbmN5RXh0cmFjdG9yKCk7XG4gICAgdGhpcy5ncmFwaEJ1aWxkZXIgPSBuZXcgRGVwZW5kZW5jeUdyYXBoQnVpbGRlcigpO1xuICAgIHRoaXMuZXZhbHVhdG9yID0gbmV3IEV2YWx1YXRvcih0aGlzLmRlY2ltYWxVdGlscywgdGhpcy5mdW5jdGlvbnMsIHRoaXMuY29uZmlnKTtcblxuICAgIC8vIFJlZ2lzdGVyIGFueSBjdXN0b20gZnVuY3Rpb25zIGZyb20gY29uZmlnXG4gICAgaWYgKHRoaXMuY29uZmlnLmZ1bmN0aW9ucykge1xuICAgICAgZm9yIChjb25zdCBmbiBvZiB0aGlzLmNvbmZpZy5mdW5jdGlvbnMpIHtcbiAgICAgICAgdGhpcy5yZWdpc3RlckZ1bmN0aW9uKGZuKTtcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogUGFyc2UgYW4gZXhwcmVzc2lvbiBpbnRvIGFuIEFTVFxuICAgKi9cbiAgcGFyc2UoZXhwcmVzc2lvbjogc3RyaW5nKTogQVNUTm9kZSB7XG4gICAgdGhpcy5jaGVja0V4cHJlc3Npb25MZW5ndGgoZXhwcmVzc2lvbik7XG5cbiAgICBpZiAodGhpcy5jb25maWcuZW5hYmxlQ2FjaGUpIHtcbiAgICAgIGNvbnN0IGNhY2hlZCA9IHRoaXMuYXN0Q2FjaGUuZ2V0KGV4cHJlc3Npb24pO1xuICAgICAgaWYgKGNhY2hlZCkge1xuICAgICAgICB0aGlzLmNhY2hlSGl0cysrO1xuICAgICAgICByZXR1cm4gY2FjaGVkO1xuICAgICAgfVxuICAgICAgdGhpcy5jYWNoZU1pc3NlcysrO1xuICAgIH1cblxuICAgIGNvbnN0IGFzdCA9IHRoaXMucGFyc2VyLnBhcnNlKGV4cHJlc3Npb24pO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUNhY2hlKSB7XG4gICAgICB0aGlzLm1heWJlRXZpY3RDYWNoZSgpO1xuICAgICAgdGhpcy5hc3RDYWNoZS5zZXQoZXhwcmVzc2lvbiwgYXN0KTtcbiAgICB9XG5cbiAgICByZXR1cm4gYXN0O1xuICB9XG5cbiAgLyoqXG4gICAqIEV4dHJhY3QgdmFyaWFibGUgZGVwZW5kZW5jaWVzIGZyb20gYW4gZXhwcmVzc2lvblxuICAgKi9cbiAgZXh0cmFjdERlcGVuZGVuY2llcyhleHByZXNzaW9uOiBzdHJpbmcpOiBTZXQ8c3RyaW5nPiB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUNhY2hlKSB7XG4gICAgICBjb25zdCBjYWNoZWQgPSB0aGlzLmRlcGVuZGVuY3lDYWNoZS5nZXQoZXhwcmVzc2lvbik7XG4gICAgICBpZiAoY2FjaGVkKSB7XG4gICAgICAgIHJldHVybiBuZXcgU2V0KGNhY2hlZCk7XG4gICAgICB9XG4gICAgfVxuXG4gICAgY29uc3QgZGVwcyA9IHRoaXMuZGVwZW5kZW5jeUV4dHJhY3Rvci5leHRyYWN0KGV4cHJlc3Npb24pO1xuXG4gICAgaWYgKHRoaXMuY29uZmlnLmVuYWJsZUNhY2hlKSB7XG4gICAgICB0aGlzLmRlcGVuZGVuY3lDYWNoZS5zZXQoZXhwcmVzc2lvbiwgbmV3IFNldChkZXBzKSk7XG4gICAgfVxuXG4gICAgcmV0dXJuIGRlcHM7XG4gIH1cblxuICAvKipcbiAgICogQnVpbGQgYSBkZXBlbmRlbmN5IGdyYXBoIGZyb20gZm9ybXVsYSBkZWZpbml0aW9uc1xuICAgKi9cbiAgYnVpbGREZXBlbmRlbmN5R3JhcGgoZm9ybXVsYXM6IEZvcm11bGFEZWZpbml0aW9uW10pOiBJRGVwZW5kZW5jeUdyYXBoIHtcbiAgICByZXR1cm4gdGhpcy5ncmFwaEJ1aWxkZXIuYnVpbGQoZm9ybXVsYXMpO1xuICB9XG5cbiAgLyoqXG4gICAqIEdldCB0aGUgZXZhbHVhdGlvbiBvcmRlciBmb3IgZm9ybXVsYXNcbiAgICovXG4gIGdldEV2YWx1YXRpb25PcmRlcihmb3JtdWxhczogRm9ybXVsYURlZmluaXRpb25bXSk6IHN0cmluZ1tdIHtcbiAgICByZXR1cm4gdGhpcy5ncmFwaEJ1aWxkZXIuZ2V0RXZhbHVhdGlvbk9yZGVyKGZvcm11bGFzKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWYWxpZGF0ZSBmb3JtdWxhcyB3aXRob3V0IGV2YWx1YXRpbmdcbiAgICovXG4gIHZhbGlkYXRlKGZvcm11bGFzOiBGb3JtdWxhRGVmaW5pdGlvbltdKTogVmFsaWRhdGlvblJlc3VsdCB7XG4gICAgY29uc3QgZXJyb3JzOiBGb3JtdWxhRW5naW5lRXJyb3JbXSA9IFtdO1xuICAgIGNvbnN0IHdhcm5pbmdzOiBzdHJpbmdbXSA9IFtdO1xuXG4gICAgLy8gQ2hlY2sgZm9yIGR1cGxpY2F0ZSBJRHNcbiAgICBjb25zdCBpZHMgPSBuZXcgU2V0PHN0cmluZz4oKTtcbiAgICBmb3IgKGNvbnN0IGZvcm11bGEgb2YgZm9ybXVsYXMpIHtcbiAgICAgIGlmIChpZHMuaGFzKGZvcm11bGEuaWQpKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKG5ldyBEdXBsaWNhdGVGb3JtdWxhRXJyb3IoZm9ybXVsYS5pZCkpO1xuICAgICAgfVxuICAgICAgaWRzLmFkZChmb3JtdWxhLmlkKTtcbiAgICB9XG5cbiAgICAvLyBUcnkgdG8gcGFyc2UgYWxsIGV4cHJlc3Npb25zXG4gICAgZm9yIChjb25zdCBmb3JtdWxhIG9mIGZvcm11bGFzKSB7XG4gICAgICB0cnkge1xuICAgICAgICB0aGlzLnBhcnNlKGZvcm11bGEuZXhwcmVzc2lvbik7XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBGb3JtdWxhRW5naW5lRXJyb3IpIHtcbiAgICAgICAgICBlcnJvcnMucHVzaChlcnJvcik7XG4gICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgZXJyb3JzLnB1c2gobmV3IEdlbmVyYWxGb3JtdWxhRXJyb3IoU3RyaW5nKGVycm9yKSkpO1xuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gQnVpbGQgZGVwZW5kZW5jeSBncmFwaCBhbmQgY2hlY2sgZm9yIGN5Y2xlc1xuICAgIGxldCBkZXBlbmRlbmN5R3JhcGg6IElEZXBlbmRlbmN5R3JhcGggPSBuZXcgRGVwZW5kZW5jeUdyYXBoKCk7XG4gICAgbGV0IGV2YWx1YXRpb25PcmRlcjogc3RyaW5nW10gPSBbXTtcblxuICAgIHRyeSB7XG4gICAgICBkZXBlbmRlbmN5R3JhcGggPSB0aGlzLmJ1aWxkRGVwZW5kZW5jeUdyYXBoKGZvcm11bGFzKTtcbiAgICAgIGV2YWx1YXRpb25PcmRlciA9IGRlcGVuZGVuY3lHcmFwaC50b3BvbG9naWNhbFNvcnQoKTtcbiAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgaWYgKGVycm9yIGluc3RhbmNlb2YgRm9ybXVsYUVuZ2luZUVycm9yKSB7XG4gICAgICAgIGVycm9ycy5wdXNoKGVycm9yKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgdmFsaWQ6IGVycm9ycy5sZW5ndGggPT09IDAsXG4gICAgICBlcnJvcnMsXG4gICAgICB3YXJuaW5ncyxcbiAgICAgIGRlcGVuZGVuY3lHcmFwaCxcbiAgICAgIGV2YWx1YXRpb25PcmRlcixcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIEV2YWx1YXRlIGEgc2luZ2xlIGV4cHJlc3Npb25cbiAgICovXG4gIGV2YWx1YXRlKGV4cHJlc3Npb246IHN0cmluZywgY29udGV4dDogRXZhbHVhdGlvbkNvbnRleHQpOiBFdmFsdWF0aW9uUmVzdWx0IHtcbiAgICB0aGlzLmNoZWNrRXhwcmVzc2lvbkxlbmd0aChleHByZXNzaW9uKTtcbiAgICBjb25zdCBub3JtYWxpemVkQ29udGV4dCA9IHRoaXMubm9ybWFsaXplQ29udGV4dChjb250ZXh0KTtcbiAgICByZXR1cm4gdGhpcy5ldmFsdWF0b3IuZXZhbHVhdGUoZXhwcmVzc2lvbiwgbm9ybWFsaXplZENvbnRleHQpO1xuICB9XG5cbiAgLyoqXG4gICAqIEV2YWx1YXRlIGFsbCBmb3JtdWxhcyBpbiBkZXBlbmRlbmN5IG9yZGVyXG4gICAqXG4gICAqIEBwYXJhbSBmb3JtdWxhcyAtIEFycmF5IG9mIGZvcm11bGEgZGVmaW5pdGlvbnMgdG8gZXZhbHVhdGVcbiAgICogQHBhcmFtIGNvbnRleHQgLSBFdmFsdWF0aW9uIGNvbnRleHQgd2l0aCB2YXJpYWJsZXNcbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcHRpb25hbCBjb25maWd1cmF0aW9uIGZvciBiYXRjaCBldmFsdWF0aW9uXG4gICAqL1xuICBldmFsdWF0ZUFsbChcbiAgICBmb3JtdWxhczogRm9ybXVsYURlZmluaXRpb25bXSxcbiAgICBjb250ZXh0OiBFdmFsdWF0aW9uQ29udGV4dCxcbiAgICBvcHRpb25zPzogRXZhbHVhdGVBbGxPcHRpb25zXG4gICk6IEV2YWx1YXRpb25SZXN1bHRTZXQge1xuICAgIGNvbnN0IHN0YXJ0VGltZSA9IERhdGUubm93KCk7XG4gICAgY29uc3QgcmVzdWx0cyA9IG5ldyBNYXA8c3RyaW5nLCBFdmFsdWF0aW9uUmVzdWx0PigpO1xuICAgIGNvbnN0IGVycm9yczogRXJyb3JbXSA9IFtdO1xuXG4gICAgLy8gR2V0IGV2YWx1YXRpb24gb3JkZXJcbiAgICBsZXQgZXZhbHVhdGlvbk9yZGVyOiBzdHJpbmdbXTtcbiAgICB0cnkge1xuICAgICAgZXZhbHVhdGlvbk9yZGVyID0gdGhpcy5nZXRFdmFsdWF0aW9uT3JkZXIoZm9ybXVsYXMpO1xuICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICByZXR1cm4ge1xuICAgICAgICByZXN1bHRzLFxuICAgICAgICBzdWNjZXNzOiBmYWxzZSxcbiAgICAgICAgZXJyb3JzOiBbZXJyb3IgYXMgRXJyb3JdLFxuICAgICAgICB0b3RhbEV4ZWN1dGlvblRpbWVNczogRGF0ZS5ub3coKSAtIHN0YXJ0VGltZSxcbiAgICAgICAgZXZhbHVhdGlvbk9yZGVyOiBbXSxcbiAgICAgIH07XG4gICAgfVxuXG4gICAgLy8gQ3JlYXRlIGEgbWFwIG9mIGZvcm11bGFzIGJ5IElEXG4gICAgY29uc3QgZm9ybXVsYU1hcCA9IG5ldyBNYXA8c3RyaW5nLCBGb3JtdWxhRGVmaW5pdGlvbj4oKTtcbiAgICBmb3IgKGNvbnN0IGZvcm11bGEgb2YgZm9ybXVsYXMpIHtcbiAgICAgIGZvcm11bGFNYXAuc2V0KGZvcm11bGEuaWQsIGZvcm11bGEpO1xuICAgIH1cblxuICAgIC8vIERldGVybWluZSBpZiBpbnRlcm1lZGlhdGUgcm91bmRpbmcgc2hvdWxkIGJlIGFwcGxpZWRcbiAgICBjb25zdCBhcHBseUludGVybWVkaWF0ZVJvdW5kaW5nID1cbiAgICAgIHRoaXMuY29uZmlnLmRlZmF1bHRSb3VuZGluZyAmJlxuICAgICAgdGhpcy5jb25maWcuZGVmYXVsdFJvdW5kaW5nLm1vZGUgIT09ICdOT05FJyAmJlxuICAgICAgIW9wdGlvbnM/LmRpc2FibGVJbnRlcm1lZGlhdGVSb3VuZGluZztcblxuICAgIC8vIEV2YWx1YXRlIGluIG9yZGVyLCBtZXJnaW5nIHJlc3VsdHMgaW50byBjb250ZXh0XG4gICAgY29uc3Qgd29ya2luZ0NvbnRleHQ6IEV2YWx1YXRpb25Db250ZXh0ID0gdGhpcy5ub3JtYWxpemVDb250ZXh0KGNvbnRleHQpO1xuXG4gICAgZm9yIChjb25zdCBmb3JtdWxhSWQgb2YgZXZhbHVhdGlvbk9yZGVyKSB7XG4gICAgICBjb25zdCBmb3JtdWxhID0gZm9ybXVsYU1hcC5nZXQoZm9ybXVsYUlkKTtcbiAgICAgIGlmICghZm9ybXVsYSkgY29udGludWU7XG5cbiAgICAgIHRyeSB7XG4gICAgICAgIGNvbnN0IHJlc3VsdCA9IHRoaXMuZXZhbHVhdG9yLmV2YWx1YXRlKGZvcm11bGEuZXhwcmVzc2lvbiwgd29ya2luZ0NvbnRleHQpO1xuXG4gICAgICAgIC8vIEFwcGx5IHJvdW5kaW5nOiBwZXItZm9ybXVsYSBjb25maWcgdGFrZXMgcHJlY2VkZW5jZSwgdGhlbiBkZWZhdWx0Um91bmRpbmdcbiAgICAgICAgbGV0IHZhbHVlID0gcmVzdWx0LnZhbHVlO1xuICAgICAgICBpZiAodGhpcy5pc0RlY2ltYWwodmFsdWUpKSB7XG4gICAgICAgICAgaWYgKGZvcm11bGEucm91bmRpbmcpIHtcbiAgICAgICAgICAgIC8vIFBlci1mb3JtdWxhIHJvdW5kaW5nIGFsd2F5cyB0YWtlcyBwcmVjZWRlbmNlXG4gICAgICAgICAgICB2YWx1ZSA9IHRoaXMuYXBwbHlSb3VuZGluZyh2YWx1ZSBhcyBEZWNpbWFsLCBmb3JtdWxhLnJvdW5kaW5nKTtcbiAgICAgICAgICB9IGVsc2UgaWYgKGFwcGx5SW50ZXJtZWRpYXRlUm91bmRpbmcpIHtcbiAgICAgICAgICAgIC8vIEFwcGx5IGRlZmF1bHQgcm91bmRpbmcgdG8gaW50ZXJtZWRpYXRlIHZhbHVlc1xuICAgICAgICAgICAgdmFsdWUgPSB0aGlzLmFwcGx5Um91bmRpbmcodmFsdWUgYXMgRGVjaW1hbCwgdGhpcy5jb25maWcuZGVmYXVsdFJvdW5kaW5nISk7XG4gICAgICAgICAgfVxuICAgICAgICB9XG5cbiAgICAgICAgLy8gSGFuZGxlIGVycm9ycyBiYXNlZCBvbiBmb3JtdWxhIGNvbmZpZ1xuICAgICAgICBpZiAoIXJlc3VsdC5zdWNjZXNzICYmIGZvcm11bGEub25FcnJvcikge1xuICAgICAgICAgIHZhbHVlID0gdGhpcy5oYW5kbGVFcnJvcihmb3JtdWxhLCByZXN1bHQuZXJyb3IpO1xuICAgICAgICB9XG5cbiAgICAgICAgcmVzdWx0cy5zZXQoZm9ybXVsYUlkLCB7XG4gICAgICAgICAgLi4ucmVzdWx0LFxuICAgICAgICAgIHZhbHVlLFxuICAgICAgICB9KTtcblxuICAgICAgICAvLyBNZXJnZSByZXN1bHQgaW50byBjb250ZXh0IGZvciBzdWJzZXF1ZW50IGZvcm11bGFzXG4gICAgICAgIHdvcmtpbmdDb250ZXh0LnZhcmlhYmxlc1tmb3JtdWxhSWRdID0gdmFsdWU7XG5cbiAgICAgICAgaWYgKCFyZXN1bHQuc3VjY2Vzcykge1xuICAgICAgICAgIGVycm9ycy5wdXNoKHJlc3VsdC5lcnJvciEpO1xuICAgICAgICB9XG4gICAgICB9IGNhdGNoIChlcnJvcikge1xuICAgICAgICBjb25zdCBldmFsUmVzdWx0OiBFdmFsdWF0aW9uUmVzdWx0ID0ge1xuICAgICAgICAgIHZhbHVlOiBudWxsLFxuICAgICAgICAgIHN1Y2Nlc3M6IGZhbHNlLFxuICAgICAgICAgIGVycm9yOiBlcnJvciBhcyBFcnJvcixcbiAgICAgICAgICBleGVjdXRpb25UaW1lTXM6IDAsXG4gICAgICAgICAgYWNjZXNzZWRWYXJpYWJsZXM6IG5ldyBTZXQoKSxcbiAgICAgICAgfTtcblxuICAgICAgICAvLyBIYW5kbGUgZXJyb3IgYmFzZWQgb24gZm9ybXVsYSBjb25maWdcbiAgICAgICAgaWYgKGZvcm11bGEub25FcnJvcikge1xuICAgICAgICAgIGV2YWxSZXN1bHQudmFsdWUgPSB0aGlzLmhhbmRsZUVycm9yKGZvcm11bGEsIGVycm9yIGFzIEVycm9yKTtcbiAgICAgICAgfVxuXG4gICAgICAgIHJlc3VsdHMuc2V0KGZvcm11bGFJZCwgZXZhbFJlc3VsdCk7XG4gICAgICAgIGVycm9ycy5wdXNoKGVycm9yIGFzIEVycm9yKTtcblxuICAgICAgICAvLyBTdGlsbCBhZGQgdG8gY29udGV4dCAoYXMgbnVsbCBvciBkZWZhdWx0IHZhbHVlKSBzbyBkZXBlbmRlbnQgZm9ybXVsYXMgY2FuIHByb2NlZWRcbiAgICAgICAgd29ya2luZ0NvbnRleHQudmFyaWFibGVzW2Zvcm11bGFJZF0gPSBldmFsUmVzdWx0LnZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiB7XG4gICAgICByZXN1bHRzLFxuICAgICAgc3VjY2VzczogZXJyb3JzLmxlbmd0aCA9PT0gMCxcbiAgICAgIGVycm9ycyxcbiAgICAgIHRvdGFsRXhlY3V0aW9uVGltZU1zOiBEYXRlLm5vdygpIC0gc3RhcnRUaW1lLFxuICAgICAgZXZhbHVhdGlvbk9yZGVyLFxuICAgIH07XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0ZXIgYSBjdXN0b20gZnVuY3Rpb25cbiAgICovXG4gIHJlZ2lzdGVyRnVuY3Rpb24oZGVmaW5pdGlvbjogRnVuY3Rpb25EZWZpbml0aW9uKTogdm9pZCB7XG4gICAgY29uc3QgbmFtZSA9IGRlZmluaXRpb24ubmFtZS50b1VwcGVyQ2FzZSgpO1xuICAgIHRoaXMuZnVuY3Rpb25zLnNldChuYW1lLCBkZWZpbml0aW9uKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBSZWdpc3RlciBtdWx0aXBsZSBjdXN0b20gZnVuY3Rpb25zXG4gICAqL1xuICByZWdpc3RlckZ1bmN0aW9ucyhkZWZpbml0aW9uczogRnVuY3Rpb25EZWZpbml0aW9uW10pOiB2b2lkIHtcbiAgICBmb3IgKGNvbnN0IGRlZmluaXRpb24gb2YgZGVmaW5pdGlvbnMpIHtcbiAgICAgIHRoaXMucmVnaXN0ZXJGdW5jdGlvbihkZWZpbml0aW9uKTtcbiAgICB9XG4gIH1cblxuICAvKipcbiAgICogR2V0IHJlZ2lzdGVyZWQgZnVuY3Rpb24gbmFtZXNcbiAgICovXG4gIGdldFJlZ2lzdGVyZWRGdW5jdGlvbnMoKTogc3RyaW5nW10ge1xuICAgIHJldHVybiBBcnJheS5mcm9tKHRoaXMuZnVuY3Rpb25zLmtleXMoKSk7XG4gIH1cblxuICAvKipcbiAgICogQ2xlYXIgdGhlIEFTVCBjYWNoZVxuICAgKi9cbiAgY2xlYXJDYWNoZSgpOiB2b2lkIHtcbiAgICB0aGlzLmFzdENhY2hlLmNsZWFyKCk7XG4gICAgdGhpcy5kZXBlbmRlbmN5Q2FjaGUuY2xlYXIoKTtcbiAgICB0aGlzLmNhY2hlSGl0cyA9IDA7XG4gICAgdGhpcy5jYWNoZU1pc3NlcyA9IDA7XG4gIH1cblxuICAvKipcbiAgICogR2V0IGNhY2hlIHN0YXRpc3RpY3NcbiAgICovXG4gIGdldENhY2hlU3RhdHMoKTogQ2FjaGVTdGF0cyB7XG4gICAgY29uc3QgdG90YWwgPSB0aGlzLmNhY2hlSGl0cyArIHRoaXMuY2FjaGVNaXNzZXM7XG4gICAgcmV0dXJuIHtcbiAgICAgIHNpemU6IHRoaXMuYXN0Q2FjaGUuc2l6ZSxcbiAgICAgIGhpdHM6IHRoaXMuY2FjaGVIaXRzLFxuICAgICAgbWlzc2VzOiB0aGlzLmNhY2hlTWlzc2VzLFxuICAgICAgaGl0UmF0ZTogdG90YWwgPiAwID8gdGhpcy5jYWNoZUhpdHMgLyB0b3RhbCA6IDAsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZXQgdGhlIGRlY2ltYWwgdXRpbGl0aWVzIGluc3RhbmNlXG4gICAqL1xuICBnZXREZWNpbWFsVXRpbHMoKTogRGVjaW1hbFV0aWxzIHtcbiAgICByZXR1cm4gdGhpcy5kZWNpbWFsVXRpbHM7XG4gIH1cblxuICAvKipcbiAgICogQ3JlYXRlIGEgRGVjaW1hbCBmcm9tIGEgdmFsdWVcbiAgICovXG4gIGNyZWF0ZURlY2ltYWwodmFsdWU6IHN0cmluZyB8IG51bWJlcik6IERlY2ltYWwge1xuICAgIHJldHVybiB0aGlzLmRlY2ltYWxVdGlscy5mcm9tKHZhbHVlKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gUHJpdmF0ZSBtZXRob2RzXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuICBwcml2YXRlIGNoZWNrRXhwcmVzc2lvbkxlbmd0aChleHByZXNzaW9uOiBzdHJpbmcpOiB2b2lkIHtcbiAgICBjb25zdCBtYXhMZW5ndGggPSB0aGlzLmNvbmZpZy5zZWN1cml0eT8ubWF4RXhwcmVzc2lvbkxlbmd0aCA/PyAxMDAwMDtcbiAgICBpZiAoZXhwcmVzc2lvbi5sZW5ndGggPiBtYXhMZW5ndGgpIHtcbiAgICAgIHRocm93IG5ldyBNYXhFeHByZXNzaW9uTGVuZ3RoRXJyb3IoZXhwcmVzc2lvbi5sZW5ndGgsIG1heExlbmd0aCk7XG4gICAgfVxuICB9XG5cbiAgcHJpdmF0ZSBub3JtYWxpemVDb250ZXh0KGNvbnRleHQ6IEV2YWx1YXRpb25Db250ZXh0KTogRXZhbHVhdGlvbkNvbnRleHQge1xuICAgIC8vIERlZXAgY29weSBhbmQgY29udmVydCBudW1lcmljIHZhbHVlcyB0byBEZWNpbWFsIGlmIGF1dG9Db252ZXJ0RmxvYXRzIGlzIGVuYWJsZWRcbiAgICBjb25zdCBhdXRvQ29udmVydCA9IHRoaXMuY29uZmlnLmRlY2ltYWw/LmF1dG9Db252ZXJ0RmxvYXRzID8/IHRydWU7XG5cbiAgICBpZiAoIWF1dG9Db252ZXJ0KSB7XG4gICAgICByZXR1cm4geyAuLi5jb250ZXh0IH07XG4gICAgfVxuXG4gICAgY29uc3Qgbm9ybWFsaXplZFZhcmlhYmxlczogUmVjb3JkPHN0cmluZywgdW5rbm93bj4gPSB7fTtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhjb250ZXh0LnZhcmlhYmxlcykpIHtcbiAgICAgIG5vcm1hbGl6ZWRWYXJpYWJsZXNba2V5XSA9IHRoaXMuY29udmVydFZhbHVlKHZhbHVlKTtcbiAgICB9XG5cbiAgICByZXR1cm4ge1xuICAgICAgLi4uY29udGV4dCxcbiAgICAgIHZhcmlhYmxlczogbm9ybWFsaXplZFZhcmlhYmxlcyxcbiAgICB9O1xuICB9XG5cbiAgcHJpdmF0ZSBjb252ZXJ0VmFsdWUodmFsdWU6IHVua25vd24pOiB1bmtub3duIHtcbiAgICBpZiAodHlwZW9mIHZhbHVlID09PSAnbnVtYmVyJyAmJiAhaXNOYU4odmFsdWUpICYmIGlzRmluaXRlKHZhbHVlKSkge1xuICAgICAgcmV0dXJuIHRoaXMuZGVjaW1hbFV0aWxzLmZyb20odmFsdWUpO1xuICAgIH1cbiAgICBpZiAoQXJyYXkuaXNBcnJheSh2YWx1ZSkpIHtcbiAgICAgIHJldHVybiB2YWx1ZS5tYXAodiA9PiB0aGlzLmNvbnZlcnRWYWx1ZSh2KSk7XG4gICAgfVxuICAgIGlmICh2YWx1ZSAhPT0gbnVsbCAmJiB0eXBlb2YgdmFsdWUgPT09ICdvYmplY3QnKSB7XG4gICAgICBjb25zdCBjb252ZXJ0ZWQ6IFJlY29yZDxzdHJpbmcsIHVua25vd24+ID0ge307XG4gICAgICBmb3IgKGNvbnN0IFtrLCB2XSBvZiBPYmplY3QuZW50cmllcyh2YWx1ZSkpIHtcbiAgICAgICAgY29udmVydGVkW2tdID0gdGhpcy5jb252ZXJ0VmFsdWUodik7XG4gICAgICB9XG4gICAgICByZXR1cm4gY29udmVydGVkO1xuICAgIH1cbiAgICByZXR1cm4gdmFsdWU7XG4gIH1cblxuICBwcml2YXRlIGlzRGVjaW1hbCh2YWx1ZTogdW5rbm93bik6IGJvb2xlYW4ge1xuICAgIHJldHVybiB2YWx1ZSBpbnN0YW5jZW9mIERlY2ltYWw7XG4gIH1cblxuICBwcml2YXRlIGFwcGx5Um91bmRpbmcoXG4gICAgdmFsdWU6IERlY2ltYWwsXG4gICAgY29uZmlnOiB7IG1vZGU6IHN0cmluZzsgcHJlY2lzaW9uOiBudW1iZXIgfVxuICApOiBEZWNpbWFsIHtcbiAgICBpZiAoY29uZmlnLm1vZGUgPT09ICdOT05FJykge1xuICAgICAgcmV0dXJuIHZhbHVlO1xuICAgIH1cbiAgICByZXR1cm4gdGhpcy5kZWNpbWFsVXRpbHMucm91bmQodmFsdWUsIGNvbmZpZy5wcmVjaXNpb24sIGNvbmZpZy5tb2RlIGFzIGFueSk7XG4gIH1cblxuICBwcml2YXRlIGhhbmRsZUVycm9yKGZvcm11bGE6IEZvcm11bGFEZWZpbml0aW9uLCBfZXJyb3I/OiBFcnJvcik6IHVua25vd24ge1xuICAgIGNvbnN0IGJlaGF2aW9yID0gZm9ybXVsYS5vbkVycm9yO1xuICAgIGlmICghYmVoYXZpb3IpIHJldHVybiBudWxsO1xuXG4gICAgc3dpdGNoIChiZWhhdmlvci50eXBlKSB7XG4gICAgICBjYXNlICdOVUxMJzpcbiAgICAgICAgcmV0dXJuIG51bGw7XG4gICAgICBjYXNlICdaRVJPJzpcbiAgICAgICAgcmV0dXJuIHRoaXMuZGVjaW1hbFV0aWxzLnplcm8oKTtcbiAgICAgIGNhc2UgJ0RFRkFVTFQnOlxuICAgICAgICByZXR1cm4gYmVoYXZpb3IuZGVmYXVsdFZhbHVlID8/IGZvcm11bGEuZGVmYXVsdFZhbHVlID8/IG51bGw7XG4gICAgICBjYXNlICdTS0lQJzpcbiAgICAgICAgcmV0dXJuIHVuZGVmaW5lZDtcbiAgICAgIGNhc2UgJ1RIUk9XJzpcbiAgICAgIGRlZmF1bHQ6XG4gICAgICAgIHRocm93IF9lcnJvcjtcbiAgICB9XG4gIH1cblxuICBwcml2YXRlIG1heWJlRXZpY3RDYWNoZSgpOiB2b2lkIHtcbiAgICBjb25zdCBtYXhTaXplID0gdGhpcy5jb25maWcubWF4Q2FjaGVTaXplID8/IDEwMDA7XG4gICAgaWYgKHRoaXMuYXN0Q2FjaGUuc2l6ZSA+PSBtYXhTaXplKSB7XG4gICAgICAvLyBTaW1wbGUgRklGTyBldmljdGlvbiAtIHJlbW92ZSBmaXJzdCAxMCUgb2YgZW50cmllc1xuICAgICAgY29uc3QgdG9SZW1vdmUgPSBNYXRoLmNlaWwobWF4U2l6ZSAqIDAuMSk7XG4gICAgICBjb25zdCBrZXlzID0gQXJyYXkuZnJvbSh0aGlzLmFzdENhY2hlLmtleXMoKSkuc2xpY2UoMCwgdG9SZW1vdmUpO1xuICAgICAgZm9yIChjb25zdCBrZXkgb2Yga2V5cykge1xuICAgICAgICB0aGlzLmFzdENhY2hlLmRlbGV0ZShrZXkpO1xuICAgICAgICB0aGlzLmRlcGVuZGVuY3lDYWNoZS5kZWxldGUoa2V5KTtcbiAgICAgIH1cbiAgICB9XG4gIH1cbn1cbiJdfQ==
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { FormulaEngine } from './formula-engine';
|
|
2
|
-
export { FormulaEngineConfig, FormulaDefinition, EvaluationContext, FunctionDefinition, ArgumentType, FunctionImplementation, DecimalConfig, DecimalRoundingMode, RoundingConfig, EvaluationResult, EvaluationResultSet, ValidationResult, CacheStats, ErrorBehavior, SecurityConfig, ASTNode, DecimalLiteral, NumberLiteral, StringLiteral, BooleanLiteral, NullLiteral, ArrayLiteral, VariableReference, BinaryOperation, UnaryOperation, ConditionalExpression, FunctionCall, MemberAccess, IndexAccess, DependencyGraph, ValueType, FormulaValue, } from './types';
|
|
2
|
+
export { FormulaEngineConfig, FormulaDefinition, EvaluationContext, FunctionDefinition, ArgumentType, FunctionImplementation, DecimalConfig, DecimalRoundingMode, RoundingConfig, EvaluationResult, EvaluationResultSet, EvaluateAllOptions, ValidationResult, CacheStats, ErrorBehavior, SecurityConfig, ASTNode, DecimalLiteral, NumberLiteral, StringLiteral, BooleanLiteral, NullLiteral, ArrayLiteral, VariableReference, BinaryOperation, UnaryOperation, ConditionalExpression, FunctionCall, MemberAccess, IndexAccess, DependencyGraph, ValueType, FormulaValue, } from './types';
|
|
3
3
|
export { Parser } from './parser';
|
|
4
4
|
export { Lexer } from './lexer';
|
|
5
5
|
export { Evaluator } from './evaluator';
|
package/dist/index.js
CHANGED
|
@@ -58,4 +58,4 @@ Object.defineProperty(exports, "SecurityError", { enumerable: true, get: functio
|
|
|
58
58
|
Object.defineProperty(exports, "MaxIterationsError", { enumerable: true, get: function () { return errors_1.MaxIterationsError; } });
|
|
59
59
|
Object.defineProperty(exports, "MaxRecursionError", { enumerable: true, get: function () { return errors_1.MaxRecursionError; } });
|
|
60
60
|
Object.defineProperty(exports, "MaxExpressionLengthError", { enumerable: true, get: function () { return errors_1.MaxExpressionLengthError; } });
|
|
61
|
-
//# sourceMappingURL=data:application/json;base64,
|
|
61
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBQUEsZUFBZTtBQUNmLG1EQUFpRDtBQUF4QywrR0FBQSxhQUFhLE9BQUE7QUFFdEIsUUFBUTtBQUNSLGlDQStDaUI7QUFwQ2YsNEdBQUEsbUJBQW1CLE9BQUE7QUFzQ3JCLGtDQUFrQztBQUNsQyxtQ0FBa0M7QUFBekIsZ0dBQUEsTUFBTSxPQUFBO0FBQ2YsaUNBQWdDO0FBQXZCLDhGQUFBLEtBQUssT0FBQTtBQUNkLHlDQUF3QztBQUEvQixzR0FBQSxTQUFTLE9BQUE7QUFDbEIsK0RBQTZEO0FBQXBELDJIQUFBLG1CQUFtQixPQUFBO0FBQzVCLHVEQUFvRztBQUEzRix1SEFBQSxlQUFlLE9BQXVCO0FBQUUsMEhBQUEsc0JBQXNCLE9BQUE7QUFDdkUsaURBQXFFO0FBQTVELDZHQUFBLFlBQVksT0FBQTtBQUFFLHdHQUFBLE9BQU8sT0FBQTtBQUM5Qix5Q0FBcUQ7QUFBNUMsbUhBQUEsc0JBQXNCLE9BQUE7QUFFL0IsU0FBUztBQUNULG1DQXdDa0I7QUF2Q2hCLDRHQUFBLGtCQUFrQixPQUFBO0FBQ2xCLDZHQUFBLG1CQUFtQixPQUFBO0FBR25CLGVBQWU7QUFDZixxR0FBQSxXQUFXLE9BQUE7QUFDWCw4R0FBQSxvQkFBb0IsT0FBQTtBQUNwQixpSEFBQSx1QkFBdUIsT0FBQTtBQUN2Qiw0R0FBQSxrQkFBa0IsT0FBQTtBQUVsQixvQkFBb0I7QUFDcEIsaUhBQUEsdUJBQXVCLE9BQUE7QUFDdkIsZ0hBQUEsc0JBQXNCLE9BQUE7QUFDdEIsZ0hBQUEsc0JBQXNCLE9BQUE7QUFDdEIsK0dBQUEscUJBQXFCLE9BQUE7QUFFckIsb0JBQW9CO0FBQ3BCLDZHQUFBLG1CQUFtQixPQUFBO0FBQ25CLDJHQUFBLGlCQUFpQixPQUFBO0FBQ2pCLDRHQUFBLGtCQUFrQixPQUFBO0FBQ2xCLCtHQUFBLHFCQUFxQixPQUFBO0FBQ3JCLDZHQUFBLG1CQUFtQixPQUFBO0FBQ25CLDBHQUFBLGdCQUFnQixPQUFBO0FBRWhCLGlCQUFpQjtBQUNqQixzR0FBQSxZQUFZLE9BQUE7QUFDWiw4R0FBQSxvQkFBb0IsT0FBQTtBQUNwQiwrR0FBQSxxQkFBcUIsT0FBQTtBQUNyQixvSEFBQSwwQkFBMEIsT0FBQTtBQUMxQiw2R0FBQSxtQkFBbUIsT0FBQTtBQUVuQix1QkFBdUI7QUFDdkIsNEdBQUEsa0JBQWtCLE9BQUE7QUFFbEIsa0JBQWtCO0FBQ2xCLHVHQUFBLGFBQWEsT0FBQTtBQUNiLDRHQUFBLGtCQUFrQixPQUFBO0FBQ2xCLDJHQUFBLGlCQUFpQixPQUFBO0FBQ2pCLGtIQUFBLHdCQUF3QixPQUFBIiwic291cmNlc0NvbnRlbnQiOlsiLy8gTWFpbiBleHBvcnRzXG5leHBvcnQgeyBGb3JtdWxhRW5naW5lIH0gZnJvbSAnLi9mb3JtdWxhLWVuZ2luZSc7XG5cbi8vIFR5cGVzXG5leHBvcnQge1xuICAvLyBDb25maWd1cmF0aW9uXG4gIEZvcm11bGFFbmdpbmVDb25maWcsXG4gIEZvcm11bGFEZWZpbml0aW9uLFxuICBFdmFsdWF0aW9uQ29udGV4dCxcbiAgRnVuY3Rpb25EZWZpbml0aW9uLFxuICBBcmd1bWVudFR5cGUsXG4gIEZ1bmN0aW9uSW1wbGVtZW50YXRpb24sXG5cbiAgLy8gRGVjaW1hbFxuICBEZWNpbWFsQ29uZmlnLFxuICBEZWNpbWFsUm91bmRpbmdNb2RlLFxuICBSb3VuZGluZ0NvbmZpZyxcblxuICAvLyBSZXN1bHRzXG4gIEV2YWx1YXRpb25SZXN1bHQsXG4gIEV2YWx1YXRpb25SZXN1bHRTZXQsXG4gIEV2YWx1YXRlQWxsT3B0aW9ucyxcbiAgVmFsaWRhdGlvblJlc3VsdCxcbiAgQ2FjaGVTdGF0cyxcblxuICAvLyBFcnJvciBoYW5kbGluZ1xuICBFcnJvckJlaGF2aW9yLFxuICBTZWN1cml0eUNvbmZpZyxcblxuICAvLyBBU1Qgbm9kZXNcbiAgQVNUTm9kZSxcbiAgRGVjaW1hbExpdGVyYWwsXG4gIE51bWJlckxpdGVyYWwsXG4gIFN0cmluZ0xpdGVyYWwsXG4gIEJvb2xlYW5MaXRlcmFsLFxuICBOdWxsTGl0ZXJhbCxcbiAgQXJyYXlMaXRlcmFsLFxuICBWYXJpYWJsZVJlZmVyZW5jZSxcbiAgQmluYXJ5T3BlcmF0aW9uLFxuICBVbmFyeU9wZXJhdGlvbixcbiAgQ29uZGl0aW9uYWxFeHByZXNzaW9uLFxuICBGdW5jdGlvbkNhbGwsXG4gIE1lbWJlckFjY2VzcyxcbiAgSW5kZXhBY2Nlc3MsXG5cbiAgLy8gR3JhcGhcbiAgRGVwZW5kZW5jeUdyYXBoLFxuXG4gIC8vIFZhbHVlc1xuICBWYWx1ZVR5cGUsXG4gIEZvcm11bGFWYWx1ZSxcbn0gZnJvbSAnLi90eXBlcyc7XG5cbi8vIENvbXBvbmVudHMgKGZvciBhZHZhbmNlZCB1c2FnZSlcbmV4cG9ydCB7IFBhcnNlciB9IGZyb20gJy4vcGFyc2VyJztcbmV4cG9ydCB7IExleGVyIH0gZnJvbSAnLi9sZXhlcic7XG5leHBvcnQgeyBFdmFsdWF0b3IgfSBmcm9tICcuL2V2YWx1YXRvcic7XG5leHBvcnQgeyBEZXBlbmRlbmN5RXh0cmFjdG9yIH0gZnJvbSAnLi9kZXBlbmRlbmN5LWV4dHJhY3Rvcic7XG5leHBvcnQgeyBEZXBlbmRlbmN5R3JhcGggYXMgRGVwZW5kZW5jeUdyYXBoSW1wbCwgRGVwZW5kZW5jeUdyYXBoQnVpbGRlciB9IGZyb20gJy4vZGVwZW5kZW5jeS1ncmFwaCc7XG5leHBvcnQgeyBEZWNpbWFsVXRpbHMsIERlY2ltYWwsIERlY2ltYWxMaWtlIH0gZnJvbSAnLi9kZWNpbWFsLXV0aWxzJztcbmV4cG9ydCB7IGNyZWF0ZUJ1aWx0SW5GdW5jdGlvbnMgfSBmcm9tICcuL2Z1bmN0aW9ucyc7XG5cbi8vIEVycm9yc1xuZXhwb3J0IHtcbiAgRm9ybXVsYUVuZ2luZUVycm9yLFxuICBHZW5lcmFsRm9ybXVsYUVycm9yLFxuICBFcnJvckNhdGVnb3J5LFxuXG4gIC8vIFBhcnNlIGVycm9yc1xuICBTeW50YXhFcnJvcixcbiAgVW5leHBlY3RlZFRva2VuRXJyb3IsXG4gIFVudGVybWluYXRlZFN0cmluZ0Vycm9yLFxuICBJbnZhbGlkTnVtYmVyRXJyb3IsXG5cbiAgLy8gVmFsaWRhdGlvbiBlcnJvcnNcbiAgQ2lyY3VsYXJEZXBlbmRlbmN5RXJyb3IsXG4gIFVuZGVmaW5lZFZhcmlhYmxlRXJyb3IsXG4gIFVuZGVmaW5lZEZ1bmN0aW9uRXJyb3IsXG4gIER1cGxpY2F0ZUZvcm11bGFFcnJvcixcblxuICAvLyBFdmFsdWF0aW9uIGVycm9yc1xuICBEaXZpc2lvbkJ5WmVyb0Vycm9yLFxuICBUeXBlTWlzbWF0Y2hFcnJvcixcbiAgQXJndW1lbnRDb3VudEVycm9yLFxuICBJbnZhbGlkT3BlcmF0aW9uRXJyb3IsXG4gIFByb3BlcnR5QWNjZXNzRXJyb3IsXG4gIEluZGV4QWNjZXNzRXJyb3IsXG5cbiAgLy8gRGVjaW1hbCBlcnJvcnNcbiAgRGVjaW1hbEVycm9yLFxuICBEZWNpbWFsT3ZlcmZsb3dFcnJvcixcbiAgRGVjaW1hbFVuZGVyZmxvd0Vycm9yLFxuICBEZWNpbWFsRGl2aXNpb25CeVplcm9FcnJvcixcbiAgSW52YWxpZERlY2ltYWxFcnJvcixcblxuICAvLyBDb25maWd1cmF0aW9uIGVycm9yc1xuICBDb25maWd1cmF0aW9uRXJyb3IsXG5cbiAgLy8gU2VjdXJpdHkgZXJyb3JzXG4gIFNlY3VyaXR5RXJyb3IsXG4gIE1heEl0ZXJhdGlvbnNFcnJvcixcbiAgTWF4UmVjdXJzaW9uRXJyb3IsXG4gIE1heEV4cHJlc3Npb25MZW5ndGhFcnJvcixcbn0gZnJvbSAnLi9lcnJvcnMnO1xuIl19
|
package/dist/types.d.ts
CHANGED
|
@@ -173,6 +173,14 @@ export interface EvaluationResultSet {
|
|
|
173
173
|
totalExecutionTimeMs: number;
|
|
174
174
|
evaluationOrder: string[];
|
|
175
175
|
}
|
|
176
|
+
export interface EvaluateAllOptions {
|
|
177
|
+
/**
|
|
178
|
+
* When true, disables automatic intermediate rounding even if defaultRounding
|
|
179
|
+
* is configured in the engine. Per-formula rounding configurations are still applied.
|
|
180
|
+
* @default false
|
|
181
|
+
*/
|
|
182
|
+
disableIntermediateRounding?: boolean;
|
|
183
|
+
}
|
|
176
184
|
export interface ValidationResult {
|
|
177
185
|
valid: boolean;
|
|
178
186
|
errors: Error[];
|
package/dist/types.js
CHANGED
|
@@ -59,4 +59,4 @@ var TokenType;
|
|
|
59
59
|
// Special
|
|
60
60
|
TokenType["EOF"] = "EOF";
|
|
61
61
|
})(TokenType || (exports.TokenType = TokenType = {}));
|
|
62
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBVUEsK0VBQStFO0FBQy9FLHdCQUF3QjtBQUN4QiwrRUFBK0U7QUFFL0UsSUFBWSxtQkFTWDtBQVRELFdBQVksbUJBQW1CO0lBQzdCLG9DQUFhLENBQUE7SUFDYixzQ0FBZSxDQUFBO0lBQ2Ysb0NBQWEsQ0FBQTtJQUNiLGdDQUFTLENBQUE7SUFDVCwwQ0FBbUIsQ0FBQTtJQUNuQiw4Q0FBdUIsQ0FBQTtJQUN2Qiw4Q0FBdUIsQ0FBQTtJQUN2Qiw0Q0FBcUIsQ0FBQTtBQUN2QixDQUFDLEVBVFcsbUJBQW1CLG1DQUFuQixtQkFBbUIsUUFTOUI7QUEwUUQsK0VBQStFO0FBQy9FLGNBQWM7QUFDZCwrRUFBK0U7QUFFL0UsSUFBWSxTQTZDWDtBQTdDRCxXQUFZLFNBQVM7SUFDbkIsV0FBVztJQUNYLDhCQUFpQixDQUFBO0lBQ2pCLDhCQUFpQixDQUFBO0lBQ2pCLGdDQUFtQixDQUFBO0lBQ25CLDBCQUFhLENBQUE7SUFFYiw0QkFBNEI7SUFDNUIsc0NBQXlCLENBQUE7SUFDekIsa0NBQXFCLENBQUE7SUFDckIsd0NBQTJCLENBQUE7SUFFM0IsWUFBWTtJQUNaLDBCQUFhLENBQUE7SUFDYiw0QkFBZSxDQUFBO0lBQ2Ysa0NBQXFCLENBQUE7SUFDckIsOEJBQWlCLENBQUE7SUFDakIsOEJBQWlCLENBQUE7SUFDakIsNEJBQWUsQ0FBQTtJQUVmLGFBQWE7SUFDYixzQkFBUyxDQUFBO0lBQ1Qsd0JBQVcsQ0FBQTtJQUNYLHNCQUFTLENBQUE7SUFDVCxzQkFBUyxDQUFBO0lBQ1Qsd0JBQVcsQ0FBQTtJQUNYLHdCQUFXLENBQUE7SUFFWCxVQUFVO0lBQ1Ysd0JBQVcsQ0FBQTtJQUNYLHNCQUFTLENBQUE7SUFDVCx3QkFBVyxDQUFBO0lBRVgsY0FBYztJQUNkLDhCQUFpQixDQUFBO0lBQ2pCLDhCQUFpQixDQUFBO0lBQ2pCLGtDQUFxQixDQUFBO0lBQ3JCLGtDQUFxQixDQUFBO0lBQ3JCLDRCQUFlLENBQUE7SUFDZix3QkFBVyxDQUFBO0lBQ1gsa0NBQXFCLENBQUE7SUFDckIsNEJBQWUsQ0FBQTtJQUVmLFVBQVU7SUFDVix3QkFBVyxDQUFBO0FBQ2IsQ0FBQyxFQTdDVyxTQUFTLHlCQUFULFNBQVMsUUE2Q3BCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGVjaW1hbCB9IGZyb20gJ2RlY2ltYWwuanMnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBWYWx1ZSBUeXBlc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgdHlwZSBWYWx1ZVR5cGUgPSAnbnVtYmVyJyB8ICdkZWNpbWFsJyB8ICdzdHJpbmcnIHwgJ2Jvb2xlYW4nIHwgJ2FycmF5JyB8ICdvYmplY3QnIHwgJ251bGwnIHwgJ2FueSc7XG5cbmV4cG9ydCB0eXBlIEZvcm11bGFWYWx1ZSA9IERlY2ltYWwgfCBudW1iZXIgfCBzdHJpbmcgfCBib29sZWFuIHwgbnVsbCB8IEZvcm11bGFWYWx1ZVtdIHwgeyBba2V5OiBzdHJpbmddOiBGb3JtdWxhVmFsdWUgfTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gRGVjaW1hbCBDb25maWd1cmF0aW9uXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBlbnVtIERlY2ltYWxSb3VuZGluZ01vZGUge1xuICBDRUlMID0gJ0NFSUwnLFxuICBGTE9PUiA9ICdGTE9PUicsXG4gIERPV04gPSAnRE9XTicsXG4gIFVQID0gJ1VQJyxcbiAgSEFMRl9VUCA9ICdIQUxGX1VQJyxcbiAgSEFMRl9ET1dOID0gJ0hBTEZfRE9XTicsXG4gIEhBTEZfRVZFTiA9ICdIQUxGX0VWRU4nLFxuICBIQUxGX09ERCA9ICdIQUxGX09ERCcsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGVjaW1hbENvbmZpZyB7XG4gIHByZWNpc2lvbj86IG51bWJlcjtcbiAgcm91bmRpbmdNb2RlPzogRGVjaW1hbFJvdW5kaW5nTW9kZTtcbiAgZGl2aXNpb25TY2FsZT86IG51bWJlcjtcbiAgcHJlc2VydmVUcmFpbGluZ1plcm9zPzogYm9vbGVhbjtcbiAgYXV0b0NvbnZlcnRGbG9hdHM/OiBib29sZWFuO1xuICBtYXhFeHBvbmVudD86IG51bWJlcjtcbiAgbWluRXhwb25lbnQ/OiBudW1iZXI7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFJvdW5kaW5nIENvbmZpZ3VyYXRpb25cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBSb3VuZGluZ0NvbmZpZyB7XG4gIG1vZGU6ICdIQUxGX1VQJyB8ICdIQUxGX0RPV04nIHwgJ0ZMT09SJyB8ICdDRUlMJyB8ICdOT05FJztcbiAgcHJlY2lzaW9uOiBudW1iZXI7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEVycm9yIEJlaGF2aW9yXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXJyb3JCZWhhdmlvciB7XG4gIHR5cGU6ICdUSFJPVycgfCAnTlVMTCcgfCAnWkVSTycgfCAnREVGQVVMVCcgfCAnU0tJUCc7XG4gIGRlZmF1bHRWYWx1ZT86IHVua25vd247XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEZvcm11bGEgRGVmaW5pdGlvblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIEZvcm11bGFEZWZpbml0aW9uIHtcbiAgaWQ6IHN0cmluZztcbiAgZXhwcmVzc2lvbjogc3RyaW5nO1xuICBkZXBlbmRlbmNpZXM/OiBzdHJpbmdbXTtcbiAgb25FcnJvcj86IEVycm9yQmVoYXZpb3I7XG4gIGRlZmF1bHRWYWx1ZT86IHVua25vd247XG4gIHJvdW5kaW5nPzogUm91bmRpbmdDb25maWc7XG4gIG1ldGFkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEV2YWx1YXRpb24gQ29udGV4dFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIEV2YWx1YXRpb25Db250ZXh0IHtcbiAgdmFyaWFibGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgY29sbGVjdGlvbnM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duW10+O1xuICBleHRyYT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBFbmdpbmUgQ29uZmlndXJhdGlvblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIE9wZXJhdG9yRGVmaW5pdGlvbiB7XG4gIHN5bWJvbDogc3RyaW5nO1xuICBwcmVjZWRlbmNlOiBudW1iZXI7XG4gIGFzc29jaWF0aXZpdHk6ICdsZWZ0JyB8ICdyaWdodCc7XG4gIGhhbmRsZXI6IChsZWZ0OiB1bmtub3duLCByaWdodDogdW5rbm93bikgPT4gdW5rbm93bjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTZWN1cml0eUNvbmZpZyB7XG4gIG1heEV4cHJlc3Npb25MZW5ndGg/OiBudW1iZXI7XG4gIG1heFJlY3Vyc2lvbkRlcHRoPzogbnVtYmVyO1xuICBtYXhJdGVyYXRpb25zPzogbnVtYmVyO1xuICBtYXhFeGVjdXRpb25UaW1lPzogbnVtYmVyO1xuICBhbGxvd2VkRnVuY3Rpb25zPzogc3RyaW5nW107XG4gIGJsb2NrZWRGdW5jdGlvbnM/OiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGb3JtdWxhRW5naW5lQ29uZmlnIHtcbiAgZW5hYmxlQ2FjaGU/OiBib29sZWFuO1xuICBtYXhDYWNoZVNpemU/OiBudW1iZXI7XG4gIGRlZmF1bHRFcnJvckJlaGF2aW9yPzogRXJyb3JCZWhhdmlvcjtcbiAgZGVmYXVsdFJvdW5kaW5nPzogUm91bmRpbmdDb25maWc7XG4gIHZhcmlhYmxlUHJlZml4Pzogc3RyaW5nO1xuICBjb250ZXh0UHJlZml4Pzogc3RyaW5nO1xuICBzdHJpY3RNb2RlPzogYm9vbGVhbjtcbiAgb3BlcmF0b3JzPzogT3BlcmF0b3JEZWZpbml0aW9uW107XG4gIGZ1bmN0aW9ucz86IEZ1bmN0aW9uRGVmaW5pdGlvbltdO1xuICBkZWNpbWFsPzogRGVjaW1hbENvbmZpZztcbiAgc2VjdXJpdHk/OiBTZWN1cml0eUNvbmZpZztcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQVNUIE5vZGUgVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBEZWNpbWFsTGl0ZXJhbCB7XG4gIHR5cGU6ICdEZWNpbWFsTGl0ZXJhbCc7XG4gIHZhbHVlOiBzdHJpbmc7XG4gIHJhdzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE51bWJlckxpdGVyYWwge1xuICB0eXBlOiAnTnVtYmVyTGl0ZXJhbCc7XG4gIHZhbHVlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RyaW5nTGl0ZXJhbCB7XG4gIHR5cGU6ICdTdHJpbmdMaXRlcmFsJztcbiAgdmFsdWU6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBCb29sZWFuTGl0ZXJhbCB7XG4gIHR5cGU6ICdCb29sZWFuTGl0ZXJhbCc7XG4gIHZhbHVlOiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE51bGxMaXRlcmFsIHtcbiAgdHlwZTogJ051bGxMaXRlcmFsJztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBcnJheUxpdGVyYWwge1xuICB0eXBlOiAnQXJyYXlMaXRlcmFsJztcbiAgZWxlbWVudHM6IEFTVE5vZGVbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWYXJpYWJsZVJlZmVyZW5jZSB7XG4gIHR5cGU6ICdWYXJpYWJsZVJlZmVyZW5jZSc7XG4gIHByZWZpeDogJyQnIHwgJ0AnO1xuICBuYW1lOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmluYXJ5T3BlcmF0aW9uIHtcbiAgdHlwZTogJ0JpbmFyeU9wZXJhdGlvbic7XG4gIG9wZXJhdG9yOiBzdHJpbmc7XG4gIGxlZnQ6IEFTVE5vZGU7XG4gIHJpZ2h0OiBBU1ROb2RlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFVuYXJ5T3BlcmF0aW9uIHtcbiAgdHlwZTogJ1VuYXJ5T3BlcmF0aW9uJztcbiAgb3BlcmF0b3I6IHN0cmluZztcbiAgb3BlcmFuZDogQVNUTm9kZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb25kaXRpb25hbEV4cHJlc3Npb24ge1xuICB0eXBlOiAnQ29uZGl0aW9uYWxFeHByZXNzaW9uJztcbiAgY29uZGl0aW9uOiBBU1ROb2RlO1xuICBjb25zZXF1ZW50OiBBU1ROb2RlO1xuICBhbHRlcm5hdGU6IEFTVE5vZGU7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRnVuY3Rpb25DYWxsIHtcbiAgdHlwZTogJ0Z1bmN0aW9uQ2FsbCc7XG4gIG5hbWU6IHN0cmluZztcbiAgYXJndW1lbnRzOiBBU1ROb2RlW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVtYmVyQWNjZXNzIHtcbiAgdHlwZTogJ01lbWJlckFjY2Vzcyc7XG4gIG9iamVjdDogQVNUTm9kZTtcbiAgcHJvcGVydHk6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbmRleEFjY2VzcyB7XG4gIHR5cGU6ICdJbmRleEFjY2Vzcyc7XG4gIG9iamVjdDogQVNUTm9kZTtcbiAgaW5kZXg6IEFTVE5vZGU7XG59XG5cbmV4cG9ydCB0eXBlIEFTVE5vZGUgPVxuICB8IERlY2ltYWxMaXRlcmFsXG4gIHwgTnVtYmVyTGl0ZXJhbFxuICB8IFN0cmluZ0xpdGVyYWxcbiAgfCBCb29sZWFuTGl0ZXJhbFxuICB8IE51bGxMaXRlcmFsXG4gIHwgQXJyYXlMaXRlcmFsXG4gIHwgVmFyaWFibGVSZWZlcmVuY2VcbiAgfCBCaW5hcnlPcGVyYXRpb25cbiAgfCBVbmFyeU9wZXJhdGlvblxuICB8IENvbmRpdGlvbmFsRXhwcmVzc2lvblxuICB8IEZ1bmN0aW9uQ2FsbFxuICB8IE1lbWJlckFjY2Vzc1xuICB8IEluZGV4QWNjZXNzO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBGdW5jdGlvbiBEZWZpbml0aW9uXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgQXJndW1lbnRUeXBlIHtcbiAgbmFtZTogc3RyaW5nO1xuICB0eXBlOiBWYWx1ZVR5cGU7XG4gIHJlcXVpcmVkOiBib29sZWFuO1xuICBkZWZhdWx0PzogdW5rbm93bjtcbn1cblxuZXhwb3J0IHR5cGUgRnVuY3Rpb25JbXBsZW1lbnRhdGlvbiA9IChcbiAgYXJnczogdW5rbm93bltdLFxuICBjb250ZXh0OiBFdmFsdWF0aW9uQ29udGV4dCxcbiAgZW5naW5lOiB1bmtub3duXG4pID0+IHVua25vd247XG5cbmV4cG9ydCBpbnRlcmZhY2UgRnVuY3Rpb25EZWZpbml0aW9uIHtcbiAgbmFtZTogc3RyaW5nO1xuICBtaW5BcmdzOiBudW1iZXI7XG4gIG1heEFyZ3M6IG51bWJlcjtcbiAgYXJnVHlwZXM/OiBBcmd1bWVudFR5cGVbXTtcbiAgcmV0dXJuVHlwZTogVmFsdWVUeXBlO1xuICBpbXBsZW1lbnRhdGlvbjogRnVuY3Rpb25JbXBsZW1lbnRhdGlvbjtcbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIERlcGVuZGVuY3kgR3JhcGhcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBEZXBlbmRlbmN5R3JhcGgge1xuICBub2RlczogU2V0PHN0cmluZz47XG4gIGVkZ2VzOiBNYXA8c3RyaW5nLCBTZXQ8c3RyaW5nPj47XG4gIGhhc0N5Y2xlcygpOiBib29sZWFuO1xuICBnZXRSb290cygpOiBTZXQ8c3RyaW5nPjtcbiAgZ2V0RGVwZW5kZW50cyhub2RlSWQ6IHN0cmluZyk6IFNldDxzdHJpbmc+O1xuICBnZXREZXBlbmRlbmNpZXMobm9kZUlkOiBzdHJpbmcpOiBTZXQ8c3RyaW5nPjtcbiAgZ2V0VHJhbnNpdGl2ZURlcGVuZGVuY2llcyhub2RlSWQ6IHN0cmluZyk6IFNldDxzdHJpbmc+O1xuICB0b3BvbG9naWNhbFNvcnQoKTogc3RyaW5nW107XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEV2YWx1YXRpb24gUmVzdWx0c1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIEV2YWx1YXRpb25SZXN1bHQge1xuICB2YWx1ZTogdW5rbm93bjtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgZXJyb3I/OiBFcnJvcjtcbiAgZXhlY3V0aW9uVGltZU1zOiBudW1iZXI7XG4gIGFjY2Vzc2VkVmFyaWFibGVzOiBTZXQ8c3RyaW5nPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFdmFsdWF0aW9uUmVzdWx0U2V0IHtcbiAgcmVzdWx0czogTWFwPHN0cmluZywgRXZhbHVhdGlvblJlc3VsdD47XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIGVycm9yczogRXJyb3JbXTtcbiAgdG90YWxFeGVjdXRpb25UaW1lTXM6IG51bWJlcjtcbiAgZXZhbHVhdGlvbk9yZGVyOiBzdHJpbmdbXTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gVmFsaWRhdGlvbiBSZXN1bHRcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgdmFsaWQ6IGJvb2xlYW47XG4gIGVycm9yczogRXJyb3JbXTtcbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xuICBkZXBlbmRlbmN5R3JhcGg6IERlcGVuZGVuY3lHcmFwaDtcbiAgZXZhbHVhdGlvbk9yZGVyOiBzdHJpbmdbXTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQ2FjaGUgU3RhdGlzdGljc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlU3RhdHMge1xuICBzaXplOiBudW1iZXI7XG4gIGhpdHM6IG51bWJlcjtcbiAgbWlzc2VzOiBudW1iZXI7XG4gIGhpdFJhdGU6IG51bWJlcjtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gVG9rZW4gVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGVudW0gVG9rZW5UeXBlIHtcbiAgLy8gTGl0ZXJhbHNcbiAgTlVNQkVSID0gJ05VTUJFUicsXG4gIFNUUklORyA9ICdTVFJJTkcnLFxuICBCT09MRUFOID0gJ0JPT0xFQU4nLFxuICBOVUxMID0gJ05VTEwnLFxuXG4gIC8vIElkZW50aWZpZXJzIGFuZCBWYXJpYWJsZXNcbiAgSURFTlRJRklFUiA9ICdJREVOVElGSUVSJyxcbiAgVkFSSUFCTEUgPSAnVkFSSUFCTEUnLFxuICBDT05URVhUX1ZBUiA9ICdDT05URVhUX1ZBUicsXG5cbiAgLy8gT3BlcmF0b3JzXG4gIFBMVVMgPSAnUExVUycsXG4gIE1JTlVTID0gJ01JTlVTJyxcbiAgTVVMVElQTFkgPSAnTVVMVElQTFknLFxuICBESVZJREUgPSAnRElWSURFJyxcbiAgTU9EVUxPID0gJ01PRFVMTycsXG4gIFBPV0VSID0gJ1BPV0VSJyxcblxuICAvLyBDb21wYXJpc29uXG4gIEVRID0gJ0VRJyxcbiAgTkVRID0gJ05FUScsXG4gIExUID0gJ0xUJyxcbiAgR1QgPSAnR1QnLFxuICBMVEUgPSAnTFRFJyxcbiAgR1RFID0gJ0dURScsXG5cbiAgLy8gTG9naWNhbFxuICBBTkQgPSAnQU5EJyxcbiAgT1IgPSAnT1InLFxuICBOT1QgPSAnTk9UJyxcblxuICAvLyBQdW5jdHVhdGlvblxuICBMUEFSRU4gPSAnTFBBUkVOJyxcbiAgUlBBUkVOID0gJ1JQQVJFTicsXG4gIExCUkFDS0VUID0gJ0xCUkFDS0VUJyxcbiAgUkJSQUNLRVQgPSAnUkJSQUNLRVQnLFxuICBDT01NQSA9ICdDT01NQScsXG4gIERPVCA9ICdET1QnLFxuICBRVUVTVElPTiA9ICdRVUVTVElPTicsXG4gIENPTE9OID0gJ0NPTE9OJyxcblxuICAvLyBTcGVjaWFsXG4gIEVPRiA9ICdFT0YnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRva2VuIHtcbiAgdHlwZTogVG9rZW5UeXBlO1xuICB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGw7XG4gIHBvc2l0aW9uOiBudW1iZXI7XG4gIGxpbmU6IG51bWJlcjtcbiAgY29sdW1uOiBudW1iZXI7XG59XG4iXX0=
|
|
62
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHlwZXMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvdHlwZXMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7O0FBVUEsK0VBQStFO0FBQy9FLHdCQUF3QjtBQUN4QiwrRUFBK0U7QUFFL0UsSUFBWSxtQkFTWDtBQVRELFdBQVksbUJBQW1CO0lBQzdCLG9DQUFhLENBQUE7SUFDYixzQ0FBZSxDQUFBO0lBQ2Ysb0NBQWEsQ0FBQTtJQUNiLGdDQUFTLENBQUE7SUFDVCwwQ0FBbUIsQ0FBQTtJQUNuQiw4Q0FBdUIsQ0FBQTtJQUN2Qiw4Q0FBdUIsQ0FBQTtJQUN2Qiw0Q0FBcUIsQ0FBQTtBQUN2QixDQUFDLEVBVFcsbUJBQW1CLG1DQUFuQixtQkFBbUIsUUFTOUI7QUF1UkQsK0VBQStFO0FBQy9FLGNBQWM7QUFDZCwrRUFBK0U7QUFFL0UsSUFBWSxTQTZDWDtBQTdDRCxXQUFZLFNBQVM7SUFDbkIsV0FBVztJQUNYLDhCQUFpQixDQUFBO0lBQ2pCLDhCQUFpQixDQUFBO0lBQ2pCLGdDQUFtQixDQUFBO0lBQ25CLDBCQUFhLENBQUE7SUFFYiw0QkFBNEI7SUFDNUIsc0NBQXlCLENBQUE7SUFDekIsa0NBQXFCLENBQUE7SUFDckIsd0NBQTJCLENBQUE7SUFFM0IsWUFBWTtJQUNaLDBCQUFhLENBQUE7SUFDYiw0QkFBZSxDQUFBO0lBQ2Ysa0NBQXFCLENBQUE7SUFDckIsOEJBQWlCLENBQUE7SUFDakIsOEJBQWlCLENBQUE7SUFDakIsNEJBQWUsQ0FBQTtJQUVmLGFBQWE7SUFDYixzQkFBUyxDQUFBO0lBQ1Qsd0JBQVcsQ0FBQTtJQUNYLHNCQUFTLENBQUE7SUFDVCxzQkFBUyxDQUFBO0lBQ1Qsd0JBQVcsQ0FBQTtJQUNYLHdCQUFXLENBQUE7SUFFWCxVQUFVO0lBQ1Ysd0JBQVcsQ0FBQTtJQUNYLHNCQUFTLENBQUE7SUFDVCx3QkFBVyxDQUFBO0lBRVgsY0FBYztJQUNkLDhCQUFpQixDQUFBO0lBQ2pCLDhCQUFpQixDQUFBO0lBQ2pCLGtDQUFxQixDQUFBO0lBQ3JCLGtDQUFxQixDQUFBO0lBQ3JCLDRCQUFlLENBQUE7SUFDZix3QkFBVyxDQUFBO0lBQ1gsa0NBQXFCLENBQUE7SUFDckIsNEJBQWUsQ0FBQTtJQUVmLFVBQVU7SUFDVix3QkFBVyxDQUFBO0FBQ2IsQ0FBQyxFQTdDVyxTQUFTLHlCQUFULFNBQVMsUUE2Q3BCIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgRGVjaW1hbCB9IGZyb20gJ2RlY2ltYWwuanMnO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBWYWx1ZSBUeXBlc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgdHlwZSBWYWx1ZVR5cGUgPSAnbnVtYmVyJyB8ICdkZWNpbWFsJyB8ICdzdHJpbmcnIHwgJ2Jvb2xlYW4nIHwgJ2FycmF5JyB8ICdvYmplY3QnIHwgJ251bGwnIHwgJ2FueSc7XG5cbmV4cG9ydCB0eXBlIEZvcm11bGFWYWx1ZSA9IERlY2ltYWwgfCBudW1iZXIgfCBzdHJpbmcgfCBib29sZWFuIHwgbnVsbCB8IEZvcm11bGFWYWx1ZVtdIHwgeyBba2V5OiBzdHJpbmddOiBGb3JtdWxhVmFsdWUgfTtcblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gRGVjaW1hbCBDb25maWd1cmF0aW9uXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBlbnVtIERlY2ltYWxSb3VuZGluZ01vZGUge1xuICBDRUlMID0gJ0NFSUwnLFxuICBGTE9PUiA9ICdGTE9PUicsXG4gIERPV04gPSAnRE9XTicsXG4gIFVQID0gJ1VQJyxcbiAgSEFMRl9VUCA9ICdIQUxGX1VQJyxcbiAgSEFMRl9ET1dOID0gJ0hBTEZfRE9XTicsXG4gIEhBTEZfRVZFTiA9ICdIQUxGX0VWRU4nLFxuICBIQUxGX09ERCA9ICdIQUxGX09ERCcsXG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRGVjaW1hbENvbmZpZyB7XG4gIHByZWNpc2lvbj86IG51bWJlcjtcbiAgcm91bmRpbmdNb2RlPzogRGVjaW1hbFJvdW5kaW5nTW9kZTtcbiAgZGl2aXNpb25TY2FsZT86IG51bWJlcjtcbiAgcHJlc2VydmVUcmFpbGluZ1plcm9zPzogYm9vbGVhbjtcbiAgYXV0b0NvbnZlcnRGbG9hdHM/OiBib29sZWFuO1xuICBtYXhFeHBvbmVudD86IG51bWJlcjtcbiAgbWluRXhwb25lbnQ/OiBudW1iZXI7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFJvdW5kaW5nIENvbmZpZ3VyYXRpb25cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBSb3VuZGluZ0NvbmZpZyB7XG4gIG1vZGU6ICdIQUxGX1VQJyB8ICdIQUxGX0RPV04nIHwgJ0ZMT09SJyB8ICdDRUlMJyB8ICdOT05FJztcbiAgcHJlY2lzaW9uOiBudW1iZXI7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEVycm9yIEJlaGF2aW9yXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXJyb3JCZWhhdmlvciB7XG4gIHR5cGU6ICdUSFJPVycgfCAnTlVMTCcgfCAnWkVSTycgfCAnREVGQVVMVCcgfCAnU0tJUCc7XG4gIGRlZmF1bHRWYWx1ZT86IHVua25vd247XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEZvcm11bGEgRGVmaW5pdGlvblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIEZvcm11bGFEZWZpbml0aW9uIHtcbiAgaWQ6IHN0cmluZztcbiAgZXhwcmVzc2lvbjogc3RyaW5nO1xuICBkZXBlbmRlbmNpZXM/OiBzdHJpbmdbXTtcbiAgb25FcnJvcj86IEVycm9yQmVoYXZpb3I7XG4gIGRlZmF1bHRWYWx1ZT86IHVua25vd247XG4gIHJvdW5kaW5nPzogUm91bmRpbmdDb25maWc7XG4gIG1ldGFkYXRhPzogUmVjb3JkPHN0cmluZywgdW5rbm93bj47XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEV2YWx1YXRpb24gQ29udGV4dFxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIEV2YWx1YXRpb25Db250ZXh0IHtcbiAgdmFyaWFibGVzOiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duPjtcbiAgY29sbGVjdGlvbnM/OiBSZWNvcmQ8c3RyaW5nLCB1bmtub3duW10+O1xuICBleHRyYT86IFJlY29yZDxzdHJpbmcsIHVua25vd24+O1xufVxuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBFbmdpbmUgQ29uZmlndXJhdGlvblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIE9wZXJhdG9yRGVmaW5pdGlvbiB7XG4gIHN5bWJvbDogc3RyaW5nO1xuICBwcmVjZWRlbmNlOiBudW1iZXI7XG4gIGFzc29jaWF0aXZpdHk6ICdsZWZ0JyB8ICdyaWdodCc7XG4gIGhhbmRsZXI6IChsZWZ0OiB1bmtub3duLCByaWdodDogdW5rbm93bikgPT4gdW5rbm93bjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBTZWN1cml0eUNvbmZpZyB7XG4gIG1heEV4cHJlc3Npb25MZW5ndGg/OiBudW1iZXI7XG4gIG1heFJlY3Vyc2lvbkRlcHRoPzogbnVtYmVyO1xuICBtYXhJdGVyYXRpb25zPzogbnVtYmVyO1xuICBtYXhFeGVjdXRpb25UaW1lPzogbnVtYmVyO1xuICBhbGxvd2VkRnVuY3Rpb25zPzogc3RyaW5nW107XG4gIGJsb2NrZWRGdW5jdGlvbnM/OiBzdHJpbmdbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBGb3JtdWxhRW5naW5lQ29uZmlnIHtcbiAgZW5hYmxlQ2FjaGU/OiBib29sZWFuO1xuICBtYXhDYWNoZVNpemU/OiBudW1iZXI7XG4gIGRlZmF1bHRFcnJvckJlaGF2aW9yPzogRXJyb3JCZWhhdmlvcjtcbiAgZGVmYXVsdFJvdW5kaW5nPzogUm91bmRpbmdDb25maWc7XG4gIHZhcmlhYmxlUHJlZml4Pzogc3RyaW5nO1xuICBjb250ZXh0UHJlZml4Pzogc3RyaW5nO1xuICBzdHJpY3RNb2RlPzogYm9vbGVhbjtcbiAgb3BlcmF0b3JzPzogT3BlcmF0b3JEZWZpbml0aW9uW107XG4gIGZ1bmN0aW9ucz86IEZ1bmN0aW9uRGVmaW5pdGlvbltdO1xuICBkZWNpbWFsPzogRGVjaW1hbENvbmZpZztcbiAgc2VjdXJpdHk/OiBTZWN1cml0eUNvbmZpZztcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQVNUIE5vZGUgVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBEZWNpbWFsTGl0ZXJhbCB7XG4gIHR5cGU6ICdEZWNpbWFsTGl0ZXJhbCc7XG4gIHZhbHVlOiBzdHJpbmc7XG4gIHJhdzogc3RyaW5nO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE51bWJlckxpdGVyYWwge1xuICB0eXBlOiAnTnVtYmVyTGl0ZXJhbCc7XG4gIHZhbHVlOiBudW1iZXI7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgU3RyaW5nTGl0ZXJhbCB7XG4gIHR5cGU6ICdTdHJpbmdMaXRlcmFsJztcbiAgdmFsdWU6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBCb29sZWFuTGl0ZXJhbCB7XG4gIHR5cGU6ICdCb29sZWFuTGl0ZXJhbCc7XG4gIHZhbHVlOiBib29sZWFuO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIE51bGxMaXRlcmFsIHtcbiAgdHlwZTogJ051bGxMaXRlcmFsJztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBBcnJheUxpdGVyYWwge1xuICB0eXBlOiAnQXJyYXlMaXRlcmFsJztcbiAgZWxlbWVudHM6IEFTVE5vZGVbXTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBWYXJpYWJsZVJlZmVyZW5jZSB7XG4gIHR5cGU6ICdWYXJpYWJsZVJlZmVyZW5jZSc7XG4gIHByZWZpeDogJyQnIHwgJ0AnO1xuICBuYW1lOiBzdHJpbmc7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgQmluYXJ5T3BlcmF0aW9uIHtcbiAgdHlwZTogJ0JpbmFyeU9wZXJhdGlvbic7XG4gIG9wZXJhdG9yOiBzdHJpbmc7XG4gIGxlZnQ6IEFTVE5vZGU7XG4gIHJpZ2h0OiBBU1ROb2RlO1xufVxuXG5leHBvcnQgaW50ZXJmYWNlIFVuYXJ5T3BlcmF0aW9uIHtcbiAgdHlwZTogJ1VuYXJ5T3BlcmF0aW9uJztcbiAgb3BlcmF0b3I6IHN0cmluZztcbiAgb3BlcmFuZDogQVNUTm9kZTtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBDb25kaXRpb25hbEV4cHJlc3Npb24ge1xuICB0eXBlOiAnQ29uZGl0aW9uYWxFeHByZXNzaW9uJztcbiAgY29uZGl0aW9uOiBBU1ROb2RlO1xuICBjb25zZXF1ZW50OiBBU1ROb2RlO1xuICBhbHRlcm5hdGU6IEFTVE5vZGU7XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgRnVuY3Rpb25DYWxsIHtcbiAgdHlwZTogJ0Z1bmN0aW9uQ2FsbCc7XG4gIG5hbWU6IHN0cmluZztcbiAgYXJndW1lbnRzOiBBU1ROb2RlW107XG59XG5cbmV4cG9ydCBpbnRlcmZhY2UgTWVtYmVyQWNjZXNzIHtcbiAgdHlwZTogJ01lbWJlckFjY2Vzcyc7XG4gIG9iamVjdDogQVNUTm9kZTtcbiAgcHJvcGVydHk6IHN0cmluZztcbn1cblxuZXhwb3J0IGludGVyZmFjZSBJbmRleEFjY2VzcyB7XG4gIHR5cGU6ICdJbmRleEFjY2Vzcyc7XG4gIG9iamVjdDogQVNUTm9kZTtcbiAgaW5kZXg6IEFTVE5vZGU7XG59XG5cbmV4cG9ydCB0eXBlIEFTVE5vZGUgPVxuICB8IERlY2ltYWxMaXRlcmFsXG4gIHwgTnVtYmVyTGl0ZXJhbFxuICB8IFN0cmluZ0xpdGVyYWxcbiAgfCBCb29sZWFuTGl0ZXJhbFxuICB8IE51bGxMaXRlcmFsXG4gIHwgQXJyYXlMaXRlcmFsXG4gIHwgVmFyaWFibGVSZWZlcmVuY2VcbiAgfCBCaW5hcnlPcGVyYXRpb25cbiAgfCBVbmFyeU9wZXJhdGlvblxuICB8IENvbmRpdGlvbmFsRXhwcmVzc2lvblxuICB8IEZ1bmN0aW9uQ2FsbFxuICB8IE1lbWJlckFjY2Vzc1xuICB8IEluZGV4QWNjZXNzO1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBGdW5jdGlvbiBEZWZpbml0aW9uXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgQXJndW1lbnRUeXBlIHtcbiAgbmFtZTogc3RyaW5nO1xuICB0eXBlOiBWYWx1ZVR5cGU7XG4gIHJlcXVpcmVkOiBib29sZWFuO1xuICBkZWZhdWx0PzogdW5rbm93bjtcbn1cblxuZXhwb3J0IHR5cGUgRnVuY3Rpb25JbXBsZW1lbnRhdGlvbiA9IChcbiAgYXJnczogdW5rbm93bltdLFxuICBjb250ZXh0OiBFdmFsdWF0aW9uQ29udGV4dCxcbiAgZW5naW5lOiB1bmtub3duXG4pID0+IHVua25vd247XG5cbmV4cG9ydCBpbnRlcmZhY2UgRnVuY3Rpb25EZWZpbml0aW9uIHtcbiAgbmFtZTogc3RyaW5nO1xuICBtaW5BcmdzOiBudW1iZXI7XG4gIG1heEFyZ3M6IG51bWJlcjtcbiAgYXJnVHlwZXM/OiBBcmd1bWVudFR5cGVbXTtcbiAgcmV0dXJuVHlwZTogVmFsdWVUeXBlO1xuICBpbXBsZW1lbnRhdGlvbjogRnVuY3Rpb25JbXBsZW1lbnRhdGlvbjtcbiAgZGVzY3JpcHRpb24/OiBzdHJpbmc7XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIERlcGVuZGVuY3kgR3JhcGhcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBEZXBlbmRlbmN5R3JhcGgge1xuICBub2RlczogU2V0PHN0cmluZz47XG4gIGVkZ2VzOiBNYXA8c3RyaW5nLCBTZXQ8c3RyaW5nPj47XG4gIGhhc0N5Y2xlcygpOiBib29sZWFuO1xuICBnZXRSb290cygpOiBTZXQ8c3RyaW5nPjtcbiAgZ2V0RGVwZW5kZW50cyhub2RlSWQ6IHN0cmluZyk6IFNldDxzdHJpbmc+O1xuICBnZXREZXBlbmRlbmNpZXMobm9kZUlkOiBzdHJpbmcpOiBTZXQ8c3RyaW5nPjtcbiAgZ2V0VHJhbnNpdGl2ZURlcGVuZGVuY2llcyhub2RlSWQ6IHN0cmluZyk6IFNldDxzdHJpbmc+O1xuICB0b3BvbG9naWNhbFNvcnQoKTogc3RyaW5nW107XG59XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIEV2YWx1YXRpb24gUmVzdWx0c1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIEV2YWx1YXRpb25SZXN1bHQge1xuICB2YWx1ZTogdW5rbm93bjtcbiAgc3VjY2VzczogYm9vbGVhbjtcbiAgZXJyb3I/OiBFcnJvcjtcbiAgZXhlY3V0aW9uVGltZU1zOiBudW1iZXI7XG4gIGFjY2Vzc2VkVmFyaWFibGVzOiBTZXQ8c3RyaW5nPjtcbn1cblxuZXhwb3J0IGludGVyZmFjZSBFdmFsdWF0aW9uUmVzdWx0U2V0IHtcbiAgcmVzdWx0czogTWFwPHN0cmluZywgRXZhbHVhdGlvblJlc3VsdD47XG4gIHN1Y2Nlc3M6IGJvb2xlYW47XG4gIGVycm9yczogRXJyb3JbXTtcbiAgdG90YWxFeGVjdXRpb25UaW1lTXM6IG51bWJlcjtcbiAgZXZhbHVhdGlvbk9yZGVyOiBzdHJpbmdbXTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQmF0Y2ggRXZhbHVhdGlvbiBPcHRpb25zXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbmV4cG9ydCBpbnRlcmZhY2UgRXZhbHVhdGVBbGxPcHRpb25zIHtcbiAgLyoqXG4gICAqIFdoZW4gdHJ1ZSwgZGlzYWJsZXMgYXV0b21hdGljIGludGVybWVkaWF0ZSByb3VuZGluZyBldmVuIGlmIGRlZmF1bHRSb3VuZGluZ1xuICAgKiBpcyBjb25maWd1cmVkIGluIHRoZSBlbmdpbmUuIFBlci1mb3JtdWxhIHJvdW5kaW5nIGNvbmZpZ3VyYXRpb25zIGFyZSBzdGlsbCBhcHBsaWVkLlxuICAgKiBAZGVmYXVsdCBmYWxzZVxuICAgKi9cbiAgZGlzYWJsZUludGVybWVkaWF0ZVJvdW5kaW5nPzogYm9vbGVhbjtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gVmFsaWRhdGlvbiBSZXN1bHRcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGludGVyZmFjZSBWYWxpZGF0aW9uUmVzdWx0IHtcbiAgdmFsaWQ6IGJvb2xlYW47XG4gIGVycm9yczogRXJyb3JbXTtcbiAgd2FybmluZ3M6IHN0cmluZ1tdO1xuICBkZXBlbmRlbmN5R3JhcGg6IERlcGVuZGVuY3lHcmFwaDtcbiAgZXZhbHVhdGlvbk9yZGVyOiBzdHJpbmdbXTtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gQ2FjaGUgU3RhdGlzdGljc1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG5leHBvcnQgaW50ZXJmYWNlIENhY2hlU3RhdHMge1xuICBzaXplOiBudW1iZXI7XG4gIGhpdHM6IG51bWJlcjtcbiAgbWlzc2VzOiBudW1iZXI7XG4gIGhpdFJhdGU6IG51bWJlcjtcbn1cblxuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuLy8gVG9rZW4gVHlwZXNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuZXhwb3J0IGVudW0gVG9rZW5UeXBlIHtcbiAgLy8gTGl0ZXJhbHNcbiAgTlVNQkVSID0gJ05VTUJFUicsXG4gIFNUUklORyA9ICdTVFJJTkcnLFxuICBCT09MRUFOID0gJ0JPT0xFQU4nLFxuICBOVUxMID0gJ05VTEwnLFxuXG4gIC8vIElkZW50aWZpZXJzIGFuZCBWYXJpYWJsZXNcbiAgSURFTlRJRklFUiA9ICdJREVOVElGSUVSJyxcbiAgVkFSSUFCTEUgPSAnVkFSSUFCTEUnLFxuICBDT05URVhUX1ZBUiA9ICdDT05URVhUX1ZBUicsXG5cbiAgLy8gT3BlcmF0b3JzXG4gIFBMVVMgPSAnUExVUycsXG4gIE1JTlVTID0gJ01JTlVTJyxcbiAgTVVMVElQTFkgPSAnTVVMVElQTFknLFxuICBESVZJREUgPSAnRElWSURFJyxcbiAgTU9EVUxPID0gJ01PRFVMTycsXG4gIFBPV0VSID0gJ1BPV0VSJyxcblxuICAvLyBDb21wYXJpc29uXG4gIEVRID0gJ0VRJyxcbiAgTkVRID0gJ05FUScsXG4gIExUID0gJ0xUJyxcbiAgR1QgPSAnR1QnLFxuICBMVEUgPSAnTFRFJyxcbiAgR1RFID0gJ0dURScsXG5cbiAgLy8gTG9naWNhbFxuICBBTkQgPSAnQU5EJyxcbiAgT1IgPSAnT1InLFxuICBOT1QgPSAnTk9UJyxcblxuICAvLyBQdW5jdHVhdGlvblxuICBMUEFSRU4gPSAnTFBBUkVOJyxcbiAgUlBBUkVOID0gJ1JQQVJFTicsXG4gIExCUkFDS0VUID0gJ0xCUkFDS0VUJyxcbiAgUkJSQUNLRVQgPSAnUkJSQUNLRVQnLFxuICBDT01NQSA9ICdDT01NQScsXG4gIERPVCA9ICdET1QnLFxuICBRVUVTVElPTiA9ICdRVUVTVElPTicsXG4gIENPTE9OID0gJ0NPTE9OJyxcblxuICAvLyBTcGVjaWFsXG4gIEVPRiA9ICdFT0YnLFxufVxuXG5leHBvcnQgaW50ZXJmYWNlIFRva2VuIHtcbiAgdHlwZTogVG9rZW5UeXBlO1xuICB2YWx1ZTogc3RyaW5nIHwgbnVtYmVyIHwgYm9vbGVhbiB8IG51bGw7XG4gIHBvc2l0aW9uOiBudW1iZXI7XG4gIGxpbmU6IG51bWJlcjtcbiAgY29sdW1uOiBudW1iZXI7XG59XG4iXX0=
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@the-trybe/formula-engine",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.1.1",
|
|
4
4
|
"description": "Configuration-driven expression evaluation system with dependency resolution and decimal precision",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|
|
@@ -10,7 +10,8 @@
|
|
|
10
10
|
"test:watch": "jest --watch",
|
|
11
11
|
"test:coverage": "jest --coverage",
|
|
12
12
|
"lint": "eslint src --ext .ts",
|
|
13
|
-
"clean": "rm -rf dist"
|
|
13
|
+
"clean": "rm -rf dist",
|
|
14
|
+
"prepublishOnly": "npm run clean && npm run build && npm test"
|
|
14
15
|
},
|
|
15
16
|
"keywords": [
|
|
16
17
|
"formula",
|
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Tests for evaluateAll() batch evaluation rounding behavior
|
|
3
|
+
*
|
|
4
|
+
* Issue: evaluateAll() batch evaluation doesn't respect rounded intermediate values
|
|
5
|
+
* in dependency chains when consumers need to round intermediate values for accuracy.
|
|
6
|
+
*
|
|
7
|
+
* @see https://github.com/monaam/formula-engine/issues/XX
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import { FormulaEngine } from './formula-engine';
|
|
11
|
+
import { FormulaDefinition, EvaluationContext, RoundingConfig } from './types';
|
|
12
|
+
import { Decimal } from './decimal-utils';
|
|
13
|
+
|
|
14
|
+
describe('evaluateAll() Intermediate Value Rounding', () => {
|
|
15
|
+
let engine: FormulaEngine;
|
|
16
|
+
|
|
17
|
+
beforeEach(() => {
|
|
18
|
+
engine = new FormulaEngine();
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
describe('Current Behavior - Unrounded Intermediate Values', () => {
|
|
22
|
+
it('should demonstrate the issue: unrounded values propagate through dependency chain', () => {
|
|
23
|
+
// This test documents the current (problematic) behavior
|
|
24
|
+
// In financial calculations, intermediate values should be rounded to cents
|
|
25
|
+
|
|
26
|
+
const formulas: FormulaDefinition[] = [
|
|
27
|
+
{ id: '_discount1', expression: '127.5 * 0.15' }, // = 19.125
|
|
28
|
+
{ id: '_discountTotal', expression: '$_discount1' }, // = 19.125 (raw)
|
|
29
|
+
{ id: 'totalHt', expression: '127.5 - $_discountTotal' }, // = 108.375 (using raw)
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
33
|
+
|
|
34
|
+
expect(results.success).toBe(true);
|
|
35
|
+
|
|
36
|
+
// Current behavior: raw unrounded values propagate
|
|
37
|
+
expect((results.results.get('_discount1')?.value as Decimal).toNumber()).toBe(19.125);
|
|
38
|
+
expect((results.results.get('_discountTotal')?.value as Decimal).toNumber()).toBe(19.125);
|
|
39
|
+
expect((results.results.get('totalHt')?.value as Decimal).toNumber()).toBe(108.375);
|
|
40
|
+
|
|
41
|
+
// Expected for financial calculations:
|
|
42
|
+
// _discount1 = 19.125 → round to 19.13
|
|
43
|
+
// _discountTotal = 19.13
|
|
44
|
+
// totalHt = 127.5 - 19.13 = 108.37
|
|
45
|
+
//
|
|
46
|
+
// But we get 108.375 instead of 108.37
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
it('should show accumulated rounding errors in complex financial chain', () => {
|
|
50
|
+
// Multiple line items each with small rounding differences that accumulate
|
|
51
|
+
const formulas: FormulaDefinition[] = [
|
|
52
|
+
// Line item 1: quantity 3 at price 10.33
|
|
53
|
+
{ id: 'line1_subtotal', expression: '3 * 10.33' }, // = 30.99
|
|
54
|
+
{ id: 'line1_tax', expression: '$line1_subtotal * 0.0825' }, // = 2.556675 (should be 2.56)
|
|
55
|
+
|
|
56
|
+
// Line item 2: quantity 7 at price 5.67
|
|
57
|
+
{ id: 'line2_subtotal', expression: '7 * 5.67' }, // = 39.69
|
|
58
|
+
{ id: 'line2_tax', expression: '$line2_subtotal * 0.0825' }, // = 3.274425 (should be 3.27)
|
|
59
|
+
|
|
60
|
+
// Total tax should use rounded line item taxes
|
|
61
|
+
{ id: 'totalTax', expression: '$line1_tax + $line2_tax' }, // = 5.8311 (should be 5.83)
|
|
62
|
+
|
|
63
|
+
// Grand total
|
|
64
|
+
{ id: 'grandTotal', expression: '$line1_subtotal + $line2_subtotal + $totalTax' },
|
|
65
|
+
];
|
|
66
|
+
|
|
67
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
68
|
+
|
|
69
|
+
expect(results.success).toBe(true);
|
|
70
|
+
|
|
71
|
+
// Raw calculated values (what we currently get)
|
|
72
|
+
const line1Tax = (results.results.get('line1_tax')?.value as Decimal).toNumber();
|
|
73
|
+
const line2Tax = (results.results.get('line2_tax')?.value as Decimal).toNumber();
|
|
74
|
+
const totalTax = (results.results.get('totalTax')?.value as Decimal).toNumber();
|
|
75
|
+
|
|
76
|
+
// These are NOT rounded to 2 decimal places as financial calculations require
|
|
77
|
+
expect(line1Tax).toBeCloseTo(2.556675, 6);
|
|
78
|
+
expect(line2Tax).toBeCloseTo(3.274425, 6);
|
|
79
|
+
expect(totalTax).toBeCloseTo(5.8311, 4);
|
|
80
|
+
|
|
81
|
+
// For proper financial calculation:
|
|
82
|
+
// line1_tax should be 2.56 (rounded)
|
|
83
|
+
// line2_tax should be 3.27 (rounded)
|
|
84
|
+
// totalTax should be 2.56 + 3.27 = 5.83
|
|
85
|
+
//
|
|
86
|
+
// Difference of 0.0011 may seem small, but accumulates across many line items
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
it('should show discrepancy between batch and sequential evaluation with manual rounding', () => {
|
|
90
|
+
// When evaluating sequentially with manual rounding between steps,
|
|
91
|
+
// we get different results than batch evaluation
|
|
92
|
+
|
|
93
|
+
const basePrice = 127.5;
|
|
94
|
+
const discountRate = 0.15;
|
|
95
|
+
|
|
96
|
+
// Sequential evaluation with rounding
|
|
97
|
+
const discount1 = new Decimal(basePrice).times(discountRate).toDecimalPlaces(2, Decimal.ROUND_HALF_UP);
|
|
98
|
+
const discountTotal = discount1; // Already rounded
|
|
99
|
+
const totalHtSequential = new Decimal(basePrice).minus(discountTotal).toNumber();
|
|
100
|
+
|
|
101
|
+
// Batch evaluation
|
|
102
|
+
const formulas: FormulaDefinition[] = [
|
|
103
|
+
{ id: '_discount1', expression: `${basePrice} * ${discountRate}` },
|
|
104
|
+
{ id: '_discountTotal', expression: '$_discount1' },
|
|
105
|
+
{ id: 'totalHt', expression: `${basePrice} - $_discountTotal` },
|
|
106
|
+
];
|
|
107
|
+
|
|
108
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
109
|
+
const totalHtBatch = (results.results.get('totalHt')?.value as Decimal).toNumber();
|
|
110
|
+
|
|
111
|
+
// Sequential with rounding: 127.5 - 19.13 = 108.37
|
|
112
|
+
expect(totalHtSequential).toBe(108.37);
|
|
113
|
+
|
|
114
|
+
// Batch without intermediate rounding: 127.5 - 19.125 = 108.375
|
|
115
|
+
expect(totalHtBatch).toBe(108.375);
|
|
116
|
+
|
|
117
|
+
// They are NOT equal - this is the core issue
|
|
118
|
+
expect(totalHtSequential).not.toBe(totalHtBatch);
|
|
119
|
+
});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
describe('Workaround - Per-Formula Rounding Configuration', () => {
|
|
123
|
+
it('should apply rounding when configured on individual formulas', () => {
|
|
124
|
+
// The existing rounding config on FormulaDefinition DOES work
|
|
125
|
+
// but requires specifying it on every intermediate formula
|
|
126
|
+
|
|
127
|
+
const roundConfig: RoundingConfig = { mode: 'HALF_UP', precision: 2 };
|
|
128
|
+
|
|
129
|
+
const formulas: FormulaDefinition[] = [
|
|
130
|
+
{ id: '_discount1', expression: '127.5 * 0.15', rounding: roundConfig },
|
|
131
|
+
{ id: '_discountTotal', expression: '$_discount1', rounding: roundConfig },
|
|
132
|
+
{ id: 'totalHt', expression: '127.5 - $_discountTotal', rounding: roundConfig },
|
|
133
|
+
];
|
|
134
|
+
|
|
135
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
136
|
+
|
|
137
|
+
expect(results.success).toBe(true);
|
|
138
|
+
|
|
139
|
+
// With per-formula rounding configured, values ARE rounded
|
|
140
|
+
expect((results.results.get('_discount1')?.value as Decimal).toNumber()).toBe(19.13);
|
|
141
|
+
expect((results.results.get('_discountTotal')?.value as Decimal).toNumber()).toBe(19.13);
|
|
142
|
+
expect((results.results.get('totalHt')?.value as Decimal).toNumber()).toBe(108.37);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
it('should propagate rounded values to dependent formulas', () => {
|
|
146
|
+
// Verify that rounded values (not raw) are used in subsequent calculations
|
|
147
|
+
|
|
148
|
+
const roundConfig: RoundingConfig = { mode: 'HALF_UP', precision: 2 };
|
|
149
|
+
|
|
150
|
+
const formulas: FormulaDefinition[] = [
|
|
151
|
+
{ id: 'line1_subtotal', expression: '3 * 10.33', rounding: roundConfig },
|
|
152
|
+
{ id: 'line1_tax', expression: '$line1_subtotal * 0.0825', rounding: roundConfig },
|
|
153
|
+
|
|
154
|
+
{ id: 'line2_subtotal', expression: '7 * 5.67', rounding: roundConfig },
|
|
155
|
+
{ id: 'line2_tax', expression: '$line2_subtotal * 0.0825', rounding: roundConfig },
|
|
156
|
+
|
|
157
|
+
{ id: 'totalTax', expression: '$line1_tax + $line2_tax', rounding: roundConfig },
|
|
158
|
+
{ id: 'grandTotal', expression: '$line1_subtotal + $line2_subtotal + $totalTax', rounding: roundConfig },
|
|
159
|
+
];
|
|
160
|
+
|
|
161
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
162
|
+
|
|
163
|
+
expect(results.success).toBe(true);
|
|
164
|
+
|
|
165
|
+
// All values should be properly rounded to 2 decimal places
|
|
166
|
+
expect((results.results.get('line1_subtotal')?.value as Decimal).toNumber()).toBe(30.99);
|
|
167
|
+
expect((results.results.get('line1_tax')?.value as Decimal).toNumber()).toBe(2.56);
|
|
168
|
+
expect((results.results.get('line2_subtotal')?.value as Decimal).toNumber()).toBe(39.69);
|
|
169
|
+
expect((results.results.get('line2_tax')?.value as Decimal).toNumber()).toBe(3.27);
|
|
170
|
+
expect((results.results.get('totalTax')?.value as Decimal).toNumber()).toBe(5.83);
|
|
171
|
+
expect((results.results.get('grandTotal')?.value as Decimal).toNumber()).toBe(76.51);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
it('should be tedious to specify rounding on many formulas', () => {
|
|
175
|
+
// This test documents why the feature request makes sense:
|
|
176
|
+
// Having to specify rounding on every formula is verbose and error-prone
|
|
177
|
+
|
|
178
|
+
const roundConfig: RoundingConfig = { mode: 'HALF_UP', precision: 2 };
|
|
179
|
+
|
|
180
|
+
// In a real application, you might have 50+ formulas
|
|
181
|
+
// Forgetting rounding on ANY intermediate formula breaks the chain
|
|
182
|
+
const formulas: FormulaDefinition[] = [
|
|
183
|
+
{ id: 'unitPrice', expression: '$basePrice / $packageQty', rounding: roundConfig },
|
|
184
|
+
{ id: 'lineSubtotal', expression: '$unitPrice * $qty', rounding: roundConfig },
|
|
185
|
+
{ id: 'discountAmount', expression: '$lineSubtotal * $discountPct / 100', rounding: roundConfig },
|
|
186
|
+
{ id: 'afterDiscount', expression: '$lineSubtotal - $discountAmount', rounding: roundConfig },
|
|
187
|
+
{ id: 'taxableAmount', expression: '$afterDiscount', rounding: roundConfig },
|
|
188
|
+
{ id: 'stateTax', expression: '$taxableAmount * $stateTaxRate', rounding: roundConfig },
|
|
189
|
+
{ id: 'localTax', expression: '$taxableAmount * $localTaxRate', rounding: roundConfig },
|
|
190
|
+
{ id: 'totalTax', expression: '$stateTax + $localTax', rounding: roundConfig },
|
|
191
|
+
{ id: 'lineTotal', expression: '$afterDiscount + $totalTax', rounding: roundConfig },
|
|
192
|
+
// ... many more formulas in a real system
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
const context: EvaluationContext = {
|
|
196
|
+
variables: {
|
|
197
|
+
basePrice: 99.99,
|
|
198
|
+
packageQty: 3,
|
|
199
|
+
qty: 7,
|
|
200
|
+
discountPct: 10,
|
|
201
|
+
stateTaxRate: 0.0625,
|
|
202
|
+
localTaxRate: 0.02,
|
|
203
|
+
},
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
const results = engine.evaluateAll(formulas, context);
|
|
207
|
+
expect(results.success).toBe(true);
|
|
208
|
+
|
|
209
|
+
// Every formula needs rounding: { mode: 'HALF_UP', precision: 2 }
|
|
210
|
+
// This is repetitive and easy to forget
|
|
211
|
+
expect(formulas.every(f => f.rounding !== undefined)).toBe(true);
|
|
212
|
+
});
|
|
213
|
+
});
|
|
214
|
+
|
|
215
|
+
describe('Default Rounding Configuration', () => {
|
|
216
|
+
it('should apply defaultRounding to all intermediate values when configured', () => {
|
|
217
|
+
const engineWithRounding = new FormulaEngine({
|
|
218
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
const formulas: FormulaDefinition[] = [
|
|
222
|
+
{ id: '_discount1', expression: '127.5 * 0.15' },
|
|
223
|
+
{ id: '_discountTotal', expression: '$_discount1' },
|
|
224
|
+
{ id: 'totalHt', expression: '127.5 - $_discountTotal' },
|
|
225
|
+
];
|
|
226
|
+
|
|
227
|
+
const results = engineWithRounding.evaluateAll(formulas, { variables: {} });
|
|
228
|
+
|
|
229
|
+
expect(results.success).toBe(true);
|
|
230
|
+
// All values should be rounded to 2 decimal places
|
|
231
|
+
expect((results.results.get('_discount1')?.value as Decimal).toNumber()).toBe(19.13);
|
|
232
|
+
expect((results.results.get('_discountTotal')?.value as Decimal).toNumber()).toBe(19.13);
|
|
233
|
+
expect((results.results.get('totalHt')?.value as Decimal).toNumber()).toBe(108.37);
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
it('should apply defaultRounding to tax calculations', () => {
|
|
237
|
+
const engineWithRounding = new FormulaEngine({
|
|
238
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
const formulas: FormulaDefinition[] = [
|
|
242
|
+
{ id: 'line1_tax', expression: '30.99 * 0.0825' },
|
|
243
|
+
{ id: 'line2_tax', expression: '39.69 * 0.0825' },
|
|
244
|
+
{ id: 'totalTax', expression: '$line1_tax + $line2_tax' },
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
const results = engineWithRounding.evaluateAll(formulas, { variables: {} });
|
|
248
|
+
|
|
249
|
+
expect(results.success).toBe(true);
|
|
250
|
+
expect((results.results.get('line1_tax')?.value as Decimal).toNumber()).toBe(2.56);
|
|
251
|
+
expect((results.results.get('line2_tax')?.value as Decimal).toNumber()).toBe(3.27);
|
|
252
|
+
expect((results.results.get('totalTax')?.value as Decimal).toNumber()).toBe(5.83);
|
|
253
|
+
});
|
|
254
|
+
|
|
255
|
+
it('should allow per-formula override of defaultRounding', () => {
|
|
256
|
+
const engineWithRounding = new FormulaEngine({
|
|
257
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
258
|
+
});
|
|
259
|
+
|
|
260
|
+
// Use 1/3 which is 0.3333... to clearly show precision difference
|
|
261
|
+
// At 4 decimals: 0.3333, at 2 decimals: 0.33
|
|
262
|
+
const formulas: FormulaDefinition[] = [
|
|
263
|
+
{ id: 'rate', expression: '1 / 3', rounding: { mode: 'HALF_UP', precision: 4 } },
|
|
264
|
+
{ id: 'amount', expression: '1000 * $rate' }, // Uses default 2 decimal rounding
|
|
265
|
+
];
|
|
266
|
+
|
|
267
|
+
const results = engineWithRounding.evaluateAll(formulas, { variables: {} });
|
|
268
|
+
|
|
269
|
+
expect(results.success).toBe(true);
|
|
270
|
+
// Per-formula rounding to 4 decimals: 1/3 = 0.3333
|
|
271
|
+
expect((results.results.get('rate')?.value as Decimal).toNumber()).toBe(0.3333);
|
|
272
|
+
// amount = 1000 * 0.3333 = 333.3, rounded to 2 decimals = 333.30
|
|
273
|
+
// If default rounding was applied to rate (0.33), amount would be 330
|
|
274
|
+
expect((results.results.get('amount')?.value as Decimal).toNumber()).toBe(333.3);
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
it('should disable intermediate rounding with disableIntermediateRounding option', () => {
|
|
278
|
+
const engineWithRounding = new FormulaEngine({
|
|
279
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
const formulas: FormulaDefinition[] = [
|
|
283
|
+
{ id: '_discount1', expression: '127.5 * 0.15' },
|
|
284
|
+
{ id: '_discountTotal', expression: '$_discount1' },
|
|
285
|
+
{ id: 'totalHt', expression: '127.5 - $_discountTotal' },
|
|
286
|
+
];
|
|
287
|
+
|
|
288
|
+
// Disable intermediate rounding
|
|
289
|
+
const results = engineWithRounding.evaluateAll(formulas, { variables: {} }, {
|
|
290
|
+
disableIntermediateRounding: true
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
expect(results.success).toBe(true);
|
|
294
|
+
// Raw unrounded values should propagate (like the original behavior)
|
|
295
|
+
expect((results.results.get('_discount1')?.value as Decimal).toNumber()).toBe(19.125);
|
|
296
|
+
expect((results.results.get('_discountTotal')?.value as Decimal).toNumber()).toBe(19.125);
|
|
297
|
+
expect((results.results.get('totalHt')?.value as Decimal).toNumber()).toBe(108.375);
|
|
298
|
+
});
|
|
299
|
+
|
|
300
|
+
it('should still apply per-formula rounding when disableIntermediateRounding is true', () => {
|
|
301
|
+
const engineWithRounding = new FormulaEngine({
|
|
302
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
303
|
+
});
|
|
304
|
+
|
|
305
|
+
const formulas: FormulaDefinition[] = [
|
|
306
|
+
{ id: '_discount1', expression: '127.5 * 0.15', rounding: { mode: 'HALF_UP', precision: 2 } },
|
|
307
|
+
{ id: '_discountTotal', expression: '$_discount1' }, // No per-formula rounding
|
|
308
|
+
{ id: 'totalHt', expression: '127.5 - $_discountTotal' },
|
|
309
|
+
];
|
|
310
|
+
|
|
311
|
+
const results = engineWithRounding.evaluateAll(formulas, { variables: {} }, {
|
|
312
|
+
disableIntermediateRounding: true
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
expect(results.success).toBe(true);
|
|
316
|
+
// Per-formula rounding is still applied
|
|
317
|
+
expect((results.results.get('_discount1')?.value as Decimal).toNumber()).toBe(19.13);
|
|
318
|
+
// But default rounding is disabled, so _discountTotal uses raw value from context
|
|
319
|
+
// which is the rounded 19.13 from the previous formula
|
|
320
|
+
expect((results.results.get('_discountTotal')?.value as Decimal).toNumber()).toBe(19.13);
|
|
321
|
+
expect((results.results.get('totalHt')?.value as Decimal).toNumber()).toBe(108.37);
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
it('should not apply defaultRounding when mode is NONE', () => {
|
|
325
|
+
const engineWithNoneRounding = new FormulaEngine({
|
|
326
|
+
defaultRounding: { mode: 'NONE', precision: 2 }
|
|
327
|
+
});
|
|
328
|
+
|
|
329
|
+
const formulas: FormulaDefinition[] = [
|
|
330
|
+
{ id: '_discount1', expression: '127.5 * 0.15' },
|
|
331
|
+
{ id: 'totalHt', expression: '127.5 - $_discount1' },
|
|
332
|
+
];
|
|
333
|
+
|
|
334
|
+
const results = engineWithNoneRounding.evaluateAll(formulas, { variables: {} });
|
|
335
|
+
|
|
336
|
+
expect(results.success).toBe(true);
|
|
337
|
+
// NONE mode should not round
|
|
338
|
+
expect((results.results.get('_discount1')?.value as Decimal).toNumber()).toBe(19.125);
|
|
339
|
+
expect((results.results.get('totalHt')?.value as Decimal).toNumber()).toBe(108.375);
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
it('should match sequential evaluation when defaultRounding is configured', () => {
|
|
343
|
+
const engineWithRounding = new FormulaEngine({
|
|
344
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
const basePrice = 127.5;
|
|
348
|
+
const discountRate = 0.15;
|
|
349
|
+
|
|
350
|
+
// Sequential evaluation with manual rounding
|
|
351
|
+
const discount1 = new Decimal(basePrice).times(discountRate).toDecimalPlaces(2, Decimal.ROUND_HALF_UP);
|
|
352
|
+
const discountTotal = discount1;
|
|
353
|
+
const totalHtSequential = new Decimal(basePrice).minus(discountTotal).toDecimalPlaces(2, Decimal.ROUND_HALF_UP).toNumber();
|
|
354
|
+
|
|
355
|
+
// Batch evaluation with defaultRounding
|
|
356
|
+
const formulas: FormulaDefinition[] = [
|
|
357
|
+
{ id: '_discount1', expression: `${basePrice} * ${discountRate}` },
|
|
358
|
+
{ id: '_discountTotal', expression: '$_discount1' },
|
|
359
|
+
{ id: 'totalHt', expression: `${basePrice} - $_discountTotal` },
|
|
360
|
+
];
|
|
361
|
+
|
|
362
|
+
const results = engineWithRounding.evaluateAll(formulas, { variables: {} });
|
|
363
|
+
const totalHtBatch = (results.results.get('totalHt')?.value as Decimal).toNumber();
|
|
364
|
+
|
|
365
|
+
// Sequential with rounding: 127.5 - 19.13 = 108.37
|
|
366
|
+
expect(totalHtSequential).toBe(108.37);
|
|
367
|
+
|
|
368
|
+
// Batch with defaultRounding should now match!
|
|
369
|
+
expect(totalHtBatch).toBe(108.37);
|
|
370
|
+
expect(totalHtSequential).toBe(totalHtBatch);
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
it('should handle complex financial chain with defaultRounding', () => {
|
|
374
|
+
const engineWithRounding = new FormulaEngine({
|
|
375
|
+
defaultRounding: { mode: 'HALF_UP', precision: 2 }
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
const formulas: FormulaDefinition[] = [
|
|
379
|
+
// Line item 1: quantity 3 at price 10.33
|
|
380
|
+
{ id: 'line1_subtotal', expression: '3 * 10.33' },
|
|
381
|
+
{ id: 'line1_tax', expression: '$line1_subtotal * 0.0825' },
|
|
382
|
+
|
|
383
|
+
// Line item 2: quantity 7 at price 5.67
|
|
384
|
+
{ id: 'line2_subtotal', expression: '7 * 5.67' },
|
|
385
|
+
{ id: 'line2_tax', expression: '$line2_subtotal * 0.0825' },
|
|
386
|
+
|
|
387
|
+
// Total tax uses rounded line item taxes
|
|
388
|
+
{ id: 'totalTax', expression: '$line1_tax + $line2_tax' },
|
|
389
|
+
|
|
390
|
+
// Grand total
|
|
391
|
+
{ id: 'grandTotal', expression: '$line1_subtotal + $line2_subtotal + $totalTax' },
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
const results = engineWithRounding.evaluateAll(formulas, { variables: {} });
|
|
395
|
+
|
|
396
|
+
expect(results.success).toBe(true);
|
|
397
|
+
|
|
398
|
+
// All values properly rounded to 2 decimal places
|
|
399
|
+
expect((results.results.get('line1_subtotal')?.value as Decimal).toNumber()).toBe(30.99);
|
|
400
|
+
expect((results.results.get('line1_tax')?.value as Decimal).toNumber()).toBe(2.56);
|
|
401
|
+
expect((results.results.get('line2_subtotal')?.value as Decimal).toNumber()).toBe(39.69);
|
|
402
|
+
expect((results.results.get('line2_tax')?.value as Decimal).toNumber()).toBe(3.27);
|
|
403
|
+
expect((results.results.get('totalTax')?.value as Decimal).toNumber()).toBe(5.83);
|
|
404
|
+
expect((results.results.get('grandTotal')?.value as Decimal).toNumber()).toBe(76.51);
|
|
405
|
+
});
|
|
406
|
+
});
|
|
407
|
+
|
|
408
|
+
describe('Edge Cases', () => {
|
|
409
|
+
it('should handle rounding mode NONE correctly', () => {
|
|
410
|
+
const formulas: FormulaDefinition[] = [
|
|
411
|
+
{ id: 'calc', expression: '1 / 3', rounding: { mode: 'NONE', precision: 2 } },
|
|
412
|
+
];
|
|
413
|
+
|
|
414
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
415
|
+
|
|
416
|
+
// NONE mode should not round
|
|
417
|
+
const value = (results.results.get('calc')?.value as Decimal).toString();
|
|
418
|
+
expect(value.length).toBeGreaterThan(5); // Not truncated to 2 decimals
|
|
419
|
+
});
|
|
420
|
+
|
|
421
|
+
it('should handle rounding with FLOOR mode', () => {
|
|
422
|
+
const formulas: FormulaDefinition[] = [
|
|
423
|
+
{ id: 'calc', expression: '19.129', rounding: { mode: 'FLOOR', precision: 2 } },
|
|
424
|
+
];
|
|
425
|
+
|
|
426
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
427
|
+
expect((results.results.get('calc')?.value as Decimal).toNumber()).toBe(19.12);
|
|
428
|
+
});
|
|
429
|
+
|
|
430
|
+
it('should handle rounding with CEIL mode', () => {
|
|
431
|
+
const formulas: FormulaDefinition[] = [
|
|
432
|
+
{ id: 'calc', expression: '19.121', rounding: { mode: 'CEIL', precision: 2 } },
|
|
433
|
+
];
|
|
434
|
+
|
|
435
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
436
|
+
expect((results.results.get('calc')?.value as Decimal).toNumber()).toBe(19.13);
|
|
437
|
+
});
|
|
438
|
+
|
|
439
|
+
it('should handle mixed rounding configurations in chain', () => {
|
|
440
|
+
const formulas: FormulaDefinition[] = [
|
|
441
|
+
{ id: 'a', expression: '10.555', rounding: { mode: 'HALF_UP', precision: 2 } }, // 10.56
|
|
442
|
+
{ id: 'b', expression: '$a * 2', rounding: { mode: 'FLOOR', precision: 1 } }, // 21.1 (floor of 21.12)
|
|
443
|
+
{ id: 'c', expression: '$b + 0.99', rounding: { mode: 'CEIL', precision: 0 } }, // 23 (ceil of 22.09)
|
|
444
|
+
];
|
|
445
|
+
|
|
446
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
447
|
+
|
|
448
|
+
expect((results.results.get('a')?.value as Decimal).toNumber()).toBe(10.56);
|
|
449
|
+
expect((results.results.get('b')?.value as Decimal).toNumber()).toBe(21.1);
|
|
450
|
+
expect((results.results.get('c')?.value as Decimal).toNumber()).toBe(23);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it('should propagate rounded value even when dependent formula has no rounding', () => {
|
|
454
|
+
// If formula A has rounding, formula B that depends on A should see the rounded value
|
|
455
|
+
const formulas: FormulaDefinition[] = [
|
|
456
|
+
{ id: 'a', expression: '19.125', rounding: { mode: 'HALF_UP', precision: 2 } },
|
|
457
|
+
{ id: 'b', expression: '$a * 2' }, // No rounding on b, but should use rounded a
|
|
458
|
+
];
|
|
459
|
+
|
|
460
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
461
|
+
|
|
462
|
+
expect((results.results.get('a')?.value as Decimal).toNumber()).toBe(19.13);
|
|
463
|
+
// b should be 19.13 * 2 = 38.26, NOT 19.125 * 2 = 38.25
|
|
464
|
+
expect((results.results.get('b')?.value as Decimal).toNumber()).toBe(38.26);
|
|
465
|
+
});
|
|
466
|
+
|
|
467
|
+
it('should handle non-numeric results without rounding errors', () => {
|
|
468
|
+
const formulas: FormulaDefinition[] = [
|
|
469
|
+
{ id: 'amount', expression: '19.125', rounding: { mode: 'HALF_UP', precision: 2 } },
|
|
470
|
+
{ id: 'label', expression: '"Total: " + STRING($amount)' },
|
|
471
|
+
{ id: 'isPositive', expression: '$amount > 0' },
|
|
472
|
+
];
|
|
473
|
+
|
|
474
|
+
const results = engine.evaluateAll(formulas, { variables: {} });
|
|
475
|
+
|
|
476
|
+
expect(results.success).toBe(true);
|
|
477
|
+
expect((results.results.get('amount')?.value as Decimal).toNumber()).toBe(19.13);
|
|
478
|
+
expect(results.results.get('label')?.value).toBe('Total: 19.13');
|
|
479
|
+
expect(results.results.get('isPositive')?.value).toBe(true);
|
|
480
|
+
});
|
|
481
|
+
});
|
|
482
|
+
|
|
483
|
+
describe('Real-World Financial Scenarios', () => {
|
|
484
|
+
it('should calculate invoice with proper rounding for accounting', () => {
|
|
485
|
+
const roundConfig: RoundingConfig = { mode: 'HALF_UP', precision: 2 };
|
|
486
|
+
|
|
487
|
+
const formulas: FormulaDefinition[] = [
|
|
488
|
+
// Line items
|
|
489
|
+
{ id: 'line1', expression: '$qty1 * $price1', rounding: roundConfig },
|
|
490
|
+
{ id: 'line2', expression: '$qty2 * $price2', rounding: roundConfig },
|
|
491
|
+
{ id: 'line3', expression: '$qty3 * $price3', rounding: roundConfig },
|
|
492
|
+
|
|
493
|
+
// Subtotal
|
|
494
|
+
{ id: 'subtotal', expression: '$line1 + $line2 + $line3', rounding: roundConfig },
|
|
495
|
+
|
|
496
|
+
// Discount (percentage)
|
|
497
|
+
{ id: 'discountAmount', expression: '$subtotal * $discountPct / 100', rounding: roundConfig },
|
|
498
|
+
{ id: 'afterDiscount', expression: '$subtotal - $discountAmount', rounding: roundConfig },
|
|
499
|
+
|
|
500
|
+
// Tax calculations (separate state and local)
|
|
501
|
+
{ id: 'stateTax', expression: '$afterDiscount * 0.0625', rounding: roundConfig },
|
|
502
|
+
{ id: 'localTax', expression: '$afterDiscount * 0.0225', rounding: roundConfig },
|
|
503
|
+
{ id: 'totalTax', expression: '$stateTax + $localTax', rounding: roundConfig },
|
|
504
|
+
|
|
505
|
+
// Final total
|
|
506
|
+
{ id: 'grandTotal', expression: '$afterDiscount + $totalTax', rounding: roundConfig },
|
|
507
|
+
];
|
|
508
|
+
|
|
509
|
+
const context: EvaluationContext = {
|
|
510
|
+
variables: {
|
|
511
|
+
qty1: 3, price1: 29.99, // 89.97
|
|
512
|
+
qty2: 2, price2: 49.95, // 99.90
|
|
513
|
+
qty3: 5, price3: 9.99, // 49.95
|
|
514
|
+
discountPct: 15, // 15% discount
|
|
515
|
+
},
|
|
516
|
+
};
|
|
517
|
+
|
|
518
|
+
const results = engine.evaluateAll(formulas, context);
|
|
519
|
+
|
|
520
|
+
expect(results.success).toBe(true);
|
|
521
|
+
|
|
522
|
+
// Verify each step is properly rounded
|
|
523
|
+
expect((results.results.get('line1')?.value as Decimal).toNumber()).toBe(89.97);
|
|
524
|
+
expect((results.results.get('line2')?.value as Decimal).toNumber()).toBe(99.90);
|
|
525
|
+
expect((results.results.get('line3')?.value as Decimal).toNumber()).toBe(49.95);
|
|
526
|
+
expect((results.results.get('subtotal')?.value as Decimal).toNumber()).toBe(239.82);
|
|
527
|
+
expect((results.results.get('discountAmount')?.value as Decimal).toNumber()).toBe(35.97); // 239.82 * 0.15 = 35.973 -> 35.97
|
|
528
|
+
expect((results.results.get('afterDiscount')?.value as Decimal).toNumber()).toBe(203.85);
|
|
529
|
+
expect((results.results.get('stateTax')?.value as Decimal).toNumber()).toBe(12.74); // 203.85 * 0.0625 = 12.740625 -> 12.74
|
|
530
|
+
expect((results.results.get('localTax')?.value as Decimal).toNumber()).toBe(4.59); // 203.85 * 0.0225 = 4.586625 -> 4.59
|
|
531
|
+
expect((results.results.get('totalTax')?.value as Decimal).toNumber()).toBe(17.33);
|
|
532
|
+
expect((results.results.get('grandTotal')?.value as Decimal).toNumber()).toBe(221.18);
|
|
533
|
+
});
|
|
534
|
+
|
|
535
|
+
it('should handle currency conversion with proper intermediate rounding', () => {
|
|
536
|
+
const roundConfig: RoundingConfig = { mode: 'HALF_UP', precision: 2 };
|
|
537
|
+
|
|
538
|
+
const formulas: FormulaDefinition[] = [
|
|
539
|
+
// Amount in USD
|
|
540
|
+
{ id: 'usdAmount', expression: '$baseAmount * $usdRate', rounding: roundConfig },
|
|
541
|
+
|
|
542
|
+
// Convert USD to EUR (intermediate conversion)
|
|
543
|
+
{ id: 'eurAmount', expression: '$usdAmount * $eurRate', rounding: roundConfig },
|
|
544
|
+
|
|
545
|
+
// Add VAT in EUR
|
|
546
|
+
{ id: 'vatAmount', expression: '$eurAmount * 0.20', rounding: roundConfig },
|
|
547
|
+
{ id: 'totalEur', expression: '$eurAmount + $vatAmount', rounding: roundConfig },
|
|
548
|
+
];
|
|
549
|
+
|
|
550
|
+
const context: EvaluationContext = {
|
|
551
|
+
variables: {
|
|
552
|
+
baseAmount: 1000,
|
|
553
|
+
usdRate: 1.0, // 1:1 for simplicity
|
|
554
|
+
eurRate: 0.92, // USD to EUR
|
|
555
|
+
},
|
|
556
|
+
};
|
|
557
|
+
|
|
558
|
+
const results = engine.evaluateAll(formulas, context);
|
|
559
|
+
|
|
560
|
+
expect(results.success).toBe(true);
|
|
561
|
+
expect((results.results.get('usdAmount')?.value as Decimal).toNumber()).toBe(1000);
|
|
562
|
+
expect((results.results.get('eurAmount')?.value as Decimal).toNumber()).toBe(920);
|
|
563
|
+
expect((results.results.get('vatAmount')?.value as Decimal).toNumber()).toBe(184);
|
|
564
|
+
expect((results.results.get('totalEur')?.value as Decimal).toNumber()).toBe(1104);
|
|
565
|
+
});
|
|
566
|
+
|
|
567
|
+
it('should handle commission calculations with tiered rates', () => {
|
|
568
|
+
const roundConfig: RoundingConfig = { mode: 'HALF_UP', precision: 2 };
|
|
569
|
+
|
|
570
|
+
const formulas: FormulaDefinition[] = [
|
|
571
|
+
// Base commission
|
|
572
|
+
{ id: 'baseCommission', expression: '$saleAmount * 0.05', rounding: roundConfig },
|
|
573
|
+
|
|
574
|
+
// Bonus for exceeding threshold
|
|
575
|
+
{ id: 'bonusEligible', expression: '$saleAmount > 10000 ? ($saleAmount - 10000) * 0.02 : 0', rounding: roundConfig },
|
|
576
|
+
|
|
577
|
+
// Total commission
|
|
578
|
+
{ id: 'totalCommission', expression: '$baseCommission + $bonusEligible', rounding: roundConfig },
|
|
579
|
+
|
|
580
|
+
// Tax withholding
|
|
581
|
+
{ id: 'taxWithholding', expression: '$totalCommission * 0.22', rounding: roundConfig },
|
|
582
|
+
|
|
583
|
+
// Net payout
|
|
584
|
+
{ id: 'netPayout', expression: '$totalCommission - $taxWithholding', rounding: roundConfig },
|
|
585
|
+
];
|
|
586
|
+
|
|
587
|
+
const context: EvaluationContext = {
|
|
588
|
+
variables: {
|
|
589
|
+
saleAmount: 15750.50,
|
|
590
|
+
},
|
|
591
|
+
};
|
|
592
|
+
|
|
593
|
+
const results = engine.evaluateAll(formulas, context);
|
|
594
|
+
|
|
595
|
+
expect(results.success).toBe(true);
|
|
596
|
+
// 15750.50 * 0.05 = 787.525 -> 787.53
|
|
597
|
+
expect((results.results.get('baseCommission')?.value as Decimal).toNumber()).toBe(787.53);
|
|
598
|
+
// (15750.50 - 10000) * 0.02 = 115.01
|
|
599
|
+
expect((results.results.get('bonusEligible')?.value as Decimal).toNumber()).toBe(115.01);
|
|
600
|
+
// 787.53 + 115.01 = 902.54
|
|
601
|
+
expect((results.results.get('totalCommission')?.value as Decimal).toNumber()).toBe(902.54);
|
|
602
|
+
// 902.54 * 0.22 = 198.5588 -> 198.56
|
|
603
|
+
expect((results.results.get('taxWithholding')?.value as Decimal).toNumber()).toBe(198.56);
|
|
604
|
+
// 902.54 - 198.56 = 703.98
|
|
605
|
+
expect((results.results.get('netPayout')?.value as Decimal).toNumber()).toBe(703.98);
|
|
606
|
+
});
|
|
607
|
+
});
|
|
608
|
+
});
|
package/src/formula-engine.ts
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
EvaluationContext,
|
|
5
5
|
EvaluationResult,
|
|
6
6
|
EvaluationResultSet,
|
|
7
|
+
EvaluateAllOptions,
|
|
7
8
|
ValidationResult,
|
|
8
9
|
FunctionDefinition,
|
|
9
10
|
ASTNode,
|
|
@@ -182,10 +183,15 @@ export class FormulaEngine {
|
|
|
182
183
|
|
|
183
184
|
/**
|
|
184
185
|
* Evaluate all formulas in dependency order
|
|
186
|
+
*
|
|
187
|
+
* @param formulas - Array of formula definitions to evaluate
|
|
188
|
+
* @param context - Evaluation context with variables
|
|
189
|
+
* @param options - Optional configuration for batch evaluation
|
|
185
190
|
*/
|
|
186
191
|
evaluateAll(
|
|
187
192
|
formulas: FormulaDefinition[],
|
|
188
|
-
context: EvaluationContext
|
|
193
|
+
context: EvaluationContext,
|
|
194
|
+
options?: EvaluateAllOptions
|
|
189
195
|
): EvaluationResultSet {
|
|
190
196
|
const startTime = Date.now();
|
|
191
197
|
const results = new Map<string, EvaluationResult>();
|
|
@@ -211,6 +217,12 @@ export class FormulaEngine {
|
|
|
211
217
|
formulaMap.set(formula.id, formula);
|
|
212
218
|
}
|
|
213
219
|
|
|
220
|
+
// Determine if intermediate rounding should be applied
|
|
221
|
+
const applyIntermediateRounding =
|
|
222
|
+
this.config.defaultRounding &&
|
|
223
|
+
this.config.defaultRounding.mode !== 'NONE' &&
|
|
224
|
+
!options?.disableIntermediateRounding;
|
|
225
|
+
|
|
214
226
|
// Evaluate in order, merging results into context
|
|
215
227
|
const workingContext: EvaluationContext = this.normalizeContext(context);
|
|
216
228
|
|
|
@@ -221,10 +233,16 @@ export class FormulaEngine {
|
|
|
221
233
|
try {
|
|
222
234
|
const result = this.evaluator.evaluate(formula.expression, workingContext);
|
|
223
235
|
|
|
224
|
-
// Apply rounding
|
|
236
|
+
// Apply rounding: per-formula config takes precedence, then defaultRounding
|
|
225
237
|
let value = result.value;
|
|
226
|
-
if (
|
|
227
|
-
|
|
238
|
+
if (this.isDecimal(value)) {
|
|
239
|
+
if (formula.rounding) {
|
|
240
|
+
// Per-formula rounding always takes precedence
|
|
241
|
+
value = this.applyRounding(value as Decimal, formula.rounding);
|
|
242
|
+
} else if (applyIntermediateRounding) {
|
|
243
|
+
// Apply default rounding to intermediate values
|
|
244
|
+
value = this.applyRounding(value as Decimal, this.config.defaultRounding!);
|
|
245
|
+
}
|
|
228
246
|
}
|
|
229
247
|
|
|
230
248
|
// Handle errors based on formula config
|
package/src/index.ts
CHANGED
package/src/types.ts
CHANGED
|
@@ -264,6 +264,19 @@ export interface EvaluationResultSet {
|
|
|
264
264
|
evaluationOrder: string[];
|
|
265
265
|
}
|
|
266
266
|
|
|
267
|
+
// ============================================================================
|
|
268
|
+
// Batch Evaluation Options
|
|
269
|
+
// ============================================================================
|
|
270
|
+
|
|
271
|
+
export interface EvaluateAllOptions {
|
|
272
|
+
/**
|
|
273
|
+
* When true, disables automatic intermediate rounding even if defaultRounding
|
|
274
|
+
* is configured in the engine. Per-formula rounding configurations are still applied.
|
|
275
|
+
* @default false
|
|
276
|
+
*/
|
|
277
|
+
disableIntermediateRounding?: boolean;
|
|
278
|
+
}
|
|
279
|
+
|
|
267
280
|
// ============================================================================
|
|
268
281
|
// Validation Result
|
|
269
282
|
// ============================================================================
|