@jarenjs/linq 0.49.2 → 0.66.1

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 (79) hide show
  1. package/ARCHITECTURE.md +227 -0
  2. package/README.md +650 -17
  3. package/docs/APP-PEN.md +1143 -0
  4. package/docs/CONTRACT-PEN.md +1221 -0
  5. package/docs/DB-CLIENT.md +882 -0
  6. package/docs/FLOW-PEN.md +1033 -0
  7. package/docs/FORMS-PEN.md +940 -0
  8. package/docs/JSLT-PEN.md +955 -0
  9. package/docs/LINQ-FORMAT.md +778 -383
  10. package/docs/MIGRATION-PEN.md +781 -0
  11. package/docs/MODEL-PEN.md +1092 -0
  12. package/docs/QUERY-PEN.md +1724 -0
  13. package/docs/SCHEMA-PEN.md +1218 -0
  14. package/package.json +57 -4
  15. package/src/app/action.js +251 -0
  16. package/src/app/capture.js +63 -0
  17. package/src/app/define.js +255 -0
  18. package/src/app/index.js +20 -0
  19. package/src/app/patch.js +277 -0
  20. package/src/app/sub.js +106 -0
  21. package/src/async.js +377 -75
  22. package/src/capture-root.js +82 -0
  23. package/src/concurrency.js +48 -11
  24. package/src/contract/define.js +282 -0
  25. package/src/contract/http.js +247 -0
  26. package/src/contract/index.js +23 -0
  27. package/src/contract/operation.js +338 -0
  28. package/src/db/handle.js +89 -0
  29. package/src/db/include.js +351 -0
  30. package/src/db/index.js +24 -0
  31. package/src/db/ledger.js +195 -0
  32. package/src/db/live.js +43 -0
  33. package/src/db/membership.js +37 -0
  34. package/src/db/open.js +130 -0
  35. package/src/document.js +143 -13
  36. package/src/effect.js +65 -0
  37. package/src/errors.js +78 -6
  38. package/src/expression.js +463 -36
  39. package/src/federate.js +531 -0
  40. package/src/flow/capture.js +33 -0
  41. package/src/flow/dag.js +316 -0
  42. package/src/flow/fsm.js +323 -0
  43. package/src/flow/index.js +22 -0
  44. package/src/forms/index.js +43 -0
  45. package/src/forms/rules.js +170 -0
  46. package/src/forms/submit.js +177 -0
  47. package/src/index.js +5 -2
  48. package/src/jslt/body.js +226 -0
  49. package/src/jslt/index.js +18 -0
  50. package/src/jslt/rules.js +202 -0
  51. package/src/json-boundary.js +90 -0
  52. package/src/migration/define.js +318 -0
  53. package/src/migration/index.js +15 -0
  54. package/src/migration/steps.js +244 -0
  55. package/src/model/collection.js +273 -0
  56. package/src/model/define.js +125 -0
  57. package/src/model/entity.js +307 -0
  58. package/src/model/index.js +47 -0
  59. package/src/model/relation.js +85 -0
  60. package/src/provider.js +137 -20
  61. package/src/schema/brand.js +31 -0
  62. package/src/schema/builders.js +526 -0
  63. package/src/schema/check.js +29 -0
  64. package/src/schema/emit.js +394 -0
  65. package/src/schema/factories.js +239 -0
  66. package/src/schema/index.js +37 -0
  67. package/src/schema-of.js +24 -0
  68. package/src/sequence.js +233 -103
  69. package/src/sources.js +10 -3
  70. package/types/app.d.ts +293 -0
  71. package/types/contract.d.ts +468 -0
  72. package/types/db.d.ts +359 -0
  73. package/types/flow.d.ts +285 -0
  74. package/types/forms.d.ts +253 -0
  75. package/types/index.d.ts +296 -26
  76. package/types/jslt.d.ts +193 -0
  77. package/types/migration.d.ts +201 -0
  78. package/types/model.d.ts +526 -0
  79. package/types/schema.d.ts +494 -0
@@ -0,0 +1,253 @@
1
+ /**
2
+ * Hand-authored declarations for `@jarenjs/linq/forms` — the schema
3
+ * pen's every name, from subclasses that carry the `x-form` vocabulary,
4
+ * plus `assertOnSubmit()`.
5
+ *
6
+ * A rule is an ANNOTATION, so nothing here changes what a builder
7
+ * INFERS: `Infer<>`, `Input<>` and the flags read exactly as they do on
8
+ * the schema pen, and the subclasses exist only so `form()` survives
9
+ * every chained method. What the rules are typed against is the rule
10
+ * CONTEXT: `c.root` is the whole form document, typed by annotation
11
+ * (`(c: RuleContext<Invoice>) => …`) because a member builder is
12
+ * written before the object that will hold it exists — the same limit
13
+ * the flow pen's `context` meets, and TypeScript's own.
14
+ *
15
+ * Every claim here has a runtime twin in `test/linq/forms-pen.test.js`
16
+ * and a compile-level pin in `test/consumer/linq-app.ts`; FORMS-PEN.md
17
+ * is the normative mapping table.
18
+ */
19
+
20
+ import type { BoolExpr, DateTime, MemberExpr, StringExpr } from './index.js';
21
+ import type {
22
+ Annotations, BuilderLike, Flag, Infer, Input, Json, JsonSchema, NamedLike, Simplify,
23
+ SchemaBuilder, StringBuilder, NumberBuilder, BooleanBuilder, NullBuilder, ArrayBuilder,
24
+ TupleBuilder, ObjectBuilder, NamedBuilder, WhenBuilder, NeverBuilder,
25
+ } from './schema.js';
26
+
27
+ type AnyBuilder = BuilderLike<any, any, any>;
28
+ type Props = Record<string, AnyBuilder>;
29
+ type Nullify<T, N extends boolean> = N extends true ? T | null : T;
30
+
31
+ // ————— the rule context —————
32
+
33
+ /**
34
+ * The three names a rule query binds (the forms README, "The rule query
35
+ * context"): the whole document at `$`, the field's own value as the
36
+ * `$value` external and its pointer as `$pointer`. `Doc` is the honest
37
+ * top until the callback is annotated.
38
+ */
39
+ export interface RuleContext<Doc = unknown, Value = unknown> {
40
+ /** The whole form document (`$`) — cross-field is the point. */
41
+ readonly root: MemberExpr<Doc>;
42
+ /** The field's current value (`$value`); an absent field binds `null`. */
43
+ readonly value: MemberExpr<Value>;
44
+ /** The field's data pointer (`$pointer`), `'/vatId'`. */
45
+ readonly pointer: StringExpr;
46
+ }
47
+
48
+ /** A rule: a callback captured over the context, or a query document. */
49
+ export type Rule<Doc = unknown, Value = unknown> =
50
+ | ((context: RuleContext<Doc, Value>) => unknown)
51
+ | { readonly [keyword: string]: unknown };
52
+
53
+ /** The message an `assert` failure renders: an inline template, or a
54
+ * catalog spec (the forms README, "MessageSpec in `x-form.message`"). */
55
+ export type MessageSpec =
56
+ | string
57
+ | { readonly $msgid?: string; readonly message?: string; readonly params?: Record<string, Json> };
58
+
59
+ /**
60
+ * What `form()` takes — exactly the members `x-form` defines. `preview`
61
+ * is absent on purpose: a field's preview hint is DERIVED from its
62
+ * format by the registry, never authored, and writing it is `JL0102`.
63
+ */
64
+ export interface FormRules<Doc = unknown, Value = unknown> {
65
+ /** Should the field be shown? Asserted by effective boolean value; fails OPEN. */
66
+ readonly visible?: Rule<Doc, Value>;
67
+ /** Should the field accept input? EBV; fails OPEN. */
68
+ readonly enabled?: Rule<Doc, Value>;
69
+ /** A cross-field preemptive assertion. EBV; fails CLOSED. */
70
+ readonly assert?: Rule<Doc, Value>;
71
+ /** The field's derived value, mapped to plain JSON. */
72
+ readonly computed?: Rule<Doc, Value>;
73
+ /** Shown when `assert` fails. */
74
+ readonly message?: MessageSpec;
75
+ }
76
+
77
+ // ————— the rule-aware builders —————
78
+
79
+ /** The base every untyped kind is built from, plus `form()`. */
80
+ export class FormBuilder<Out = unknown, In = Out, F extends Flag = never> extends SchemaBuilder<Out, In, F> {
81
+ optional(): FormBuilder<Out, In, F | 'optional'>;
82
+ nullable(): FormBuilder<Out | null, In | null, F>;
83
+ default(value: Out): FormBuilder<Out, In, F | 'defaulted'>;
84
+ /** One `x-form` annotation; a second call merges into the same one. */
85
+ form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
86
+ /** As in the schema pen, but `x-form` is owned here. */
87
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
88
+ }
89
+
90
+ export class FormStringBuilder<Out = string, In = Out, F extends Flag = never> extends StringBuilder<Out, In, F> {
91
+ optional(): FormStringBuilder<Out, In, F | 'optional'>;
92
+ nullable(): FormStringBuilder<Out | null, In | null, F>;
93
+ default(value: Out): FormStringBuilder<Out, In, F | 'defaulted'>;
94
+ coerce(): FormStringBuilder<Out, In | number | boolean, F>;
95
+ format(name: 'date-time' | 'date'): FormStringBuilder<DateTime, DateTime, F>;
96
+ format(name: string): this;
97
+ enumOf<const V extends readonly string[]>(values: V): FormStringBuilder<V[number], V[number], F>;
98
+ form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
99
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
100
+ }
101
+
102
+ export class FormNumberBuilder<Out = number, In = Out, F extends Flag = never> extends NumberBuilder<Out, In, F> {
103
+ optional(): FormNumberBuilder<Out, In, F | 'optional'>;
104
+ nullable(): FormNumberBuilder<Out | null, In | null, F>;
105
+ default(value: Out): FormNumberBuilder<Out, In, F | 'defaulted'>;
106
+ coerce(): FormNumberBuilder<Out, In | string, F>;
107
+ enumOf<const V extends readonly number[]>(values: V): FormNumberBuilder<V[number], V[number] | Exclude<In, number>, F>;
108
+ form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
109
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
110
+ }
111
+
112
+ declare class FormBooleanBuilder<Out = boolean, In = Out, F extends Flag = never> extends BooleanBuilder<Out, In, F> {
113
+ optional(): FormBooleanBuilder<Out, In, F | 'optional'>;
114
+ nullable(): FormBooleanBuilder<Out | null, In | null, F>;
115
+ default(value: Out): FormBooleanBuilder<Out, In, F | 'defaulted'>;
116
+ coerce(): FormBooleanBuilder<Out, In | string, F>;
117
+ form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
118
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
119
+ }
120
+
121
+ declare class FormNullBuilder<Out = null, In = Out, F extends Flag = never> extends NullBuilder<Out, In, F> {
122
+ optional(): FormNullBuilder<Out, In, F | 'optional'>;
123
+ default(value: Out): FormNullBuilder<Out, In, F | 'defaulted'>;
124
+ coerce(): FormNullBuilder<Out, In | string, F>;
125
+ form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
126
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
127
+ }
128
+
129
+ export class FormArrayBuilder<Out = unknown[], In = Out, F extends Flag = never> extends ArrayBuilder<Out, In, F> {
130
+ optional(): FormArrayBuilder<Out, In, F | 'optional'>;
131
+ nullable(): FormArrayBuilder<Out | null, In | null, F>;
132
+ default(value: Out): FormArrayBuilder<Out, In, F | 'defaulted'>;
133
+ form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
134
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
135
+ }
136
+
137
+ export class FormTupleBuilder<
138
+ T extends readonly AnyBuilder[], R = unknown, RIn = R,
139
+ N extends boolean = false, F extends Flag = never,
140
+ > extends TupleBuilder<T, R, RIn, N, F> {
141
+ optional(): FormTupleBuilder<T, R, RIn, N, F | 'optional'>;
142
+ nullable(): FormTupleBuilder<T, R, RIn, true, F>;
143
+ rest<B extends AnyBuilder>(builder: B): FormTupleBuilder<T, Infer<B>, Input<B>, N, F>;
144
+ form<Doc = unknown>(rules: FormRules<Doc, unknown>): this;
145
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
146
+ }
147
+
148
+ export class FormObjectBuilder<
149
+ P extends Props, Open extends boolean = false, PV = never, PVIn = PV,
150
+ N extends boolean = false, F extends Flag = never,
151
+ > extends ObjectBuilder<P, Open, PV, PVIn, N, F> {
152
+ optional(): FormObjectBuilder<P, Open, PV, PVIn, N, F | 'optional'>;
153
+ nullable(): FormObjectBuilder<P, Open, PV, PVIn, true, F>;
154
+ open(): FormObjectBuilder<P, true, PV, PVIn, N, F>;
155
+ patternProperties<M extends Props>(map: M): FormObjectBuilder<P, Open, Infer<M[keyof M]>, Input<M[keyof M]>, N, F>;
156
+ extend<Q extends Props>(props: Q): FormObjectBuilder<Simplify<Omit<P, keyof Q> & Q>, Open, PV, PVIn, N, F>;
157
+ pick<K extends keyof P & string>(keys: readonly K[]): FormObjectBuilder<Pick<P, K>, Open, PV, PVIn, N, F>;
158
+ omit<K extends keyof P & string>(keys: readonly K[]): FormObjectBuilder<Omit<P, K>, Open, PV, PVIn, N, F>;
159
+ /** A rule on the ROOT's `visible` is refused by `compileFormRules`:
160
+ * hiding the whole form would null the render tree and its summary. */
161
+ form<Doc = unknown>(rules: FormRules<Doc, unknown>): this;
162
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
163
+ }
164
+
165
+ declare class FormNamedBuilder<Out, In = Out, F extends Flag = never> extends NamedBuilder<Out, In, F> {
166
+ optional(): FormNamedBuilder<Out, In, F | 'optional'>;
167
+ nullable(): FormNamedBuilder<Out | null, In | null, F>;
168
+ form<Doc = unknown>(rules: FormRules<Doc, Out>): this;
169
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
170
+ }
171
+
172
+ /**
173
+ * `when()` on this pen. A conditional carries a rule like any other
174
+ * node: `buildFormModel` reads `x-form` off whatever schema it builds a
175
+ * field for, so a `when()` used as an object MEMBER answers a field whose
176
+ * rules evaluate — the runtime twin is in `test/linq/forms-pen.test.js`.
177
+ * `Value` is `unknown` here, as on the object and tuple builders: the
178
+ * node describes a shape rather than a value.
179
+ */
180
+ export class FormWhenBuilder<F extends Flag = never> extends WhenBuilder<F> {
181
+ optional(): FormWhenBuilder<F | 'optional'>;
182
+ then(builder: AnyBuilder): FormWhenBuilder<F>;
183
+ else(builder: AnyBuilder): FormWhenBuilder<F>;
184
+ form<Doc = unknown>(rules: FormRules<Doc, unknown>): this;
185
+ meta(annotations: Annotations & { readonly 'x-form'?: never }): this;
186
+ }
187
+
188
+ /**
189
+ * `never()` on this pen — and `never()` ANSWERS one, so a caller meets
190
+ * this class without narrowing to it. A rule is an annotation and
191
+ * `false` carries no annotation, so `form()` and `meta()` both raise
192
+ * `JL0102` here: `form()` is not declared at all, and `meta()` is
193
+ * inherited from `NeverBuilder` with a `never` parameter, so neither
194
+ * call compiles either. `nullable()` widens the node and hands back this
195
+ * pen's base builder, where both are legal again.
196
+ */
197
+ export class FormNeverBuilder<Out = never, In = Out, F extends Flag = never> extends NeverBuilder<Out, In, F> {
198
+ optional(): FormNeverBuilder<Out, In, F | 'optional'>;
199
+ /** As on the schema pen: widening to admit `null` is what makes a rule
200
+ * writable, so it answers this pen's base builder. */
201
+ nullable(): FormBuilder<Out | null, In | null, F>;
202
+ }
203
+
204
+ // ————— the named factories —————
205
+
206
+ export function string(): FormStringBuilder;
207
+ export function number(): FormNumberBuilder;
208
+ export function integer(): FormNumberBuilder;
209
+ export function boolean(): FormBooleanBuilder;
210
+ export function nil(): FormNullBuilder;
211
+ export function literal<const V extends Json>(value: V): FormBuilder<V, V>;
212
+ export function enumOf<const V extends readonly Json[]>(values: V): FormBuilder<V[number], V[number]>;
213
+ export function object<P extends Props>(props: P): FormObjectBuilder<P>;
214
+ export function array<B extends AnyBuilder>(items: B): FormArrayBuilder<Infer<B>[], Input<B>[]>;
215
+ export function tuple<T extends readonly AnyBuilder[]>(items: readonly [...T]): FormTupleBuilder<T>;
216
+ export function record<B extends AnyBuilder>(values: B):
217
+ FormBuilder<{ [key: string]: Infer<B> }, { [key: string]: Input<B> }>;
218
+ export function union<T extends readonly AnyBuilder[]>(options: readonly [...T]):
219
+ FormBuilder<Infer<T[number]>, Input<T[number]>>;
220
+ export function discriminated<K extends string, T extends readonly BuilderLike<Record<K, unknown>, any, any>[]>(
221
+ key: K, options: readonly [...T]): FormBuilder<Infer<T[number]>, Input<T[number]>>;
222
+ export function intersection<T extends readonly AnyBuilder[]>(parts: readonly [...T]):
223
+ FormBuilder<Intersect<{ [I in keyof T]: Infer<T[I]> }>, Intersect<{ [I in keyof T]: Input<T[I]> }>>;
224
+ type Intersect<T extends readonly unknown[]> = T extends readonly [infer H, ...infer R] ? H & Intersect<R> : unknown;
225
+ export function named<B extends AnyBuilder>(name: string, builder: B): FormNamedBuilder<Infer<B>, Input<B>>;
226
+ export function ref<T = unknown>(name: string): FormBuilder<T, T>;
227
+ export function lazy<T, I = T>(thunk: () => NamedLike<T, I>): FormBuilder<T, I>;
228
+ export function any(): FormBuilder<unknown, unknown>;
229
+ export function never(): FormNeverBuilder;
230
+ export function when(cond: AnyBuilder): FormWhenBuilder;
231
+ export function from<T = unknown>(json: JsonSchema | boolean): FormBuilder<T, T>;
232
+ export function document(root: AnyBuilder, options?: { draft?: '2020-12' }): JsonSchema | boolean;
233
+ export function datetime(): FormStringBuilder<DateTime, DateTime>;
234
+ export function date(): FormStringBuilder<DateTime, DateTime>;
235
+ export function time(): FormStringBuilder;
236
+ export function duration(): FormStringBuilder;
237
+
238
+ /** The mixin the classes above are built with: a NEW class carrying `form()`. */
239
+ export function withForm<B extends new (...args: any[]) => any>(Base: B): B;
240
+
241
+ /**
242
+ * The submit twin of a document's `x-form.assert` rules (the forms
243
+ * README's layer 3): every assert copied onto the ROOT as its own
244
+ * `allOf` branch `{ $query, errorMessage }`, so the rule an author wrote
245
+ * once for per-keystroke feedback is what the compiled validator
246
+ * enforces. A document with no assert answers itself.
247
+ */
248
+ export function assertOnSubmit(root: AnyBuilder | JsonSchema): JsonSchema;
249
+
250
+ export const SCHEMA_BUILDER: unique symbol;
251
+ export function isSchemaBuilder(value: unknown): value is BuilderLike;
252
+ export function schemaOf(value: unknown): unknown;
253
+ export type { BoolExpr };