@bjornpagen/bumbledb 0.7.0 → 0.9.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.
Files changed (68) hide show
  1. package/COOKBOOK.md +105 -3
  2. package/README.md +3 -3
  3. package/dist/capacity.d.ts +310 -0
  4. package/dist/capacity.d.ts.map +1 -0
  5. package/dist/capacity.js +138 -0
  6. package/dist/capacity.js.map +1 -0
  7. package/dist/db.d.ts +5 -3
  8. package/dist/db.d.ts.map +1 -1
  9. package/dist/db.js +8 -8
  10. package/dist/db.js.map +1 -1
  11. package/dist/face.d.ts +1 -1
  12. package/dist/face.d.ts.map +1 -1
  13. package/dist/face.js.map +1 -1
  14. package/dist/index.d.ts +8 -8
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +3 -3
  17. package/dist/index.js.map +1 -1
  18. package/dist/law.d.ts +3 -2
  19. package/dist/law.d.ts.map +1 -1
  20. package/dist/law.js +1 -1
  21. package/dist/law.js.map +1 -1
  22. package/dist/lower.d.ts.map +1 -1
  23. package/dist/lower.js +3 -2
  24. package/dist/lower.js.map +1 -1
  25. package/dist/native.d.ts +6 -3
  26. package/dist/native.d.ts.map +1 -1
  27. package/dist/native.js.map +1 -1
  28. package/dist/order.d.ts +53 -2
  29. package/dist/order.d.ts.map +1 -1
  30. package/dist/order.js +30 -12
  31. package/dist/order.js.map +1 -1
  32. package/dist/query/atom.d.ts +33 -13
  33. package/dist/query/atom.d.ts.map +1 -1
  34. package/dist/query/atom.js +1 -1
  35. package/dist/query/atom.js.map +1 -1
  36. package/dist/query/find.d.ts +19 -8
  37. package/dist/query/find.d.ts.map +1 -1
  38. package/dist/query/find.js +6 -5
  39. package/dist/query/find.js.map +1 -1
  40. package/dist/schema.js +1 -1
  41. package/dist/schema.js.map +1 -1
  42. package/dist/spec.d.ts +76 -23
  43. package/dist/spec.d.ts.map +1 -1
  44. package/dist/spec.js +39 -7
  45. package/dist/spec.js.map +1 -1
  46. package/dist/statements.d.ts +42 -25
  47. package/dist/statements.d.ts.map +1 -1
  48. package/dist/statements.js +81 -19
  49. package/dist/statements.js.map +1 -1
  50. package/package.json +4 -4
  51. package/src/capacity.ts +454 -0
  52. package/src/db.ts +13 -11
  53. package/src/face.ts +1 -0
  54. package/src/index.ts +20 -9
  55. package/src/law.ts +3 -2
  56. package/src/lower.ts +3 -2
  57. package/src/native.ts +6 -3
  58. package/src/order.ts +83 -5
  59. package/src/query/atom.ts +37 -13
  60. package/src/query/find.ts +34 -16
  61. package/src/schema.ts +1 -1
  62. package/src/spec.ts +91 -25
  63. package/src/statements.ts +160 -34
  64. package/dist/count.d.ts +0 -102
  65. package/dist/count.d.ts.map +0 -1
  66. package/dist/count.js +0 -115
  67. package/dist/count.js.map +0 -1
  68. package/src/count.ts +0 -211
package/src/statements.ts CHANGED
@@ -2,7 +2,7 @@
2
2
  * Dependency statements as typed values (`docs/architecture/30-dependencies.md`
3
3
  * owns the semantics; `docs/architecture/70-api.md` the surface): the FD key
4
4
  * form, conditional containment, the bidirectional `==` abbreviation, and
5
- * the cardinality window. A statement value is opaque and inert — no
5
+ * the capacity statement. A statement value is opaque and inert — no
6
6
  * methods, no fluent continuation: a fact about the theory, not a builder.
7
7
  *
8
8
  * Every field reference is checked against the relation it names in the
@@ -35,12 +35,21 @@
35
35
  */
36
36
 
37
37
  import * as errors from "@superbuilders/errors"
38
+ import {
39
+ type BoundsOnTarget,
40
+ type CapacityWeight,
41
+ type CapacityWindow,
42
+ isCapacityWeight,
43
+ isCapacityWindow,
44
+ type UnitWindowBan,
45
+ unitWeight,
46
+ type WeightOnSource
47
+ } from "#capacity.ts"
38
48
  import { isClosedMember, sealedFieldOf } from "#closed.ts"
39
- import type { Count } from "#count.ts"
40
49
  import { type AnyFace, type FaceData, renderFace, type SameArity, type SameShapes } from "#face.ts"
41
50
  import { type ClosedRoster, rosterOf } from "#fields.ts"
42
51
  import type { AnyRelation, RelationFields } from "#relation.ts"
43
- import { renderWindow, type WindowSpec } from "#spec.ts"
52
+ import { type CapacityWindowSpec, renderCapacityWindow, renderWeight, type WeightSpec } from "#spec.ts"
44
53
 
45
54
  /** A `key()` statement's runtime description — owner and projection carried at exact types. */
46
55
  interface KeyData<R extends AnyRelation, Projection extends readonly string[]> {
@@ -63,20 +72,26 @@ interface ContainmentData<Src extends FaceData = FaceData, Tgt extends FaceData
63
72
  readonly bidirectional: boolean
64
73
  }
65
74
 
66
- /** A window statement's runtime description — target-left, faces at exact types like {@link ContainmentData}. */
67
- interface WindowData<Tgt extends FaceData = FaceData, Src extends FaceData = FaceData> {
68
- readonly kind: "window"
75
+ /**
76
+ * A capacity statement's runtime description target-left, in the
77
+ * operator's own order (C2: target, weight, window, source), faces at
78
+ * exact types like {@link ContainmentData}. The weight is ALWAYS present
79
+ * (C4 — `unit` is a case, not an absence).
80
+ */
81
+ interface CapacityData<Tgt extends FaceData = FaceData, Src extends FaceData = FaceData> {
82
+ readonly kind: "capacity"
69
83
  readonly target: Tgt
70
- readonly window: WindowSpec
84
+ readonly weight: WeightSpec
85
+ readonly window: CapacityWindowSpec
71
86
  readonly source: Src
72
87
  }
73
88
 
74
89
  /** One statement's runtime description, tagged by form. */
75
- type StatementData = KeyData<AnyRelation, readonly string[]> | ContainmentData | WindowData
90
+ type StatementData = KeyData<AnyRelation, readonly string[]> | ContainmentData | CapacityData
76
91
 
77
92
  /**
78
93
  * The admission brand — a module-private symbol, deliberately unexported
79
- * (the `count.ts` pattern): `Statement` is a public structural type, so
94
+ * (the `capacity.ts` pattern): `Statement` is a public structural type, so
80
95
  * without this brand a forged plain object of the right shape would walk
81
96
  * past the construction-time arity and roster walls into `schema()` — and
82
97
  * the roster wall is the one the engine cannot backstop (the wire carries
@@ -115,9 +130,9 @@ interface ContainedStatement<Src extends FaceData, Tgt extends FaceData> extends
115
130
  readonly data: ContainmentData<Src, Tgt>
116
131
  }
117
132
 
118
- /** A window statement as a TYPED value — the {@link ContainedStatement} of the window form. */
119
- interface WindowStatement<Tgt extends FaceData, Src extends FaceData> extends Statement {
120
- readonly data: WindowData<Tgt, Src>
133
+ /** A capacity statement as a TYPED value — the {@link ContainedStatement} of the capacity form. */
134
+ interface CapacityStatement<Tgt extends FaceData, Src extends FaceData> extends Statement {
135
+ readonly data: CapacityData<Tgt, Src>
121
136
  }
122
137
 
123
138
  /**
@@ -266,29 +281,138 @@ function mirrors<A extends AnyFace, B extends AnyFace>(
266
281
  }
267
282
 
268
283
  /**
269
- * `B(Y|ψ) <={window} A(X|φ)` the cardinality window. READ CAREFULLY: the
270
- * LEFT face is the window's TARGET, the per-group parent (B-family,
271
- * target-left macro parity), and the RIGHT face is the counted source.
272
- * `window(on(Holder, "id"), atMost(3n), on(Account, "holder"))` says: each
273
- * Holder id groups at most three Account rows by holder. The two faces
274
- * pair by arity AND structural shape ({@link SameShapes}), exactly as
275
- * containment — the grouping join reads the same positionwise field
276
- * pairing.
284
+ * The runtime twin of the weight source wall ({@link WeightOnSource}): the
285
+ * weighed field must be a u64-encoded position of the SOURCE's own row
286
+ * (a signed weight would break the polarity scheduler the illegal weight
287
+ * is unrepresentable, not checked), an interval position for the
288
+ * `Duration(...)` form. Judged at CONSTRUCTION for untyped callers; the
289
+ * engine's `validate_capacity` stays the final authority.
290
+ */
291
+ function assertWeightOnSource(weight: WeightSpec, source: FaceData, statement: Statement): void {
292
+ if (weight.kind === "unit") {
293
+ return
294
+ }
295
+ const field = sealedFieldOf(source.owner, weight.field)
296
+ if (field === undefined) {
297
+ throw errors.new(
298
+ `${source.owner.name} has no field ${weight.field} — a weight names a field of the SOURCE's own row (the weight vocabulary is closed at the row) — ${renderStatement(statement)}`
299
+ )
300
+ }
301
+ if (weight.kind === "field" && field.kind !== "u64") {
302
+ throw errors.new(
303
+ `${source.owner.name}.${weight.field} is ${field.kind}, not u64 — a weight is u64-encoded (a signed weight would break the polarity scheduler: an insert could lower a sum) — ${renderStatement(statement)}`
304
+ )
305
+ }
306
+ if (weight.kind === "durationField" && field.kind !== "interval") {
307
+ throw errors.new(
308
+ `${source.owner.name}.${weight.field} is ${field.kind}, not an interval — Duration(...) weighs an interval field's measure — ${renderStatement(statement)}`
309
+ )
310
+ }
311
+ }
312
+
313
+ /**
314
+ * The runtime twin of the dependent-bound target wall
315
+ * ({@link BoundsOnTarget}): a `ref()` bound must name a u64 field of the
316
+ * TARGET's own row, a `duration()` bound an interval field — bound names
317
+ * resolve against the target's FULL roster (C1), never the projection.
318
+ * `within()` mints dependent bounds in the hi slot only (C6), but the walk
319
+ * here is total over the window's bound slots.
277
320
  */
278
- function window<B extends AnyFace, A extends AnyFace>(
321
+ function assertBoundsOnTarget(window: CapacityWindowSpec, target: FaceData, statement: Statement): void {
322
+ const bounds = window.kind === "range" ? [window.lo, window.hi] : [window.kind === "exact" ? window.n : window.lo]
323
+ for (const bound of bounds) {
324
+ if (bound.kind === "lit") {
325
+ continue
326
+ }
327
+ const field = sealedFieldOf(target.owner, bound.field)
328
+ if (field === undefined) {
329
+ throw errors.new(
330
+ `${target.owner.name} has no field ${bound.field} — a dependent bound names a field of the TARGET's own row (bound names resolve against the target's full roster) — ${renderStatement(statement)}`
331
+ )
332
+ }
333
+ if (bound.kind === "field" && field.kind !== "u64") {
334
+ throw errors.new(
335
+ `${target.owner.name}.${bound.field} is ${field.kind}, not u64 — a dependent bound reads a u64 field of the TARGET row (Duration(...) is the interval-measure spelling) — ${renderStatement(statement)}`
336
+ )
337
+ }
338
+ if (bound.kind === "durationField" && field.kind !== "interval") {
339
+ throw errors.new(
340
+ `${target.owner.name}.${bound.field} is ${field.kind}, not an interval — Duration(...) bounds by an interval field's measure — ${renderStatement(statement)}`
341
+ )
342
+ }
343
+ }
344
+ }
345
+
346
+ /**
347
+ * `B(Y|ψ) <=[w]{window} A(X|φ)` — the capacity statement, the one
348
+ * extension form: per ψ-selected target fact, the group of φ-selected
349
+ * source facts sharing its key tuple must have its MEASURE (Σ weight; the
350
+ * unit weight IS the count instance) inside the window. READ CAREFULLY:
351
+ * the LEFT face is the TARGET, the per-group parent (B-family, target-left
352
+ * — macro parity), and the RIGHT face is the weighed source. Two
353
+ * overloads mirror the operator positionally (target, weight?, window,
354
+ * source): `capacity(on(Holder, "id"), within(0n, 3n), on(Account,
355
+ * "holder"))` says each Holder id groups at most three Account rows;
356
+ * `capacity(on(Pool, "id"), weigh("watts"), within(0n, ref("supply")),
357
+ * on(Device, "pool"))` bounds each pool's summed draw by the pool's own
358
+ * row. The two faces pair by arity AND structural shape
359
+ * ({@link SameShapes}), exactly as containment — the grouping join reads
360
+ * the same positionwise field pairing. The weight-sensitive `{1..*}` ban
361
+ * rides the UNIT overload only ({@link UnitWindowBan} — on a weighted
362
+ * statement "positive total" is a different, weaker law than containment).
363
+ */
364
+ function capacity<B extends AnyFace, W extends CapacityWindow, A extends AnyFace>(
365
+ target: B,
366
+ window: W & UnitWindowBan<W> & BoundsOnTarget<W, B>,
367
+ source: A & SameArity<B, A> & SameShapes<B, A>
368
+ ): CapacityStatement<B["data"], A["data"]>
369
+ function capacity<B extends AnyFace, M extends CapacityWeight, W extends CapacityWindow, A extends AnyFace>(
279
370
  target: B,
280
- count: Count,
371
+ weight: M & WeightOnSource<M, A>,
372
+ window: W & BoundsOnTarget<W, B>,
281
373
  source: A & SameArity<B, A> & SameShapes<B, A>
282
- ): WindowStatement<B["data"], A["data"]> {
283
- const data: WindowData<B["data"], A["data"]> = Object.freeze({
284
- kind: "window",
374
+ ): CapacityStatement<B["data"], A["data"]>
375
+ function capacity(
376
+ target: AnyFace,
377
+ second: unknown,
378
+ third: unknown,
379
+ fourth?: AnyFace
380
+ ): CapacityStatement<FaceData, FaceData> {
381
+ const weighted = fourth !== undefined
382
+ const windowValue = weighted ? third : second
383
+ const source = weighted ? fourth : (third as AnyFace)
384
+ if (!isCapacityWindow(windowValue)) {
385
+ throw errors.new(
386
+ "a capacity window is minted only by within() — a structural literal skips the ban table (the canonical-utterance law)"
387
+ )
388
+ }
389
+ let weight: WeightSpec = unitWeight
390
+ if (weighted) {
391
+ if (!isCapacityWeight(second)) {
392
+ throw errors.new(
393
+ "a capacity weight is minted only by weigh() — a structural literal skips the row-local weight wall"
394
+ )
395
+ }
396
+ weight = second.weight
397
+ }
398
+ const window = windowValue.window
399
+ if (weight.kind === "unit" && window.kind === "floor" && window.lo.kind === "lit" && window.lo.value === 1n) {
400
+ throw errors.new(
401
+ "`{1..*}` on the unit instance says only what the bare containment says — drop the annotation and write the containment: contained(source, target)"
402
+ )
403
+ }
404
+ const data: CapacityData = Object.freeze({
405
+ kind: "capacity",
285
406
  target: target.data,
286
- window: count.window,
407
+ weight,
408
+ window,
287
409
  source: source.data
288
410
  })
289
411
  const statement = Object.freeze({ data, [admitted]: true as const })
290
412
  assertArityAgreement(data.source, data.target, statement)
291
413
  assertRosterAgreement(data.source, data.target, statement)
414
+ assertWeightOnSource(weight, data.source, statement)
415
+ assertBoundsOnTarget(window, data.target, statement)
292
416
  return statement
293
417
  }
294
418
 
@@ -298,9 +422,11 @@ function window<B extends AnyFace, A extends AnyFace>(
298
422
  * same shapes for violations) — `Account(id) -> Account`,
299
423
  * `Account(holder) <= Holder(id)`,
300
424
  * `Account(id | kind == Savings) == SavingsTerms(account)`,
301
- * `Holder(id) <={0..3} Account(holder)` — so TS-side errors and
425
+ * `Holder(id) <={0..3} Account(holder)`,
426
+ * `Pool(id) <=[watts]{0..supply} Device(pool)` — so TS-side errors and
302
427
  * engine-side diagnostics read identically. A renderer, never a parser:
303
- * strings are output-only.
428
+ * strings are output-only. The unit weight renders nothing — the count
429
+ * utterance falls out of the one printer.
304
430
  */
305
431
  function renderStatement(statement: Statement): string {
306
432
  const data = statement.data
@@ -311,19 +437,19 @@ function renderStatement(statement: Statement): string {
311
437
  const operator = data.bidirectional ? "==" : "<="
312
438
  return `${renderFace(data.source)} ${operator} ${renderFace(data.target)}`
313
439
  }
314
- case "window":
315
- return `${renderFace(data.target)} <=${renderWindow(data.window)} ${renderFace(data.source)}`
440
+ case "capacity":
441
+ return `${renderFace(data.target)} <=${renderWeight(data.weight)}${renderCapacityWindow(data.window)} ${renderFace(data.source)}`
316
442
  }
317
443
  }
318
444
 
319
445
  export type {
446
+ CapacityData,
447
+ CapacityStatement,
320
448
  ContainedStatement,
321
449
  ContainmentData,
322
450
  KeyData,
323
451
  KeyStatement,
324
452
  Statement,
325
- StatementData,
326
- WindowData,
327
- WindowStatement
453
+ StatementData
328
454
  }
329
- export { contained, isStatement, key, mirrors, renderStatement, window }
455
+ export { capacity, contained, isStatement, key, mirrors, renderStatement }
package/dist/count.d.ts DELETED
@@ -1,102 +0,0 @@
1
- /**
2
- * Cardinality-window counts — exactly five constructors, and nothing else
3
- * (`docs/architecture/70-api.md` § the canonical-utterance law). The five
4
- * constructors PARTITION the legal windows, and the ban table is enforced
5
- * REPRESENTATIONALLY, stronger than Rust's expansion errors, in two tiers:
6
- *
7
- * - **The type tier**: a banned spelling written as a LITERAL does not
8
- * compile — `exactly(0n)`, `between(n, n)`, `between(0n, hi)`,
9
- * `atLeast(0n)`, `atLeast(1n)`, `atMost(0n)`, and every negative bound
10
- * are type errors naming the canonical form (`{n..n}`, `{0..0}`,
11
- * `{0..hi}`-via-between, `{0..*}`, `{1..*}` have NO argument shape that
12
- * produces them), and no sixth constructor exists at all.
13
- * - **The construction tier**: a bound the type level cannot judge — a
14
- * COMPUTED `bigint`, whose literal identity is erased, or an inverted
15
- * `between(lo, hi)` order, which type-level bigints cannot compare — is
16
- * judged here at construction with the same canonical-naming errors; and
17
- * past both tiers the engine's own spec validation remains the law for a
18
- * hostile FFI caller (the standing two-tier ban enforcement).
19
- *
20
- * Bounds are `bigint` (u64 crosses as bigint always, PRD-04's law).
21
- */
22
- import type { WindowSpec } from "#spec.ts";
23
- /**
24
- * The admission brand — a module-private symbol, deliberately unexported:
25
- * `WindowSpec` is a public wire type, so without this brand every banned
26
- * spelling in the ban table would be writable as a plain object literal
27
- * (`{ window: { kind: "floor", lo: 1n } }` typechecks structurally). The
28
- * symbol makes the five constructors the ONLY producers of a `Count`
29
- * value, which is what "the ban table is unwritable" means.
30
- */
31
- declare const admitted: unique symbol;
32
- /**
33
- * An admitted window count — opaque and inert: a fact about the theory,
34
- * not a builder. Only the five constructors below produce one (the
35
- * module-private {@link admitted} brand forecloses structural literals).
36
- */
37
- interface Count {
38
- readonly window: WindowSpec;
39
- readonly [admitted]: true;
40
- }
41
- /**
42
- * The legible banned-spelling verdict: intersected into a count
43
- * constructor's parameter when the LITERAL argument spells a banned window,
44
- * naming the canonical form — the compile-time face of the ban table.
45
- */
46
- interface BannedWindow<Canonical extends string> {
47
- readonly "banned window spelling — the canonical-utterance law names the one legal form": Canonical;
48
- }
49
- /** `true` exactly when the literal bigint `N` is negative (out of the u64 count domain). */
50
- type IsNegative<N extends bigint> = `${N}` extends `-${string}` ? true : false;
51
- /** The ban verdict on `exactly(n)`: negatives are out of domain; `{0}` is the exclusion, written `none`. */
52
- type ExactlyBan<N extends bigint> = bigint extends N ? unknown : IsNegative<N> extends true ? BannedWindow<"window counts are u64 — a negative count is out of domain"> : N extends 0n ? BannedWindow<"`{0}` is the exclusion — write none"> : unknown;
53
- /** The ban verdict on `atLeast(lo)`: `{0..*}` is vacuous; `{1..*}` is the bare containment respelled. */
54
- type AtLeastBan<N extends bigint> = bigint extends N ? unknown : IsNegative<N> extends true ? BannedWindow<"window counts are u64 — a negative count is out of domain"> : N extends 0n ? BannedWindow<"`{0..*}` is vacuous — it provably says nothing; delete the statement"> : N extends 1n ? BannedWindow<"`{1..*}` says only what the bare containment says — write contained(source, target)"> : unknown;
55
- /** The ban verdict on `atMost(hi)`: `{0..0}` is the exclusion, written `none`. */
56
- type AtMostBan<N extends bigint> = bigint extends N ? unknown : IsNegative<N> extends true ? BannedWindow<"window counts are u64 — a negative count is out of domain"> : N extends 0n ? BannedWindow<"`{0..0}` — the exclusion is written `{0}`: use none"> : unknown;
57
- /** The ban verdict on a `between` floor of zero: `{0..hi}` is the ceiling respelled (`atMost(hi)`). */
58
- type BetweenFloorBan<Lo extends bigint> = Lo extends 0n ? BannedWindow<"`{0..hi}` — a ceiling is written atMost(hi)"> : unknown;
59
- /**
60
- * The ban verdict on `between(lo, hi)`, judged on the second bound once
61
- * both literals are known: `{n..n}` is the exact count respelled
62
- * (`exactly(n)`, or `none` at 0), and `{0..hi}` is the ceiling respelled
63
- * (`atMost(hi)` — the five constructors PARTITION the legal windows, so
64
- * the one ceiling window keeps its one spelling). Bound ORDER (`{hi..lo}`
65
- * inverted) is not type-expressible — bigint literals have no type-level
66
- * comparison — so inversion stays a construction error below.
67
- */
68
- type BetweenBan<Lo extends bigint, Hi extends bigint> = bigint extends Lo ? unknown : bigint extends Hi ? unknown : IsNegative<Lo> extends true ? BannedWindow<"window counts are u64 — a negative bound is out of domain"> : IsNegative<Hi> extends true ? BannedWindow<"window counts are u64 — a negative bound is out of domain"> : Lo extends Hi ? Hi extends Lo ? Lo extends 0n ? BannedWindow<"`{0..0}` — the exclusion is written `{0}`: use none"> : BannedWindow<"`{n..n}` — an exact count is written `{n}`: use exactly(n)"> : BetweenFloorBan<Lo> : BetweenFloorBan<Lo>;
69
- /**
70
- * `{n}` — THE exact-count spelling, n ≥ 1. `exactly(0)` is the exclusion
71
- * respelled: unwritable as a literal ({@link ExactlyBan} names `none`),
72
- * rejected at construction when computed.
73
- */
74
- declare function exactly<const N extends bigint>(n: N & ExactlyBan<N>): Count;
75
- /** `{0}` — the exclusion: no source fact may pair with the target group. */
76
- declare const none: Count;
77
- /**
78
- * `{lo..hi}` — both bounds explicit, 1 ≤ lo < hi. `lo === hi` is the exact
79
- * count respelled and `lo === 0` is the ceiling respelled: unwritable as
80
- * literals ({@link BetweenBan} names `exactly(n)`, `none` at `{0..0}`, or
81
- * `atMost(hi)` at a zero floor — the five constructors PARTITION the legal
82
- * windows), rejected at construction when computed; an inverted window is
83
- * unsatisfiable and rejected at construction (bigint literals carry no
84
- * type-level order).
85
- */
86
- declare function between<const Lo extends bigint, const Hi extends bigint>(lo: Lo, hi: Hi & BetweenBan<Lo, Hi>): Count;
87
- /**
88
- * `{lo..*}` — a floor with no ceiling, lo ≥ 2: `atLeast(1)` says only what
89
- * the bare containment says and `atLeast(0)` is vacuous — both unwritable
90
- * as literals ({@link AtLeastBan} names the canonical form), rejected at
91
- * construction when computed.
92
- */
93
- declare function atLeast<const N extends bigint>(lo: N & AtLeastBan<N>): Count;
94
- /**
95
- * `{0..hi}` — a ceiling, hi ≥ 1: `atMost(0)` is the exclusion respelled —
96
- * unwritable as a literal ({@link AtMostBan} names `none`), rejected at
97
- * construction when computed.
98
- */
99
- declare function atMost<const N extends bigint>(hi: N & AtMostBan<N>): Count;
100
- export type { Count };
101
- export { atLeast, atMost, between, exactly, none };
102
- //# sourceMappingURL=count.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"count.d.ts","sourceRoot":"","sources":["../src/count.ts"],"names":[],"mappings":"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"}
package/dist/count.js DELETED
@@ -1,115 +0,0 @@
1
- /**
2
- * Cardinality-window counts — exactly five constructors, and nothing else
3
- * (`docs/architecture/70-api.md` § the canonical-utterance law). The five
4
- * constructors PARTITION the legal windows, and the ban table is enforced
5
- * REPRESENTATIONALLY, stronger than Rust's expansion errors, in two tiers:
6
- *
7
- * - **The type tier**: a banned spelling written as a LITERAL does not
8
- * compile — `exactly(0n)`, `between(n, n)`, `between(0n, hi)`,
9
- * `atLeast(0n)`, `atLeast(1n)`, `atMost(0n)`, and every negative bound
10
- * are type errors naming the canonical form (`{n..n}`, `{0..0}`,
11
- * `{0..hi}`-via-between, `{0..*}`, `{1..*}` have NO argument shape that
12
- * produces them), and no sixth constructor exists at all.
13
- * - **The construction tier**: a bound the type level cannot judge — a
14
- * COMPUTED `bigint`, whose literal identity is erased, or an inverted
15
- * `between(lo, hi)` order, which type-level bigints cannot compare — is
16
- * judged here at construction with the same canonical-naming errors; and
17
- * past both tiers the engine's own spec validation remains the law for a
18
- * hostile FFI caller (the standing two-tier ban enforcement).
19
- *
20
- * Bounds are `bigint` (u64 crosses as bigint always, PRD-04's law).
21
- */
22
- import * as errors from "@superbuilders/errors";
23
- /** The exclusion's one spelling, shared by `none`. */
24
- const exclusion = Object.freeze({ kind: "exact", n: 0n });
25
- /**
26
- * The admission brand — a module-private symbol, deliberately unexported:
27
- * `WindowSpec` is a public wire type, so without this brand every banned
28
- * spelling in the ban table would be writable as a plain object literal
29
- * (`{ window: { kind: "floor", lo: 1n } }` typechecks structurally). The
30
- * symbol makes the five constructors the ONLY producers of a `Count`
31
- * value, which is what "the ban table is unwritable" means.
32
- */
33
- const admitted = Symbol("bumbledb.count.admitted");
34
- /** Stamps one admitted window as a frozen `Count` value. */
35
- function admit(window) {
36
- const count = { window, [admitted]: true };
37
- return Object.freeze(count);
38
- }
39
- /**
40
- * `{n}` — THE exact-count spelling, n ≥ 1. `exactly(0)` is the exclusion
41
- * respelled: unwritable as a literal ({@link ExactlyBan} names `none`),
42
- * rejected at construction when computed.
43
- */
44
- function exactly(n) {
45
- if (n < 0n) {
46
- throw errors.new(`window counts are u64: exactly(${n}) is out of domain`);
47
- }
48
- if (n === 0n) {
49
- throw errors.new("`{0}` is the exclusion — write none");
50
- }
51
- return admit(Object.freeze({ kind: "exact", n }));
52
- }
53
- /** `{0}` — the exclusion: no source fact may pair with the target group. */
54
- const none = admit(exclusion);
55
- /**
56
- * `{lo..hi}` — both bounds explicit, 1 ≤ lo < hi. `lo === hi` is the exact
57
- * count respelled and `lo === 0` is the ceiling respelled: unwritable as
58
- * literals ({@link BetweenBan} names `exactly(n)`, `none` at `{0..0}`, or
59
- * `atMost(hi)` at a zero floor — the five constructors PARTITION the legal
60
- * windows), rejected at construction when computed; an inverted window is
61
- * unsatisfiable and rejected at construction (bigint literals carry no
62
- * type-level order).
63
- */
64
- function between(lo, hi) {
65
- if (lo < 0n || hi < 0n) {
66
- throw errors.new(`window counts are u64: between(${lo}, ${hi}) is out of domain`);
67
- }
68
- if (hi < lo) {
69
- throw errors.new(`the window \`{${lo}..${hi}}\` is inverted — no count satisfies it; bounds are \`{lo..hi}\` with lo < hi (an exact count is \`{n}\`: exactly(n))`);
70
- }
71
- if (lo === hi) {
72
- if (lo === 0n) {
73
- throw errors.new("`{0..0}` — the exclusion is written `{0}`: use none");
74
- }
75
- throw errors.new(`\`{${lo}..${lo}}\` — an exact count is written \`{${lo}}\`: use exactly(${lo})`);
76
- }
77
- if (lo === 0n) {
78
- throw errors.new(`\`{0..${hi}}\` — a ceiling is written atMost: use atMost(${hi})`);
79
- }
80
- return admit(Object.freeze({ kind: "range", lo, hi }));
81
- }
82
- /**
83
- * `{lo..*}` — a floor with no ceiling, lo ≥ 2: `atLeast(1)` says only what
84
- * the bare containment says and `atLeast(0)` is vacuous — both unwritable
85
- * as literals ({@link AtLeastBan} names the canonical form), rejected at
86
- * construction when computed.
87
- */
88
- function atLeast(lo) {
89
- if (lo < 0n) {
90
- throw errors.new(`window counts are u64: atLeast(${lo}) is out of domain`);
91
- }
92
- if (lo === 0n) {
93
- throw errors.new("the `{0..*}` window is vacuous — it provably says nothing; delete the statement");
94
- }
95
- if (lo === 1n) {
96
- throw errors.new("`{1..*}` says only what the bare containment says — drop the annotation and write the containment: contained(source, target)");
97
- }
98
- return admit(Object.freeze({ kind: "floor", lo }));
99
- }
100
- /**
101
- * `{0..hi}` — a ceiling, hi ≥ 1: `atMost(0)` is the exclusion respelled —
102
- * unwritable as a literal ({@link AtMostBan} names `none`), rejected at
103
- * construction when computed.
104
- */
105
- function atMost(hi) {
106
- if (hi < 0n) {
107
- throw errors.new(`window counts are u64: atMost(${hi}) is out of domain`);
108
- }
109
- if (hi === 0n) {
110
- throw errors.new("`{0..0}` — the exclusion is written `{0}`: use none");
111
- }
112
- return admit(Object.freeze({ kind: "range", lo: 0n, hi }));
113
- }
114
- export { atLeast, atMost, between, exactly, none };
115
- //# sourceMappingURL=count.js.map
package/dist/count.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"count.js","sourceRoot":"","sources":["../src/count.ts"],"names":[],"mappings":"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"}