Commit Graph
4 Commits
Author SHA1 Message Date
Claude 666762a146 ✨ feat: add field-name mapping, access control and transform options
A library whose headline feature is "JSON mapping" could not map a name: there
was no way to read {"first_name": ...} into firstName, no way to keep a password
out of the response, and no way to parse a payload without validating it.

Name mapping
- @JsonProperty(name) renames a property in both directions
- @JsonAlias(...names) accepts extra names on input only, so a field can be
  renamed without breaking older clients
- naming strategies (snake_case, kebab-case, SCREAMING_SNAKE_CASE, PascalCase,
  camelCase, or your own function) for properties with no explicit name.
  Acronyms split where a reader expects: parseHTTPResponse -> parse_http_response

Access control
- @JsonIgnore()    excluded both ways
- @JsonWriteOnly() accepted from input, never echoed back (passwords)
- @JsonReadOnly()  serialized, never settable by a client (server-owned ids)

Blocked names are dropped explicitly rather than falling through to the unknown
key path, which would otherwise have copied a rejected id straight back on under
the default policy.

Transform options, per call or globally via configure()
- validate: false to map without validating, for lenient parsing
- unknownKeys: 'allow' | 'strip' | 'error'
- namingStrategy

Error ergonomics — the nested ValidationError tree was hard to turn into an HTTP
400 body. flattenErrors() yields {"items[0].qty": ["qty must be at least 1"]},
plus formatErrors() and collectErrorMessages(). Adds validateOrReject().

All defaults preserve existing behaviour; the 68 prior tests pass unchanged.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAcqrz3FcadkYr3xG32CjK
2026-08-03 23:46:18 +00:00
Claude 6d04b43964 🐛 fix: repair eight correctness defects in the mapping and validation engines
Each fix is pinned by a regression test in src/regressions.test.ts describing the
old behaviour.

- Inheritance dropped base-class rules. A subclass re-decorating an inherited
  property registered its constraints against its own prototype, and validate()
  read only the nearest set, so everything the base declared was silently lost.
  Constraints are now merged down the whole prototype chain, base first, with
  genuinely identical rules collapsed so restating @IsString() on an override
  does not double-report. The library's own example.ts was affected: Media's
  @IsString() title had never been enforced for Book.
- Circular references exhausted the heap. serialize() recursed forever, taking
  8 GB and the process with it; it now tracks ancestors and raises a
  JsonMappingError naming the cause. Diamonds still serialize. validate() skips
  back-edges instead of recursing.
- @Matches with a g or y flag was stateful: RegExp.test advances lastIndex, so
  validating the same value twice gave different answers. Those flags are
  stripped.
- An unmatched @JsonPolymorphic discriminator silently dropped the value — the
  single-object branch fell through without assigning. The raw value is now
  preserved, with { onUnknown: 'error' } and { fallback } to choose otherwise.
- Custom @JsonSerialize serializers ran on null/undefined, crashing on any unset
  optional property. They now only see real values.
- serialize() read obj.constructor.prototype, which throws for null-prototype
  objects; both engines now agree on Object.getPrototypeOf.
- __proto__, constructor and prototype arriving in untrusted JSON were copied
  onto the instance, detaching it from its own class. They are dropped.
- The "each element in ..." prefix was glued onto caller-supplied messages, and
  two rules sharing a name overwrote each other so only one failure surfaced.

Also adds toInstanceArray/fromJsonArray, since toInstance and fromJson accept
arrays at runtime but type the result as T, and reports a non-JSON request body
in fromRequest as a JsonMappingError rather than a raw SyntaxError.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01SAcqrz3FcadkYr3xG32CjK
2026-08-03 23:41:10 +00:00
Enzo Marioni fa75147e4e ✨ feat: implement core Cereale library for JSON mapping and validation
- 🎨 add Spring-like decorators (@JsonSerialize, @JsonDeserialize, etc.)
- ⚙️ implement JsonMapper and metadata storage for transformations
- 🧪 add comprehensive test suite using Vitest
- 📝 add README, CONTRIBUTING, and API documentation
- 👷 setup GitHub Actions CI workflow
- 🔧 configure TypeScript and project settings
2026-04-18 19:33:19 +02:00
Enzo Marioni 7fe7e8c7c3 ✨ feat: implement core Optimus library for JSON mapping and validation
- 🎨 add Spring-like decorators (@JsonSerialize, @JsonDeserialize, etc.)
- ⚙️ implement JsonMapper and metadata storage for transformations
- 🧪 add comprehensive test suite using Vitest
- 📝 add README, CONTRIBUTING, and API documentation
- 👷 setup GitHub Actions CI workflow
- 🔧 configure TypeScript and project settings
2026-04-11 16:58:12 +02:00