Skip to content

feat: Enhance monorepo with cross-platform utilities and advanced ESLint rules#2

Merged
jdutton merged 9 commits into
mainfrom
feat/template-improvements
Jan 8, 2026
Merged

feat: Enhance monorepo with cross-platform utilities and advanced ESLint rules#2
jdutton merged 9 commits into
mainfrom
feat/template-improvements

Conversation

@jdutton

@jdutton jdutton commented Jan 8, 2026

Copy link
Copy Markdown
Owner

Summary

This PR significantly enhances the TypeScript monorepo template with cross-platform compatibility utilities and advanced ESLint rules designed for agentic development workflows.

Key Features

🛠️ Cross-Platform Path Utilities

  • New path-utils.ts in example-utils package with Windows 8.3 short path resolution
    • normalizedTmpdir() - Resolves Windows RUNNER~1 style paths
    • mkdirSyncReal() - Creates directories with real path resolution
    • normalizePath() - Cross-platform path normalization using realpathSync.native()
  • Test helpers with getTestOutputDir() for isolated test environments
  • Comprehensive test coverage (242 lines of tests)

🔒 Custom ESLint Rules for Agentic Code Safety

Five new custom ESLint rules to prevent AI from reintroducing dangerous patterns:

  • no-os-tmpdir - Enforces normalizedTmpdir() over os.tmpdir()
  • no-fs-mkdirSync - Enforces mkdirSyncReal() for proper path handling
  • no-fs-realpathSync - Enforces normalizePath() for consistent resolution
  • no-unix-shell-commands - Prevents Unix-specific commands (tar, ls, grep, etc.)
  • no-command-direct-factory - Factory pattern for creating ESLint rules with auto-fix

📚 Enhanced TypeScript Configuration

  • Implemented TypeScript project references with tsc --build
  • Added noPropertyAccessFromIndexSignature: true for stricter type safety
  • Improved monorepo build performance with incremental compilation

✨ Additional ESLint Rules

  • @typescript-eslint/no-require-imports - Enforce ES modules
  • @typescript-eslint/max-params (4 max) - Reduce function complexity
  • Multiple Unicorn rules for code quality
  • Cognitive complexity reduction in custom rules (max 15)

📖 Documentation Updates

  • Comprehensive CLAUDE.md updates with:
    • Cross-platform compatibility patterns
    • Custom ESLint rule creation guide
    • Agentic development best practices
    • Complete API documentation for path utilities

Why This Matters

For Agentic Development: When working with AI code generation (Claude, Cursor, Copilot), these custom ESLint rules act as automatic guardrails that catch dangerous patterns immediately, preventing security vulnerabilities and cross-platform issues from being reintroduced.

Pattern: Identify dangerous code → Create ESLint rule → Never repeat the mistake

Testing

  • All existing tests pass
  • 242 lines of new tests for path utilities
  • Cross-platform validation on Windows/macOS/Linux via CI

Files Changed

  • 20 files changed, 1280 insertions, 36 deletions
  • New: path-utils.ts, test-helpers.ts, 5 ESLint rules
  • Enhanced: CLAUDE.md, example-utils/README.md

🤖 Generated with Claude Code

Co-Authored-By: Claude Sonnet 4.5 noreply@anthropic.com

jdutton and others added 8 commits January 4, 2026 14:56
- Add .worktrees/ to ESLint ignore patterns for git worktree support
- Disable base no-unused-vars in favor of @typescript-eslint/no-unused-vars
- Remove unnecessary eslint-disable comments in common.ts
- Add explicit rootDir to tsconfig.base.json for better path resolution

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
- Update package.json build scripts to use tsc --build
- Configure TypeScript composite projects in tsconfig.json files
- Add tsBuildInfoFile to each package for incremental builds
- Update typecheck to use tsc --build --dry --force
- Update clean to use tsc --build --clean
- Fix ESLint ignore patterns to use **/dist/** for nested directories
- Update vibe-validate to 0.18.2

Benefits:
- Packages build in dependency order automatically
- Incremental builds (only rebuilds what changed)
- Better type checking across package boundaries
- Single command builds everything correctly

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add missing rules from vibe-agent-toolkit for better code quality:

TypeScript rules:
- @typescript-eslint/no-redundant-type-constituents: Prevent redundant type unions
- @typescript-eslint/prefer-function-type: Prefer function types over interfaces with call signatures

Unicorn rules:
- unicorn/prefer-number-properties: Use Number.isNaN() instead of isNaN()
- unicorn/no-negated-condition: Prefer positive conditions for readability
- unicorn/prefer-export-from: Simplify re-exports (export {x} from 'y')
- unicorn/prefer-structured-clone: Use structuredClone() over custom implementations
- unicorn/no-zero-fractions: Disallow 1.0 in favor of 1

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Enforce ESM import syntax over CommonJS require():
- Prevents mixing module systems
- Ensures consistent ESM usage across the codebase
- Aligns with moduleResolution: "NodeNext" in tsconfig

This rule helps maintain modern JavaScript/TypeScript practices
and prevents accidental use of CommonJS in ESM projects.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Add 'max-params': ['error', 7] rule to catch functions with too many
parameters during development (before SonarQube).

Matches SonarQube's threshold of 7 parameters max.

Discovered in vibe-agent-toolkit when a test helper had 8 parameters
and triggered a SonarQube code smell. This rule ensures similar issues
are caught early by ESLint.
Add comprehensive cross-platform utilities for handling Windows 8.3 short path names (RUNNER~1) that cause test failures on Windows CI, along with custom ESLint rules to automatically enforce their usage.

**New Utilities (packages/example-utils/src/):**
- path-utils.ts: normalizePath(), normalizedTmpdir(), mkdirSyncReal(), isAbsolutePath(), toAbsolutePath(), getRelativePath(), toForwardSlash()
- test-helpers.ts: getTestOutputDir(), getTestOutputBase()

**New ESLint Rules (packages/dev-tools/eslint-local-rules/):**
- no-os-tmpdir: Enforces normalizedTmpdir() instead of os.tmpdir()
- no-fs-mkdirSync: Enforces mkdirSyncReal() instead of fs.mkdirSync()
- no-fs-realpathSync: Enforces normalizePath() instead of fs.realpathSync()
- no-unix-shell-commands: Prevents Unix-specific commands (tar, grep, ls, etc.)
- no-command-direct-factory.cjs: Shared factory for command execution rules

**Tests & Coverage:**
- Comprehensive test suite for path-utils (path-utils.test.ts)
- Platform-specific tests skip on non-matching platforms (Windows/Unix)
- Excluded test-helpers.ts from coverage (test utilities)

**Documentation (Progressive Disclosure):**
- Detailed API docs in packages/example-utils/README.md
- Brief overview in CLAUDE.md with link to README
- Explains Windows 8.3 short path problem and solutions

**ESLint Configuration:**
- Enabled all 4 new cross-platform rules in eslint.config.js
- Rules provide clear error messages with alternatives

All validation passes: build, typecheck, lint (zero warnings), duplication check (zero duplicates), tests (100% passing), coverage (>80%).

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
…ctory

Extract helper functions to reduce cognitive complexity from 18 to 6-8:
- checkShellFreeExecution(): Handle safeExecSync, spawn, etc.
- checkExecSyncExecution(): Handle execSync calls
- isShellFreeExecution(): Predicate to check function names
- Add early return for empty arguments

This refactoring eliminates SonarQube code smell while maintaining the same functionality.
@codecov

codecov Bot commented Jan 8, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 82.35294% with 12 lines in your changes missing coverage. Please review.
✅ Project coverage is 85.54%. Comparing base (58bb82d) to head (a101d5c).
⚠️ Report is 1 commits behind head on main.

Files with missing lines Patch % Lines
packages/example-utils/src/path-utils.ts 82.35% 12 Missing ⚠️
Additional details and impacted files

Impacted file tree graph

@@             Coverage Diff              @@
##              main       #2       +/-   ##
============================================
- Coverage   100.00%   85.54%   -14.46%     
============================================
  Files            1        2        +1     
  Lines           15       83       +68     
  Branches         7       27       +20     
============================================
+ Hits            15       71       +56     
- Misses           0       12       +12     
Files with missing lines Coverage Δ
packages/example-utils/src/path-utils.ts 82.35% <82.35%> (ø)
Files with missing lines Coverage Δ
packages/example-utils/src/path-utils.ts 82.35% <82.35%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

…platform guide

- Fix toAbsolutePath test to handle platform-specific path separators
- Update JSDoc to clarify platform behavior and provide usage examples
- Add CROSS_PLATFORM_EXAMPLE.md with comprehensive guide demonstrating:
  * The Windows 8.3 short path problem
  * How to use each utility function
  * Real-world examples and use cases
  * ESLint enforcement explanation
  * Complete test suite example

The test was failing on Windows because toAbsolutePath() returns
platform-specific separators (\\ on Windows, / on Unix). Updated test
to verify the path is absolute and contains expected components rather
than exact string match.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
@sonarqubecloud

sonarqubecloud Bot commented Jan 8, 2026

Copy link
Copy Markdown

@jdutton jdutton merged commit 0e462e6 into main Jan 8, 2026
9 checks passed
@jdutton jdutton deleted the feat/template-improvements branch January 8, 2026 16:59
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