Skip to content

Improved-scala3-enums#2246

Merged
schani merged 22 commits into
glideapps:masterfrom
Quafadas:improved-scala3-enums
Jul 20, 2026
Merged

Improved-scala3-enums#2246
schani merged 22 commits into
glideapps:masterfrom
Quafadas:improved-scala3-enums

Conversation

@Quafadas

Copy link
Copy Markdown
Contributor

Improves encoding of scala 3 enums... the more idiomatic encoding has better ergonomics to work with later

Quafadas and others added 22 commits April 14, 2023 13:35
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Resolve conflicts keeping the PR's semantics on master's lint formatting
(.js import extensions, template literals). Take master's test/fixtures.ts
verbatim (the PR's only change there was a no-op reorder) and revert the
PR's whitespace-only edit to .github/workflows/test-pr.yaml.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Enum cases are now styled Scala identifiers (via a proper enum-case
namer) with explicit Decoder/Encoder mappings back to the original JSON
strings, so keywords, "_", "", and other arbitrary values all work.
This subsumes the special-cased blank-enum emission, which produced
Decoder[""] -- a literal singleton type that plain circe has no decoder
for -- alongside a commented-out generic given.

Union decoders are tried most-discriminating-first (enums, then
strings, then the remaining primitives, classes last) via a shared
sort order in utils, because circe's numeric decoders also accept
strings like "5".

Scala.Right/scala.Left are fully qualified in the enum codecs so that
generated types named Right/Left don't shadow them, property names
containing spaces are backtick-quoted (one shared backtickedName
helper replaces the copy-pasted quoting logic), and top-level
primitives emit a type alias so they compile at all.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The upickle rewrite from PR glideapps#2246 (OptionPickler for absent/null
options, badMerge for untagged unions) had several bugs that were
never caught because the fixture was unregistered:

- Union readers were tried in name order, so a case class whose fields
  are all defaulted would spuriously read strings and arrays as the
  all-defaults instance. Readers now run most-discriminating-first
  (shared sort order with the circe renderer).
- upickle's built-in primitive readers are lenient in both directions
  (numbers read as strings, strings read as numbers/booleans), so
  unions now use strict per-type readers emitted in JsonExt.
- The union writer used OptionPickler.write (a String) inside
  comap[ujson.Value], double-encoding every union value; it now uses
  writeJs.
- Unions containing null referenced a NullValue type that was never
  emitted; the header now defines it with a strict ReadWriter.
- Enums relied on raw JSON strings as case names; they are now styled
  identifiers with an explicit bimap ReadWriter mapping them back to
  the original strings.
- The unused upickleEncoderForType, the unused widen extension, the
  commented-out singleton pickler, and the mislabeled
  unionReader/unionWriter given names are cleaned up.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
PR glideapps#2246 added test/fixtures/scala3-upickle/ but never registered it:
there was no Language entry, no fixture registration, and no CI matrix
entry, so the upickle renderer had zero test exposure. This adds
Scala3UpickleLanguage (framework: upickle), registers scala3-upickle /
schema-scala3-upickle fixtures, and puts them in the CI matrix (the
existing scala3 toolchain-setup conditions match the new names).

Driver fixes:
- circe.scala now exits nonzero on parse/decode failure (it used to
  print the DecodingFailure and exit 0, making every expected-failure
  schema sample undetectable), uses scala.Right/scala.Left patterns so
  generated types named Right/Left can't shadow them, and drops dead
  commented-out code.
- upickle.scala drops the unused os-lib dependency and dead code.

Skip lists are rebuilt from an exhaustive local generate+compile+
round-trip sweep of priority/samples/misc JSON and the schema corpus
with scala-cli (Scala 3.2.2, circe 0.14.5, upickle 3.1.0):

- Both frameworks now run everything except six inputs that hit the
  raw-identifier limitation (empty property names, bare "_",
  backticks/emoji in names, generated classes shadowing None/Option)
  plus keyword-unions.schema for the same reason.
- Un-skipped for circe: github-events, kitchen-sink, no-classes,
  name-style, combinations1-4, unions, php-mixed-union, the whole
  "sorted differently" group, and 13 schemas including
  keyword-enum.schema, enum.schema, required.schema, intersection
  and the untagged-union group (the driver exit-code fix makes their
  fail samples detectable, and the renderer fixes make them pass).
- Four misc inputs move from skipJSON to skipDiffViaSchema: they
  round-trip fine and only hit a pre-existing property-ordering quirk
  in the JSON-Schema-derived generation path.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@schani
schani merged commit 6325f66 into glideapps:master Jul 20, 2026
27 checks passed
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.

3 participants