@@ -4486,95 +4486,122 @@ Node._findEnum = schema => {
44864486}
44874487
44884488/**
4489- * Return the part of a JSON schema matching given path.
4489+ * Implementation for _findSchema
44904490 * @param {Object } topLevelSchema
44914491 * @param {Object } schemaRefs
44924492 * @param {Array.<string | number> } path
44934493 * @param {Object } currentSchema
4494- * @return {Object | null }
4494+ * @return {Object | boolean | null }
44954495 * @private
44964496 */
4497- Node . _findSchema = ( topLevelSchema , schemaRefs , path , currentSchema = topLevelSchema ) => {
4497+ Node . _findOneSchema = ( topLevelSchema , schemaRefs , path , currentSchema ) => {
44984498 const nextPath = path . slice ( 1 , path . length )
44994499 const nextKey = path [ 0 ]
45004500
4501- let possibleSchemas = [ currentSchema ]
4502- for ( const subSchemas of [ currentSchema . oneOf , currentSchema . anyOf , currentSchema . allOf ] ) {
4503- if ( Array . isArray ( subSchemas ) ) {
4504- possibleSchemas = possibleSchemas . concat ( subSchemas )
4505- }
4506- }
4507-
4508- for ( const schema of possibleSchemas ) {
4509- currentSchema = schema
4510-
4511- if ( '$ref' in currentSchema && typeof currentSchema . $ref === 'string' ) {
4512- const ref = currentSchema . $ref
4513- if ( ref in schemaRefs ) {
4514- currentSchema = schemaRefs [ ref ]
4515- } else if ( ref . startsWith ( '#/' ) ) {
4516- const refPath = ref . substring ( 2 ) . split ( '/' )
4517- currentSchema = topLevelSchema
4518- for ( const segment of refPath ) {
4519- if ( segment in currentSchema ) {
4520- currentSchema = currentSchema [ segment ]
4521- } else {
4522- throw Error ( `Unable to resolve reference ${ ref } ` )
4523- }
4524- }
4525- } else if ( ref . match ( / # \/ / g) ?. length === 1 ) {
4526- const [ schemaUrl , relativePath ] = ref . split ( '#/' )
4527- if ( schemaUrl in schemaRefs ) {
4528- const referencedSchema = schemaRefs [ schemaUrl ]
4529- const reference = { $ref : '#/' . concat ( relativePath ) }
4530- const auxNextPath = [ ]
4531- auxNextPath . push ( nextKey )
4532- if ( nextPath . length > 0 ) {
4533- auxNextPath . push ( ...nextPath )
4534- }
4535- return Node . _findSchema ( referencedSchema , schemaRefs , auxNextPath , reference )
4501+ if ( typeof currentSchema === 'object' && '$ref' in currentSchema && typeof currentSchema . $ref === 'string' ) {
4502+ const ref = currentSchema . $ref
4503+ if ( ref in schemaRefs ) {
4504+ currentSchema = schemaRefs [ ref ]
4505+ } else if ( ref . startsWith ( '#/' ) ) {
4506+ const refPath = ref . substring ( 2 ) . split ( '/' )
4507+ currentSchema = topLevelSchema
4508+ for ( const segment of refPath ) {
4509+ if ( segment in currentSchema ) {
4510+ currentSchema = currentSchema [ segment ]
45364511 } else {
45374512 throw Error ( `Unable to resolve reference ${ ref } ` )
45384513 }
4514+ }
4515+ } else if ( ref . match ( / # \/ / g) ?. length === 1 ) {
4516+ const [ schemaUrl , relativePath ] = ref . split ( '#/' )
4517+ if ( schemaUrl in schemaRefs ) {
4518+ const referencedSchema = schemaRefs [ schemaUrl ]
4519+ const reference = { $ref : '#/' . concat ( relativePath ) }
4520+ const auxNextPath = [ ]
4521+ auxNextPath . push ( nextKey )
4522+ if ( nextPath . length > 0 ) {
4523+ auxNextPath . push ( ...nextPath )
4524+ }
4525+ return Node . _findSchema ( referencedSchema , schemaRefs , auxNextPath , reference )
45394526 } else {
45404527 throw Error ( `Unable to resolve reference ${ ref } ` )
45414528 }
4529+ } else {
4530+ throw Error ( `Unable to resolve reference ${ ref } ` )
45424531 }
4532+ }
45434533
4544- // We have no more path segments to resolve, return the currently found schema
4545- // We do this here, after resolving references, in case of the leaf schema beeing a reference
4546- if ( nextKey === undefined ) {
4547- return currentSchema
4548- }
4534+ // We have no more path segments to resolve, return the currently found schema
4535+ // We do this here, after resolving references, in case of the leaf schema beeing a reference
4536+ if ( nextKey === undefined ) {
4537+ return currentSchema
4538+ }
45494539
4550- if ( typeof nextKey === 'string' ) {
4551- if ( typeof currentSchema . properties === 'object' && currentSchema . properties !== null && nextKey in currentSchema . properties ) {
4552- currentSchema = currentSchema . properties [ nextKey ]
4553- return Node . _findSchema ( topLevelSchema , schemaRefs , nextPath , currentSchema )
4554- }
4555- if ( typeof currentSchema . patternProperties === 'object' && currentSchema . patternProperties !== null ) {
4556- for ( const prop in currentSchema . patternProperties ) {
4557- if ( nextKey . match ( prop ) ) {
4558- currentSchema = currentSchema . patternProperties [ prop ]
4559- return Node . _findSchema ( topLevelSchema , schemaRefs , nextPath , currentSchema )
4560- }
4540+ if ( typeof nextKey === 'string' ) {
4541+ if ( typeof currentSchema . properties === 'object' && currentSchema . properties !== null && nextKey in currentSchema . properties ) {
4542+ currentSchema = currentSchema . properties [ nextKey ]
4543+ return Node . _findSchema ( topLevelSchema , schemaRefs , nextPath , currentSchema )
4544+ }
4545+ if ( typeof currentSchema . patternProperties === 'object' && currentSchema . patternProperties !== null ) {
4546+ for ( const prop in currentSchema . patternProperties ) {
4547+ if ( nextKey . match ( prop ) ) {
4548+ currentSchema = currentSchema . patternProperties [ prop ]
4549+ return Node . _findSchema ( topLevelSchema , schemaRefs , nextPath , currentSchema )
45614550 }
45624551 }
4563- if ( typeof currentSchema . additionalProperties === 'object' ) {
4564- currentSchema = currentSchema . additionalProperties
4565- return Node . _findSchema ( topLevelSchema , schemaRefs , nextPath , currentSchema )
4566- }
4567- continue
45684552 }
4569- if ( typeof nextKey === 'number' && typeof currentSchema . items === 'object' && currentSchema . items !== null ) {
4570- currentSchema = currentSchema . items
4553+ if ( typeof currentSchema . additionalProperties === 'object' ) {
4554+ currentSchema = currentSchema . additionalProperties
45714555 return Node . _findSchema ( topLevelSchema , schemaRefs , nextPath , currentSchema )
45724556 }
4557+ return null
4558+ }
4559+ if ( typeof nextKey === 'number' && typeof currentSchema . items === 'object' && currentSchema . items !== null ) {
4560+ currentSchema = currentSchema . items
4561+ return Node . _findSchema ( topLevelSchema , schemaRefs , nextPath , currentSchema )
45734562 }
45744563
45754564 return null
45764565}
45774566
4567+ /**
4568+ * Return the part of a JSON schema matching given path.
4569+ *
4570+ * Note that this attempts to find *a* schema matching the path, not necessarily
4571+ * the best / most appropriate. For example, oneOf vs. anyOf vs. allOf may
4572+ * result in different schemas being applied in practice.
4573+ *
4574+ * @param {Object } topLevelSchema
4575+ * @param {Object } schemaRefs
4576+ * @param {Array.<string | number> } path
4577+ * @param {Object } currentSchema
4578+ * @return {Object | null }
4579+ * @private
4580+ */
4581+ Node . _findSchema = ( topLevelSchema , schemaRefs , path , currentSchema = topLevelSchema ) => {
4582+ let possibleSchemas = [ currentSchema ]
4583+ for ( const subSchemas of [ currentSchema . oneOf , currentSchema . anyOf , currentSchema . allOf ] ) {
4584+ if ( Array . isArray ( subSchemas ) ) {
4585+ possibleSchemas = possibleSchemas . concat ( subSchemas )
4586+ }
4587+ }
4588+
4589+ let fallback = null
4590+ for ( const schema of possibleSchemas ) {
4591+ const result = Node . _findOneSchema ( topLevelSchema , schemaRefs , path , schema )
4592+ // Although we don't attempt to find the best / most appropriate schema, we
4593+ // can at least attempt to find something more specific than `true`.
4594+ if ( result === true ) {
4595+ fallback = true
4596+ continue
4597+ } else if ( result !== null ) {
4598+ return result
4599+ }
4600+ }
4601+
4602+ return fallback
4603+ }
4604+
45784605/**
45794606 * Remove nodes
45804607 * @param {Node[] | Node } nodes
0 commit comments