@kalada/core 0.1.0 → 0.3.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/README.md +25 -0
- package/dist/kalada-v1/canonical-input.cjs +133 -0
- package/dist/kalada-v1/canonical-input.cjs.map +1 -0
- package/dist/kalada-v1/canonical-input.d.cts +25 -0
- package/dist/kalada-v1/canonical-input.d.ts +25 -0
- package/dist/kalada-v1/canonical-input.js +122 -0
- package/dist/kalada-v1/canonical-input.js.map +1 -0
- package/dist/kalada-v1/canonicalize.cjs +214 -0
- package/dist/kalada-v1/canonicalize.cjs.map +1 -0
- package/dist/kalada-v1/canonicalize.d.cts +8 -0
- package/dist/kalada-v1/canonicalize.d.ts +8 -0
- package/dist/kalada-v1/canonicalize.js +212 -0
- package/dist/kalada-v1/canonicalize.js.map +1 -0
- package/dist/kalada-v1/codec.cjs +173 -0
- package/dist/kalada-v1/codec.cjs.map +1 -0
- package/dist/kalada-v1/codec.d.cts +32 -0
- package/dist/kalada-v1/codec.d.ts +32 -0
- package/dist/kalada-v1/codec.js +170 -0
- package/dist/kalada-v1/codec.js.map +1 -0
- package/dist/kalada-v1/compile.cjs +45 -0
- package/dist/kalada-v1/compile.cjs.map +1 -0
- package/dist/kalada-v1/compile.d.cts +8 -0
- package/dist/kalada-v1/compile.d.ts +8 -0
- package/dist/kalada-v1/compile.js +43 -0
- package/dist/kalada-v1/compile.js.map +1 -0
- package/dist/kalada-v1/dependencies.cjs +58 -0
- package/dist/kalada-v1/dependencies.cjs.map +1 -0
- package/dist/kalada-v1/dependencies.d.cts +8 -0
- package/dist/kalada-v1/dependencies.d.ts +8 -0
- package/dist/kalada-v1/dependencies.js +56 -0
- package/dist/kalada-v1/dependencies.js.map +1 -0
- package/dist/kalada-v1/diagnostics.cjs +49 -0
- package/dist/kalada-v1/diagnostics.cjs.map +1 -0
- package/dist/kalada-v1/diagnostics.d.cts +14 -0
- package/dist/kalada-v1/diagnostics.d.ts +14 -0
- package/dist/kalada-v1/diagnostics.js +45 -0
- package/dist/kalada-v1/diagnostics.js.map +1 -0
- package/dist/kalada-v1/evaluate.cjs +176 -0
- package/dist/kalada-v1/evaluate.cjs.map +1 -0
- package/dist/kalada-v1/evaluate.d.cts +8 -0
- package/dist/kalada-v1/evaluate.d.ts +8 -0
- package/dist/kalada-v1/evaluate.js +174 -0
- package/dist/kalada-v1/evaluate.js.map +1 -0
- package/dist/kalada-v1/factories.cjs +66 -0
- package/dist/kalada-v1/factories.cjs.map +1 -0
- package/dist/kalada-v1/factories.d.cts +30 -0
- package/dist/kalada-v1/factories.d.ts +30 -0
- package/dist/kalada-v1/factories.js +64 -0
- package/dist/kalada-v1/factories.js.map +1 -0
- package/dist/kalada-v1/index.cjs +88 -0
- package/dist/kalada-v1/index.cjs.map +1 -0
- package/dist/kalada-v1/index.d.cts +11 -0
- package/dist/kalada-v1/index.d.ts +11 -0
- package/dist/kalada-v1/index.js +11 -0
- package/dist/kalada-v1/index.js.map +1 -0
- package/dist/kalada-v1/json.cjs +129 -0
- package/dist/kalada-v1/json.cjs.map +1 -0
- package/dist/kalada-v1/json.d.cts +20 -0
- package/dist/kalada-v1/json.d.ts +20 -0
- package/dist/kalada-v1/json.js +123 -0
- package/dist/kalada-v1/json.js.map +1 -0
- package/dist/kalada-v1/limits.cjs +34 -0
- package/dist/kalada-v1/limits.cjs.map +1 -0
- package/dist/kalada-v1/limits.d.cts +9 -0
- package/dist/kalada-v1/limits.d.ts +9 -0
- package/dist/kalada-v1/limits.js +31 -0
- package/dist/kalada-v1/limits.js.map +1 -0
- package/dist/kalada-v1/schemas.cjs +182 -0
- package/dist/kalada-v1/schemas.cjs.map +1 -0
- package/dist/kalada-v1/schemas.d.cts +5 -0
- package/dist/kalada-v1/schemas.d.ts +5 -0
- package/dist/kalada-v1/schemas.js +179 -0
- package/dist/kalada-v1/schemas.js.map +1 -0
- package/dist/kalada-v1/temporal-evaluation.cjs +74 -0
- package/dist/kalada-v1/temporal-evaluation.cjs.map +1 -0
- package/dist/kalada-v1/temporal-evaluation.d.cts +13 -0
- package/dist/kalada-v1/temporal-evaluation.d.ts +13 -0
- package/dist/kalada-v1/temporal-evaluation.js +71 -0
- package/dist/kalada-v1/temporal-evaluation.js.map +1 -0
- package/dist/kalada-v1/temporal.cjs +42 -0
- package/dist/kalada-v1/temporal.cjs.map +1 -0
- package/dist/kalada-v1/temporal.d.cts +22 -0
- package/dist/kalada-v1/temporal.d.ts +22 -0
- package/dist/kalada-v1/temporal.js +37 -0
- package/dist/kalada-v1/temporal.js.map +1 -0
- package/dist/kalada-v1/types.cjs +4 -0
- package/dist/kalada-v1/types.cjs.map +1 -0
- package/dist/kalada-v1/types.d.cts +120 -0
- package/dist/kalada-v1/types.d.ts +120 -0
- package/dist/kalada-v1/types.js +3 -0
- package/dist/kalada-v1/types.js.map +1 -0
- package/dist/kalada-v1/values.cjs +112 -0
- package/dist/kalada-v1/values.cjs.map +1 -0
- package/dist/kalada-v1/values.d.cts +49 -0
- package/dist/kalada-v1/values.d.ts +49 -0
- package/dist/kalada-v1/values.js +105 -0
- package/dist/kalada-v1/values.js.map +1 -0
- package/package.json +11 -1
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { JsonValue } from './json.cjs';
|
|
2
|
+
import { KaladaV1Options, KaladaV1Outcome, KaladaV1Program } from './types.cjs';
|
|
3
|
+
import './temporal.cjs';
|
|
4
|
+
import './values.cjs';
|
|
5
|
+
|
|
6
|
+
declare function canonicalizeKaladaV1Program<R extends JsonValue = string>(input: unknown, options?: KaladaV1Options<R>): KaladaV1Outcome<KaladaV1Program<R>>;
|
|
7
|
+
|
|
8
|
+
export { canonicalizeKaladaV1Program };
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { JsonValue } from './json.js';
|
|
2
|
+
import { KaladaV1Options, KaladaV1Outcome, KaladaV1Program } from './types.js';
|
|
3
|
+
import './temporal.js';
|
|
4
|
+
import './values.js';
|
|
5
|
+
|
|
6
|
+
declare function canonicalizeKaladaV1Program<R extends JsonValue = string>(input: unknown, options?: KaladaV1Options<R>): KaladaV1Outcome<KaladaV1Program<R>>;
|
|
7
|
+
|
|
8
|
+
export { canonicalizeKaladaV1Program };
|
|
@@ -0,0 +1,212 @@
|
|
|
1
|
+
import { properties, count, exact, safeJson, inspectJson, safeValidate, safeCanonicalize, referenceLength, bindingName, strictArray } from './canonical-input.js';
|
|
2
|
+
import { KaladaFailure, success, failure } from './diagnostics.js';
|
|
3
|
+
import { resolveLimits } from './limits.js';
|
|
4
|
+
|
|
5
|
+
const NODE_KEYS = /* @__PURE__ */ new Set([
|
|
6
|
+
"kind",
|
|
7
|
+
"value",
|
|
8
|
+
"ref",
|
|
9
|
+
"name",
|
|
10
|
+
"body",
|
|
11
|
+
"variant",
|
|
12
|
+
"type",
|
|
13
|
+
"arms",
|
|
14
|
+
"milliseconds",
|
|
15
|
+
"operator",
|
|
16
|
+
"left",
|
|
17
|
+
"right"
|
|
18
|
+
]);
|
|
19
|
+
const ARM_ORDER = Object.freeze({ Option: ["some", "none"], Result: ["ok", "err"] });
|
|
20
|
+
function canonicalizeKaladaV1Program(input, options = {}) {
|
|
21
|
+
try {
|
|
22
|
+
const limits = resolveLimits(options.limits);
|
|
23
|
+
const fields = properties(input, [], /* @__PURE__ */ new Set(["format", "version", "profile", "expression"]));
|
|
24
|
+
if (fields.format !== "kalada-program" || fields.version !== 1 || fields.profile !== "kalada-v1") {
|
|
25
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", []);
|
|
26
|
+
}
|
|
27
|
+
const state = {
|
|
28
|
+
limits,
|
|
29
|
+
options,
|
|
30
|
+
active: /* @__PURE__ */ new WeakSet(),
|
|
31
|
+
astNodes: 0,
|
|
32
|
+
valueNodes: 0
|
|
33
|
+
};
|
|
34
|
+
const expression = canonicalNode(fields.expression, ["expression"], 0, state);
|
|
35
|
+
return success(
|
|
36
|
+
Object.freeze({ format: "kalada-program", version: 1, profile: "kalada-v1", expression })
|
|
37
|
+
);
|
|
38
|
+
} catch (error) {
|
|
39
|
+
const problem = error instanceof KaladaFailure ? error : new KaladaFailure("KALADA_INVALID_INPUT", []);
|
|
40
|
+
return failure(problem.code, problem.path);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
function canonicalNode(input, path, depth, state) {
|
|
44
|
+
count(path, depth, state);
|
|
45
|
+
if (typeof input !== "object" || input === null || state.active.has(input)) {
|
|
46
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", path);
|
|
47
|
+
}
|
|
48
|
+
state.active.add(input);
|
|
49
|
+
try {
|
|
50
|
+
const raw = properties(input, path, NODE_KEYS, false);
|
|
51
|
+
if (raw.kind === "literal") return canonicalLiteral(raw, path, state);
|
|
52
|
+
if (raw.kind === "ref") return canonicalReference(raw, path, state);
|
|
53
|
+
if (raw.kind === "binding") return canonicalBinding(raw, path, depth, state);
|
|
54
|
+
if (raw.kind === "option") return canonicalOption(raw, path, depth, state);
|
|
55
|
+
if (raw.kind === "result") return canonicalResult(raw, path, depth, state);
|
|
56
|
+
if (raw.kind === "match") return canonicalMatch(raw, path, depth, state);
|
|
57
|
+
if (raw.kind === "instant" || raw.kind === "duration") return canonicalTemporal(raw, path);
|
|
58
|
+
if (raw.kind === "current-instant") return canonicalCurrentInstant(raw, path);
|
|
59
|
+
if (raw.kind === "temporal-arithmetic") {
|
|
60
|
+
return canonicalTemporalOperation(raw, path, depth, state, ["add", "subtract"]);
|
|
61
|
+
}
|
|
62
|
+
if (raw.kind === "temporal-comparison") {
|
|
63
|
+
return canonicalTemporalOperation(raw, path, depth, state, [
|
|
64
|
+
"equal",
|
|
65
|
+
"not-equal",
|
|
66
|
+
"less-than",
|
|
67
|
+
"less-than-or-equal",
|
|
68
|
+
"greater-than",
|
|
69
|
+
"greater-than-or-equal"
|
|
70
|
+
]);
|
|
71
|
+
}
|
|
72
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", [...path, "kind"]);
|
|
73
|
+
} finally {
|
|
74
|
+
state.active.delete(input);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
function canonicalTemporal(raw, path) {
|
|
78
|
+
exact(raw, path, ["kind", "milliseconds"]);
|
|
79
|
+
if (!Number.isSafeInteger(raw.milliseconds)) {
|
|
80
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", [...path, "milliseconds"]);
|
|
81
|
+
}
|
|
82
|
+
return Object.freeze({
|
|
83
|
+
kind: raw.kind,
|
|
84
|
+
milliseconds: Object.is(raw.milliseconds, -0) ? 0 : raw.milliseconds
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
function canonicalCurrentInstant(raw, path) {
|
|
88
|
+
exact(raw, path, ["kind"]);
|
|
89
|
+
return Object.freeze({ kind: "current-instant" });
|
|
90
|
+
}
|
|
91
|
+
function canonicalTemporalOperation(raw, path, depth, state, operators) {
|
|
92
|
+
exact(raw, path, ["kind", "operator", "left", "right"]);
|
|
93
|
+
if (typeof raw.operator !== "string" || !operators.includes(raw.operator)) {
|
|
94
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", [...path, "operator"]);
|
|
95
|
+
}
|
|
96
|
+
return Object.freeze({
|
|
97
|
+
kind: raw.kind,
|
|
98
|
+
operator: raw.operator,
|
|
99
|
+
left: canonicalNode(raw.left, [...path, "left"], depth + 1, state),
|
|
100
|
+
right: canonicalNode(raw.right, [...path, "right"], depth + 1, state)
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function canonicalLiteral(raw, path, state) {
|
|
104
|
+
exact(raw, path, ["kind", "value"]);
|
|
105
|
+
return Object.freeze({
|
|
106
|
+
kind: "literal",
|
|
107
|
+
value: safeJson(raw.value, [...path, "value"], state)
|
|
108
|
+
});
|
|
109
|
+
}
|
|
110
|
+
function canonicalReference(raw, path, state) {
|
|
111
|
+
exact(raw, path, ["kind", "ref"]);
|
|
112
|
+
const refPath = [...path, "ref"];
|
|
113
|
+
const codec = state.options.reference;
|
|
114
|
+
const ref = codec ? inspectJson(raw.ref, refPath, state) : safeJson(raw.ref, refPath, state);
|
|
115
|
+
if (codec ? !safeValidate(codec.validate, ref) : typeof ref !== "string" || ref.length === 0) {
|
|
116
|
+
throw new KaladaFailure("KALADA_INVALID_REFERENCE", refPath);
|
|
117
|
+
}
|
|
118
|
+
const replacement = codec?.canonicalize ? safeCanonicalize(codec.canonicalize, ref, refPath) : ref;
|
|
119
|
+
const output = codec ? safeJson(replacement, refPath, state) : replacement;
|
|
120
|
+
if (codec && !safeValidate(codec.validate, output))
|
|
121
|
+
throw new KaladaFailure("KALADA_INVALID_REFERENCE", refPath);
|
|
122
|
+
if (referenceLength(output) > state.limits.maxReferenceLength)
|
|
123
|
+
throw new KaladaFailure("KALADA_LIMIT_EXCEEDED", refPath);
|
|
124
|
+
return Object.freeze({ kind: "ref", ref: output });
|
|
125
|
+
}
|
|
126
|
+
function canonicalBinding(raw, path, depth, state) {
|
|
127
|
+
exact(raw, path, ["kind", "name", "value", "body"]);
|
|
128
|
+
const name = bindingName(raw.name, [...path, "name"], state.limits);
|
|
129
|
+
return Object.freeze({
|
|
130
|
+
kind: "binding",
|
|
131
|
+
name,
|
|
132
|
+
value: canonicalNode(raw.value, [...path, "value"], depth + 1, state),
|
|
133
|
+
body: canonicalNode(raw.body, [...path, "body"], depth + 1, state)
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
function canonicalOption(raw, path, depth, state) {
|
|
137
|
+
if (raw.variant === "none") {
|
|
138
|
+
exact(raw, path, ["kind", "variant"]);
|
|
139
|
+
return Object.freeze({ kind: "option", variant: "none" });
|
|
140
|
+
}
|
|
141
|
+
if (raw.variant !== "some") throw new KaladaFailure("KALADA_INVALID_INPUT", [...path, "variant"]);
|
|
142
|
+
exact(raw, path, ["kind", "variant", "value"]);
|
|
143
|
+
return Object.freeze({
|
|
144
|
+
kind: "option",
|
|
145
|
+
variant: "some",
|
|
146
|
+
value: canonicalNode(raw.value, [...path, "value"], depth + 1, state)
|
|
147
|
+
});
|
|
148
|
+
}
|
|
149
|
+
function canonicalResult(raw, path, depth, state) {
|
|
150
|
+
if (raw.variant !== "ok" && raw.variant !== "err")
|
|
151
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", [...path, "variant"]);
|
|
152
|
+
exact(raw, path, ["kind", "variant", "value"]);
|
|
153
|
+
return Object.freeze({
|
|
154
|
+
kind: "result",
|
|
155
|
+
variant: raw.variant,
|
|
156
|
+
value: canonicalNode(raw.value, [...path, "value"], depth + 1, state)
|
|
157
|
+
});
|
|
158
|
+
}
|
|
159
|
+
function canonicalMatch(raw, path, depth, state) {
|
|
160
|
+
exact(raw, path, ["kind", "type", "value", "arms"]);
|
|
161
|
+
if (raw.type !== "Option" && raw.type !== "Result")
|
|
162
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", [...path, "type"]);
|
|
163
|
+
const value = canonicalNode(raw.value, [...path, "value"], depth + 1, state);
|
|
164
|
+
const arms = canonicalArms(raw.arms, raw.type, path, depth, state);
|
|
165
|
+
return Object.freeze({ kind: "match", type: raw.type, value, arms });
|
|
166
|
+
}
|
|
167
|
+
function canonicalArms(input, type, path, depth, state) {
|
|
168
|
+
if (!Array.isArray(input)) throw new KaladaFailure("KALADA_INVALID_INPUT", [...path, "arms"]);
|
|
169
|
+
const entries = strictArray(input, [...path, "arms"]);
|
|
170
|
+
const expected = ARM_ORDER[type];
|
|
171
|
+
const found = /* @__PURE__ */ new Map();
|
|
172
|
+
entries.forEach((entry, index) => {
|
|
173
|
+
addArm(entry, index, type, expected, found, path, depth, state);
|
|
174
|
+
});
|
|
175
|
+
if (found.size !== expected.length)
|
|
176
|
+
throw new KaladaFailure("KALADA_MATCH_MISSING_ARM", [...path, "arms"]);
|
|
177
|
+
return Object.freeze(expected.map((variant) => requiredArm(found, variant, path)));
|
|
178
|
+
}
|
|
179
|
+
function addArm(input, index, type, expected, found, path, depth, state) {
|
|
180
|
+
const armPath = [...path, "arms", index];
|
|
181
|
+
const raw = properties(input, armPath, /* @__PURE__ */ new Set(["variant", "binding", "body"]), false);
|
|
182
|
+
if (found.size === expected.length)
|
|
183
|
+
throw new KaladaFailure("KALADA_MATCH_UNREACHABLE_ARM", armPath);
|
|
184
|
+
if (typeof raw.variant !== "string" || !expected.includes(raw.variant))
|
|
185
|
+
throw new KaladaFailure("KALADA_MATCH_UNKNOWN_ARM", [...armPath, "variant"]);
|
|
186
|
+
if (found.has(raw.variant))
|
|
187
|
+
throw new KaladaFailure("KALADA_MATCH_DUPLICATE_ARM", [...armPath, "variant"]);
|
|
188
|
+
const allowsBinding = raw.variant !== "none";
|
|
189
|
+
if (!allowsBinding && "binding" in raw)
|
|
190
|
+
throw new KaladaFailure("KALADA_INVALID_INPUT", [...armPath, "binding"]);
|
|
191
|
+
exact(
|
|
192
|
+
raw,
|
|
193
|
+
armPath,
|
|
194
|
+
allowsBinding ? ["variant", "body", "binding"] : ["variant", "body"],
|
|
195
|
+
allowsBinding
|
|
196
|
+
);
|
|
197
|
+
const binding = raw.binding === void 0 ? void 0 : bindingName(raw.binding, [...armPath, "binding"], state.limits);
|
|
198
|
+
const body = canonicalNode(raw.body, [...armPath, "body"], depth + 1, state);
|
|
199
|
+
found.set(
|
|
200
|
+
raw.variant,
|
|
201
|
+
Object.freeze({ variant: raw.variant, ...binding ? { binding } : {}, body })
|
|
202
|
+
);
|
|
203
|
+
}
|
|
204
|
+
function requiredArm(found, variant, path) {
|
|
205
|
+
const arm = found.get(variant);
|
|
206
|
+
if (!arm) throw new KaladaFailure("KALADA_MATCH_MISSING_ARM", [...path, "arms"]);
|
|
207
|
+
return arm;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
export { canonicalizeKaladaV1Program };
|
|
211
|
+
//# sourceMappingURL=canonicalize.js.map
|
|
212
|
+
//# sourceMappingURL=canonicalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/kalada-v1/canonicalize.ts"],"names":[],"mappings":"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","file":"canonicalize.js","sourcesContent":["import {\n bindingName,\n count,\n exact,\n inspectJson,\n type Path,\n properties,\n referenceLength,\n type CanonicalState as State,\n safeCanonicalize,\n safeJson,\n safeValidate,\n strictArray,\n} from \"./canonical-input.js\";\nimport { failure, KaladaFailure, success } from \"./diagnostics.js\";\nimport type { JsonValue } from \"./json.js\";\nimport { resolveLimits } from \"./limits.js\";\nimport type {\n KaladaV1Expression,\n KaladaV1Options,\n KaladaV1Outcome,\n KaladaV1Program,\n MatchArm,\n} from \"./types.js\";\n\nconst NODE_KEYS = new Set([\n \"kind\",\n \"value\",\n \"ref\",\n \"name\",\n \"body\",\n \"variant\",\n \"type\",\n \"arms\",\n \"milliseconds\",\n \"operator\",\n \"left\",\n \"right\",\n]);\nconst ARM_ORDER = Object.freeze({ Option: [\"some\", \"none\"], Result: [\"ok\", \"err\"] } as const);\n\nexport function canonicalizeKaladaV1Program<R extends JsonValue = string>(\n input: unknown,\n options: KaladaV1Options<R> = {},\n): KaladaV1Outcome<KaladaV1Program<R>> {\n try {\n const limits = resolveLimits(options.limits);\n const fields = properties(input, [], new Set([\"format\", \"version\", \"profile\", \"expression\"]));\n if (\n fields.format !== \"kalada-program\" ||\n fields.version !== 1 ||\n fields.profile !== \"kalada-v1\"\n ) {\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", []);\n }\n const state: State<R> = {\n limits,\n options,\n active: new WeakSet(),\n astNodes: 0,\n valueNodes: 0,\n };\n const expression = canonicalNode(fields.expression, [\"expression\"], 0, state);\n return success(\n Object.freeze({ format: \"kalada-program\", version: 1, profile: \"kalada-v1\", expression }),\n );\n } catch (error) {\n const problem =\n error instanceof KaladaFailure ? error : new KaladaFailure(\"KALADA_INVALID_INPUT\", []);\n return failure(problem.code, problem.path);\n }\n}\n\nfunction canonicalNode<R extends JsonValue>(\n input: unknown,\n path: Path,\n depth: number,\n state: State<R>,\n): KaladaV1Expression<R> {\n count(path, depth, state);\n if (typeof input !== \"object\" || input === null || state.active.has(input)) {\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", path);\n }\n state.active.add(input);\n try {\n const raw = properties(input, path, NODE_KEYS, false);\n if (raw.kind === \"literal\") return canonicalLiteral(raw, path, state);\n if (raw.kind === \"ref\") return canonicalReference(raw, path, state);\n if (raw.kind === \"binding\") return canonicalBinding(raw, path, depth, state);\n if (raw.kind === \"option\") return canonicalOption(raw, path, depth, state);\n if (raw.kind === \"result\") return canonicalResult(raw, path, depth, state);\n if (raw.kind === \"match\") return canonicalMatch(raw, path, depth, state);\n if (raw.kind === \"instant\" || raw.kind === \"duration\") return canonicalTemporal(raw, path);\n if (raw.kind === \"current-instant\") return canonicalCurrentInstant(raw, path);\n if (raw.kind === \"temporal-arithmetic\") {\n return canonicalTemporalOperation(raw, path, depth, state, [\"add\", \"subtract\"]);\n }\n if (raw.kind === \"temporal-comparison\") {\n return canonicalTemporalOperation(raw, path, depth, state, [\n \"equal\",\n \"not-equal\",\n \"less-than\",\n \"less-than-or-equal\",\n \"greater-than\",\n \"greater-than-or-equal\",\n ]);\n }\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...path, \"kind\"]);\n } finally {\n state.active.delete(input);\n }\n}\n\nfunction canonicalTemporal(\n raw: Record<string, unknown>,\n path: Path,\n): Extract<KaladaV1Expression, { kind: \"instant\" | \"duration\" }> {\n exact(raw, path, [\"kind\", \"milliseconds\"]);\n if (!Number.isSafeInteger(raw.milliseconds)) {\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...path, \"milliseconds\"]);\n }\n return Object.freeze({\n kind: raw.kind,\n milliseconds: Object.is(raw.milliseconds, -0) ? 0 : raw.milliseconds,\n }) as Extract<KaladaV1Expression, { kind: \"instant\" | \"duration\" }>;\n}\n\nfunction canonicalCurrentInstant(\n raw: Record<string, unknown>,\n path: Path,\n): Extract<KaladaV1Expression, { kind: \"current-instant\" }> {\n exact(raw, path, [\"kind\"]);\n return Object.freeze({ kind: \"current-instant\" });\n}\n\nfunction canonicalTemporalOperation<R extends JsonValue>(\n raw: Record<string, unknown>,\n path: Path,\n depth: number,\n state: State<R>,\n operators: readonly string[],\n): KaladaV1Expression<R> {\n exact(raw, path, [\"kind\", \"operator\", \"left\", \"right\"]);\n if (typeof raw.operator !== \"string\" || !operators.includes(raw.operator)) {\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...path, \"operator\"]);\n }\n return Object.freeze({\n kind: raw.kind,\n operator: raw.operator,\n left: canonicalNode(raw.left, [...path, \"left\"], depth + 1, state),\n right: canonicalNode(raw.right, [...path, \"right\"], depth + 1, state),\n }) as KaladaV1Expression<R>;\n}\n\nfunction canonicalLiteral<R extends JsonValue>(\n raw: Record<string, unknown>,\n path: Path,\n state: State<R>,\n): KaladaV1Expression<R> {\n exact(raw, path, [\"kind\", \"value\"]);\n return Object.freeze({\n kind: \"literal\",\n value: safeJson(raw.value, [...path, \"value\"], state),\n });\n}\n\nfunction canonicalReference<R extends JsonValue>(\n raw: Record<string, unknown>,\n path: Path,\n state: State<R>,\n): KaladaV1Expression<R> {\n exact(raw, path, [\"kind\", \"ref\"]);\n const refPath = [...path, \"ref\"];\n const codec = state.options.reference;\n const ref = (\n codec ? inspectJson(raw.ref, refPath, state) : safeJson(raw.ref, refPath, state)\n ) as R;\n if (codec ? !safeValidate(codec.validate, ref) : typeof ref !== \"string\" || ref.length === 0) {\n throw new KaladaFailure(\"KALADA_INVALID_REFERENCE\", refPath);\n }\n const replacement = codec?.canonicalize\n ? safeCanonicalize(codec.canonicalize, ref, refPath)\n : ref;\n const output = (codec ? safeJson(replacement, refPath, state) : replacement) as R;\n if (codec && !safeValidate(codec.validate, output))\n throw new KaladaFailure(\"KALADA_INVALID_REFERENCE\", refPath);\n if (referenceLength(output) > state.limits.maxReferenceLength)\n throw new KaladaFailure(\"KALADA_LIMIT_EXCEEDED\", refPath);\n return Object.freeze({ kind: \"ref\", ref: output });\n}\n\nfunction canonicalBinding<R extends JsonValue>(\n raw: Record<string, unknown>,\n path: Path,\n depth: number,\n state: State<R>,\n): KaladaV1Expression<R> {\n exact(raw, path, [\"kind\", \"name\", \"value\", \"body\"]);\n const name = bindingName(raw.name, [...path, \"name\"], state.limits);\n return Object.freeze({\n kind: \"binding\",\n name,\n value: canonicalNode(raw.value, [...path, \"value\"], depth + 1, state),\n body: canonicalNode(raw.body, [...path, \"body\"], depth + 1, state),\n });\n}\n\nfunction canonicalOption<R extends JsonValue>(\n raw: Record<string, unknown>,\n path: Path,\n depth: number,\n state: State<R>,\n): KaladaV1Expression<R> {\n if (raw.variant === \"none\") {\n exact(raw, path, [\"kind\", \"variant\"]);\n return Object.freeze({ kind: \"option\", variant: \"none\" });\n }\n if (raw.variant !== \"some\") throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...path, \"variant\"]);\n exact(raw, path, [\"kind\", \"variant\", \"value\"]);\n return Object.freeze({\n kind: \"option\",\n variant: \"some\",\n value: canonicalNode(raw.value, [...path, \"value\"], depth + 1, state),\n });\n}\n\nfunction canonicalResult<R extends JsonValue>(\n raw: Record<string, unknown>,\n path: Path,\n depth: number,\n state: State<R>,\n): KaladaV1Expression<R> {\n if (raw.variant !== \"ok\" && raw.variant !== \"err\")\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...path, \"variant\"]);\n exact(raw, path, [\"kind\", \"variant\", \"value\"]);\n return Object.freeze({\n kind: \"result\",\n variant: raw.variant,\n value: canonicalNode(raw.value, [...path, \"value\"], depth + 1, state),\n });\n}\n\nfunction canonicalMatch<R extends JsonValue>(\n raw: Record<string, unknown>,\n path: Path,\n depth: number,\n state: State<R>,\n): KaladaV1Expression<R> {\n exact(raw, path, [\"kind\", \"type\", \"value\", \"arms\"]);\n if (raw.type !== \"Option\" && raw.type !== \"Result\")\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...path, \"type\"]);\n const value = canonicalNode(raw.value, [...path, \"value\"], depth + 1, state);\n const arms = canonicalArms(raw.arms, raw.type, path, depth, state);\n return Object.freeze({ kind: \"match\", type: raw.type, value, arms });\n}\n\nfunction canonicalArms<R extends JsonValue>(\n input: unknown,\n type: \"Option\" | \"Result\",\n path: Path,\n depth: number,\n state: State<R>,\n): readonly MatchArm<R>[] {\n if (!Array.isArray(input)) throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...path, \"arms\"]);\n const entries = strictArray(input, [...path, \"arms\"]);\n const expected: readonly string[] = ARM_ORDER[type];\n const found = new Map<string, MatchArm<R>>();\n entries.forEach((entry, index) => {\n addArm(entry, index, type, expected, found, path, depth, state);\n });\n if (found.size !== expected.length)\n throw new KaladaFailure(\"KALADA_MATCH_MISSING_ARM\", [...path, \"arms\"]);\n return Object.freeze(expected.map((variant) => requiredArm(found, variant, path)));\n}\n\nfunction addArm<R extends JsonValue>(\n input: unknown,\n index: number,\n type: \"Option\" | \"Result\",\n expected: readonly string[],\n found: Map<string, MatchArm<R>>,\n path: Path,\n depth: number,\n state: State<R>,\n): void {\n const armPath = [...path, \"arms\", index];\n const raw = properties(input, armPath, new Set([\"variant\", \"binding\", \"body\"]), false);\n if (found.size === expected.length)\n throw new KaladaFailure(\"KALADA_MATCH_UNREACHABLE_ARM\", armPath);\n if (typeof raw.variant !== \"string\" || !expected.includes(raw.variant))\n throw new KaladaFailure(\"KALADA_MATCH_UNKNOWN_ARM\", [...armPath, \"variant\"]);\n if (found.has(raw.variant))\n throw new KaladaFailure(\"KALADA_MATCH_DUPLICATE_ARM\", [...armPath, \"variant\"]);\n const allowsBinding = raw.variant !== \"none\";\n if (!allowsBinding && \"binding\" in raw)\n throw new KaladaFailure(\"KALADA_INVALID_INPUT\", [...armPath, \"binding\"]);\n exact(\n raw,\n armPath,\n allowsBinding ? [\"variant\", \"body\", \"binding\"] : [\"variant\", \"body\"],\n allowsBinding,\n );\n const binding =\n raw.binding === undefined\n ? undefined\n : bindingName(raw.binding, [...armPath, \"binding\"], state.limits);\n const body = canonicalNode(raw.body, [...armPath, \"body\"], depth + 1, state);\n found.set(\n raw.variant,\n Object.freeze({ variant: raw.variant, ...(binding ? { binding } : {}), body }) as MatchArm<R>,\n );\n void type;\n}\n\nfunction requiredArm<R extends JsonValue>(\n found: Map<string, MatchArm<R>>,\n variant: string,\n path: Path,\n): MatchArm<R> {\n const arm = found.get(variant);\n if (!arm) throw new KaladaFailure(\"KALADA_MATCH_MISSING_ARM\", [...path, \"arms\"]);\n return arm;\n}\n"]}
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var json_js = require('./json.js');
|
|
4
|
+
var limits_js = require('./limits.js');
|
|
5
|
+
var temporal_js = require('./temporal.js');
|
|
6
|
+
var values_js = require('./values.js');
|
|
7
|
+
|
|
8
|
+
const INVALID = "Invalid kalada-value v1 envelope.";
|
|
9
|
+
const LIMITS = Object.freeze({
|
|
10
|
+
maxDepth: limits_js.DEFAULT_KALADA_V1_LIMITS.maxValueDepth,
|
|
11
|
+
maxNodes: limits_js.DEFAULT_KALADA_V1_LIMITS.maxValueNodes,
|
|
12
|
+
maxStringLength: limits_js.DEFAULT_KALADA_V1_LIMITS.maxStringLength
|
|
13
|
+
});
|
|
14
|
+
function encodeKaladaValue(value) {
|
|
15
|
+
const frames = [];
|
|
16
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
17
|
+
let current = value;
|
|
18
|
+
let nodes = 0;
|
|
19
|
+
while (values_js.isOption(current) || values_js.isResult(current)) {
|
|
20
|
+
nodes = charge(nodes, frames.length);
|
|
21
|
+
if (seen.has(current)) throw new TypeError(INVALID);
|
|
22
|
+
seen.add(current);
|
|
23
|
+
if (values_js.isOption(current) && current.variant === "none") {
|
|
24
|
+
return wrapFrames(frozenNone(), frames);
|
|
25
|
+
}
|
|
26
|
+
frames.push({ type: current.type, variant: current.variant });
|
|
27
|
+
current = current.value;
|
|
28
|
+
}
|
|
29
|
+
if (temporal_js.isInstant(current) || temporal_js.isDuration(current)) {
|
|
30
|
+
charge(nodes, frames.length);
|
|
31
|
+
return wrapFrames(frozenTemporal(current.type, current.milliseconds), frames);
|
|
32
|
+
}
|
|
33
|
+
const remaining = LIMITS.maxNodes - charge(nodes, frames.length);
|
|
34
|
+
const json = json_js.cloneJsonWithStats(current, {
|
|
35
|
+
...LIMITS,
|
|
36
|
+
maxDepth: remainingDepth(frames.length),
|
|
37
|
+
maxNodes: remaining
|
|
38
|
+
});
|
|
39
|
+
return wrapFrames(frozenJson(json.value), frames);
|
|
40
|
+
}
|
|
41
|
+
function decodeKaladaValue(input) {
|
|
42
|
+
const frames = [];
|
|
43
|
+
const active = /* @__PURE__ */ new WeakSet();
|
|
44
|
+
let current = input;
|
|
45
|
+
let nodes = 0;
|
|
46
|
+
while (true) {
|
|
47
|
+
nodes = charge(nodes, frames.length);
|
|
48
|
+
const envelope = envelopeObject(current);
|
|
49
|
+
if (active.has(envelope)) throw new TypeError(INVALID);
|
|
50
|
+
active.add(envelope);
|
|
51
|
+
const fields = envelopeFields(envelope);
|
|
52
|
+
const temporal = decodeTemporal(envelope, fields);
|
|
53
|
+
if (temporal) return wrapValues(temporal, frames);
|
|
54
|
+
if (fields.type === "Json" && fields.variant === "value") {
|
|
55
|
+
assertKeys(envelope, ["format", "version", "type", "variant", "value"]);
|
|
56
|
+
const value = decodeJson(json_js.dataValue(envelope, "value"), nodes, frames.length);
|
|
57
|
+
return wrapValues(value, frames);
|
|
58
|
+
}
|
|
59
|
+
if (fields.type === "Option" && fields.variant === "none") {
|
|
60
|
+
assertKeys(envelope, ["format", "version", "type", "variant"]);
|
|
61
|
+
return wrapValues(values_js.Option.none(), frames);
|
|
62
|
+
}
|
|
63
|
+
frames.push(payloadFrame(fields.type, fields.variant));
|
|
64
|
+
assertKeys(envelope, ["format", "version", "type", "variant", "value"]);
|
|
65
|
+
current = json_js.dataValue(envelope, "value");
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
function decodeTemporal(envelope, fields) {
|
|
69
|
+
if (fields.type !== "Instant" && fields.type !== "Duration") return void 0;
|
|
70
|
+
if (fields.variant !== "milliseconds") throw new TypeError(INVALID);
|
|
71
|
+
assertKeys(envelope, ["format", "version", "type", "variant", "value"]);
|
|
72
|
+
const value = json_js.dataValue(envelope, "value");
|
|
73
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value)) throw new TypeError(INVALID);
|
|
74
|
+
return fields.type === "Instant" ? temporal_js.Instant.fromMilliseconds(value) : temporal_js.Duration.fromMilliseconds(value);
|
|
75
|
+
}
|
|
76
|
+
function decodeJson(input, nodes, depth) {
|
|
77
|
+
return json_js.cloneJson(input, {
|
|
78
|
+
...LIMITS,
|
|
79
|
+
maxDepth: remainingDepth(depth),
|
|
80
|
+
maxNodes: LIMITS.maxNodes - nodes
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
function envelopeObject(input) {
|
|
84
|
+
if (typeof input !== "object" || input === null || Array.isArray(input))
|
|
85
|
+
throw new TypeError(INVALID);
|
|
86
|
+
try {
|
|
87
|
+
const prototype = Object.getPrototypeOf(input);
|
|
88
|
+
if (prototype !== Object.prototype && prototype !== null) throw new TypeError(INVALID);
|
|
89
|
+
return input;
|
|
90
|
+
} catch {
|
|
91
|
+
throw new TypeError(INVALID);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
function envelopeFields(input) {
|
|
95
|
+
try {
|
|
96
|
+
if (json_js.dataValue(input, "format") !== "kalada-value" || json_js.dataValue(input, "version") !== 1) {
|
|
97
|
+
throw new TypeError(INVALID);
|
|
98
|
+
}
|
|
99
|
+
return { type: json_js.dataValue(input, "type"), variant: json_js.dataValue(input, "variant") };
|
|
100
|
+
} catch {
|
|
101
|
+
throw new TypeError(INVALID);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
function payloadFrame(type, variant) {
|
|
105
|
+
if (type === "Option" && variant === "some") return { type, variant };
|
|
106
|
+
if (type === "Result" && (variant === "ok" || variant === "err")) return { type, variant };
|
|
107
|
+
throw new TypeError(INVALID);
|
|
108
|
+
}
|
|
109
|
+
function assertKeys(input, expected) {
|
|
110
|
+
let keys;
|
|
111
|
+
try {
|
|
112
|
+
keys = Reflect.ownKeys(input);
|
|
113
|
+
} catch {
|
|
114
|
+
throw new TypeError(INVALID);
|
|
115
|
+
}
|
|
116
|
+
if (keys.length !== expected.length || !keys.every((key) => typeof key === "string" && expected.includes(key))) {
|
|
117
|
+
throw new TypeError(INVALID);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
function wrapFrames(leaf, frames) {
|
|
121
|
+
let output = leaf;
|
|
122
|
+
for (let index = frames.length - 1; index >= 0; index -= 1) {
|
|
123
|
+
const frame = frames[index];
|
|
124
|
+
if (!frame) throw new TypeError(INVALID);
|
|
125
|
+
output = Object.freeze({ format: "kalada-value", version: 1, ...frame, value: output });
|
|
126
|
+
}
|
|
127
|
+
return output;
|
|
128
|
+
}
|
|
129
|
+
function wrapValues(leaf, frames) {
|
|
130
|
+
let output = leaf;
|
|
131
|
+
for (let index = frames.length - 1; index >= 0; index -= 1) {
|
|
132
|
+
const frame = frames[index];
|
|
133
|
+
if (!frame) throw new TypeError(INVALID);
|
|
134
|
+
output = frame.type === "Option" ? values_js.Option.some(output) : frame.variant === "ok" ? values_js.Result.ok(output) : values_js.Result.err(output);
|
|
135
|
+
}
|
|
136
|
+
return output;
|
|
137
|
+
}
|
|
138
|
+
function charge(nodes, depth) {
|
|
139
|
+
if (depth > LIMITS.maxDepth || nodes >= LIMITS.maxNodes)
|
|
140
|
+
throw new RangeError("Kalada value exceeds its limits.");
|
|
141
|
+
return nodes + 1;
|
|
142
|
+
}
|
|
143
|
+
function remainingDepth(depth) {
|
|
144
|
+
const remaining = LIMITS.maxDepth - depth;
|
|
145
|
+
if (remaining < 0) throw new RangeError("Kalada value exceeds its limits.");
|
|
146
|
+
return remaining;
|
|
147
|
+
}
|
|
148
|
+
function frozenNone() {
|
|
149
|
+
return Object.freeze({ format: "kalada-value", version: 1, type: "Option", variant: "none" });
|
|
150
|
+
}
|
|
151
|
+
function frozenJson(value) {
|
|
152
|
+
return Object.freeze({
|
|
153
|
+
format: "kalada-value",
|
|
154
|
+
version: 1,
|
|
155
|
+
type: "Json",
|
|
156
|
+
variant: "value",
|
|
157
|
+
value
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
function frozenTemporal(type, value) {
|
|
161
|
+
return Object.freeze({
|
|
162
|
+
format: "kalada-value",
|
|
163
|
+
version: 1,
|
|
164
|
+
type,
|
|
165
|
+
variant: "milliseconds",
|
|
166
|
+
value
|
|
167
|
+
});
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
exports.decodeKaladaValue = decodeKaladaValue;
|
|
171
|
+
exports.encodeKaladaValue = encodeKaladaValue;
|
|
172
|
+
//# sourceMappingURL=codec.cjs.map
|
|
173
|
+
//# sourceMappingURL=codec.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/kalada-v1/codec.ts"],"names":["DEFAULT_KALADA_V1_LIMITS","isOption","isResult","isInstant","isDuration","cloneJsonWithStats","dataValue","Option","Instant","Duration","cloneJson","Result"],"mappings":"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","file":"codec.cjs","sourcesContent":["import { cloneJson, cloneJsonWithStats, dataValue, type JsonValue } from \"./json.js\";\nimport { DEFAULT_KALADA_V1_LIMITS } from \"./limits.js\";\nimport {\n Duration,\n type DurationValue,\n Instant,\n type InstantValue,\n isDuration,\n isInstant,\n} from \"./temporal.js\";\nimport { isOption, isResult, type KaladaValue, Option, Result } from \"./values.js\";\n\ninterface EncodedHeader {\n readonly format: \"kalada-value\";\n readonly version: 1;\n}\n\nexport type EncodedKaladaValueV1 =\n | (EncodedHeader & {\n readonly type: \"Json\";\n readonly variant: \"value\";\n readonly value: JsonValue;\n })\n | (EncodedHeader & { readonly type: \"Option\"; readonly variant: \"none\" })\n | (EncodedHeader & {\n readonly type: \"Option\";\n readonly variant: \"some\";\n readonly value: EncodedKaladaValueV1;\n })\n | (EncodedHeader & {\n readonly type: \"Result\";\n readonly variant: \"ok\" | \"err\";\n readonly value: EncodedKaladaValueV1;\n })\n | (EncodedHeader & {\n readonly type: \"Instant\" | \"Duration\";\n readonly variant: \"milliseconds\";\n readonly value: number;\n });\n\ntype Frame =\n | { readonly type: \"Option\"; readonly variant: \"some\" }\n | {\n readonly type: \"Result\";\n readonly variant: \"ok\" | \"err\";\n };\n\nconst INVALID = \"Invalid kalada-value v1 envelope.\";\nconst LIMITS = Object.freeze({\n maxDepth: DEFAULT_KALADA_V1_LIMITS.maxValueDepth,\n maxNodes: DEFAULT_KALADA_V1_LIMITS.maxValueNodes,\n maxStringLength: DEFAULT_KALADA_V1_LIMITS.maxStringLength,\n});\n\nexport function encodeKaladaValue(value: KaladaValue): EncodedKaladaValueV1 {\n const frames: Frame[] = [];\n const seen = new WeakSet<object>();\n let current = value;\n let nodes = 0;\n while (isOption(current) || isResult(current)) {\n nodes = charge(nodes, frames.length);\n if (seen.has(current)) throw new TypeError(INVALID);\n seen.add(current);\n if (isOption(current) && current.variant === \"none\") {\n return wrapFrames(frozenNone(), frames);\n }\n frames.push({ type: current.type, variant: current.variant } as Frame);\n current = current.value;\n }\n if (isInstant(current) || isDuration(current)) {\n charge(nodes, frames.length);\n return wrapFrames(frozenTemporal(current.type, current.milliseconds), frames);\n }\n const remaining = LIMITS.maxNodes - charge(nodes, frames.length);\n const json = cloneJsonWithStats(current, {\n ...LIMITS,\n maxDepth: remainingDepth(frames.length),\n maxNodes: remaining,\n });\n return wrapFrames(frozenJson(json.value), frames);\n}\n\nexport function decodeKaladaValue(input: unknown): KaladaValue {\n const frames: Frame[] = [];\n const active = new WeakSet<object>();\n let current = input;\n let nodes = 0;\n while (true) {\n nodes = charge(nodes, frames.length);\n const envelope = envelopeObject(current);\n if (active.has(envelope)) throw new TypeError(INVALID);\n active.add(envelope);\n const fields = envelopeFields(envelope);\n const temporal = decodeTemporal(envelope, fields);\n if (temporal) return wrapValues(temporal, frames);\n if (fields.type === \"Json\" && fields.variant === \"value\") {\n assertKeys(envelope, [\"format\", \"version\", \"type\", \"variant\", \"value\"]);\n const value = decodeJson(dataValue(envelope, \"value\"), nodes, frames.length);\n return wrapValues(value, frames);\n }\n if (fields.type === \"Option\" && fields.variant === \"none\") {\n assertKeys(envelope, [\"format\", \"version\", \"type\", \"variant\"]);\n return wrapValues(Option.none(), frames);\n }\n frames.push(payloadFrame(fields.type, fields.variant));\n assertKeys(envelope, [\"format\", \"version\", \"type\", \"variant\", \"value\"]);\n current = dataValue(envelope, \"value\");\n }\n}\n\nfunction decodeTemporal(\n envelope: object,\n fields: { type: unknown; variant: unknown },\n): InstantValue | DurationValue | undefined {\n if (fields.type !== \"Instant\" && fields.type !== \"Duration\") return undefined;\n if (fields.variant !== \"milliseconds\") throw new TypeError(INVALID);\n assertKeys(envelope, [\"format\", \"version\", \"type\", \"variant\", \"value\"]);\n const value = dataValue(envelope, \"value\");\n if (typeof value !== \"number\" || !Number.isSafeInteger(value)) throw new TypeError(INVALID);\n return fields.type === \"Instant\"\n ? Instant.fromMilliseconds(value)\n : Duration.fromMilliseconds(value);\n}\n\nfunction decodeJson(input: unknown, nodes: number, depth: number): JsonValue {\n return cloneJson(input, {\n ...LIMITS,\n maxDepth: remainingDepth(depth),\n maxNodes: LIMITS.maxNodes - nodes,\n });\n}\n\nfunction envelopeObject(input: unknown): object {\n if (typeof input !== \"object\" || input === null || Array.isArray(input))\n throw new TypeError(INVALID);\n try {\n const prototype = Object.getPrototypeOf(input);\n if (prototype !== Object.prototype && prototype !== null) throw new TypeError(INVALID);\n return input;\n } catch {\n throw new TypeError(INVALID);\n }\n}\n\nfunction envelopeFields(input: object): { type: unknown; variant: unknown } {\n try {\n if (dataValue(input, \"format\") !== \"kalada-value\" || dataValue(input, \"version\") !== 1) {\n throw new TypeError(INVALID);\n }\n return { type: dataValue(input, \"type\"), variant: dataValue(input, \"variant\") };\n } catch {\n throw new TypeError(INVALID);\n }\n}\n\nfunction payloadFrame(type: unknown, variant: unknown): Frame {\n if (type === \"Option\" && variant === \"some\") return { type, variant };\n if (type === \"Result\" && (variant === \"ok\" || variant === \"err\")) return { type, variant };\n throw new TypeError(INVALID);\n}\n\nfunction assertKeys(input: object, expected: readonly string[]): void {\n let keys: PropertyKey[];\n try {\n keys = Reflect.ownKeys(input);\n } catch {\n throw new TypeError(INVALID);\n }\n if (\n keys.length !== expected.length ||\n !keys.every((key) => typeof key === \"string\" && expected.includes(key))\n ) {\n throw new TypeError(INVALID);\n }\n}\n\nfunction wrapFrames(leaf: EncodedKaladaValueV1, frames: readonly Frame[]): EncodedKaladaValueV1 {\n let output = leaf;\n for (let index = frames.length - 1; index >= 0; index -= 1) {\n const frame = frames[index];\n if (!frame) throw new TypeError(INVALID);\n output = Object.freeze({ format: \"kalada-value\", version: 1, ...frame, value: output });\n }\n return output;\n}\n\nfunction wrapValues(leaf: KaladaValue, frames: readonly Frame[]): KaladaValue {\n let output = leaf;\n for (let index = frames.length - 1; index >= 0; index -= 1) {\n const frame = frames[index];\n if (!frame) throw new TypeError(INVALID);\n output =\n frame.type === \"Option\"\n ? Option.some(output)\n : frame.variant === \"ok\"\n ? Result.ok(output)\n : Result.err(output);\n }\n return output;\n}\n\nfunction charge(nodes: number, depth: number): number {\n if (depth > LIMITS.maxDepth || nodes >= LIMITS.maxNodes)\n throw new RangeError(\"Kalada value exceeds its limits.\");\n return nodes + 1;\n}\n\nfunction remainingDepth(depth: number): number {\n const remaining = LIMITS.maxDepth - depth;\n if (remaining < 0) throw new RangeError(\"Kalada value exceeds its limits.\");\n return remaining;\n}\n\nfunction frozenNone(): EncodedKaladaValueV1 {\n return Object.freeze({ format: \"kalada-value\", version: 1, type: \"Option\", variant: \"none\" });\n}\n\nfunction frozenJson(value: JsonValue): EncodedKaladaValueV1 {\n return Object.freeze({\n format: \"kalada-value\",\n version: 1,\n type: \"Json\",\n variant: \"value\",\n value,\n });\n}\n\nfunction frozenTemporal(type: \"Instant\" | \"Duration\", value: number): EncodedKaladaValueV1 {\n return Object.freeze({\n format: \"kalada-value\",\n version: 1,\n type,\n variant: \"milliseconds\",\n value,\n });\n}\n"]}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { JsonValue } from './json.cjs';
|
|
2
|
+
import { KaladaValue } from './values.cjs';
|
|
3
|
+
import './temporal.cjs';
|
|
4
|
+
|
|
5
|
+
interface EncodedHeader {
|
|
6
|
+
readonly format: "kalada-value";
|
|
7
|
+
readonly version: 1;
|
|
8
|
+
}
|
|
9
|
+
type EncodedKaladaValueV1 = (EncodedHeader & {
|
|
10
|
+
readonly type: "Json";
|
|
11
|
+
readonly variant: "value";
|
|
12
|
+
readonly value: JsonValue;
|
|
13
|
+
}) | (EncodedHeader & {
|
|
14
|
+
readonly type: "Option";
|
|
15
|
+
readonly variant: "none";
|
|
16
|
+
}) | (EncodedHeader & {
|
|
17
|
+
readonly type: "Option";
|
|
18
|
+
readonly variant: "some";
|
|
19
|
+
readonly value: EncodedKaladaValueV1;
|
|
20
|
+
}) | (EncodedHeader & {
|
|
21
|
+
readonly type: "Result";
|
|
22
|
+
readonly variant: "ok" | "err";
|
|
23
|
+
readonly value: EncodedKaladaValueV1;
|
|
24
|
+
}) | (EncodedHeader & {
|
|
25
|
+
readonly type: "Instant" | "Duration";
|
|
26
|
+
readonly variant: "milliseconds";
|
|
27
|
+
readonly value: number;
|
|
28
|
+
});
|
|
29
|
+
declare function encodeKaladaValue(value: KaladaValue): EncodedKaladaValueV1;
|
|
30
|
+
declare function decodeKaladaValue(input: unknown): KaladaValue;
|
|
31
|
+
|
|
32
|
+
export { type EncodedKaladaValueV1, decodeKaladaValue, encodeKaladaValue };
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { JsonValue } from './json.js';
|
|
2
|
+
import { KaladaValue } from './values.js';
|
|
3
|
+
import './temporal.js';
|
|
4
|
+
|
|
5
|
+
interface EncodedHeader {
|
|
6
|
+
readonly format: "kalada-value";
|
|
7
|
+
readonly version: 1;
|
|
8
|
+
}
|
|
9
|
+
type EncodedKaladaValueV1 = (EncodedHeader & {
|
|
10
|
+
readonly type: "Json";
|
|
11
|
+
readonly variant: "value";
|
|
12
|
+
readonly value: JsonValue;
|
|
13
|
+
}) | (EncodedHeader & {
|
|
14
|
+
readonly type: "Option";
|
|
15
|
+
readonly variant: "none";
|
|
16
|
+
}) | (EncodedHeader & {
|
|
17
|
+
readonly type: "Option";
|
|
18
|
+
readonly variant: "some";
|
|
19
|
+
readonly value: EncodedKaladaValueV1;
|
|
20
|
+
}) | (EncodedHeader & {
|
|
21
|
+
readonly type: "Result";
|
|
22
|
+
readonly variant: "ok" | "err";
|
|
23
|
+
readonly value: EncodedKaladaValueV1;
|
|
24
|
+
}) | (EncodedHeader & {
|
|
25
|
+
readonly type: "Instant" | "Duration";
|
|
26
|
+
readonly variant: "milliseconds";
|
|
27
|
+
readonly value: number;
|
|
28
|
+
});
|
|
29
|
+
declare function encodeKaladaValue(value: KaladaValue): EncodedKaladaValueV1;
|
|
30
|
+
declare function decodeKaladaValue(input: unknown): KaladaValue;
|
|
31
|
+
|
|
32
|
+
export { type EncodedKaladaValueV1, decodeKaladaValue, encodeKaladaValue };
|