Skip to content

feat: add format command#2667

Merged
davydkov merged 10 commits intolikec4:mainfrom
m9810223:feat/cli-format-command
Mar 6, 2026
Merged

feat: add format command#2667
davydkov merged 10 commits intolikec4:mainfrom
m9810223:feat/cli-format-command

Conversation

@m9810223
Copy link
Copy Markdown
Contributor

@m9810223 m9810223 commented Feb 22, 2026

Summary

Add a likec4 format (alias likec4 fmt) CLI command that formats .c4 source files in place, with a --check mode for CI pipelines.

The feature is implemented across three layers:

  • @likec4/language-serverformat() method on LikeC4LanguageServices interface, batch-formats documents via the existing LikeC4Formatter and returns Map<string, string> (URI → formatted text)
  • @likec4/language-servicesformat() method on the LikeC4 facade, translates project name strings to ProjectId and delegates
  • likec4format CLI command wired into yargs

Usage

# Format all files in current workspace
likec4 format

# Alias
likec4 fmt

# Format a specific workspace directory
likec4 format ./my-project

# Format only specific project(s) in a multi-project workspace
likec4 format --project alpha --project beta

# Format specific files
likec4 format --files src/model.c4 --files src/views.c4

# Check mode (CI-friendly, exits with code 1 if any file needs formatting)
likec4 format --check

Changes

packages/language-server

  • Add format(options?: FormatOptions) to LikeC4LanguageServices interface and DefaultLikeC4LanguageServices implementation
  • Add FormatOptions interface with projectIds, documentUris, and LSP formatting options (tabSize, insertSpaces, etc.)
  • Export FormatOptions type from common-exports.ts
  • Add format.spec.ts — unit tests covering multi-document formatting, documentUris/projectIds filtering, union semantics, formatting options (tabSize, insertSpaces), idempotency, and unknown URI handling

packages/language-services

  • Add format(options?: LikeC4FormatOptions) to LikeC4 facade
  • Add LikeC4FormatOptions interface (uses project name strings instead of ProjectId)

packages/likec4

  • Add format CLI command (packages/likec4/src/cli/format/index.ts)
  • Wire into CLI pipeline in packages/likec4/src/cli/index.ts

Design Notes

  • Documents are formatted sequentially because LikeC4Formatter (Langium's AbstractFormatter) stores mutable state per call — concurrent invocations would corrupt each other's state.
  • Document selection uses union semantics: projectIdsdocumentUris; omit both to format all documents.
  • The CLI reads original files from disk to compare with formatted output, only writing files that actually changed.

Testing

  • 306-line test suite (format.spec.ts) covering:
    • Multi-document formatting (all docs, filtered by URI, filtered by project)
    • Union of projectIds + documentUris
    • Unknown URI handling (graceful skip)
    • Formatting options (tabSize, insertSpaces)
    • Idempotency (formatting already-formatted content produces identical output)

command:

unbuffer pnpm --filter likec4 cli format --check | sed "s|$(pwd)/|<repo-root>/|g"
image image image

Checklist

  • I've thoroughly read the latest contribution guidelines.
  • I've rebased my branch onto main before creating this PR.
  • My commit messages follow conventional spec
  • I've added tests to cover my changes (if applicable).
  • I've verified that all new and existing tests have passed locally for mobile, tablet, and desktop screen sizes.
  • My change requires documentation updates.
  • I've updated the documentation accordingly.

Summary by CodeRabbit

  • New Features
    • Added a formatting API that returns formatted content per document with project/file selection and editor preferences (indentation, trimming, final newline).
    • Added a CLI command (format / fmt) to run formatting with project/file filters and a CI-friendly --check mode; reports missing targets and applies or reports changes.
  • Tests
    • Added comprehensive tests covering multi-project/file selection, idempotence, URI handling, and formatting option variations.
  • Documentation
    • Added CLI usage and examples for the new format command.

- Add format/check CLI command (likec4 format, likec4 fmt)
- Add FormatOptions and format() to LikeC4LanguageServices
- Add LikeC4FormatOptions and format() to LikeC4 facade
- Extract collectDocumentsToFormat with clear project/document filtering
- Add --verbose debug logging (workspace, projects, files, unchanged)
- Display paths relative to cwd (absolute when outside cwd)
@changeset-bot
Copy link
Copy Markdown

changeset-bot bot commented Feb 22, 2026

🦋 Changeset detected

Latest commit: dbd9efb

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 19 packages
Name Type
@likec4/language-server Minor
@likec4/language-services Minor
likec4 Minor
@likec4/playground Minor
@likec4/mcp Minor
@likec4/vite-plugin Minor
likec4-vscode Minor
@likec4/docs-astro Minor
@likec4/style-preset Minor
@likec4/styles Minor
@likec4/config Minor
@likec4/core Minor
@likec4/diagram Minor
@likec4/generators Minor
@likec4/layouts Minor
@likec4/log Minor
@likec4/react Minor
@likec4/tsconfig Minor
@likec4/vscode-preview Minor

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@m9810223 m9810223 marked this pull request as ready for review February 22, 2026 19:02
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai bot commented Feb 22, 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
📝 Walkthrough

Walkthrough

Adds a multi-document formatting feature: a public format API on the language service returning Map<URI, formatted>, a LikeC4.format facade accepting project names/URIs and editor options, tests, and a CLI format/fmt command that applies or checks formatting on disk.

Changes

Cohort / File(s) Summary
Core Language Service API
packages/language-server/src/LikeC4LanguageServices.ts
Adds FormatOptions and format(options?) to LikeC4LanguageServices; implements document collection/deduplication, sequential formatting, a formatting-options builder, and returns Map<string,string>.
Format Tests
packages/language-server/src/__tests__/format.spec.ts
Adds comprehensive tests for the new formatting API: whole-run formatting, project/document filters, idempotence, result keys, and editor option behaviors (tabSize, insertSpaces).
Public Type Exports
packages/language-server/src/common-exports.ts
Re-exports FormatOptions alongside LikeC4LanguageServices, expanding the public types.
High-Level Facade
packages/language-services/src/common/LikeC4.ts
Adds LikeC4.format() and LikeC4FormatOptions to accept project names or document URIs, resolve project IDs, and delegate to language service format.
CLI Command Implementation
packages/likec4/src/cli/format/index.ts
New CLI format/fmt command: loads workspace services, calls formatting, compares results to disk, supports --check mode, writes changes, reports missing targets and I/O errors.
CLI Integration
packages/likec4/src/cli/index.ts
Registers the new format CLI command in the main CLI pipeline.
Docs & Release
apps/docs/src/content/docs/tooling/cli.mdx, .changeset/add-cli-format-command.md
Adds CLI usage/docs for format (including check mode) and a changeset that bumps package versions and documents the new APIs/CLI.

Sequence Diagram

sequenceDiagram
    participant CLI as CLI Command
    participant Facade as LikeC4 Facade
    participant LangServices as Language Services
    participant Formatter as Langium Formatter
    participant FS as File System

    CLI->>Facade: format(options)
    Facade->>Facade: resolve project names -> projectIds
    Facade->>LangServices: format(FormatOptions)
    LangServices->>LangServices: collect & dedupe documents
    loop per document
        LangServices->>Formatter: format document (FormattingOptions)
        Formatter-->>LangServices: formatted text
    end
    LangServices-->>Facade: Map<URI, formatted>
    Facade-->>CLI: results
    loop per result
        CLI->>FS: read original file
        FS-->>CLI: original content
        alt content differs
            CLI->>FS: write formatted content
            FS-->>CLI: write result
        else unchanged
            CLI-->>CLI: skip write
        end
    end
    CLI-->>CLI: report summary / exit code
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • davydkov

Poem

🐇 I hopped through files with tidy care,
Collected docs, deduped everywhere.
Tabs or spaces, every line aligned,
CLI checked, then wrote—no mess left behind.
Hop—formatted, neat, and ready to share.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 50.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title 'feat: add format command' clearly and concisely summarizes the main change—adding a new format CLI command—and follows conventional commit conventions.
Description check ✅ Passed The PR description is comprehensive and well-structured, covering summary, usage examples, changes across three packages, design notes, testing, and a completed checklist. Most required sections from the template are addressed.

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

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

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

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

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (3)
packages/likec4/src/cli/format/index.ts (2)

71-74: Inconsistent guard between projects and documentUris.

Line 72 checks projects?.length (falsy for empty arrays), but Line 73 checks documentUris && (truthy for empty arrays). If --files is passed with no values, documentUris could be [], which gets passed through and changes the semantics in collectDocumentsToFormat — though it happens to work correctly since empty arrays are treated like undefined in the current logic. Aligning the guards would be cleaner:

♻️ Proposed fix
       const formatted = await languageServices.format({
         ...(projects?.length && { projects }),
-        ...(documentUris && { documentUris }),
+        ...(documentUris?.length && { documentUris }),
       })
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/likec4/src/cli/format/index.ts` around lines 71 - 74, The guards for
optional args are inconsistent: change the documentUris spread guard to mirror
projects by checking documentUris?.length so empty arrays aren’t passed through;
update the call to languageServices.format to use ...(documentUris?.length && {
documentUris }) so both projects and documentUris only get included when
non-empty, ensuring collectDocumentsToFormat receives the same semantics.

92-128: Disk read for comparison is correct but has a subtle TOCTOU window.

The handler reads the original file from disk to compare against the in-memory formatted output. In a CLI batch-formatting context this is fine, but if the file was modified between workspace load and readFile, the comparison could be stale. This is unlikely in practice for a CLI tool but worth being aware of for future consideration (e.g., file-watcher integration).

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/likec4/src/cli/format/index.ts` around lines 92 - 128, The current
loop that reads disk (readFile) to compare against the in-memory formattedText
has a TOCTOU window; fix it by validating the file wasn’t changed between the
initial read and the write: after obtaining fsPath (fileURLToPath) and before
writing, stat the file (fs.stat) to capture a timestamp/size, then after
readFile and before writeFile re-stat and compare mtime/size (or an inode/size
tuple); if they differ, treat the file as changed (increment failedFiles or log
and skip) instead of blindly writing formattedText; update the code paths around
formatted, readFile, writeFile, needsFormatting and checkOnly to perform this
re-stat check and handle the fallback behavior (log skip or retry) when the file
changed.
packages/language-server/src/__tests__/format.spec.ts (1)

64-75: Inline snapshot is fragile to leading/trailing whitespace in test sources.

The test input has leading newlines and trailing whitespace baked into the template literal. Because the formatter doesn't strip leading content outside of specification/model blocks, the snapshot captures that surrounding whitespace. If the formatter behavior changes around document boundaries, this will break. This is acceptable for now but worth noting.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/language-server/src/__tests__/format.spec.ts` around lines 64 - 75,
The inline snapshot is fragile due to leading/trailing whitespace in the test
input; update the assertion to normalize the formatter output before
snapshotting by referencing the generated value (result.values().next().value /
formatted) and calling a trim-normalization (e.g. use formatted.trim() or a
small normalizeWhitespace(formatted) helper) and then call
expect(...).toMatchInlineSnapshot(...) so surrounding newlines/space don't break
the snapshot if formatter document-boundary behavior changes.
🤖 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/language-server/src/__tests__/format.spec.ts`:
- Around line 104-116: The test fails if langiumDocuments.getDocument throws for
unknown URIs; update collectDocumentsToFormat to defensively handle that by
calling langiumDocuments.getDocument inside a try/catch (or using a safe
existence check) and treating thrown errors as a missing document (skip it), so
format (languageServices.format) receives no document for unknown URIs and
returns an empty result; reference the collectDocumentsToFormat function and
langiumDocuments.getDocument call and ensure any thrown error is
swallowed/logged and the URI is skipped.

---

Nitpick comments:
In `@packages/language-server/src/__tests__/format.spec.ts`:
- Around line 64-75: The inline snapshot is fragile due to leading/trailing
whitespace in the test input; update the assertion to normalize the formatter
output before snapshotting by referencing the generated value
(result.values().next().value / formatted) and calling a trim-normalization
(e.g. use formatted.trim() or a small normalizeWhitespace(formatted) helper) and
then call expect(...).toMatchInlineSnapshot(...) so surrounding newlines/space
don't break the snapshot if formatter document-boundary behavior changes.

In `@packages/likec4/src/cli/format/index.ts`:
- Around line 71-74: The guards for optional args are inconsistent: change the
documentUris spread guard to mirror projects by checking documentUris?.length so
empty arrays aren’t passed through; update the call to languageServices.format
to use ...(documentUris?.length && { documentUris }) so both projects and
documentUris only get included when non-empty, ensuring collectDocumentsToFormat
receives the same semantics.
- Around line 92-128: The current loop that reads disk (readFile) to compare
against the in-memory formattedText has a TOCTOU window; fix it by validating
the file wasn’t changed between the initial read and the write: after obtaining
fsPath (fileURLToPath) and before writing, stat the file (fs.stat) to capture a
timestamp/size, then after readFile and before writeFile re-stat and compare
mtime/size (or an inode/size tuple); if they differ, treat the file as changed
(increment failedFiles or log and skip) instead of blindly writing
formattedText; update the code paths around formatted, readFile, writeFile,
needsFormatting and checkOnly to perform this re-stat check and handle the
fallback behavior (log skip or retry) when the file changed.

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
packages/language-server/src/LikeC4LanguageServices.ts (1)

357-367: Consider per-document error handling to prevent one bad document from aborting the entire batch.

If formatter.formatDocument throws for a single document (e.g., due to a parse error), the whole format() call fails and all successfully formatted results in the Map are lost. Wrapping the inner loop body in a try/catch with a warning log and falling back to the original text would make this more resilient, especially when invoked from the CLI on large workspaces.

♻️ Suggested resilient loop
     for (const doc of documents) {
       const docUri = doc.uri.toString()
-      const edits = await formatter.formatDocument(doc, {
-        options: fmtOptions,
-        textDocument: { uri: docUri },
-      })
-      const text = edits.length === 0
-        ? doc.textDocument.getText()
-        : TextDocument.applyEdits(doc.textDocument, edits)
-      result.set(docUri, text)
+      try {
+        const edits = await formatter.formatDocument(doc, {
+          options: fmtOptions,
+          textDocument: { uri: docUri },
+        })
+        const text = edits.length === 0
+          ? doc.textDocument.getText()
+          : TextDocument.applyEdits(doc.textDocument, edits)
+        result.set(docUri, text)
+      } catch (e) {
+        logger.warn(`format: failed to format ${docUri}, keeping original`, loggable(e))
+        result.set(docUri, doc.textDocument.getText())
+      }
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/language-server/src/LikeC4LanguageServices.ts` around lines 357 -
367, The loop over documents should catch per-document formatting errors so one
bad file doesn't abort the whole batch: wrap the body that calls
formatter.formatDocument(...) and applies edits (the code that computes edits,
text via TextDocument.applyEdits, and result.set(docUri, text)) in a try/catch;
on error log a warning including docUri and the error, then set
result.set(docUri, doc.textDocument.getText()) to preserve the original content
and continue to the next document, ensuring previously formatted entries in
result remain intact; reference the existing variables/functions
formatter.formatDocument, fmtOptions, TextDocument.applyEdits, doc.textDocument,
and result.set when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@packages/language-server/src/LikeC4LanguageServices.ts`:
- Around line 357-367: The loop over documents should catch per-document
formatting errors so one bad file doesn't abort the whole batch: wrap the body
that calls formatter.formatDocument(...) and applies edits (the code that
computes edits, text via TextDocument.applyEdits, and result.set(docUri, text))
in a try/catch; on error log a warning including docUri and the error, then set
result.set(docUri, doc.textDocument.getText()) to preserve the original content
and continue to the next document, ensuring previously formatted entries in
result remain intact; reference the existing variables/functions
formatter.formatDocument, fmtOptions, TextDocument.applyEdits, doc.textDocument,
and result.set when making the change.

Copy link
Copy Markdown
Contributor

@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

🧹 Nitpick comments (2)
packages/likec4/src/cli/format/index.ts (2)

108-115: Inconsistent error serialisation inside the loop

Read/write failures (lines 112, 131) interpolate e directly in a template literal — Error.prototype.toString() adds the redundant "Error: " prefix, producing e.g. "Failed to read …: Error: ENOENT …". The outer catch blocks (lines 48, 78) already use the correct pattern e instanceof Error ? e.message : String(e). Align the inner catches for consistent log output.

♻️ Proposed fix
-          logger.error(`Failed to read ${relPath}: ${e}`)
+          logger.error(`Failed to read ${relPath}: ${e instanceof Error ? e.message : String(e)}`)
-              logger.error(`Failed to write ${relPath}: ${e}`)
+              logger.error(`Failed to write ${relPath}: ${e instanceof Error ? e.message : String(e)}`)

Also applies to: 127-133

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/likec4/src/cli/format/index.ts` around lines 108 - 115, The catch
blocks inside the formatting loop use template interpolation `${e}` which yields
"Error: ..." inconsistently; update the read and write error logging (the
logger.error calls that reference relPath and the exception variable e in the
block handling readFile and the block handling writeFile/failedFiles) to
serialize the error like the outer handlers do (use e instanceof Error ?
e.message : String(e)) so logs match the outer catch formatting and keep
failedFiles/continue behavior unchanged.

26-32: normalize: true is redundant alongside the coerce that calls resolve()

In yargs, normalize runs before coerce. Since resolve(f) already produces a normalized, absolute path, the preceding path.normalize pass from normalize: true is a no-op. Safe to remove to keep the option descriptor lean.

♻️ Proposed change
         files: {
           type: 'string',
           array: true,
-          normalize: true,
           coerce: (files: string[]) => files.map(f => resolve(f)),
           desc: 'specific file(s) to format (repeatable)',
         },
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/likec4/src/cli/format/index.ts` around lines 26 - 32, The option
descriptor for the CLI "files" option includes redundant normalize: true because
yargs runs normalize before the coerce which calls resolve(f); remove the
normalize property from the "files" option so the coerce (files: string[] =>
files.map(f => resolve(f))) is the sole normalization step, leaving the
descriptor leaner and functionally unchanged.
🤖 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/likec4/src/cli/format/index.ts`:
- Around line 138-154: When failedFiles > 0 the current handler returns before
emitting the --check summary; update the failing branch to still emit the
check-mode summary when checkOnly is true and needsFormatting/changedFiles are
populated. Specifically, in the block that inspects failedFiles, log the
existing failure message as now, but if checkOnly is true then also log the
formatted summary using needsFormatting, changedFiles and formatted.size (and
set process.exitCode = 1 as needed) before returning so users see which files
need formatting in partial runs; keep using logger, failedFiles, checkOnly,
needsFormatting, changedFiles and formatted to locate and implement the change.

---

Nitpick comments:
In `@packages/likec4/src/cli/format/index.ts`:
- Around line 108-115: The catch blocks inside the formatting loop use template
interpolation `${e}` which yields "Error: ..." inconsistently; update the read
and write error logging (the logger.error calls that reference relPath and the
exception variable e in the block handling readFile and the block handling
writeFile/failedFiles) to serialize the error like the outer handlers do (use e
instanceof Error ? e.message : String(e)) so logs match the outer catch
formatting and keep failedFiles/continue behavior unchanged.
- Around line 26-32: The option descriptor for the CLI "files" option includes
redundant normalize: true because yargs runs normalize before the coerce which
calls resolve(f); remove the normalize property from the "files" option so the
coerce (files: string[] => files.map(f => resolve(f))) is the sole normalization
step, leaving the descriptor leaner and functionally unchanged.

Comment on lines +138 to +154
if (failedFiles > 0) {
logger.error(`${failedFiles} file(s) failed to process`)
process.exitCode = 1
return
}

if (checkOnly) {
if (changedFiles > 0) {
logger.error(
`${changedFiles} of ${formatted.size} file(s) need formatting:\n${
needsFormatting.map(f => ` ${f}`).join('\n')
}`,
)
process.exitCode = 1
return
}
logger.info(k.green(`All ${formatted.size} file(s) are formatted`))
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor

--check result silently suppressed when reads fail

When failedFiles > 0, the handler exits at line 141 before reaching the check-mode summary (lines 144–153). By that point needsFormatting is already populated, so the information about which files need formatting exists — it's just never logged. Users see only "X file(s) failed to process" and get no hint about the formatting state of the other files.

Consider reporting the partial check result alongside the failure:

🛡️ Proposed improvement
         if (failedFiles > 0) {
           logger.error(`${failedFiles} file(s) failed to process`)
+          if (checkOnly && needsFormatting.length > 0) {
+            logger.error(
+              `${needsFormatting.length} file(s) also need formatting:\n${needsFormatting.map(f => `  ${f}`).join('\n')}`,
+            )
+          }
           process.exitCode = 1
           return
         }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (failedFiles > 0) {
logger.error(`${failedFiles} file(s) failed to process`)
process.exitCode = 1
return
}
if (checkOnly) {
if (changedFiles > 0) {
logger.error(
`${changedFiles} of ${formatted.size} file(s) need formatting:\n${
needsFormatting.map(f => ` ${f}`).join('\n')
}`,
)
process.exitCode = 1
return
}
logger.info(k.green(`All ${formatted.size} file(s) are formatted`))
if (failedFiles > 0) {
logger.error(`${failedFiles} file(s) failed to process`)
if (checkOnly && needsFormatting.length > 0) {
logger.error(
`${needsFormatting.length} file(s) also need formatting:\n${needsFormatting.map(f => ` ${f}`).join('\n')}`,
)
}
process.exitCode = 1
return
}
if (checkOnly) {
if (changedFiles > 0) {
logger.error(
`${changedFiles} of ${formatted.size} file(s) need formatting:\n${
needsFormatting.map(f => ` ${f}`).join('\n')
}`,
)
process.exitCode = 1
return
}
logger.info(k.green(`All ${formatted.size} file(s) are formatted`))
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/likec4/src/cli/format/index.ts` around lines 138 - 154, When
failedFiles > 0 the current handler returns before emitting the --check summary;
update the failing branch to still emit the check-mode summary when checkOnly is
true and needsFormatting/changedFiles are populated. Specifically, in the block
that inspects failedFiles, log the existing failure message as now, but if
checkOnly is true then also log the formatted summary using needsFormatting,
changedFiles and formatted.size (and set process.exitCode = 1 as needed) before
returning so users see which files need formatting in partial runs; keep using
logger, failedFiles, checkOnly, needsFormatting, changedFiles and formatted to
locate and implement the change.

@m9810223 m9810223 changed the title Feat/cli format command feat: add format command Feb 23, 2026
@m9810223
Copy link
Copy Markdown
Contributor Author

@davydkov Could you please review this?

Copy link
Copy Markdown
Member

@davydkov davydkov left a comment

Choose a reason for hiding this comment

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

Hey @m9810223

Thanks for contribution, good one!
Can you fix the merge conflict and add changeset?

@davydkov
Copy link
Copy Markdown
Member

davydkov commented Mar 4, 2026

Could you also mention new command in docs, just usage examples from PR description would be enough

@github-actions github-actions bot temporarily deployed to docs-preview March 4, 2026 10:16 Destroyed
@github-actions
Copy link
Copy Markdown
Contributor

github-actions bot commented Mar 4, 2026

Copy link
Copy Markdown
Contributor

@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.

🧹 Nitpick comments (1)
apps/docs/src/content/docs/tooling/cli.mdx (1)

273-278: Consider documenting the -p alias and LIKEC4_WORKSPACE env variable.

The options table has minor gaps compared to the actual CLI implementation:

  1. The --project option has an alias -p that isn't documented
  2. The path description omits the LIKEC4_WORKSPACE environment variable fallback
📝 Suggested improvements
 | Option              | Description                                                     |
 | ------------------- | --------------------------------------------------------------- |
-| `path`              | Path to workspace (default: current directory)                  |
-| `--project`         | Format only specific project(s) by name (repeatable)            |
+| `path`              | Path to workspace (default: current directory or `LIKEC4_WORKSPACE` env) |
+| `--project, -p`     | Format only specific project(s) by name (repeatable)            |
 | `--files`           | Format only specific files (repeatable)                         |
 | `--check`           | Check if files are formatted without writing changes            |
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@apps/docs/src/content/docs/tooling/cli.mdx` around lines 273 - 278, Update
the CLI options table so it matches the actual implementation: add the `-p`
alias to the `--project` row (e.g., show `--project / -p`) and update the `path`
description to mention the `LIKEC4_WORKSPACE` environment variable fallback
(e.g., "Path to workspace (default: current directory; falls back to
LIKEC4_WORKSPACE)"). Ensure the displayed option names match the CLI flags
`--project`/`-p` and the `path` entry references `LIKEC4_WORKSPACE`.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@apps/docs/src/content/docs/tooling/cli.mdx`:
- Around line 273-278: Update the CLI options table so it matches the actual
implementation: add the `-p` alias to the `--project` row (e.g., show `--project
/ -p`) and update the `path` description to mention the `LIKEC4_WORKSPACE`
environment variable fallback (e.g., "Path to workspace (default: current
directory; falls back to LIKEC4_WORKSPACE)"). Ensure the displayed option names
match the CLI flags `--project`/`-p` and the `path` entry references
`LIKEC4_WORKSPACE`.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5b1afff0-4f70-4740-849c-1c1a8ae79219

📥 Commits

Reviewing files that changed from the base of the PR and between 58a54e7 and b2a8667.

📒 Files selected for processing (1)
  • apps/docs/src/content/docs/tooling/cli.mdx

@m9810223 m9810223 requested a review from davydkov March 5, 2026 07:49
@m9810223
Copy link
Copy Markdown
Contributor Author

m9810223 commented Mar 5, 2026

@davydkov All requested changes are done — merge conflict resolved, changeset added, and CLI docs updated.

Ready for re-review when you have a chance. Thanks!

@davydkov davydkov merged commit 2c6a43d into likec4:main Mar 6, 2026
13 checks passed
@likec4-ci likec4-ci bot mentioned this pull request Mar 6, 2026
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.

2 participants