Skip to content

fix(cli): resolve component and hook names case-exactly on case-insensitive filesystems - #5478

Merged
cixzhang merged 3 commits into
mainfrom
fix-cli-resolvers
Aug 26, 2026
Merged

fix(cli): resolve component and hook names case-exactly on case-insensitive filesystems#5478
cixzhang merged 3 commits into
mainfrom
fix-cli-resolvers

Conversation

@cixzhang

Copy link
Copy Markdown
Contributor

Why

Two CLI tests fail on macOS on a clean origin/main, and pass in CI:

  • hook-discovery.test.mjsresolves a bare (use-prefix-stripped, case-insensitive) name
  • component.test.mjsis case-SENSITIVE: a lowercased name is unknown

They are not a matched pair pulling in opposite directions, and no rule changed.
Both are the same defect, and the tests encode the correct behaviour.

findComponentReadme, findComponentSource and findHookDoc probe candidate
paths with fs.existsSync, which answers through the filesystem's own case
folding
. On case-insensitive APFS/NTFS, existsSync('src/button/button.doc.mjs')
is true against the real src/Button/Button.doc.mjs. So on a Mac:

  • astryx component button silently answers for Button instead of reporting an
    unknown component with suggestions.
  • findHookDoc(core, 'mediaquery') returns .../hooks/useMediaquery.doc.mjs — a
    spelling that exists nowhere. It is read back fine on the Mac that produced it
    and breaks anywhere case-sensitive.

Confirmed by running the unmodified resolvers against the same packages/core
tree on a case-sensitive APFS volume and on the Mac's normal one:

call case-sensitive volume Mac (before)
findHookDoc(core, 'mediaquery') src/hooks/useMediaQuery.doc.mjs src/hooks/useMediaquery.doc.mjs
findComponentReadme(core, 'button') null src/button/button.doc.mjs

What

Adds existsCaseExact(targetPath, rootDir) to foundation/fs/paths.mjs: it
keeps the cheap existsSync short-circuit, then verifies every path segment
below rootDir against its parent's real directory listing. The three resolvers
use it for their name-derived probes.

The deliberate case-insensitive hook lookup is unchanged — mediaquery still
resolves, it now just returns the file's true casing (step 2 of findHookDoc,
which reads real names off readdirSync, does the work the folded existsSync
was shadowing).

Risk

Low, and confined to the CLI's name resolution.

Behaviour on Linux is unchanged by construction — existsSync already answered
case-exactly there, so the added check can only agree. On macOS/Windows, a
lowercase name that used to resolve by accident now takes the normal
unknown-name path (fuzzy suggestions, or ERR_UNKNOWN_COMPONENT) — the same
answer Linux and CI have always given.

One cost: on macOS a miss like component button now pays the full-tree
fallback scan (~0.5ms → ~50ms), because it stops short-circuiting on a wrong-case
hit. That is the cost every unknown name already pays, and the cost Linux
already paid.

Testing

  • Both named tests pass; the full packages/cli node suite is green
    (2837/2837). At the default 30s per-test timeout this laptop flakes several
    unrelated tests under load — --testTimeout=180000 clears them, on this branch
    and on origin/main alike.
  • New colocated tests for existsCaseExact in paths.test.mjs cover basename
    case, a wrong-case directory segment, missing paths, and a target outside the
    root. They pass on both filesystem kinds (trivially on Linux, meaningfully on a
    Mac).
  • Re-ran the case-sensitive-volume comparison with the fix: all four probes now
    return byte-identical paths on both filesystems.
  • astryx component button on macOS now prints No component named "button"
    with Button (exact name) / IconButton (keyword "button") suggestions.
  • eslint clean; all four packages/cli typecheck projects clean.

@meta-cla meta-cla Bot added the CLA Signed This label is managed by the Meta Open Source bot. label Aug 25, 2026
@vercel

vercel Bot commented Aug 25, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
astryx Ready Ready Preview Aug 26, 2026 9:30pm

Request Review

@github-actions

github-actions Bot commented Aug 25, 2026

Copy link
Copy Markdown
Contributor

PR Analysis Report

📚 Storybook Preview

View Storybook for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

🧪 Sandbox Preview

View Sandbox for this PR
GitHub Pages may take up to a minute to hydrate after deploy.

No new or modified components detected.

Bundle Size Summary

No component packages changed.

Accessibility Audit

Status: No accessibility violations detected.


Generated by PR Enrichment workflow | Storybook | Sandbox | View full report

github-actions Bot added a commit that referenced this pull request Aug 25, 2026
@cixzhang
cixzhang merged commit 553b07f into main Aug 26, 2026
21 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed This label is managed by the Meta Open Source bot.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant