Conversation
A top-level schema whose whole body is a `$ref` is an alias, and OpenAPI 3.1
lets keywords sit beside the `$ref` - nestjs-zod writes `{ id, $ref }` when a
DTO is exposed under a second name. Referring properties kept naming the alias
while nothing generated a file for it, because getSchemas() drops anything
carrying a `$ref` and isEmpty() reads what is left as an empty schema. The
result was an import of a file nobody wrote and an undefined type:
import 'open_shift_response_dto_v2.f.dart'; // no such file
List<OpenShiftResponseDtoV2>? openShiftResponses, // no such class
build_runner reports it as `Could not generate 'fromJson' code for ... InvalidType`.
Aliases now generate a typedef. The re-export alongside the import is
load-bearing: freezed writes its output as a `part of` the referring model and
resolves the typedef to the underlying class there, so that class has to be in
the referring file's scope. With only an import, build_runner still fails with
InvalidType.
A `$ref` carrying real constraints is an override rather than a second name,
and is left to the paths that already handle it.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Collaborator
Author
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A top-level schema whose whole body is a
$refis an alias for another schema. OpenAPI 3.1 allows keywords beside a$ref, and nestjs-zod emits exactly this when a DTO is exposed under a second name:dorval treats such a schema asymmetrically: referring properties keep the alias name, and nothing ever generates a file for it.
models/index.dartstays self-consistent (it only exports files that were written), so the breakage surfaces only through the referring models' imports.build_runnerreports it as:Two places drop the alias, one after the other:
OpenAPIParser.getSchemas()filters out every schema carrying a$ref("Filter out reference objects"), so the alias never reaches the model loop;isEmpty()would have discarded it anyway — it checkstype,properties,enum,constand composition, and never looks at$ref, so{ id, $ref }reads as an empty schema.Meanwhile
processPropertyresolves a$refto a class name and an import without asking whether that schema produced a file.Not a regression: the same spec produces the same 252 models on 0.10.2, 0.10.3, 0.10.7 and 0.10.8, none of them containing the aliases. It stays hidden while stale hand-written or previously-generated classes sit in the output directory, and surfaces the moment that directory is cleared.
Change
An alias generates a typedef:
The re-export is load-bearing, not decoration. freezed writes its output as a
part ofthe referring model, and a typedef resolves to the underlying class in that part, so the class has to be in the referring file's scope. Reaching it only through the alias import leaves json_serializable seeing anInvalidType. Verified both ways, see below.A typedef rather than a duplicated class also means the alias cannot drift from its base.
A
$refcarrying real constraints beside it is an override, not a second name, and is left to the paths that already handle it. Only$refplus pure metadata (id,title,description,example,deprecated, …) counts as an alias.Tests
4 cases in
models-ref-alias.test.ts: the 3.1 sibling-keyword form, the bare{ $ref }form, self-consistency of the referring model's imports against the emitted file list, and the override form staying off this path. Three of them fail without the fix.packages/core: 454 tests pass, lint unchanged at its 3 pre-existing errors.End-to-end through the real toolchain, with an alias referenced from a list and from a required field:
build_runnerBuilt with build_runner in 4s; wrote 12 outputs,dart analyzecleanCould not generate 'fromJson' code for 'item'/InvalidType/Failed to buildThe generated decoders show why — the typedef is resolved to the base class inside a
part ofthe referrer:Notes
Reported alongside a separate config-loading problem:
dorval.config.tsfails to load under TypeScript 7 withtypescript.findConfigFile is not a function. That one is real and unrelated to this change — TypeScript 7's main entry exports onlyversionandversionMajorMinor, so cosmiconfig's built-in TS loader cannot work — andsearchPlacesinpackages/dorval/src/config.tslistsorval.config.*rather than thedorval.config.*names the README documents. Both belong in the CLI package and will be filed separately.