chore(tooling): plain ASCII punctuation everywhere, and a guard that keeps it - #341
Conversation
…keeps it scripts/check-typography.mjs walks every tracked text file and fails on invisible characters (zero-width space, word joiner, byte order mark, soft hyphen), on typographic punctuation (en and em dashes, curly quotes, the ellipsis character, non-breaking spaces), on U+FFFD, and on UTF-8 that was read as Latin-1 somewhere upstream. It runs from the pre-commit hook and the CI lint job, and its own character table is written as code points, so it does not report itself. U+200C, U+200D and the bidi marks are deliberately left alone: Persian needs the first between the parts of a word, emoji sequences need the second, and mixed right-to-left text needs the last two. The sweep it demanded came to 3,451 characters across 674 files, and two parts of it are worth reading rather than skimming. A curly apostrophe inside a single-quoted string ends that string. Twenty-one test names and story descriptions had one, so those literals now use double quotes. The two tests that assert on typography build their fixtures from code points instead, or the sweep would have rewritten both sides of the assertion and left them passing while proving nothing.
|
Important Review skippedToo many files! This PR contains 686 files, which is 586 over the limit of 100. To get a review, reduce the PR to 100 files or fewer by splitting it into smaller PRs or changing its base branch. Upgrade to a paid plan to raise the limit. Usage-priced reviews support at most 300 files. ⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Plus Run ID: ⛔ Files ignored due to path filters (2)
📒 Files selected for processing (686)
You can disable this status message by setting the Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The node script it replaced is gone, so the lint job has been failing on a missing check:typography script rather than on anything it found. The published binary backs that script now, and the hooks use the two modes the script never had. pre-commit runs it over the staged files: prose is fixed and re-staged, code is reported and the commit stops. Rewriting a curly apostrophe inside a quoted string is how a file stops parsing, so that half is deliberately hands-off. commit-msg is new. Messages are fixed in place before the commit object exists, which is the only moment that costs nothing - amending afterwards would change every sha from there on and void the signatures over them. The binary arrives prebuilt as an optional dependency keyed by os and cpu, so a machine fetches one package of a couple of megabytes and no others. Nothing compiles and no install script runs, which is what keeps it working under --ignore-scripts everywhere in CI. The lockfile carries all seven targets because it has to describe the install on the runners too, not just here.
|
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
Benchmark resultsBaseline case:
|
| case | avg | p75 | alloc/iter | vs fastest |
|---|---|---|---|---|
| styled-system color() :: local-cjs | 428 ns | 428 ns | 248 B (least) | fastest |
| styled-system color() :: local-mjs | 439 ns | 439 ns | 248 B (+0.0%) | +2.7% |
| styled-system color() :: previous | 449 ns | 449 ns | 248 B (+0.0%) | +5.0% |
Bundle ReportChanges will decrease total bundle size by 524 bytes (-0.0%) ⬇️. This is within the configured threshold ✅ Detailed changes
Affected Assets, Files, and Routes:view changes for bundle: @soroush.tech/dev-esmAssets Changed:
|



Every en/em dash, curly quote, ellipsis and non-breaking space in tracked text is now plain ASCII, and
ai-watermark-guardkeeps it that way from the pre-commit hook, a new commit-msg hook, and the lint job.What changed
The sweep - 3,451 characters across 674 files. Invisible characters and mojibake go with them: the first run found a literal
U+200Bsitting inside a string inSelect.tsx, invisible in the source, in a diff and in review alike.The guard -
ai-watermark-guard@0.1.0as a root devDependency. This replaces the in-reposcripts/check-typography.mjsan earlier revision of this branch carried; the published tool does the same work and adds the commit-message modes a package script could not..husky/pre-commitaiwg --staged --fix.husky/commit-msgaiwg --message "$1" --fixaiwg --allThe binary arrives prebuilt as an optional dependency keyed by
os/cpu, so each machine fetches one package of a couple of megabytes, nothing compiles, and no install script runs - it keeps working under--ignore-scripts, as CI installs everywhere. The lockfile carries all seven targets because it has to describe the install on the runners too, not just on the machine that wrote it.Deliberately not flagged
U+200C,U+200D,U+200E,U+200F. Persian needs the first between the parts of a word, an emoji sequence needs the second to hold itself together, and the last two set the direction of mixed right-to-left text. Removing them corrupts text rather than cleaning it. Letters are never touched, in any script - this is not an ASCII-only rule.Consumer-visible changes
Three published packages changed rendered output, so six are bumped with notes:
design-systemTablePaginationdefault label now reads1-10 of 57with a hyphenmarkdownEditorandLiveEditplaceholders end in three periodsbenchplaywright-coveragestyled-systemvite-plugin-msw-serverlabelDisplayedRowsandplaceholderare props, so a consumer wanting the old text can pass it.Two things worth reviewing rather than skimming
21 string literals were re-quoted. A curly apostrophe inside a single-quoted string becomes a straight quote that ends the string -
it('the run's own result'does not parse. Those literals now use double quotes. It is also why--fixwrites prose and never code.Two test files build their fixtures from code points.
normalizeTypography.test.tsandClaudePanel.test.tsxassert on these characters; sweeping them would have rewritten both sides of each assertion and left the tests passing while proving nothing.Also in here
The editor writes model output into the document in plain typography, and its edit prompt asks for the same upfront. Only the model's own output goes through it - text restored after a cancelled or failed run comes back byte for byte.
Verification
pnpm test- 4,328 tests across every workspacepnpm lint,pnpm typecheck,pnpm format:check- cleanpnpm check:typography- 1,605 files clean, 23 binaries skipped