@orkestrel/rater 0.0.11 → 0.0.13
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 +12 -8
- package/dist/src/core/index.cjs +127 -127
- package/dist/src/core/index.cjs.map +1 -0
- package/dist/src/core/index.d.cts +256 -253
- package/dist/src/core/index.d.ts +256 -253
- package/dist/src/core/index.js +120 -120
- package/dist/src/core/index.js.map +1 -0
- package/package.json +23 -18
package/dist/src/core/index.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
import { arrayOf, isArray, isBoolean, isJSONValue, isNumber, isString, literalOf, objectOf, recordOf } from "@orkestrel/contract";
|
|
2
|
-
import { buildErrorResult, createQuantitativeReasoner, createReason, formatField, isAggregation, isComparison, isFieldPath, isQuantitativeDefinition
|
|
1
|
+
import { arrayOf, isArray, isBoolean, isJSONValue, isNumber, isRecord, isString, literalOf, objectOf, recordOf } from "@orkestrel/contract";
|
|
2
|
+
import { buildErrorResult, createQuantitativeReasoner, createReason, formatField, isAggregation, isComparison, isFieldPath, isQuantitativeDefinition } from "@orkestrel/reason";
|
|
3
3
|
import { Emitter } from "@orkestrel/emitter";
|
|
4
4
|
//#region src/core/errors.ts
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* Represents a coded programmer error thrown by the rating layer.
|
|
7
7
|
*
|
|
8
8
|
* @remarks
|
|
9
9
|
* `DEFINITION` — the `rate` input failed both the array-of-lines and rating
|
|
@@ -28,10 +28,10 @@ var RaterError = class extends Error {
|
|
|
28
28
|
}
|
|
29
29
|
};
|
|
30
30
|
/**
|
|
31
|
-
*
|
|
31
|
+
* Narrows a caught value to a {@link RaterError}.
|
|
32
32
|
*
|
|
33
33
|
* @param value - The caught value to test
|
|
34
|
-
* @returns
|
|
34
|
+
* @returns True if `value` is a `RaterError`; false otherwise
|
|
35
35
|
*
|
|
36
36
|
* @example
|
|
37
37
|
* ```ts
|
|
@@ -50,10 +50,10 @@ function isRaterError(value) {
|
|
|
50
50
|
//#endregion
|
|
51
51
|
//#region src/core/validators.ts
|
|
52
52
|
/**
|
|
53
|
-
*
|
|
53
|
+
* Determines whether a value is a {@link Stage} literal.
|
|
54
54
|
*
|
|
55
55
|
* @param value - The value to test
|
|
56
|
-
* @returns
|
|
56
|
+
* @returns True if `value` is `'factor'`, `'group'`, or `'total'`; false otherwise
|
|
57
57
|
*
|
|
58
58
|
* @example
|
|
59
59
|
* ```ts
|
|
@@ -65,21 +65,21 @@ function isRaterError(value) {
|
|
|
65
65
|
*/
|
|
66
66
|
var isStage = literalOf("factor", "group", "total");
|
|
67
67
|
/**
|
|
68
|
-
*
|
|
68
|
+
* Determines whether a value is an exact {@link LineDefinition} record.
|
|
69
69
|
*
|
|
70
70
|
* @remarks
|
|
71
|
-
* Total guard
|
|
72
|
-
*
|
|
71
|
+
* Total guard: adversarial input (cycles, hostile prototypes) returns `false`,
|
|
72
|
+
* never throws. The record shape is EXACT — an extra key fails.
|
|
73
73
|
*
|
|
74
74
|
* @param value - The value to test
|
|
75
|
-
* @returns
|
|
75
|
+
* @returns True if `value` is a `LineDefinition`; false otherwise
|
|
76
76
|
*
|
|
77
77
|
* @example
|
|
78
78
|
* ```ts
|
|
79
|
-
* import {
|
|
79
|
+
* import { createQuantitativeDefinition } from '@orkestrel/reason'
|
|
80
80
|
* import { isLineDefinition } from '@orkestrel/rater'
|
|
81
81
|
*
|
|
82
|
-
* isLineDefinition({ id: 'base', name: 'Base', rate:
|
|
82
|
+
* isLineDefinition({ id: 'base', name: 'Base', rate: createQuantitativeDefinition('base', 'Base', []) }) // true
|
|
83
83
|
* ```
|
|
84
84
|
*/
|
|
85
85
|
function isLineDefinition(value) {
|
|
@@ -92,14 +92,14 @@ function isLineDefinition(value) {
|
|
|
92
92
|
}, ["description", "metadata"])(value);
|
|
93
93
|
}
|
|
94
94
|
/**
|
|
95
|
-
*
|
|
95
|
+
* Determines whether a value is an exact {@link RatingDefinition} record.
|
|
96
96
|
*
|
|
97
97
|
* @remarks
|
|
98
|
-
* Total guard
|
|
99
|
-
*
|
|
98
|
+
* Total guard: adversarial input (cycles, hostile prototypes) returns `false`,
|
|
99
|
+
* never throws. The record shape is EXACT — an extra key fails.
|
|
100
100
|
*
|
|
101
101
|
* @param value - The value to test
|
|
102
|
-
* @returns
|
|
102
|
+
* @returns True if `value` is a `RatingDefinition`; false otherwise
|
|
103
103
|
*
|
|
104
104
|
* @example
|
|
105
105
|
* ```ts
|
|
@@ -118,7 +118,7 @@ function isRatingDefinition(value) {
|
|
|
118
118
|
}, ["description", "metadata"])(value);
|
|
119
119
|
}
|
|
120
120
|
/**
|
|
121
|
-
*
|
|
121
|
+
* Determines whether a value is an open result-side {@link Evidence} object.
|
|
122
122
|
*
|
|
123
123
|
* @remarks
|
|
124
124
|
* Unknown members, prototypes, and class instances are admitted. Arrays are
|
|
@@ -127,7 +127,7 @@ function isRatingDefinition(value) {
|
|
|
127
127
|
* members rather than requiring or enumerating own keys.
|
|
128
128
|
*
|
|
129
129
|
* @param value - The value to test
|
|
130
|
-
* @returns
|
|
130
|
+
* @returns True if every checked `Evidence` member conforms; false otherwise
|
|
131
131
|
*
|
|
132
132
|
* @example
|
|
133
133
|
* ```ts
|
|
@@ -150,14 +150,14 @@ function isEvidence(value) {
|
|
|
150
150
|
])(value);
|
|
151
151
|
}
|
|
152
152
|
/**
|
|
153
|
-
*
|
|
153
|
+
* Determines whether a value is an open {@link WorksheetFactor} result object.
|
|
154
154
|
*
|
|
155
155
|
* @remarks
|
|
156
156
|
* Unknown members, prototypes, and class instances are admitted. Arrays are
|
|
157
157
|
* refused. Optional members may be absent or read as `undefined`.
|
|
158
158
|
*
|
|
159
159
|
* @param value - The value to test
|
|
160
|
-
* @returns
|
|
160
|
+
* @returns True if every published worksheet-factor member conforms; false otherwise
|
|
161
161
|
*
|
|
162
162
|
* @example
|
|
163
163
|
* ```ts
|
|
@@ -181,14 +181,14 @@ function isWorksheetFactor(value) {
|
|
|
181
181
|
])(value);
|
|
182
182
|
}
|
|
183
183
|
/**
|
|
184
|
-
*
|
|
184
|
+
* Determines whether a value is an open {@link WorksheetGroup} result object.
|
|
185
185
|
*
|
|
186
186
|
* @remarks
|
|
187
187
|
* Unknown members, prototypes, and class instances are admitted. Arrays are
|
|
188
188
|
* refused. Optional members may be absent or read as `undefined`.
|
|
189
189
|
*
|
|
190
190
|
* @param value - The value to test
|
|
191
|
-
* @returns
|
|
191
|
+
* @returns True if every published worksheet-group member conforms; false otherwise
|
|
192
192
|
*
|
|
193
193
|
* @example
|
|
194
194
|
* ```ts
|
|
@@ -208,14 +208,14 @@ function isWorksheetGroup(value) {
|
|
|
208
208
|
}, ["name", "description"])(value);
|
|
209
209
|
}
|
|
210
210
|
/**
|
|
211
|
-
*
|
|
211
|
+
* Determines whether a value is an open {@link Step} result object.
|
|
212
212
|
*
|
|
213
213
|
* @remarks
|
|
214
214
|
* Unknown members, prototypes, and class instances are admitted. Arrays are
|
|
215
215
|
* refused. Optional members may be absent or read as `undefined`.
|
|
216
216
|
*
|
|
217
217
|
* @param value - The value to test
|
|
218
|
-
* @returns
|
|
218
|
+
* @returns True if every published worksheet-step member conforms; false otherwise
|
|
219
219
|
*
|
|
220
220
|
* @example
|
|
221
221
|
* ```ts
|
|
@@ -238,14 +238,14 @@ function isStep(value) {
|
|
|
238
238
|
])(value);
|
|
239
239
|
}
|
|
240
240
|
/**
|
|
241
|
-
*
|
|
241
|
+
* Determines whether a value is an open {@link Worksheet} result object.
|
|
242
242
|
*
|
|
243
243
|
* @remarks
|
|
244
244
|
* Unknown members, prototypes, and class instances are admitted. Arrays are
|
|
245
245
|
* refused. Optional members may be absent or read as `undefined`.
|
|
246
246
|
*
|
|
247
247
|
* @param value - The value to test
|
|
248
|
-
* @returns
|
|
248
|
+
* @returns True if every published worksheet member conforms; false otherwise
|
|
249
249
|
*
|
|
250
250
|
* @example
|
|
251
251
|
* ```ts
|
|
@@ -269,21 +269,22 @@ function isWorksheet(value) {
|
|
|
269
269
|
}, ["precision"])(value);
|
|
270
270
|
}
|
|
271
271
|
/**
|
|
272
|
-
*
|
|
272
|
+
* Determines whether a value is an open {@link LineResult} object.
|
|
273
273
|
*
|
|
274
274
|
* @remarks
|
|
275
275
|
* Unknown members, prototypes, and class instances are admitted. Arrays are
|
|
276
276
|
* refused. `amount` may be absent or read as `undefined`; when present it stays
|
|
277
|
-
* a plain JavaScript `number` without a finite or range refinement.
|
|
277
|
+
* a plain JavaScript `number` without a finite or range refinement. The line's
|
|
278
|
+
* outcome lives on `worksheet`, so `worksheet.success` carries it.
|
|
278
279
|
*
|
|
279
280
|
* @param value - The value to test
|
|
280
|
-
* @returns
|
|
281
|
+
* @returns True if every published line-result member conforms; false otherwise
|
|
281
282
|
*
|
|
282
283
|
* @example
|
|
283
284
|
* ```ts
|
|
284
285
|
* import { isLineResult } from '@orkestrel/rater'
|
|
285
286
|
*
|
|
286
|
-
* isLineResult({ id: 'base', name: 'Base', worksheet: { id: 'base', name: 'Base', aggregation: 'sum', value: 0, groups: [], steps: [], trace: [], errors: [], success: false }
|
|
287
|
+
* isLineResult({ id: 'base', name: 'Base', worksheet: { id: 'base', name: 'Base', aggregation: 'sum', value: 0, groups: [], steps: [], trace: [], errors: [], success: false } }) // true
|
|
287
288
|
* ```
|
|
288
289
|
*/
|
|
289
290
|
function isLineResult(value) {
|
|
@@ -291,12 +292,11 @@ function isLineResult(value) {
|
|
|
291
292
|
id: isString,
|
|
292
293
|
name: isString,
|
|
293
294
|
amount: isNumber,
|
|
294
|
-
worksheet: isWorksheet
|
|
295
|
-
success: isBoolean
|
|
295
|
+
worksheet: isWorksheet
|
|
296
296
|
}, ["amount"])(value);
|
|
297
297
|
}
|
|
298
298
|
/**
|
|
299
|
-
*
|
|
299
|
+
* Determines whether a value is an open {@link RatingResult} object.
|
|
300
300
|
*
|
|
301
301
|
* @remarks
|
|
302
302
|
* Use this guard for a result returned by a borrowed `RaterInterface`. Unknown
|
|
@@ -305,7 +305,7 @@ function isLineResult(value) {
|
|
|
305
305
|
* JavaScript `number` without a finite or range refinement.
|
|
306
306
|
*
|
|
307
307
|
* @param value - The value to test
|
|
308
|
-
* @returns
|
|
308
|
+
* @returns True if every published rating-result member conforms; false otherwise
|
|
309
309
|
*
|
|
310
310
|
* @example
|
|
311
311
|
* ```ts
|
|
@@ -324,7 +324,7 @@ function isRatingResult(value) {
|
|
|
324
324
|
//#endregion
|
|
325
325
|
//#region src/core/helpers.ts
|
|
326
326
|
/**
|
|
327
|
-
*
|
|
327
|
+
* Builds a {@link LineDefinition}.
|
|
328
328
|
*
|
|
329
329
|
* @param id - The line id
|
|
330
330
|
* @param name - The display name
|
|
@@ -334,13 +334,13 @@ function isRatingResult(value) {
|
|
|
334
334
|
*
|
|
335
335
|
* @example
|
|
336
336
|
* ```ts
|
|
337
|
-
* import {
|
|
338
|
-
* import {
|
|
337
|
+
* import { createQuantitativeDefinition } from '@orkestrel/reason'
|
|
338
|
+
* import { buildLineDefinition } from '@orkestrel/rater'
|
|
339
339
|
*
|
|
340
|
-
*
|
|
340
|
+
* buildLineDefinition('base', 'Base Amount', createQuantitativeDefinition('base', 'Base', []))
|
|
341
341
|
* ```
|
|
342
342
|
*/
|
|
343
|
-
function
|
|
343
|
+
function buildLineDefinition(id, name, rate, overrides) {
|
|
344
344
|
return {
|
|
345
345
|
id,
|
|
346
346
|
name,
|
|
@@ -349,7 +349,7 @@ function lineDefinition(id, name, rate, overrides) {
|
|
|
349
349
|
};
|
|
350
350
|
}
|
|
351
351
|
/**
|
|
352
|
-
*
|
|
352
|
+
* Builds a {@link RatingDefinition}.
|
|
353
353
|
*
|
|
354
354
|
* @param id - The rating id
|
|
355
355
|
* @param name - The display name
|
|
@@ -359,15 +359,15 @@ function lineDefinition(id, name, rate, overrides) {
|
|
|
359
359
|
*
|
|
360
360
|
* @example
|
|
361
361
|
* ```ts
|
|
362
|
-
* import {
|
|
363
|
-
* import {
|
|
362
|
+
* import { buildLineDefinition, buildRatingDefinition } from '@orkestrel/rater'
|
|
363
|
+
* import { createQuantitativeDefinition } from '@orkestrel/reason'
|
|
364
364
|
*
|
|
365
|
-
*
|
|
366
|
-
*
|
|
365
|
+
* buildRatingDefinition('r1', 'Rating', [
|
|
366
|
+
* buildLineDefinition('base', 'Base Amount', createQuantitativeDefinition('base', 'Base', [])),
|
|
367
367
|
* ])
|
|
368
368
|
* ```
|
|
369
369
|
*/
|
|
370
|
-
function
|
|
370
|
+
function buildRatingDefinition(id, name, lines, overrides) {
|
|
371
371
|
return {
|
|
372
372
|
id,
|
|
373
373
|
name,
|
|
@@ -376,24 +376,25 @@ function ratingDefinition(id, name, lines, overrides) {
|
|
|
376
376
|
};
|
|
377
377
|
}
|
|
378
378
|
/**
|
|
379
|
-
*
|
|
379
|
+
* Builds an {@link Evidence} row from an evaluated {@link Check}.
|
|
380
380
|
*
|
|
381
381
|
* @param check - The authored check
|
|
382
382
|
* @param actual - The resolved subject value
|
|
383
|
-
* @param met -
|
|
383
|
+
* @param met - If `true`, the check was met; if `false`, it was not; absent when the check
|
|
384
|
+
* was not yet evaluated
|
|
384
385
|
* @param labels - Optional field-to-label overrides, keyed by dot-joined field
|
|
385
386
|
* @returns A fresh evidence row
|
|
386
387
|
*
|
|
387
388
|
* @example
|
|
388
389
|
* ```ts
|
|
389
|
-
* import {
|
|
390
|
-
* import {
|
|
390
|
+
* import { createCheck } from '@orkestrel/reason'
|
|
391
|
+
* import { buildEvidence } from '@orkestrel/rater'
|
|
391
392
|
*
|
|
392
|
-
* const entry =
|
|
393
|
-
*
|
|
393
|
+
* const entry = createCheck('age', 'above', 18)
|
|
394
|
+
* buildEvidence(entry, 25, true) // { field: 'age', comparison: 'above', expected: 18, actual: 25, met: true }
|
|
394
395
|
* ```
|
|
395
396
|
*/
|
|
396
|
-
function
|
|
397
|
+
function buildEvidence(check, actual, met, labels) {
|
|
397
398
|
const field = formatField(check.field);
|
|
398
399
|
return {
|
|
399
400
|
field: check.field,
|
|
@@ -405,8 +406,8 @@ function evidenceCheck(check, actual, met, labels) {
|
|
|
405
406
|
};
|
|
406
407
|
}
|
|
407
408
|
/**
|
|
408
|
-
*
|
|
409
|
-
*
|
|
409
|
+
* Builds one evidence row per authored check of a quantitative factor, joined
|
|
410
|
+
* to that check's evaluated result.
|
|
410
411
|
*
|
|
411
412
|
* @param checks - The factor's authored checks
|
|
412
413
|
* @param results - The corresponding {@link CheckResult}s, in the same order
|
|
@@ -415,21 +416,21 @@ function evidenceCheck(check, actual, met, labels) {
|
|
|
415
416
|
*
|
|
416
417
|
* @example
|
|
417
418
|
* ```ts
|
|
418
|
-
* import {
|
|
419
|
-
* import {
|
|
419
|
+
* import { createCheck } from '@orkestrel/reason'
|
|
420
|
+
* import { buildEvidenceRows } from '@orkestrel/rater'
|
|
420
421
|
*
|
|
421
|
-
* const checks = [
|
|
422
|
-
*
|
|
422
|
+
* const checks = [createCheck('age', 'above', 18)]
|
|
423
|
+
* buildEvidenceRows(checks, [{ field: 'age', met: true, actual: 25 }])
|
|
423
424
|
* ```
|
|
424
425
|
*/
|
|
425
|
-
function
|
|
426
|
+
function buildEvidenceRows(checks, results, labels) {
|
|
426
427
|
return (checks ?? []).map((check, index) => {
|
|
427
428
|
const result = results?.[index];
|
|
428
|
-
return
|
|
429
|
+
return buildEvidence(check, result?.actual, result?.met, labels);
|
|
429
430
|
});
|
|
430
431
|
}
|
|
431
432
|
/**
|
|
432
|
-
*
|
|
433
|
+
* Joins one authored quantitative factor to its evaluated {@link FactorResult}.
|
|
433
434
|
*
|
|
434
435
|
* @param definition - The authored factor
|
|
435
436
|
* @param results - The group's factor results
|
|
@@ -438,14 +439,14 @@ function checkEvidence(checks, results, labels) {
|
|
|
438
439
|
*
|
|
439
440
|
* @example
|
|
440
441
|
* ```ts
|
|
441
|
-
* import {
|
|
442
|
-
* import {
|
|
442
|
+
* import { createFieldFactor } from '@orkestrel/reason'
|
|
443
|
+
* import { buildWorksheetFactor } from '@orkestrel/rater'
|
|
443
444
|
*
|
|
444
|
-
* const factor =
|
|
445
|
-
*
|
|
445
|
+
* const factor = createFieldFactor('seats', 'seats')
|
|
446
|
+
* buildWorksheetFactor(factor, [{ id: 'seats', applied: true, value: 10 }])
|
|
446
447
|
* ```
|
|
447
448
|
*/
|
|
448
|
-
function
|
|
449
|
+
function buildWorksheetFactor(definition, results, labels) {
|
|
449
450
|
const result = results.find((entry) => entry.id === definition.id);
|
|
450
451
|
return {
|
|
451
452
|
id: definition.id,
|
|
@@ -453,11 +454,11 @@ function worksheetFactor(definition, results, labels) {
|
|
|
453
454
|
...definition.description === void 0 ? {} : { description: definition.description },
|
|
454
455
|
applied: result?.applied ?? false,
|
|
455
456
|
...result?.value === void 0 ? {} : { value: result.value },
|
|
456
|
-
evidence:
|
|
457
|
+
evidence: buildEvidenceRows(definition.checks, result?.checks, labels)
|
|
457
458
|
};
|
|
458
459
|
}
|
|
459
460
|
/**
|
|
460
|
-
*
|
|
461
|
+
* Joins one authored quantitative group to its evaluated {@link GroupResult}.
|
|
461
462
|
*
|
|
462
463
|
* @param definition - The authored group
|
|
463
464
|
* @param results - The definition's group results
|
|
@@ -466,14 +467,14 @@ function worksheetFactor(definition, results, labels) {
|
|
|
466
467
|
*
|
|
467
468
|
* @example
|
|
468
469
|
* ```ts
|
|
469
|
-
* import {
|
|
470
|
-
* import {
|
|
470
|
+
* import { createFactorGroup, createStaticFactor } from '@orkestrel/reason'
|
|
471
|
+
* import { buildWorksheetGroup } from '@orkestrel/rater'
|
|
471
472
|
*
|
|
472
|
-
* const group =
|
|
473
|
-
*
|
|
473
|
+
* const group = createFactorGroup('charge', 'sum', [createStaticFactor('base', 100)])
|
|
474
|
+
* buildWorksheetGroup(group, [{ id: 'charge', applied: true, value: 100, factors: [] }])
|
|
474
475
|
* ```
|
|
475
476
|
*/
|
|
476
|
-
function
|
|
477
|
+
function buildWorksheetGroup(definition, results, labels) {
|
|
477
478
|
const result = results.find((entry) => entry.id === definition.id);
|
|
478
479
|
return {
|
|
479
480
|
id: definition.id,
|
|
@@ -481,11 +482,11 @@ function worksheetGroup(definition, results, labels) {
|
|
|
481
482
|
...definition.description === void 0 ? {} : { description: definition.description },
|
|
482
483
|
applied: result?.applied ?? false,
|
|
483
484
|
value: result?.value ?? 0,
|
|
484
|
-
factors: definition.factors.map((factor) =>
|
|
485
|
+
factors: definition.factors.map((factor) => buildWorksheetFactor(factor, result?.factors ?? [], labels))
|
|
485
486
|
};
|
|
486
487
|
}
|
|
487
488
|
/**
|
|
488
|
-
*
|
|
489
|
+
* Builds one display-neutral {@link Step} row.
|
|
489
490
|
*
|
|
490
491
|
* @param stage - The step's stage
|
|
491
492
|
* @param id - The stage's authored id, when it has one
|
|
@@ -496,13 +497,13 @@ function worksheetGroup(definition, results, labels) {
|
|
|
496
497
|
*
|
|
497
498
|
* @example
|
|
498
499
|
* ```ts
|
|
499
|
-
* import {
|
|
500
|
+
* import { buildWorksheetStep } from '@orkestrel/rater'
|
|
500
501
|
*
|
|
501
|
-
*
|
|
502
|
+
* buildWorksheetStep('total', 'quote', 'Quote', 110, 'sum = 110')
|
|
502
503
|
* // { stage: 'total', id: 'quote', name: 'Quote', value: 110, expression: 'sum = 110' }
|
|
503
504
|
* ```
|
|
504
505
|
*/
|
|
505
|
-
function
|
|
506
|
+
function buildWorksheetStep(stage, id, name, value, expression) {
|
|
506
507
|
return {
|
|
507
508
|
stage,
|
|
508
509
|
...id === void 0 ? {} : { id },
|
|
@@ -512,7 +513,7 @@ function worksheetStep(stage, id, name, value, expression) {
|
|
|
512
513
|
};
|
|
513
514
|
}
|
|
514
515
|
/**
|
|
515
|
-
*
|
|
516
|
+
* Builds the ordered {@link Step} rows for a resolved {@link Worksheet}.
|
|
516
517
|
*
|
|
517
518
|
* @param definition - The authored quantitative definition
|
|
518
519
|
* @param result - The evaluated quantitative result
|
|
@@ -521,27 +522,27 @@ function worksheetStep(stage, id, name, value, expression) {
|
|
|
521
522
|
*
|
|
522
523
|
* @example
|
|
523
524
|
* ```ts
|
|
524
|
-
* import {
|
|
525
|
-
* import {
|
|
525
|
+
* import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'
|
|
526
|
+
* import { buildWorksheetGroup, buildWorksheetSteps } from '@orkestrel/rater'
|
|
526
527
|
*
|
|
527
|
-
* const definition =
|
|
528
|
+
* const definition = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])
|
|
528
529
|
* const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, definition)
|
|
529
530
|
* if (result.reasoning === 'quantitative') {
|
|
530
|
-
*
|
|
531
|
+
* buildWorksheetSteps(definition, result, definition.groups.map((group) => buildWorksheetGroup(group, result.groups)))
|
|
531
532
|
* }
|
|
532
533
|
* ```
|
|
533
534
|
*/
|
|
534
|
-
function
|
|
535
|
+
function buildWorksheetSteps(definition, result, groups) {
|
|
535
536
|
const output = [];
|
|
536
537
|
for (const group of groups) {
|
|
537
|
-
for (const factor of group.factors) if (factor.applied && factor.value !== void 0) output.push(
|
|
538
|
-
output.push(
|
|
538
|
+
for (const factor of group.factors) if (factor.applied && factor.value !== void 0) output.push(buildWorksheetStep("factor", factor.id, factor.name, factor.value, `${factor.id} = ${factor.value}`));
|
|
539
|
+
output.push(buildWorksheetStep("group", group.id, group.name, group.value, `${group.id} = ${group.value}`));
|
|
539
540
|
}
|
|
540
|
-
output.push(
|
|
541
|
+
output.push(buildWorksheetStep("total", definition.id, definition.name, result.value, `${definition.aggregation} = ${result.value}`));
|
|
541
542
|
return output;
|
|
542
543
|
}
|
|
543
544
|
/**
|
|
544
|
-
*
|
|
545
|
+
* Joins a {@link QuantitativeDefinition} and its {@link QuantitativeResult} into
|
|
545
546
|
* a {@link Worksheet} — the rating audit trail.
|
|
546
547
|
*
|
|
547
548
|
* @param definition - The authored quantitative definition
|
|
@@ -551,16 +552,16 @@ function worksheetSteps(definition, result, groups) {
|
|
|
551
552
|
*
|
|
552
553
|
* @example
|
|
553
554
|
* ```ts
|
|
554
|
-
* import {
|
|
555
|
-
* import {
|
|
555
|
+
* import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'
|
|
556
|
+
* import { buildWorksheet } from '@orkestrel/rater'
|
|
556
557
|
*
|
|
557
|
-
* const definition =
|
|
558
|
+
* const definition = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])
|
|
558
559
|
* const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, definition)
|
|
559
|
-
* if (result.reasoning === 'quantitative')
|
|
560
|
+
* if (result.reasoning === 'quantitative') buildWorksheet(definition, result) // the full audit trail
|
|
560
561
|
* ```
|
|
561
562
|
*/
|
|
562
|
-
function
|
|
563
|
-
const groups = definition.groups.map((group) =>
|
|
563
|
+
function buildWorksheet(definition, result, labels) {
|
|
564
|
+
const groups = definition.groups.map((group) => buildWorksheetGroup(group, result.groups, labels));
|
|
564
565
|
return {
|
|
565
566
|
id: definition.id,
|
|
566
567
|
name: definition.name,
|
|
@@ -568,14 +569,14 @@ function resultsWorksheet(definition, result, labels) {
|
|
|
568
569
|
...definition.precision === void 0 ? {} : { precision: definition.precision },
|
|
569
570
|
value: result.value,
|
|
570
571
|
groups,
|
|
571
|
-
steps:
|
|
572
|
+
steps: buildWorksheetSteps(definition, result, groups),
|
|
572
573
|
trace: result.trace,
|
|
573
574
|
errors: result.errors,
|
|
574
575
|
success: result.success
|
|
575
576
|
};
|
|
576
577
|
}
|
|
577
578
|
/**
|
|
578
|
-
*
|
|
579
|
+
* Builds a rated {@link LineResult} from a line's evaluated
|
|
579
580
|
* {@link QuantitativeResult}.
|
|
580
581
|
*
|
|
581
582
|
* @param definition - The authored line definition
|
|
@@ -585,38 +586,37 @@ function resultsWorksheet(definition, result, labels) {
|
|
|
585
586
|
*
|
|
586
587
|
* @example
|
|
587
588
|
* ```ts
|
|
588
|
-
* import { createQuantitativeReasoner, createReason
|
|
589
|
-
* import {
|
|
589
|
+
* import { createQuantitativeDefinition, createQuantitativeReasoner, createReason } from '@orkestrel/reason'
|
|
590
|
+
* import { buildLineDefinition, buildLineResult } from '@orkestrel/rater'
|
|
590
591
|
*
|
|
591
|
-
* const line =
|
|
592
|
+
* const line = buildLineDefinition('base', 'Base', createQuantitativeDefinition('base', 'Base', []))
|
|
592
593
|
* const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, line.rate)
|
|
593
|
-
* if (result.reasoning === 'quantitative')
|
|
594
|
+
* if (result.reasoning === 'quantitative') buildLineResult(line, result) // amount present only on a successful worksheet
|
|
594
595
|
* ```
|
|
595
596
|
*/
|
|
596
|
-
function
|
|
597
|
+
function buildLineResult(definition, result, labels) {
|
|
597
598
|
return {
|
|
598
599
|
id: definition.id,
|
|
599
600
|
name: definition.name,
|
|
600
601
|
...result.success ? { amount: result.value } : {},
|
|
601
|
-
worksheet:
|
|
602
|
-
success: result.success
|
|
602
|
+
worksheet: buildWorksheet(definition.rate, result, labels)
|
|
603
603
|
};
|
|
604
604
|
}
|
|
605
605
|
/**
|
|
606
|
-
*
|
|
606
|
+
* Sums defined line amounts.
|
|
607
607
|
*
|
|
608
608
|
* @param lines - The rated lines
|
|
609
609
|
* @returns The sum of every line's `amount`, or `undefined` when no line has one
|
|
610
610
|
*
|
|
611
611
|
* @example
|
|
612
612
|
* ```ts
|
|
613
|
-
* import {
|
|
614
|
-
* import {
|
|
613
|
+
* import { createFactorGroup, createQuantitativeDefinition, createQuantitativeReasoner, createReason, createStaticFactor } from '@orkestrel/reason'
|
|
614
|
+
* import { buildLineDefinition, buildLineResult, sumAmounts } from '@orkestrel/rater'
|
|
615
615
|
*
|
|
616
|
-
* const rate =
|
|
617
|
-
* const line =
|
|
616
|
+
* const rate = createQuantitativeDefinition('base', 'Base', [createFactorGroup('g', 'sum', [createStaticFactor('flat', 100)])])
|
|
617
|
+
* const line = buildLineDefinition('base', 'Base', rate)
|
|
618
618
|
* const result = createReason({ reasoners: [createQuantitativeReasoner()] }).reason({}, rate)
|
|
619
|
-
* if (result.reasoning === 'quantitative') sumAmounts([
|
|
619
|
+
* if (result.reasoning === 'quantitative') sumAmounts([buildLineResult(line, result)]) // 100
|
|
620
620
|
* ```
|
|
621
621
|
*/
|
|
622
622
|
function sumAmounts(lines) {
|
|
@@ -631,17 +631,17 @@ function sumAmounts(lines) {
|
|
|
631
631
|
//#endregion
|
|
632
632
|
//#region src/core/Rater.ts
|
|
633
633
|
/**
|
|
634
|
-
*
|
|
634
|
+
* Orchestrates rating — owns (or receives) the shared quantitative
|
|
635
635
|
* reasoning engine and projects results into the rating domain vocabulary.
|
|
636
636
|
*
|
|
637
637
|
* @remarks
|
|
638
638
|
* When no `engine` is injected, `Rater` builds and OWNS its own
|
|
639
639
|
* quantitative-only engine (`bail: false`) — Rater performs NO evaluation
|
|
640
640
|
* arithmetic of its own; it only orchestrates and projects. The
|
|
641
|
-
* array-of-lines `rate` overload is declared FIRST
|
|
642
|
-
* destroys an OWNED engine, then the
|
|
643
|
-
* engine is never destroyed. Afterwards every
|
|
644
|
-
* {@link RaterError} `'DESTROYED'`.
|
|
641
|
+
* array-of-lines `rate` overload is declared FIRST so a plain line list
|
|
642
|
+
* resolves to that form. `destroy()` destroys an OWNED engine, then the
|
|
643
|
+
* emitter LAST; an INJECTED engine is never destroyed. Afterwards every
|
|
644
|
+
* other method throws {@link RaterError} `'DESTROYED'`.
|
|
645
645
|
*
|
|
646
646
|
* @example
|
|
647
647
|
* ```ts
|
|
@@ -683,10 +683,10 @@ var Rater = class {
|
|
|
683
683
|
rate(input, subject) {
|
|
684
684
|
this.#ensureAlive();
|
|
685
685
|
const lines = this.#normalize(input);
|
|
686
|
-
if (!
|
|
686
|
+
if (!isRecord(subject)) throw new RaterError("MISMATCH", "Subject must be a record");
|
|
687
687
|
const results = lines.map((line) => this.#rateLine(line, subject));
|
|
688
688
|
const total = (this.#total ?? sumAmounts)(results);
|
|
689
|
-
const success = results.every((entry) => entry.success);
|
|
689
|
+
const success = results.every((entry) => entry.worksheet.success);
|
|
690
690
|
const result = {
|
|
691
691
|
lines: results,
|
|
692
692
|
...total === void 0 ? {} : { total },
|
|
@@ -707,7 +707,7 @@ var Rater = class {
|
|
|
707
707
|
throw new RaterError("DEFINITION", "Rating input must be an array of line definitions or a rating definition");
|
|
708
708
|
}
|
|
709
709
|
#rateLine(line, subject) {
|
|
710
|
-
return
|
|
710
|
+
return buildLineResult(line, this.#reasonQuantitative(subject, line.rate), this.#labels);
|
|
711
711
|
}
|
|
712
712
|
#reasonQuantitative(subject, definition) {
|
|
713
713
|
const result = this.#engine.reason(subject, definition);
|
|
@@ -735,7 +735,7 @@ var Rater = class {
|
|
|
735
735
|
//#endregion
|
|
736
736
|
//#region src/core/factories.ts
|
|
737
737
|
/**
|
|
738
|
-
*
|
|
738
|
+
* Creates a rating orchestrator.
|
|
739
739
|
*
|
|
740
740
|
* @param options - Optional total handler, labels, injected engine, and emitter hooks
|
|
741
741
|
* @returns A {@link RaterInterface}
|
|
@@ -752,6 +752,6 @@ function createRater(options) {
|
|
|
752
752
|
return new Rater(options);
|
|
753
753
|
}
|
|
754
754
|
//#endregion
|
|
755
|
-
export { Rater, RaterError,
|
|
755
|
+
export { Rater, RaterError, buildEvidence, buildEvidenceRows, buildLineDefinition, buildLineResult, buildRatingDefinition, buildWorksheet, buildWorksheetFactor, buildWorksheetGroup, buildWorksheetStep, buildWorksheetSteps, createRater, isEvidence, isLineDefinition, isLineResult, isRaterError, isRatingDefinition, isRatingResult, isStage, isStep, isWorksheet, isWorksheetFactor, isWorksheetGroup, sumAmounts };
|
|
756
756
|
|
|
757
757
|
//# sourceMappingURL=index.js.map
|