@@ -1815,6 +1815,50 @@ module.exports = {
18151815    return  path . match ( / ( \{ \{ [ ^ \/ \{ \} ] + \} \} ) / g) ; 
18161816  } , 
18171817
1818+   /** 
1819+    * Finds all the possible path variables conversion from schema path, 
1820+    * and excludes path variable that are converted to collection variable 
1821+    * @param  {string } path Path string 
1822+    * @returns  {array } Array of path variables. 
1823+    */ 
1824+   findPathVariablesFromSchemaPath : function  ( path )  { 
1825+     // /{path}/{file}.{format}/{hello} return [ '/{path}', '/{hello}' ] 
1826+     // https://regex101.com/r/aFRWQD/4 
1827+     let  matches  =  path . match ( / ( \/ \{ [ ^ \/ \{ \} ] + \} (? = [ \/ \0 ] | $ ) ) / g) ; 
1828+ 
1829+     // remove leading '/' and starting and ending curly braces 
1830+     return  _ . map ( matches ,  ( match )  =>  {  return  match . slice ( 2 ,  - 1 ) ;  } ) ; 
1831+   } , 
1832+ 
1833+   /** 
1834+    * Finds fixed parts present in path segment of collection or schema. 
1835+    * 
1836+    * @param  {String } segment - Path segment 
1837+    * @param  {String } pathType - Path type (one of 'collection' / 'schema') 
1838+    * @returns  {Array } - Array of strings where each element is fixed part in order of their occurence 
1839+    */ 
1840+   getFixedPartsFromPathSegment : function  ( segment ,  pathType  =  'collection' )  { 
1841+     var  tempSegment  =  segment , 
1842+       // collection is default 
1843+       varMatches  =  segment . match ( pathType  ===  'schema'  ? / ( \{ [ ^ \/ \{ \} ] + \} ) / g/ ( \{ \{ [ ^ \/ \{ \} ] + \} \} ) / g) , 
1844+       fixedParts  =  [ ] ; 
1845+ 
1846+     _ . forEach ( varMatches ,  ( match )  =>  { 
1847+       let  matchedIndex  =  tempSegment . indexOf ( match ) ; 
1848+ 
1849+       // push fixed part before collection variable if present 
1850+       ( matchedIndex  !==  0 )  &&  ( fixedParts . push ( tempSegment . slice ( 0 ,  matchedIndex ) ) ) ; 
1851+ 
1852+       // substract starting fixed and variable part from tempSegment 
1853+       tempSegment  =  tempSegment . substr ( matchedIndex  +  match . length ) ; 
1854+     } ) ; 
1855+ 
1856+     // add last fixed part if present 
1857+     ( tempSegment . length  >  0 )  &&  ( fixedParts . push ( tempSegment ) ) ; 
1858+ 
1859+     return  fixedParts ; 
1860+   } , 
1861+ 
18181862  /** Separates out collection and path variables from the reqUrl 
18191863   * 
18201864   * @param  {string } reqUrl Request Url 
@@ -1874,7 +1918,7 @@ module.exports = {
18741918      reqBody  =  operationItem . properties . requestBody , 
18751919      itemParams  =  operationItem . properties . parameters , 
18761920      reqParams  =  this . getParametersForPathItem ( itemParams ) , 
1877-       baseUrl  =  openapi . baseUrl , 
1921+       baseUrl  =  '{{ baseUrl}}' , 
18781922      pathVarArray  =  [ ] , 
18791923      authHelper , 
18801924      item , 
@@ -1906,12 +1950,14 @@ module.exports = {
19061950    // Add collection variables to the variableStore. 
19071951    sanitizeResult . collectionVars . forEach ( ( element )  =>  { 
19081952      if  ( ! variableStore [ element . name ] )  { 
1909-         variableStore [ element . name ]  =  { 
1910-           id : element . name , 
1911-           value : element . default  ||  '' , 
1912-           description : element . description , 
1913-           type : 'collection' 
1914-         } ; 
1953+         let  fakedData  =  options . schemaFaker  ?
1954+             safeSchemaFaker ( element . schema  ||  { } ,  options . requestParametersResolution ,  PROCESSING_TYPE . CONVERSION , 
1955+               PARAMETER_SOURCE . REQUEST ,  components ,  SCHEMA_FORMATS . DEFAULT ,  options . indentCharacter ,  schemaCache , 
1956+               options . stackLimit )  : '' , 
1957+           convertedPathVar  =  _ . get ( this . convertParamsWithStyle ( element ,  fakedData ,  PARAMETER_SOURCE . REQUEST , 
1958+             components ,  schemaCache ) ,  '[0]' ,  { } ) ; 
1959+ 
1960+         variableStore [ element . name ]  =  _ . assign ( convertedPathVar ,  {  id : element . name ,  type : 'collection'  } ) ; 
19151961      } 
19161962    } ) ; 
19171963    // accounting for the overriding of the root level and path level servers object if present at the operation level 
@@ -2294,7 +2340,8 @@ module.exports = {
22942340      retVal . push ( { 
22952341        // using path instead of operationId / sumamry since it's widely understood 
22962342        name : method  +  ' '  +  path , 
2297-         path : matchedPath , 
2343+         // assign path as schemaPathName property to use path in path object 
2344+         path : _ . assign ( matchedPath ,  {  schemaPathName : path  } ) , 
22982345        jsonPath : matchedPathJsonPath  +  '.'  +  method . toLowerCase ( ) , 
22992346        pathVariables : pathVars , 
23002347        score : score 
@@ -2410,8 +2457,8 @@ module.exports = {
24102457    // decide explodable params, starting value and separators between key-value and properties for serialisation 
24112458    switch  ( style )  { 
24122459      case  'matrix' :
2413-         isExplodable  =  true ; 
2414-         startValue  =  ';'  +  ( paramSchema . type  ===  'object'  ? ''  : ( paramName  +   _ . isEmpty ( paramValue )  ?  ''  :  '=' ) ) ; 
2460+         isExplodable  =  paramSchema . type   ===   'object'   ||   explode ; 
2461+         startValue  =  ';'  +  ( ( paramSchema . type  ===  'object'  &&   explode )   ? ''  : ( paramName  +  '=' ) ) ; 
24152462        propSeparator  =  explode  ? ';'  : ',' ; 
24162463        keyValueSeparator  =  explode  ? '='  : ',' ; 
24172464        break ; 
@@ -2475,7 +2522,7 @@ module.exports = {
24752522      } ; 
24762523
24772524    // for invalid param object return null 
2478-     if  ( ! _ . isObject ( param ) )  { 
2525+     if  ( ! _ . isObject ( param )   ||   ! _ . isString ( paramValue ) )  { 
24792526      return  null ; 
24802527    } 
24812528
@@ -2702,10 +2749,10 @@ module.exports = {
27022749
27032750                  // for empty string _.set creates new key with empty string '', so separate handling 
27042751                  if  ( dataPath  ===  '' )  { 
2705-                     suggestedValue  =  this . getSuggestedValue ( fakedValue ,  valueToUse ,  ajvError ) ; 
2752+                     suggestedValue  =  this . getSuggestedValue ( fakedValue ,  suggestedValue ,  ajvError ) ; 
27062753                  } 
27072754                  else  { 
2708-                     _ . set ( suggestedValue ,  dataPath ,  this . getSuggestedValue ( fakedValue ,  valueToUse ,  ajvError ) ) ; 
2755+                     _ . set ( suggestedValue ,  dataPath ,  this . getSuggestedValue ( fakedValue ,  suggestedValue ,  ajvError ) ) ; 
27092756                  } 
27102757                } ) ; 
27112758
@@ -2794,14 +2841,18 @@ module.exports = {
27942841    var  mismatchProperty  =  'PATHVARIABLE' , 
27952842      // all path variables defined in this path. acc. to the spec, all path params are required 
27962843      schemaPathVariables , 
2844+       pmPathVariables , 
27972845      schemaPathVar ; 
27982846
27992847    if  ( options . validationPropertiesToIgnore . includes ( mismatchProperty ) )  { 
28002848      return  callback ( null ,  [ ] ) ; 
28012849    } 
28022850
2851+     // find all schema path variables that can be present as collection path variables 
2852+     pmPathVariables  =  this . findPathVariablesFromSchemaPath ( schemaPath . schemaPathName ) ; 
28032853    schemaPathVariables  =  _ . filter ( schemaPath . parameters ,  ( param )  =>  { 
2804-       return  ( param . in  ===  'path' ) ; 
2854+       // exclude path variables stored as collection variable from being validated further 
2855+       return  ( param . in  ===  'path'  &&  _ . includes ( pmPathVariables ,  param . name ) ) ; 
28052856    } ) ; 
28062857
28072858    async . map ( determinedPathVariables ,  ( pathVar ,  cb )  =>  { 
@@ -3413,6 +3464,10 @@ module.exports = {
34133464          schemaPathPrefix  +  '.content' ,  _ . get ( schemaResponse ,  'content' ) ,  mismatchProperty ,  options ) ; 
34143465
34153466      _ . each ( _ . filter ( schemaHeaders ,  ( h ,  hName )  =>  { 
3467+         // exclude empty headers fron validation 
3468+         if  ( _ . isEmpty ( h ) )  { 
3469+           return  false ; 
3470+         } 
34163471        h . name  =  hName ; 
34173472        return  h . required ; 
34183473      } ) ,  ( header )  =>  { 
@@ -3610,6 +3665,15 @@ module.exports = {
36103665      } 
36113666    } ) ; 
36123667
3668+     // handle root path '/' 
3669+     if  ( postmanPath  ===  '/'  &&  schemaPath  ===  '/' )  { 
3670+       anyMatchFound  =  true ; 
3671+       maxScoreFound  =  1 ;  // assign max possible score 
3672+       matchedPathVars  =  [ ] ;  // no path variables present 
3673+       fixedMatchedSegments  =  0 ; 
3674+       variableMatchedSegments  =  0 ; 
3675+     } 
3676+ 
36133677    if  ( anyMatchFound )  { 
36143678      return  { 
36153679        match : true , 
@@ -3642,7 +3706,14 @@ module.exports = {
36423706      // No. of fixed segment matches between schema and postman url path 
36433707      fixedMatchedSegments  =  0 , 
36443708      // No. of variable segment matches between schema and postman url path 
3645-       variableMatchedSegments  =  0 ; 
3709+       variableMatchedSegments  =  0 , 
3710+       // checks if schema segment provided is path variable 
3711+       isSchemaSegmentPathVar  =  ( segment )  =>  { 
3712+         return  segment . startsWith ( '{' )  && 
3713+         segment . endsWith ( '}' )  && 
3714+         // check that only one path variable is present as collection path variable can contain only one var 
3715+         segment . indexOf ( '}' )  ===  segment . lastIndexOf ( '}' ) ; 
3716+       } ; 
36463717
36473718    if  ( options . strictRequestMatching  &&  pmSuffix . length  !==  schemaPath . length )  { 
36483719      return  { 
@@ -3656,28 +3727,31 @@ module.exports = {
36563727    // segments match if the schemaPath segment is {..} or the postmanPathStr is :<anything> or {{anything}} 
36573728    // for (let i = pmSuffix.length - 1; i >= 0; i--) { 
36583729    for  ( let  i  =  0 ;  i  <  minLength ;  i ++ )  { 
3730+       let  schemaFixedParts  =  this . getFixedPartsFromPathSegment ( schemaPath [ sMax  -  i ] ,  'schema' ) , 
3731+         collectionFixedParts  =  this . getFixedPartsFromPathSegment ( pmSuffix [ pMax  -  i ] ,  'collection' ) ; 
3732+ 
36593733      if  ( 
3660-         ( schemaPath [ sMax   -   i ]   ===   pmSuffix [ pMax   -   i ] )  ||  // exact match 
3661-         ( schemaPath [ sMax   -   i ] . startsWith ( '{' )   &&   schemaPath [ sMax  -  i ] . endsWith ( '}' ) )  ||  // schema segment is a pathVar 
3734+         ( _ . isEqual ( schemaFixedParts ,   collectionFixedParts ) )  ||  // exact fixed parts  match 
3735+         ( isSchemaSegmentPathVar ( schemaPath [ sMax  -  i ] ) )  ||  // schema segment is a pathVar 
36623736        ( pmSuffix [ pMax  -  i ] . startsWith ( ':' ) )  ||  // postman segment is a pathVar 
36633737        ( this . isPmVariable ( pmSuffix [ pMax  -  i ] ) )  // postman segment is an env/collection var 
36643738      )  { 
36653739
36663740        // for variable match increase variable matched segments count (used for determining order for multiple matches) 
36673741        if  ( 
3668-           ( schemaPath [ sMax   -   i ] . startsWith ( '{' )   &&   schemaPath [ sMax  -  i ] . endsWith ( '}' ) )  &&  // schema segment is a pathVar 
3742+           ( isSchemaSegmentPathVar ( schemaPath [ sMax  -  i ] ) )  &&  // schema segment is a pathVar 
36693743          ( ( pmSuffix [ pMax  -  i ] . startsWith ( ':' ) )  ||  // postman segment is a pathVar 
36703744            ( this . isPmVariable ( pmSuffix [ pMax  -  i ] ) ) )  // postman segment is an env/collection var 
36713745        )  { 
36723746          variableMatchedSegments ++ ; 
36733747        } 
36743748        // for exact match increase fix matched segments count (used for determining order for multiple matches) 
3675-         else  if  ( schemaPath [ sMax   -   i ]   ===   pmSuffix [ pMax   -   i ] )  { 
3749+         else  if  ( _ . isEqual ( schemaFixedParts ,   collectionFixedParts ) )  { 
36763750          fixedMatchedSegments ++ ; 
36773751        } 
36783752
3679-         // add a matched path variable only if the schema one was a pathVar 
3680-         if  ( schemaPath [ sMax   -   i ] . startsWith ( '{' )   &&   schemaPath [ sMax  -  i ] . endsWith ( '}' ) )  { 
3753+         // add a matched path variable only if the schema one was a pathVar and only one path variable is in segment  
3754+         if  ( isSchemaSegmentPathVar ( schemaPath [ sMax  -  i ] ) )  { 
36813755          variables . push ( { 
36823756            key : schemaPath [ sMax  -  i ] . substring ( 1 ,  schemaPath [ sMax  -  i ] . length  -  1 ) , 
36833757            value : pmSuffix [ pMax  -  i ] 
@@ -3859,7 +3933,7 @@ module.exports = {
38593933              // Not adding colloection variables for now 
38603934              suggestedValue : { 
38613935                request : convertedRequest , 
3862-                 variables
3936+                 variables :  _ . values ( variables ) 
38633937              } 
38643938            } ; 
38653939          } 
0 commit comments