@strictly/define 0.0.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.
- package/.eslintrc.cjs +31 -0
- package/.out/index.d.ts +20 -0
- package/.out/index.js +20 -0
- package/.out/transformers/copies/copy.d.ts +4 -0
- package/.out/transformers/copies/copy.js +7 -0
- package/.out/transformers/copies/copy_to.d.ts +6 -0
- package/.out/transformers/copies/copy_to.js +91 -0
- package/.out/transformers/copies/mobx_copy.d.ts +5 -0
- package/.out/transformers/copies/mobx_copy.js +42 -0
- package/.out/transformers/copies/specs/copy_to.tests.d.ts +1 -0
- package/.out/transformers/copies/specs/copy_to.tests.js +97 -0
- package/.out/transformers/copies/specs/mobx_copy.tests.d.ts +1 -0
- package/.out/transformers/copies/specs/mobx_copy.tests.js +19 -0
- package/.out/transformers/flatteners/flatten_accessors_of.d.ts +5 -0
- package/.out/transformers/flatteners/flatten_accessors_of.js +11 -0
- package/.out/transformers/flatteners/flatten_json_value_to_type_paths_of.d.ts +3 -0
- package/.out/transformers/flatteners/flatten_json_value_to_type_paths_of.js +10 -0
- package/.out/transformers/flatteners/flatten_type_def_to.d.ts +4 -0
- package/.out/transformers/flatteners/flatten_type_def_to.js +49 -0
- package/.out/transformers/flatteners/flatten_type_defs_of.d.ts +3 -0
- package/.out/transformers/flatteners/flatten_type_defs_of.js +7 -0
- package/.out/transformers/flatteners/flatten_value_type_to.d.ts +11 -0
- package/.out/transformers/flatteners/flatten_value_type_to.js +79 -0
- package/.out/transformers/flatteners/flatten_value_types_of.d.ts +3 -0
- package/.out/transformers/flatteners/flatten_value_types_of.js +7 -0
- package/.out/transformers/flatteners/json_path.d.ts +2 -0
- package/.out/transformers/flatteners/json_path.js +14 -0
- package/.out/transformers/flatteners/specs/flatten_accessors_of.tests.d.ts +1 -0
- package/.out/transformers/flatteners/specs/flatten_accessors_of.tests.js +90 -0
- package/.out/transformers/flatteners/specs/flatten_json_value_to_type_paths_of.tests.d.ts +1 -0
- package/.out/transformers/flatteners/specs/flatten_json_value_to_type_paths_of.tests.js +94 -0
- package/.out/transformers/flatteners/specs/flatten_type_def_to.tests.d.ts +1 -0
- package/.out/transformers/flatteners/specs/flatten_type_def_to.tests.js +110 -0
- package/.out/transformers/flatteners/specs/flatten_type_defs_of.tests.d.ts +1 -0
- package/.out/transformers/flatteners/specs/flatten_type_defs_of.tests.js +17 -0
- package/.out/transformers/flatteners/specs/flatten_value_type_to.tests.d.ts +1 -0
- package/.out/transformers/flatteners/specs/flatten_value_type_to.tests.js +297 -0
- package/.out/transformers/flatteners/specs/flatten_value_types_of.tests.d.ts +1 -0
- package/.out/transformers/flatteners/specs/flatten_value_types_of.tests.js +37 -0
- package/.out/transformers/flatteners/specs/value_path_to_type_path.tests.d.ts +1 -0
- package/.out/transformers/flatteners/specs/value_path_to_type_path.tests.js +167 -0
- package/.out/transformers/flatteners/value_path_to_type_path.d.ts +2 -0
- package/.out/transformers/flatteners/value_path_to_type_path.js +96 -0
- package/.out/tsconfig.json +15 -0
- package/.out/tsconfig.tsbuildinfo +1 -0
- package/.out/tsup.config.d.ts +3 -0
- package/.out/tsup.config.js +12 -0
- package/.out/types/builders.d.ts +62 -0
- package/.out/types/builders.js +148 -0
- package/.out/types/definitions.d.ts +41 -0
- package/.out/types/definitions.js +26 -0
- package/.out/types/flattened.d.ts +2 -0
- package/.out/types/flattened.js +1 -0
- package/.out/types/flattened_accessors_of.d.ts +9 -0
- package/.out/types/flattened_accessors_of.js +1 -0
- package/.out/types/flattened_type_defs_of.d.ts +21 -0
- package/.out/types/flattened_type_defs_of.js +1 -0
- package/.out/types/flattened_value_types_of.d.ts +6 -0
- package/.out/types/flattened_value_types_of.js +1 -0
- package/.out/types/json_path_of.d.ts +1 -0
- package/.out/types/json_path_of.js +1 -0
- package/.out/types/json_paths_of.d.ts +16 -0
- package/.out/types/json_paths_of.js +1 -0
- package/.out/types/mobx_value_type_of.d.ts +11 -0
- package/.out/types/mobx_value_type_of.js +2 -0
- package/.out/types/partial_type_def_of.d.ts +40 -0
- package/.out/types/partial_type_def_of.js +1 -0
- package/.out/types/readonly_type_def_of.d.ts +29 -0
- package/.out/types/readonly_type_def_of.js +1 -0
- package/.out/types/specs/builder.tests.d.ts +1 -0
- package/.out/types/specs/builder.tests.js +93 -0
- package/.out/types/specs/flattened_accessors_of.tests.d.ts +1 -0
- package/.out/types/specs/flattened_accessors_of.tests.js +11 -0
- package/.out/types/specs/flattened_type_defs_of.tests.d.ts +1 -0
- package/.out/types/specs/flattened_type_defs_of.tests.js +71 -0
- package/.out/types/specs/flattened_value_types_of.tests.d.ts +1 -0
- package/.out/types/specs/flattened_value_types_of.tests.js +11 -0
- package/.out/types/specs/json_paths_of.tests.d.ts +1 -0
- package/.out/types/specs/json_paths_of.tests.js +199 -0
- package/.out/types/specs/partial_type_def_of.tests.d.ts +1 -0
- package/.out/types/specs/partial_type_def_of.tests.js +50 -0
- package/.out/types/specs/readonly_type_def_of.tests.d.ts +1 -0
- package/.out/types/specs/readonly_type_def_of.tests.js +55 -0
- package/.out/types/specs/strict_definitions.tests.d.ts +1 -0
- package/.out/types/specs/strict_definitions.tests.js +42 -0
- package/.out/types/specs/value_to_type_paths_of.tests.d.ts +1 -0
- package/.out/types/specs/value_to_type_paths_of.tests.js +90 -0
- package/.out/types/specs/value_type_of.tests.d.ts +1 -0
- package/.out/types/specs/value_type_of.tests.js +91 -0
- package/.out/types/specs/value_types_of_discriminated_union.tests.d.ts +1 -0
- package/.out/types/specs/value_types_of_discriminated_union.tests.js +9 -0
- package/.out/types/strict_definitions.d.ts +44 -0
- package/.out/types/strict_definitions.js +1 -0
- package/.out/types/value_to_type_paths_of.d.ts +22 -0
- package/.out/types/value_to_type_paths_of.js +1 -0
- package/.out/types/value_type_of.d.ts +24 -0
- package/.out/types/value_type_of.js +1 -0
- package/.out/types/value_types_of_discriminated_union.d.ts +9 -0
- package/.out/types/value_types_of_discriminated_union.js +1 -0
- package/.out/vitest.workspace.d.ts +2 -0
- package/.out/vitest.workspace.js +7 -0
- package/.turbo/turbo-build.log +18 -0
- package/.turbo/turbo-check-types.log +3 -0
- package/.turbo/turbo-release$colon$exports.log +3 -0
- package/README.md +12 -0
- package/dist/index.cjs +798 -0
- package/dist/index.d.cts +301 -0
- package/dist/index.d.ts +301 -0
- package/dist/index.js +775 -0
- package/index.ts +20 -0
- package/package.exports.json +18 -0
- package/package.json +45 -0
- package/transformers/copies/copy.ts +18 -0
- package/transformers/copies/copy_to.ts +226 -0
- package/transformers/copies/mobx_copy.ts +81 -0
- package/transformers/copies/specs/copy_to.tests.ts +143 -0
- package/transformers/copies/specs/mobx_copy.tests.ts +26 -0
- package/transformers/flatteners/flatten_accessors_of.ts +43 -0
- package/transformers/flatteners/flatten_json_value_to_type_paths_of.ts +39 -0
- package/transformers/flatteners/flatten_type_def_to.ts +127 -0
- package/transformers/flatteners/flatten_type_defs_of.ts +16 -0
- package/transformers/flatteners/flatten_value_type_to.ts +227 -0
- package/transformers/flatteners/flatten_value_types_of.ts +23 -0
- package/transformers/flatteners/json_path.ts +15 -0
- package/transformers/flatteners/specs/flatten_accessors_of.tests.ts +113 -0
- package/transformers/flatteners/specs/flatten_json_value_to_type_paths_of.tests.ts +115 -0
- package/transformers/flatteners/specs/flatten_type_def_to.tests.ts +146 -0
- package/transformers/flatteners/specs/flatten_type_defs_of.tests.ts +26 -0
- package/transformers/flatteners/specs/flatten_value_type_to.tests.ts +452 -0
- package/transformers/flatteners/specs/flatten_value_types_of.tests.ts +46 -0
- package/transformers/flatteners/specs/value_path_to_type_path.tests.ts +240 -0
- package/transformers/flatteners/value_path_to_type_path.ts +164 -0
- package/tsconfig.build.json +11 -0
- package/tsconfig.json +15 -0
- package/tsup.config.ts +16 -0
- package/types/builders.ts +284 -0
- package/types/definitions.ts +106 -0
- package/types/flattened.ts +5 -0
- package/types/flattened_accessors_of.ts +15 -0
- package/types/flattened_type_defs_of.ts +130 -0
- package/types/flattened_value_types_of.ts +11 -0
- package/types/json_path_of.ts +7 -0
- package/types/json_paths_of.ts +129 -0
- package/types/mobx_value_type_of.ts +16 -0
- package/types/partial_type_def_of.ts +64 -0
- package/types/readonly_type_def_of.ts +53 -0
- package/types/specs/builder.tests.ts +295 -0
- package/types/specs/flattened_accessors_of.tests.ts +27 -0
- package/types/specs/flattened_type_defs_of.tests.ts +212 -0
- package/types/specs/flattened_value_types_of.tests.ts +21 -0
- package/types/specs/json_paths_of.tests.ts +304 -0
- package/types/specs/partial_type_def_of.tests.ts +251 -0
- package/types/specs/readonly_type_def_of.tests.ts +158 -0
- package/types/specs/strict_definitions.tests.ts +184 -0
- package/types/specs/value_to_type_paths_of.tests.ts +181 -0
- package/types/specs/value_type_of.tests.ts +329 -0
- package/types/specs/value_types_of_discriminated_union.tests.ts +30 -0
- package/types/strict_definitions.ts +107 -0
- package/types/value_to_type_paths_of.ts +184 -0
- package/types/value_type_of.ts +84 -0
- package/types/value_types_of_discriminated_union.ts +14 -0
- package/vitest.workspace.ts +11 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type IsFieldReadonly,
|
|
3
|
+
} from '@strictly/base'
|
|
4
|
+
import {
|
|
5
|
+
type ListTypeDef,
|
|
6
|
+
type LiteralTypeDef,
|
|
7
|
+
type ObjectFieldKey,
|
|
8
|
+
type ObjectTypeDef,
|
|
9
|
+
type RecordKeyType,
|
|
10
|
+
type RecordTypeDef,
|
|
11
|
+
type Type,
|
|
12
|
+
type TypeDef,
|
|
13
|
+
TypeDefType,
|
|
14
|
+
type UnionKey,
|
|
15
|
+
type UnionTypeDef,
|
|
16
|
+
} from './definitions'
|
|
17
|
+
|
|
18
|
+
class TypeDefBuilder<T extends TypeDef> implements Type<T> {
|
|
19
|
+
constructor(readonly definition: T) {
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
// returns just the relevant types, which can help typescript
|
|
23
|
+
// from complaining about infinitely deep data structures
|
|
24
|
+
get narrow(): Type<T> {
|
|
25
|
+
return {
|
|
26
|
+
definition: this.definition,
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
class LiteralTypeDefBuilder<T> extends TypeDefBuilder<LiteralTypeDef<T>> {
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
class ListTypeDefBuilder<
|
|
35
|
+
T extends ListTypeDef,
|
|
36
|
+
> extends TypeDefBuilder<T> {
|
|
37
|
+
readonly(): ListTypeDefBuilder<{
|
|
38
|
+
readonly type: TypeDefType.List,
|
|
39
|
+
readonly elements: T['elements'],
|
|
40
|
+
}> {
|
|
41
|
+
return this
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
class RecordTypeDefBuilder<T extends RecordTypeDef> extends TypeDefBuilder<T> {
|
|
46
|
+
partial(): IsFieldReadonly<T, 'valueTypeDef'> extends true ? RecordTypeDefBuilder<{
|
|
47
|
+
readonly type: TypeDefType.Record,
|
|
48
|
+
readonly keyPrototype: T['keyPrototype'],
|
|
49
|
+
readonly valueTypeDef: T['valueTypeDef'] | undefined,
|
|
50
|
+
}>
|
|
51
|
+
: RecordTypeDefBuilder<{
|
|
52
|
+
readonly type: TypeDefType.Record,
|
|
53
|
+
readonly keyPrototype: T['keyPrototype'],
|
|
54
|
+
valueTypeDef: T['valueTypeDef'] | undefined,
|
|
55
|
+
}>
|
|
56
|
+
{
|
|
57
|
+
return this
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
readonly(): RecordTypeDefBuilder<{
|
|
61
|
+
readonly type: TypeDefType.Record,
|
|
62
|
+
readonly keyPrototype: T['keyPrototype'],
|
|
63
|
+
readonly valueTypeDef: T['valueTypeDef'],
|
|
64
|
+
}> {
|
|
65
|
+
return this
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
class ObjectTypeDefBuilder<
|
|
70
|
+
Fields extends Readonly<Record<ObjectFieldKey, TypeDef>> = {},
|
|
71
|
+
> extends TypeDefBuilder<
|
|
72
|
+
ObjectTypeDef<Fields>
|
|
73
|
+
> {
|
|
74
|
+
set<
|
|
75
|
+
Name extends string,
|
|
76
|
+
T extends TypeDef,
|
|
77
|
+
>(
|
|
78
|
+
name: Name,
|
|
79
|
+
{ definition: typeDef }: Type<T>,
|
|
80
|
+
): ObjectTypeDefBuilder<
|
|
81
|
+
Fields & Record<Name, T>
|
|
82
|
+
> {
|
|
83
|
+
const newFields = {
|
|
84
|
+
[name]: typeDef,
|
|
85
|
+
}
|
|
86
|
+
// have to explicitly supply types as TS will infinitely recurse trying to infer them!
|
|
87
|
+
return new ObjectTypeDefBuilder<
|
|
88
|
+
Fields & Record<Name, T>
|
|
89
|
+
>({
|
|
90
|
+
type: TypeDefType.Object,
|
|
91
|
+
fields: {
|
|
92
|
+
...this.definition.fields,
|
|
93
|
+
...newFields,
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
setReadonly<
|
|
99
|
+
Name extends string,
|
|
100
|
+
T extends TypeDef,
|
|
101
|
+
>(
|
|
102
|
+
name: Name,
|
|
103
|
+
{ definition: typeDef }: Type<T>,
|
|
104
|
+
): ObjectTypeDefBuilder<
|
|
105
|
+
Fields & Readonly<Record<Name, T>>
|
|
106
|
+
> {
|
|
107
|
+
const newFields = {
|
|
108
|
+
[name]: typeDef,
|
|
109
|
+
}
|
|
110
|
+
// have to explicitly supply types as TS will infinitely recurse trying to infer them!
|
|
111
|
+
return new ObjectTypeDefBuilder<
|
|
112
|
+
Fields & Readonly<Record<Name, T>>
|
|
113
|
+
>({
|
|
114
|
+
type: TypeDefType.Object,
|
|
115
|
+
fields: {
|
|
116
|
+
...this.definition.fields,
|
|
117
|
+
...newFields,
|
|
118
|
+
},
|
|
119
|
+
})
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
setOptional<
|
|
123
|
+
Name extends string,
|
|
124
|
+
T extends TypeDef,
|
|
125
|
+
>(
|
|
126
|
+
name: Name,
|
|
127
|
+
{ definition: typeDef }: Type<T>,
|
|
128
|
+
): ObjectTypeDefBuilder<
|
|
129
|
+
Fields & Partial<Record<Name, T>>
|
|
130
|
+
> {
|
|
131
|
+
const newFields = {
|
|
132
|
+
[name]: typeDef,
|
|
133
|
+
}
|
|
134
|
+
// have to explicitly supply types as TS will infinitely recurse trying to infer them!
|
|
135
|
+
return new ObjectTypeDefBuilder<
|
|
136
|
+
Fields & Partial<Record<Name, T>>
|
|
137
|
+
>({
|
|
138
|
+
type: TypeDefType.Object,
|
|
139
|
+
fields: {
|
|
140
|
+
...this.definition.fields,
|
|
141
|
+
...newFields,
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
setReadonlyOptional<
|
|
147
|
+
Name extends string,
|
|
148
|
+
T extends TypeDef,
|
|
149
|
+
>(
|
|
150
|
+
name: Name,
|
|
151
|
+
{ definition: typeDef }: Type<T>,
|
|
152
|
+
): ObjectTypeDefBuilder<
|
|
153
|
+
Fields & Partial<Readonly<Record<Name, T>>>
|
|
154
|
+
> {
|
|
155
|
+
const newFields = {
|
|
156
|
+
[name]: typeDef,
|
|
157
|
+
}
|
|
158
|
+
// have to explicitly supply types as TS will infinitely recurse trying to infer them!
|
|
159
|
+
return new ObjectTypeDefBuilder<
|
|
160
|
+
Fields & Partial<Readonly<Record<Name, T>>>
|
|
161
|
+
>({
|
|
162
|
+
type: TypeDefType.Object,
|
|
163
|
+
fields: {
|
|
164
|
+
...this.definition.fields,
|
|
165
|
+
...newFields,
|
|
166
|
+
},
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
class UnionTypeDefBuilder<
|
|
172
|
+
D extends string | null,
|
|
173
|
+
U extends Record<UnionKey, TypeDef>,
|
|
174
|
+
> extends TypeDefBuilder<
|
|
175
|
+
UnionTypeDef<
|
|
176
|
+
D,
|
|
177
|
+
U
|
|
178
|
+
>
|
|
179
|
+
> {
|
|
180
|
+
add<
|
|
181
|
+
K extends Exclude<UnionKey, keyof U>,
|
|
182
|
+
T extends TypeDef,
|
|
183
|
+
>(
|
|
184
|
+
k: K,
|
|
185
|
+
{
|
|
186
|
+
definition: typeDef,
|
|
187
|
+
}: Type<T>,
|
|
188
|
+
): UnionTypeDefBuilder<D, Readonly<Record<K, T>> & U> {
|
|
189
|
+
const {
|
|
190
|
+
discriminator,
|
|
191
|
+
unions,
|
|
192
|
+
} = this.definition
|
|
193
|
+
return new UnionTypeDefBuilder<D, Readonly<Record<K, T>> & U>(
|
|
194
|
+
{
|
|
195
|
+
type: TypeDefType.Union,
|
|
196
|
+
discriminator: discriminator,
|
|
197
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
198
|
+
unions: {
|
|
199
|
+
...unions,
|
|
200
|
+
[k]: typeDef,
|
|
201
|
+
} as Readonly<Record<K, T>> & U,
|
|
202
|
+
},
|
|
203
|
+
)
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
export function literal<T>(value?: [T]): LiteralTypeDefBuilder<T> {
|
|
208
|
+
return new LiteralTypeDefBuilder({
|
|
209
|
+
type: TypeDefType.Literal,
|
|
210
|
+
valuePrototype: value!,
|
|
211
|
+
})
|
|
212
|
+
}
|
|
213
|
+
|
|
214
|
+
export const stringType = literal<string>()
|
|
215
|
+
export const numberType = literal<number>()
|
|
216
|
+
export const booleanType = literal<boolean>()
|
|
217
|
+
export const nullType = literal([null])
|
|
218
|
+
|
|
219
|
+
export function nullable<T extends TypeDef>(nonNullable: Type<T>): UnionTypeDefBuilder<null, {
|
|
220
|
+
readonly ['0']: T,
|
|
221
|
+
readonly ['1']: LiteralTypeDef<null>,
|
|
222
|
+
}> {
|
|
223
|
+
return new UnionTypeDefBuilder(
|
|
224
|
+
{
|
|
225
|
+
type: TypeDefType.Union,
|
|
226
|
+
discriminator: null,
|
|
227
|
+
unions: {
|
|
228
|
+
['0']: nonNullable.definition,
|
|
229
|
+
['1']: nullType.definition,
|
|
230
|
+
},
|
|
231
|
+
},
|
|
232
|
+
)
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
export function list<T extends TypeDef>(elements: Type<T>): ListTypeDefBuilder<{
|
|
236
|
+
readonly type: TypeDefType.List,
|
|
237
|
+
elements: T,
|
|
238
|
+
}> {
|
|
239
|
+
// have to explicitly supply types as TS will infinitely recurse trying to infer them!
|
|
240
|
+
return new ListTypeDefBuilder<ListTypeDef<T>>({
|
|
241
|
+
type: TypeDefType.List,
|
|
242
|
+
elements: elements.definition,
|
|
243
|
+
})
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
export function record<
|
|
247
|
+
V extends Type,
|
|
248
|
+
// NOTE if we swap these generics and the caller forgets to supply the second one (so the Type)
|
|
249
|
+
// TSC will freeze
|
|
250
|
+
K extends RecordKeyType,
|
|
251
|
+
>({ definition: typeDef }: V) {
|
|
252
|
+
return new RecordTypeDefBuilder<{
|
|
253
|
+
readonly type: TypeDefType.Record,
|
|
254
|
+
readonly keyPrototype: K,
|
|
255
|
+
valueTypeDef: V['definition'],
|
|
256
|
+
}>({
|
|
257
|
+
type: TypeDefType.Record,
|
|
258
|
+
// eslint-disable-next-line no-undefined
|
|
259
|
+
keyPrototype: undefined!,
|
|
260
|
+
valueTypeDef: typeDef,
|
|
261
|
+
})
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
export function object(): ObjectTypeDefBuilder<{}> {
|
|
265
|
+
// have to explicitly supply types as TS will infinitely recurse trying to infer them!
|
|
266
|
+
return new ObjectTypeDefBuilder<{}>({
|
|
267
|
+
type: TypeDefType.Object,
|
|
268
|
+
fields: {},
|
|
269
|
+
})
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
export function union<D extends null>(): UnionTypeDefBuilder<D, {}>
|
|
273
|
+
export function union<D extends string>(discriminator: D): UnionTypeDefBuilder<D, {}>
|
|
274
|
+
export function union<D extends string | null>(discriminator?: D): UnionTypeDefBuilder<D, {}> {
|
|
275
|
+
// have to explicitly supply types as TS will infinitely recurse trying to infer them!
|
|
276
|
+
return new UnionTypeDefBuilder<D, {}>(
|
|
277
|
+
{
|
|
278
|
+
type: TypeDefType.Union,
|
|
279
|
+
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
|
|
280
|
+
discriminator: (discriminator ?? null) as D,
|
|
281
|
+
unions: {},
|
|
282
|
+
},
|
|
283
|
+
)
|
|
284
|
+
}
|
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
// NOTE: this file, in conjunction with the types that derive information from these types, pushes the
|
|
2
|
+
// Typescript compiler to its absolute limit. It tends to be a death of 1000 cuts so no individual feature
|
|
3
|
+
// breaks it. When combined they hit some threshold (memory? performance? time?) beyond which the compiler
|
|
4
|
+
// gives up. To avoid problems try to follow these guidelines
|
|
5
|
+
// 1. Keep types as simple as possible.
|
|
6
|
+
// If you find yourself having to unwrap a bunch of boolean flags (for example) you're probably going to encounter issues
|
|
7
|
+
// 2. Only expose externally, and pass internally, the absolute minimum information information you need
|
|
8
|
+
// TS tends to get overwhelmed, where you can, narrow the types that are being returned to just the information
|
|
9
|
+
// the caller needs
|
|
10
|
+
// 3. Take advantage of helper functions to hide complexity/fragility from client code
|
|
11
|
+
// 4. Manually unroll complex operations
|
|
12
|
+
// Typescript can choke on things like the below, however you can manually do a full implementation where you
|
|
13
|
+
// check each type and return the appropriate value, and that seems to work.
|
|
14
|
+
// ```
|
|
15
|
+
// type HomogeneousFattenedValue<T extends TypeDef, V> = { [K in keyof FlattenedOf<T>]?: V }
|
|
16
|
+
// ```
|
|
17
|
+
// 5. Use longhand { [s: string]: number } instead of Record<string, number> when doing transformations and
|
|
18
|
+
// defining types
|
|
19
|
+
|
|
20
|
+
export type Type<T extends TypeDef = TypeDef> = {
|
|
21
|
+
readonly definition: T,
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export type TypeDef =
|
|
25
|
+
| LiteralTypeDef
|
|
26
|
+
| ListTypeDef
|
|
27
|
+
| RecordTypeDef
|
|
28
|
+
| ObjectTypeDef
|
|
29
|
+
| UnionTypeDef
|
|
30
|
+
|
|
31
|
+
export enum TypeDefType {
|
|
32
|
+
Literal = 1,
|
|
33
|
+
List,
|
|
34
|
+
Record,
|
|
35
|
+
Object,
|
|
36
|
+
Union,
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
// used to avoid TS complaining about circular references
|
|
40
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
41
|
+
type AnyTypeDef = any
|
|
42
|
+
|
|
43
|
+
// literal
|
|
44
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
45
|
+
export type LiteralTypeDef<V = any> = {
|
|
46
|
+
readonly type: TypeDefType.Literal,
|
|
47
|
+
readonly valuePrototype: [V],
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
// list
|
|
51
|
+
export type ListTypeDef<
|
|
52
|
+
E extends TypeDef = AnyTypeDef,
|
|
53
|
+
> = {
|
|
54
|
+
readonly type: TypeDefType.List,
|
|
55
|
+
// readonly is inherited by the output
|
|
56
|
+
readonly elements: E,
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// map
|
|
60
|
+
export type RecordKeyType = string | number
|
|
61
|
+
|
|
62
|
+
// might be able to combine map and list into a single "homogeneous" type def with an implementation
|
|
63
|
+
// hint, which might help with performance
|
|
64
|
+
export type RecordTypeDef<
|
|
65
|
+
K extends RecordKeyType = RecordKeyType,
|
|
66
|
+
// if `V` includes `undefined` the map is partial
|
|
67
|
+
V extends TypeDef | undefined = AnyTypeDef,
|
|
68
|
+
> = {
|
|
69
|
+
readonly type: TypeDefType.Record,
|
|
70
|
+
// never actually populate
|
|
71
|
+
readonly keyPrototype: K,
|
|
72
|
+
// readonly is inherited by the output
|
|
73
|
+
readonly valueTypeDef: V,
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
// structured type
|
|
77
|
+
// could be replaced with a map and an intersection
|
|
78
|
+
export type ObjectFieldKey = string | number
|
|
79
|
+
|
|
80
|
+
// NOTE we use the `readonly` and `?` (partial) status of these field definitions
|
|
81
|
+
// to describe the same attributes of the fields
|
|
82
|
+
export type ObjectTypeDefFields = {
|
|
83
|
+
[Key: ObjectFieldKey]: AnyTypeDef,
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// NOTE: we cannot collapse this type to
|
|
87
|
+
// `StructuredTypeDef = StructuredTypeDefFields`
|
|
88
|
+
// as we rely on the `fields` field being unique to discriminate between different
|
|
89
|
+
// TypeDefs
|
|
90
|
+
export type ObjectTypeDef<
|
|
91
|
+
Fields extends ObjectTypeDefFields = ObjectTypeDefFields,
|
|
92
|
+
> = {
|
|
93
|
+
readonly type: TypeDefType.Object,
|
|
94
|
+
readonly fields: Fields,
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export type UnionKey = string
|
|
98
|
+
|
|
99
|
+
export type UnionTypeDef<
|
|
100
|
+
D extends string | null = string | null,
|
|
101
|
+
U extends Readonly<Record<UnionKey, AnyTypeDef>> = Readonly<Record<UnionKey, AnyTypeDef>>,
|
|
102
|
+
> = {
|
|
103
|
+
readonly discriminator: D,
|
|
104
|
+
readonly type: TypeDefType.Union,
|
|
105
|
+
readonly unions: U,
|
|
106
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
// Unfortunately the TS compiler will infinitely loop if we don't give it a way of breaking out.
|
|
2
|
+
// A starting depth of 10 (the maximum) will cause performance issues while developing
|
|
3
|
+
export type StartingDepth = 8
|
|
4
|
+
// Going much above a depth of 10 will also blow up
|
|
5
|
+
export type Depths = [-1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { type Type } from './definitions'
|
|
2
|
+
import { type FlattenedValueTypesOf } from './flattened_value_types_of'
|
|
3
|
+
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5
|
+
export type Accessor<T = any> = {
|
|
6
|
+
readonly value: T,
|
|
7
|
+
set(v: T): void,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export type FlattenedAccessorsOf<
|
|
11
|
+
T extends Type,
|
|
12
|
+
Flattened extends Readonly<Record<string, Accessor>> = FlattenedValueTypesOf<T>,
|
|
13
|
+
> = {
|
|
14
|
+
readonly [K in keyof Flattened]: Accessor<Flattened[K]>
|
|
15
|
+
}
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type UnionToIntersection,
|
|
3
|
+
} from 'type-fest'
|
|
4
|
+
import {
|
|
5
|
+
type ListTypeDef,
|
|
6
|
+
type LiteralTypeDef,
|
|
7
|
+
type ObjectTypeDef,
|
|
8
|
+
type RecordTypeDef,
|
|
9
|
+
type Type,
|
|
10
|
+
type TypeDef,
|
|
11
|
+
type UnionTypeDef,
|
|
12
|
+
} from './definitions'
|
|
13
|
+
import {
|
|
14
|
+
type Depths,
|
|
15
|
+
type StartingDepth,
|
|
16
|
+
} from './flattened'
|
|
17
|
+
import { type JsonPathOf } from './json_path_of'
|
|
18
|
+
|
|
19
|
+
// NOTE removing any ternary from this file improves the performance and the depth of data structure we can go to
|
|
20
|
+
|
|
21
|
+
export type FlattenedTypeDefsOf<
|
|
22
|
+
T extends Type,
|
|
23
|
+
SegmentOverride extends string | null,
|
|
24
|
+
Path extends string = '$',
|
|
25
|
+
Depth extends number = StartingDepth,
|
|
26
|
+
> = InternalFlattenedTypeDefsOf<T['definition'], SegmentOverride, Path, '', Depth>
|
|
27
|
+
|
|
28
|
+
type InternalFlattenedTypeDefsOf<
|
|
29
|
+
T extends TypeDef,
|
|
30
|
+
SegmentOverride extends string | null,
|
|
31
|
+
Path extends string,
|
|
32
|
+
Qualifier extends string,
|
|
33
|
+
Depth extends number,
|
|
34
|
+
> =
|
|
35
|
+
& {
|
|
36
|
+
readonly [K in Path]: Type<T>
|
|
37
|
+
}
|
|
38
|
+
& InternalFlattenedTypeDefsOfChildren<T, SegmentOverride, Path, Qualifier, Depth>
|
|
39
|
+
|
|
40
|
+
type InternalFlattenedTypeDefsOfChildren<
|
|
41
|
+
T extends TypeDef,
|
|
42
|
+
SegmentOverride extends string | null,
|
|
43
|
+
Path extends string,
|
|
44
|
+
Qualifier extends string,
|
|
45
|
+
Depth extends number,
|
|
46
|
+
NextDepth extends number = Depths[Depth],
|
|
47
|
+
> =
|
|
48
|
+
// resolve anything too deep to `never` instead of to {} so the caller knows
|
|
49
|
+
// it has explicitly failed
|
|
50
|
+
NextDepth extends -1 ? never
|
|
51
|
+
: T extends LiteralTypeDef ? InternalFlattenedTypeDefsOfLiteralChildren
|
|
52
|
+
: T extends ListTypeDef ? InternalFlattenedTypeDefsOfListChildren<T, SegmentOverride, Path, NextDepth>
|
|
53
|
+
: T extends RecordTypeDef ? InternalFlattenedTypeDefsOfRecordChildren<T, SegmentOverride, Path, NextDepth>
|
|
54
|
+
: T extends ObjectTypeDef
|
|
55
|
+
? InternalFlattenedTypeDefsOfObjectChildren<T, SegmentOverride, Path, Qualifier, NextDepth>
|
|
56
|
+
: T extends UnionTypeDef ? InternalFlattenedTypeDefsOfUnionChildren<T, SegmentOverride, Path, Qualifier, NextDepth>
|
|
57
|
+
: never
|
|
58
|
+
|
|
59
|
+
type InternalFlattenedTypeDefsOfLiteralChildren = {}
|
|
60
|
+
|
|
61
|
+
type InternalFlattenedTypeDefsOfListChildren<
|
|
62
|
+
T extends ListTypeDef,
|
|
63
|
+
SegmentOverride extends string | null,
|
|
64
|
+
Path extends string,
|
|
65
|
+
Depth extends number,
|
|
66
|
+
> = InternalFlattenedTypeDefsOf<
|
|
67
|
+
T['elements'],
|
|
68
|
+
SegmentOverride,
|
|
69
|
+
JsonPathOf<Path, number, SegmentOverride>,
|
|
70
|
+
'',
|
|
71
|
+
Depth
|
|
72
|
+
>
|
|
73
|
+
|
|
74
|
+
type InternalFlattenedTypeDefsOfRecordChildren<
|
|
75
|
+
T extends RecordTypeDef,
|
|
76
|
+
SegmentOverride extends string | null,
|
|
77
|
+
Path extends string,
|
|
78
|
+
Depth extends number,
|
|
79
|
+
> = InternalFlattenedTypeDefsOf<
|
|
80
|
+
T['valueTypeDef'],
|
|
81
|
+
SegmentOverride,
|
|
82
|
+
JsonPathOf<Path, T['keyPrototype'], SegmentOverride>,
|
|
83
|
+
'',
|
|
84
|
+
Depth
|
|
85
|
+
>
|
|
86
|
+
|
|
87
|
+
type InternalFlattenedTypeDefsOfObjectChildren<
|
|
88
|
+
T extends ObjectTypeDef,
|
|
89
|
+
SegmentOverride extends string | null,
|
|
90
|
+
Path extends string,
|
|
91
|
+
Qualifier extends string,
|
|
92
|
+
Depth extends number,
|
|
93
|
+
> = T extends ObjectTypeDef<infer Fields> ? {} extends Fields ? {} : keyof Fields extends string ? UnionToIntersection<{
|
|
94
|
+
readonly [K in keyof Fields]-?: InternalFlattenedTypeDefsOf<
|
|
95
|
+
Exclude<Fields[K], undefined>,
|
|
96
|
+
SegmentOverride,
|
|
97
|
+
JsonPathOf<Path, `${Qualifier}${K}`, null>,
|
|
98
|
+
'',
|
|
99
|
+
Depth
|
|
100
|
+
>
|
|
101
|
+
}[keyof Fields]>
|
|
102
|
+
: never
|
|
103
|
+
: never
|
|
104
|
+
|
|
105
|
+
type InternalFlattenedTypeDefsOfUnionChildren<
|
|
106
|
+
T extends UnionTypeDef,
|
|
107
|
+
SegmentOverride extends string | null,
|
|
108
|
+
Path extends string,
|
|
109
|
+
Qualifier extends string,
|
|
110
|
+
Depth extends number,
|
|
111
|
+
> = T extends UnionTypeDef<infer D, infer Unions> ? keyof Unions extends string ? D extends null ? UnionToIntersection<{
|
|
112
|
+
readonly [K in keyof Unions]: InternalFlattenedTypeDefsOfChildren<
|
|
113
|
+
Unions[K],
|
|
114
|
+
SegmentOverride,
|
|
115
|
+
Path,
|
|
116
|
+
'',
|
|
117
|
+
Depth
|
|
118
|
+
>
|
|
119
|
+
}[keyof Unions]>
|
|
120
|
+
: UnionToIntersection<{
|
|
121
|
+
readonly [K in keyof Unions]: InternalFlattenedTypeDefsOfChildren<
|
|
122
|
+
Unions[K],
|
|
123
|
+
SegmentOverride,
|
|
124
|
+
Path,
|
|
125
|
+
`${Qualifier}${K}:`,
|
|
126
|
+
Depth
|
|
127
|
+
>
|
|
128
|
+
}[keyof Unions]>
|
|
129
|
+
: never
|
|
130
|
+
: never
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Type } from './definitions'
|
|
2
|
+
import { type FlattenedTypeDefsOf } from './flattened_type_defs_of'
|
|
3
|
+
import { type ValueTypeOf } from './value_type_of'
|
|
4
|
+
|
|
5
|
+
export type FlattenedValueTypesOf<
|
|
6
|
+
T extends Type,
|
|
7
|
+
SegmentOverride extends string | null = null,
|
|
8
|
+
Flattened extends Readonly<Record<string, Type>> = FlattenedTypeDefsOf<T, SegmentOverride>,
|
|
9
|
+
> = {
|
|
10
|
+
[K in keyof Flattened]: ValueTypeOf<Flattened[K], {}>
|
|
11
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type JsonPathOf<
|
|
2
|
+
Prefix extends string,
|
|
3
|
+
Accessor extends string | number | symbol,
|
|
4
|
+
SegmentOverride extends string | null = null,
|
|
5
|
+
> = SegmentOverride extends string ? `${Prefix}.${SegmentOverride}`
|
|
6
|
+
: Accessor extends string | number ? `${Prefix}.${Accessor}`
|
|
7
|
+
: never
|
|
@@ -0,0 +1,129 @@
|
|
|
1
|
+
import {
|
|
2
|
+
type ListTypeDef,
|
|
3
|
+
type LiteralTypeDef,
|
|
4
|
+
type ObjectTypeDef,
|
|
5
|
+
type RecordTypeDef,
|
|
6
|
+
type Type,
|
|
7
|
+
type TypeDef,
|
|
8
|
+
type UnionTypeDef,
|
|
9
|
+
} from './definitions'
|
|
10
|
+
import {
|
|
11
|
+
type Depths,
|
|
12
|
+
type StartingDepth,
|
|
13
|
+
} from './flattened'
|
|
14
|
+
import { type JsonPathOf } from './json_path_of'
|
|
15
|
+
|
|
16
|
+
export type JsonPathsOf<
|
|
17
|
+
T extends Type,
|
|
18
|
+
SegmentOverride extends string | null = null,
|
|
19
|
+
Prefix extends string = '$',
|
|
20
|
+
> = InternalJsonPathsOf<T['definition'], Prefix, SegmentOverride, StartingDepth>
|
|
21
|
+
|
|
22
|
+
export type InternalJsonPathsOf<
|
|
23
|
+
F extends TypeDef,
|
|
24
|
+
Prefix extends string,
|
|
25
|
+
SegmentOverride extends string | null,
|
|
26
|
+
// TODO maybe depth isn't necessary here?
|
|
27
|
+
Depth extends number,
|
|
28
|
+
NextDepth extends number = Depths[Depth],
|
|
29
|
+
> = InternalJsonPathsOfChildren<F, Prefix, SegmentOverride, '', NextDepth> | Prefix
|
|
30
|
+
|
|
31
|
+
type InternalJsonPathsOfChildren<
|
|
32
|
+
F extends TypeDef,
|
|
33
|
+
Prefix extends string,
|
|
34
|
+
SegmentOverride extends string | null,
|
|
35
|
+
Qualifier extends string,
|
|
36
|
+
Depth extends number,
|
|
37
|
+
> = Depth extends -1 ? never
|
|
38
|
+
: F extends LiteralTypeDef ? InternalJsonPathsOfLiteralChildren
|
|
39
|
+
: F extends ListTypeDef ? InternalJsonPathsOfListChildren<F, Prefix, SegmentOverride, Depth>
|
|
40
|
+
: F extends RecordTypeDef ? InternalJsonPathsOfRecordChildren<F, Prefix, SegmentOverride, Depth>
|
|
41
|
+
: F extends ObjectTypeDef ? InternalJsonPathsOfObjectChildren<F, Prefix, SegmentOverride, Qualifier, Depth>
|
|
42
|
+
: F extends UnionTypeDef ? InternalJsonPathsOfUnionChildren<
|
|
43
|
+
F,
|
|
44
|
+
Prefix,
|
|
45
|
+
SegmentOverride,
|
|
46
|
+
Qualifier,
|
|
47
|
+
Depth
|
|
48
|
+
>
|
|
49
|
+
: never
|
|
50
|
+
|
|
51
|
+
type InternalJsonPathsOfLiteralChildren = never
|
|
52
|
+
|
|
53
|
+
type InternalJsonPathsOfListChildren<
|
|
54
|
+
F extends ListTypeDef,
|
|
55
|
+
Prefix extends string,
|
|
56
|
+
SegmentOverride extends string | null,
|
|
57
|
+
Depth extends number,
|
|
58
|
+
> = InternalJsonPathsOf<
|
|
59
|
+
F['elements'],
|
|
60
|
+
JsonPathOf<
|
|
61
|
+
Prefix,
|
|
62
|
+
number,
|
|
63
|
+
SegmentOverride
|
|
64
|
+
>,
|
|
65
|
+
SegmentOverride,
|
|
66
|
+
Depth
|
|
67
|
+
>
|
|
68
|
+
|
|
69
|
+
type InternalJsonPathsOfRecordChildren<
|
|
70
|
+
F extends RecordTypeDef,
|
|
71
|
+
Prefix extends string,
|
|
72
|
+
SegmentOverride extends string | null,
|
|
73
|
+
Depth extends number,
|
|
74
|
+
> = InternalJsonPathsOf<
|
|
75
|
+
F['valueTypeDef'],
|
|
76
|
+
JsonPathOf<
|
|
77
|
+
Prefix,
|
|
78
|
+
F['keyPrototype'],
|
|
79
|
+
SegmentOverride
|
|
80
|
+
>,
|
|
81
|
+
SegmentOverride,
|
|
82
|
+
Depth
|
|
83
|
+
>
|
|
84
|
+
|
|
85
|
+
type InternalJsonPathsOfObjectChildren<
|
|
86
|
+
F extends ObjectTypeDef,
|
|
87
|
+
Prefix extends string,
|
|
88
|
+
SegmentOverride extends string | null,
|
|
89
|
+
Qualifier extends string,
|
|
90
|
+
Depth extends number,
|
|
91
|
+
> = F extends ObjectTypeDef<infer Fields> ? keyof Fields extends string ? {
|
|
92
|
+
[K in keyof Fields]: InternalJsonPathsOf<
|
|
93
|
+
Fields[K],
|
|
94
|
+
JsonPathOf<
|
|
95
|
+
Prefix,
|
|
96
|
+
`${Qualifier}${K}`,
|
|
97
|
+
null
|
|
98
|
+
>,
|
|
99
|
+
SegmentOverride,
|
|
100
|
+
Depth
|
|
101
|
+
>
|
|
102
|
+
}[keyof Fields]
|
|
103
|
+
: never
|
|
104
|
+
: never
|
|
105
|
+
|
|
106
|
+
type InternalJsonPathsOfUnionChildren<
|
|
107
|
+
F extends UnionTypeDef,
|
|
108
|
+
Prefix extends string,
|
|
109
|
+
SegmentOverride extends string | null,
|
|
110
|
+
Qualifier extends string,
|
|
111
|
+
Depth extends number,
|
|
112
|
+
> // typescript cannot infer the key in unions unless we get the value directly
|
|
113
|
+
= F extends UnionTypeDef<infer D, infer Unions> ? keyof Unions extends string ? {
|
|
114
|
+
readonly [K in keyof Unions]: InternalJsonPathsOfChildren<
|
|
115
|
+
Unions[K],
|
|
116
|
+
// This will overload paths, but we don't actually care about that here
|
|
117
|
+
// I think what we should do is have a "denormalize of", which you can then
|
|
118
|
+
// get the paths of if you want the unique paths
|
|
119
|
+
// (alt PrefixOf<Prefix, K>,)
|
|
120
|
+
Prefix,
|
|
121
|
+
SegmentOverride,
|
|
122
|
+
D extends null ? Qualifier : `${Qualifier}${K}:`,
|
|
123
|
+
Depth
|
|
124
|
+
>
|
|
125
|
+
}[keyof Unions]
|
|
126
|
+
// do not expose the discriminator as we cannot set this value independently
|
|
127
|
+
// | (D extends string ? JsonPathOf<Prefix, D, null, Qualifier> : never)
|
|
128
|
+
: never
|
|
129
|
+
: never
|