@bjornpagen/bumbledb 0.4.0 → 0.5.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 +181 -47
- package/README.md +4 -2
- package/dist/closed.d.ts +30 -2
- package/dist/closed.d.ts.map +1 -1
- package/dist/closed.js +66 -20
- package/dist/closed.js.map +1 -1
- package/dist/db.d.ts +33 -6
- package/dist/db.d.ts.map +1 -1
- package/dist/db.js +87 -70
- package/dist/db.js.map +1 -1
- package/dist/exhume.d.ts.map +1 -1
- package/dist/exhume.js +1 -14
- package/dist/exhume.js.map +1 -1
- package/dist/face.d.ts +1 -1
- package/dist/face.d.ts.map +1 -1
- package/dist/face.js +2 -1
- package/dist/face.js.map +1 -1
- package/dist/fields.d.ts +18 -1
- package/dist/fields.d.ts.map +1 -1
- package/dist/fields.js +44 -16
- package/dist/fields.js.map +1 -1
- package/dist/index.d.ts +11 -6
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +8 -4
- package/dist/index.js.map +1 -1
- package/dist/law.d.ts +2 -1
- package/dist/law.d.ts.map +1 -1
- package/dist/law.js +15 -14
- package/dist/law.js.map +1 -1
- package/dist/lower.d.ts.map +1 -1
- package/dist/lower.js +1 -7
- package/dist/lower.js.map +1 -1
- package/dist/marshal.d.ts.map +1 -1
- package/dist/marshal.js +15 -27
- package/dist/marshal.js.map +1 -1
- package/dist/native.d.ts +21 -2
- package/dist/native.d.ts.map +1 -1
- package/dist/native.js +20 -3
- package/dist/native.js.map +1 -1
- package/dist/order.d.ts +36 -0
- package/dist/order.d.ts.map +1 -0
- package/dist/order.js +135 -0
- package/dist/order.js.map +1 -0
- package/dist/query/atom.d.ts +18 -15
- package/dist/query/atom.d.ts.map +1 -1
- package/dist/query/atom.js +9 -16
- package/dist/query/atom.js.map +1 -1
- package/dist/query/lower.d.ts +5 -8
- package/dist/query/lower.d.ts.map +1 -1
- package/dist/query/lower.js +87 -76
- package/dist/query/lower.js.map +1 -1
- package/dist/query/predicate.d.ts.map +1 -1
- package/dist/query/predicate.js +34 -2
- package/dist/query/predicate.js.map +1 -1
- package/dist/query/run.d.ts.map +1 -1
- package/dist/query/run.js +1 -2
- package/dist/query/run.js.map +1 -1
- package/dist/query/scope.d.ts +2 -16
- package/dist/query/scope.d.ts.map +1 -1
- package/dist/query/scope.js +7 -47
- package/dist/query/scope.js.map +1 -1
- package/dist/relation.d.ts +9 -22
- package/dist/relation.d.ts.map +1 -1
- package/dist/relation.js +9 -28
- package/dist/relation.js.map +1 -1
- package/dist/schema.d.ts.map +1 -1
- package/dist/schema.js +7 -31
- package/dist/schema.js.map +1 -1
- package/dist/statements.d.ts +5 -2
- package/dist/statements.d.ts.map +1 -1
- package/dist/statements.js +30 -35
- package/dist/statements.js.map +1 -1
- package/package.json +2 -5
- package/src/closed.ts +73 -28
- package/src/db.ts +122 -84
- package/src/exhume.ts +1 -15
- package/src/face.ts +4 -3
- package/src/fields.ts +58 -16
- package/src/index.ts +10 -8
- package/src/law.ts +15 -14
- package/src/lower.ts +2 -9
- package/src/marshal.ts +15 -31
- package/src/native.ts +22 -4
- package/src/order.ts +156 -0
- package/src/query/atom.ts +13 -21
- package/src/query/lower.ts +90 -91
- package/src/query/predicate.ts +39 -4
- package/src/query/run.ts +1 -3
- package/src/query/scope.ts +7 -59
- package/src/relation.ts +9 -51
- package/src/schema.ts +7 -33
- package/src/statements.ts +33 -38
package/src/relation.ts
CHANGED
|
@@ -2,12 +2,14 @@
|
|
|
2
2
|
* `relation()` — the ordinary-relation half of the theory's signature. A
|
|
3
3
|
* relation value is a frozen plain object carrying its name, its ordered
|
|
4
4
|
* field descriptors (declaration order = ordinal ids, the macro's law),
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
5
|
+
* and — since selections are the relation's own vocabulary — `where()`,
|
|
6
|
+
* which resolves a selection into lowered bindings eagerly (handles
|
|
7
|
+
* verified against their roster at construction). Fields are addressed by
|
|
8
|
+
* NAME everywhere — statements (`on(R, "holder")`), selections, and match
|
|
9
|
+
* records all spell the field's own name, checked by type
|
|
10
|
+
* (`FaceFields`/`MatchShape`). `Fact<>`/`InsertFact<>` are the inferred
|
|
11
|
+
* row object types at BARE structural value types (no brands): fresh
|
|
12
|
+
* fields are optional on insert input (omit-to-mint) and present on read
|
|
11
13
|
* (resupply-to-preserve-identity), typed exactly.
|
|
12
14
|
*/
|
|
13
15
|
|
|
@@ -18,23 +20,6 @@ import { type LiteralSetSpec, type LiteralSpec, renderLiteral } from "#spec.ts"
|
|
|
18
20
|
/** Flattens an intersection into one displayed object type (hover legibility). */
|
|
19
21
|
type Flatten<T> = { [K in keyof T]: T[K] }
|
|
20
22
|
|
|
21
|
-
/**
|
|
22
|
-
* The one trusted seam of `relation()`: the reference record is built by
|
|
23
|
-
* iterating the declared fields, and this guard verifies the checkable
|
|
24
|
-
* facts — one reference per declared field, each carrying its own name —
|
|
25
|
-
* before the record is admitted as the typed {@link FieldRefs} (the
|
|
26
|
-
* macro-emission analog).
|
|
27
|
-
*/
|
|
28
|
-
function refsComplete<RName extends string, Fields extends FieldsShape>(
|
|
29
|
-
refs: Record<string, unknown>,
|
|
30
|
-
fields: Fields
|
|
31
|
-
): refs is FieldRefs<RName, Fields> {
|
|
32
|
-
return Object.keys(fields).every(function hasRef(fieldName) {
|
|
33
|
-
const ref = refs[fieldName]
|
|
34
|
-
return typeof ref === "object" && ref !== null && "field" in ref && ref.field === fieldName
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
|
|
38
23
|
/**
|
|
39
24
|
* Resolves one selection entry to its lowered literal set: a plain ARRAY
|
|
40
25
|
* (detected by `Array.isArray` — no field's value type is an array;
|
|
@@ -117,22 +102,6 @@ function resolveSelection(
|
|
|
117
102
|
/** The field block of a relation: field name to field descriptor. */
|
|
118
103
|
type FieldsShape = Record<string, AnyField>
|
|
119
104
|
|
|
120
|
-
/**
|
|
121
|
-
* A typed field reference (`Account.fields.holder`) — the value statements,
|
|
122
|
-
* selections, and queries address a field through. Purely positional
|
|
123
|
-
* (relation name + field name); the field's descriptor is read off the
|
|
124
|
-
* relation's schema type structurally.
|
|
125
|
-
*/
|
|
126
|
-
interface FieldRef<Rel extends string, Name extends string> {
|
|
127
|
-
readonly relation: Rel
|
|
128
|
-
readonly field: Name
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
/** The typed field-reference record of a relation. */
|
|
132
|
-
type FieldRefs<RName extends string, Fields extends FieldsShape> = {
|
|
133
|
-
readonly [K in keyof Fields & string]: FieldRef<RName, K>
|
|
134
|
-
}
|
|
135
|
-
|
|
136
105
|
/** One declared field: name plus its descriptor, in declaration order. */
|
|
137
106
|
interface RelationField {
|
|
138
107
|
readonly name: string
|
|
@@ -178,7 +147,6 @@ interface Selected<Name extends string, Fields extends FieldsShape> {
|
|
|
178
147
|
interface Relation<Name extends string, Fields extends FieldsShape> {
|
|
179
148
|
readonly name: Name
|
|
180
149
|
readonly data: RelationData
|
|
181
|
-
readonly fields: FieldRefs<Name, Fields>
|
|
182
150
|
where(selection: SelectionInput<Fields>): Selected<Name, Fields>
|
|
183
151
|
}
|
|
184
152
|
|
|
@@ -236,14 +204,6 @@ function relation<const Name extends string, Fields extends FieldsShape>(
|
|
|
236
204
|
ordered.push(Object.freeze({ name: fieldName, field }))
|
|
237
205
|
}
|
|
238
206
|
const data: RelationData = Object.freeze({ name, fields: Object.freeze(ordered) })
|
|
239
|
-
const refs: Record<string, unknown> = {}
|
|
240
|
-
for (const declared of ordered) {
|
|
241
|
-
refs[declared.name] = Object.freeze({ relation: name, field: declared.name })
|
|
242
|
-
}
|
|
243
|
-
Object.freeze(refs)
|
|
244
|
-
if (!refsComplete<Name, Fields>(refs, fields)) {
|
|
245
|
-
throw errors.new(`relation ${name}: field-reference construction incomplete`)
|
|
246
|
-
}
|
|
247
207
|
const holder: { value: Relation<Name, Fields> | undefined } = { value: undefined }
|
|
248
208
|
function where(selection: SelectionInput<Fields>): Selected<Name, Fields> {
|
|
249
209
|
const owner = holder.value
|
|
@@ -255,7 +215,7 @@ function relation<const Name extends string, Fields extends FieldsShape>(
|
|
|
255
215
|
selection: resolveSelection(name, ordered, Object.entries(selection))
|
|
256
216
|
})
|
|
257
217
|
}
|
|
258
|
-
const value: Relation<Name, Fields> = Object.freeze({ name, data,
|
|
218
|
+
const value: Relation<Name, Fields> = Object.freeze({ name, data, where })
|
|
259
219
|
holder.value = value
|
|
260
220
|
return value
|
|
261
221
|
}
|
|
@@ -264,8 +224,6 @@ export type {
|
|
|
264
224
|
AnyRelation,
|
|
265
225
|
AnySelected,
|
|
266
226
|
Fact,
|
|
267
|
-
FieldRef,
|
|
268
|
-
FieldRefs,
|
|
269
227
|
FieldsShape,
|
|
270
228
|
FreshKeys,
|
|
271
229
|
InsertFact,
|
package/src/schema.ts
CHANGED
|
@@ -11,8 +11,9 @@
|
|
|
11
11
|
|
|
12
12
|
import * as errors from "@superbuilders/errors"
|
|
13
13
|
import type { AnyClosed } from "#closed.ts"
|
|
14
|
+
import { isClosedMember, sealedFieldOf } from "#closed.ts"
|
|
14
15
|
import type { FaceData } from "#face.ts"
|
|
15
|
-
import {
|
|
16
|
+
import { assertDeclarationOrderKey, rosterOf } from "#fields.ts"
|
|
16
17
|
import { type ClassesOf, classesComplete, computeClasses, type LawfulStatements, type SchemaClasses } from "#law.ts"
|
|
17
18
|
import type { AnyRelation } from "#relation.ts"
|
|
18
19
|
import type { LiteralSetSpec, LiteralSpec } from "#spec.ts"
|
|
@@ -34,7 +35,7 @@ function collectImplied(name: string, relations: SchemaRelations): Set<string> {
|
|
|
34
35
|
`schema ${name}: record key ${recordKey} holds relation ${member.name} — the key must equal the relation's declared name`
|
|
35
36
|
)
|
|
36
37
|
}
|
|
37
|
-
if (
|
|
38
|
+
if (isClosedMember(member)) {
|
|
38
39
|
implied.add(`${member.name}(id) -> ${member.name}`)
|
|
39
40
|
continue
|
|
40
41
|
}
|
|
@@ -75,33 +76,6 @@ function verifyMembership(name: string, relations: SchemaRelations, statement: S
|
|
|
75
76
|
}
|
|
76
77
|
}
|
|
77
78
|
|
|
78
|
-
/** Finds a face's field descriptor by name, across both relation kinds. */
|
|
79
|
-
function faceField(face: FaceData, fieldName: string): AnyField | undefined {
|
|
80
|
-
const data = face.owner.data
|
|
81
|
-
if ("handles" in data) {
|
|
82
|
-
const column = data.columns.find(function byName(candidate) {
|
|
83
|
-
return candidate.name === fieldName
|
|
84
|
-
})
|
|
85
|
-
return column?.field
|
|
86
|
-
}
|
|
87
|
-
const declared = data.fields.find(function byName(candidate) {
|
|
88
|
-
return candidate.name === fieldName
|
|
89
|
-
})
|
|
90
|
-
return declared?.field
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
/**
|
|
94
|
-
* The roster a field resolves handles through: present exactly on a closed
|
|
95
|
-
* reference descriptor (the structural `closed` property — S1's
|
|
96
|
-
* `ClosedIdField`), absent on every other field kind.
|
|
97
|
-
*/
|
|
98
|
-
function rosterOf(field: AnyField | undefined): ClosedRoster | undefined {
|
|
99
|
-
if (field !== undefined && "closed" in field) {
|
|
100
|
-
return field.closed
|
|
101
|
-
}
|
|
102
|
-
return undefined
|
|
103
|
-
}
|
|
104
|
-
|
|
105
79
|
/** Flattens one binding's literal set into its literals. */
|
|
106
80
|
function bindingLiterals(set: LiteralSetSpec): readonly LiteralSpec[] {
|
|
107
81
|
if (set.kind === "one") {
|
|
@@ -122,7 +96,7 @@ function verifyBindingHandles(
|
|
|
122
96
|
binding: { readonly field: string; readonly set: LiteralSetSpec },
|
|
123
97
|
rendered: string
|
|
124
98
|
): void {
|
|
125
|
-
const roster = rosterOf(
|
|
99
|
+
const roster = rosterOf(sealedFieldOf(face.owner, binding.field))
|
|
126
100
|
for (const literal of bindingLiterals(binding.set)) {
|
|
127
101
|
if (literal.kind !== "handle") {
|
|
128
102
|
continue
|
|
@@ -177,7 +151,7 @@ function closedTargetOf(statements: readonly Statement[], owner: string, field:
|
|
|
177
151
|
source.projection[0] === field &&
|
|
178
152
|
target.projection.length === 1 &&
|
|
179
153
|
target.projection[0] === "id" &&
|
|
180
|
-
|
|
154
|
+
isClosedMember(target.owner)
|
|
181
155
|
) {
|
|
182
156
|
return target.owner.name
|
|
183
157
|
}
|
|
@@ -227,11 +201,11 @@ function verifyClosedReferenceBinding(
|
|
|
227
201
|
if (!spellsHandle) {
|
|
228
202
|
return
|
|
229
203
|
}
|
|
230
|
-
const roster = rosterOf(
|
|
204
|
+
const roster = rosterOf(sealedFieldOf(face.owner, binding.field))
|
|
231
205
|
if (roster === undefined) {
|
|
232
206
|
return
|
|
233
207
|
}
|
|
234
|
-
if (
|
|
208
|
+
if (isClosedMember(face.owner) && binding.field === "id") {
|
|
235
209
|
return
|
|
236
210
|
}
|
|
237
211
|
const resolved = closedTargetOf(statements, face.owner.name, binding.field)
|
package/src/statements.ts
CHANGED
|
@@ -12,8 +12,11 @@
|
|
|
12
12
|
* schema type (the minimal kernel — descriptors are pure structure) and
|
|
13
13
|
* constrained positionwise equal, so a u64 face against a str face, a
|
|
14
14
|
* bytes width mismatch, an interval element mismatch, or a bare column
|
|
15
|
-
* against a closed reference is a compile error.
|
|
16
|
-
* construction-time runtime
|
|
15
|
+
* against a closed reference is a compile error. TWO of those walls carry
|
|
16
|
+
* construction-time runtime twins here for untyped callers: ARITY
|
|
17
|
+
* ({@link assertArityAgreement} — cleanup-0.5.0 ruling 9: an
|
|
18
|
+
* arity-mismatched pairing fails at the statement, never by silent
|
|
19
|
+
* truncation) and the ROSTER slot ({@link assertRosterAgreement} —
|
|
17
20
|
* roster IDENTITY, positionwise: a closed vocabulary's referencing column
|
|
18
21
|
* is spelled with the vocabulary's own id descriptor, the ONE spelling, so
|
|
19
22
|
* a plain u64 column can never alias a vocabulary through a declared law
|
|
@@ -32,9 +35,10 @@
|
|
|
32
35
|
*/
|
|
33
36
|
|
|
34
37
|
import * as errors from "@superbuilders/errors"
|
|
38
|
+
import { isClosedMember, sealedFieldOf } from "#closed.ts"
|
|
35
39
|
import type { Count } from "#count.ts"
|
|
36
40
|
import { type AnyFace, type FaceData, renderFace, type SameArity, type SameShapes } from "#face.ts"
|
|
37
|
-
import
|
|
41
|
+
import { type ClosedRoster, rosterOf } from "#fields.ts"
|
|
38
42
|
import type { AnyRelation, RelationFields } from "#relation.ts"
|
|
39
43
|
import { renderWindow, type WindowSpec } from "#spec.ts"
|
|
40
44
|
|
|
@@ -105,43 +109,28 @@ interface KeyStatement<R extends AnyRelation, Projection extends readonly string
|
|
|
105
109
|
readonly data: KeyData<R, Projection>
|
|
106
110
|
}
|
|
107
111
|
|
|
108
|
-
/**
|
|
109
|
-
* The field descriptor one face position projects: an ordinary relation's
|
|
110
|
-
* declared field; a closed relation's SEALED shape — the synthetic `id`
|
|
111
|
-
* (the value's own roster-carrying descriptor, by identity) or a declared
|
|
112
|
-
* payload column. `undefined` when the name is foreign (the type tier makes
|
|
113
|
-
* that unwritable; the engine re-judges projections at `Db.create`).
|
|
114
|
-
*/
|
|
115
|
-
function projectedFieldOf(face: FaceData, fieldName: string): AnyField | undefined {
|
|
116
|
-
const owner = face.owner
|
|
117
|
-
if ("axioms" in owner) {
|
|
118
|
-
if (fieldName === "id") {
|
|
119
|
-
return owner.id
|
|
120
|
-
}
|
|
121
|
-
const column = owner.data.columns.find(function byName(candidate) {
|
|
122
|
-
return candidate.name === fieldName
|
|
123
|
-
})
|
|
124
|
-
return column?.field
|
|
125
|
-
}
|
|
126
|
-
const declared = owner.data.fields.find(function byName(candidate) {
|
|
127
|
-
return candidate.name === fieldName
|
|
128
|
-
})
|
|
129
|
-
return declared?.field
|
|
130
|
-
}
|
|
131
|
-
|
|
132
|
-
/** The roster a descriptor carries: present exactly on a closed reference, absent on every other kind. */
|
|
133
|
-
function rosterOfField(field: AnyField | undefined): ClosedRoster | undefined {
|
|
134
|
-
if (field !== undefined && "closed" in field) {
|
|
135
|
-
return field.closed
|
|
136
|
-
}
|
|
137
|
-
return undefined
|
|
138
|
-
}
|
|
139
|
-
|
|
140
112
|
/** Renders one face position's closedness for the roster-agreement diagnostics. */
|
|
141
113
|
function renderRosterSide(roster: ClosedRoster | undefined): string {
|
|
142
114
|
return roster === undefined ? "a bare column" : `a ${roster.name} reference`
|
|
143
115
|
}
|
|
144
116
|
|
|
117
|
+
/**
|
|
118
|
+
* The runtime twin of {@link SameArity} (cleanup-0.5.0 ruling 9): the two
|
|
119
|
+
* faces must project equally many fields, judged at CONSTRUCTION for
|
|
120
|
+
* untyped callers too — without it an arity-mismatched containment
|
|
121
|
+
* silently truncates to the shorter projection (this module's positionwise
|
|
122
|
+
* walk and `law.ts`'s `unionSlot` both skip unpaired positions) until
|
|
123
|
+
* `Db.create`'s colder engine refusal. The error carries the two faces'
|
|
124
|
+
* own facts: names, arities, and the rendered statement.
|
|
125
|
+
*/
|
|
126
|
+
function assertArityAgreement(source: FaceData, target: FaceData, statement: Statement): void {
|
|
127
|
+
if (source.projection.length !== target.projection.length) {
|
|
128
|
+
throw errors.new(
|
|
129
|
+
`${source.owner.name}(${source.projection.join(", ")}) and ${target.owner.name}(${target.projection.join(", ")}) project ${source.projection.length} vs ${target.projection.length} fields — positional pairing requires both faces to project equally many — ${renderStatement(statement)}`
|
|
130
|
+
)
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
|
|
145
134
|
/**
|
|
146
135
|
* The runtime twin of {@link SameShapes}'s roster slot: the two faces'
|
|
147
136
|
* projected descriptors must agree POSITIONWISE on closedness — the same
|
|
@@ -154,6 +143,9 @@ function renderRosterSide(roster: ClosedRoster | undefined): string {
|
|
|
154
143
|
* vocabulary's own descriptor (`Kind.id`) is the ONE spelling of a closed
|
|
155
144
|
* reference at this surface (the canonical-utterance law); the engine
|
|
156
145
|
* cannot backstop this one — the wire carries plain u64s, no rosters.
|
|
146
|
+
* Arity agreement ({@link assertArityAgreement}) runs first, so the
|
|
147
|
+
* positionwise walk here never sees an unpaired position from a well-typed
|
|
148
|
+
* OR an untyped caller.
|
|
157
149
|
*/
|
|
158
150
|
function assertRosterAgreement(source: FaceData, target: FaceData, statement: Statement): void {
|
|
159
151
|
source.projection.forEach(function agreeAt(fieldName, position) {
|
|
@@ -161,8 +153,8 @@ function assertRosterAgreement(source: FaceData, target: FaceData, statement: St
|
|
|
161
153
|
if (targetField === undefined) {
|
|
162
154
|
return
|
|
163
155
|
}
|
|
164
|
-
const sourceRoster =
|
|
165
|
-
const targetRoster =
|
|
156
|
+
const sourceRoster = rosterOf(sealedFieldOf(source.owner, fieldName))
|
|
157
|
+
const targetRoster = rosterOf(sealedFieldOf(target.owner, targetField))
|
|
166
158
|
if (sourceRoster !== targetRoster) {
|
|
167
159
|
throw errors.new(
|
|
168
160
|
`${source.owner.name}.${fieldName} is ${renderRosterSide(sourceRoster)} but ${target.owner.name}.${targetField} is ${renderRosterSide(targetRoster)} — closedness rides the descriptor: a closed reference is spelled with the vocabulary's own id descriptor (one meaning, one spelling), so faces pair closed-with-closed through one roster or bare-with-bare, never across — ${renderStatement(statement)}`
|
|
@@ -186,7 +178,7 @@ function key<
|
|
|
186
178
|
R extends AnyRelation,
|
|
187
179
|
const Projection extends readonly [keyof RelationFields<R> & string, ...(keyof RelationFields<R> & string)[]]
|
|
188
180
|
>(relation: R, fields: Projection): KeyStatement<R, Projection> {
|
|
189
|
-
if (
|
|
181
|
+
if (isClosedMember(relation)) {
|
|
190
182
|
throw errors.new(
|
|
191
183
|
`key(${relation.name}, ...): closedness already materializes ${relation.name}(id) -> ${relation.name} — an explicit key on a closed relation is rejected as a duplicate`
|
|
192
184
|
)
|
|
@@ -219,6 +211,7 @@ function contained<A extends AnyFace, B extends AnyFace>(
|
|
|
219
211
|
bidirectional: false
|
|
220
212
|
})
|
|
221
213
|
const statement = Object.freeze({ data })
|
|
214
|
+
assertArityAgreement(data.source, data.target, statement)
|
|
222
215
|
assertRosterAgreement(data.source, data.target, statement)
|
|
223
216
|
return statement
|
|
224
217
|
}
|
|
@@ -243,6 +236,7 @@ function mirrors<A extends AnyFace, B extends AnyFace>(
|
|
|
243
236
|
bidirectional: true
|
|
244
237
|
})
|
|
245
238
|
const statement = Object.freeze({ data })
|
|
239
|
+
assertArityAgreement(data.source, data.target, statement)
|
|
246
240
|
assertRosterAgreement(data.source, data.target, statement)
|
|
247
241
|
return statement
|
|
248
242
|
}
|
|
@@ -269,6 +263,7 @@ function window<B extends AnyFace, A extends AnyFace>(
|
|
|
269
263
|
source: source.data
|
|
270
264
|
})
|
|
271
265
|
const statement = Object.freeze({ data })
|
|
266
|
+
assertArityAgreement(data.source, data.target, statement)
|
|
272
267
|
assertRosterAgreement(data.source, data.target, statement)
|
|
273
268
|
return statement
|
|
274
269
|
}
|