Skip to content

fix(typia): tune random default lengths#1982

Merged
samchon merged 20 commits into
masterfrom
feat/random
Jun 30, 2026
Merged

fix(typia): tune random default lengths#1982
samchon merged 20 commits into
masterfrom
feat/random

Conversation

@samchon

@samchon samchon commented Jun 29, 2026

Copy link
Copy Markdown
Owner

Summary

  • change unconstrained random strings to generate length 5..10
  • change non-recursive random arrays to generate length 1..6, while recursive array props keep a zero-length default path
  • pass recursive: true through IRandomGenerator.array props when the array element graph is recursive
  • add a regression test for defaults, explicit zero constraints, and custom recursive array generator props
  • keep the typia ttsc descriptor compatible with the current descriptor loader by exporting createTtscPlugin as a named export as well as default

Tests

  • pnpm --filter ./tests/test-typia-schema start -- --include random_defaults
  • pnpm test:go
  • pnpm format
  • pnpm --dir website build
  • git diff --cached --check

@samchon

samchon commented Jun 29, 2026

Copy link
Copy Markdown
Owner Author

Follow-up after CI: the first run exposed an oversized recursive ArrayRecursive SDK payload. I kept the
ecursive marker inside the array props as designed, and capped recursive default arrays to

@samchon

samchon commented Jun 29, 2026

Copy link
Copy Markdown
Owner Author

Follow-up for recursive random arrays with positive MinItems:

  • Reject recursive random array types carrying positive tags.MinItems<N> at transform time.
  • Covered direct self recursion, array alias recursion, root recursive array aliases, mutual graph recursion, and tuple/union nested recursion in tests/test-error.
  • Added a Go unit test for positive/zero/nonrecursive cases plus schema/value numeric payloads, including defined numeric types.
  • Kept non-recursive MinItems<1> accepted in test_random_defaults.

Local validation:

  • pnpm format
  • pnpm --filter ./tests/test-error start
  • pnpm --filter ./tests/test-typia-schema start -- --include random_defaults
  • pnpm test:go

CI: all current PR checks pass except sdk, which fails in experiments/nestia/tests/test-sdk at clone-and-keyword with /arrayRecursive HTTP 413. Per the explicit instruction to ignore the nestia.yml/Nestia failure, I did not change that area in this PR.

samchon and others added 15 commits June 30, 2026 13:35
RandomJoiner.RequiresRecursiveArrayGuard (the single-argument wrapper)
had no callers in production or tests; the decode path uses the
RecursiveArrayGuardProps-based ...For variant exclusively. Remove the
dead wrapper.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
_randomArray already imports OpenApi as a type; align _randomString,
which references OpenApi only in a type position.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pin the _randomString length arithmetic: the unconstrained 5..10 span,
a MaxLength below the default collapsing to exactly the cap, a lone
MinLength keeping the +5 span, and a MinLength/MaxLength pair.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Exercise the oneOf expansion in randomProgrammer_array_schema_list for a
recursive array whose element is `Self | string`, asserting the depth
guard caps the self-referential branch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Add a MapRecursiveKey @typia/template structure whose recursion travels
through a `Map<Self, number>` key. The shared metadata recursion marker
now follows map keys, but only the random feature exercised that path;
feeding the structure into the generator matrix runs is/assert/validate/
random (plus standard-schema validate) and their spoilers against it, so
the cross-feature codegen for a recursive map key is locked in.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Pin the non-recursive _randomArray length arithmetic, mirroring the
string-length test: the unconstrained 1..6 span, a MaxItems that caps only
the maximum while the minimum stays 1 (MaxItems<8> stays 1..8), a lone
MinItems keeping the +5 span, and a MinItems/MaxItems pair.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…rator

The random programmer now passes `recursive: true` to the array generator
for arrays on a recursive type's cycle, and custom generators key off it to
keep graph-shaped data finite. Document the field on both IRandomGenerator
and IRandomGenerator.CustomMap so the contract is discoverable.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
typia.random walked some recursive types until the stack overflowed at
runtime: a required, non-nullable object edge back to itself (e.g.
`interface A { self: A }`), a mutual object cycle, or a recursive tuple
rest element. These have no escape the depth cutoff can take — an
array/set/map empties, a nullable edge becomes null, an optional or
index-signature property drops out, or a union picks a finite variant —
so no finite value exists for the generator to build.

Add a least-fixpoint terminability analysis (a schema terminates if ANY
union option does; an object if ALL required literal properties do) and
reject an unsatisfiable recursive object or tuple at compile time through
the transform-diagnostic path, mirroring the existing recursive-MinItems
rejection. Types with any escape — including unions where only one variant
is finite and index-signature trees — keep generating as before.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
… types

Explain that recursion terminates only through an escape the depth cutoff
can take (empty container, nullable, optional, index signature, or a finite
union variant), and that a valveless recursive cycle is rejected at compile
time with the satisfiable alternatives.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
A `...X[]` tuple rest used to generate exactly one `X`, never a real
spread, so `[number, ...string[]]` produced `[number, oneString]` and a
recursive rest `[string, ...T[]]` recursed forever. Route the rest through
the array helper so it spreads a possibly-empty array: it now emits zero or
more elements, and when the element is the recursive owner the spread
carries the `recursive` depth cutoff and empties at the limit.

This makes recursive rest tuples terminate, so they are no longer caught by
the unsatisfiable-recursion check; drop that diagnostic case and cover the
spread (non-recursive and recursive) with a runtime test. Valveless object
cycles stay rejected.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The recursive depth cutoff (`5 >= _depth ? ... : []`) on a tuple rest
spread referenced `_depth`, which only exists inside a generated helper.
A top-level tuple whose element recurses through its own helper —
`typia.random<[string, ...INode[]]>()` with `interface INode { children:
INode[] }` — is inlined with no `_depth` binding, so the spread threw
`ReferenceError: _depth is not defined`. Emit the cutoff only when the
surrounding function exposes `_depth`; the element's own helper already
terminates the recursion otherwise. Cover the top-level case in the rest
runtime test.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Extend the recursive-termination test with `Set<Self>`, `Map<Self, V>`, and
`Map<K, Self>` escapes so the container-empties-at-cutoff path is pinned for
sets and for both map sides, not just arrays.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
The unsatisfiable-recursion check ran a fresh reachability collect and
terminability fixpoint for every recursive object and tuple. Since the
metadata collection already enumerates every reachable object and tuple,
replace the per-type IsUnsatisfiableRecursive* helpers (and their collect
DFS) with a single UnsatisfiableRecursives pass over the whole collection,
computed once in each function writer. Same rejections, fewer passes, ~60
fewer lines.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use the en-us spellings `recognize` and `stabilizes` in the random
recursion comments, and allow the Go `typ` identifier — a deliberate idiom
the native tree uses because `type` is a reserved word — in typos.toml so
the spell-check workflow passes.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@samchon samchon marked this pull request as ready for review June 30, 2026 13:31
@samchon samchon merged commit fccd651 into master Jun 30, 2026
14 checks passed
@samchon samchon deleted the feat/random branch June 30, 2026 13:31
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.

1 participant