@bjornpagen/bumbledb 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/COOKBOOK.md +1450 -0
- package/README.md +69 -30
- package/dist/closed.d.ts +157 -38
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +232 -47
- package/dist/closed.js.map +1 -1
- package/dist/count.d.ts +64 -17
- package/dist/count.d.ts.map +1 -1
- package/dist/count.js +37 -14
- package/dist/count.js.map +1 -1
- package/dist/db.d.ts +27 -8
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +33 -10
- package/dist/db.js.map +1 -1
- package/dist/exhume.d.ts +12 -11
- package/dist/exhume.d.ts.map +1 -1
- package/dist/exhume.js +7 -6
- package/dist/exhume.js.map +1 -1
- package/dist/face.d.ts +135 -30
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +44 -19
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +130 -130
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +60 -94
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +29 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +19 -14
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +224 -0
- package/dist/law.d.ts.map +1 -0
- package/dist/law.js +224 -0
- package/dist/law.js.map +1 -0
- package/dist/lower.d.ts +17 -7
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +66 -24
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts +36 -21
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +41 -25
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +6 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +2 -2
- package/dist/native.js.map +1 -1
- package/dist/query/atom.d.ts +370 -174
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +75 -172
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts +312 -109
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +906 -387
- package/dist/query/lower.js.map +1 -1
- package/dist/query/predicate.d.ts +70 -88
- package/dist/query/predicate.d.ts.map +1 -1
- package/dist/query/predicate.js +118 -72
- package/dist/query/predicate.js.map +1 -1
- package/dist/query/run.d.ts +19 -16
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +31 -24
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +178 -127
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +111 -108
- package/dist/query/scope.js.map +1 -1
- package/dist/query/select.d.ts +102 -80
- package/dist/query/select.d.ts.map +1 -1
- package/dist/query/select.js +39 -34
- package/dist/query/select.js.map +1 -1
- package/dist/relation.d.ts +48 -38
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +24 -19
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts +41 -3
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +34 -9
- package/dist/schema.js.map +1 -1
- package/dist/spec.d.ts +7 -5
- package/dist/spec.d.ts.map +1 -1
- package/dist/spec.js.map +1 -1
- package/dist/statements.d.ts +91 -36
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +42 -12
- package/dist/statements.js.map +1 -1
- package/package.json +4 -3
- package/src/closed.ts +448 -95
- package/src/count.ts +112 -18
- package/src/db.ts +45 -17
- package/src/exhume.ts +12 -11
- package/src/face.ts +211 -41
- package/src/fields.ts +199 -234
- package/src/index.ts +78 -61
- package/src/law.ts +519 -0
- package/src/lower.ts +82 -27
- package/src/marshal.ts +48 -30
- package/src/native.ts +8 -4
- package/src/query/atom.ts +525 -374
- package/src/query/lower.ts +1469 -538
- package/src/query/predicate.ts +208 -161
- package/src/query/run.ts +35 -25
- package/src/query/scope.ts +264 -218
- package/src/query/select.ts +168 -93
- package/src/relation.ts +47 -47
- package/src/schema.ts +69 -18
- package/src/spec.ts +7 -5
- package/src/statements.ts +124 -41
- package/dist/brand.d.ts +0 -59
- package/dist/brand.d.ts.map +0 -1
- package/dist/brand.js +0 -47
- package/dist/brand.js.map +0 -1
- package/src/brand.ts +0 -82
package/src/fields.ts
CHANGED
|
@@ -1,203 +1,211 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Field
|
|
3
|
-
* (`docs/architecture/70-api.md`): `bool`, `u64`, `i64`,
|
|
4
|
-
* `interval(u64|i64[, width])`, each a plain frozen value
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* `.fresh` exists only on
|
|
14
|
-
*
|
|
15
|
-
*
|
|
2
|
+
* Field descriptors — the value half of the `schema!` field grammar
|
|
3
|
+
* (`docs/architecture/70-api.md`), MINIMAL edition: `bool`, `u64`, `i64`,
|
|
4
|
+
* `str`, `bytes(n)`, `interval(u64|i64[, width])`, each a plain frozen value
|
|
5
|
+
* that IS its own descriptor type — `{ kind, width?, element?, fresh? }` —
|
|
6
|
+
* honest at runtime and in the type alike. A field's VALUE type is its bare
|
|
7
|
+
* structural type (`u64` → `bigint`, `str` → `string`, `bytes(n)` →
|
|
8
|
+
* `Uint8Array`, intervals → `{ start, end }`): no brands, no phantoms, no
|
|
9
|
+
* minting casts. A descriptor carries STRUCTURE ONLY — domains are never
|
|
10
|
+
* declared anywhere (the owner ruling: THE LAWS TYPE THE COLUMNS): a
|
|
11
|
+
* field's domain is COMPUTED by `schema()` from the statement list, where
|
|
12
|
+
* the dependencies themselves induce the equivalence classes. The macro's
|
|
13
|
+
* refusals are reproduced representationally: `.fresh` exists only on u64,
|
|
14
|
+
* and no field-level constraint vocabulary of any kind exists —
|
|
15
|
+
* `unique`/`fk` are unwritable, not rejected.
|
|
16
16
|
*/
|
|
17
17
|
|
|
18
18
|
import * as errors from "@superbuilders/errors"
|
|
19
|
-
import type {
|
|
20
|
-
import { phantom } from "#brand.ts"
|
|
21
|
-
import type { LiteralSpec, ValueTypeSpec } from "#spec.ts"
|
|
19
|
+
import type { LiteralSpec } from "#spec.ts"
|
|
22
20
|
|
|
23
21
|
/**
|
|
24
|
-
*
|
|
25
|
-
*
|
|
22
|
+
* A half-open interval `[start, end)` as a plain value object — the ONE
|
|
23
|
+
* interval value type, whatever the field's element type or width label.
|
|
24
|
+
* The ray is representable (`end` = the element type's MAX_END); widths
|
|
25
|
+
* and signedness are NOT modeled on the value — they are descriptor-type
|
|
26
|
+
* labels the engine judges at the typed write boundary. Interval fields
|
|
27
|
+
* derive no order (the Rust refusal, `docs/architecture/10-data-model.md`),
|
|
28
|
+
* so no comparators exist on the value type.
|
|
26
29
|
*/
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
/** Narrows an interval literal: a plain object with bigint start/end. */
|
|
32
|
-
function isIntervalLiteral(value: unknown): value is IntervalValue {
|
|
33
|
-
return (
|
|
34
|
-
typeof value === "object" &&
|
|
35
|
-
value !== null &&
|
|
36
|
-
"start" in value &&
|
|
37
|
-
"end" in value &&
|
|
38
|
-
typeof value.start === "bigint" &&
|
|
39
|
-
typeof value.end === "bigint"
|
|
40
|
-
)
|
|
30
|
+
interface IntervalValue {
|
|
31
|
+
readonly start: bigint
|
|
32
|
+
readonly end: bigint
|
|
41
33
|
}
|
|
42
34
|
|
|
43
35
|
/**
|
|
44
|
-
*
|
|
45
|
-
*
|
|
46
|
-
*
|
|
47
|
-
*
|
|
36
|
+
* Constructs an interval literal — the `start..end` spelling. Half-open
|
|
37
|
+
* and nonempty by construction: `start >= end` is a typed construction
|
|
38
|
+
* error (parse, don't validate — the same invariant Rust's
|
|
39
|
+
* `Interval::new` enforces at the host boundary). The value is bare and
|
|
40
|
+
* structural: it is assignable to any interval field.
|
|
48
41
|
*/
|
|
49
|
-
function
|
|
50
|
-
if (
|
|
51
|
-
throw
|
|
42
|
+
function span(start: bigint, end: bigint): IntervalValue {
|
|
43
|
+
if (start >= end) {
|
|
44
|
+
throw errors.new(`interval is half-open and nonempty: start must be < end (got ${start}..${end})`)
|
|
52
45
|
}
|
|
53
|
-
|
|
54
|
-
if (handle === undefined) {
|
|
55
|
-
throw errors.new(
|
|
56
|
-
`closed relation ${closed.name} has no handle with id ${value} (roster holds ${closed.handles.length})`
|
|
57
|
-
)
|
|
58
|
-
}
|
|
59
|
-
return { kind: "handle", handle }
|
|
60
|
-
}
|
|
61
|
-
|
|
62
|
-
/** Lowers one interval literal at its element type. */
|
|
63
|
-
function intervalLiteral(element: "u64" | "i64", value: unknown): LiteralSpec {
|
|
64
|
-
if (!isIntervalLiteral(value)) {
|
|
65
|
-
throw literalShapeError("interval ({ start, end } bigints)", value)
|
|
66
|
-
}
|
|
67
|
-
if (element === "u64") {
|
|
68
|
-
return { kind: "value", value: { kind: "intervalU64", start: value.start, end: value.end } }
|
|
69
|
-
}
|
|
70
|
-
return { kind: "value", value: { kind: "intervalI64", start: value.start, end: value.end } }
|
|
46
|
+
return Object.freeze({ start, end })
|
|
71
47
|
}
|
|
72
48
|
|
|
73
49
|
/**
|
|
74
50
|
* A closed relation's roster as seen from a referencing field: the handle
|
|
75
|
-
* namespace `where()` selections and ground axioms resolve bare
|
|
76
|
-
* through (the macro's own rule: a handle is legal exactly on a field
|
|
77
|
-
*
|
|
51
|
+
* namespace `where()` selections and ground axioms resolve bare handle ids
|
|
52
|
+
* through (the macro's own rule: a handle is legal exactly on a field that
|
|
53
|
+
* references a closed relation).
|
|
78
54
|
*/
|
|
79
55
|
interface ClosedRoster {
|
|
80
56
|
readonly name: string
|
|
81
57
|
readonly handles: readonly string[]
|
|
82
58
|
}
|
|
83
59
|
|
|
84
|
-
/**
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
*/
|
|
90
|
-
interface
|
|
91
|
-
readonly
|
|
92
|
-
readonly newtype: string | undefined
|
|
93
|
-
readonly minted: Minted
|
|
94
|
-
readonly closed: ClosedRoster | undefined
|
|
60
|
+
/** The `bool` field descriptor: value type `boolean`. No `.fresh` (macro parity). */
|
|
61
|
+
interface BoolField {
|
|
62
|
+
readonly kind: "bool"
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
/** The `str` field descriptor: value type `string`. No `.fresh` (macro parity). */
|
|
66
|
+
interface StrField {
|
|
67
|
+
readonly kind: "str"
|
|
95
68
|
}
|
|
96
69
|
|
|
97
70
|
/**
|
|
98
|
-
*
|
|
99
|
-
*
|
|
71
|
+
* A `fresh`-marked u64 field descriptor — `id: u64.fresh`. The mark is a
|
|
72
|
+
* structural label (`fresh: true`) in the descriptor type AND on the
|
|
73
|
+
* runtime value; it implies the key `R(field) -> R`, which the ENGINE
|
|
74
|
+
* materializes (`SchemaDescriptor::materialized_statements`), and it makes
|
|
75
|
+
* the field a GENERATOR — `schema()` names its equivalence class by the
|
|
76
|
+
* declaration coordinate (`"Account.id"`). Terminal: no builder property
|
|
77
|
+
* survives the mark.
|
|
100
78
|
*/
|
|
101
|
-
interface
|
|
102
|
-
readonly
|
|
103
|
-
readonly
|
|
79
|
+
interface FreshU64Field {
|
|
80
|
+
readonly kind: "u64"
|
|
81
|
+
readonly fresh: true
|
|
104
82
|
}
|
|
105
83
|
|
|
106
|
-
/**
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
readonly
|
|
84
|
+
/**
|
|
85
|
+
* The `u64` field descriptor. `.fresh` marks the field as engine-minted —
|
|
86
|
+
* the property doubles as the mark itself: on an unmarked descriptor it
|
|
87
|
+
* holds the marked descriptor, on a marked one it IS the literal `true`
|
|
88
|
+
* (one structural property, read either way).
|
|
89
|
+
*/
|
|
90
|
+
interface U64Field {
|
|
91
|
+
readonly kind: "u64"
|
|
92
|
+
readonly fresh: FreshU64Field
|
|
115
93
|
}
|
|
116
94
|
|
|
117
|
-
/** The `
|
|
118
|
-
interface
|
|
119
|
-
readonly
|
|
95
|
+
/** The `i64` field descriptor. Terminal: `.fresh` is legal on u64 only. */
|
|
96
|
+
interface I64Field {
|
|
97
|
+
readonly kind: "i64"
|
|
120
98
|
}
|
|
121
99
|
|
|
122
100
|
/**
|
|
123
|
-
* A `
|
|
124
|
-
*
|
|
125
|
-
* `
|
|
126
|
-
*
|
|
127
|
-
* explicit duplicate of it (macro parity).
|
|
101
|
+
* A `bytes<N>` field descriptor. The width is a descriptor-type label
|
|
102
|
+
* (load-bearing: the engine enforces it at the write boundary) and the
|
|
103
|
+
* value type is bare `Uint8Array`. No order is derived — no comparators
|
|
104
|
+
* exist on the value type (the engine refuses order on bytes).
|
|
128
105
|
*/
|
|
129
|
-
interface
|
|
130
|
-
readonly
|
|
106
|
+
interface BytesField<Width extends number = number> {
|
|
107
|
+
readonly kind: "bytes"
|
|
108
|
+
readonly width: Width
|
|
131
109
|
}
|
|
132
110
|
|
|
133
111
|
/**
|
|
134
|
-
*
|
|
135
|
-
*
|
|
136
|
-
*
|
|
137
|
-
*
|
|
138
|
-
* fields, so bare-u64 fresh is unwritable).
|
|
112
|
+
* An interval field descriptor — `interval(i64)` general (rays
|
|
113
|
+
* representable), `interval(u64, w)` the fixed-width family. Element and
|
|
114
|
+
* width are descriptor-type labels; the value type is always the bare
|
|
115
|
+
* {@link IntervalValue}.
|
|
139
116
|
*/
|
|
140
|
-
interface
|
|
141
|
-
|
|
142
|
-
|
|
117
|
+
interface IntervalField<
|
|
118
|
+
Element extends "u64" | "i64" = "u64" | "i64",
|
|
119
|
+
Width extends bigint | undefined = bigint | undefined
|
|
120
|
+
> {
|
|
121
|
+
readonly kind: "interval"
|
|
122
|
+
readonly element: Element
|
|
123
|
+
readonly width: Width
|
|
143
124
|
}
|
|
144
125
|
|
|
145
|
-
/**
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
interface
|
|
153
|
-
readonly
|
|
126
|
+
/**
|
|
127
|
+
* A closed relation's reference field descriptor (`Kind.id`) — a u64
|
|
128
|
+
* descriptor carrying the closed linkage: the roster resolves bare handle
|
|
129
|
+
* ids in selections and ground axioms, and `schema()` names the id's
|
|
130
|
+
* generator class `"Kind.id"`. Terminal: no `.fresh` — a vocabulary's rows
|
|
131
|
+
* are ground axioms, never minted.
|
|
132
|
+
*/
|
|
133
|
+
interface ClosedIdField {
|
|
134
|
+
readonly kind: "u64"
|
|
135
|
+
readonly closed: ClosedRoster
|
|
154
136
|
}
|
|
155
137
|
|
|
156
|
-
/**
|
|
157
|
-
|
|
158
|
-
readonly data: FieldData<false>
|
|
159
|
-
newtype<const Name extends string>(name: Name): I64Newtype<Name>
|
|
160
|
-
}
|
|
138
|
+
/** Any field descriptor, whatever its kind or marks. */
|
|
139
|
+
type AnyField = BoolField | StrField | U64Field | FreshU64Field | I64Field | BytesField | IntervalField | ClosedIdField
|
|
161
140
|
|
|
162
|
-
/**
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
141
|
+
/**
|
|
142
|
+
* The bare structural VALUE type of a field descriptor — the one total
|
|
143
|
+
* definition every fact, result row, and query term reads: `bool` →
|
|
144
|
+
* `boolean`, `str` → `string`, `u64`/`i64` → `bigint`, `bytes<N>` →
|
|
145
|
+
* `Uint8Array`, intervals → {@link IntervalValue}.
|
|
146
|
+
*/
|
|
147
|
+
type Infer<F extends AnyField> = F extends { readonly kind: "bool" }
|
|
148
|
+
? boolean
|
|
149
|
+
: F extends { readonly kind: "str" }
|
|
150
|
+
? string
|
|
151
|
+
: F extends { readonly kind: "u64" }
|
|
152
|
+
? bigint
|
|
153
|
+
: F extends { readonly kind: "i64" }
|
|
154
|
+
? bigint
|
|
155
|
+
: F extends { readonly kind: "bytes" }
|
|
156
|
+
? Uint8Array
|
|
157
|
+
: F extends { readonly kind: "interval" }
|
|
158
|
+
? IntervalValue
|
|
159
|
+
: never
|
|
172
160
|
|
|
173
|
-
/**
|
|
174
|
-
|
|
175
|
-
|
|
161
|
+
/**
|
|
162
|
+
* The typed shape refusal of the selection-literal machine — reached only
|
|
163
|
+
* through ill-typed input (the well-typed surfaces make it unrepresentable).
|
|
164
|
+
*/
|
|
165
|
+
function literalShapeError(expected: string, value: unknown): Error {
|
|
166
|
+
return errors.new(`selection literal shape mismatch: expected ${expected}, got ${typeof value}`)
|
|
176
167
|
}
|
|
177
168
|
|
|
178
|
-
/**
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
169
|
+
/** Narrows an interval literal: a plain object with bigint start/end. */
|
|
170
|
+
function isIntervalLiteral(value: unknown): value is IntervalValue {
|
|
171
|
+
return (
|
|
172
|
+
typeof value === "object" &&
|
|
173
|
+
value !== null &&
|
|
174
|
+
"start" in value &&
|
|
175
|
+
"end" in value &&
|
|
176
|
+
typeof value.start === "bigint" &&
|
|
177
|
+
typeof value.end === "bigint"
|
|
178
|
+
)
|
|
182
179
|
}
|
|
183
180
|
|
|
184
181
|
/**
|
|
185
|
-
*
|
|
186
|
-
*
|
|
187
|
-
*
|
|
188
|
-
*
|
|
189
|
-
* `id` field infers its handle brand the same way).
|
|
182
|
+
* Resolves one closed-handle literal: the handle id (a bare bigint) back to
|
|
183
|
+
* its handle NAME through the roster — an out-of-roster id is a
|
|
184
|
+
* construction error, the belt the type level deliberately does not provide
|
|
185
|
+
* (structural values make any bigint spellable here; the roster judges).
|
|
190
186
|
*/
|
|
191
|
-
|
|
187
|
+
function handleLiteral(closed: ClosedRoster, value: unknown): LiteralSpec {
|
|
188
|
+
if (typeof value !== "bigint") {
|
|
189
|
+
throw literalShapeError(`a ${closed.name} handle id (bigint)`, value)
|
|
190
|
+
}
|
|
191
|
+
const handle = closed.handles[Number(value)]
|
|
192
|
+
if (handle === undefined) {
|
|
193
|
+
throw errors.new(
|
|
194
|
+
`closed relation ${closed.name} has no handle with id ${value} (roster holds ${closed.handles.length})`
|
|
195
|
+
)
|
|
196
|
+
}
|
|
197
|
+
return { kind: "handle", handle }
|
|
198
|
+
}
|
|
192
199
|
|
|
193
|
-
/**
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
200
|
+
/** Lowers one interval literal at its element type. */
|
|
201
|
+
function intervalLiteral(element: "u64" | "i64", value: unknown): LiteralSpec {
|
|
202
|
+
if (!isIntervalLiteral(value)) {
|
|
203
|
+
throw literalShapeError("interval ({ start, end } bigints)", value)
|
|
204
|
+
}
|
|
205
|
+
if (element === "u64") {
|
|
206
|
+
return { kind: "value", value: { kind: "intervalU64", start: value.start, end: value.end } }
|
|
207
|
+
}
|
|
208
|
+
return { kind: "value", value: { kind: "intervalI64", start: value.start, end: value.end } }
|
|
201
209
|
}
|
|
202
210
|
|
|
203
211
|
/**
|
|
@@ -218,84 +226,53 @@ function assertDeclarationOrderKey(where: string, name: string): void {
|
|
|
218
226
|
}
|
|
219
227
|
}
|
|
220
228
|
|
|
221
|
-
/**
|
|
222
|
-
|
|
223
|
-
* constructors here and by `closed()` (which mints {@link ClosedIdField}
|
|
224
|
-
* values against its own roster).
|
|
225
|
-
*/
|
|
226
|
-
function fieldData<Minted extends boolean>(
|
|
227
|
-
type: ValueTypeSpec,
|
|
228
|
-
newtype: string | undefined,
|
|
229
|
-
minted: Minted,
|
|
230
|
-
closed: ClosedRoster | undefined
|
|
231
|
-
): FieldData<Minted> {
|
|
232
|
-
return Object.freeze({ type: Object.freeze(type), newtype, minted, closed })
|
|
233
|
-
}
|
|
229
|
+
/** The one fresh-marked u64 descriptor (the `.fresh` property of the unmarked one). */
|
|
230
|
+
const freshU64: FreshU64Field = Object.freeze({ kind: "u64", fresh: true })
|
|
234
231
|
|
|
235
|
-
/** The one `u64`
|
|
236
|
-
const u64: U64Field = Object.freeze({
|
|
237
|
-
data: fieldData({ kind: "u64" }, undefined, false, undefined),
|
|
238
|
-
newtype<const Name extends string>(name: Name): U64Newtype<Name> {
|
|
239
|
-
const fresh: FreshU64Newtype<Name> = Object.freeze({
|
|
240
|
-
data: fieldData({ kind: "u64" }, name, true, undefined)
|
|
241
|
-
})
|
|
242
|
-
return Object.freeze({
|
|
243
|
-
data: fieldData({ kind: "u64" }, name, false, undefined),
|
|
244
|
-
fresh
|
|
245
|
-
})
|
|
246
|
-
}
|
|
247
|
-
})
|
|
232
|
+
/** The one `u64` constructor value. */
|
|
233
|
+
const u64: U64Field = Object.freeze({ kind: "u64", fresh: freshU64 })
|
|
248
234
|
|
|
249
|
-
/** The one `i64`
|
|
250
|
-
const i64: I64Field = Object.freeze({
|
|
251
|
-
data: fieldData({ kind: "i64" }, undefined, false, undefined),
|
|
252
|
-
newtype<const Name extends string>(name: Name): I64Newtype<Name> {
|
|
253
|
-
return Object.freeze({ data: fieldData({ kind: "i64" }, name, false, undefined) })
|
|
254
|
-
}
|
|
255
|
-
})
|
|
235
|
+
/** The one `i64` constructor value. */
|
|
236
|
+
const i64: I64Field = Object.freeze({ kind: "i64" })
|
|
256
237
|
|
|
257
|
-
/** The one `bool`
|
|
258
|
-
const bool: BoolField = Object.freeze({
|
|
259
|
-
data: fieldData({ kind: "bool" }, undefined, false, undefined)
|
|
260
|
-
})
|
|
238
|
+
/** The one `bool` constructor value. */
|
|
239
|
+
const bool: BoolField = Object.freeze({ kind: "bool" })
|
|
261
240
|
|
|
262
|
-
/** The one `str`
|
|
263
|
-
const str: StrField = Object.freeze({
|
|
264
|
-
data: fieldData({ kind: "string" }, undefined, false, undefined)
|
|
265
|
-
})
|
|
241
|
+
/** The one `str` constructor value. */
|
|
242
|
+
const str: StrField = Object.freeze({ kind: "str" })
|
|
266
243
|
|
|
267
244
|
/**
|
|
268
|
-
* The `bytes<N>` field constructor. The width is mandatory and
|
|
269
|
-
* type; `
|
|
270
|
-
* range at declaration (`docs/architecture/70-api.md`
|
|
271
|
-
* grammar: N ∈ 1..=64 — bare `bytes` does not parse), the
|
|
272
|
-
* boundary's analog being construction.
|
|
245
|
+
* The `bytes<N>` field constructor. The width is mandatory and a
|
|
246
|
+
* descriptor-type label; `width` is validated to 1..=64 here because the
|
|
247
|
+
* grammar pins that range at declaration (`docs/architecture/70-api.md`
|
|
248
|
+
* § the `schema!` grammar: N ∈ 1..=64 — bare `bytes` does not parse), the
|
|
249
|
+
* macro-expansion boundary's analog being construction.
|
|
273
250
|
*/
|
|
274
|
-
function bytes(
|
|
275
|
-
if (!Number.isInteger(
|
|
251
|
+
function bytes<const Width extends number>(width: Width): BytesField<Width> {
|
|
252
|
+
if (!Number.isInteger(width) || width < 1 || width > 64) {
|
|
276
253
|
throw errors.new(
|
|
277
|
-
`bytes width must be an integer in 1..=64 (got ${
|
|
254
|
+
`bytes width must be an integer in 1..=64 (got ${width}) — docs/architecture/70-api.md pins the range at declaration`
|
|
278
255
|
)
|
|
279
256
|
}
|
|
280
|
-
return Object.freeze({
|
|
281
|
-
data: fieldData({ kind: "fixedBytes", len }, undefined, false, undefined),
|
|
282
|
-
newtype<const Name extends string>(name: Name): BytesNewtype<Name> {
|
|
283
|
-
return Object.freeze({ data: fieldData({ kind: "fixedBytes", len }, name, false, undefined) })
|
|
284
|
-
}
|
|
285
|
-
})
|
|
257
|
+
return Object.freeze({ kind: "bytes", width })
|
|
286
258
|
}
|
|
287
259
|
|
|
288
260
|
/**
|
|
289
261
|
* The interval field constructor — `interval(u64)` / `interval(i64)` for
|
|
290
262
|
* the general type (rays representable), `interval(u64, w)` for the
|
|
291
|
-
* fixed-width family whose width IS
|
|
292
|
-
* the u64/i64
|
|
293
|
-
* >= 1` is validated here because the grammar pins it at declaration
|
|
263
|
+
* fixed-width family whose width IS a descriptor-type label. The element is
|
|
264
|
+
* spelled with the u64/i64 constructor values themselves, never a string.
|
|
265
|
+
* `width >= 1` is validated here because the grammar pins it at declaration
|
|
294
266
|
* (`docs/architecture/70-api.md`: w ≥ 1; `interval<u64, 0>` is an
|
|
295
267
|
* expansion error naming the field).
|
|
296
268
|
*/
|
|
297
|
-
function interval
|
|
298
|
-
|
|
269
|
+
function interval<Element extends U64Field | I64Field>(element: Element): IntervalField<Element["kind"], undefined>
|
|
270
|
+
function interval<Element extends U64Field | I64Field, const Width extends bigint>(
|
|
271
|
+
element: Element,
|
|
272
|
+
width: Width
|
|
273
|
+
): IntervalField<Element["kind"], Width>
|
|
274
|
+
function interval(element: U64Field | I64Field, width?: bigint): IntervalField<"u64" | "i64", bigint | undefined> {
|
|
275
|
+
const elementKind = element.kind
|
|
299
276
|
if (elementKind !== "u64" && elementKind !== "i64") {
|
|
300
277
|
throw errors.new(`interval element must be the u64 or i64 field constructor (got ${elementKind})`)
|
|
301
278
|
}
|
|
@@ -304,13 +281,7 @@ function interval(element: U64Field | I64Field, width?: bigint): IntervalField {
|
|
|
304
281
|
`interval width must be >= 1 (got ${width}) — docs/architecture/70-api.md pins w >= 1 at declaration`
|
|
305
282
|
)
|
|
306
283
|
}
|
|
307
|
-
|
|
308
|
-
return Object.freeze({
|
|
309
|
-
data: fieldData(type, undefined, false, undefined),
|
|
310
|
-
newtype<const Name extends string>(name: Name): IntervalNewtype<Name> {
|
|
311
|
-
return Object.freeze({ data: fieldData(type, name, false, undefined) })
|
|
312
|
-
}
|
|
313
|
-
})
|
|
284
|
+
return Object.freeze({ kind: "interval", element: elementKind, width })
|
|
314
285
|
}
|
|
315
286
|
|
|
316
287
|
/**
|
|
@@ -318,15 +289,15 @@ function interval(element: U64Field | I64Field, width?: bigint): IntervalField {
|
|
|
318
289
|
* {@link LiteralSpec} — the selection-literal machine ground axioms and
|
|
319
290
|
* `where()` bindings both ride (one machine, same errors — the macro's own
|
|
320
291
|
* rule). A value on a closed-reference field resolves to its handle NAME
|
|
321
|
-
* (the id is
|
|
292
|
+
* (the id is verified against the roster: an out-of-roster id is a
|
|
322
293
|
* construction error); everything else lowers to a plain value tagged by
|
|
323
|
-
* the field's structural
|
|
294
|
+
* the field's structural kind.
|
|
324
295
|
*/
|
|
325
|
-
function literalOf(field:
|
|
326
|
-
if (
|
|
296
|
+
function literalOf(field: AnyField, value: unknown): LiteralSpec {
|
|
297
|
+
if ("closed" in field) {
|
|
327
298
|
return handleLiteral(field.closed, value)
|
|
328
299
|
}
|
|
329
|
-
switch (field.
|
|
300
|
+
switch (field.kind) {
|
|
330
301
|
case "bool": {
|
|
331
302
|
if (typeof value !== "boolean") {
|
|
332
303
|
throw literalShapeError("boolean", value)
|
|
@@ -345,20 +316,20 @@ function literalOf(field: FieldData, value: unknown): LiteralSpec {
|
|
|
345
316
|
}
|
|
346
317
|
return { kind: "value", value: { kind: "i64", value } }
|
|
347
318
|
}
|
|
348
|
-
case "
|
|
319
|
+
case "str": {
|
|
349
320
|
if (typeof value !== "string") {
|
|
350
321
|
throw literalShapeError("string", value)
|
|
351
322
|
}
|
|
352
323
|
return { kind: "value", value: { kind: "string", value } }
|
|
353
324
|
}
|
|
354
|
-
case "
|
|
325
|
+
case "bytes": {
|
|
355
326
|
if (!(value instanceof Uint8Array)) {
|
|
356
327
|
throw literalShapeError("Uint8Array", value)
|
|
357
328
|
}
|
|
358
329
|
return { kind: "value", value: { kind: "fixedBytes", value } }
|
|
359
330
|
}
|
|
360
331
|
case "interval":
|
|
361
|
-
return intervalLiteral(field.
|
|
332
|
+
return intervalLiteral(field.element, value)
|
|
362
333
|
}
|
|
363
334
|
}
|
|
364
335
|
|
|
@@ -366,20 +337,14 @@ export type {
|
|
|
366
337
|
AnyField,
|
|
367
338
|
BoolField,
|
|
368
339
|
BytesField,
|
|
369
|
-
BytesNewtype,
|
|
370
340
|
ClosedIdField,
|
|
371
341
|
ClosedRoster,
|
|
372
|
-
|
|
373
|
-
FieldData,
|
|
374
|
-
FieldValue,
|
|
375
|
-
FreshU64Newtype,
|
|
342
|
+
FreshU64Field,
|
|
376
343
|
I64Field,
|
|
377
|
-
I64Newtype,
|
|
378
344
|
Infer,
|
|
379
345
|
IntervalField,
|
|
380
|
-
|
|
346
|
+
IntervalValue,
|
|
381
347
|
StrField,
|
|
382
|
-
U64Field
|
|
383
|
-
U64Newtype
|
|
348
|
+
U64Field
|
|
384
349
|
}
|
|
385
|
-
export { assertDeclarationOrderKey, bool, bytes,
|
|
350
|
+
export { assertDeclarationOrderKey, bool, bytes, i64, interval, literalOf, span, str, u64 }
|