fix(vscode-extension): Export to React wrote a phantom registerDefaultRenderers import into every generated file (objectui#7837) - #7863
Merged
Conversation
…every generated file (objectui#7837)
`generateReactComponent()` — the body of the `Export to React` command — wrote
`import { registerDefaultRenderers } from '@object-ui/components';` plus a call
to it into every file a user received. That symbol is on no export of that
package: its built `dist/index.d.ts` carries exactly one `register*` name,
`registerPlaceholders`, and `registerDefaultRenderers` occurs 0 times in either
`dist/index.d.ts` or `dist/index.js` (measured at 3faaa7d). So the command's
output failed to compile with TS2305 naming a symbol the user never typed.
The package registers its renderers as an import side effect — `sideEffects:
true`, `import './renderers'` in the barrel, 114 module-scope `register(` call
sites in the built `dist/index.js` — so there is no registration function to
call. The preamble now imports the package for the side effect and says so, the
spelling the root README landed for objectui#7417.
`DESIGN.md`, which documented the identical two lines, moves in the same commit
so the design record does not freeze the defect.
A pin on the template's own text is added, because the preamble lives inside a
template literal where `tsc --noEmit` sees only a string and no doc gate's
surface reaches this file. It asserts source text rather than compiling the
output: compiling would require exporting `generateReactComponent()`, which this
change is not allowed to do.
No export added, no signature changed.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
…tui#7837) `scripts/check-type-check-coverage.mjs` exited 1 on the pin added in the previous commit: `packages/vscode-extension/tsconfig.json` is the BUILD program and correctly excludes `**/*.test.ts`, so nothing compiled the test — and an unchecked test can assert a contract the compiler never checked and then read as evidence that the contract holds, which is the same defect class this card is about. Adds `tsconfig.test.json` in the shape 35 sibling packages already use, chained off the package's `type-check` script as the gate requires. Its `module` / `moduleResolution` are ESNext/Bundler rather than the build's node16 CommonJS because that is the program vitest actually runs these files in — `import.meta.url` is legal there and TS1470 under the build's target. `include` and `exclude` are overridden rather than merged, so the project is not left green while reading nothing. Verified with `tsc -p tsconfig.test.json --listFiles`: the project reads the pin. `check-type-check-coverage` now reports 42/42 packages compiling their tests. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
Contributor
✅ Console Performance Budget
The eager closure is every chunk the entry reaches through static imports — what the browser fetches and parses before the app renders. The entry chunk on its own is a small fraction of it. 📦 Bundle Size Report
Size Limits
|
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.
Fixes #7837
The VS Code extension's Export to React command wrote a phantom import into
every file it generated for a user.
generateReactComponent()emittedand that symbol is on no export of the package, so the file the user received did
not compile — and the error named a symbol they never typed.
The preamble lives inside a template literal, which is why this survived: this
package's
tsc --noEmitsees a string,tsupcopies it through, and no doc gate'sscan surface reaches this file. The package's own type-check is green before this
PR and green after; on this defect it proves nothing in either direction.
Re-verified on today's tree, not taken from the card
3faaa7d0fregisterDefaultRenderersis not an export of@object-ui/componentspackages/components/dist/index.d.tsand 0 indist/index.js; the onlyregister*name it exports isregisterPlaceholderssideEffects: truein its manifest;import './renderers';insrc/index.tsunder the commentRegister all ObjectUI renderers (side-effects); 114register(call sites in the builtdist/index.js, at module scope (e.g.n.register("div", …)at column 0 of the ESM bundle)ObjectRendererSchemaRendererfrom@object-ui/react, which is a real export and type-checks. TheObjectRendererrow of the ruling has no site hereSame spelling the root README landed for objectui#7417.
The reading that matters: the OUTPUT, before and after
The package's own type-check cannot see inside the template, so it is not evidence.
What is: taking the file a user would actually receive and compiling it.
generateReactComponent()is module-private and this change may not export it, sothe harness brace-matches the function out of the source file on disk, strips
the two type annotations from its signature, evaluates it, and calls it with a
representative page schema. The emitted file is then compiled against the built
dist/index.d.tsof@object-ui/reactand@object-ui/components(
jsx: react-jsx,strict: true,skipLibCheck).Before —
tscexit 2, one diagnostic, and it is exactly the defect:After, at
bf51ca4ef—tscexit 0, no output. The generated preamble is now:End to end: the built
dist/extension.jsthat goes into the.vsixcarries0 occurrences of
registerDefaultRenderersand oneimport '@object-ui/components';.Ships with it:
DESIGN.mdpackages/vscode-extension/DESIGN.mddocumented the identical two lines. It movesin the same commit, so the design record does not freeze the defect the moment this
lands.
A pin, and what it cost
packages/vscode-extension/src/__tests__/export-to-react-preamble.test.tsreads thetemplate out of the source and asserts three things: the identifier appears nowhere
in the module; the template imports
@object-ui/componentsfor its side effect andcarries no named import from that specifier at all (the shape, so the next
phantom off that specifier fails here too); and the
SchemaRendererimport it mustkeep is still there.
It is a source-text pin, deliberately. Compiling the emitted output under test
would require exporting
generateReactComponent(), and this card's clause 2 isno— no new export, no signature change. So it can catch the return of thisphantom and the loss of its replacement; it cannot catch a new one. The
stronger instrument is a proposal in the report, not built here.
Ablation, run against the committed fix. Restoring the pre-fix
extension.tsfrom3faaa7d0fturned 2 of the 3 assertions red (the third,which pins the untouched
SchemaRendererline, correctly stayed green); themutation was confirmed on disk before the run (
registerDefaultRendererscount2, side-effect-import count 0) and the restore was verified by
git diff HEADbeing empty and
git hash-objectreproducing the HEAD blobe52b0abc15a2d84305e2ab8080819e8e15029139. No build is involved on either leg —the pin reads source text, not
dist.The pin's cost is the second commit:
scripts/check-type-check-coverage.mjsexited1 on it, because
tsconfig.jsonis the build program and correctly excludes**/*.test.ts, so nothing compiled the new test — the same "verifier not bound tothe thing verified" shape this card is about. A
tsconfig.test.jsonin the shape 35sibling packages already use, chained off the package's
type-checkscript, closesit;
tsc -p tsconfig.test.json --listFilesconfirms the project reads the pin, andthe gate now reports 42/42 packages compiling their tests.
Gates, all at
bf51ca4ef, exit code captured by redirecting before any pipeobject-uitype-checktsc --noEmit && tsc -p tsconfig.test.json— both legsobject-uitestTest Files 1 passed (1) · Tests 3 passed (3)object-uilint13 problems (0 errors, 13 warnings), unchanged from before this PR; the new test file is linted (eslint JSON reports it, 0/0) and not ignoredobject-uibuildtsupCJS build successcheck-changeset-presence2 source file(s) of 1 released package(s) changed, and this change declares 1 changeset(s): .changeset/7837-vscode-export-react-side-effect-import.md.check-changeset-fixedcheck-changeset-no-majorcheck-type-check-coverage42/42 packages compile their testscheck-lint-coverage46/46 packages lintedcheck-control-bytesgrep -naPcontrol-byte scan of all six changed files: cleancheck-unreferenced-sourcescheck-vi-mock-specifiers/check-vi-mock-inheritcheck-doc-fence-languagescheck-package-self-importcheck-published-tsconfig-tooling-excludecheck-entry-guardcheck-shell-escape-residuecheck-phantom-dependenciescheck-governed-queue-guard --testNOT GOVERNED — 6 path(s) checked against 5 governed surface(s); none matched.A changeset is owed here, against the card's expectation
The dispatch expected none, since
packages/vscode-extensionisprivate: true.The gate disagreed and it is right:
object-uiis private because it ships to theVS Code marketplace rather than npm, but it sits in the changesets
fixedgroupwith
privatePackages.version: true, so changesets versions it and writes itsCHANGELOG. Its first run said so verbatim:
.changeset/7837-vscode-export-react-side-effect-import.mddeclarespatch,never
majorper the fixed-group rule.Not run, stated plainly
paths derive to plus everything cheap that plausibly reads them.
pnpm lint/turbo run lintacross all 46 packages and every other package'stest suite. This diff does not leave
packages/vscode-extension, and thatpackage's own
lintandtestare its complete population.eslint.config.jsdeclares no
project/projectService, so no rule reads across files and thisdiff cannot move an untouched file's verdict.
check-published-dist-tooling— it needs a full repo build, and it skipsprivate packages by construction (
manifest.private === trueis checked beforerelease-group membership), so
object-uiis outside it either way.the end-to-end reading substituted for it is compiling the command's own output,
above.
Out of scope, filed rather than corrected in passing
objectui#7862 — the same generated file opens with
import React from 'react';and its only JSX is a single SchemaRenderer element (written in words: GitHub
deletes tag-shaped fragments from PR bodies, code fences included). Under
jsx: react-jsxthe identifier is never read, so the same output compiled withnoUnusedLocals: trueadded istscexit 2 withTS6133: 'React' is declared but its value is never read.Different defect classfrom this card — a real import that is unused, not a symbol that does not exist —
and correcting it is a decision about classic-transform users, so it is filed with
no assignee.
Also reported to the PM seat rather than filed, because the dispatch asked for the
reading and a proposal only:
packages/vscode-extensionhad zero test filesbefore this PR, and its
testscript isvitest run --passWithNoTests, so it was structurally green with nothing to run.🤖 Generated with Claude Code
https://claude.ai/code/session_01KbJQ1y1J12nZxYzFWhP8Q3
Generated by Claude Code