@oscarpalmer/jhunal 0.17.0 → 0.19.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. package/dist/constants.d.mts +28 -15
  2. package/dist/constants.mjs +31 -14
  3. package/dist/helpers.d.mts +8 -1
  4. package/dist/helpers.mjs +68 -3
  5. package/dist/index.d.mts +304 -240
  6. package/dist/index.mjs +201 -51
  7. package/dist/models/infer.model.d.mts +66 -0
  8. package/dist/models/infer.model.mjs +1 -0
  9. package/dist/models/misc.model.d.mts +153 -0
  10. package/dist/models/misc.model.mjs +1 -0
  11. package/dist/models/schema.plain.model.d.mts +92 -0
  12. package/dist/models/schema.plain.model.mjs +1 -0
  13. package/dist/models/schema.typed.model.d.mts +96 -0
  14. package/dist/models/schema.typed.model.mjs +1 -0
  15. package/dist/models/transform.model.d.mts +59 -0
  16. package/dist/models/transform.model.mjs +1 -0
  17. package/dist/models/validation.model.d.mts +82 -0
  18. package/dist/models/validation.model.mjs +21 -0
  19. package/dist/schematic.d.mts +34 -1
  20. package/dist/schematic.mjs +11 -12
  21. package/dist/validation/property.validation.d.mts +1 -1
  22. package/dist/validation/property.validation.mjs +21 -17
  23. package/dist/validation/value.validation.d.mts +2 -2
  24. package/dist/validation/value.validation.mjs +73 -12
  25. package/package.json +2 -2
  26. package/src/constants.ts +84 -19
  27. package/src/helpers.ts +162 -4
  28. package/src/index.ts +3 -1
  29. package/src/models/infer.model.ts +105 -0
  30. package/src/models/misc.model.ts +212 -0
  31. package/src/models/schema.plain.model.ts +110 -0
  32. package/src/models/schema.typed.model.ts +109 -0
  33. package/src/models/transform.model.ts +85 -0
  34. package/src/models/validation.model.ts +124 -0
  35. package/src/schematic.ts +55 -10
  36. package/src/validation/property.validation.ts +41 -36
  37. package/src/validation/value.validation.ts +133 -20
  38. package/dist/models.d.mts +0 -484
  39. package/dist/models.mjs +0 -13
  40. package/src/models.ts +0 -665
@@ -1,29 +1,90 @@
1
- import { isSchematic } from "../helpers.mjs";
1
+ import "../constants.mjs";
2
+ import { getInvalidInputMessage, getInvalidMissingMessage, getInvalidTypeMessage, getInvalidValidatorMessage, isSchematic } from "../helpers.mjs";
3
+ import { ValidationError } from "../models/validation.model.mjs";
2
4
  import { isPlainObject } from "@oscarpalmer/atoms/is";
3
5
  //#region src/validation/value.validation.ts
4
- function validateObject(obj, properties) {
5
- if (!isPlainObject(obj)) return false;
6
+ function validateNamed(property, name, value, validation) {
7
+ if (!validators[name](value)) return false;
8
+ const propertyValidators = property.validators[name];
9
+ if (propertyValidators == null || propertyValidators.length === 0) return true;
10
+ const { length } = propertyValidators;
11
+ for (let index = 0; index < length; index += 1) {
12
+ const validator = propertyValidators[index];
13
+ if (!validator(value)) {
14
+ validation.push({
15
+ value,
16
+ key: { ...property.key },
17
+ message: getInvalidValidatorMessage(property, name, index, length),
18
+ validator
19
+ });
20
+ return false;
21
+ }
22
+ }
23
+ return true;
24
+ }
25
+ function validateObject(obj, properties, reporting, property, validation) {
26
+ if (!isPlainObject(obj)) {
27
+ const information = {
28
+ key: {
29
+ full: "",
30
+ short: ""
31
+ },
32
+ message: property == null ? getInvalidInputMessage(obj) : getInvalidTypeMessage(property, obj),
33
+ value: obj
34
+ };
35
+ if (reporting.throw) throw new ValidationError([information]);
36
+ return reporting.none ? false : [information];
37
+ }
38
+ const allInformation = [];
6
39
  const propertiesLength = properties.length;
7
40
  outer: for (let propertyIndex = 0; propertyIndex < propertiesLength; propertyIndex += 1) {
8
41
  const property = properties[propertyIndex];
9
42
  const { key, required, types } = property;
10
- const value = obj[key];
11
- if (value === void 0 && required) return false;
43
+ const value = obj[key.short];
44
+ if (value === void 0 && required) {
45
+ const information = {
46
+ value,
47
+ key: { ...key },
48
+ message: getInvalidMissingMessage(property)
49
+ };
50
+ if (reporting.throw && validation == null) throw new ValidationError([information]);
51
+ if (validation != null) validation.push(information);
52
+ if (reporting.all) {
53
+ allInformation.push(information);
54
+ continue;
55
+ }
56
+ return reporting.none ? false : [information];
57
+ }
12
58
  const typesLength = types.length;
59
+ const information = [];
13
60
  for (let typeIndex = 0; typeIndex < typesLength; typeIndex += 1) {
14
61
  const type = types[typeIndex];
15
- if (validateValue(type, property, value)) continue outer;
62
+ if (validateValue(type, property, value, reporting, information)) continue outer;
63
+ }
64
+ if (information.length === 0) information.push({
65
+ value,
66
+ key: { ...key },
67
+ message: getInvalidTypeMessage(property, value)
68
+ });
69
+ if (reporting.throw && validation == null) throw new ValidationError(information);
70
+ validation?.push(...information);
71
+ if (reporting.all) {
72
+ allInformation.push(...information);
73
+ continue;
16
74
  }
17
- return false;
75
+ return reporting.none ? false : information;
18
76
  }
19
- return true;
77
+ return reporting.none ? true : allInformation.length === 0 ? true : allInformation;
20
78
  }
21
- function validateValue(type, property, value) {
79
+ function validateValue(type, property, value, reporting, validation) {
22
80
  switch (true) {
23
- case isSchematic(type): return type.is(value);
24
81
  case typeof type === "function": return type(value);
25
- case typeof type === "object": return validateObject(value, [type]);
26
- default: return validators[type](value) && (property.validators[type]?.every((validator) => validator(value)) ?? true);
82
+ case Array.isArray(type): {
83
+ const nested = validateObject(value, type, reporting, property, validation);
84
+ return typeof nested !== "boolean" ? false : nested;
85
+ }
86
+ case isSchematic(type): return type.is(value, reporting);
87
+ default: return validateNamed(property, type, value, validation);
27
88
  }
28
89
  }
29
90
  const validators = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@oscarpalmer/jhunal",
3
- "version": "0.17.0",
3
+ "version": "0.19.0",
4
4
  "description": "Flies free beneath the glistening moons…",
5
5
  "keywords": [
6
6
  "schema",
@@ -38,7 +38,7 @@
38
38
  "watch": "npx vite build --watch"
39
39
  },
40
40
  "dependencies": {
41
- "@oscarpalmer/atoms": "^0.168"
41
+ "@oscarpalmer/atoms": "^0.169"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@types/node": "^25.5",
package/src/constants.ts CHANGED
@@ -1,43 +1,106 @@
1
- import type {ValueName} from './models';
1
+ import type {ValueName} from './models/misc.model';
2
+ import type {ReportingType} from './models/validation.model';
2
3
 
3
- export const ERROR_NAME = 'SchematicError';
4
+ // #region Misc.
4
5
 
5
6
  export const MESSAGE_CONSTRUCTOR = 'Expected a constructor function';
6
7
 
7
- export const MESSAGE_SCHEMA_INVALID_EMPTY = 'Schema must have at least one property';
8
+ // #endregion
8
9
 
9
- export const MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED =
10
- "'<key>.<property>' property is not allowed for schemas in $type";
10
+ // #region Names
11
11
 
12
- export const MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE =
13
- "'<>' property must not be 'null' or 'undefined'";
14
-
15
- export const MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED = "'<>.$required' property must be a boolean";
12
+ export const NAME_SCHEMATIC = 'Schematic';
16
13
 
17
- export const MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE = "'<>' property must be of a valid type";
14
+ export const NAME_ERROR_SCHEMATIC = 'SchematicError';
18
15
 
19
- export const MESSAGE_SCHEMA_INVALID_TYPE = 'Schema must be an object';
16
+ export const NAME_ERROR_VALIDATION = 'ValidationError';
20
17
 
21
- export const MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
18
+ // #endregion
22
19
 
23
- export const MESSAGE_VALIDATOR_INVALID_TYPE = 'Validators must be an object';
24
-
25
- export const MESSAGE_VALIDATOR_INVALID_VALUE =
26
- "Validator '<>' must be a function or an array of functions";
20
+ // #region Properties
27
21
 
28
22
  export const PROPERTY_REQUIRED = '$required';
29
23
 
24
+ export const PROPERTY_SCHEMATIC = '$schematic';
25
+
30
26
  export const PROPERTY_TYPE = '$type';
31
27
 
32
28
  export const PROPERTY_VALIDATORS = '$validators';
33
29
 
34
- export const SCHEMATIC_NAME = '$schematic';
30
+ // #endregion
31
+
32
+ // #region Property validation
33
+
34
+ export const VALIDATION_MESSAGE_INVALID_INPUT = "Expected 'object' as input but received <>";
35
+
36
+ export const VALIDATION_MESSAGE_INVALID_REQUIRED = "Expected <> for required property '<>'";
37
+
38
+ export const VALIDATION_MESSAGE_INVALID_TYPE = "Expected <> for '<>' but received <>";
39
+
40
+ export const VALIDATION_MESSAGE_INVALID_VALUE =
41
+ "Value does not satisfy validator for '<>' and type '<>'";
42
+
43
+ export const VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX = ' at index <>';
44
+
45
+ // #endregion
46
+
47
+ // #region Reporting
48
+
49
+ export const REPORTING_ALL: ReportingType = 'all';
50
+
51
+ export const REPORTING_FIRST: ReportingType = 'first';
52
+
53
+ export const REPORTING_NONE: ReportingType = 'none';
54
+
55
+ export const REPORTING_THROW: ReportingType = 'throw';
56
+
57
+ export const REPORTING_TYPES = new Set<ReportingType>([
58
+ REPORTING_ALL,
59
+ REPORTING_FIRST,
60
+ REPORTING_NONE,
61
+ REPORTING_THROW,
62
+ ]);
63
+
64
+ // #endregion
65
+
66
+ // #region Schematic validation
67
+
68
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_EMPTY = 'Schema must have at least one property';
69
+
70
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_DISALLOWED =
71
+ "'<>.<>' property is not allowed for schemas in $type";
72
+
73
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_NULLABLE =
74
+ "'<>' property must not be 'null' or 'undefined'";
75
+
76
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_REQUIRED =
77
+ "'<>.$required' property must be a boolean";
78
+
79
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_PROPERTY_TYPE =
80
+ "'<>' property must be of a valid type";
81
+
82
+ export const SCHEMATIC_MESSAGE_SCHEMA_INVALID_TYPE = 'Schema must be an object';
83
+
84
+ export const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_KEY = "Validator '<>' does not exist";
85
+
86
+ export const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_TYPE = 'Validators must be an object';
87
+
88
+ export const SCHEMATIC_MESSAGE_VALIDATOR_INVALID_VALUE =
89
+ "Validator '<>' must be a function or an array of functions";
90
+
91
+ // #endregion
92
+
93
+ // #region Templates
35
94
 
36
95
  export const TEMPLATE_PATTERN = '<>';
37
96
 
38
- export const TEMPLATE_PATTERN_KEY = '<key>';
97
+ // #endregion
98
+
99
+ // #region Types
39
100
 
40
- export const TEMPLATE_PATTERN_PROPERTY = '<property>';
101
+ export const TYPE_ARRAY = 'array';
102
+
103
+ export const TYPE_NULL = 'null';
41
104
 
42
105
  export const TYPE_OBJECT = 'object';
43
106
 
@@ -56,3 +119,5 @@ export const VALIDATABLE_TYPES = new Set<ValueName>([
56
119
  ]);
57
120
 
58
121
  export const TYPE_ALL = new Set<ValueName>([...VALIDATABLE_TYPES, 'null', TYPE_UNDEFINED]);
122
+
123
+ // #endregion
package/src/helpers.ts CHANGED
@@ -1,8 +1,134 @@
1
- import {isConstructor} from '@oscarpalmer/atoms/is';
1
+ import {isConstructor, isPlainObject} from '@oscarpalmer/atoms/is';
2
2
  import type {Constructor} from '@oscarpalmer/atoms/models';
3
- import {MESSAGE_CONSTRUCTOR, SCHEMATIC_NAME} from './constants';
3
+ import {
4
+ MESSAGE_CONSTRUCTOR,
5
+ NAME_SCHEMATIC,
6
+ PROPERTY_SCHEMATIC,
7
+ REPORTING_ALL,
8
+ REPORTING_FIRST,
9
+ REPORTING_NONE,
10
+ REPORTING_THROW,
11
+ REPORTING_TYPES,
12
+ TEMPLATE_PATTERN,
13
+ TYPE_ARRAY,
14
+ TYPE_NULL,
15
+ TYPE_OBJECT,
16
+ TYPE_UNDEFINED,
17
+ VALIDATION_MESSAGE_INVALID_INPUT,
18
+ VALIDATION_MESSAGE_INVALID_REQUIRED,
19
+ VALIDATION_MESSAGE_INVALID_TYPE,
20
+ VALIDATION_MESSAGE_INVALID_VALUE,
21
+ VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX,
22
+ } from './constants';
23
+ import type {ValueName} from './models/misc.model';
24
+ import type {
25
+ ReportingInformation,
26
+ ReportingType,
27
+ ValidatedProperty,
28
+ ValidatedPropertyType,
29
+ } from './models/validation.model';
4
30
  import type {Schematic} from './schematic';
5
31
 
32
+ export function getInvalidInputMessage(actual: unknown): string {
33
+ return VALIDATION_MESSAGE_INVALID_INPUT.replace(TEMPLATE_PATTERN, getValueType(actual));
34
+ }
35
+
36
+ export function getInvalidMissingMessage(property: ValidatedProperty): string {
37
+ let message = VALIDATION_MESSAGE_INVALID_REQUIRED.replace(
38
+ TEMPLATE_PATTERN,
39
+ renderTypes(property.types),
40
+ );
41
+
42
+ message = message.replace(TEMPLATE_PATTERN, property.key.full);
43
+
44
+ return message;
45
+ }
46
+
47
+ export function getInvalidTypeMessage(property: ValidatedProperty, actual: unknown): string {
48
+ let message = VALIDATION_MESSAGE_INVALID_TYPE.replace(
49
+ TEMPLATE_PATTERN,
50
+ renderTypes(property.types),
51
+ );
52
+
53
+ message = message.replace(TEMPLATE_PATTERN, property.key.full);
54
+ message = message.replace(TEMPLATE_PATTERN, getValueType(actual));
55
+
56
+ return message;
57
+ }
58
+
59
+ export function getInvalidValidatorMessage(
60
+ property: ValidatedProperty,
61
+ type: ValueName,
62
+ index: number,
63
+ length: number,
64
+ ): string {
65
+ let message = VALIDATION_MESSAGE_INVALID_VALUE.replace(TEMPLATE_PATTERN, property.key.full);
66
+
67
+ message = message.replace(TEMPLATE_PATTERN, type);
68
+
69
+ if (length > 1) {
70
+ message += VALIDATION_MESSAGE_INVALID_VALUE_SUFFIX.replace(TEMPLATE_PATTERN, String(index));
71
+ }
72
+
73
+ return message;
74
+ }
75
+
76
+ function getPropertyType(original: ValidatedPropertyType): string {
77
+ if (typeof original === 'function') {
78
+ return 'a validated value';
79
+ }
80
+
81
+ if (Array.isArray(original)) {
82
+ return `'${TYPE_OBJECT}'`;
83
+ }
84
+
85
+ if (isSchematic(original)) {
86
+ return `a ${NAME_SCHEMATIC}`;
87
+ }
88
+
89
+ return `'${String(original)}'`;
90
+ }
91
+
92
+ export function getReporting(value: unknown): ReportingInformation {
93
+ const type = REPORTING_TYPES.has(value as ReportingType)
94
+ ? (value as ReportingType)
95
+ : REPORTING_NONE;
96
+
97
+ return {
98
+ [REPORTING_ALL]: type === REPORTING_ALL,
99
+ [REPORTING_FIRST]: type === REPORTING_FIRST,
100
+ [REPORTING_NONE]: type === REPORTING_NONE,
101
+ [REPORTING_THROW]: type === REPORTING_THROW,
102
+ } as ReportingInformation;
103
+ }
104
+
105
+ function getValueType(value: unknown): string {
106
+ const valueType = typeof value;
107
+
108
+ switch (true) {
109
+ case value === null:
110
+ return `'${TYPE_NULL}'`;
111
+
112
+ case value === undefined:
113
+ return `'${TYPE_UNDEFINED}'`;
114
+
115
+ case valueType !== TYPE_OBJECT:
116
+ return `'${valueType}'`;
117
+
118
+ case Array.isArray(value):
119
+ return `'${TYPE_ARRAY}'`;
120
+
121
+ case isPlainObject(value):
122
+ return `'${TYPE_OBJECT}'`;
123
+
124
+ case isSchematic(value):
125
+ return `a ${NAME_SCHEMATIC}`;
126
+
127
+ default:
128
+ return value.constructor.name;
129
+ }
130
+ }
131
+
6
132
  /**
7
133
  * Creates a validator function for a given constructor
8
134
  * @param constructor - Constructor to check against
@@ -30,7 +156,39 @@ export function isSchematic(value: unknown): value is Schematic<never> {
30
156
  return (
31
157
  typeof value === 'object' &&
32
158
  value !== null &&
33
- SCHEMATIC_NAME in value &&
34
- value[SCHEMATIC_NAME] === true
159
+ PROPERTY_SCHEMATIC in value &&
160
+ value[PROPERTY_SCHEMATIC] === true
35
161
  );
36
162
  }
163
+
164
+ function renderTypes(types: ValidatedPropertyType[]): string {
165
+ const unique = new Set<string>();
166
+ const parts: string[] = [];
167
+
168
+ for (let index = 0; index < types.length; index += 1) {
169
+ const rendered = getPropertyType(types[index]);
170
+
171
+ if (unique.has(rendered)) {
172
+ continue;
173
+ }
174
+
175
+ unique.add(rendered);
176
+ parts.push(rendered);
177
+ }
178
+
179
+ const {length} = parts;
180
+
181
+ let rendered = '';
182
+
183
+ for (let index = 0; index < length; index += 1) {
184
+ rendered += parts[index];
185
+
186
+ if (index < length - 2) {
187
+ rendered += ', ';
188
+ } else if (index === length - 2) {
189
+ rendered += parts.length > 2 ? ', or ' : ' or ';
190
+ }
191
+ }
192
+
193
+ return rendered;
194
+ }
package/src/index.ts CHANGED
@@ -1,3 +1,5 @@
1
1
  export {instanceOf, isSchematic} from './helpers';
2
- export {SchematicError, type Schema, type TypedSchema} from './models';
2
+ export type {Schema} from './models/schema.plain.model';
3
+ export type {TypedSchema} from './models/schema.typed.model';
4
+ export {SchematicError, ValidationError} from './models/validation.model';
3
5
  export {schematic, type Schematic} from './schematic';
@@ -0,0 +1,105 @@
1
+ import type {Constructor, Simplify} from '@oscarpalmer/atoms/models';
2
+ import type {Schematic} from '../schematic';
3
+ import type {IsOptionalProperty, ValueName, Values} from './misc.model';
4
+ import type {PlainSchema, Schema, SchemaProperty} from './schema.plain.model';
5
+
6
+ /**
7
+ * Infers the TypeScript type from a {@link Schema} definition
8
+ *
9
+ * @template Model - Schema to infer types from
10
+ *
11
+ * @example
12
+ * ```ts
13
+ * const userSchema = {
14
+ * name: 'string',
15
+ * age: 'number',
16
+ * address: { $required: false, $type: 'string' },
17
+ * } satisfies Schema;
18
+ *
19
+ * type User = Infer<typeof userSchema>;
20
+ * // { name: string; age: number; address?: string }
21
+ * ```
22
+ */
23
+ export type Infer<Model extends Schema> = Simplify<
24
+ {
25
+ [Key in InferRequiredKeys<Model>]: InferSchemaEntry<Model[Key]>;
26
+ } & {
27
+ [Key in InferOptionalKeys<Model>]?: InferSchemaEntry<Model[Key]>;
28
+ }
29
+ >;
30
+
31
+ /**
32
+ * Extracts keys from a {@link Schema} whose entries are optional _(i.e., `$required` is `false`)_
33
+ *
34
+ * @template Model - {@link Schema} to extract optional keys from
35
+ */
36
+ export type InferOptionalKeys<Model extends Schema> = keyof {
37
+ [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? Key : never]: never;
38
+ };
39
+
40
+ /**
41
+ * Infers the TypeScript type of a {@link SchemaProperty}'s `$type` field, unwrapping arrays to infer their item type
42
+ *
43
+ * @template Value - `$type` value _(single or array)_
44
+ */
45
+ export type InferPropertyType<Value> = Value extends (infer Item)[]
46
+ ? InferPropertyValue<Item>
47
+ : InferPropertyValue<Value>;
48
+
49
+ /**
50
+ * Maps a single type definition to its TypeScript equivalent
51
+ *
52
+ * Resolves, in order: {@link Constructor} instances, {@link Schematic} models, {@link ValueName} strings, and nested {@link Schema} objects
53
+ *
54
+ * @template Value - single type definition
55
+ */
56
+ export type InferPropertyValue<Value> =
57
+ Value extends Constructor<infer Instance>
58
+ ? Instance
59
+ : Value extends Schematic<infer Model>
60
+ ? Model
61
+ : Value extends ValueName
62
+ ? Values[Value & ValueName]
63
+ : Value extends Schema
64
+ ? Infer<Value>
65
+ : never;
66
+
67
+ /**
68
+ * Extracts keys from a {@link Schema} whose entries are required _(i.e., `$required` is not `false`)_
69
+ *
70
+ * @template Model - Schema to extract required keys from
71
+ */
72
+ export type InferRequiredKeys<Model extends Schema> = keyof {
73
+ [Key in keyof Model as IsOptionalProperty<Model[Key]> extends true ? never : Key]: never;
74
+ };
75
+
76
+ /**
77
+ * Infers the type for a top-level {@link Schema} entry, unwrapping arrays to infer their item type
78
+ *
79
+ * @template Value - Schema entry value _(single or array)_
80
+ */
81
+ export type InferSchemaEntry<Value> = Value extends (infer Item)[]
82
+ ? InferSchemaEntryValue<Item>
83
+ : InferSchemaEntryValue<Value>;
84
+
85
+ /**
86
+ * Resolves a single schema entry to its TypeScript type
87
+ *
88
+ * Handles, in order: {@link Constructor} instances, {@link Schematic} models, {@link SchemaProperty} objects, {@link NestedSchema} objects, {@link ValueName} strings, and plain {@link Schema} objects
89
+ *
90
+ * @template Value - single schema entry
91
+ */
92
+ export type InferSchemaEntryValue<Value> =
93
+ Value extends Constructor<infer Instance>
94
+ ? Instance
95
+ : Value extends Schematic<infer Model>
96
+ ? Model
97
+ : Value extends SchemaProperty
98
+ ? InferPropertyType<Value['$type']>
99
+ : Value extends PlainSchema
100
+ ? Infer<Value & Schema>
101
+ : Value extends ValueName
102
+ ? Values[Value & ValueName]
103
+ : Value extends Schema
104
+ ? Infer<Value>
105
+ : never;