@chelone/core 0.1.1 → 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.
@@ -0,0 +1,114 @@
1
+ import type { Get, Paths } from "dot.paths";
2
+ import type { LooseRecord } from "./record.js";
3
+ import type { RegisteredResources } from "./register.js";
4
+ import type { RecordOf, ResourceMap } from "./registry.js";
5
+ /**
6
+ * Source-path types for a registered resource's record.
7
+ *
8
+ * Every path prop in Chelone is composed at runtime (`source.ts`,
9
+ * `input-binding.ts`); these types say which paths are legal for a given
10
+ * record, so `<TextInput source="titel" />` stops compiling once an app
11
+ * registers its resources. They are built on `dot.paths`' `Paths` and `Get`,
12
+ * and accept the bracket grammar only (`tags[0].label`) — the syntax
13
+ * `composeSource` and form-core's `DeepKeys` use. A dot index
14
+ * (`tags.0.label`) still works at runtime but is not a legal prop type.
15
+ */
16
+ /** Object levels walked while looking for arrays in a record. */
17
+ type _WalkDepth = 8;
18
+ /** How deep `RowSourcePath` follows nested arrays. */
19
+ type _MaxArrayNesting = 3;
20
+ /** Decrement tables for the two counters above (`_Prev[N]` is `N - 1`). */
21
+ type _PrevWalk = [never, 0, 1, 2, 3, 4, 5, 6, 7];
22
+ type _PrevNesting = [never, 0, 1, 2];
23
+ /**
24
+ * The item type of every array reachable in `T`. Object members are walked up
25
+ * to `_WalkDepth` levels; array nesting up to `_MaxArrayNesting`, so a
26
+ * recursive record type terminates and the resulting path union stays small.
27
+ *
28
+ * The union is walked one member at a time (`T extends unknown` distributes,
29
+ * and object members are walked per key) because `any` absorbs a union: walked
30
+ * as one type, a single `any`-typed field would turn every array in the record
31
+ * into `any`.
32
+ */
33
+ type _ArrayItems<T, Walk extends number, Nesting extends number> = [
34
+ Walk
35
+ ] extends [0] ? never : [Nesting] extends [0] ? never : T extends unknown ? _ItemsOf<T, Walk, Nesting> : never;
36
+ type _ItemsOf<T, Walk extends number, Nesting extends number> = 0 extends 1 & T ? never : T extends readonly unknown[] ? T extends readonly [] ? never : _Row<NonNullable<T[number]>> | _ArrayItems<NonNullable<T[number]>, _PrevWalk[Walk], _PrevNesting[Nesting]> : T extends object ? {
37
+ [K in keyof T]: _ArrayItems<T[K], _PrevWalk[Walk], Nesting>;
38
+ }[keyof T] : never;
39
+ /**
40
+ * The item type of an array, minus `any` (it names no key set) and minus any
41
+ * member that is itself an array: a row that is an array has no named path
42
+ * under it, and `Paths` of it is a wall of `[${number}]` patterns.
43
+ */
44
+ type _Row<T> = Exclude<0 extends 1 & T ? never : T, readonly unknown[]>;
45
+ /**
46
+ * Every legal `source` path into `TRecord`: dotted object paths and bracket
47
+ * array indices (`items[0].sku`).
48
+ *
49
+ * The `unknown` guard is load-bearing: `Paths<unknown>` is `never`, which would
50
+ * reject every source of a resource with no schema, while
51
+ * `Paths<LooseRecord, { arrays: "bracket" }>` is `string`.
52
+ */
53
+ export type SourcePath<TRecord> = unknown extends TRecord ? string : Paths<TRecord, {
54
+ arrays: "bracket";
55
+ }>;
56
+ /**
57
+ * The value type at `TPath`, including the `null`/`undefined` of every parent
58
+ * along it — what reading `record.author?.name` gives. `unknown` for a loose
59
+ * record.
60
+ */
61
+ export type SourceValue<TRecord, TPath extends string> = unknown extends TRecord ? unknown : Get<TRecord, TPath, {
62
+ nullish: "path";
63
+ }>;
64
+ /**
65
+ * The top-level keys of `TRecord`, for props that read or write one flat key
66
+ * (a filter's field, a reference's target). `string` for a loose record.
67
+ */
68
+ export type SourceKey<TRecord> = unknown extends TRecord ? string : keyof TRecord & string;
69
+ /**
70
+ * The paths *relative to an array item* of every array in `TRecord`: `sku` is
71
+ * one for a record with `items: { sku: string }[]`.
72
+ *
73
+ * Children of an `ArrayInput` bind a path relative to their row
74
+ * (`createRowSourceScope`), so a root-only path type would reject every
75
+ * iterator child.
76
+ *
77
+ * A row whose type names no keys contributes nothing, and it is filtered per
78
+ * member so it cannot poison the rest: a `z.record` column, a jsonb `Json`
79
+ * member and a `z.any()` field all give `Paths` = `string`, and one `string`
80
+ * here would swallow every other array's paths and let every typo through
81
+ * again. A record that wants its jsonb rows checked gives them a schema.
82
+ */
83
+ export type RowSourcePath<TRecord> = unknown extends TRecord ? string : string extends keyof TRecord ? string : _ArrayItems<TRecord, _WalkDepth, _MaxArrayNesting> extends infer TItem ? TItem extends unknown ? Paths<TItem, {
84
+ arrays: "bracket";
85
+ }> extends infer TPath extends string ? string extends TPath ? never : TPath : never : never : never;
86
+ /**
87
+ * A filter key: the free-text `q`, or a source path with an operator suffix —
88
+ * the keys Chelone writes itself (`calendarRangeFilter` builds
89
+ * `` `${startSource}_gte` ``) and a filter input's `source` is named with.
90
+ */
91
+ export type FilterSourceKey<TRecord> = "q" | `${SourcePath<TRecord>}_${string}`;
92
+ /** The source props one record accepts: its paths, its row paths, its filter keys. */
93
+ type _RecordSourcePath<TRecord> = SourcePath<TRecord> | RowSourcePath<TRecord> | FilterSourceKey<TRecord>;
94
+ /**
95
+ * The union of every registered resource's source paths.
96
+ *
97
+ * `string` when the name set is `string` — the unregistered case, and the one
98
+ * that keeps `AnySourcePath` from recursing on itself through
99
+ * {@link SourceProp} — and `string` when any resource has no schema.
100
+ */
101
+ export type AnySourcePathOf<TResources extends ResourceMap> = string extends keyof TResources ? string : {
102
+ [TName in keyof TResources & string]: _RecordSourcePath<RecordOf<TResources, TName>>;
103
+ }[keyof TResources & string];
104
+ /** {@link AnySourcePathOf} over the app's registered resources. */
105
+ export type AnySourcePath = AnySourcePathOf<RegisteredResources>;
106
+ /**
107
+ * The type a `source` prop takes.
108
+ *
109
+ * A loose record (the default, and every app that registers nothing) gets
110
+ * {@link AnySourcePath}, which is `string` until `Register` is augmented; a
111
+ * typed record gets its own paths.
112
+ */
113
+ export type SourceProp<TRecord = LooseRecord> = LooseRecord extends TRecord ? AnySourcePath : _RecordSourcePath<TRecord>;
114
+ export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@chelone/core",
3
- "version": "0.1.1",
3
+ "version": "0.3.0",
4
4
  "license": "MIT",
5
5
  "repository": {
6
6
  "type": "git",
@@ -43,6 +43,9 @@
43
43
  "vitest": "^3.0.0",
44
44
  "zod": "^3.25.0"
45
45
  },
46
+ "dependencies": {
47
+ "dot.paths": "^0.2.0"
48
+ },
46
49
  "scripts": {
47
50
  "build": "vite build && tsc -p tsconfig.build.json && node ../../scripts/dts-extensions.mjs dist",
48
51
  "check:pack": "publint --pack pnpm --strict && d=$(mktemp -d) && trap 'rm -rf $d' EXIT && pnpm pack --pack-destination $d && attw $d/*.tgz --profile esm-only",