Skip to content

feat: validate maxProperties/minProperties as map entry-count bounds (#370) - #371

Open
eseidel wants to merge 1 commit into
mainfrom
es/max-properties-validation
Open

eseidel wants to merge 1 commit into
mainfrom
es/max-properties-validation

Conversation

@eseidel

@eseidel eseidel commented Jul 21, 2026

Copy link
Copy Markdown
Owner

Summary

maxProperties/minProperties were parsed then discarded
(_ignored in parser.dart), dropping a real constraint on
map-shaped schemas (type: object + additionalProperties, no
fixed properties) — a -v regen tallies 49 sites in discord and 3 in
github. For a Map<String, T> the entry count is dynamic, so these are
the map analog of an array's maxItems/minItems, which we already
validate.

This threads both bounds through every layer
(SchemaMapResolvedMapRenderMap), mirroring the existing
maxItems/minItems path, and emits a combined
validate(minProperties: ..., maxProperties: ...) call on the map
field. A new ValidateMap extension in the shipped api_exception.dart
enforces it via Map.length, matching ValidateArray.

On a fixed-property object the property count is static, so the
constraint carries no runtime meaning — it stays dropped-and-detail-
logged there (the resolver owns the semantics).

Generated output (optional map → ?., required map → .):

Lobby({required this.requiredMeta, this.metadata}) {
  metadata?.validate(minProperties: 1, maxProperties: 25);
  requiredMeta.validate(maxProperties: 5);
}

Closes #370.

Validation

  • Unit tests: parser (a map carries the bounds and is not detail-logged;
    a fixed-property object drops + detail-logs them), render
    (RenderMap.validationCall combines both bounds, omits the absent
    one, is null when unconstrained).
  • End-to-end repro: analyze-clean, correct ?./. receiver per
    optional/required.
  • Regenerated the rotation: discord (29 files) and github (8 files) now
    emit validate(maxProperties: N) on map fields; github, discord, and
    backstage third_party packages stay analyze-clean; the
    minProperties: 1 model's generated round-trip test passes (the
    single-entry map example satisfies the bound).

…370)

## Summary

`maxProperties`/`minProperties` were parsed then discarded
(`_ignored` in `parser.dart`), dropping a real constraint on
**map-shaped** schemas (`type: object` + `additionalProperties`, no
fixed `properties`) — 49 sites in discord, 3 in github. For a
`Map<String, T>` the entry count is dynamic, so these are the map
analog of an array's `maxItems`/`minItems`, which we already validate.

Threads both bounds through every layer
(`SchemaMap` → `ResolvedMap` → `RenderMap`), mirroring the existing
`maxItems`/`minItems` path, and emits a combined
`validate(minProperties: ..., maxProperties: ...)` call on the map
field. A new `ValidateMap` extension in the shipped `api_exception.dart`
enforces it via `Map.length`, matching `ValidateArray`.

On a fixed-property object the property count is static, so the
constraint carries no runtime meaning — it stays dropped-and-detail-
logged there (resolver owns the semantics).

Generated output (optional map → `?.`, required map → `.`):

```dart
Lobby({required this.requiredMeta, this.metadata}) {
  metadata?.validate(minProperties: 1, maxProperties: 25);
  requiredMeta.validate(maxProperties: 5);
}
```

## Validation

- Unit tests: parser (map carries the bounds; fixed-property object
  drops+logs them), render (`RenderMap.validationCall` combines/omits
  bounds).
- End-to-end repro: analyze-clean, correct `?.`/`.` receiver.
- Regenerated the rotation: discord (29 files) and github (8 files)
  now emit `validate(maxProperties: N)` on map fields; github, discord,
  and backstage third_party packages stay analyze-clean; the
  `minProperties: 1` model's round-trip test passes (the single-entry
  map example satisfies the bound).
@codecov

codecov Bot commented Jul 21, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 60.86957% with 9 lines in your changes missing coverage. Please review.
✅ Project coverage is 96.53%. Comparing base (1c1567a) to head (4161006).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
lib/templates/api_exception.dart 0.00% 9 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main     #371      +/-   ##
==========================================
- Coverage   96.67%   96.53%   -0.14%     
==========================================
  Files          25       25              
  Lines        5957     5981      +24     
==========================================
+ Hits         5759     5774      +15     
- Misses        198      207       +9     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: honor maxProperties/minProperties as map-length validation

1 participant