@@ -5,14 +5,15 @@ import { QueryFn, QueryFunction } from "../../libs/jsonpath.ts";
5
5
import { TypeGraph } from "../../typegraph/mod.ts" ;
6
6
import { Type } from "../../typegraph/type_node.ts" ;
7
7
import { ParameterTransformNode } from "../../typegraph/types.ts" ;
8
- import { generateBooleanValidator } from "../typecheck/inline_validators/boolean .ts" ;
8
+ import { ValidationContext , validationContext } from "../typecheck/common .ts" ;
9
9
import { generateListValidator } from "../typecheck/inline_validators/list.ts" ;
10
10
import { generateNumberValidator } from "../typecheck/inline_validators/number.ts" ;
11
11
import {
12
12
generateObjectValidator ,
13
13
getKeys ,
14
14
} from "../typecheck/inline_validators/object.ts" ;
15
15
import { generateStringValidator } from "../typecheck/inline_validators/string.ts" ;
16
+ import { InputValidationCompiler } from "../typecheck/input.ts" ;
16
17
17
18
export type TransformParamsInput = {
18
19
args : Record < string , any > ;
@@ -35,7 +36,10 @@ type CompiledTransformerInput = {
35
36
} ;
36
37
37
38
type CompiledTransformer = {
38
- ( input : CompiledTransformerInput ) : Record < string , any > ;
39
+ (
40
+ input : CompiledTransformerInput ,
41
+ contxt : ValidationContext ,
42
+ ) : Record < string , any > ;
39
43
} ;
40
44
41
45
export function compileParameterTransformer (
@@ -45,10 +49,10 @@ export function compileParameterTransformer(
45
49
) : TransformParams {
46
50
const ctx = new TransformerCompilationContext ( typegraph , parentProps ) ;
47
51
const { fnBody, deps } = ctx . compile ( transformerTreeRoot ) ;
48
- const fn = new Function ( "input" , fnBody ) as CompiledTransformer ;
52
+ const fn = new Function ( "input" , "context" , fnBody ) as CompiledTransformer ;
49
53
return ( { args, context, parent } ) => {
50
54
const getContext = compileContextQueries ( deps . contexts ) ( context ) ;
51
- const res = fn ( { args, getContext, parent } ) ;
55
+ const res = fn ( { args, getContext, parent } , validationContext ) ;
52
56
return res ;
53
57
} ;
54
58
}
@@ -105,10 +109,16 @@ class TransformerCompilationContext {
105
109
nonStrictMode : new Set ( ) ,
106
110
} ,
107
111
} ;
112
+ #inputValidatorCompiler: InputValidationCompiler ;
113
+ #typesWithCustomValidator: Set < number > = new Set ( ) ;
108
114
109
115
constructor ( typegraph : TypeGraph , parentProps : Record < string , number > ) {
110
116
this . #tg = typegraph ;
111
117
this . #parentProps = parentProps ;
118
+ this . #inputValidatorCompiler = new InputValidationCompiler (
119
+ typegraph ,
120
+ ( idx ) => `validate_${ idx } ` ,
121
+ ) ;
112
122
}
113
123
114
124
#reset( ) {
@@ -127,8 +137,11 @@ class TransformerCompilationContext {
127
137
this . #reset( ) ;
128
138
const varName = this . #compileNode( rootNode ) ;
129
139
this . #collector. push ( `return ${ varName } ;` ) ;
140
+ const customValidators = [ ...this . #typesWithCustomValidator]
141
+ . map ( ( idx ) => this . #inputValidatorCompiler. codes . get ( idx ) )
142
+ . join ( "\n" ) ;
130
143
const res = {
131
- fnBody : this . #collector. join ( "\n" ) ,
144
+ fnBody : customValidators + this . #collector. join ( "\n" ) ,
132
145
deps : this . #dependencies,
133
146
} ;
134
147
@@ -232,7 +245,7 @@ class TransformerCompilationContext {
232
245
const varName = this . #createVarName( ) ;
233
246
let typeNode = this . #tg. type ( typeIdx ) ;
234
247
let optional = false ;
235
- if ( typeNode . type === Type . OPTIONAL ) {
248
+ while ( typeNode . type === Type . OPTIONAL ) {
236
249
typeNode = this . #tg. type ( typeNode . item ) ;
237
250
optional = true ;
238
251
}
@@ -248,45 +261,24 @@ class TransformerCompilationContext {
248
261
249
262
this . #collector. push ( `if (${ varName } != null) {` ) ;
250
263
251
- switch ( typeNode . type ) {
252
- case Type . OPTIONAL :
253
- throw new Error ( `At "${ path } ": nested optional not supported` ) ;
254
- case Type . INTEGER : {
255
- const parsedVar = this . #createVarName( ) ;
256
- this . #collector. push (
257
- `const ${ parsedVar } = parseInt(${ varName } , 10);` ,
258
- ...generateNumberValidator ( typeNode , parsedVar , path ) ,
259
- ) ;
260
- break ;
261
- }
262
- case Type . FLOAT : {
263
- const parsedVar = this . #createVarName( ) ;
264
- this . #collector. push (
265
- `const ${ parsedVar } = parseFloat(${ varName } );` ,
266
- ...generateNumberValidator ( typeNode , parsedVar , path ) ,
267
- ) ;
268
- break ;
269
- }
270
- case Type . STRING :
271
- this . #collector. push (
272
- ...generateStringValidator ( typeNode , varName , path ) ,
273
- ) ;
274
- break ;
275
- case Type . BOOLEAN : {
276
- const parsedVar = this . #createVarName( ) ;
277
-
278
- this . #collector. push (
279
- `const ${ varName } = Boolean(${ varName } );` ,
280
- ...generateBooleanValidator ( typeNode , parsedVar , path ) ,
281
- ) ;
282
- break ;
283
- }
284
-
285
- default :
286
- throw new Error (
287
- `At "${ path } ": Unsupported type "${ typeNode . type } " for context injection` ,
288
- ) ;
264
+ const types = this . #inputValidatorCompiler. generateValidators ( typeIdx ) ;
265
+ for ( const idx of types ) {
266
+ this . #typesWithCustomValidator. add ( idx ) ;
289
267
}
268
+ const errorVar = this . #createVarName( ) ;
269
+ this . #collector. push ( `const ${ errorVar } = [];` ) ;
270
+ const args = [ varName , JSON . stringify ( path ) , errorVar , "context" ] ;
271
+ this . #collector. push ( ` validate_${ typeIdx } (${ args . join ( ", " ) } );` ) ;
272
+ this . #collector. push ( ` if (${ errorVar } .length > 0) {` ) ;
273
+ const errorStrVar = this . #createVarName( ) ;
274
+ const errMap = `([path, msg]) => \` - at \${path}: \${msg}\`` ;
275
+ this . #collector. push (
276
+ ` const ${ errorStrVar } = ${ errorVar } .map(${ errMap } ).join("\\n");` ,
277
+ ) ;
278
+ this . #collector. push (
279
+ ` throw new Error(\`Context validation failed:\\n\${${ errorStrVar } }\`);` ,
280
+ ) ;
281
+ this . #collector. push ( ` }` ) ;
290
282
291
283
this . #collector. push ( "}" ) ;
292
284
if ( ! optional ) {
@@ -316,14 +308,23 @@ class TransformerCompilationContext {
316
308
...generateStringValidator ( typeNode , varName , path ) ,
317
309
) ;
318
310
break ;
319
- case Type . INTEGER :
320
- case Type . FLOAT :
311
+ case Type . INTEGER : {
312
+ const parsedVar = this . #createVarName( ) ;
313
+ this . #collector. push (
314
+ `const ${ parsedVar } = parseInt(${ varName } , 10);` ,
315
+ ...generateNumberValidator ( typeNode , parsedVar , path ) ,
316
+ ) ;
317
+ break ;
318
+ }
319
+ case Type . FLOAT : {
320
+ const parsedVar = this . #createVarName( ) ;
321
321
this . #collector. push (
322
- ...generateNumberValidator ( typeNode , varName , path ) ,
322
+ `const ${ parsedVar } = parseFloat(${ varName } );` ,
323
+ ...generateNumberValidator ( typeNode , parsedVar , path ) ,
323
324
) ;
324
325
break ;
326
+ }
325
327
default :
326
- // TODO optional??
327
328
throw new Error (
328
329
`At "${ path } ": Unsupported type "${ typeNode . type } " for secret injection` ,
329
330
) ;
0 commit comments