trilean 0.0.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +634 -0
- package/dist/computed-value.cjs +71 -0
- package/dist/computed-value.d.cts +43 -0
- package/dist/computed-value.d.ts +43 -0
- package/dist/computed-value.js +65 -0
- package/dist/derived-aggregates.cjs +74 -0
- package/dist/derived-aggregates.d.cts +12 -0
- package/dist/derived-aggregates.d.ts +12 -0
- package/dist/derived-aggregates.js +70 -0
- package/dist/derived-connectives.cjs +40 -0
- package/dist/derived-connectives.d.cts +17 -0
- package/dist/derived-connectives.d.ts +17 -0
- package/dist/derived-connectives.js +31 -0
- package/dist/evaluation.cjs +39 -0
- package/dist/evaluation.d.cts +29 -0
- package/dist/evaluation.d.ts +29 -0
- package/dist/evaluation.js +35 -0
- package/dist/evaluator.cjs +482 -0
- package/dist/evaluator.d.cts +18 -0
- package/dist/evaluator.d.ts +18 -0
- package/dist/evaluator.js +479 -0
- package/dist/functions.cjs +5 -0
- package/dist/functions.d.cts +11 -0
- package/dist/functions.d.ts +11 -0
- package/dist/functions.js +4 -0
- package/dist/index.cjs +69 -0
- package/dist/index.d.cts +10 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +9 -0
- package/dist/json-value-B1Hjjjri.d.cts +11 -0
- package/dist/json-value-B1Hjjjri.d.ts +11 -0
- package/dist/json-value.cjs +13 -0
- package/dist/json-value.d.cts +2 -0
- package/dist/json-value.d.ts +2 -0
- package/dist/json-value.js +12 -0
- package/dist/resolvers.cjs +0 -0
- package/dist/resolvers.d.cts +28 -0
- package/dist/resolvers.d.ts +28 -0
- package/dist/resolvers.js +0 -0
- package/dist/tree.cjs +289 -0
- package/dist/tree.d.cts +368 -0
- package/dist/tree.d.ts +368 -0
- package/dist/tree.js +257 -0
- package/package.json +114 -2
- package/schemas/trilean.schema.json +1 -0
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let zod = require("zod");
|
|
3
|
+
//#region src/computed-value.ts
|
|
4
|
+
/** Dimension symbol -> exponent, e.g. `{ m: 1, s: -1 }` for metres per second. A bare symbol like `"kg"` is shorthand for `{ kg: 1 }`. */
|
|
5
|
+
const UnitSchema = zod.z.record(zod.z.string(), zod.z.number());
|
|
6
|
+
const DurationUnitSchema = zod.z.enum([
|
|
7
|
+
"ms",
|
|
8
|
+
"s",
|
|
9
|
+
"min",
|
|
10
|
+
"h",
|
|
11
|
+
"d"
|
|
12
|
+
]);
|
|
13
|
+
const ComputedValueSchema = zod.z.discriminatedUnion("kind", [
|
|
14
|
+
zod.z.object({
|
|
15
|
+
kind: zod.z.literal("number"),
|
|
16
|
+
value: zod.z.number(),
|
|
17
|
+
unit: UnitSchema.optional()
|
|
18
|
+
}),
|
|
19
|
+
zod.z.object({
|
|
20
|
+
kind: zod.z.literal("text"),
|
|
21
|
+
value: zod.z.string()
|
|
22
|
+
}),
|
|
23
|
+
zod.z.object({
|
|
24
|
+
kind: zod.z.literal("instant"),
|
|
25
|
+
value: zod.z.string()
|
|
26
|
+
}),
|
|
27
|
+
zod.z.object({
|
|
28
|
+
kind: zod.z.literal("duration"),
|
|
29
|
+
value: zod.z.number(),
|
|
30
|
+
unit: DurationUnitSchema
|
|
31
|
+
})
|
|
32
|
+
]);
|
|
33
|
+
/** Drops zero-exponent dimensions so that, e.g., dividing a unit by itself normalises to the same dimensionless `{}` as an absent unit -- without this, `{ m: 0 }` and `{}` would compare unequal despite representing the same dimension. */
|
|
34
|
+
function normalizeUnit(unit) {
|
|
35
|
+
if (unit === void 0) return {};
|
|
36
|
+
const normalized = {};
|
|
37
|
+
for (const [dimension, exponent] of Object.entries(unit)) if (exponent !== 0) normalized[dimension] = exponent;
|
|
38
|
+
return normalized;
|
|
39
|
+
}
|
|
40
|
+
/** An operand with no `unit` is dimensionless (an empty map) for comparison purposes. */
|
|
41
|
+
function unitsEqual(a, b) {
|
|
42
|
+
const normalizedA = normalizeUnit(a);
|
|
43
|
+
const normalizedB = normalizeUnit(b);
|
|
44
|
+
const dimensionsA = Object.keys(normalizedA);
|
|
45
|
+
const dimensionsB = Object.keys(normalizedB);
|
|
46
|
+
if (dimensionsA.length !== dimensionsB.length) return false;
|
|
47
|
+
return dimensionsA.every((dimension) => normalizedA[dimension] === normalizedB[dimension]);
|
|
48
|
+
}
|
|
49
|
+
/** Multiplying two unit-tagged numbers adds exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
50
|
+
function combineUnitsForMultiply(a, b) {
|
|
51
|
+
const normalizedA = normalizeUnit(a);
|
|
52
|
+
const normalizedB = normalizeUnit(b);
|
|
53
|
+
const combined = { ...normalizedA };
|
|
54
|
+
for (const [dimension, exponent] of Object.entries(normalizedB)) combined[dimension] = (combined[dimension] ?? 0) + exponent;
|
|
55
|
+
return normalizeUnit(combined);
|
|
56
|
+
}
|
|
57
|
+
/** Dividing two unit-tagged numbers subtracts exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
58
|
+
function combineUnitsForDivide(a, b) {
|
|
59
|
+
const normalizedA = normalizeUnit(a);
|
|
60
|
+
const normalizedB = normalizeUnit(b);
|
|
61
|
+
const combined = { ...normalizedA };
|
|
62
|
+
for (const [dimension, exponent] of Object.entries(normalizedB)) combined[dimension] = (combined[dimension] ?? 0) - exponent;
|
|
63
|
+
return normalizeUnit(combined);
|
|
64
|
+
}
|
|
65
|
+
//#endregion
|
|
66
|
+
exports.ComputedValueSchema = ComputedValueSchema;
|
|
67
|
+
exports.DurationUnitSchema = DurationUnitSchema;
|
|
68
|
+
exports.UnitSchema = UnitSchema;
|
|
69
|
+
exports.combineUnitsForDivide = combineUnitsForDivide;
|
|
70
|
+
exports.combineUnitsForMultiply = combineUnitsForMultiply;
|
|
71
|
+
exports.unitsEqual = unitsEqual;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/computed-value.d.ts
|
|
3
|
+
/** Dimension symbol -> exponent, e.g. `{ m: 1, s: -1 }` for metres per second. A bare symbol like `"kg"` is shorthand for `{ kg: 1 }`. */
|
|
4
|
+
declare const UnitSchema: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
5
|
+
type Unit = z.infer<typeof UnitSchema>;
|
|
6
|
+
declare const DurationUnitSchema: z.ZodEnum<{
|
|
7
|
+
ms: "ms";
|
|
8
|
+
s: "s";
|
|
9
|
+
min: "min";
|
|
10
|
+
h: "h";
|
|
11
|
+
d: "d";
|
|
12
|
+
}>;
|
|
13
|
+
type DurationUnit = z.infer<typeof DurationUnitSchema>;
|
|
14
|
+
declare const ComputedValueSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
15
|
+
kind: z.ZodLiteral<"number">;
|
|
16
|
+
value: z.ZodNumber;
|
|
17
|
+
unit: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
18
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
19
|
+
kind: z.ZodLiteral<"text">;
|
|
20
|
+
value: z.ZodString;
|
|
21
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
22
|
+
kind: z.ZodLiteral<"instant">;
|
|
23
|
+
value: z.ZodString;
|
|
24
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
25
|
+
kind: z.ZodLiteral<"duration">;
|
|
26
|
+
value: z.ZodNumber;
|
|
27
|
+
unit: z.ZodEnum<{
|
|
28
|
+
ms: "ms";
|
|
29
|
+
s: "s";
|
|
30
|
+
min: "min";
|
|
31
|
+
h: "h";
|
|
32
|
+
d: "d";
|
|
33
|
+
}>;
|
|
34
|
+
}, z.core.$strip>], "kind">;
|
|
35
|
+
type ComputedValue = z.infer<typeof ComputedValueSchema>;
|
|
36
|
+
/** An operand with no `unit` is dimensionless (an empty map) for comparison purposes. */
|
|
37
|
+
declare function unitsEqual(a: Unit | undefined, b: Unit | undefined): boolean;
|
|
38
|
+
/** Multiplying two unit-tagged numbers adds exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
39
|
+
declare function combineUnitsForMultiply(a: Unit | undefined, b: Unit | undefined): Unit;
|
|
40
|
+
/** Dividing two unit-tagged numbers subtracts exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
41
|
+
declare function combineUnitsForDivide(a: Unit | undefined, b: Unit | undefined): Unit;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { ComputedValue, ComputedValueSchema, DurationUnit, DurationUnitSchema, Unit, UnitSchema, combineUnitsForDivide, combineUnitsForMultiply, unitsEqual };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/computed-value.d.ts
|
|
3
|
+
/** Dimension symbol -> exponent, e.g. `{ m: 1, s: -1 }` for metres per second. A bare symbol like `"kg"` is shorthand for `{ kg: 1 }`. */
|
|
4
|
+
declare const UnitSchema: z.ZodRecord<z.ZodString, z.ZodNumber>;
|
|
5
|
+
type Unit = z.infer<typeof UnitSchema>;
|
|
6
|
+
declare const DurationUnitSchema: z.ZodEnum<{
|
|
7
|
+
ms: "ms";
|
|
8
|
+
s: "s";
|
|
9
|
+
min: "min";
|
|
10
|
+
h: "h";
|
|
11
|
+
d: "d";
|
|
12
|
+
}>;
|
|
13
|
+
type DurationUnit = z.infer<typeof DurationUnitSchema>;
|
|
14
|
+
declare const ComputedValueSchema: z.ZodDiscriminatedUnion<[z.ZodObject<{
|
|
15
|
+
kind: z.ZodLiteral<"number">;
|
|
16
|
+
value: z.ZodNumber;
|
|
17
|
+
unit: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodNumber>>;
|
|
18
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
19
|
+
kind: z.ZodLiteral<"text">;
|
|
20
|
+
value: z.ZodString;
|
|
21
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
22
|
+
kind: z.ZodLiteral<"instant">;
|
|
23
|
+
value: z.ZodString;
|
|
24
|
+
}, z.core.$strip>, z.ZodObject<{
|
|
25
|
+
kind: z.ZodLiteral<"duration">;
|
|
26
|
+
value: z.ZodNumber;
|
|
27
|
+
unit: z.ZodEnum<{
|
|
28
|
+
ms: "ms";
|
|
29
|
+
s: "s";
|
|
30
|
+
min: "min";
|
|
31
|
+
h: "h";
|
|
32
|
+
d: "d";
|
|
33
|
+
}>;
|
|
34
|
+
}, z.core.$strip>], "kind">;
|
|
35
|
+
type ComputedValue = z.infer<typeof ComputedValueSchema>;
|
|
36
|
+
/** An operand with no `unit` is dimensionless (an empty map) for comparison purposes. */
|
|
37
|
+
declare function unitsEqual(a: Unit | undefined, b: Unit | undefined): boolean;
|
|
38
|
+
/** Multiplying two unit-tagged numbers adds exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
39
|
+
declare function combineUnitsForMultiply(a: Unit | undefined, b: Unit | undefined): Unit;
|
|
40
|
+
/** Dividing two unit-tagged numbers subtracts exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
41
|
+
declare function combineUnitsForDivide(a: Unit | undefined, b: Unit | undefined): Unit;
|
|
42
|
+
//#endregion
|
|
43
|
+
export { ComputedValue, ComputedValueSchema, DurationUnit, DurationUnitSchema, Unit, UnitSchema, combineUnitsForDivide, combineUnitsForMultiply, unitsEqual };
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/computed-value.ts
|
|
3
|
+
/** Dimension symbol -> exponent, e.g. `{ m: 1, s: -1 }` for metres per second. A bare symbol like `"kg"` is shorthand for `{ kg: 1 }`. */
|
|
4
|
+
const UnitSchema = z.record(z.string(), z.number());
|
|
5
|
+
const DurationUnitSchema = z.enum([
|
|
6
|
+
"ms",
|
|
7
|
+
"s",
|
|
8
|
+
"min",
|
|
9
|
+
"h",
|
|
10
|
+
"d"
|
|
11
|
+
]);
|
|
12
|
+
const ComputedValueSchema = z.discriminatedUnion("kind", [
|
|
13
|
+
z.object({
|
|
14
|
+
kind: z.literal("number"),
|
|
15
|
+
value: z.number(),
|
|
16
|
+
unit: UnitSchema.optional()
|
|
17
|
+
}),
|
|
18
|
+
z.object({
|
|
19
|
+
kind: z.literal("text"),
|
|
20
|
+
value: z.string()
|
|
21
|
+
}),
|
|
22
|
+
z.object({
|
|
23
|
+
kind: z.literal("instant"),
|
|
24
|
+
value: z.string()
|
|
25
|
+
}),
|
|
26
|
+
z.object({
|
|
27
|
+
kind: z.literal("duration"),
|
|
28
|
+
value: z.number(),
|
|
29
|
+
unit: DurationUnitSchema
|
|
30
|
+
})
|
|
31
|
+
]);
|
|
32
|
+
/** Drops zero-exponent dimensions so that, e.g., dividing a unit by itself normalises to the same dimensionless `{}` as an absent unit -- without this, `{ m: 0 }` and `{}` would compare unequal despite representing the same dimension. */
|
|
33
|
+
function normalizeUnit(unit) {
|
|
34
|
+
if (unit === void 0) return {};
|
|
35
|
+
const normalized = {};
|
|
36
|
+
for (const [dimension, exponent] of Object.entries(unit)) if (exponent !== 0) normalized[dimension] = exponent;
|
|
37
|
+
return normalized;
|
|
38
|
+
}
|
|
39
|
+
/** An operand with no `unit` is dimensionless (an empty map) for comparison purposes. */
|
|
40
|
+
function unitsEqual(a, b) {
|
|
41
|
+
const normalizedA = normalizeUnit(a);
|
|
42
|
+
const normalizedB = normalizeUnit(b);
|
|
43
|
+
const dimensionsA = Object.keys(normalizedA);
|
|
44
|
+
const dimensionsB = Object.keys(normalizedB);
|
|
45
|
+
if (dimensionsA.length !== dimensionsB.length) return false;
|
|
46
|
+
return dimensionsA.every((dimension) => normalizedA[dimension] === normalizedB[dimension]);
|
|
47
|
+
}
|
|
48
|
+
/** Multiplying two unit-tagged numbers adds exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
49
|
+
function combineUnitsForMultiply(a, b) {
|
|
50
|
+
const normalizedA = normalizeUnit(a);
|
|
51
|
+
const normalizedB = normalizeUnit(b);
|
|
52
|
+
const combined = { ...normalizedA };
|
|
53
|
+
for (const [dimension, exponent] of Object.entries(normalizedB)) combined[dimension] = (combined[dimension] ?? 0) + exponent;
|
|
54
|
+
return normalizeUnit(combined);
|
|
55
|
+
}
|
|
56
|
+
/** Dividing two unit-tagged numbers subtracts exponents per dimension. An operand with no `unit` is treated as dimensionless (an empty map). */
|
|
57
|
+
function combineUnitsForDivide(a, b) {
|
|
58
|
+
const normalizedA = normalizeUnit(a);
|
|
59
|
+
const normalizedB = normalizeUnit(b);
|
|
60
|
+
const combined = { ...normalizedA };
|
|
61
|
+
for (const [dimension, exponent] of Object.entries(normalizedB)) combined[dimension] = (combined[dimension] ?? 0) - exponent;
|
|
62
|
+
return normalizeUnit(combined);
|
|
63
|
+
}
|
|
64
|
+
//#endregion
|
|
65
|
+
export { ComputedValueSchema, DurationUnitSchema, UnitSchema, combineUnitsForDivide, combineUnitsForMultiply, unitsEqual };
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/derived-aggregates.ts
|
|
3
|
+
/**
|
|
4
|
+
* `sum`, `count`, and `average` are never their own `FoldCombiner` mode -- each is a builder function that assembles an ordinary `fold` (and, for `average`, one `arithmetic` division of two ordinary folds), exactly the same treatment `derived-connectives.ts` already gives `xor`/`nand`/`nor`/`implies`/`iff`/`none` (see the "Derived aggregates" section of README.md).
|
|
5
|
+
*/
|
|
6
|
+
const sum = (collection, item, filter) => ({
|
|
7
|
+
kind: "fold",
|
|
8
|
+
collection,
|
|
9
|
+
filter,
|
|
10
|
+
combiner: {
|
|
11
|
+
mode: "reduce",
|
|
12
|
+
initial: {
|
|
13
|
+
kind: "numberLiteral",
|
|
14
|
+
value: 0
|
|
15
|
+
},
|
|
16
|
+
combine: {
|
|
17
|
+
kind: "arithmetic",
|
|
18
|
+
op: "add",
|
|
19
|
+
left: { kind: "accumulator" },
|
|
20
|
+
right: item
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
});
|
|
24
|
+
const presenceOf = (probe) => ({
|
|
25
|
+
kind: "conditional",
|
|
26
|
+
cases: [{
|
|
27
|
+
when: {
|
|
28
|
+
kind: "memberOf",
|
|
29
|
+
op: "in",
|
|
30
|
+
operand: probe,
|
|
31
|
+
candidates: [probe]
|
|
32
|
+
},
|
|
33
|
+
then: {
|
|
34
|
+
kind: "numberLiteral",
|
|
35
|
+
value: 1
|
|
36
|
+
}
|
|
37
|
+
}],
|
|
38
|
+
fallback: {
|
|
39
|
+
kind: "numberLiteral",
|
|
40
|
+
value: 0
|
|
41
|
+
}
|
|
42
|
+
});
|
|
43
|
+
const count = (collection, filter, probe) => ({
|
|
44
|
+
kind: "fold",
|
|
45
|
+
collection,
|
|
46
|
+
filter,
|
|
47
|
+
combiner: {
|
|
48
|
+
mode: "reduce",
|
|
49
|
+
initial: {
|
|
50
|
+
kind: "numberLiteral",
|
|
51
|
+
value: 0
|
|
52
|
+
},
|
|
53
|
+
combine: {
|
|
54
|
+
kind: "arithmetic",
|
|
55
|
+
op: "add",
|
|
56
|
+
left: { kind: "accumulator" },
|
|
57
|
+
right: probe ? presenceOf(probe) : {
|
|
58
|
+
kind: "numberLiteral",
|
|
59
|
+
value: 1
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
const average = (collection, item, filter) => ({
|
|
65
|
+
kind: "arithmetic",
|
|
66
|
+
op: "divide",
|
|
67
|
+
left: sum(collection, item, filter),
|
|
68
|
+
right: count(collection, filter)
|
|
69
|
+
});
|
|
70
|
+
//#endregion
|
|
71
|
+
exports.average = average;
|
|
72
|
+
exports.count = count;
|
|
73
|
+
exports.presenceOf = presenceOf;
|
|
74
|
+
exports.sum = sum;
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { t as JsonValue } from "./json-value-B1Hjjjri.cjs";
|
|
2
|
+
import { ExpressionNode, PredicateNode } from "./tree.cjs";
|
|
3
|
+
//#region src/derived-aggregates.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* `sum`, `count`, and `average` are never their own `FoldCombiner` mode -- each is a builder function that assembles an ordinary `fold` (and, for `average`, one `arithmetic` division of two ordinary folds), exactly the same treatment `derived-connectives.ts` already gives `xor`/`nand`/`nor`/`implies`/`iff`/`none` (see the "Derived aggregates" section of README.md).
|
|
6
|
+
*/
|
|
7
|
+
declare const sum: (collection: JsonValue, item: ExpressionNode, filter?: PredicateNode) => ExpressionNode;
|
|
8
|
+
declare const presenceOf: (probe: ExpressionNode) => ExpressionNode;
|
|
9
|
+
declare const count: (collection: JsonValue, filter?: PredicateNode, probe?: ExpressionNode) => ExpressionNode;
|
|
10
|
+
declare const average: (collection: JsonValue, item: ExpressionNode, filter?: PredicateNode) => ExpressionNode;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { average, count, presenceOf, sum };
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { t as JsonValue } from "./json-value-B1Hjjjri.js";
|
|
2
|
+
import { ExpressionNode, PredicateNode } from "./tree.js";
|
|
3
|
+
//#region src/derived-aggregates.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* `sum`, `count`, and `average` are never their own `FoldCombiner` mode -- each is a builder function that assembles an ordinary `fold` (and, for `average`, one `arithmetic` division of two ordinary folds), exactly the same treatment `derived-connectives.ts` already gives `xor`/`nand`/`nor`/`implies`/`iff`/`none` (see the "Derived aggregates" section of README.md).
|
|
6
|
+
*/
|
|
7
|
+
declare const sum: (collection: JsonValue, item: ExpressionNode, filter?: PredicateNode) => ExpressionNode;
|
|
8
|
+
declare const presenceOf: (probe: ExpressionNode) => ExpressionNode;
|
|
9
|
+
declare const count: (collection: JsonValue, filter?: PredicateNode, probe?: ExpressionNode) => ExpressionNode;
|
|
10
|
+
declare const average: (collection: JsonValue, item: ExpressionNode, filter?: PredicateNode) => ExpressionNode;
|
|
11
|
+
//#endregion
|
|
12
|
+
export { average, count, presenceOf, sum };
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
//#region src/derived-aggregates.ts
|
|
2
|
+
/**
|
|
3
|
+
* `sum`, `count`, and `average` are never their own `FoldCombiner` mode -- each is a builder function that assembles an ordinary `fold` (and, for `average`, one `arithmetic` division of two ordinary folds), exactly the same treatment `derived-connectives.ts` already gives `xor`/`nand`/`nor`/`implies`/`iff`/`none` (see the "Derived aggregates" section of README.md).
|
|
4
|
+
*/
|
|
5
|
+
const sum = (collection, item, filter) => ({
|
|
6
|
+
kind: "fold",
|
|
7
|
+
collection,
|
|
8
|
+
filter,
|
|
9
|
+
combiner: {
|
|
10
|
+
mode: "reduce",
|
|
11
|
+
initial: {
|
|
12
|
+
kind: "numberLiteral",
|
|
13
|
+
value: 0
|
|
14
|
+
},
|
|
15
|
+
combine: {
|
|
16
|
+
kind: "arithmetic",
|
|
17
|
+
op: "add",
|
|
18
|
+
left: { kind: "accumulator" },
|
|
19
|
+
right: item
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
const presenceOf = (probe) => ({
|
|
24
|
+
kind: "conditional",
|
|
25
|
+
cases: [{
|
|
26
|
+
when: {
|
|
27
|
+
kind: "memberOf",
|
|
28
|
+
op: "in",
|
|
29
|
+
operand: probe,
|
|
30
|
+
candidates: [probe]
|
|
31
|
+
},
|
|
32
|
+
then: {
|
|
33
|
+
kind: "numberLiteral",
|
|
34
|
+
value: 1
|
|
35
|
+
}
|
|
36
|
+
}],
|
|
37
|
+
fallback: {
|
|
38
|
+
kind: "numberLiteral",
|
|
39
|
+
value: 0
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
const count = (collection, filter, probe) => ({
|
|
43
|
+
kind: "fold",
|
|
44
|
+
collection,
|
|
45
|
+
filter,
|
|
46
|
+
combiner: {
|
|
47
|
+
mode: "reduce",
|
|
48
|
+
initial: {
|
|
49
|
+
kind: "numberLiteral",
|
|
50
|
+
value: 0
|
|
51
|
+
},
|
|
52
|
+
combine: {
|
|
53
|
+
kind: "arithmetic",
|
|
54
|
+
op: "add",
|
|
55
|
+
left: { kind: "accumulator" },
|
|
56
|
+
right: probe ? presenceOf(probe) : {
|
|
57
|
+
kind: "numberLiteral",
|
|
58
|
+
value: 1
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
const average = (collection, item, filter) => ({
|
|
64
|
+
kind: "arithmetic",
|
|
65
|
+
op: "divide",
|
|
66
|
+
left: sum(collection, item, filter),
|
|
67
|
+
right: count(collection, filter)
|
|
68
|
+
});
|
|
69
|
+
//#endregion
|
|
70
|
+
export { average, count, presenceOf, sum };
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
//#region src/derived-connectives.ts
|
|
3
|
+
/**
|
|
4
|
+
* `not`/`and`/`or` are the primitive `PredicateNode` object-constructors -- everything else in this file is built purely by composing these three, so its three-valued correctness is inherited from the already-verified AND/OR/NOT tables rather than requiring a separate proof (see the "Derived connectives" section of README.md).
|
|
5
|
+
*/
|
|
6
|
+
const not = (a) => ({
|
|
7
|
+
kind: "not",
|
|
8
|
+
operand: a
|
|
9
|
+
});
|
|
10
|
+
const and = (a, b) => ({
|
|
11
|
+
kind: "and",
|
|
12
|
+
left: a,
|
|
13
|
+
right: b
|
|
14
|
+
});
|
|
15
|
+
const or = (a, b) => ({
|
|
16
|
+
kind: "or",
|
|
17
|
+
left: a,
|
|
18
|
+
right: b
|
|
19
|
+
});
|
|
20
|
+
const xor = (a, b) => or(and(a, not(b)), and(not(a), b));
|
|
21
|
+
const nand = (a, b) => not(and(a, b));
|
|
22
|
+
const nor = (a, b) => not(or(a, b));
|
|
23
|
+
const implies = (a, b) => or(not(a), b);
|
|
24
|
+
const iff = (a, b) => not(xor(a, b));
|
|
25
|
+
const none = (collection, item, filter) => not({
|
|
26
|
+
kind: "some",
|
|
27
|
+
collection,
|
|
28
|
+
item,
|
|
29
|
+
filter
|
|
30
|
+
});
|
|
31
|
+
//#endregion
|
|
32
|
+
exports.and = and;
|
|
33
|
+
exports.iff = iff;
|
|
34
|
+
exports.implies = implies;
|
|
35
|
+
exports.nand = nand;
|
|
36
|
+
exports.none = none;
|
|
37
|
+
exports.nor = nor;
|
|
38
|
+
exports.not = not;
|
|
39
|
+
exports.or = or;
|
|
40
|
+
exports.xor = xor;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { t as JsonValue } from "./json-value-B1Hjjjri.cjs";
|
|
2
|
+
import { PredicateNode } from "./tree.cjs";
|
|
3
|
+
//#region src/derived-connectives.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* `not`/`and`/`or` are the primitive `PredicateNode` object-constructors -- everything else in this file is built purely by composing these three, so its three-valued correctness is inherited from the already-verified AND/OR/NOT tables rather than requiring a separate proof (see the "Derived connectives" section of README.md).
|
|
6
|
+
*/
|
|
7
|
+
declare const not: (a: PredicateNode) => PredicateNode;
|
|
8
|
+
declare const and: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
9
|
+
declare const or: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
10
|
+
declare const xor: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
11
|
+
declare const nand: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
12
|
+
declare const nor: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
13
|
+
declare const implies: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
14
|
+
declare const iff: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
15
|
+
declare const none: (collection: JsonValue, item: PredicateNode, filter?: PredicateNode) => PredicateNode;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { and, iff, implies, nand, none, nor, not, or, xor };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { t as JsonValue } from "./json-value-B1Hjjjri.js";
|
|
2
|
+
import { PredicateNode } from "./tree.js";
|
|
3
|
+
//#region src/derived-connectives.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* `not`/`and`/`or` are the primitive `PredicateNode` object-constructors -- everything else in this file is built purely by composing these three, so its three-valued correctness is inherited from the already-verified AND/OR/NOT tables rather than requiring a separate proof (see the "Derived connectives" section of README.md).
|
|
6
|
+
*/
|
|
7
|
+
declare const not: (a: PredicateNode) => PredicateNode;
|
|
8
|
+
declare const and: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
9
|
+
declare const or: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
10
|
+
declare const xor: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
11
|
+
declare const nand: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
12
|
+
declare const nor: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
13
|
+
declare const implies: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
14
|
+
declare const iff: (a: PredicateNode, b: PredicateNode) => PredicateNode;
|
|
15
|
+
declare const none: (collection: JsonValue, item: PredicateNode, filter?: PredicateNode) => PredicateNode;
|
|
16
|
+
//#endregion
|
|
17
|
+
export { and, iff, implies, nand, none, nor, not, or, xor };
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
//#region src/derived-connectives.ts
|
|
2
|
+
/**
|
|
3
|
+
* `not`/`and`/`or` are the primitive `PredicateNode` object-constructors -- everything else in this file is built purely by composing these three, so its three-valued correctness is inherited from the already-verified AND/OR/NOT tables rather than requiring a separate proof (see the "Derived connectives" section of README.md).
|
|
4
|
+
*/
|
|
5
|
+
const not = (a) => ({
|
|
6
|
+
kind: "not",
|
|
7
|
+
operand: a
|
|
8
|
+
});
|
|
9
|
+
const and = (a, b) => ({
|
|
10
|
+
kind: "and",
|
|
11
|
+
left: a,
|
|
12
|
+
right: b
|
|
13
|
+
});
|
|
14
|
+
const or = (a, b) => ({
|
|
15
|
+
kind: "or",
|
|
16
|
+
left: a,
|
|
17
|
+
right: b
|
|
18
|
+
});
|
|
19
|
+
const xor = (a, b) => or(and(a, not(b)), and(not(a), b));
|
|
20
|
+
const nand = (a, b) => not(and(a, b));
|
|
21
|
+
const nor = (a, b) => not(or(a, b));
|
|
22
|
+
const implies = (a, b) => or(not(a), b);
|
|
23
|
+
const iff = (a, b) => not(xor(a, b));
|
|
24
|
+
const none = (collection, item, filter) => not({
|
|
25
|
+
kind: "some",
|
|
26
|
+
collection,
|
|
27
|
+
item,
|
|
28
|
+
filter
|
|
29
|
+
});
|
|
30
|
+
//#endregion
|
|
31
|
+
export { and, iff, implies, nand, none, nor, not, or, xor };
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
let zod = require("zod");
|
|
3
|
+
//#region src/evaluation.ts
|
|
4
|
+
const IndeterminateReasonSchema = zod.z.object({
|
|
5
|
+
/** Which of the three reason categories applies. */
|
|
6
|
+
code: zod.z.enum([
|
|
7
|
+
"not-found",
|
|
8
|
+
"wrong-type",
|
|
9
|
+
"domain-error"
|
|
10
|
+
]),
|
|
11
|
+
/** A human-readable explanation, for logging and debugging. */
|
|
12
|
+
message: zod.z.string()
|
|
13
|
+
});
|
|
14
|
+
function definite(value) {
|
|
15
|
+
return {
|
|
16
|
+
status: "definite",
|
|
17
|
+
value
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
function indeterminate(code, message) {
|
|
21
|
+
return {
|
|
22
|
+
status: "indeterminate",
|
|
23
|
+
reason: {
|
|
24
|
+
code,
|
|
25
|
+
message
|
|
26
|
+
}
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Implements the tie-break rule from "The evaluation model": when several sub-evaluations could each independently be indeterminate for a different reason, take the first indeterminate reason encountered in the node's own declared operand order. Entries that are `undefined` (an operand not yet evaluated, or not applicable to this node kind) are skipped rather than treated as indeterminate.
|
|
31
|
+
*/
|
|
32
|
+
function firstIndeterminate(...results) {
|
|
33
|
+
for (const result of results) if (result?.status === "indeterminate") return result.reason;
|
|
34
|
+
}
|
|
35
|
+
//#endregion
|
|
36
|
+
exports.IndeterminateReasonSchema = IndeterminateReasonSchema;
|
|
37
|
+
exports.definite = definite;
|
|
38
|
+
exports.firstIndeterminate = firstIndeterminate;
|
|
39
|
+
exports.indeterminate = indeterminate;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/evaluation.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Every evaluation -- of a predicate node or an expression node -- produces exactly one of two outcomes: a definite result, or an indeterminate result carrying a reason. Never a bare boolean/number, and never a thrown exception for a data-quality problem.
|
|
5
|
+
*/
|
|
6
|
+
type Evaluation<T> = {
|
|
7
|
+
status: "definite";
|
|
8
|
+
value: T;
|
|
9
|
+
} | {
|
|
10
|
+
status: "indeterminate";
|
|
11
|
+
reason: IndeterminateReason;
|
|
12
|
+
};
|
|
13
|
+
declare const IndeterminateReasonSchema: z.ZodObject<{
|
|
14
|
+
code: z.ZodEnum<{
|
|
15
|
+
"not-found": "not-found";
|
|
16
|
+
"wrong-type": "wrong-type";
|
|
17
|
+
"domain-error": "domain-error";
|
|
18
|
+
}>;
|
|
19
|
+
message: z.ZodString;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
type IndeterminateReason = z.infer<typeof IndeterminateReasonSchema>;
|
|
22
|
+
declare function definite<T>(value: T): Evaluation<T>;
|
|
23
|
+
declare function indeterminate(code: IndeterminateReason["code"], message: string): Evaluation<never>;
|
|
24
|
+
/**
|
|
25
|
+
* Implements the tie-break rule from "The evaluation model": when several sub-evaluations could each independently be indeterminate for a different reason, take the first indeterminate reason encountered in the node's own declared operand order. Entries that are `undefined` (an operand not yet evaluated, or not applicable to this node kind) are skipped rather than treated as indeterminate.
|
|
26
|
+
*/
|
|
27
|
+
declare function firstIndeterminate(...results: readonly (Evaluation<unknown> | undefined)[]): IndeterminateReason | undefined;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { Evaluation, IndeterminateReason, IndeterminateReasonSchema, definite, firstIndeterminate, indeterminate };
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/evaluation.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* Every evaluation -- of a predicate node or an expression node -- produces exactly one of two outcomes: a definite result, or an indeterminate result carrying a reason. Never a bare boolean/number, and never a thrown exception for a data-quality problem.
|
|
5
|
+
*/
|
|
6
|
+
type Evaluation<T> = {
|
|
7
|
+
status: "definite";
|
|
8
|
+
value: T;
|
|
9
|
+
} | {
|
|
10
|
+
status: "indeterminate";
|
|
11
|
+
reason: IndeterminateReason;
|
|
12
|
+
};
|
|
13
|
+
declare const IndeterminateReasonSchema: z.ZodObject<{
|
|
14
|
+
code: z.ZodEnum<{
|
|
15
|
+
"not-found": "not-found";
|
|
16
|
+
"wrong-type": "wrong-type";
|
|
17
|
+
"domain-error": "domain-error";
|
|
18
|
+
}>;
|
|
19
|
+
message: z.ZodString;
|
|
20
|
+
}, z.core.$strip>;
|
|
21
|
+
type IndeterminateReason = z.infer<typeof IndeterminateReasonSchema>;
|
|
22
|
+
declare function definite<T>(value: T): Evaluation<T>;
|
|
23
|
+
declare function indeterminate(code: IndeterminateReason["code"], message: string): Evaluation<never>;
|
|
24
|
+
/**
|
|
25
|
+
* Implements the tie-break rule from "The evaluation model": when several sub-evaluations could each independently be indeterminate for a different reason, take the first indeterminate reason encountered in the node's own declared operand order. Entries that are `undefined` (an operand not yet evaluated, or not applicable to this node kind) are skipped rather than treated as indeterminate.
|
|
26
|
+
*/
|
|
27
|
+
declare function firstIndeterminate(...results: readonly (Evaluation<unknown> | undefined)[]): IndeterminateReason | undefined;
|
|
28
|
+
//#endregion
|
|
29
|
+
export { Evaluation, IndeterminateReason, IndeterminateReasonSchema, definite, firstIndeterminate, indeterminate };
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/evaluation.ts
|
|
3
|
+
const IndeterminateReasonSchema = z.object({
|
|
4
|
+
/** Which of the three reason categories applies. */
|
|
5
|
+
code: z.enum([
|
|
6
|
+
"not-found",
|
|
7
|
+
"wrong-type",
|
|
8
|
+
"domain-error"
|
|
9
|
+
]),
|
|
10
|
+
/** A human-readable explanation, for logging and debugging. */
|
|
11
|
+
message: z.string()
|
|
12
|
+
});
|
|
13
|
+
function definite(value) {
|
|
14
|
+
return {
|
|
15
|
+
status: "definite",
|
|
16
|
+
value
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
function indeterminate(code, message) {
|
|
20
|
+
return {
|
|
21
|
+
status: "indeterminate",
|
|
22
|
+
reason: {
|
|
23
|
+
code,
|
|
24
|
+
message
|
|
25
|
+
}
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Implements the tie-break rule from "The evaluation model": when several sub-evaluations could each independently be indeterminate for a different reason, take the first indeterminate reason encountered in the node's own declared operand order. Entries that are `undefined` (an operand not yet evaluated, or not applicable to this node kind) are skipped rather than treated as indeterminate.
|
|
30
|
+
*/
|
|
31
|
+
function firstIndeterminate(...results) {
|
|
32
|
+
for (const result of results) if (result?.status === "indeterminate") return result.reason;
|
|
33
|
+
}
|
|
34
|
+
//#endregion
|
|
35
|
+
export { IndeterminateReasonSchema, definite, firstIndeterminate, indeterminate };
|