1+ import { int } from "../number" ;
12import { randomString } from "../string" ;
23import { clone } from "../util" ;
34import * as templates from "./templates" ;
4- import type { ArrayTemplate , BooleanTemplate , FloatTemplate , IntegerTemplate , LiteralTemplate , NumberTemplate , ObjectTemplate , OrTemplate , StringTemplate , Template , TemplateNode } from "./types" ;
5+ import type { ArrayTemplate , BooleanTemplate , FloatTemplate , IntegerTemplate , LiteralTemplate , NumberTemplate , ObjectTemplate , OrTemplate , StringTemplate , Template , TemplateNode , TemplateShorthand } from "./types" ;
56
67export interface TemplateJsonOpts {
7- maxNodeCount ?: number ;
8+ /**
9+ * Sets the limit of maximum number of JSON nodes to generate. This is a soft
10+ * limit: once this limit is reached, no further optional values are generate
11+ * (optional object and map keys are not generated, arrays are generated with
12+ * their minimum required size).
13+ */
14+ maxNodes ?: number ;
815}
916
1017export class TemplateJson {
@@ -17,16 +24,16 @@ export class TemplateJson {
1724 protected maxNodes : number ;
1825
1926 constructor ( public readonly template : Template = templates . nil , public readonly opts : TemplateJsonOpts = { } ) {
20- this . maxNodes = opts . maxNodeCount ?? 100 ;
27+ this . maxNodes = opts . maxNodes ?? 100 ;
2128 }
2229
2330 public gen ( ) : unknown {
2431 return this . generate ( this . template ) ;
2532 }
2633
2734 protected generate ( tpl : Template ) : unknown {
28- if ( this . nodes >= this . maxNodes ) return null ;
2935 this . nodes ++ ;
36+ while ( typeof tpl === 'function' ) tpl = tpl ( ) ;
3037 const template : TemplateNode = typeof tpl === 'string' ? [ tpl ] : tpl ;
3138 const type = template [ 0 ] ;
3239 switch ( type ) {
@@ -55,13 +62,19 @@ export class TemplateJson {
5562 }
5663 }
5764
65+ protected minmax ( min : number , max : number ) : number {
66+ if ( this . nodes > this . maxNodes ) return min ;
67+ if ( this . nodes + max > this . maxNodes ) max = this . maxNodes - this . nodes ;
68+ if ( max < min ) max = min ;
69+ return int ( min , max ) ;
70+ }
71+
5872 protected generateArray ( template : ArrayTemplate ) : unknown [ ] {
5973 const [ , min = 0 , max = 5 , itemTemplate = 'nil' , head = [ ] , tail = [ ] ] = template ;
60- const length = Math . floor ( Math . random ( ) * ( max - min + 1 ) ) + min ;
74+ const length = this . minmax ( min , max ) ;
6175 const result : unknown [ ] = [ ] ;
6276 for ( const tpl of head ) result . push ( this . generate ( tpl ) ) ;
63- const mainCount = Math . max ( 0 , length - head . length - tail . length ) ;
64- for ( let i = 0 ; i < mainCount ; i ++ ) result . push ( this . generate ( itemTemplate ) ) ;
77+ for ( let i = 0 ; i < length ; i ++ ) result . push ( this . generate ( itemTemplate ) ) ;
6578 for ( const tpl of tail ) result . push ( this . generate ( tpl ) ) ;
6679 return result ;
6780 }
@@ -71,8 +84,11 @@ export class TemplateJson {
7184 const result : Record < string , unknown > = { } ;
7285 for ( const field of fields ) {
7386 const [ keyToken , valueTemplate = 'nil' , optionality = 0 ] = field ;
74- if ( optionality && Math . random ( ) < optionality ) continue ;
75- const key = randomString ( keyToken ?? templates . tokensHelloWorld ) ;
87+ if ( optionality ) {
88+ if ( this . nodes > this . maxNodes ) continue ;
89+ if ( Math . random ( ) < optionality ) continue ;
90+ }
91+ const key = randomString ( keyToken ?? templates . tokensObjectKey ) ;
7692 const value = this . generate ( valueTemplate ) ;
7793 result [ key ] = value ;
7894 }
@@ -90,31 +106,28 @@ export class TemplateJson {
90106
91107 protected generateInteger ( template : IntegerTemplate ) : number {
92108 const [ , min = Number . MIN_SAFE_INTEGER , max = Number . MAX_SAFE_INTEGER ] = template ;
93- let int = Math . round ( Math . random ( ) * ( max - min ) + min ) ;
94- int = Math . max ( Number . MIN_SAFE_INTEGER , Math . min ( Number . MAX_SAFE_INTEGER , int ) ) ;
95- return int ;
109+ return int ( min , max ) ;
96110 }
97111
98112 protected generateFloat ( template : FloatTemplate ) : number {
99113 const [ , min = - Number . MAX_VALUE , max = Number . MAX_VALUE ] = template ;
100114 let float = Math . random ( ) * ( max - min ) + min ;
101- float = Math . max ( - Number . MAX_VALUE , Math . min ( Number . MAX_VALUE , float ) ) ;
115+ float = Math . max ( min , Math . min ( max , float ) ) ;
102116 return float ;
103117 }
104118
105119 protected generateBoolean ( template : BooleanTemplate ) : boolean {
106- const [ , value ] = template ;
120+ const value = template [ 1 ] ;
107121 return value !== undefined ? value : Math . random ( ) < 0.5 ;
108122 }
109123
110124 protected generateLiteral ( template : LiteralTemplate ) : unknown {
111- const [ , value ] = template ;
112- return clone ( value ) ;
125+ return clone ( template [ 1 ] ) ;
113126 }
114127
115128 protected generateOr ( template : OrTemplate ) : unknown {
116129 const [ , ...options ] = template ;
117- const randomIndex = Math . floor ( Math . random ( ) * options . length ) ;
118- return this . generate ( options [ randomIndex ] ) ;
130+ const index = int ( 0 , options . length - 1 ) ;
131+ return this . generate ( options [ index ] ) ;
119132 }
120133}
0 commit comments