Repository navigation
fix(cli): init refuses a name too long for a folder in one plain sentence - #5071
Conversation
Edit accuracy: accurate 2055 (base branch 2055), smooth 1627 of thoseThe gate passes. Quarantined, measured but not gated (0) |
jrusso1020
left a comment
There was a problem hiding this comment.
Approving at d9ba903a.
The check measures what the disk measures. nameTooLongMessage checks each folder of the resolved destination against 255:
- UTF-8 bytes on Linux, UTF-16 units elsewhere.
- On Windows it splits on both
\and/.
Both init paths run it on resolve(name) before existsSync or any mkdir. So a long folder that .. removes doesn't block a valid destination, and nothing is created on refusal. The whole-path limit is not checked, which is right: Node handles long full paths on Windows, and on Linux/macOS the per-folder limit is the one people hit.
Tests:
init.test.ts+init.interactive.test.ts: 36/36 on Linux.- Run by hand against
src/cli.ts:- 300
aprints "That name is 300 bytes long; a folder name can be at most 255 bytes." - 128
éprints the 256-bytes sentence. - In both cases nothing is created and no
ENAMETOOLONGor path is printed.
- 300
Mutations: 6 of 6 turn tests red:
- limit 256
>=- characters on Linux
- splitting on
/only - checking the raw name instead of the resolved one
- dropping the interactive check
Reuse: I didn't find an existing name validator in the CLI to reuse. toPackageName only normalizes for package.json.
One small fit with existing code, not blocking: for a name typed at the prompt, clack.text takes validate, as promptForKey in auth/login.ts already uses. validate: (v) => nameTooLongMessage(resolve(v || "my-video")) ?? undefined would re-ask for the name instead of cancelling the whole setup. The positional path still needs the check as written.
Simplify: the code is 19 lines; the other 135 are tests that each pin a separate rule, so I don't see anything to cut. The other design would be catching ENAMETOOLONG from mkdir. That measures the real filesystem (HFS+, NTFS mounts, shorter limits), but a nested name can leave parent folders behind. Checking first, as here, is the better trade for "nothing is created".
Not verified by me: the macOS unit. I didn't run on macOS, and whether APFS counts UTF-16 units or UTF-8 bytes decides whether a long accented name gets this sentence or the raw error there. Either way it's no worse than today.
CI: 92 pass, 0 fail.
— Rames
What
hyperframes initrefuses a project name that is too long for a folder, with one plain sentence that names the limit and the name's length, before it creates anything:Why
A name longer than the disk's folder-name limit reached
mkdirSync, and the command exited with Node's raw error and the full path:Repro on 0.8.126 and on current
main:npx hyperframes init $(printf 'a%.0s' $(seq 300)) --example blank --non-interactive.Related work
None found.
How
nameTooLongMessage(name, platform)inpackages/cli/src/commands/init.tschecks each folder in the resolved destination (a nested name likeparent/<name>is held to the limit per folder, not as a whole path) and measures it the way the disk does: UTF-8 bytes on Linux, UTF-16 units on macOS and Windows. The limit is 255 for all three...cannot reject a valid destination: non-interactive mode prints the sentence with the usual error style; interactive mode prints it through the prompt UI and cancels. Both exit 1 and leave no folder behind.Test plan
Ran on Linux:
init.test.ts, written first and red before the fix (the over-limit run printed the rawENAMETOOLONGwith the path):ENAMETOOLONG, no path, and no folder created;é(256 bytes, 128 characters) is refused on Linux and accepted on macOS, 127éis accepted on Linux, a nested name is held to the limit per folder.init.test.tspassed 34 tests andinit.interactive.test.tspassed 2 tests, each run alone three times with one worker. Every run exited 0 with no skipped tests.tsc --noEmitinpackages/cli, the pre-commit hooks (oxlint, oxfmt, fallow, typecheck),check-comment-citationsandcomment-ratchetpass.init.interactive.test.ts): a long name given on the command line and one typed into the prompt each show the sentence and leave no folder. Removing the interactive check fails it...scaffolds its resolved destination. Checking the raw name fails this regression and reports the wrong length in both interactive cases.parent\<256 characters>is measured per folder. Splitting on/only fails that assertion.Not exercised: a macOS or Windows run; the macOS and Windows rule is covered by the unit test only. Filesystems with a shorter limit than 255 (some encrypted or network mounts) still reach
mkdirSyncand its own error.Known limits
épasses the check there and still fails with the raw error. Counting decomposed would wrongly refuse valid names on APFS, the current macOS format./mnt/c, an NTFS or exFAT USB stick) is measured in bytes, so a name that would fit there can be refused. It fails with the clear sentence, never the raw error.Why this PR is small
One user-facing fix with its tests; nothing else in flight shares its code path, so there is nothing to bundle it with.
Independent review