@nmtjs/type 0.5.3 → 0.6.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 (59) hide show
  1. package/dist/compiler.js +16 -79
  2. package/dist/compiler.js.map +1 -1
  3. package/dist/index.js +30 -54
  4. package/dist/index.js.map +1 -1
  5. package/dist/inference.js +1 -0
  6. package/dist/inference.js.map +1 -0
  7. package/dist/parse.js +145 -0
  8. package/dist/parse.js.map +1 -0
  9. package/dist/runtime.js +73 -0
  10. package/dist/runtime.js.map +1 -0
  11. package/dist/schemas/default.js +6 -0
  12. package/dist/schemas/default.js.map +1 -0
  13. package/dist/schemas/discriminated-union.js.map +1 -1
  14. package/dist/schemas/nullable.js.map +1 -1
  15. package/dist/temporal.js.map +1 -1
  16. package/dist/types/any.js.map +1 -1
  17. package/dist/types/array.js +1 -1
  18. package/dist/types/array.js.map +1 -1
  19. package/dist/types/base.js +4 -16
  20. package/dist/types/base.js.map +1 -1
  21. package/dist/types/boolean.js.map +1 -1
  22. package/dist/types/custom.js.map +1 -1
  23. package/dist/types/date.js +9 -1
  24. package/dist/types/date.js.map +1 -1
  25. package/dist/types/enum.js +6 -2
  26. package/dist/types/enum.js.map +1 -1
  27. package/dist/types/literal.js +3 -1
  28. package/dist/types/literal.js.map +1 -1
  29. package/dist/types/never.js.map +1 -1
  30. package/dist/types/number.js +2 -0
  31. package/dist/types/number.js.map +1 -1
  32. package/dist/types/object.js +32 -1
  33. package/dist/types/object.js.map +1 -1
  34. package/dist/types/string.js.map +1 -1
  35. package/dist/types/union.js +9 -5
  36. package/dist/types/union.js.map +1 -1
  37. package/package.json +8 -8
  38. package/src/compiler.ts +36 -121
  39. package/src/index.ts +36 -119
  40. package/src/inference.ts +128 -0
  41. package/src/parse.ts +217 -0
  42. package/src/runtime.ts +137 -0
  43. package/src/schemas/default.ts +12 -0
  44. package/src/schemas/discriminated-union.ts +1 -1
  45. package/src/schemas/nullable.ts +0 -6
  46. package/src/temporal.ts +0 -1
  47. package/src/types/any.ts +2 -4
  48. package/src/types/array.ts +1 -12
  49. package/src/types/base.ts +45 -144
  50. package/src/types/boolean.ts +3 -10
  51. package/src/types/custom.ts +14 -13
  52. package/src/types/date.ts +13 -1
  53. package/src/types/enum.ts +12 -15
  54. package/src/types/literal.ts +3 -5
  55. package/src/types/never.ts +2 -4
  56. package/src/types/number.ts +18 -18
  57. package/src/types/object.ts +108 -43
  58. package/src/types/string.ts +8 -5
  59. package/src/types/union.ts +43 -78
package/src/compiler.ts CHANGED
@@ -1,42 +1,39 @@
1
- import type { TSchema } from '@sinclair/typebox'
1
+ import { TypeCompiler } from '@sinclair/typebox/compiler'
2
+ import { TransformDecode, TransformEncode } from '@sinclair/typebox/value'
3
+ import type {
4
+ StaticInputEncode,
5
+ StaticOutputDecode,
6
+ StaticOutputEncode,
7
+ } from './inference.ts'
2
8
  import {
3
- TypeCompiler,
4
- type ValueErrorIterator,
5
- } from '@sinclair/typebox/compiler'
6
- import {
7
- TransformDecode,
8
- TransformEncode,
9
- Value,
10
- } from '@sinclair/typebox/value'
11
- import type { t } from './index.ts'
12
- import { IsDiscriminatedUnion } from './schemas/discriminated-union.ts'
9
+ type CloneOptions,
10
+ type ValidationError,
11
+ _applyDefaults,
12
+ _parse,
13
+ _traversErrors,
14
+ } from './runtime.ts'
13
15
  import type { BaseType } from './types/base.ts'
14
16
 
15
- type ValidationError = {
16
- path: string
17
- message: string
18
- value: unknown
19
- }
20
-
21
17
  export type Compiled<T extends BaseType = BaseType> = {
22
- check: (val: unknown) => boolean
18
+ check: (val: unknown) => val is StaticInputEncode<T['schema']>
23
19
  errors: (val: unknown) => ValidationError[]
24
- parse: (val: unknown) => unknown
20
+ parse: (val: unknown, cloneOptions?: CloneOptions) => unknown
21
+ applyDefaults: (val: unknown) => unknown
25
22
  /**
26
23
  * Requires to `check` before calling
27
24
  */
28
- decode: (val: unknown) => t.infer.decoded<T>
25
+ decode: (val: unknown) => StaticOutputDecode<T['schema']>
29
26
  /**
30
27
  * Requires to `check` before calling
31
28
  */
32
- encode: (val: unknown) => t.infer.encoded<T>
29
+ encode: (val: unknown) => StaticOutputEncode<T['schema']>
33
30
  /**
34
31
  * Requires to `check` before calling
35
32
  */
36
33
  decodeSafe: (
37
34
  val: unknown,
38
35
  ) =>
39
- | { success: true; value: t.infer.decoded<T> }
36
+ | { success: true; value: StaticOutputDecode<T['schema']> }
40
37
  | { success: false; error: any }
41
38
  /**
42
39
  * Requires to `check` before calling
@@ -44,88 +41,34 @@ export type Compiled<T extends BaseType = BaseType> = {
44
41
  encodeSafe: (
45
42
  val: unknown,
46
43
  ) =>
47
- | { success: true; value: t.infer.encoded<T> }
44
+ | { success: true; value: StaticOutputEncode<T['schema']> }
48
45
  | { success: false; error: any }
49
46
  }
50
47
 
51
- // FIXME: this one is very slow
52
- function _parse(schema: TSchema, value: any) {
53
- // Clone -> Clean -> Default -> Convert
54
- return Value.Convert(
55
- schema,
56
- Value.Default(schema, Value.Clean(schema, Value.Clone(value))),
57
- )
58
- }
59
-
60
- function _errors(errors: ValueErrorIterator) {
61
- const result: ValidationError[] = []
62
-
63
- for (const error of errors) {
64
- if (IsDiscriminatedUnion(error.schema)) {
65
- const discriminator = error.schema.discriminator
66
- const discriminatorValue = error.value?.[discriminator]
67
- if (discriminatorValue !== undefined) {
68
- const variantSchema = error.schema.anyOf.find(
69
- (schema) =>
70
- schema.properties[discriminator].const === discriminatorValue,
71
- )
72
- if (variantSchema) {
73
- const propertiesSchemas: TSchema[] = []
74
- for (const element in variantSchema.properties) {
75
- const propertySchema = variantSchema.properties[element]
76
- if (propertySchema !== variantSchema.properties[discriminator]) {
77
- propertiesSchemas.push(propertySchema)
78
- }
79
- }
80
-
81
- for (const iter of error.errors) {
82
- for (const err of iter) {
83
- if (!propertiesSchemas.includes(err.schema)) continue
84
- result.push({
85
- path: err.path,
86
- message: err.message,
87
- value: err.value,
88
- })
89
- }
90
- }
91
-
92
- continue
93
- }
94
- }
95
- }
96
-
97
- result.push({
98
- path: error.path,
99
- message: error.message,
100
- value: error.value,
101
- })
102
-
103
- for (const nestedError of error.errors) {
104
- result.push(..._errors(nestedError))
105
- }
106
- }
107
-
108
- return result
109
- }
110
-
111
48
  function compileType(type: BaseType) {
112
- const { final: schema } = type
49
+ const { schema } = type
113
50
  const compiled = TypeCompiler.Compile(schema)
114
- const errors = (value) => {
115
- return _errors(compiled.Errors(value))
116
- }
51
+
52
+ const check = (value: unknown) => compiled.Check(value)
53
+ const applyDefaults = (value: unknown) => _applyDefaults(schema, value)
54
+ const parse = (value: unknown, cloneOptions?: CloneOptions) =>
55
+ _parse(schema, value, cloneOptions)
56
+ const errors = (value: unknown) => _traversErrors(compiled.Errors(value))
57
+ const decode = TransformDecode.bind(null, schema, compiled.References())
58
+ const encode = TransformEncode.bind(null, schema, compiled.References())
117
59
 
118
60
  return {
119
- check: compiled.Check.bind(compiled),
120
- parse: _parse.bind(null, schema),
61
+ check,
62
+ parse,
121
63
  errors,
122
- decode: TransformDecode.bind(null, schema, compiled.References()),
123
- encode: TransformEncode.bind(null, schema, compiled.References()),
64
+ applyDefaults,
65
+ decode,
66
+ encode,
124
67
  }
125
68
  }
126
69
 
127
- export function compile<T extends BaseType>(schema: T): Compiled<T> {
128
- const compiled = compileType(schema)
70
+ export function compile<T extends BaseType>(type: T): Compiled<T> {
71
+ const compiled = compileType(type)
129
72
 
130
73
  function decodeSafe(val: unknown) {
131
74
  try {
@@ -155,31 +98,3 @@ export function compile<T extends BaseType>(schema: T): Compiled<T> {
155
98
  encodeSafe,
156
99
  } as any
157
100
  }
158
-
159
- export namespace runtime {
160
- export function parse(type: BaseType, value: any) {
161
- return _parse(type.final, value)
162
- }
163
-
164
- export function errors(type: BaseType, value: any): ValidationError[] {
165
- return _errors(Value.Errors(type.final, value))
166
- }
167
-
168
- export function check(type: BaseType, value: any): boolean {
169
- return Value.Check(type.final, value)
170
- }
171
-
172
- export function decode<T extends BaseType>(
173
- type: T,
174
- value: any,
175
- ): t.infer.decoded<T> {
176
- return TransformDecode(type.final, [], value)
177
- }
178
-
179
- export function encode<T extends BaseType>(
180
- type: T,
181
- value: any,
182
- ): t.infer.encoded<T> {
183
- return TransformEncode(type.final, [], value)
184
- }
185
- }
package/src/index.ts CHANGED
@@ -1,16 +1,12 @@
1
1
  import type {
2
- StaticDecode,
3
- StaticEncode,
4
- TLiteralValue,
5
- } from '@sinclair/typebox/type'
2
+ StaticInputDecode,
3
+ StaticInputEncode,
4
+ StaticOutputDecode,
5
+ StaticOutputEncode,
6
+ } from './inference.ts'
6
7
  import { AnyType } from './types/any.ts'
7
8
  import { ArrayType } from './types/array.ts'
8
- import type {
9
- BaseType,
10
- BaseTypeAny,
11
- OptionalType,
12
- Static,
13
- } from './types/base.ts'
9
+ import type { BaseTypeAny, OptionalType } from './types/base.ts'
14
10
  import { BooleanType } from './types/boolean.ts'
15
11
  import { CustomType } from './types/custom.ts'
16
12
  import { DateType } from './types/date.ts'
@@ -18,22 +14,26 @@ import { EnumType, ObjectEnumType } from './types/enum.ts'
18
14
  import { LiteralType } from './types/literal.ts'
19
15
  import { NeverType } from './types/never.ts'
20
16
  import { BigIntType, IntegerType, NumberType } from './types/number.ts'
21
- import { ObjectType, type ObjectTypeProps, RecordType } from './types/object.ts'
17
+ import {
18
+ ObjectType,
19
+ RecordType,
20
+ extend,
21
+ keyof,
22
+ merge,
23
+ omit,
24
+ partial,
25
+ pick,
26
+ } from './types/object.ts'
22
27
  import { StringType } from './types/string.ts'
23
28
  import {
24
29
  DiscriminatedUnionType,
25
30
  IntersactionType,
26
31
  UnionType,
27
32
  } from './types/union.ts'
28
- import type { UnionToTupleString } from './utils.ts'
29
-
30
- // register ajv formats
31
- import { register } from './formats.ts'
32
- register()
33
33
 
34
34
  export * from './schemas/nullable.ts'
35
35
  export { BaseType, type BaseTypeAny } from './types/base.ts'
36
- export { type TSchema } from '@sinclair/typebox'
36
+ export type { TSchema } from '@sinclair/typebox'
37
37
  export {
38
38
  ArrayType,
39
39
  BooleanType,
@@ -51,20 +51,20 @@ export {
51
51
  NeverType,
52
52
  }
53
53
 
54
- export namespace t {
54
+ export namespace type {
55
55
  export namespace infer {
56
- export type decoded<T extends BaseTypeAny> = StaticDecode<
57
- T['_']['decoded']['output']
56
+ export type decoded<T extends BaseTypeAny<any>> = StaticOutputDecode<
57
+ T['schema']
58
58
  >
59
- export type encoded<T extends BaseTypeAny> = StaticEncode<
60
- T['_']['encoded']['output']
59
+ export type encoded<T extends BaseTypeAny<any>> = StaticOutputEncode<
60
+ T['schema']
61
61
  >
62
62
  export namespace input {
63
- export type decoded<T extends BaseTypeAny> = StaticDecode<
64
- T['_']['decoded']['input']
63
+ export type decoded<T extends BaseTypeAny<any>> = StaticInputDecode<
64
+ T['schema']
65
65
  >
66
- export type encoded<T extends BaseTypeAny> = StaticEncode<
67
- T['_']['encoded']['input']
66
+ export type encoded<T extends BaseTypeAny<any>> = StaticInputEncode<
67
+ T['schema']
68
68
  >
69
69
  }
70
70
  }
@@ -80,103 +80,20 @@ export namespace t {
80
80
  export const arrayEnum = EnumType.factory
81
81
  export const date = DateType.factory
82
82
  export const array = ArrayType.factory
83
- export const object = ObjectType.factory
84
83
  export const record = RecordType.factory
85
84
  export const any = AnyType.factory
86
85
  export const or = UnionType.factory
87
86
  export const and = IntersactionType.factory
88
87
  export const discriminatedUnion = DiscriminatedUnionType.factory
89
88
  export const custom = CustomType.factory
90
-
91
- export const keyof = <T extends ObjectType>(
92
- type: T,
93
- ): EnumType<
94
- UnionToTupleString<T extends ObjectType<infer Props> ? keyof Props : never>
95
- > => {
96
- return arrayEnum(Object.keys(type.props.properties) as any)
97
- }
98
-
99
- export const pick = <
100
- T extends ObjectType,
101
- P extends { [K in keyof T['props']['properties']]?: true },
102
- >(
103
- source: T,
104
- pick: P,
105
- ): ObjectType<{
106
- [K in keyof T['props']['properties'] as K extends keyof P
107
- ? K
108
- : never]: T['props']['properties'][K]
109
- }> => {
110
- const properties = Object.fromEntries(
111
- Object.entries(source.props.properties).filter(([key]) => pick[key]),
112
- )
113
- return ObjectType.factory(properties) as any
114
- }
115
-
116
- export const omit = <
117
- T extends ObjectType,
118
- P extends { [K in keyof T]?: true },
119
- >(
120
- source: T,
121
- omit: P,
122
- ): ObjectType<{
123
- [K in keyof T['props']['properties'] as K extends keyof P
124
- ? never
125
- : K]: T['props']['properties'][K]
126
- }> => {
127
- const properties = Object.fromEntries(
128
- Object.entries(source.props.properties).filter(([key]) => !omit[key]),
129
- )
130
- return ObjectType.factory(properties) as any
131
- }
132
-
133
- export const extend = <T extends ObjectType, P extends ObjectTypeProps>(
134
- object1: T,
135
- properties: P,
136
- ): ObjectType<{
137
- [K in keyof T['props']['properties'] | keyof P]: K extends keyof P
138
- ? P[K]
139
- : K extends keyof T['props']['properties']
140
- ? T['props']['properties'][K]
141
- : never
142
- }> => {
143
- return ObjectType.factory({
144
- ...object1.props.properties,
145
- ...properties,
146
- }) as any
147
- }
148
-
149
- export const merge = <T1 extends ObjectType, T2 extends ObjectType>(
150
- object1: T1,
151
- object2: T2,
152
- ): ObjectType<{
153
- [K in
154
- | keyof T1['props']['properties']
155
- | keyof T2['props']['properties']]: K extends keyof T2['props']['properties']
156
- ? T2['props']['properties'][K]
157
- : K extends keyof T1['props']['properties']
158
- ? T1['props']['properties'][K]
159
- : never
160
- }> => {
161
- return ObjectType.factory({
162
- ...object1.props.properties,
163
- ...object2.props.properties,
164
- }) as any
165
- }
166
-
167
- export const partial = <T extends ObjectType>(
168
- object: T,
169
- ): ObjectType<{
170
- [K in keyof T['props']['properties']]: OptionalType<
171
- T['props']['properties'][K]
172
- >
173
- }> => {
174
- const properties = {} as any
175
-
176
- for (const [key, value] of Object.entries(object.props.properties)) {
177
- properties[key] = value.optional()
178
- }
179
-
180
- return ObjectType.factory(properties, {}) as any
181
- }
89
+ export const object = Object.assign(ObjectType.factory.bind(ObjectType), {
90
+ keyof,
91
+ partial,
92
+ merge,
93
+ omit,
94
+ extend,
95
+ pick,
96
+ })
182
97
  }
98
+
99
+ export { type as t }
@@ -0,0 +1,128 @@
1
+ import type { TProperties, TSchema } from '@sinclair/typebox'
2
+ import type * as Types from '@sinclair/typebox'
3
+ import type { TDefault } from './schemas/default.ts'
4
+
5
+ export type StaticInputEncode<Type extends TSchema> =
6
+ Type extends Types.TOptional<TSchema>
7
+ ? Types.StaticEncode<Type> | undefined
8
+ : Types.StaticEncode<Type>
9
+
10
+ export type StaticInputDecode<Type extends TSchema> =
11
+ Type extends Types.TOptional<TSchema>
12
+ ? Types.StaticDecode<Type> | undefined
13
+ : Types.StaticDecode<Type>
14
+
15
+ export type StaticOutputEncode<Type extends TSchema> = Types.StaticEncode<
16
+ TMap<Type, StaticOutputMapping>
17
+ >
18
+
19
+ export type StaticOutputDecode<Type extends TSchema> = Types.StaticDecode<
20
+ TMap<Type, StaticOutputMapping>
21
+ >
22
+
23
+ interface StaticOutputMapping extends TMapping {
24
+ output: this['input']
25
+ }
26
+
27
+ interface TMapping {
28
+ input: unknown
29
+ output: unknown
30
+ }
31
+
32
+ type TApply<
33
+ Type extends TSchema,
34
+ Mapping extends TMapping,
35
+ Mapped = (Mapping & { input: Type })['output'],
36
+ Result = Mapped extends TSchema ? Mapped : never,
37
+ > = Result
38
+
39
+ type TFromProperties<
40
+ Properties extends TProperties,
41
+ Mapping extends TMapping,
42
+ Result extends TProperties = {
43
+ [Key in keyof Properties]: TMap<Properties[Key], Mapping>
44
+ },
45
+ > = Result
46
+
47
+ type TFromRest<
48
+ Types extends TSchema[],
49
+ Mapping extends TMapping,
50
+ Result extends TSchema[] = [],
51
+ > = Types extends [infer Left extends TSchema, ...infer Right extends TSchema[]]
52
+ ? TFromRest<Right, Mapping, [...Result, TMap<Left, Mapping>]>
53
+ : Result
54
+
55
+ type TFromType<
56
+ Type extends TSchema,
57
+ Mapping extends TMapping,
58
+ Result extends TSchema = TApply<Type, Mapping>,
59
+ > = Result
60
+
61
+ type UnwrapDefault<T extends TSchema> = T extends TDefault<infer U>
62
+ ? U extends Types.TOptional<infer V>
63
+ ? V
64
+ : U
65
+ : T
66
+
67
+ type TMap<
68
+ Type extends TSchema,
69
+ Mapping extends TMapping,
70
+ // Maps the Exterior Type
71
+ Exterior extends TSchema = TFromType<Type, Mapping>,
72
+ // Maps the Interior Parameterized Types
73
+ Interior extends TSchema = Exterior extends Types.TConstructor<
74
+ infer Parameters extends TSchema[],
75
+ infer ReturnType extends TSchema
76
+ >
77
+ ? Types.TConstructor<
78
+ TFromRest<Parameters, Mapping>,
79
+ TFromType<ReturnType, Mapping>
80
+ >
81
+ : Exterior extends Types.TFunction<
82
+ infer Parameters extends TSchema[],
83
+ infer ReturnType extends TSchema
84
+ >
85
+ ? Types.TFunction<
86
+ TFromRest<Parameters, Mapping>,
87
+ TFromType<ReturnType, Mapping>
88
+ >
89
+ : Exterior extends Types.TIntersect<infer Types extends TSchema[]>
90
+ ? Types.TIntersect<TFromRest<Types, Mapping>>
91
+ : Exterior extends Types.TUnion<infer Types extends TSchema[]>
92
+ ? Types.TUnion<TFromRest<Types, Mapping>>
93
+ : Exterior extends Types.TTuple<infer Types extends TSchema[]>
94
+ ? Types.TTuple<TFromRest<Types, Mapping>>
95
+ : Exterior extends Types.TArray<infer Type extends TSchema>
96
+ ? Types.TArray<TFromType<Type, Mapping>>
97
+ : Exterior extends Types.TAsyncIterator<
98
+ infer Type extends TSchema
99
+ >
100
+ ? Types.TAsyncIterator<TFromType<Type, Mapping>>
101
+ : Exterior extends Types.TIterator<infer Type extends TSchema>
102
+ ? Types.TIterator<TFromType<Type, Mapping>>
103
+ : Exterior extends Types.TPromise<infer Type extends TSchema>
104
+ ? Types.TPromise<TFromType<Type, Mapping>>
105
+ : Exterior extends Types.TObject<
106
+ infer Properties extends TProperties
107
+ >
108
+ ? Types.TObject<TFromProperties<Properties, Mapping>>
109
+ : Exterior extends Types.TRecord<
110
+ infer Key extends TSchema,
111
+ infer Value extends TSchema
112
+ >
113
+ ? Types.TRecordOrObject<
114
+ TFromType<Key, Mapping>,
115
+ TFromType<Value, Mapping>
116
+ >
117
+ : Exterior,
118
+ // Modifiers Derived from Exterior Type Mapping
119
+ IsOptional extends number = Exterior extends Types.TOptional<TSchema> ? 1 : 0,
120
+ IsReadonly extends number = Exterior extends Types.TReadonly<TSchema> ? 1 : 0,
121
+ Result extends TSchema = [IsReadonly, IsOptional] extends [1, 1]
122
+ ? Types.TReadonly<UnwrapDefault<Interior>>
123
+ : [IsReadonly, IsOptional] extends [0, 1]
124
+ ? UnwrapDefault<Interior>
125
+ : [IsReadonly, IsOptional] extends [1, 0]
126
+ ? Types.TReadonly<UnwrapDefault<Interior>>
127
+ : UnwrapDefault<Interior>,
128
+ > = Result