Skip to content

[pull] master from glideapps:master#66

Merged
pull[bot] merged 9 commits into
meonBot:masterfrom
glideapps:master
Jul 15, 2026
Merged

[pull] master from glideapps:master#66
pull[bot] merged 9 commits into
meonBot:masterfrom
glideapps:master

Conversation

@pull

@pull pull Bot commented Jul 15, 2026

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

schani and others added 9 commits July 14, 2026 12:19
PHP generation failed with "union are not supported" for any union that
wasn't just nullable — a heterogeneous array like [1, "two", {...}] made
the whole render throw.

Unions are now rendered inline as PHP 8.0 union type declarations
(e.g. `MixedClass|int|string`), so no named union class is emitted.  The
from/to/validate converters dispatch on the runtime type of the value
with an if/elseif chain, testing the most specific checks first
(instanceof for classes, enums and DateTime, then is_int before the
float check, which also accepts integers) and throwing on unmatched
values.  Samples use the first member.  On the JSON side classes and
maps are stdClass and enums and dates are strings, with textual
duplicates deduplicated in the declaration.

This also adds the PHP reserved words to the renderer's forbidden
names: the motivating fixture has a property named "mixed", which used
to name its class `Mixed` — a compile error in PHP 8 (reserved type
name), now renamed to `MixedClass`.  Previously no reserved word was
protected at all, so a JSON key like "class" or "print" with an object
value generated uncompilable PHP.

Generated output for the fixtures parses cleanly as PHP 8.0.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…an enum

Most languages spell "generate plain types without (de)serialization
helpers" as a `just-types` boolean option, but C# spelled it
`--features just-types` and Kotlin, Scala 3, and Smithy4s
`--framework just-types`, so the common `--just-types` flag was
rejected for them with an option-parsing error.

Those four languages now also accept `just-types` (secondary option).
When it's set, makeRenderer forces the corresponding enum option to its
just-types value before resolving options, so the boolean wins over a
conflicting explicit enum value.  The enum spellings keep working
unchanged.

The renderer-options type test that used kotlin + just-types as its
"another language's option" compile error now uses rust, which really
has no such option.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
BREAKING CHANGE: the enum spellings of "plain types" are gone. C# loses
`--features just-types` and `--features just-types-and-namespace` (their
value maps were identical); Kotlin and Scala 3 lose `--framework
just-types`; Smithy4s loses its single-value `--framework` option
entirely. Every language now spells it the way the other 15 always have:
the boolean `--just-types`, which wins over a conflicting explicit
`--features`/`--framework`.

Scala 3's default changes with this: a bare `quicktype -l scala3` now
generates circe (de)serialization instead of plain case classes — plain
types now require asking for `--just-types`, like in every other
language.

The VS Code extension's per-language special-casing collapses into a
single check for whether the target language has a `just-types` option
(fixing a bug where its "just types" commands silently did nothing for
languages other than C# and Kotlin), and the Smithy4s test fixture
migrates to the boolean spelling.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
feat(options)!: unify --just-types across all languages
Running the union-heavy JSON inputs and the JSON Schema fixture against
the PHP renderer for the first time exposed several bugs in generated
code:

- `any`- and `null`-typed properties were declared as `Object` (and the
  converter parameters as the nonexistent types `any`/`null`), which
  fatals as soon as a null or scalar flows through.  They are now
  `mixed`, matching the PHP 8.0 baseline the inline union declarations
  already require.
- The `any` validation called `defined()`, which tests whether a
  *constant* of the given name exists and throws for non-string
  arguments.  Any value is a valid `any`, so no check is emitted.
- Double validation used a bare `is_float`, rejecting whole numbers,
  which json_decode hands over as ints.  It now accepts ints, like the
  union member checks already did.
- Nullable DateTime/UUID properties lost their `?` in type declarations
  (`optionalize` was not applied), so `fromX` fataled returning null.
- The nullable branch of the `from` converters emitted a hardcoded
  `return null;`, which is wrong when the conversion is nested inside a
  map's foreach; it now uses the caller's lhs like the `to` side does.
- Nested array samples closed with `);` in expression position, and map
  samples emitted statements in expression position; array closings now
  respect the caller's suffix and map samples are immediately-invoked
  closures.
- Classes without properties generated a bodyless non-void
  `validate(): bool`, a TypeError when called; it now returns true.
- A property named "this" produced an illegal `$this` constructor
  parameter; "this" is now a forbidden property name.
- A union-member check for an enum on the JSON side only tested
  `is_string`, shadowing plain-string members (e.g. a UUID sharing a
  union with an enum); it now checks membership in the enum's values.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The PHP fixture previously ran only a whitelist of easy JSON samples
and no schema fixture at all, so the new union support was covered by
unit tests alone.  quicktype's primary testing method is the end-to-end
JSON / JSON Schema fixture tests, so:

- Enable the union-heavy JSON inputs for PHP: unions.json,
  union-constructor-clash.json, combinations1-4.json,
  nst-test-suite.json, kitchen-sink.json, list.json and bug427.json.
- Add test/inputs/json/priority/php-mixed-union.json, the motivating
  repro: a heterogeneous array (int, string, bool, null and an object)
  under a property named "mixed", which is a PHP reserved word, so it
  exercises the reserved-word class renaming and the union runtime
  dispatch together.  The input is skipped for the languages that
  already skip unions.json (Ruby, Scala 3, Smithy4s, Kotlin and Kotlin
  Jackson), since it is a subset of that input's shapes.
- Register the JSON Schema fixture for PHP and run it in CI as
  schema-php.  61 of the 65 schemas run; the four skips are
  keyword-unions.schema (PHP class names are case-insensitive but the
  namer dedups case-sensitively — the same reason Java and Python skip
  it), recursive-union-flattening.schema (a top-level union produces no
  named TopLevel class now that unions are inlined),
  top-level-enum.schema (generated top-level enum code is incompatible
  with the driver, as for C# and Ruby) and union.schema (the driver
  does not support top-level arrays).

Not enabled: optional-union.json and the identifiers/keywords inputs.
Top-level arrays are unsupported by the PHP driver, identifiers.json
needs comment/string escaping of raw JSON names, and keywords.json hits
the case-insensitive class-name collision above — all pre-existing
limitations independent of union support.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Any change affecting generated output must be covered by the JSON /
JSON Schema fixture tests; unit tests complement them but are never a
substitute.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
fix(php): support non-nullable unions
@pull pull Bot locked and limited conversation to collaborators Jul 15, 2026
@pull pull Bot added the ⤵️ pull label Jul 15, 2026
@pull
pull Bot merged commit 1d3749f into meonBot:master Jul 15, 2026
1 check failed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant