Skip to content

ci: silence baseUrl deprecation in docs tsconfig under TS 6+#5921

Closed
dokson wants to merge 1 commit into
colinhacks:mainfrom
dokson:ci/patch-docs-tsconfig-ts6
Closed

ci: silence baseUrl deprecation in docs tsconfig under TS 6+#5921
dokson wants to merge 1 commit into
colinhacks:mainfrom
dokson:ci/patch-docs-tsconfig-ts6

Conversation

@dokson

@dokson dokson commented May 1, 2026

Copy link
Copy Markdown
Contributor

Summary

Fixes the pnpm test job under Test with TypeScript latest (currently TS 6.0.3), which has been failing on every PR opened since e58ea4d (yesterday) with:

TypeCheckError: Option 'baseUrl' is deprecated and will stop functioning in TypeScript 7.0.
Specify compilerOption '"ignoreDeprecations" "6.0"' to silence this error.
 ❯ packages/docs/tsconfig.test.json:3:3

Test Files  339 passed (339)
     Tests  3791 passed (3791)
Type Errors  no errors
     Errors  1 error    ← exit 1 here

All tests pass; the failure is a vitest-side classification of a TS deprecation as an unhandled error.

Root cause

Commit e58ea4d ("docs: test Zod Mini tab code heights", 2026-04-30) added a brand-new packages/docs/tsconfig.test.json. That file extends packages/docs/tsconfig.json, which has carried "baseUrl": "." since long before TS deprecated it. Before e58ea4d, the docs package had no vitest typecheck setup, so the deprecation never reached pnpm test. After e58ea4d it does, and vitest 4.x's typecheck.checker: "tsc" re-emits TS source errors as test-runner unhandled errors → exit 1.

This explains the recent CI breakage: PR #5914 (opened 2026-04-30 18:50 UTC, before the e58ea4d landed at 19:12 UTC) passes; PRs opened or rerun after that point fail. Same TypeScript 6.0.3, same vitest 4.1.5 — only the new docs tsconfig differs.

Why a source-level fix doesn't work

Tried first; closed PR #5920. Three things ruled out:

  1. "ignoreDeprecations": "6.0" in source — TS 5.5 rejects with TS5103: Invalid value for '--ignoreDeprecations' and breaks the Test with TypeScript 5.5 job.
  2. "ignoreDeprecations": "5.0" in source — accepted by TS 5.5, but TS 6 still emits the baseUrl deprecation under it (the deprecation message specifically demands "6.0").
  3. Removing baseUrl outright — breaks Next.js asset imports in app/layout.config.tsx: Cannot find module '@/public/logo/logo.png'. Removing it would require touching unrelated runtime code.

So the fix has to be TS-version-conditional, which means workflow logic.

Fix

Add a single matrix-conditional jq step before pnpm build, injecting ignoreDeprecations: "6.0" into packages/docs/tsconfig.json only when the matrix typescript value is not 5.5. This mirrors the pattern already used in the repo (e.g. on the fix-tests-ci branch's commit 4e29983) for the same kind of TS-version delta on .configs/tsconfig.base.json.

- if: matrix.typescript != '5.5'
  run: |
    TSCONFIG=packages/docs/tsconfig.json
    jq '.compilerOptions.ignoreDeprecations = "6.0"' "$TSCONFIG" > "$TSCONFIG.tmp"
    mv "$TSCONFIG.tmp" "$TSCONFIG"

The patched file is only used for the duration of the CI run; nothing in source changes.

Verification

Reproduced and validated locally with TS 6.0.3 + vitest 4.1.5. Before the patch, the unhandled error appears on most runs; after applying the same jq transform manually, three consecutive pnpm test invocations all complete without Errors 1 error. TS 5.5 path is unchanged (the conditional skips the patch).

Scope

  • 1 file touched: .github/workflows/test.yml (+8 lines).
  • Strictly additive: no existing step removed, no matrix entry changed.
  • No source / runtime / library-code changes.
  • The jq binary is already available on ubuntu-latest runners.

Alternative considered

The fix-tests-ci branch's commit 4e29983 already adds a similar jq step plus a typescript: "6" matrix entry and fail-fast: false, but it patches .configs/tsconfig.base.json (not the docs one) and isn't merged yet. If that branch lands first, the same jq invocation can be folded into its block; the deltas don't conflict. Happy to defer or rebase if preferred.

Commit e58ea4d added `packages/docs/tsconfig.test.json`, which
extends `packages/docs/tsconfig.json` (`baseUrl: "."`). Under TS 6
the legacy `baseUrl` triggers a deprecation that vitest 4.x's
typecheck integration re-emits as an Unhandled Source Error, failing
`pnpm test` with `Errors 1 error` even when every test passes:

    TypeCheckError: Option 'baseUrl' is deprecated and will stop
    functioning in TypeScript 7.0. Specify compilerOption
    '"ignoreDeprecations" "6.0"' to silence this error.
     ❯ packages/docs/tsconfig.test.json:3:3

A source-level fix doesn't compose: TS 5.5 rejects `"6.0"` as
`TS5103: Invalid value for '--ignoreDeprecations'`, and TS 6 isn't
silenced by `"5.0"` for the `baseUrl` deprecation specifically.
Removing `baseUrl` outright breaks Next.js asset imports
(`Cannot find module '@/public/logo/...'`).

Inject the option only on the non-5.5 matrix entries via `jq`,
mirroring the pattern used elsewhere in the repo for similar TS-version
deltas. Three consecutive local `pnpm test` runs on TS 6.0.3 confirm
the unhandled error is gone deterministically; TS 5.5 is unchanged.
@pullfrog

pullfrog Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

Reviewed PR #5921 — the fix is correct and well-scoped. Approved with an informational inline note. The conditional jq injection of ignoreDeprecations: "6.0" is the right approach for the TS 5.5/6.0 matrix split. #5921 (review)

Task list (3/3 completed)
  • Checkout PR and read the diff
  • Investigate the change and assess correctness
  • Submit review

Pullfrog  | View workflow run | via Pullfrog | Using Claude Opus𝕏

@pullfrog

pullfrog Bot commented May 1, 2026

Copy link
Copy Markdown
Contributor

TL;DR — Adds a matrix-conditional CI step that injects "ignoreDeprecations": "6.0" into the docs tsconfig.json before build/test, silencing a TS 6+ deprecation warning that vitest surfaces as a fatal error. Only runs on non-5.5 matrix entries; no source files are modified.

Key changes

  • Inject ignoreDeprecations via jq in CI for TS 6+ matrix entries — conditionally patches packages/docs/tsconfig.json at workflow time so the baseUrl deprecation doesn't cause vitest to exit 1, while leaving the TS 5.5 job untouched.

Summary | 1 file | 1 commit | base: mainci/patch-docs-tsconfig-ts6


Before: The Test with TypeScript latest job fails on every PR because vitest treats the TS 6 baseUrl deprecation as an unhandled error (exit 1), even though all tests pass.
After: A jq step injects "ignoreDeprecations": "6.0" into packages/docs/tsconfig.json only when matrix.typescript != '5.5', suppressing the deprecation without touching source code or breaking the TS 5.5 job.

The fix is version-conditional because TS 5.5 rejects "ignoreDeprecations": "6.0" as an invalid value, and removing baseUrl outright would break Next.js path aliases in the docs package. This mirrors the pattern from commit 4e29983 on the fix-tests-ci branch.

.github/workflows/test.yml

Pullfrog  | View workflow run | via Pullfrog | Using Claude Opus𝕏

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The fix is correct — e58ea4d broke CI by adding a docs tsconfig.test.json that inherits the long-standing baseUrl: ".", which TS 6 now deprecates. The conditional jq injection is the right approach given that ignoreDeprecations: "6.0" is invalid under TS 5.5 and removing baseUrl would require touching runtime Next.js imports. No issues found with the implementation.

Task list (3/3 completed)
  • Checkout PR and read the diff
  • Investigate the change and assess correctness
  • Submit review

Pullfrog  | View workflow run | Using Claude Opus𝕏

# baseUrl in packages/docs/tsconfig.json is deprecated under TS 6
# and vitest's typecheck integration surfaces it as an unhandled
# error; TS 5.5 rejects "6.0", so inject only on newer matrix entries.
- if: matrix.typescript != '5.5'

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nit: if the matrix ever gains entries like "5.6" or "6.1", this condition still works correctly since only 5.5 is excluded. Worth noting the condition is version-string equality — not a semver comparison — so it's tied to the literal matrix values. Fine as-is.

@pullfrog pullfrog Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewed — no issues found.

Task list (3/3 completed)
  • Checkout PR and read the diff
  • Investigate the change and assess correctness
  • Submit review

Pullfrog  | View workflow run | Using Claude Opus𝕏

dokson added a commit to dokson/zod that referenced this pull request May 1, 2026
…nhacks#2854, colinhacks#2106)

`.deepPartial()` was deprecated in v3.21.0 and removed in v4 because the
underlying recursive `instanceof` traversal had structural problems
(see colinhacks#2106): it could not see user-defined schema subclasses, accumulated
edge cases for every new schema type, and silently broke on advanced
shapes. The community has been asking for a working alternative ever
since (colinhacks#2854, 60+ commenters).

Adds a v4-native implementation that addresses the design concerns of
colinhacks#2106 head-on:

- Dispatches on `schema._zod.def.type`, not `instanceof`. Custom schemas
  with unknown `def.type` fall through to identity instead of being
  silently mishandled. Users intercept inside `fn` for custom rewriting.
- Cycle-safe via a `Map<schema, RESOLVING|result>` cache. Lazy schemas
  unfold lazily so recursive shapes terminate; shared sub-schemas are
  visited once. Direct (non-`lazy`) cycles throw rather than loop.
- Bottom-up rewrite as a primitive. `core.mapOnSchema(schema, fn)` is
  the general traversal; `deepPartial` is one line on top of it.
  `deepStrict`, `deepReadonly`, etc. become trivial follow-ups.
- Covers the v4 def vocabulary: object, array, tuple (+rest), record,
  map, set, union (incl. discriminated union — discriminator metadata
  preserved by spreading `def`), intersection, optional, nullable,
  default, prefault, nonoptional, catch, readonly, promise, success,
  pipe, function, lazy. Leaves (primitives, enum, literal, transform,
  custom, file, etc.) returned untouched.

`mapOnSchema` lives in `core/` so both `classic` and `mini` reuse it;
each variant has its own thin `deepPartial` wired to its own `partial`.

Traversal pattern adapted from Jaen's v3 `mapOnSchema` (Apache-2.0,
https://gist.github.com/jaens/7e15ae1984bb338c86eb5e452dee3010).
Implementation rewritten for v4: `def.type` dispatch instead of
`instanceof`, schema construction via `core.clone` instead of
`new ZodFoo(...)`, full v4 def coverage.

```ts
const Node: z.ZodType = z.object({
  name: z.string(),
  children: z.array(z.lazy(() => Node)).optional(),
});

z.deepPartial(Node).parse({});                    // ok
z.deepPartial(Node).parse({ children: [{}] });    // ok
```

Adds 22 tests covering shallow + nested objects, arrays, tuples with
rest, unions, optional/nullable wrappers, recursive (lazy) schemas,
primitive leaf preservation, and `mapOnSchema` identity / targeted
rewrites.

CI on TS 6+ may surface the unrelated `baseUrl` deprecation error
from colinhacks#5921 until that lands; this PR doesn't touch that path.
@dokson

dokson commented May 1, 2026

Copy link
Copy Markdown
Contributor Author

Superseded by 88015df (fix(docs): drop deprecated baseUrl from tsconfig) — cleaner source-level fix that removes baseUrl entirely. Since paths already uses relative ./ notation, the option was a no-op for resolution and just a CI landmine. My approach (matrix-conditional jq patch in the workflow) was overkill once the underlying option could simply be dropped.

Thanks 👍

@dokson dokson closed this May 1, 2026
@dokson dokson deleted the ci/patch-docs-tsconfig-ts6 branch May 1, 2026 21:59
dokson added a commit to dokson/zod that referenced this pull request May 1, 2026
…nhacks#2854, colinhacks#2106)

`.deepPartial()` was deprecated in v3.21.0 and removed in v4 because the
underlying recursive `instanceof` traversal had structural problems
(see colinhacks#2106): it could not see user-defined schema subclasses, accumulated
edge cases for every new schema type, and silently broke on advanced
shapes. The community has been asking for a working alternative ever
since (colinhacks#2854, 60+ commenters).

Adds a v4-native implementation that addresses the design concerns of
colinhacks#2106 head-on:

- Dispatches on `schema._zod.def.type`, not `instanceof`. Custom schemas
  with unknown `def.type` fall through to identity instead of being
  silently mishandled. Users intercept inside `fn` for custom rewriting.
- Cycle-safe via a `Map<schema, RESOLVING|result>` cache. Lazy schemas
  unfold lazily so recursive shapes terminate; shared sub-schemas are
  visited once. Direct (non-`lazy`) cycles throw rather than loop.
- Bottom-up rewrite as a primitive. `core.mapOnSchema(schema, fn)` is
  the general traversal; `deepPartial` is one line on top of it.
  `deepStrict`, `deepReadonly`, etc. become trivial follow-ups.
- Covers the v4 def vocabulary: object, array, tuple (+rest), record,
  map, set, union (incl. discriminated union — discriminator metadata
  preserved by spreading `def`), intersection, optional, nullable,
  default, prefault, nonoptional, catch, readonly, promise, success,
  pipe, function, lazy. Leaves (primitives, enum, literal, transform,
  custom, file, etc.) returned untouched.

`mapOnSchema` lives in `core/` so both `classic` and `mini` reuse it;
each variant has its own thin `deepPartial` wired to its own `partial`.

Traversal pattern adapted from Jaen's v3 `mapOnSchema` (Apache-2.0,
https://gist.github.com/jaens/7e15ae1984bb338c86eb5e452dee3010).
Implementation rewritten for v4: `def.type` dispatch instead of
`instanceof`, schema construction via `core.clone` instead of
`new ZodFoo(...)`, full v4 def coverage.

```ts
const Node: z.ZodType = z.object({
  name: z.string(),
  children: z.array(z.lazy(() => Node)).optional(),
});

z.deepPartial(Node).parse({});                    // ok
z.deepPartial(Node).parse({ children: [{}] });    // ok
```

Adds 22 tests covering shallow + nested objects, arrays, tuples with
rest, unions, optional/nullable wrappers, recursive (lazy) schemas,
primitive leaf preservation, and `mapOnSchema` identity / targeted
rewrites.

CI on TS 6+ may surface the unrelated `baseUrl` deprecation error
from colinhacks#5921 until that lands; this PR doesn't touch that path.
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