Skip to content

fix(js): export all-objects converters from module.exports#3009

Merged
schani merged 4 commits into
masterfrom
agent/fix-issue-1655
Jul 22, 2026
Merged

fix(js): export all-objects converters from module.exports#3009
schani merged 4 commits into
masterfrom
agent/fix-issue-1655

Conversation

@schani

@schani schani commented Jul 20, 2026

Copy link
Copy Markdown
Member

Bug

With --converters all-objects, the JavaScript renderer generates
toX/xToJson converter functions for every object type in the schema, not
just the top-level types. However, module.exports only ever listed the
top-level converters, so the extra per-object converters were generated but
inaccessible/unusable to callers of the module.

Repro:

node dist/index.js --src-lang schema json.schema --lang js --runtime-typecheck --acronym-style pascal --converters all-objects -o output.js

produced toData123/data123ToJson functions in the file body, but
module.exports only contained the top-level toOutput/outputToJson.

Root cause

In packages/quicktype-core/src/language/JavaScript/JavaScriptRenderer.ts,
emitConvertModuleBody() already branches on
this._jsOptions.converters === ConvertersOptions.AllObjects to decide
whether to iterate forEachObject or forEachTopLevel when emitting the
converter functions themselves. emitModuleExports() did not have the same
branch — it unconditionally used forEachTopLevel, so the export list never
matched what was actually generated when all-objects was selected.

Fix

emitModuleExports() now mirrors emitConvertModuleBody()'s switch on
this._jsOptions.converters, using forEachObject for
ConvertersOptions.AllObjects and forEachTopLevel otherwise (unchanged
default behavior).

Test coverage

  • Added test/inputs/json/samples/issue-1655.json, a sample with a nested
    object type, wired into test/languages.ts's
    JavaScriptLanguage.quickTestRendererOptions with
    { converters: "all-objects" } (same tuple pattern already used for other
    targeted regression samples like pokedex.json).
  • Extended test/fixtures/javascript/main.js to additionally call the
    nested object's exported converter (toData123/data123ToJson) when the
    generated source defines it, so the fixture driver actually exercises the
    export and fails with a runtime TypeError if it's missing.
  • Verified locally that reverting just the renderer fix makes this new
    fixture fail (TypeError: TopLevel.toData123 is not a function), and that
    with the fix in place it passes.

Verification

  • npm run build passes.
  • QUICKTEST=true FIXTURE=javascript script/test — all 59 JavaScript
    fixture tests pass, including the new issue-1655.json case run with
    converters: all-objects.
  • Manually re-ran the exact repro command from the issue and confirmed
    module.exports now includes data123ToJson/toData123 alongside the
    top-level converters.
  • Full CI suite (other languages, lint, etc.) is left to GitHub Actions.

Fixes #1655

🤖 Generated with Claude Code

With --converters all-objects, the JavaScript renderer generates
toX/xToJson functions for every object type, but module.exports only
listed the top-level converters, making the extra converters
unreachable by callers of the module.

Co-Authored-By: gpt-5.6-sol via pi <noreply@openai.com>
Comment thread test/fixtures/javascript/main.js Outdated
The issue-1655 fixture driver decided whether to exercise the nested data123
converter by matching the generated source for the exact string
"function toData123(". Replace that brittle hard-coded gate with a check of
the invariant #1655 actually establishes: every converter the generated
module defines (`function to<Name>(json)` / `function <name>ToJson(value)`)
must also be reachable through module.exports. The module's helper functions
have different signatures and are not matched, so the check is general across
samples and converter modes rather than tied to one sample name.

The same sample is rendered with several converter options and the driver
only receives the sample path, so the set of emitted converters is read from
the generated module; in the default (top-level) rendering data123 is simply
never defined and never checked.

Co-Authored-By: Claude <noreply@anthropic.com>
@schani
schani force-pushed the agent/fix-issue-1655 branch from 9cddc5d to 37d8d92 Compare July 21, 2026 15:46
The fixture driver read the generated TopLevel.js back and grepped its
source for converter definitions to check they were all exported. That
inspection of emitted source belongs in a render-and-inspect unit test,
not in the round-trip fixture driver.

Move the #1655 regression check into test/unit: render the JS module with
converters: all-objects and assert every defined converter appears in the
module.exports block (plus a top-level control that shows the nested
converter is neither generated nor exported in the default mode). This
mirrors the existing java-acronym-names unit test, whose comment explains
the same rationale — a round-trip fixture cannot observe the defect because
the top-level converter it exercises works regardless. Reverting the
renderer fix makes the new test fail.

The javascript fixture driver returns to a plain round-trip; issue-1655.json
still renders with converters: all-objects, keeping fixture coverage that
the mode generates runnable code.

Co-Authored-By: Claude <noreply@anthropic.com>
Comment thread test/inputs/json/samples/issue-1655.json Outdated
@schani
schani merged commit a2ac821 into master Jul 22, 2026
28 checks passed
@schani
schani deleted the agent/fix-issue-1655 branch July 22, 2026 00:55
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.

Javascript all-objects output should export all converters

1 participant