@@ -3405,4 +3405,38 @@ suite('JSON Parser', () => {
34053405 assert . strictEqual ( res . length , 0 ) ;
34063406 } ) ;
34073407
3408+ test ( 'Validation should not take exponential time for recursive schemas with enum discriminators' , async function ( ) {
3409+ const schema : JSONSchema = {
3410+ $id : "http://example.com/schema" ,
3411+ definitions : {
3412+ rule : {
3413+ anyOf : [
3414+ { type : "object" , properties : { type : { enum : [ "A" ] } , content : { $ref : "#/definitions/rule" } } } ,
3415+ { type : "object" , properties : { type : { enum : [ "B" ] } , content : { $ref : "#/definitions/rule" } } } ,
3416+ { type : "object" , properties : { type : { enum : [ "C" ] } , content : { $ref : "#/definitions/rule" } } }
3417+ ]
3418+ }
3419+ } ,
3420+ $ref : "#/definitions/rule"
3421+ } ;
3422+
3423+ // {"content": {"content": {"content": ... }}}
3424+ let nested = '{"type": "A"}' ;
3425+ for ( let i = 0 ; i < 14 ; i ++ ) {
3426+ nested = `{"type": "A", "content": ${ nested } }` ;
3427+ }
3428+
3429+ const { textDoc, jsonDoc } = toDocument ( nested ) ;
3430+ const ls = getLanguageService ( { } ) ;
3431+ ls . configure ( { schemas : [ { fileMatch : [ "*.json" ] , uri : "http://example.com/schema" , schema } ] } ) ;
3432+
3433+ const startTime = Date . now ( ) ;
3434+ await ls . doValidation ( textDoc , jsonDoc , undefined , schema ) ;
3435+ const endTime = Date . now ( ) ;
3436+
3437+ // Validation should finish well under 10ms. Before the `enum` optimization,
3438+ // this produced 4.7 million branch iterations and took nearly 5,000ms.
3439+ assert . ok ( endTime - startTime < 100 , "Validation took too long! Exponential scaling detected." ) ;
3440+ } ) ;
3441+
34083442} ) ;
0 commit comments