UNPKG

@redocly/openapi-core

Version:

See https://github.com/Redocly/redocly-cli

78 lines 4.3 kB
import { isRef } from '../../ref-utils.js'; import { getOwn } from '../../utils/get-own.js'; export const NoRequiredSchemaPropertiesUndefined = () => { const parents = []; return { Schema: { leave(_) { parents.pop(); }, enter(schema, { location, report, resolve }) { parents.push(schema); if (!schema.required) return; const visitedSchemas = new Set(); const elevateProperties = (schema, from, includeFirstLevelExclusiveSchemas = true) => { // Check if the schema has been visited before processing it if (visitedSchemas.has(schema)) { return {}; } visitedSchemas.add(schema); if (isRef(schema)) { const resolved = resolve(schema, from); if (!resolved.node) { return {}; } return elevateProperties(resolved.node, resolved.location?.source.absoluteRef); } return Object.assign({}, schema.properties, ...(schema.allOf?.map((s) => elevateProperties(s, from)) ?? []), ...(('anyOf' in schema && includeFirstLevelExclusiveSchemas ? schema.anyOf?.map((s) => elevateProperties(s, from)) : undefined) ?? []), ...(('oneOf' in schema && includeFirstLevelExclusiveSchemas ? schema.oneOf?.map((s) => elevateProperties(s, from)) : undefined) ?? [])); }; /** * The index to use to lookup grand parent schemas when dealing with composed schemas. * @summary The current schema should always end up with under ../anyOf/1, if we get multiple ancestors, they should always be a multiple. */ const locationLookupIndex = 2; const getParentSchema = (lookupIndex) => { lookupIndex++; if (!parents || parents.length < lookupIndex) return undefined; const parent = parents[parents.length - lookupIndex]; return parent; }; const recursivelyGetParentProperties = (splitLocation, parentLookupIndex = 0) => { const isMemberOfComposedType = splitLocation.length > locationLookupIndex && !isNaN(parseInt(splitLocation[splitLocation.length - 1])) && !!/(allOf|oneOf|anyOf)/.exec(splitLocation[splitLocation.length - locationLookupIndex]); const parentSchema = isMemberOfComposedType ? getParentSchema(++parentLookupIndex) : undefined; const grandParentProperties = splitLocation.length >= locationLookupIndex + locationLookupIndex ? recursivelyGetParentProperties(splitLocation.slice(0, -locationLookupIndex), parentLookupIndex) : {}; return parentSchema ? { ...elevateProperties(parentSchema, undefined, false), ...grandParentProperties, } : undefined; }; const allProperties = elevateProperties(schema); const parentProperties = recursivelyGetParentProperties(location.pointer.split('/')); for (const [i, requiredProperty] of schema.required.entries()) { if ((!allProperties || getOwn(allProperties, requiredProperty) === undefined) && (!parentProperties || getOwn(parentProperties, requiredProperty) === undefined)) { report({ message: `Required property '${requiredProperty}' is undefined.`, location: location.child(['required', i]), }); } } }, }, }; }; //# sourceMappingURL=no-required-schema-properties-undefined.js.map