Skip to content

feat(base): ban bare @conform-to/zod import specifier - #38

Merged
stevensacks merged 1 commit into
mainfrom
feat/ban-bare-conform-zod-import
Jul 19, 2026
Merged

feat(base): ban bare @conform-to/zod import specifier#38
stevensacks merged 1 commit into
mainfrom
feat/ban-bare-conform-zod-import

Conversation

@stevensacks

Copy link
Copy Markdown
Contributor

What

Ban the bare @conform-to/zod import specifier via no-restricted-imports in the shared base config.

The bare @conform-to/zod specifier targets Zod v3 and throws at runtime — uncaught by typecheck, lint, and build — so a wrong import ships silently and only fails in the running app. This adds a lint-time guardrail so every consuming app catches it.

How

  • New shared const RESTRICTED_IMPORT_PATHS (src/configs/restricted-imports.ts), using exact-match paths (not patterns), so the distinct @conform-to/zod/v4 specifier stays allowed.
  • Global no-restricted-imports block added to base.ts, scoped to **/*.ts?(x).
  • The same const is spread into testing.ts's existing no-restricted-imports block (which bans *.server / internals on test/story files). Flat config replaces a rule's options wholesale, so without this the conform ban would be dropped on test/story files. Both call sites reference the one const to stay DRY.
  • src/configs/restricted-imports.test.ts lints real snippets against the actual exported config blocks (extracted by name from buildBase() and testing): proves a bare import errors, a /v4 import does not, and — regression — that *.server / internals bans still fire on test files.

Version reconciliation

Source lagged published reality: package.json was 1.8.0 while npm latest was 1.9.0 (the no-zod-enum rule shipped as 1.9.0 but the version bump/changeset-consumption was never committed, and there is no v1.9.0 tag). Left as-is, the next changeset version would bump 1.8.0 → 1.9.0 and collide with the published 1.9.0. This PR:

  • Bumps package.json to 1.9.0.
  • Drops the already-shipped no-zod-enum changeset.
  • Backfills the truthful ## 1.9.0 CHANGELOG entry (PR feat: add no-zod-enum guardrail #36 / fe262a6).

So the changesets action will now correctly bump to 1.10.0.

Bump level

Minor. A new error-level rule can break a consumer that violates it, but the package's convention ships new guardrail rules as minor (no-zod-enum, no-null-render both did), and the sole known consumer (gaia) is clean — all usages are already @conform-to/zod/v4.

Verification

pnpm typecheck && pnpm lint && pnpm test && pnpm build all green. 22 tests pass (6 new).

🤖 Generated with Claude Code

https://claude.ai/code/session_012zBEFqBaJAUkq8Mdhdk5Xo

The bare `@conform-to/zod` specifier targets Zod v3 and throws at RUNTIME,
uncaught by typecheck, lint, and build, so a wrong import ships silently and
only fails in the running app. Add a global `no-restricted-imports` `paths`
ban (exact-match, so the distinct `@conform-to/zod/v4` specifier stays allowed)
via a shared `RESTRICTED_IMPORT_PATHS` const. The same const is spread into
testing.ts's existing `no-restricted-imports` block so test/story files keep
the conform ban alongside their server-only/`internals` restrictions (flat
config replaces a rule's options wholesale, so the later block would otherwise
drop it).

Reconcile the lagging source with published reality: bump to 1.9.0, drop the
already-shipped `no-zod-enum` changeset, and backfill its 1.9.0 CHANGELOG entry
so the next release bumps to 1.10.0 instead of colliding with published 1.9.0.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_012zBEFqBaJAUkq8Mdhdk5Xo
@stevensacks
stevensacks merged commit 7bf6cec into main Jul 19, 2026
1 check passed
@stevensacks
stevensacks deleted the feat/ban-bare-conform-zod-import branch July 19, 2026 12:15
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