@@ -30,11 +30,10 @@ THE SOFTWARE.
3030
3131import { Settings } from '../system/settings/index.ts'
3232import { Arguments } from '../system/arguments/index.ts'
33- import { Environment } from '../system/environment/index.ts'
3433import { type TLocalizedValidationError } from '../error/index.ts'
3534import { type StaticDecode , type StaticEncode , type TProperties , type TSchema , Base } from '../type/index.ts'
3635import { Errors , Clean , Convert , Create , Default , Decode , Encode , HasCodec , Parser , ParseError } from '../value/index.ts'
37- import { Build } from '../schema/index.ts'
36+ import { Build , BuildResult , EvaluateResult } from '../schema/index.ts'
3837
3938// ------------------------------------------------------------------
4039// Validator<...>
@@ -43,121 +42,117 @@ export class Validator<Context extends TProperties = TProperties, Type extends T
4342 Encode extends unknown = StaticEncode < Type , Context > ,
4443 Decode extends unknown = StaticDecode < Type , Context >
4544> extends Base < Encode > {
46- private readonly context : Context
47- private readonly type : Type
48- private readonly isAccelerated : boolean
4945 private readonly hasCodec : boolean
50- private readonly code : string
51- private readonly check : ( value : unknown ) => boolean
46+ private readonly buildResult : BuildResult
47+ private readonly evaluateResult : EvaluateResult
5248 /** Constructs a Validator with the given Context and Type. */
5349 constructor ( context : Context , type : Type )
5450 /** Constructs a Validator with the given arguments. */
55- constructor ( context : Context , type : Type , isEvaluated : boolean , hasCodec : boolean , code : string , check : ( value : unknown ) => boolean )
51+ constructor ( hasCodec : boolean , buildResult : BuildResult , evaluateResult : EvaluateResult )
5652 /** Constructs a Validator. */
5753 constructor ( ...args : unknown [ ] ) {
5854 super ( )
59- const matched : [ Context , Type , boolean , boolean , string , ( value : unknown ) => boolean ] | [ Context , Type ] = Arguments . Match ( args , {
60- 6 : ( context , type , isEvalulated , hasCodec , code , check ) => [ context , type , isEvalulated , hasCodec , code , check ] ,
55+ const matched : [ boolean , BuildResult , EvaluateResult ] | [ Context , Type ] = Arguments . Match ( args , {
56+ 3 : ( hasCodec , buildResult , evaluateResult ) => [ hasCodec , buildResult , evaluateResult ] ,
6157 2 : ( context , type ) => [ context , type ]
6258 } )
63- if ( matched . length === 6 ) {
64- const [ context , type , isEvaluated , hasCodec , code , check ] = matched
65- this . context = context
66- this . type = type
67- this . isAccelerated = isEvaluated
59+ // Note: The Base type requires this Validator to be Clone, but where we cannot safely clone
60+ // the BuildResult or the EvaluateResult. For now we need pass the Validator constructor a
61+ // cloned instance of BuildResult and EvaluateResult such that the Validator clone shares
62+ // the same pre-compiled fields. We should remove this overload when Base is removed.
63+ if ( matched . length === 3 && matched [ 1 ] instanceof BuildResult && matched [ 2 ] instanceof EvaluateResult ) {
64+ const [ hasCodec , buildResult , evaluateResult ] = matched
6865 this . hasCodec = hasCodec
69- this . code = code
70- this . check = check
66+ this . buildResult = buildResult
67+ this . evaluateResult = evaluateResult
7168 } else {
7269 const [ context , type ] = matched as [ Context , Type ]
73- const result = Build ( context , type ) . Evaluate ( )
7470 this . hasCodec = HasCodec ( context , type )
75- this . context = context
76- this . type = type
77- this . isAccelerated = result . IsAccelerated
78- this . code = result . Code
79- this . check = result . Check as never
71+ this . buildResult = Build ( context , type )
72+ this . evaluateResult = this . buildResult . Evaluate ( )
8073 }
8174 }
8275 // ----------------------------------------------------------------
8376 // IsAccelerated
8477 // ----------------------------------------------------------------
8578 /** Returns true if this Validator is using JIT acceleration. */
8679 public IsAccelerated ( ) : boolean {
87- return this . isAccelerated
80+ return this . evaluateResult . IsAccelerated ( )
8881 }
8982 // ----------------------------------------------------------------
90- // Context | Type
83+ // Context & Type
9184 // ----------------------------------------------------------------
9285 /** Returns the Context for this validator. */
9386 public Context ( ) : Context {
94- return this . context
87+ return this . buildResult . Context ( ) as never
9588 }
9689 /** Returns the underlying Type used to construct this Validator. */
9790 public Type ( ) : Type {
98- return this . type
91+ return this . buildResult . Schema ( ) as never
9992 }
10093 // ----------------------------------------------------------------
10194 // Code
10295 // ----------------------------------------------------------------
10396 /** Returns the generated code for this validator. */
10497 public Code ( ) : string {
105- return this . code
98+ return this . evaluateResult . Code ( )
10699 }
107100 // ----------------------------------------------------------------
108- // Base<...>
101+ // Standard Validator
109102 // ----------------------------------------------------------------
110103 /** Performs a type-guard check on the provided value. */
111104 public override Check ( value : unknown ) : value is Encode {
112- return this . check ( value )
105+ return this . evaluateResult . Check ( value )
106+ }
107+ /** Validates a value and returns it. Will throw if invalid. */
108+ public Parse ( value : unknown ) : Encode {
109+ const checked = this . Check ( value )
110+ if ( checked ) return value as never
111+ if ( Settings . Get ( ) . correctiveParse ) return Parser ( this . Context ( ) , this . Type ( ) , value ) as never
112+ throw new ParseError ( value , this . Errors ( value ) )
113113 }
114114 /** Inspects a value and returns a detailed list of validation errors. */
115115 public override Errors ( value : unknown ) : TLocalizedValidationError [ ] {
116- if ( Environment . CanEvaluate ( ) && this . check ( value ) ) return [ ]
117- return Errors ( this . context , this . type , value )
116+ if ( this . IsAccelerated ( ) && this . Check ( value ) ) return [ ]
117+ return Errors ( this . Context ( ) , this . Type ( ) , value )
118118 }
119+ // ----------------------------------------------------------------
120+ // Value.* Operations
121+ // ----------------------------------------------------------------
119122 /** Cleans a value using the Validator type. */
120123 public override Clean ( value : unknown ) : unknown {
121- return Clean ( this . context , this . type , value )
124+ return Clean ( this . Context ( ) , this . Type ( ) , value )
122125 }
123126 /** Converts a value using the Validator type. */
124127 public override Convert ( value : unknown ) : unknown {
125- return Convert ( this . context , this . type , value )
128+ return Convert ( this . Context ( ) , this . Type ( ) , value )
126129 }
127130 /** Creates a value using the Validator type. */
128131 public override Create ( ) : Encode {
129- return Create ( this . context , this . type )
132+ return Create ( this . Context ( ) , this . Type ( ) )
130133 }
131134 /** Creates defaults using the Validator type. */
132135 public override Default ( value : unknown ) : unknown {
133- return Default ( this . context , this . type , value )
134- }
135- /** Clones this validator. */
136- public override Clone ( ) : Validator < Context , Type > {
137- return new Validator < Context , Type > (
138- this . context ,
139- this . type ,
140- this . isAccelerated ,
141- this . hasCodec ,
142- this . code ,
143- this . check
144- )
145- }
146- /** Validates a value and returns it. Will throw if invalid. */
147- public Parse ( value : unknown ) : Encode {
148- const checked = this . Check ( value )
149- if ( checked ) return value as never
150- if ( Settings . Get ( ) . correctiveParse ) return Parser ( this . context , this . type , value ) as never
151- throw new ParseError ( value , this . Errors ( value ) )
136+ return Default ( this . Context ( ) , this . Type ( ) , value )
152137 }
153138 /** Decodes a value */
154139 public Decode ( value : unknown ) : Decode {
155- const result = this . hasCodec ? Decode ( this . context , this . type , value ) : this . Parse ( value )
140+ const result = this . hasCodec ? Decode ( this . Context ( ) , this . Type ( ) , value ) : this . Parse ( value )
156141 return result as never
157142 }
158143 /** Encodes a value */
159144 public Encode ( value : unknown ) : Encode {
160- const result = this . hasCodec ? Encode ( this . context , this . type , value ) : this . Parse ( value )
145+ const result = this . hasCodec ? Encode ( this . Context ( ) , this . Type ( ) , value ) : this . Parse ( value )
161146 return result as never
162147 }
148+ // ----------------------------------------------------------------
149+ // Deprecations
150+ // ----------------------------------------------------------------
151+ /**
152+ * @deprecated Validator instances should not support Clone because they are owners of JIT evaluated functions. This function will be
153+ * removed in the next version of TypeBox (relates to Type.Base deprecation)
154+ */
155+ public override Clone ( ) : Validator < Context , Type > {
156+ return new Validator < Context , Type > ( this . hasCodec , this . buildResult , this . evaluateResult )
157+ }
163158}
0 commit comments