Skip to content

Add fontaine CLI entrypoint#757

Open
AgentGoose32 wants to merge 5 commits into
unjs:mainfrom
AgentGoose32:polar-17-cli-usage
Open

Add fontaine CLI entrypoint#757
AgentGoose32 wants to merge 5 commits into
unjs:mainfrom
AgentGoose32:polar-17-cli-usage

Conversation

@AgentGoose32
Copy link
Copy Markdown

@AgentGoose32 AgentGoose32 commented Apr 28, 2026

Summary

Adds a first CLI entrypoint for fontaine so the package can be used directly against a CSS file without wiring up Vite/Webpack/Rollup.

Changes:

  • adds src/cli.ts with fontaine <input.css> [output.css]
  • exposes the executable through package.json bin
  • includes the CLI entry in tsdown so dist/cli.mjs is built with a shebang and execute bit
  • exports transformCssFile() for programmatic usage
  • documents the CLI usage in the README

Testing

  • pnpm --filter fontaine build
  • node packages/fontaine/dist/cli.mjs --help
  • pnpm --filter fontaine test:types
  • git diff --check

Note: pnpm --filter fontaine test:unit currently fails locally due 12 pre-existing inline snapshot mismatches unrelated to this CLI entrypoint. The CLI build/typecheck/help-path validation above passes.

Fixes #17

Summary by CodeRabbit

  • New Features

    • Added a command-line interface so users can run the tool directly (via npx or installed) to transform CSS files.
    • CLI prints a confirmation like "Generated " and defaults output to .fontaine.css if none is specified.
  • Documentation

    • Added CLI usage docs with examples and workflow for running the tool from the command line.

@AgentGoose32 AgentGoose32 requested a review from danielroe as a code owner April 28, 2026 18:34
@netlify
Copy link
Copy Markdown

netlify Bot commented Apr 28, 2026

Deploy Preview for fontless ready!

Name Link
🔨 Latest commit a1f5d7b
🔍 Latest deploy log https://app.netlify.com/projects/fontless/deploys/69f1fc0c9b830f000828b325
😎 Deploy Preview https://deploy-preview-757--fontless.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Apr 28, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 78795125-135a-4d64-9792-16eb6f763b3e

📥 Commits

Reviewing files that changed from the base of the PR and between 953106f and a1f5d7b.

📒 Files selected for processing (1)
  • packages/fontaine/src/cli.ts

📝 Walkthrough

Walkthrough

Adds a Node ESM CLI and programmatic entrypoint: transformCssFile and FontaineCliOptions are exported; a fontaine executable is registered. The CLI reads an input CSS file, runs the Fontaine transform, and writes output to a provided path or <input>.fontaine.css.

Changes

Cohort / File(s) Summary
CLI implementation
packages/fontaine/src/cli.ts
New CLI module and programmatic function: parses args, validates input, reads CSS, constructs/normalizes the Fontaine transform plugin (including resolvePath/fallbacks), invokes transform.handler, determines output path, ensures parent dirs, writes output, and exports transformCssFile and FontaineCliOptions.
Package manifest
packages/fontaine/package.json
Adds bin.fontaine./dist/cli.mjs to register the CLI executable.
Public API
packages/fontaine/src/index.ts
Re-exports transformCssFile and FontaineCliOptions from ./cli.
Docs / Build config
packages/fontaine/README.md, packages/fontaine/tsdown.config.ts
Documents usage (npx fontaine <input> [output]) and adds src/cli.ts to tsdown entries so the CLI is included in build/docs outputs.

Sequence Diagram

sequenceDiagram
    participant User as User/CLI
    participant CLI as packages/fontaine/src/cli.ts
    participant FS as File System
    participant Transform as FontaineTransform
    participant Output as Output File

    User->>CLI: Run `fontaine input.css [output.css]`
    CLI->>CLI: Parse args, validate input
    CLI->>FS: Read input CSS file
    FS-->>CLI: Return CSS content
    CLI->>Transform: Create/normalize plugin (resolvePath / fallbacks)
    CLI->>Transform: Invoke transform.handler(source, inputPath)
    Transform-->>CLI: Return transformed result
    CLI->>CLI: Choose output path (explicit or .fontaine.css)
    CLI->>FS: Ensure parent directories exist
    CLI->>Output: Write transformed CSS (or original if fallback)
    Output-->>CLI: Confirm written
    CLI->>User: Print generated filename
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐇 I hopped through styles with eager paws,
Read input rules and chased their flaws,
I called the transform, stitched each line,
Wrote a new file — crisp and fine,
Hooray: fontaine's CLI unfurls its laws.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly summarizes the main change: adding a CLI entrypoint to the fontaine package, matching the primary objective.
Linked Issues check ✅ Passed The PR successfully addresses issue #17 by implementing both a CLI entrypoint (fontaine [output]) and programmatic API (transformCssFile function) as requested.
Out of Scope Changes check ✅ Passed All changes are directly related to implementing the CLI entrypoint and programmatic API: CLI implementation, bin configuration, exports, build config, and documentation.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share
Review rate limit: 6/8 reviews remaining, refill in 9 minutes and 55 seconds.

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (1)
packages/fontaine/src/cli.ts (1)

1-5: Use top-level type-only import for consistency.

Per the ESLint import/consistent-type-specifier-style rule, prefer a separate type import.

🔧 Proposed fix
 #!/usr/bin/env node
 import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'node:fs'
 import { basename, dirname, resolve } from 'node:path'
 import { pathToFileURL } from 'node:url'
-import { FontaineTransform, type FontaineTransformOptions } from './transform'
+import type { FontaineTransformOptions } from './transform'
+import { FontaineTransform } from './transform'
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/fontaine/src/cli.ts` around lines 1 - 5, The import line mixes a
value and a type; change it to use a top-level type-only import for
FontaineTransformOptions by separating the imports from './transform' so that
FontaineTransform is imported as a value and FontaineTransformOptions is
imported with the type-only specifier (reference symbols: FontaineTransform,
FontaineTransformOptions, import from './transform').
🤖 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/fontaine/src/cli.ts`:
- Line 27: The outputPath computation can accidentally equal inputPath when the
input extension isn't exactly ".css" (case-sensitive), causing overwrites;
update the logic that sets outputPath (currently using output ? resolve(output)
: inputPath.replace(/\.css$/, '.fontaine.css')) to instead build the output
filename in a case-insensitive and extension-agnostic way—use Node's path
utilities (e.g., path.parse/path.format or path.extname) to replace the input
file's extension with ".fontaine.css" when output is not provided, or apply a
case-insensitive regex like /\.[^.]+$/i to strip the extension before appending
".fontaine.css", keeping resolve(output) behavior when output is provided.

In `@packages/fontaine/src/index.ts`:
- Around line 6-7: Move the exports from './cli' (export { transformCssFile }
and export type { FontaineCliOptions }) so they appear before the './metrics'
exports in the index export list to satisfy the perfectionist/sort-exports
ESLint rule; locate the export statements for transformCssFile and
FontaineCliOptions and reorder them to be placed above any exports coming from
'./metrics'.

---

Nitpick comments:
In `@packages/fontaine/src/cli.ts`:
- Around line 1-5: The import line mixes a value and a type; change it to use a
top-level type-only import for FontaineTransformOptions by separating the
imports from './transform' so that FontaineTransform is imported as a value and
FontaineTransformOptions is imported with the type-only specifier (reference
symbols: FontaineTransform, FontaineTransformOptions, import from
'./transform').
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 71445b53-7d0e-4120-bc76-e2c556cad245

📥 Commits

Reviewing files that changed from the base of the PR and between 385bb7b and 4e8d6e3.

📒 Files selected for processing (5)
  • packages/fontaine/README.md
  • packages/fontaine/package.json
  • packages/fontaine/src/cli.ts
  • packages/fontaine/src/index.ts
  • packages/fontaine/tsdown.config.ts

Comment thread packages/fontaine/src/cli.ts Outdated
Comment thread packages/fontaine/src/index.ts Outdated
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
packages/fontaine/src/cli.ts (1)

35-38: ⚠️ Potential issue | 🟠 Major

Prevent accidental source-file overwrite when deriving default output path.

At Line 35, the fallback path replacement only matches lowercase .css. For inputs like styles.CSS (or non-.css files), outputPath can equal inputPath, and Line 38 will overwrite the original file.

🐛 Proposed fix
-  const outputPath = output ? resolve(output) : inputPath.replace(/\.css$/, '.fontaine.css')
+  const outputPath = output
+    ? resolve(output)
+    : inputPath.replace(/\.[^.]+$/i, '.fontaine.css')
+
+  if (!output && outputPath === inputPath) {
+    throw new Error(`Cannot determine output path for "${input}". Please specify an output path.`)
+  }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/fontaine/src/cli.ts` around lines 35 - 38, The current fallback that
computes outputPath from inputPath only replaces lowercase ".css", which can
leave outputPath equal to inputPath for inputs like "styles.CSS" and cause
writeFileSync to overwrite the source; update the logic that derives outputPath
(the code computing outputPath from inputPath) to perform a case-insensitive
extension replacement (e.g., use a case-insensitive regex like /\.css$/i) or,
more robustly, use path.extname/path.basename to detect the extension and
produce a distinct filename (e.g., replace .css case-insensitively or append
".fontaine.css" when no .css extension), and add a safety check before calling
writeFileSync to ensure outputPath !== inputPath and fail or alter the name if
they are equal.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@packages/fontaine/src/cli.ts`:
- Around line 35-38: The current fallback that computes outputPath from
inputPath only replaces lowercase ".css", which can leave outputPath equal to
inputPath for inputs like "styles.CSS" and cause writeFileSync to overwrite the
source; update the logic that derives outputPath (the code computing outputPath
from inputPath) to perform a case-insensitive extension replacement (e.g., use a
case-insensitive regex like /\.css$/i) or, more robustly, use
path.extname/path.basename to detect the extension and produce a distinct
filename (e.g., replace .css case-insensitively or append ".fontaine.css" when
no .css extension), and add a safety check before calling writeFileSync to
ensure outputPath !== inputPath and fail or alter the name if they are equal.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 847cf8d5-0149-4c34-a9a0-329bd2e4b892

📥 Commits

Reviewing files that changed from the base of the PR and between 4e8d6e3 and 7edb9a6.

📒 Files selected for processing (1)
  • packages/fontaine/src/cli.ts

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🤖 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/fontaine/src/cli.ts`:
- Around line 35-36: The code assigns code using || which treats an empty-string
transform output as missing; update the assignment that sets code (the line
using transformed and source) to use nullish coalescing so only null/undefined
fall back to source—i.e., when calling transform.handler.call and inspecting the
resulting transformed value (variable transformed), keep empty string results
instead of replacing them with source by using ?? rather than ||.
- Around line 67-79: The CLI currently ignores extra positional args after the
expected two; update the argument handling in packages/fontaine/src/cli.ts to
fail fast when more than two positional arguments are present: after
destructuring const [input, output] = args, check if args.length > 2 and if so
print an error like "Unexpected positional arguments: <list>" (or similar), set
process.exitCode = 1 and return; keep the existing checks for missing input and
missing file (existsSync) unchanged—use the existing args/input/output
identifiers to locate where to insert this validation.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 4a445b83-3e68-400a-b4a7-f98a31eb5974

📥 Commits

Reviewing files that changed from the base of the PR and between 7edb9a6 and 26756dc.

📒 Files selected for processing (2)
  • packages/fontaine/src/cli.ts
  • packages/fontaine/src/index.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/fontaine/src/index.ts

Comment thread packages/fontaine/src/cli.ts Outdated
Comment thread packages/fontaine/src/cli.ts
@AgentGoose32
Copy link
Copy Markdown
Author

Fixed the latest CodeRabbit findings in 953106f:

  • transform result now uses nullish coalescing, so intentionally empty generated output is preserved and only null/undefined falls back to source
  • CLI now fails fast when more than two positional args are provided

Validation:

  • pnpm --filter fontaine lint
  • pnpm --filter fontaine build
  • node packages/fontaine/dist/cli.mjs --help
  • extra-arg failure path check
  • git diff --check

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 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/fontaine/src/cli.ts`:
- Around line 25-28: The default fallbacks value is being overwritten by the
spread of options (so callers passing { fallbacks: undefined } nullify the CLI
default), so update the object passed to FontaineTransform.rollup to derive
fallbacks from options using a nullish-coalescing check (e.g. use
options.fallbacks ?? ['Arial'] or place fallbacks after the spread) and keep the
existing resolvePath logic; locate the call to FontaineTransform.rollup (the
plugin variable) and replace the current spread pattern with one that ensures
fallbacks defaults to ['Arial'] when options.fallbacks is null or undefined to
preserve behavior for transformCssFile().
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 5a4759db-3ab9-4ba7-a658-458a6fc1f286

📥 Commits

Reviewing files that changed from the base of the PR and between 26756dc and 953106f.

📒 Files selected for processing (1)
  • packages/fontaine/src/cli.ts

Comment thread packages/fontaine/src/cli.ts Outdated
@AgentGoose32
Copy link
Copy Markdown
Author

Fixed the latest CodeRabbit finding in a1f5d7b. fallbacks and resolvePath are now pulled out before spreading the remaining transform options, so fallbacks: undefined cannot accidentally clear the CLI/API default.

Validation:

  • pnpm --filter fontaine lint
  • pnpm --filter fontaine build
  • node packages/fontaine/dist/cli.mjs --help
  • git diff --check

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.

CLI/programmatic usage

1 participant