fix(packages/cli,deps): fix EMFILE error and upgrade to zod 4.x and type-fest 5.x#27
Conversation
…ype-fest 5.x - Fix EMFILE (too many open files) error on macOS by adding depth limit to chokidar - Improve watcher output to show only first 3 paths + count instead of listing all paths - Upgrade zod to 4.3.6 (from 3.24.1) with compatibility fixes for new API - Upgrade type-fest to 5.4.4 (from 4.30.0) - Upgrade turbo to 2.8.17 - Add zod and type-fest to pnpm workspace catalog for consistency - Fix Zod 4.x API changes: errors -> issues, tuple syntax, record signature - Replace forEach with map to comply with functional programming rules Co-Authored-By: Claude <noreply@anthropic.com>
|
| Name | Type |
|---|---|
| @zpress/theme | Minor |
| @zpress/config | Minor |
| @zpress/core | Major |
| @zpress/ui | Major |
| @zpress/cli | Major |
| @zpress/kit | Major |
Click here to learn what changesets are, and how to add one.
Click here if you're a maintainer who wants to add a changeset to this PR
📝 WalkthroughWalkthroughRefactors and expands the configuration schema/API (new Entry base type, TitleConfig, Discovery; renames like Changes
Estimated code review effort🎯 4 (Complex) | ⏱️ ~45 minutes Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches
🧪 Generate unit tests (beta)
📝 Coding Plan
Comment |
Fixes Flash of Unstyled Content (FOUC) by injecting minified critical CSS directly into HTML <head> during build. Critical CSS includes essential color variables and html/body background styling for immediate first paint, while full CSS loads asynchronously. Changes: - Add critical-css.ts with minified theme-specific critical CSS - Update config.ts to inject critical CSS via Rspress head config - Support all built-in themes (base, midnight, arcade, arcade-fx) Impact: - Eliminates ~100-300ms white flash on cold page loads - Improves first paint experience on production deployments - ~1KB inline CSS per theme Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 4
🧹 Nitpick comments (1)
packages/config/src/errors.ts (1)
49-60: Add JSDoc forconfigErrorFromZod.This exported helper is part of the package surface and is touched in this PR, but it still has no in-source doc block.
As per coding guidelines "Include JSDoc comments on exported functions".
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/config/src/errors.ts` around lines 49 - 60, Add a JSDoc block for the exported function configErrorFromZod describing its purpose (convert a ZodError into a ConfigError), the parameter zodError (type ZodError) and what it contains, and the return value (ConfigError with _tag, type, message, and errors array), and include any relevant notes about the shape of errors.path (string|number) and that this is part of the public package surface; place the JSDoc immediately above the configErrorFromZod function declaration to satisfy the exported-function documentation guideline.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@packages/config/package.json`:
- Line 56: The project is passing Zod v4 schemas to zod-to-json-schema v3 which
expects Zod v3; fix by either updating the dependency "zod-to-json-schema" in
package.json to a release that supports Zod v4, or change the import in
packages/config/src/schema.ts to import { z } from 'zod/v3' so the schemas
passed to zodToJsonSchema match the expected Zod version; locate references to z
and zodToJsonSchema in schema.ts (and ensure package.json dependency bump is
published compatible) and update accordingly.
In `@packages/config/README.md`:
- Line 365: The README's ConfigErrorType union is incomplete; update the
documented union to include every exported case from
packages/config/src/errors.ts so consumers can exhaustively handle errors —
replace the current type ConfigErrorType = 'not_found' | 'parse_error' |
'validation_failed' | 'empty_sections' with the full set (add 'missing_field',
'invalid_entry', 'invalid_section', 'invalid_field', 'invalid_icon',
'invalid_theme', 'duplicate_prefix', 'unknown') and ensure the README's API
reference for ConfigErrorType matches the actual exports in errors.ts (reference
symbol: ConfigErrorType and the exported cases in errors.ts).
In `@packages/config/src/schema.ts`:
- Around line 26-33: The current frontmatter.head schema uses
z.array(...).min(2).max(2) which allows any ordering of the two types; change it
to enforce fixed positions by replacing the inner array with a tuple (use
z.tuple) so the first element is z.string() and the second is
z.record(z.string(), z.string()); keep the outer z.array(...) and .optional()
semantics but make each item a z.tuple([z.string(), z.record(z.string(),
z.string())]) so consumers relying on positional semantics get validated data.
- Around line 91-151: The schemas (entrySchema, workspaceItemSchema,
workspaceGroupSchema, featureSchema) are too strict and no longer match the
documented/migrated config shapes, causing validateConfig (used by loadConfig)
to reject real user configs; update these Zod schemas to accept the
legacy/advertised fields and optional titles (e.g., allow title OR text,
description, titleFrom, titleTransform as optional alternatives), restore
top-level discovery fields on workspaceItemSchema, and relax or remove .strict()
where necessary (or add .passthrough()) so unknown-but-documented fields are
allowed; ensure validateConfig still enforces required new constraints but does
not reject configs following the README migration examples.
---
Nitpick comments:
In `@packages/config/src/errors.ts`:
- Around line 49-60: Add a JSDoc block for the exported function
configErrorFromZod describing its purpose (convert a ZodError into a
ConfigError), the parameter zodError (type ZodError) and what it contains, and
the return value (ConfigError with _tag, type, message, and errors array), and
include any relevant notes about the shape of errors.path (string|number) and
that this is part of the public package surface; place the JSDoc immediately
above the configErrorFromZod function declaration to satisfy the
exported-function documentation guideline.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 623bbd68-166b-48b6-b41d-9014d14ee5a8
⛔ Files ignored due to path filters (1)
pnpm-lock.yamlis excluded by!**/pnpm-lock.yaml
📒 Files selected for processing (46)
.changeset/config-theme-packages.md.changeset/refactor-workspace-config-api.md.changeset/vscode-ui-improvements.md.vscode/kitchen-sink.code-workspace.vscode/settings.json.vscode/simple.code-workspacedocs/guides/workspaces.mddocs/references/icons/colors.mdxdocs/references/icons/overview.mdxdocs/references/icons/technology/databases.mdxdocs/references/icons/technology/frameworks.mdxdocs/references/icons/technology/infrastructure.mdxdocs/references/icons/technology/integrations.mdxdocs/references/icons/technology/languages.mdxdocs/references/icons/technology/overview.mdxdocs/references/icons/technology/tooling.mdxextensions/vscode/src/extension.tspackage.jsonpackages/cli/package.jsonpackages/cli/src/commands/build.tspackages/cli/src/commands/dev.tspackages/cli/src/commands/dump.tspackages/cli/src/commands/generate.tspackages/cli/src/commands/serve.tspackages/cli/src/commands/sync.tspackages/cli/src/lib/rspress.tspackages/cli/src/lib/watcher.tspackages/config/README.mdpackages/config/package.jsonpackages/config/schemas/schema.jsonpackages/config/scripts/generate-schema.tspackages/config/src/errors.tspackages/config/src/loader.tspackages/config/src/schema.tspackages/config/src/validator.tspackages/core/src/define-config.tspackages/core/src/sync/home.tspackages/core/src/sync/index.tspackages/core/src/sync/resolve/index.tspackages/core/src/sync/resolve/recursive.tspackages/core/src/sync/workspace.tspackages/theme/README.mdpackages/theme/package.jsonpackages/theme/src/types.tspackages/ui/src/config.tspnpm-workspace.yaml
💤 Files with no reviewable changes (1)
- packages/core/src/sync/workspace.ts
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/ui/src/config.ts (1)
119-124: Optional: Simplify IIFE to conditional expression.The IIFE pattern works but a conditional expression would be more concise and equally declarative. I note the same pattern exists at lines 148-153, so this could be addressed together in a future cleanup.
♻️ Suggested simplification
- const headElements = (() => { - if (criticalCss) { - return [`<style data-zpress-critical>${criticalCss}</style>`] - } - return [] - })() + const headElements = criticalCss + ? [`<style data-zpress-critical>${criticalCss}</style>`] + : []🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ui/src/config.ts` around lines 119 - 124, Replace the IIFE that builds headElements with a concise conditional expression: instead of const headElements = (() => { if (criticalCss) { return [`<style data-zpress-critical>${criticalCss}</style>`] } return [] })(), set headElements using a ternary/conditional expression that returns the same array when criticalCss is truthy and an empty array otherwise (refer to the headElements identifier and the criticalCss variable); repeat the same simplification for the similar pattern around the other instance currently at lines 148-153.packages/ui/src/critical-css.ts (1)
33-40: Consider usingisBuiltInThemetype guard for cleaner type narrowing.The
as BuiltInThemeNameassertion bypasses type checking. SinceisBuiltInThemeis already available from@zpress/theme(used inconfig.ts), using it here would make the validation explicit and avoid the unsafe cast.♻️ Suggested refactor using type guard
-import type { BuiltInThemeName } from '@zpress/config' +import type { BuiltInThemeName } from '@zpress/config' +import { isBuiltInTheme } from '@zpress/theme' // ... CSS constants unchanged ... export function getCriticalCss(themeName: string): string { - const theme = themeName as BuiltInThemeName - const css = CRITICAL_CSS_MAP[theme] - if (!css) { + if (!isBuiltInTheme(themeName)) { return '' } - return css + return CRITICAL_CSS_MAP[themeName] }🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/ui/src/critical-css.ts` around lines 33 - 40, The function getCriticalCss uses an unsafe cast to BuiltInThemeName; replace the assertion with the isBuiltInTheme type guard to validate themeName before indexing CRITICAL_CSS_MAP. Update getCriticalCss to call isBuiltInTheme(themeName) and only treat it as BuiltInThemeName when true, returning '' otherwise; reference the isBuiltInTheme import from `@zpress/theme`, the CRITICAL_CSS_MAP lookup, and the BuiltInThemeName type to guide the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/ui/src/config.ts`:
- Around line 119-124: Replace the IIFE that builds headElements with a concise
conditional expression: instead of const headElements = (() => { if
(criticalCss) { return [`<style data-zpress-critical>${criticalCss}</style>`] }
return [] })(), set headElements using a ternary/conditional expression that
returns the same array when criticalCss is truthy and an empty array otherwise
(refer to the headElements identifier and the criticalCss variable); repeat the
same simplification for the similar pattern around the other instance currently
at lines 148-153.
In `@packages/ui/src/critical-css.ts`:
- Around line 33-40: The function getCriticalCss uses an unsafe cast to
BuiltInThemeName; replace the assertion with the isBuiltInTheme type guard to
validate themeName before indexing CRITICAL_CSS_MAP. Update getCriticalCss to
call isBuiltInTheme(themeName) and only treat it as BuiltInThemeName when true,
returning '' otherwise; reference the isBuiltInTheme import from `@zpress/theme`,
the CRITICAL_CSS_MAP lookup, and the BuiltInThemeName type to guide the change.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: ae8ca80c-331d-4078-a8d3-75c54a9255b5
📒 Files selected for processing (2)
packages/ui/src/config.tspackages/ui/src/critical-css.ts
Fixes multiple schema and compatibility issues identified in PR review:
1. **Zod v3 compatibility**: Change to `import { z } from 'zod/v3'` for
compatibility with zod-to-json-schema@3.25.1, which requires Zod v3
schema objects. Redefined theme schema inline to avoid type conflicts.
2. **ConfigErrorType documentation**: Updated README to include all error
types (missing_field, invalid_entry, invalid_section, invalid_field,
invalid_icon, invalid_theme, duplicate_prefix, unknown).
3. **Schema strictness fixes**:
- Changed frontmatter.head to use tuple for fixed positions:
`z.tuple([z.string(), z.record(z.string(), z.string())])`
- Changed outline to use tuple instead of array for fixed positions
- Added deprecated fields (titleFrom, titleTransform) to entrySchema
for backward compatibility with existing configs
All packages build successfully and pass type checks.
Co-Authored-By: Claude <noreply@anthropic.com>
There was a problem hiding this comment.
🧹 Nitpick comments (2)
packages/config/src/schema.ts (1)
108-110: Good backward compatibility with deprecated fields.Adding
titleFromandtitleTransformas optional deprecated fields allows existing configs to continue validating while encouraging migration to the newtitleobject structure. Consider adding a JSDoc@deprecatedtag or runtime warning to guide users toward the new pattern.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/config/src/schema.ts` around lines 108 - 110, The schema currently accepts deprecated fields titleFrom and titleTransform but doesn't indicate deprecation; add JSDoc `@deprecated` comments above the zod entries for titleFrom and titleTransform and, in the validation path that consumes this schema (or in a helper that normalizes config), detect when either titleFrom or titleTransform is present and emit a runtime warning directing users to the new title object pattern; reference the symbols titleFrom and titleTransform in your changes so the comments and warning logic are colocated with the existing optional zod definitions.packages/config/README.md (1)
114-116: Consider using.map()in documentation examples for consistency.The coding guidelines prefer
.map()over.forEach()for functional-style compliance. While these are documentation examples, they serve as reference patterns for users. Consider updating to demonstrate the preferred approach.♻️ Suggested change for line 114-116
- error.errors?.forEach((err) => { - console.error(` ${err.path.join('.')}: ${err.message}`) - }) + error.errors?.map((err) => + console.error(` ${err.path.join('.')}: ${err.message}`) + )♻️ Suggested change for line 396-398
- error.errors?.forEach((err) => { - console.error(` ${err.path.join('.')}: ${err.message}`) - }) + error.errors?.map((err) => + console.error(` ${err.path.join('.')}: ${err.message}`) + )As per coding guidelines: "Use pure, immutable, declarative TypeScript — avoid classes, loops,
let, andthrow; prefermap,filter,reduce".Also applies to: 396-398
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@packages/config/README.md` around lines 114 - 116, Replace the documentation example that uses error.errors?.forEach(...) with a pure/functional pattern: call error.errors?.map(err => ` ${err.path.join('.')}: ${err.message}`) to produce an array of formatted lines, then log them in one call (e.g., console.error(lines.join('\n'))). Update both occurrences (the snippet using error.errors, err.path.join and err.message at lines shown) to use map + join so the example follows the preferred immutable/declarative style.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Nitpick comments:
In `@packages/config/README.md`:
- Around line 114-116: Replace the documentation example that uses
error.errors?.forEach(...) with a pure/functional pattern: call
error.errors?.map(err => ` ${err.path.join('.')}: ${err.message}`) to produce
an array of formatted lines, then log them in one call (e.g.,
console.error(lines.join('\n'))). Update both occurrences (the snippet using
error.errors, err.path.join and err.message at lines shown) to use map + join so
the example follows the preferred immutable/declarative style.
In `@packages/config/src/schema.ts`:
- Around line 108-110: The schema currently accepts deprecated fields titleFrom
and titleTransform but doesn't indicate deprecation; add JSDoc `@deprecated`
comments above the zod entries for titleFrom and titleTransform and, in the
validation path that consumes this schema (or in a helper that normalizes
config), detect when either titleFrom or titleTransform is present and emit a
runtime warning directing users to the new title object pattern; reference the
symbols titleFrom and titleTransform in your changes so the comments and warning
logic are colocated with the existing optional zod definitions.
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro
Run ID: 81ae4511-3a3f-4637-ba2e-2c966909371f
📒 Files selected for processing (4)
packages/config/README.mdpackages/config/schemas/schema.jsonpackages/config/src/errors.tspackages/config/src/schema.ts
🚧 Files skipped from review as they are similar to previous changes (1)
- packages/config/src/errors.ts
Summary
EMFILE: too many open fileserror when watching many directories on macOSzodto 4.3.6 andtype-festto 5.4.4 with all necessary compatibility fixesChanges
Watcher Fixes (
packages/cli)depth: 99limit to chokidar to reduce file descriptor usagets-patternmatch instead of ternaries for functional style complianceDependency Upgrades
3.24.1→4.3.6(added to workspace catalog)4.30.0→5.4.4(added to workspace catalog)2.8.16→2.8.17Zod 4.x Compatibility (
packages/config)zodError.errors→zodError.issuesz.tuple([...])→z.array(...).min(2).max(2)z.record(key, value)now requires both parameterszod-to-json-schemacompatibility with type assertionCode Style (
packages/cli)forEachloops with.map()to comply withfunctional/no-loop-statementsruleTest Plan
pnpm checkpasses (typecheck + lint + format)Summary by CodeRabbit
New Features
Breaking Changes
Improvements