fix(no-required-schema-properties-undefined): resolve false positives for bare-required schemas in allOf-composed types - #2836
Conversation
🦋 Changeset detectedLatest commit: d34a79f The changes in this PR will be included in the next version bump. This PR includes changesets to release 4 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
8856aa1 to
929f198
Compare
929f198 to
2cc6d1f
Compare
tatomyr
left a comment
There was a problem hiding this comment.
Finally got my hands on this. It looks mostly okay for me. However, I'd like to ask you to explore the possibility to solve this without introducing a new concept leveraging the existing logic (if possible).
| - Name | ||
| ``` | ||
|
|
||
| The rule accepts bare `required` constraints on property sub-schemas when the property's type is defined in a parent `allOf` sibling. This is a valid JSON Schema pattern for adding presence constraints on top of a referenced base type: |
There was a problem hiding this comment.
Please do not modify V1 docs.
| !hasProperty(compositionRoot, requiredProperty, new Set()) && | ||
| !hasPropertyInParentContext(requiredProperty, compositionRoot ?? currentSchema) |
There was a problem hiding this comment.
This line actually seems like it should do the same as the previous one, but from a different prospective. Maybe it worth modifying findCompositionRoot / isCompositionChild instead?
Also, the existing code has protection against circular references. Does your code have it? (I haven't found that in your tests.)
There was a problem hiding this comment.
I think line 85 is actually a different concern from findCompositionRoot / isCompositionChild.
isCompositionChildonly checks whether the current schema is an item in a parentallOf/anyOf/oneOf.findCompositionRootthen walks that composition chain upward to the outer composed ancestor.
The logic at L85 is not just “what composition chain this schema belongs to”; it is “which ancestor property owns this schema, and does a sibling compositional branch define the required property?”
So I’d keep findCompositionRoot for composition-root lookup, and keep the parent-property / sibling-branch logic separate.
I did update the code a bit to reuse some existing utils like getOwn.
2cc6d1f to
c56e1ea
Compare
Performance Benchmark (Lower is Faster)
|
f04e878 to
405e289
Compare
405e289 to
d34a79f
Compare
There was a problem hiding this comment.
Cursor Bugbot has reviewed your changes using default effort and found 2 potential issues.
❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.
Reviewed by Cursor Bugbot for commit d34a79f. Configure here.
| propertyDef !== undefined && | ||
| schemaHasProperty(propertyDef, propertyName, ctx, new Set(), location) | ||
| ); | ||
| }); |
There was a problem hiding this comment.
Sibling property lookup skips composition
Medium Severity
checkSiblings only reads a sibling’s direct properties map and returns false when that map is missing. Property keys defined through nested allOf/anyOf/oneOf on the resolved sibling are ignored, so valid bare-required overrides against composed base schemas still false-positive. This diverges from schemaHasProperty, which already walks composition.
Reviewed by Cursor Bugbot for commit d34a79f. Configure here.
There was a problem hiding this comment.
I feel like this could be important for some very advanced schema users but, also a pretty advanced edge case. I'll play with this a bit and see if I can get it working with nested composition but, as it stands, I think I'm ok with the current implementation, if you are.
| ) { | ||
| ctx.report({ | ||
| message: `Required property '${requiredProperty}' is not defined.`, | ||
| message: `Required property '${requiredProperty}' is undefined.`, |
There was a problem hiding this comment.
Inconsistent required-property error text
Low Severity
The Schema enter path now reports is undefined, but reportUndefinedRequired used by the ref leave path still reports is not defined. Same rule, same condition, different user-facing text, and the docs only document the new wording.
Additional Locations (1)
Reviewed by Cursor Bugbot for commit d34a79f. Configure here.
There was a problem hiding this comment.
i'll leave this one to you if you want to update the grammar.


Summary
Fixes false positives in
no-required-schema-properties-undefinedfor barerequiredconstraints used in parent-property composition contexts.Problem
The
no-required-schema-properties-undefinedrule could report false positives for valid JSON Schema patterns where a barerequiredlist is used as a presence constraint on a property sub-schema, while the property’s actual type is defined through a parent composition context.This affected two cases:
Both patterns are valid under JSON Schema, where required and properties are independent keywords.
Solution
The rule now checks the parent-property context before reporting a missing required property. When the usual local-property and composition-root checks do not find the required key, it walks up the ancestor chain to find the containing property schema and then evaluates sibling composition branches (
allOf/anyOf/oneOf) for that property.This refactor keeps the logic focused on the parent-property context rather than treating it as a general composition-root lookup. In particular, the new parent-context check is distinct from
findCompositionRoot/isCompositionChild: the latter answers whether the current schema belongs to a composition chain, while the new logic answers whether the enclosing property owns the schema and whether a sibling compositional branch defines the required property.This preserves the existing behavior for misspellings: if a required key is not actually defined in the resolved property type, the rule still reports it as undefined.
Testing
Added regression coverage for:
allOfsiblingoneOf-style constraint fragmentsanyOf-style constraint fragmentsDocumentation
Updated the V2 rule documentation to describe the supported parent-context behavior for
oneOf/anyOfconstraint fragments.relates to #2320 #2060 #2061
Check yourself
Security
Note
Low Risk
Scoped to one lint rule’s property-resolution logic with broad test and doc updates; no auth, runtime API, or data-path changes.
Overview
Fixes false positives in
no-required-schema-properties-undefinedwhen schemas use valid JSON Schema patterns: property sub-schemas with onlyrequired(no localproperties), oroneOf/anyOfbranches that are purerequiredfragments, while the property’s shape comes from a parentallOfsibling (often via$ref).The rule’s
Schemavisitor now falls back tohasPropertyInParentContext: it walks ancestor schemas, finds which named property holds the current sub-schema, and checksallOf/anyOf/oneOfsiblings for definitions of keys listed inrequired. Misspelled required keys still fail that check and are reported.Lint messages from the main schema path use
is undefinedinstead ofis not defined. Docs add PersonBase/Person examples for these patterns; a changeset marks@redocly/openapi-coreand@redocly/clias patch.Reviewed by Cursor Bugbot for commit d34a79f. Bugbot is set up for automated code reviews on this repo. Configure here.