@@ -68,12 +68,14 @@ Validator.prototype.compile = function(schema) {
6868 }
6969
7070 const rules = this . compileSchemaType ( schema ) ;
71+ this . cache . clear ( ) ;
7172 return function ( value ) {
7273 return self . checkSchemaType ( value , rules , undefined , null ) ;
7374 } ;
7475 }
7576
7677 const rule = this . compileSchemaObject ( schema ) ;
78+ this . cache . clear ( ) ;
7779 return function ( value ) {
7880 return self . checkSchemaObject ( value , rule , undefined , null ) ;
7981 } ;
@@ -84,26 +86,32 @@ Validator.prototype.compileSchemaObject = function(schemaObject) {
8486 throw new Error ( "Invalid schema!" ) ;
8587 }
8688
87- const compiledObject = Object . keys ( schemaObject ) . map ( name => {
89+ let compiledObject = this . cache . get ( schemaObject ) ;
90+ if ( compiledObject ) {
91+ compiledObject . cycle = true ;
92+ return compiledObject ;
93+ } else {
94+ compiledObject = { cycle : false , properties : null , compiledObjectFunction : null , objectStack : [ ] } ;
95+ this . cache . set ( schemaObject , compiledObject ) ;
96+ }
97+
98+ compiledObject . properties = Object . keys ( schemaObject ) . map ( name => {
8899 const compiledType = this . compileSchemaType ( schemaObject [ name ] ) ;
89100 return { name : name , compiledType : compiledType } ;
90101 } ) ;
91102
92- // Uncomment this line to use compiled object validator:
93- // return compiledObject;
94-
95103 const sourceCode = [ ] ;
96104 sourceCode . push ( "let res;" ) ;
97105 sourceCode . push ( "let propertyPath;" ) ;
98106 sourceCode . push ( "const errors = [];" ) ;
99- for ( let i = 0 ; i < compiledObject . length ; i ++ ) {
100- const property = compiledObject [ i ] ;
107+ for ( let i = 0 ; i < compiledObject . properties . length ; i ++ ) {
108+ const property = compiledObject . properties [ i ] ;
101109 const name = property . name ;
102110 sourceCode . push ( `propertyPath = (path !== undefined ? path + ".${ name } " : "${ name } ");` ) ;
103111 if ( Array . isArray ( property . compiledType ) ) {
104- sourceCode . push ( `res = this.checkSchemaType(value.${ name } , compiledObject [${ i } ].compiledType, propertyPath, value);` ) ;
112+ sourceCode . push ( `res = this.checkSchemaType(value.${ name } , properties [${ i } ].compiledType, propertyPath, value);` ) ;
105113 } else {
106- sourceCode . push ( `res = this.checkSchemaRule(value.${ name } , compiledObject [${ i } ].compiledType, propertyPath, value);` ) ;
114+ sourceCode . push ( `res = this.checkSchemaRule(value.${ name } , properties [${ i } ].compiledType, propertyPath, value);` ) ;
107115 }
108116 sourceCode . push ( "if (res !== true) {" ) ;
109117 sourceCode . push ( "\tthis.handleResult(errors, propertyPath, res);" ) ;
@@ -112,12 +120,9 @@ Validator.prototype.compileSchemaObject = function(schemaObject) {
112120
113121 sourceCode . push ( "return errors.length === 0 ? true : errors;" ) ;
114122
115- const compiledObjectFunction = new Function ( "value" , "compiledObject " , "path" , "parent" , sourceCode . join ( "\n" ) ) ;
123+ compiledObject . compiledObjectFunction = new Function ( "value" , "properties " , "path" , "parent" , sourceCode . join ( "\n" ) ) ;
116124
117- const self = this ;
118- return function ( value , _unused , path , parent ) {
119- return compiledObjectFunction . call ( self , value , compiledObject , path , parent ) ;
120- } ;
125+ return compiledObject ;
121126} ;
122127
123128Validator . prototype . compileSchemaType = function ( schemaType ) {
@@ -135,14 +140,6 @@ Validator.prototype.compileSchemaType = function(schemaType) {
135140} ;
136141
137142Validator . prototype . compileSchemaRule = function ( schemaRule ) {
138- const compiledRule = { } ;
139- const cachedResult = this . cache . get ( schemaRule ) ;
140- if ( cachedResult ) {
141- return cachedResult ;
142- } else {
143- this . cache . set ( schemaRule , compiledRule ) ;
144- }
145-
146143 if ( typeof schemaRule === "string" ) {
147144 schemaRule = {
148145 type : schemaRule
@@ -165,32 +162,49 @@ Validator.prototype.compileSchemaRule = function(schemaRule) {
165162 dataFunction = this . checkSchemaArray ;
166163 }
167164
168- return Object . assign ( compiledRule , {
165+ return {
169166 schemaRule : schemaRule ,
170167 ruleFunction : ruleFunction ,
171168 dataFunction : dataFunction ,
172169 dataParameter : dataParameter
173- } ) ;
170+ } ;
174171} ;
175172
176173Validator . prototype . checkSchemaObject = function ( value , compiledObject , path , parent ) {
177- if ( compiledObject instanceof Function ) {
178- return compiledObject ( value , undefined , path , parent ) ;
174+ if ( compiledObject . cycle ) {
175+ if ( compiledObject . objectStack . indexOf ( value ) !== - 1 ) {
176+ return true ;
177+ }
178+
179+ compiledObject . objectStack . push ( value ) ;
180+ const result = this . checkSchemaObjectInner ( value , compiledObject , path , parent ) ;
181+ compiledObject . objectStack . pop ( ) ;
182+ return result ;
183+ } else {
184+ return this . checkSchemaObjectInner ( value , compiledObject , path , parent ) ;
179185 }
186+ } ;
187+
188+ Validator . prototype . checkSchemaObjectInner = function ( value , compiledObject , path , parent ) {
189+ return compiledObject . compiledObjectFunction . call ( this , value , compiledObject . properties , path , parent ) ;
190+
191+ /*
192+ // Reference implementation of the object checker
180193
181194 const errors = [];
182- const checksLength = compiledObject . length ;
183- for ( let i = 0 ; i < checksLength ; i ++ ) {
184- const check = compiledObject [ i ] ;
185- const propertyPath = ( path !== undefined ? path + "." : "" ) + check . name ;
186- const res = this . checkSchemaType ( value [ check . name ] , check . compiledType , propertyPath , value ) ;
195+ const propertiesLength = compiledObject.properties .length;
196+ for (let i = 0; i < propertiesLength ; i++) {
197+ const property = compiledObject.properties [i];
198+ const propertyPath = (path !== undefined ? path + "." : "") + property .name;
199+ const res = this.checkSchemaType(value[property .name], property .compiledType, propertyPath, value);
187200
188201 if (res !== true) {
189202 this.handleResult(errors, propertyPath, res);
190203 }
191204 }
192205
193206 return errors.length === 0 ? true : errors;
207+ */
194208} ;
195209
196210Validator . prototype . checkSchemaType = function ( value , compiledType , path , parent ) {
0 commit comments