@strictly/define 0.0.12 → 0.0.14

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 (34) hide show
  1. package/.out/transformers/flatteners/json_path.d.ts +6 -2
  2. package/.out/transformers/flatteners/json_path.js +15 -2
  3. package/.out/transformers/flatteners/specs/json_paths.tests.d.ts +1 -0
  4. package/.out/transformers/flatteners/specs/json_paths.tests.js +50 -0
  5. package/.out/tsconfig.tsbuildinfo +1 -1
  6. package/.out/types/builders.d.ts +21 -20
  7. package/.out/types/builders.js +8 -5
  8. package/.out/types/flattened_types_of_validating_type.d.ts +4 -4
  9. package/.out/types/flattened_validators_of_validating_type.d.ts +7 -6
  10. package/.out/types/specs/flattened_validators_of_validating_type.tests.js +2 -2
  11. package/.out/types/validating_definitions.d.ts +14 -12
  12. package/.out/types/validating_type_def_with_error.d.ts +13 -13
  13. package/.out/validation/validator.d.ts +1 -0
  14. package/.out/validation/validator.js +4 -0
  15. package/.out/validation/validators/composite_validator.d.ts +7 -0
  16. package/.out/validation/validators/composite_validator.js +32 -0
  17. package/.turbo/turbo-build.log +8 -8
  18. package/.turbo/turbo-check-types.log +1 -1
  19. package/dist/index.cjs +86 -33
  20. package/dist/index.d.cts +85 -79
  21. package/dist/index.d.ts +85 -79
  22. package/dist/index.js +62 -9
  23. package/package.json +1 -1
  24. package/transformers/flatteners/json_path.ts +44 -4
  25. package/transformers/flatteners/specs/json_paths.tests.ts +69 -0
  26. package/types/builders.ts +46 -26
  27. package/types/flattened_types_of_validating_type.ts +5 -2
  28. package/types/flattened_validators_of_validating_type.ts +7 -9
  29. package/types/specs/builder.tests.ts +31 -31
  30. package/types/specs/flattened_validators_of_validating_type.tests.ts +7 -7
  31. package/types/validating_definitions.ts +27 -15
  32. package/types/validating_type_def_with_error.ts +23 -23
  33. package/validation/validator.ts +21 -0
  34. package/validation/validators/composite_validator.ts +42 -0
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { IsEqual, Simplify, UnionToIntersection, SimplifyDeep } from 'type-fest';
2
- import { IsFieldReadonly } from '@strictly/base';
2
+ import { IsFieldReadonly, StringConcatOf } from '@strictly/base';
3
3
 
4
4
  type Type<T extends TypeDef = TypeDef> = {
5
5
  readonly definition: T;
@@ -198,50 +198,75 @@ declare function flattenJsonValueToTypePathsOf<T extends Type, R extends Record<
198
198
 
199
199
  declare function flattenTypesOfType<T extends StrictType>(t: T): Record<string, Type>;
200
200
 
201
+ type Annotations = {
202
+ readonly required: boolean;
203
+ readonly readonly: boolean;
204
+ };
205
+ type FunctionalValidator<V = any, E = any, ValuePath extends string = any, Context = any> = (v: V, valuePath: ValuePath, context: Context) => E | null;
206
+ type AnnotatedValidator<V = any, E = any, ValuePath extends string = any, Context = any> = {
207
+ readonly validate: (v: V, valuePath: ValuePath, context: Context) => E | null;
208
+ readonly annotations: (valuePath: ValuePath, context: Context) => Annotations;
209
+ };
210
+ type Validator<V = any, E = any, ValuePath extends string = any, Context = any> = FunctionalValidator<V, E, ValuePath, Context> | AnnotatedValidator<V, E, ValuePath, Context>;
211
+ type ErrorOfValidator<V extends Validator> = V extends Validator<infer _V, infer E> ? E : never;
212
+ type ValidationError<Type extends string, Data = {}> = Simplify<{
213
+ type: Type;
214
+ } & Data>;
215
+ declare function isFunctionalValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is FunctionalValidator<V, E, ValuePath, Context>;
216
+ declare function isAnnotatedValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is AnnotatedValidator<V, E, ValuePath, Context>;
217
+ declare function validate<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, v: V, valuePath: ValuePath, context: Context): E | null;
218
+ declare function mergeValidators<V = any, E1 = any, E2 = any, ValuePath extends string = any, C1 = any, C2 = any>(v1: Validator<V, E1, ValuePath, C1>, v2: Validator<V, E2, ValuePath, C2>): Validator<V, E1 | E2, ValuePath, C1 & C2>;
219
+ declare function annotations<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, valuePath: ValuePath, context: Context): Annotations;
220
+ declare function mergeAnnotations(a1: Annotations, a2: Annotations): {
221
+ readonly: boolean;
222
+ required: boolean;
223
+ };
224
+
201
225
  type ValidatingType<T extends ValidatingTypeDef = ValidatingTypeDef> = {
202
226
  readonly definition: T;
203
227
  };
204
- type Rule<E = any, V = any> = (v: V) => E | null;
205
228
  type ErrorOfValidatingTypeDef<T extends ValidatingTypeDef> = T extends ValidatingTypeDef<infer E> ? E : never;
206
- type ValidatingTypeDef<E = any> = ValidatingLiteralTypeDef<E> | ValidatingListTypeDef<E> | ValidatingRecordTypeDef<E> | ValidatingObjectTypeDef<E> | ValidatingUnionTypeDef<E>;
229
+ type ContextOfValidatingTypeDef<T extends ValidatingTypeDef> = T extends ValidatingTypeDef<infer _E, infer C> ? C : never;
230
+ type Rule<E, C, V = any> = FunctionalValidator<V, E, string, C>;
231
+ type ValidatingTypeDef<E = any, C = any> = ValidatingLiteralTypeDef<E, C> | ValidatingListTypeDef<E, C> | ValidatingRecordTypeDef<E, C> | ValidatingObjectTypeDef<E, C> | ValidatingUnionTypeDef<E, C>;
207
232
  type AnyTypeDef = any;
208
- type ValidatingLiteralTypeDef<E = any, V = any> = {
233
+ type ValidatingLiteralTypeDef<E = any, C = any, V = any> = {
209
234
  readonly type: TypeDefType.Literal;
210
235
  readonly valuePrototype: [V];
211
- readonly rule: Rule<E>;
236
+ readonly rule: Rule<E, C>;
212
237
  readonly required: boolean;
213
238
  readonly readonly: boolean;
214
239
  };
215
- type ValidatingListTypeDef<E = any, Ele extends ValidatingTypeDef = AnyTypeDef> = {
240
+ type ValidatingListTypeDef<E = any, C = any, Ele extends ValidatingTypeDef = AnyTypeDef> = {
216
241
  readonly type: TypeDefType.List;
217
242
  readonly elements: Ele;
218
- readonly rule: Rule<E>;
243
+ readonly rule: Rule<E, C>;
219
244
  readonly required: boolean;
220
245
  readonly readonly: boolean;
221
246
  };
222
- type ValidatingRecordTypeDef<E = any, K extends RecordKeyType = RecordKeyType, V extends ValidatingTypeDef | undefined = AnyTypeDef> = {
247
+ type ValidatingRecordTypeDef<E = any, C = any, K extends RecordKeyType = RecordKeyType, V extends ValidatingTypeDef | undefined = AnyTypeDef> = {
223
248
  readonly type: TypeDefType.Record;
224
249
  readonly keyPrototype: K;
225
250
  readonly valueTypeDef: V;
226
- readonly rule: Rule<E>;
251
+ readonly rule: Rule<E, C>;
227
252
  readonly required: boolean;
228
253
  readonly readonly: boolean;
229
254
  };
230
255
  type ValidatingObjectTypeDefFields = {
231
256
  [Key: ObjectFieldKey]: AnyTypeDef;
232
257
  };
233
- type ValidatingObjectTypeDef<E = any, Fields extends ValidatingObjectTypeDefFields = ValidatingObjectTypeDefFields> = {
258
+ type ValidatingObjectTypeDef<E = any, C = any, Fields extends ValidatingObjectTypeDefFields = ValidatingObjectTypeDefFields> = {
234
259
  readonly type: TypeDefType.Object;
235
260
  readonly fields: Fields;
236
- readonly rule: Rule<E>;
261
+ readonly rule: Rule<E, C>;
237
262
  readonly required: boolean;
238
263
  readonly readonly: boolean;
239
264
  };
240
- type ValidatingUnionTypeDef<E = any, D extends string | null = string | null, U extends Readonly<Record<UnionKey, AnyTypeDef>> = Readonly<Record<UnionKey, AnyTypeDef>>> = {
265
+ type ValidatingUnionTypeDef<E = any, C = any, D extends string | null = string | null, U extends Readonly<Record<UnionKey, AnyTypeDef>> = Readonly<Record<UnionKey, AnyTypeDef>>> = {
241
266
  readonly discriminator: D;
242
267
  readonly type: TypeDefType.Union;
243
268
  readonly unions: U;
244
- readonly rule: Rule<E>;
269
+ readonly rule: Rule<E, C>;
245
270
  readonly required: boolean;
246
271
  readonly readonly: boolean;
247
272
  };
@@ -254,52 +279,32 @@ type InternalFlattenedTypeDefsOfChildren<T extends TypeDef, SegmentOverride exte
254
279
  type InternalFlattenedTypeDefsOfLiteralChildren = {};
255
280
  type InternalFlattenedTypeDefsOfListChildren<T extends ValidatingListTypeDef, SegmentOverride extends string | null, Path extends string, Depth extends number> = InternalFlattenedTypeDefsOf<T['elements'], SegmentOverride, PathOf<Path, number, SegmentOverride>, '', Depth>;
256
281
  type InternalFlattenedTypeDefsOfRecordChildren<T extends ValidatingRecordTypeDef, SegmentOverride extends string | null, Path extends string, Depth extends number> = InternalFlattenedTypeDefsOf<T['valueTypeDef'], SegmentOverride, PathOf<Path, T['keyPrototype'], SegmentOverride>, '', Depth>;
257
- type InternalFlattenedTypeDefsOfObjectChildren<T extends ValidatingObjectTypeDef, SegmentOverride extends string | null, Path extends string, Qualifier extends string, Depth extends number> = T extends ValidatingObjectTypeDef<infer _E, infer Fields> ? keyof Fields extends string ? UnionToIntersection<{
258
- readonly [K in keyof Fields]-?: undefined extends Fields[K] ? InternalFlattenedTypeDefsOf<ValidatingUnionTypeDef<ErrorOfValidatingTypeDef<Exclude<Fields[K], undefined>>, null, {
282
+ type InternalFlattenedTypeDefsOfObjectChildren<T extends ValidatingObjectTypeDef, SegmentOverride extends string | null, Path extends string, Qualifier extends string, Depth extends number> = T extends ValidatingObjectTypeDef<infer _E, infer _C, infer Fields> ? keyof Fields extends string ? UnionToIntersection<{
283
+ readonly [K in keyof Fields]-?: undefined extends Fields[K] ? InternalFlattenedTypeDefsOf<ValidatingUnionTypeDef<ErrorOfValidatingTypeDef<Exclude<Fields[K], undefined>>, ContextOfValidatingTypeDef<Exclude<Fields[K], undefined>>, null, {
259
284
  readonly '0': Exclude<Fields[K], undefined>;
260
285
  readonly '1': ValidatingLiteralTypeDef<undefined>;
261
286
  }>, SegmentOverride, PathOf<Path, `${Qualifier}${K}`, null>, '', Depth> : InternalFlattenedTypeDefsOf<Exclude<Fields[K], undefined>, SegmentOverride, PathOf<Path, `${Qualifier}${K}`, null>, '', Depth>;
262
287
  }[keyof Fields]> : never : never;
263
- type InternalFlattenedTypeDefsOfUnionChildren<T extends ValidatingUnionTypeDef, SegmentOverride extends string | null, Path extends string, Qualifier extends string, Depth extends number> = T extends ValidatingUnionTypeDef<infer _E, infer D, infer Unions> ? keyof Unions extends string ? D extends null ? UnionToIntersection<{
288
+ type InternalFlattenedTypeDefsOfUnionChildren<T extends ValidatingUnionTypeDef, SegmentOverride extends string | null, Path extends string, Qualifier extends string, Depth extends number> = T extends ValidatingUnionTypeDef<infer _E, infer _C, infer D, infer Unions> ? keyof Unions extends string ? D extends null ? UnionToIntersection<{
264
289
  readonly [K in keyof Unions]: InternalFlattenedTypeDefsOfChildren<Unions[K], SegmentOverride, Path, '', Depth>;
265
290
  }[keyof Unions]> : UnionToIntersection<{
266
291
  readonly [K in keyof Unions]: InternalFlattenedTypeDefsOfChildren<Unions[K], SegmentOverride, Path, `${Qualifier}${K}:`, Depth>;
267
292
  }[keyof Unions]> : never : never;
268
293
 
269
- type Annotations = {
270
- readonly required: boolean;
271
- readonly readonly: boolean;
272
- };
273
- type FunctionalValidator<V = any, E = any, ValuePath extends string = any, Context = any> = (v: V, valuePath: ValuePath, context: Context) => E | null;
274
- type AnnotatedValidator<V = any, E = any, ValuePath extends string = any, Context = any> = {
275
- readonly validate: (v: V, valuePath: ValuePath, context: Context) => E | null;
276
- readonly annotations: (valuePath: ValuePath, context: Context) => Annotations;
277
- };
278
- type Validator<V = any, E = any, ValuePath extends string = any, Context = any> = FunctionalValidator<V, E, ValuePath, Context> | AnnotatedValidator<V, E, ValuePath, Context>;
279
- type ErrorOfValidator<V extends Validator> = V extends Validator<infer _V, infer E> ? E : never;
280
- type ValidationError<Type extends string, Data = {}> = Simplify<{
281
- type: Type;
282
- } & Data>;
283
- declare function isFunctionalValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is FunctionalValidator<V, E, ValuePath, Context>;
284
- declare function isAnnotatedValidator<V, E, ValuePath extends string, Context>(v: Validator<V, E, ValuePath, Context>): v is AnnotatedValidator<V, E, ValuePath, Context>;
285
- declare function validate<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, v: V, valuePath: ValuePath, context: Context): E | null;
286
- declare function annotations<V = any, E = any, ValuePath extends string = any, Context = any>(validator: Validator<V, E, ValuePath, Context>, valuePath: ValuePath, context: Context): Annotations;
287
- declare function mergeAnnotations(a1: Annotations, a2: Annotations): {
288
- readonly: boolean;
289
- required: boolean;
290
- };
291
-
292
- type ValidatorOfValidatingType<T extends ValidatingTypeDef, ValuePath extends string, Context> = T extends ValidatingTypeDef<infer E> ? Validator<ValueOfTypeDef<ReadonlyOfTypeDef<T>>, E, ValuePath, Context> : never;
293
- type FlattenedValidatorsOfValidatingType<T extends ValidatingType, TypePathsToValuePaths extends Readonly<Record<keyof FlattenedTypes, string>>, FlattenedTypes extends Readonly<Record<string, ValidatingType>> = FlattenedTypesOfType<T, '*'>, Context = ValueOfType<ReadonlyTypeOfType<T>>> = {
294
- [K in keyof FlattenedTypes as ErrorOfValidatingTypeDef<FlattenedTypes[K]['definition']> extends never ? never : K]: ValidatorOfValidatingType<FlattenedTypes[K]['definition'], TypePathsToValuePaths[K], Context>;
295
- };
294
+ type ValidatorOfValidatingType<T extends ValidatingTypeDef, ValuePath extends string> = T extends ValidatingTypeDef<infer E, infer C> ? Validator<ValueOfTypeDef<ReadonlyOfTypeDef<T>>, E, ValuePath, C> : never;
295
+ type FlattenedValidatorsOfValidatingType<T extends ValidatingType, TypePathsToValuePaths extends Readonly<Record<keyof FlattenedTypes, string>>, FlattenedTypes extends Readonly<Record<string, ValidatingType>> = FlattenedTypesOfType<T, '*'>> = Simplify<{
296
+ [K in keyof FlattenedTypes as ErrorOfValidatingTypeDef<FlattenedTypes[K]['definition']> extends never ? never : K]: ValidatorOfValidatingType<FlattenedTypes[K]['definition'], TypePathsToValuePaths[K]>;
297
+ }>;
296
298
 
297
299
  declare function flattenValidatorsOfValidatingType<T extends ValidatingType, TypePathsToValuePaths extends Readonly<Record<keyof FlattenedTypes, string>>, FlattenedTypes extends Readonly<Record<string, ValidatingType>> = FlattenedTypesOfValidatingType<T, '*'>>(type: T): FlattenedValidatorsOfValidatingType<T, TypePathsToValuePaths, FlattenedTypes>;
298
300
 
299
301
  declare function flattenValuesOfType<T extends Type>(typeDef: Type, value: ValueOfType<T>): Readonly<Record<string, any>>;
300
302
 
301
- declare function jsonPath(prefix: string, segment: number | string, qualifier?: string): string;
302
- declare function jsonPathPop(path: string): [string, string] | null;
303
+ declare function jsonPath<Prefix extends string, Segment extends number | string>(prefix: Prefix, segment: Segment): `${Prefix}.${Segment}`;
304
+ declare function jsonPath<Prefix extends string, Segment extends number | string, Qualifier extends string>(prefix: Prefix, segment: Segment, qualifier: Qualifier): `${Prefix}.${Qualifier}${Segment}`;
305
+ declare function jsonPathPop<Path extends string>(path: Path): [string, string] | null;
306
+ declare function jsonPathPrefix<Prefix extends string, Path extends string>(prefix: Prefix, path: Path): Path extends StringConcatOf<'$', infer ToMount> ? `${Prefix}${ToMount}` : never;
307
+ declare function jsonPathUnprefix<Prefix extends string, Path extends string>(prefix: Prefix, path: Path): Path extends StringConcatOf<Prefix, infer ToUnmount> ? `$${ToUnmount}` : never;
303
308
 
304
309
  declare function valuePathToTypePath<ValuePathsToTypePaths extends Record<string, string>, ValuePath extends keyof ValuePathsToTypePaths>({ definition: typeDef }: Type, valuePath: ValuePath, allowMissingPaths?: boolean): ValuePathsToTypePaths[ValuePath];
305
310
 
@@ -349,54 +354,54 @@ type TypeDefOfUnionTypeDef<T extends UnionTypeDef> = T extends UnionTypeDef<infe
349
354
  };
350
355
  } : never;
351
356
 
352
- type ValidatingTypeDefWithError<T extends ValidatingTypeDef, E> = T extends ValidatingLiteralTypeDef ? ValidatingLiteralTypeDefWithError<T, E> : T extends ValidatingListTypeDef ? ValidatingListTypeDefWithError<T, E> : T extends ValidatingRecordTypeDef ? ValidatingRecordTypeDefWithError<T, E> : T extends ValidatingObjectTypeDef ? ValidatingObjectTypeDefWithError<T, E> : T extends ValidatingUnionTypeDef ? ValidatingUnionTypeDefWithError<T, E> : never;
353
- type ValidatingLiteralTypeDefWithError<T extends ValidatingLiteralTypeDef, E2> = T extends ValidatingLiteralTypeDef<infer E1, infer V> ? {
357
+ type ValidatingTypeDefWithError<T extends ValidatingTypeDef, E, C> = T extends ValidatingLiteralTypeDef ? ValidatingLiteralTypeDefWithError<T, E, C> : T extends ValidatingListTypeDef ? ValidatingListTypeDefWithError<T, E, C> : T extends ValidatingRecordTypeDef ? ValidatingRecordTypeDefWithError<T, E, C> : T extends ValidatingObjectTypeDef ? ValidatingObjectTypeDefWithError<T, E, C> : T extends ValidatingUnionTypeDef ? ValidatingUnionTypeDefWithError<T, E, C> : never;
358
+ type ValidatingLiteralTypeDefWithError<T extends ValidatingLiteralTypeDef, E2, C2> = T extends ValidatingLiteralTypeDef<infer E1, infer C1, infer V> ? {
354
359
  readonly type: TypeDefType.Literal;
355
360
  readonly valuePrototype: [V];
356
- readonly rule: Rule<E1 | E2>;
361
+ readonly rule: Rule<E1 | E2, C1 & C2>;
357
362
  readonly required: boolean;
358
363
  readonly readonly: boolean;
359
364
  } : never;
360
- type ValidatingListTypeDefWithError<T extends ValidatingListTypeDef, E2> = T extends ValidatingListTypeDef<infer E1, infer E> ? IsFieldReadonly<T, 'elements'> extends true ? {
365
+ type ValidatingListTypeDefWithError<T extends ValidatingListTypeDef, E2, C2> = T extends ValidatingListTypeDef<infer E1, infer C1, infer E> ? IsFieldReadonly<T, 'elements'> extends true ? {
361
366
  readonly type: TypeDefType.List;
362
367
  readonly elements: E;
363
- readonly rule: Rule<E1 | E2>;
368
+ readonly rule: Rule<E1 | E2, C1 & C2>;
364
369
  readonly required: boolean;
365
370
  readonly readonly: boolean;
366
371
  } : {
367
372
  readonly type: TypeDefType.List;
368
373
  elements: E;
369
- readonly rule: Rule<E1 | E2>;
374
+ readonly rule: Rule<E1 | E2, C1 & C2>;
370
375
  readonly required: boolean;
371
376
  readonly readonly: boolean;
372
377
  } : never;
373
- type ValidatingRecordTypeDefWithError<T extends ValidatingRecordTypeDef, E2> = T extends ValidatingRecordTypeDef<infer E1, infer K, infer V> ? IsFieldReadonly<T, 'valueTypeDef'> extends true ? {
378
+ type ValidatingRecordTypeDefWithError<T extends ValidatingRecordTypeDef, E2, C2> = T extends ValidatingRecordTypeDef<infer E1, infer C1, infer K, infer V> ? IsFieldReadonly<T, 'valueTypeDef'> extends true ? {
374
379
  readonly type: TypeDefType.Record;
375
380
  readonly keyPrototype: K;
376
381
  readonly valueTypeDef: V;
377
- readonly rule: Rule<E1 | E2>;
382
+ readonly rule: Rule<E1 | E2, C1 & C2>;
378
383
  readonly required: boolean;
379
384
  readonly readonly: boolean;
380
385
  } : {
381
386
  readonly type: TypeDefType.Record;
382
387
  readonly keyPrototype: K;
383
388
  valueTypeDef: V;
384
- readonly rule: Rule<E1 | E2>;
389
+ readonly rule: Rule<E1 | E2, C1 & C2>;
385
390
  readonly required: boolean;
386
391
  readonly readonly: boolean;
387
392
  } : never;
388
- type ValidatingObjectTypeDefWithError<T extends ValidatingObjectTypeDef, E2> = T extends ValidatingObjectTypeDef<infer E1, infer Fields> ? {
393
+ type ValidatingObjectTypeDefWithError<T extends ValidatingObjectTypeDef, E2, C2> = T extends ValidatingObjectTypeDef<infer E1, infer C1, infer Fields> ? {
389
394
  readonly type: TypeDefType.Object;
390
395
  readonly fields: Fields;
391
- readonly rule: Rule<E1 | E2>;
396
+ readonly rule: Rule<E1 | E2, C1 & C2>;
392
397
  readonly required: boolean;
393
398
  readonly readonly: boolean;
394
399
  } : never;
395
- type ValidatingUnionTypeDefWithError<T extends ValidatingUnionTypeDef, E2> = T extends ValidatingUnionTypeDef<infer E1, infer D, infer U> ? {
400
+ type ValidatingUnionTypeDefWithError<T extends ValidatingUnionTypeDef, E2, C2> = T extends ValidatingUnionTypeDef<infer E1, infer C1, infer D, infer U> ? {
396
401
  readonly type: TypeDefType.Union;
397
402
  readonly discriminator: D;
398
403
  readonly unions: U;
399
- readonly rule: Rule<E1 | E2>;
404
+ readonly rule: Rule<E1 | E2, C1 & C2>;
400
405
  readonly required: boolean;
401
406
  readonly readonly: boolean;
402
407
  } : never;
@@ -404,7 +409,8 @@ type ValidatingUnionTypeDefWithError<T extends ValidatingUnionTypeDef, E2> = T e
404
409
  declare class TypeDefBuilder<T extends ValidatingTypeDef> implements ValidatingType<T> {
405
410
  readonly definition: T;
406
411
  constructor(definition: T);
407
- enforce<E2>(rule: Rule<E2, ValueOfType<Type<T>>> | Validator<ValueOfType<Type<T>>, E2, never, never>): TypeDefBuilder<ValidatingTypeDefWithError<T, E2>>;
412
+ enforce<E2, C2>(): TypeDefBuilder<ValidatingTypeDefWithError<T, E2, C2>>;
413
+ enforce<E2, C2>(rule: Validator<ValueOfType<Type<T>>, E2, string, C2>): TypeDefBuilder<ValidatingTypeDefWithError<T, E2, C2>>;
408
414
  required(): TypeDefBuilder<T>;
409
415
  readonly(): TypeDefBuilder<T>;
410
416
  get _type(): TypeOfType<Type<T>>;
@@ -444,29 +450,29 @@ declare class RecordTypeDefBuilder<T extends ValidatingRecordTypeDef> extends Ty
444
450
  readonly readonly: boolean;
445
451
  }>;
446
452
  }
447
- declare class ObjectTypeDefBuilder<E, Fields extends Readonly<Record<ObjectFieldKey, ValidatingTypeDef>> = {}> extends TypeDefBuilder<ValidatingObjectTypeDef<E, Fields>> {
448
- field<Name extends string, T extends ValidatingTypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, Fields & Record<Name, T>>;
449
- field<Name extends string, T extends ValidatingTypeDef, RequiredError>(name: Name, { definition }: Type<T>, rule: Rule<RequiredError, ValueOfTypeDef<T>>): ObjectTypeDefBuilder<E, Fields & Record<Name, ValidatingTypeDefWithError<T, RequiredError>>>;
450
- readonlyField<Name extends string, T extends ValidatingTypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, Fields & Readonly<Record<Name, T>>>;
451
- optionalField<Name extends string, T extends ValidatingTypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, Fields & Partial<Record<Name, T>>>;
452
- readonlyOptionalField<Name extends string, T extends TypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, Fields & Partial<Readonly<Record<Name, T>>>>;
453
+ declare class ObjectTypeDefBuilder<E, C, Fields extends Readonly<Record<ObjectFieldKey, ValidatingTypeDef>> = {}> extends TypeDefBuilder<ValidatingObjectTypeDef<E, C, Fields>> {
454
+ field<Name extends string, T extends ValidatingTypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, C, Fields & Record<Name, T>>;
455
+ field<Name extends string, T extends ValidatingTypeDef, RequiredError, C2>(name: Name, { definition }: Type<T>, rule: Rule<RequiredError, ValueOfTypeDef<T>>): ObjectTypeDefBuilder<E, C & C2, Fields & Record<Name, ValidatingTypeDefWithError<T, RequiredError, C & C2>>>;
456
+ readonlyField<Name extends string, T extends ValidatingTypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, C, Fields & Readonly<Record<Name, T>>>;
457
+ optionalField<Name extends string, T extends ValidatingTypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, C, Fields & Partial<Record<Name, T>>>;
458
+ readonlyOptionalField<Name extends string, T extends TypeDef>(name: Name, { definition }: Type<T>): ObjectTypeDefBuilder<E, C, Fields & Partial<Readonly<Record<Name, T>>>>;
453
459
  }
454
- declare class UnionTypeDefBuilder<E, D extends string | null, U extends Record<UnionKey, TypeDef>> extends TypeDefBuilder<ValidatingUnionTypeDef<E, D, U>> {
455
- or<K extends Exclude<UnionKey, keyof U>, T extends TypeDef>(k: K, { definition: typeDef, }: Type<T>): UnionTypeDefBuilder<E, D, Readonly<Record<K, T>> & U>;
460
+ declare class UnionTypeDefBuilder<E, C, D extends string | null, U extends Record<UnionKey, TypeDef>> extends TypeDefBuilder<ValidatingUnionTypeDef<E, C, D, U>> {
461
+ or<K extends Exclude<UnionKey, keyof U>, T extends TypeDef>(k: K, { definition: typeDef, }: Type<T>): UnionTypeDefBuilder<E, C, D, Readonly<Record<K, T>> & U>;
456
462
  }
457
- declare function literal<T>(value?: [T]): TypeDefBuilder<ValidatingLiteralTypeDef<never, T>>;
458
- declare const stringType: TypeDefBuilder<ValidatingLiteralTypeDef<never, string>>;
459
- declare const numberType: TypeDefBuilder<ValidatingLiteralTypeDef<never, number>>;
460
- declare const booleanType: TypeDefBuilder<ValidatingLiteralTypeDef<never, boolean>>;
461
- declare const nullType: TypeDefBuilder<ValidatingLiteralTypeDef<never, null>>;
462
- declare function nullable<T extends ValidatingTypeDef>(nonNullable: ValidatingType<T>): UnionTypeDefBuilder<never, null, {
463
+ declare function literal<T>(value?: [T]): TypeDefBuilder<ValidatingLiteralTypeDef<never, {}, T>>;
464
+ declare const stringType: TypeDefBuilder<ValidatingLiteralTypeDef<never, {}, string>>;
465
+ declare const numberType: TypeDefBuilder<ValidatingLiteralTypeDef<never, {}, number>>;
466
+ declare const booleanType: TypeDefBuilder<ValidatingLiteralTypeDef<never, {}, boolean>>;
467
+ declare const nullType: TypeDefBuilder<ValidatingLiteralTypeDef<never, {}, null>>;
468
+ declare function nullable<T extends ValidatingTypeDef>(nonNullable: ValidatingType<T>): UnionTypeDefBuilder<never, {}, null, {
463
469
  readonly ['0']: T;
464
- readonly ['1']: ValidatingLiteralTypeDef<never, null>;
470
+ readonly ['1']: ValidatingLiteralTypeDef<never, {}, null>;
465
471
  }>;
466
472
  declare function list<T extends ValidatingTypeDef>(elements: ValidatingType<T>): ListTypeDefBuilder<{
467
473
  readonly type: TypeDefType.List;
468
474
  elements: T;
469
- readonly rule: Rule<never>;
475
+ readonly rule: Rule<never, {}>;
470
476
  readonly readonly: boolean;
471
477
  readonly required: boolean;
472
478
  }>;
@@ -474,13 +480,13 @@ declare function record<V extends ValidatingType, K extends RecordKeyType>({ def
474
480
  readonly type: TypeDefType.Record;
475
481
  readonly keyPrototype: K;
476
482
  valueTypeDef: V["definition"];
477
- readonly rule: Rule<never>;
483
+ readonly rule: Rule<never, {}>;
478
484
  readonly readonly: boolean;
479
485
  readonly required: boolean;
480
486
  }>;
481
487
  declare function object(): ObjectTypeDefBuilder<never, {}>;
482
- declare function union<D extends null>(): UnionTypeDefBuilder<never, D, {}>;
483
- declare function union<D extends string>(discriminator: D): UnionTypeDefBuilder<never, D, {}>;
488
+ declare function union<D extends null>(): UnionTypeDefBuilder<never, {}, D, {}>;
489
+ declare function union<D extends string>(discriminator: D): UnionTypeDefBuilder<never, {}, D, {}>;
484
490
 
485
491
  type PathsOfType<T extends Type, SegmentOverride extends string | null = null, Prefix extends string = '$'> = InternalJsonPathsOf<T['definition'], Prefix, SegmentOverride, StartingDepth>;
486
492
  type InternalJsonPathsOf<F extends TypeDef, Prefix extends string, SegmentOverride extends string | null, Depth extends number, NextDepth extends number = Depths[Depth]> = InternalJsonPathsOfChildren<F, Prefix, SegmentOverride, '', NextDepth> | Prefix;
@@ -592,4 +598,4 @@ type ValidatorsOfValues<FlattenedValues extends Readonly<Record<string, any>>, T
592
598
  readonly [K in keyof FlattenedValues]: Validator<FlattenedValues[K], any, TypePathsToValuePaths[K], Context>;
593
599
  };
594
600
 
595
- export { type Accessor, type AnnotatedValidator, type Annotations, type AnyValueType, DefinedValidator, type ErrorOfValidator, type FlattenedAccessorsOfType, type FlattenedTypesOfType, type FlattenedValuesOfType, type FunctionalValidator, type InternalJsonPathsOf, type IsStrictUnion, type ListTypeDef, type LiteralTypeDef, type Mapper, type MinimumStringLengthValidationError, MinimumStringLengthValidationErrorType, MinimumStringLengthValidator, type MobxObservable, type MobxValueOfType, type NonMobxObservable, type ObjectFieldKey, type ObjectTypeDef, type ObjectTypeDefFields, OptionalValidatorProxy, type PathsOfType, type ReadonlyOfTypeDef, type ReadonlyTypeOfType, type RecordKeyType, type RecordTypeDef, type RegexpValidationError, RegexpValidationErrorType, RegexpValidator, type Setter, type StrictListTypeDef, type StrictLiteralTypeDef, type StrictObjectTypeDef, type StrictObjectTypeDefFields, type StrictRecordTypeDef, type StrictType, type StrictTypeDef, type StrictUnionTypeDef, type Type, type TypeDef, TypeDefType, type UnionKey, type UnionTypeDef, type ValidationError, type Validator, type ValidatorsOfValues, type ValueOfType, type ValueOfTypeDef, type ValueToTypePathsOfType, type ValueTypesOfDiscriminatedUnion, annotations, booleanType, copy, flattenAccessorsOfType, flattenJsonValueToTypePathsOf, flattenTypesOfType, flattenValidatorsOfValidatingType, flattenValueTo, flattenValuesOfType, getUnionTypeDef, isAnnotatedValidator, isFunctionalValidator, jsonPath, jsonPathPop, list, literal, mergeAnnotations, mobxCopy, nullType, nullable, numberType, object, record, stringType, union, validate, valuePathToTypePath };
601
+ export { type Accessor, type AnnotatedValidator, type Annotations, type AnyValueType, DefinedValidator, type ErrorOfValidator, type FlattenedAccessorsOfType, type FlattenedTypesOfType, type FlattenedValuesOfType, type FunctionalValidator, type InternalJsonPathsOf, type IsStrictUnion, type ListTypeDef, type LiteralTypeDef, type Mapper, type MinimumStringLengthValidationError, MinimumStringLengthValidationErrorType, MinimumStringLengthValidator, type MobxObservable, type MobxValueOfType, type NonMobxObservable, type ObjectFieldKey, type ObjectTypeDef, type ObjectTypeDefFields, OptionalValidatorProxy, type PathsOfType, type ReadonlyOfTypeDef, type ReadonlyTypeOfType, type RecordKeyType, type RecordTypeDef, type RegexpValidationError, RegexpValidationErrorType, RegexpValidator, type Setter, type StrictListTypeDef, type StrictLiteralTypeDef, type StrictObjectTypeDef, type StrictObjectTypeDefFields, type StrictRecordTypeDef, type StrictType, type StrictTypeDef, type StrictUnionTypeDef, type Type, type TypeDef, TypeDefType, type UnionKey, type UnionTypeDef, type ValidationError, type Validator, type ValidatorsOfValues, type ValueOfType, type ValueOfTypeDef, type ValueToTypePathsOfType, type ValueTypesOfDiscriminatedUnion, annotations, booleanType, copy, flattenAccessorsOfType, flattenJsonValueToTypePathsOf, flattenTypesOfType, flattenValidatorsOfValidatingType, flattenValueTo, flattenValuesOfType, getUnionTypeDef, isAnnotatedValidator, isFunctionalValidator, jsonPath, jsonPathPop, jsonPathPrefix, jsonPathUnprefix, list, literal, mergeAnnotations, mergeValidators, mobxCopy, nullType, nullable, numberType, object, record, stringType, union, validate, valuePathToTypePath };
package/dist/index.js CHANGED
@@ -185,8 +185,12 @@ import {
185
185
  } from "@strictly/base";
186
186
 
187
187
  // transformers/flatteners/json_path.ts
188
- function jsonPath(prefix, segment, qualifier = "") {
189
- const s = `.${qualifier}${segment}`;
188
+ import {
189
+ assertEqual,
190
+ assertState
191
+ } from "@strictly/base";
192
+ function jsonPath(prefix, segment, qualifier) {
193
+ const s = `.${qualifier != null ? qualifier : ""}${segment}`;
190
194
  return `${prefix}${s}`;
191
195
  }
192
196
  function jsonPathPop(path) {
@@ -199,6 +203,14 @@ function jsonPathPop(path) {
199
203
  parts.pop()
200
204
  ];
201
205
  }
206
+ function jsonPathPrefix(prefix, path) {
207
+ assertEqual(path[0], "$", "{} should start with $", path);
208
+ return `${prefix}${path.slice(1)}`;
209
+ }
210
+ function jsonPathUnprefix(prefix, path) {
211
+ assertState(path.startsWith(prefix), "{} should start with {}", path, prefix);
212
+ return `$${path.slice(prefix.length)}`;
213
+ }
202
214
 
203
215
  // transformers/flatteners/flatten_value_to.ts
204
216
  function flattenValueTo({ definition }, v, setter, mapper2) {
@@ -523,7 +535,7 @@ function flattenValuesOfType(typeDef, value) {
523
535
 
524
536
  // transformers/flatteners/value_path_to_type_path.ts
525
537
  import {
526
- assertEqual,
538
+ assertEqual as assertEqual2,
527
539
  assertExists,
528
540
  assertExistsAndReturn,
529
541
  PreconditionFailedError,
@@ -532,7 +544,7 @@ import {
532
544
  } from "@strictly/base";
533
545
  function valuePathToTypePath({ definition: typeDef }, valuePath, allowMissingPaths = false) {
534
546
  const valueSteps = valuePath.split(/\.|\[/g);
535
- assertEqual(valueSteps[0], "$");
547
+ assertEqual2(valueSteps[0], "$");
536
548
  const typeSteps = internalJsonValuePathToTypePath(
537
549
  typeDef,
538
550
  valueSteps.slice(1),
@@ -660,6 +672,40 @@ function internalJsonValuePathToTypePath(typeDef, valueSteps, allowMissingPaths,
660
672
  }
661
673
  }
662
674
 
675
+ // validation/validators/composite_validator.ts
676
+ var CompositeValidator = class {
677
+ constructor(...validators) {
678
+ __publicField(this, "validators");
679
+ this.validators = validators;
680
+ }
681
+ validate(v, valuePath, context) {
682
+ return this.validators.reduce((error, validator) => {
683
+ if (error != null) {
684
+ return error;
685
+ }
686
+ return validate(validator, v, valuePath, context);
687
+ }, null);
688
+ }
689
+ annotations(valuePath, context) {
690
+ return this.validators.reduce(({
691
+ required,
692
+ readonly
693
+ }, validator) => {
694
+ const {
695
+ readonly: validatorReadonly,
696
+ required: validatorRequired
697
+ } = annotations(validator, valuePath, context);
698
+ return {
699
+ required: required || validatorRequired,
700
+ readonly: readonly || validatorReadonly
701
+ };
702
+ }, {
703
+ required: false,
704
+ readonly: false
705
+ });
706
+ }
707
+ };
708
+
663
709
  // validation/validator.ts
664
710
  function isFunctionalValidator(v) {
665
711
  return typeof v === "function";
@@ -674,6 +720,9 @@ function validate(validator, v, valuePath, context) {
674
720
  return validator(v, valuePath, context);
675
721
  }
676
722
  }
723
+ function mergeValidators(v1, v2) {
724
+ return new CompositeValidator(v1, v2);
725
+ }
677
726
  function annotations(validator, valuePath, context) {
678
727
  if (isAnnotatedValidator(validator)) {
679
728
  return validator.annotations(valuePath, context);
@@ -782,11 +831,11 @@ var TypeDefBuilder = class _TypeDefBuilder {
782
831
  enforce(rule) {
783
832
  return new _TypeDefBuilder(
784
833
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
785
- __spreadProps(__spreadValues(__spreadValues({}, this.definition), isAnnotatedValidator(rule) ? mergeAnnotations(rule.annotations(null, null), this.definition) : {}), {
834
+ __spreadProps(__spreadValues(__spreadValues({}, this.definition), rule != null && isAnnotatedValidator(rule) ? mergeAnnotations(rule.annotations(null, null), this.definition) : {}), {
786
835
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
787
- rule: (value) => {
836
+ rule: (value, valuePath, context) => {
788
837
  var _a;
789
- return (_a = this.definition.rule(value)) != null ? _a : validate(rule, value, null, null);
838
+ return (_a = this.definition.rule(value, valuePath, context)) != null ? _a : rule && validate(rule, value, valuePath, context);
790
839
  }
791
840
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
792
841
  })
@@ -850,8 +899,9 @@ var ObjectTypeDefBuilder = class _ObjectTypeDefBuilder extends TypeDefBuilder {
850
899
  fields: __spreadProps(__spreadValues({}, this.definition.fields), {
851
900
  [name]: __spreadProps(__spreadValues({}, definition), {
852
901
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
853
- rule: function(v) {
854
- return definition.rule(v) || (rule == null ? void 0 : rule(v));
902
+ rule: function(v, valuePath, context) {
903
+ var _a;
904
+ return (_a = definition.rule(v, valuePath, context)) != null ? _a : rule && validate(rule, v, valuePath, context);
855
905
  }
856
906
  })
857
907
  })
@@ -1107,9 +1157,12 @@ export {
1107
1157
  isFunctionalValidator,
1108
1158
  jsonPath,
1109
1159
  jsonPathPop,
1160
+ jsonPathPrefix,
1161
+ jsonPathUnprefix,
1110
1162
  list,
1111
1163
  literal,
1112
1164
  mergeAnnotations,
1165
+ mergeValidators,
1113
1166
  mobxCopy,
1114
1167
  nullType,
1115
1168
  nullable,
package/package.json CHANGED
@@ -35,7 +35,7 @@
35
35
  "test:watch": "vitest"
36
36
  },
37
37
  "type": "module",
38
- "version": "0.0.12",
38
+ "version": "0.0.14",
39
39
  "exports": {
40
40
  ".": {
41
41
  "import": {
@@ -1,9 +1,30 @@
1
- export function jsonPath(prefix: string, segment: number | string, qualifier: string = ''): string {
2
- const s = `.${qualifier}${segment}`
3
- return `${prefix}${s}`
1
+ import {
2
+ assertEqual,
3
+ assertState,
4
+ type StringConcatOf,
5
+ } from '@strictly/base'
6
+
7
+ export function jsonPath<
8
+ Prefix extends string,
9
+ Segment extends number | string,
10
+ >(prefix: Prefix, segment: Segment): `${Prefix}.${Segment}`
11
+ export function jsonPath<
12
+ Prefix extends string,
13
+ Segment extends number | string,
14
+ Qualifier extends string,
15
+ >(prefix: Prefix, segment: Segment, qualifier: Qualifier): `${Prefix}.${Qualifier}${Segment}`
16
+ export function jsonPath<
17
+ Prefix extends string,
18
+ Segment extends number | string,
19
+ Qualifier extends string = '',
20
+ >(prefix: Prefix, segment: Segment, qualifier?: Qualifier) {
21
+ const s = `.${qualifier ?? ''}${segment}`
22
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
23
+ return `${prefix}${s}` as `${Prefix}.${Qualifier}${Segment}`
4
24
  }
5
25
 
6
- export function jsonPathPop(path: string): [string, string] | null {
26
+ // TODO type safety
27
+ export function jsonPathPop<Path extends string>(path: Path): [string, string] | null {
7
28
  const parts = path.split('.')
8
29
  if (parts.length <= 1) {
9
30
  return null
@@ -13,3 +34,22 @@ export function jsonPathPop(path: string): [string, string] | null {
13
34
  parts.pop()!,
14
35
  ]
15
36
  }
37
+
38
+ export function jsonPathPrefix<
39
+ Prefix extends string,
40
+ Path extends string,
41
+ >(prefix: Prefix, path: Path): Path extends StringConcatOf<'$', infer ToMount> ? `${Prefix}${ToMount}` : never {
42
+ assertEqual(path[0], '$', '{} should start with $', path)
43
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
44
+ return `${prefix}${path.slice(1)}` as Path extends StringConcatOf<'$', infer ToMount> ? `${Prefix}${ToMount}` : never
45
+ }
46
+
47
+ export function jsonPathUnprefix<
48
+ Prefix extends string,
49
+ Path extends string,
50
+ >(prefix: Prefix, path: Path): Path extends StringConcatOf<Prefix, infer ToUnmount> ? `$${ToUnmount}` : never {
51
+ assertState(path.startsWith(prefix), '{} should start with {}', path, prefix)
52
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
53
+ return `$${path.slice(prefix.length)}` as Path extends StringConcatOf<Prefix, infer ToUnmount> ? `$${ToUnmount}`
54
+ : never
55
+ }
@@ -0,0 +1,69 @@
1
+ import {
2
+ jsonPath,
3
+ jsonPathPrefix,
4
+ jsonPathUnprefix,
5
+ } from 'transformers/flatteners/json_path'
6
+
7
+ describe('json_paths', () => {
8
+ describe('jsonPath', () => {
9
+ describe('simple', () => {
10
+ const path = jsonPath('$', 'thing')
11
+
12
+ it('has the expected type', () => {
13
+ expectTypeOf(path).toEqualTypeOf<'$.thing'>()
14
+ })
15
+
16
+ it('has the expected value', () => {
17
+ expect(path).toEqual('$.thing')
18
+ })
19
+ })
20
+
21
+ describe('indexed', () => {
22
+ const path = jsonPath<`$.${number}`, number>(`$.${1}`, 1)
23
+
24
+ it('has the expected type', () => {
25
+ expectTypeOf(path).toEqualTypeOf<`$.${number}.${number}`>()
26
+ })
27
+
28
+ it('has the expected value', () => {
29
+ expect(path).toEqual('$.1.1')
30
+ })
31
+ })
32
+
33
+ describe('qualified', () => {
34
+ const path = jsonPath('$', 'x', 'y:')
35
+
36
+ it('has the expected type', () => {
37
+ expectTypeOf(path).toEqualTypeOf<'$.y:x'>()
38
+ })
39
+
40
+ it('has the expected value', () => {
41
+ expect(path).toEqual('$.y:x')
42
+ })
43
+ })
44
+ })
45
+
46
+ describe('jsonPathPrefix', () => {
47
+ const path = jsonPathPrefix('$.x', '$.x.y')
48
+
49
+ it('has the expected type', () => {
50
+ expectTypeOf(path).toEqualTypeOf<'$.x.x.y'>()
51
+ })
52
+
53
+ it('has the expected value', () => {
54
+ expect(path).toEqual('$.x.x.y')
55
+ })
56
+ })
57
+
58
+ describe('jsonPathUnprefix', () => {
59
+ const path = jsonPathUnprefix('$.x.x.x', '$.x.x.x.x.y')
60
+
61
+ it('has the expected type', () => {
62
+ expectTypeOf(path).toEqualTypeOf<'$.x.y'>()
63
+ })
64
+
65
+ it('has the expected value', () => {
66
+ expect(path).toEqual('$.x.y')
67
+ })
68
+ })
69
+ })