@@ -16,6 +16,7 @@ import {
16
16
isEnum
17
17
} from '../utils/ast-utils' ;
18
18
import {
19
+ canReferenceNode ,
19
20
convertPath ,
20
21
extractTypeArgumentIfArray ,
21
22
getDecoratorOrUndefinedByNames ,
@@ -248,7 +249,7 @@ export class ModelClassVisitor extends AbstractFileVisitor {
248
249
) : ts . ObjectLiteralExpression {
249
250
const isRequired = ! node . questionToken ;
250
251
251
- let properties = [
252
+ const properties = [
252
253
...existingProperties ,
253
254
! hasPropertyKey ( 'required' , existingProperties ) &&
254
255
factory . createPropertyAssignment (
@@ -271,7 +272,12 @@ export class ModelClassVisitor extends AbstractFileVisitor {
271
272
options ,
272
273
sourceFile
273
274
) ,
274
- this . createDefaultPropertyAssignment ( factory , node , existingProperties ) ,
275
+ this . createDefaultPropertyAssignment (
276
+ factory ,
277
+ node ,
278
+ existingProperties ,
279
+ options
280
+ ) ,
275
281
this . createEnumPropertyAssignment (
276
282
factory ,
277
283
node ,
@@ -282,8 +288,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
282
288
)
283
289
] ;
284
290
if ( options . classValidatorShim ) {
285
- properties = properties . concat (
286
- this . createValidationPropertyAssignments ( factory , node )
291
+ properties . push (
292
+ this . createValidationPropertyAssignments ( factory , node , options )
287
293
) ;
288
294
}
289
295
return factory . createObjectLiteralExpression ( compact ( flatten ( properties ) ) ) ;
@@ -471,7 +477,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
471
477
createDefaultPropertyAssignment (
472
478
factory : ts . NodeFactory ,
473
479
node : ts . PropertyDeclaration | ts . PropertySignature ,
474
- existingProperties : ts . NodeArray < ts . PropertyAssignment >
480
+ existingProperties : ts . NodeArray < ts . PropertyAssignment > ,
481
+ options : PluginOptions
475
482
) {
476
483
const key = 'default' ;
477
484
if ( hasPropertyKey ( key , existingProperties ) ) {
@@ -484,50 +491,65 @@ export class ModelClassVisitor extends AbstractFileVisitor {
484
491
if ( ts . isAsExpression ( initializer ) ) {
485
492
initializer = initializer . expression ;
486
493
}
494
+ initializer =
495
+ this . clonePrimitiveLiteral ( factory , initializer ) ?? initializer ;
496
+
497
+ if ( ! canReferenceNode ( initializer , options ) ) {
498
+ return undefined ;
499
+ }
487
500
return factory . createPropertyAssignment ( key , initializer ) ;
488
501
}
489
502
490
503
createValidationPropertyAssignments (
491
504
factory : ts . NodeFactory ,
492
- node : ts . PropertyDeclaration | ts . PropertySignature
505
+ node : ts . PropertyDeclaration | ts . PropertySignature ,
506
+ options : PluginOptions
493
507
) : ts . PropertyAssignment [ ] {
494
508
const assignments = [ ] ;
495
509
const decorators = ts . canHaveDecorators ( node ) && ts . getDecorators ( node ) ;
496
510
497
- this . addPropertyByValidationDecorator (
498
- factory ,
499
- 'IsIn' ,
500
- 'enum' ,
501
- decorators ,
502
- assignments
503
- ) ;
511
+ if ( ! options . readonly ) {
512
+ // @IsIn () annotation is not supported in readonly mode
513
+ this . addPropertyByValidationDecorator (
514
+ factory ,
515
+ 'IsIn' ,
516
+ 'enum' ,
517
+ decorators ,
518
+ assignments ,
519
+ options
520
+ ) ;
521
+ }
504
522
this . addPropertyByValidationDecorator (
505
523
factory ,
506
524
'Min' ,
507
525
'minimum' ,
508
526
decorators ,
509
- assignments
527
+ assignments ,
528
+ options
510
529
) ;
511
530
this . addPropertyByValidationDecorator (
512
531
factory ,
513
532
'Max' ,
514
533
'maximum' ,
515
534
decorators ,
516
- assignments
535
+ assignments ,
536
+ options
517
537
) ;
518
538
this . addPropertyByValidationDecorator (
519
539
factory ,
520
540
'MinLength' ,
521
541
'minLength' ,
522
542
decorators ,
523
- assignments
543
+ assignments ,
544
+ options
524
545
) ;
525
546
this . addPropertyByValidationDecorator (
526
547
factory ,
527
548
'MaxLength' ,
528
549
'maxLength' ,
529
550
decorators ,
530
- assignments
551
+ assignments ,
552
+ options
531
553
) ;
532
554
this . addPropertiesByValidationDecorator (
533
555
factory ,
@@ -564,21 +586,36 @@ export class ModelClassVisitor extends AbstractFileVisitor {
564
586
assignments ,
565
587
( decoratorRef : ts . Decorator ) => {
566
588
const decoratorArguments = getDecoratorArguments ( decoratorRef ) ;
567
-
568
589
const result = [ ] ;
569
- result . push (
570
- factory . createPropertyAssignment (
571
- 'minLength' ,
572
- head ( decoratorArguments )
573
- )
574
- ) ;
575
590
576
- if ( decoratorArguments . length > 1 ) {
591
+ const minLength = head ( decoratorArguments ) ;
592
+ if ( ! canReferenceNode ( minLength , options ) ) {
593
+ return result ;
594
+ }
595
+
596
+ const clonedMinLength = this . clonePrimitiveLiteral ( factory , minLength ) ;
597
+ if ( clonedMinLength ) {
577
598
result . push (
578
- factory . createPropertyAssignment ( 'maxLength ' , decoratorArguments [ 1 ] )
599
+ factory . createPropertyAssignment ( 'minLength ' , clonedMinLength )
579
600
) ;
580
601
}
581
602
603
+ if ( decoratorArguments . length > 1 ) {
604
+ const maxLength = decoratorArguments [ 1 ] ;
605
+ if ( ! canReferenceNode ( maxLength , options ) ) {
606
+ return result ;
607
+ }
608
+ const clonedMaxLength = this . clonePrimitiveLiteral (
609
+ factory ,
610
+ maxLength
611
+ ) ;
612
+ if ( clonedMaxLength ) {
613
+ result . push (
614
+ factory . createPropertyAssignment ( 'maxLength' , clonedMaxLength )
615
+ ) ;
616
+ }
617
+ }
618
+
582
619
return result ;
583
620
}
584
621
) ;
@@ -606,7 +643,8 @@ export class ModelClassVisitor extends AbstractFileVisitor {
606
643
decoratorName : string ,
607
644
propertyKey : string ,
608
645
decorators : readonly ts . Decorator [ ] ,
609
- assignments : ts . PropertyAssignment [ ]
646
+ assignments : ts . PropertyAssignment [ ] ,
647
+ options : PluginOptions
610
648
) {
611
649
this . addPropertiesByValidationDecorator (
612
650
factory ,
@@ -617,16 +655,12 @@ export class ModelClassVisitor extends AbstractFileVisitor {
617
655
const argument : ts . Expression = head (
618
656
getDecoratorArguments ( decoratorRef )
619
657
) ;
620
- const assignment = ts . isNumericLiteral ( argument )
621
- ? ts . factory . createNumericLiteral ( argument . text )
622
- : ts . isStringLiteral ( argument )
623
- ? ts . factory . createStringLiteral ( argument . text )
624
- : argument ;
625
-
626
- if ( assignment ) {
627
- return [ factory . createPropertyAssignment ( propertyKey , assignment ) ] ;
658
+ const assignment =
659
+ this . clonePrimitiveLiteral ( factory , argument ) ?? argument ;
660
+ if ( ! canReferenceNode ( assignment , options ) ) {
661
+ return [ ] ;
628
662
}
629
- return [ ] ;
663
+ return [ factory . createPropertyAssignment ( propertyKey , assignment ) ] ;
630
664
}
631
665
) ;
632
666
}
@@ -774,4 +808,28 @@ export class ModelClassVisitor extends AbstractFileVisitor {
774
808
}
775
809
return typeRef ;
776
810
}
811
+
812
+ private clonePrimitiveLiteral ( factory : ts . NodeFactory , node : ts . Node ) {
813
+ const primitiveTypeName = this . getInitializerPrimitiveTypeName ( node ) ;
814
+ if ( ! primitiveTypeName ) {
815
+ return undefined ;
816
+ }
817
+ return createPrimitiveLiteral ( factory , node . getText ( ) , primitiveTypeName ) ;
818
+ }
819
+
820
+ private getInitializerPrimitiveTypeName ( node : ts . Node ) {
821
+ if (
822
+ ts . isIdentifier ( node ) &&
823
+ ( node . text === 'true' || node . text === 'false' )
824
+ ) {
825
+ return 'boolean' ;
826
+ }
827
+ if ( ts . isNumericLiteral ( node ) || ts . isPrefixUnaryExpression ( node ) ) {
828
+ return 'number' ;
829
+ }
830
+ if ( ts . isStringLiteral ( node ) ) {
831
+ return 'string' ;
832
+ }
833
+ return undefined ;
834
+ }
777
835
}
0 commit comments