Skip to content

Implement beamtalk fmt CLI command (BT-978)#1020

Merged
jamesc merged 6 commits intomainfrom
worktree-BT-978
Mar 1, 2026
Merged

Implement beamtalk fmt CLI command (BT-978)#1020
jamesc merged 6 commits intomainfrom
worktree-BT-978

Conversation

@jamesc
Copy link
Owner

@jamesc jamesc commented Feb 28, 2026

Summary

Implements beamtalk fmt and beamtalk fmt-check as top-level CLI subcommands for formatting Beamtalk source files.

  • beamtalk fmt <path>... — parses .bt files, runs the AST unparser (from BT-977), and writes formatted output back in-place
  • beamtalk fmt-check <path>... — prints a unified diff for every file that would change and exits non-zero if any files need reformatting
  • Files with parse errors are skipped with a warning to prevent corruption
  • Both commands accept multiple paths (e.g., beamtalk fmt stdlib/ tests/)

Justfile targets

  • fmt-beamtalk / fmt-check-beamtalk — new targets following the established pattern
  • fmt / fmt-check aggregate targets updated to include Beamtalk formatting

Tests

5 unit tests covering:

  • Already-formatted file exits 0
  • Idempotency: fmt(fmt(source)) == fmt(source)
  • Line comment preservation through round-trip
  • Unformatted file exits non-zero
  • Error message mentions file count

Linear: https://linear.app/beamtalk/issue/BT-978

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features

    • CLI commands to format Beamtalk sources in-place and to check formatting (prints unified diffs).
    • Project recipes to format and verify Beamtalk sources.
  • Bug Fixes / Behavior

    • Formatter reports skipped files with parse errors, shows diffs for failing files, and exits non‑zero when checks fail.
    • Comment extraction now strips comment delimiters for consistent formatting.
  • Tests

    • Added idempotency and round-trip tests for the formatter.
  • Chores

    • Added a workspace dependency for text-diff utilities.

- Add `beamtalk fmt <path>...` to format .bt files in-place via the unparser
- Add `beamtalk fmt-check <path>...` to print unified diffs and exit non-zero
  for unformatted files
- Skip files with parse errors to prevent corruption
- Add `similar` crate for unified diff generation
- Add Justfile targets: fmt-beamtalk, fmt-check-beamtalk
- Update fmt/fmt-check aggregate targets to include Beamtalk formatting

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@coderabbitai
Copy link

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

Walkthrough

Adds workspace dependency similar = "2"; enables it in crates/beamtalk-cli/Cargo.toml; implements a beamtalk formatter (run_fmt) with CLI subcommands (Fmt, FmtCheck) and Justfile recipes; normalizes parser comment stripping; and adds unparse idempotency tests.

Changes

Cohort / File(s) Summary
Workspace manifest
Cargo.toml
Added workspace dependency similar = "2".
beamtalk-cli manifest
crates/beamtalk-cli/Cargo.toml
Marked the similar dependency to participate in the workspace (similar.workspace = true).
Build system / Tasks
Justfile
Added fmt-beamtalk and fmt-check-beamtalk recipes and wired them into top-level format targets.
Formatter implementation
crates/beamtalk-cli/src/commands/fmt.rs
New module providing pub fn run_fmt(paths: &[String], check_only: bool) -> Result<()>: resolves/deduplicates .bt paths, reads/parses/unparses sources, prints unified diffs in check mode, writes formatted files in write mode, skips parse-error files with warnings, and includes unit tests.
CLI integration
crates/beamtalk-cli/src/commands/mod.rs, crates/beamtalk-cli/src/main.rs
Exported fmt module and added Command::Fmt / Command::FmtCheck variants; dispatches to commands::fmt::run_fmt with appropriate check_only.
Parser comment handling
crates/beamtalk-core/src/source_analysis/parser/mod.rs
Strips language comment delimiters when collecting line and block comments so comment text excludes wrappers (//, /* */) for leading and trailing comments.
Unparse tests
crates/beamtalk-core/src/unparse/mod.rs
Added idempotency test helper and a suite of round-trip unparse/parse idempotency tests (tests only; no production logic changes).

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant CLI as beamtalk-cli
    participant FS as File System
    participant Parser as Parser/Unparser

    User->>CLI: beamtalk-cli fmt[ --check] [paths]
    CLI->>FS: collect .bt files from paths
    FS-->>CLI: file list

    loop for each file
        CLI->>FS: read file content
        FS-->>CLI: content
        CLI->>Parser: parse(content)
        Parser-->>CLI: AST or parse-error
        alt parsed
            CLI->>Parser: unparse(AST)
            Parser-->>CLI: formatted content
            CLI->>CLI: compare original vs formatted
            alt check mode & differs
                CLI->>User: print unified diff
            else write mode & differs
                CLI->>FS: write formatted content
                FS-->>CLI: write result
            end
        else parse-error
            CLI->>User: warn and mark skipped
        end
    end

    alt check mode with diffs or skipped files
        CLI->>User: exit non-zero
    else
        CLI->>User: exit zero
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely summarizes the main change: implementing the beamtalk fmt CLI command, with the ticket reference (BT-978) for traceability.
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
  • Post copyable unit tests in a comment
  • Commit unit tests in branch worktree-BT-978

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

Copy link

@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)
crates/beamtalk-cli/Cargo.toml (1)

59-61: Redundant tempfile dev-dependency.

tempfile = "3.14" is already declared as a regular dependency on line 51. The dev-dependency declaration is unnecessary since regular dependencies are available in tests.

🔧 Proposed fix
 [dev-dependencies]
 serial_test = "3"
-tempfile = "3.14"
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/beamtalk-cli/Cargo.toml` around lines 59 - 61, Remove the redundant
dev-dependency entry for tempfile by deleting the `tempfile = "3.14"` line from
the [dev-dependencies] section in Cargo.toml (the crate already lists tempfile
as a normal dependency earlier), leaving only `serial_test = "3"` under
[dev-dependencies].
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/beamtalk-cli/Cargo.toml`:
- Around line 59-61: Remove the redundant dev-dependency entry for tempfile by
deleting the `tempfile = "3.14"` line from the [dev-dependencies] section in
Cargo.toml (the crate already lists tempfile as a normal dependency earlier),
leaving only `serial_test = "3"` under [dev-dependencies].

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 213f695 and 02c97b6.

📒 Files selected for processing (6)
  • Cargo.toml
  • Justfile
  • crates/beamtalk-cli/Cargo.toml
  • crates/beamtalk-cli/src/commands/fmt.rs
  • crates/beamtalk-cli/src/commands/mod.rs
  • crates/beamtalk-cli/src/main.rs

Copilot AI review requested due to automatic review settings March 1, 2026 08:06
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds first-party Beamtalk source formatting support to the beamtalk CLI by introducing fmt (in-place) and fmt-check (diff + non-zero exit) commands, and wiring them into repo-wide formatting targets.

Changes:

  • Introduce beamtalk fmt / beamtalk fmt-check subcommands and dispatch them from the CLI.
  • Implement formatting + unified-diff checking via parse → unparse round-trip (skipping parse-error files).
  • Add similar for diff output, plus Justfile targets to include Beamtalk formatting in fmt / fmt-check.

Reviewed changes

Copilot reviewed 6 out of 6 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
crates/beamtalk-cli/src/main.rs Adds new CLI subcommands and routes them to the formatter implementation.
crates/beamtalk-cli/src/commands/mod.rs Exposes the new fmt command module.
crates/beamtalk-cli/src/commands/fmt.rs Implements format / format-check logic and adds unit tests for core behaviors.
crates/beamtalk-cli/Cargo.toml Adds dependency needed for unified diff output and updates dev deps.
Justfile Adds fmt targets for Beamtalk and includes them in aggregate fmt/fmt-check.
Cargo.toml Adds similar to workspace dependencies for shared versioning.

- Remove redundant tempfile dev-dependency (already in [dependencies])
- Use --bin beamtalk in Justfile fmt-beamtalk/fmt-check-beamtalk targets
  for consistency with all other Justfile targets
- Deduplicate source_files when overlapping paths are given, preventing
  duplicate diff output and incorrect changed-file counts
- Exit non-zero in fmt-check when files are skipped due to parse errors
  (previously could exit 0 while not verifying all files)
- Add 2 new tests: deduplication and parse-error behavior

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link

@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)
crates/beamtalk-cli/src/commands/fmt.rs (1)

37-61: Make file processing order deterministic in run_fmt.

fmt-check output order can vary across filesystems because collected paths are not sorted. Sorting once after collection makes diffs and summary behavior stable across environments.

♻️ Suggested change
     for path in paths {
         let source_path = Utf8PathBuf::from(path);
@@
         }
     }
 
+    source_files.sort_unstable_by(|a, b| a.as_str().cmp(b.as_str()));
+
     if source_files.is_empty() {
         miette::bail!("No .bt source files found");
     }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/beamtalk-cli/src/commands/fmt.rs` around lines 37 - 61, The collection
of source files in run_fmt is nondeterministic because paths (and files from
collect_source_files_from_dir) are pushed in iteration order; after the loop
that builds source_files (using variables paths, source_path, seen,
collect_source_files_from_dir), sort source_files once before the empty
check/return so subsequent fmt-check output is stable across filesystems—e.g.,
call a stable sort on Utf8PathBuf (by string representation) to make order
deterministic before using source_files.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/beamtalk-cli/src/commands/fmt.rs`:
- Around line 37-61: The collection of source files in run_fmt is
nondeterministic because paths (and files from collect_source_files_from_dir)
are pushed in iteration order; after the loop that builds source_files (using
variables paths, source_path, seen, collect_source_files_from_dir), sort
source_files once before the empty check/return so subsequent fmt-check output
is stable across filesystems—e.g., call a stable sort on Utf8PathBuf (by string
representation) to make order deterministic before using source_files.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 471ac31 and 853382b.

📒 Files selected for processing (3)
  • Justfile
  • crates/beamtalk-cli/Cargo.toml
  • crates/beamtalk-cli/src/commands/fmt.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • crates/beamtalk-cli/Cargo.toml

jamesc and others added 2 commits March 1, 2026 09:20
Add a hidden --check flag to beamtalk fmt that emits a clear error
message directing users to `beamtalk fmt-check` instead of the
misleading clap tip about `-- --check`.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Fix comment doubling bug: `// Copyright` was becoming `// // Copyright`
  because the lexer stored full `// text` in Trivia::LineComment, and the
  unparser added `// ` again when rendering
- Parser now strips `"// "` (with space) or `"//"` from LineComment trivia
  before constructing Comment objects, matching how collect_doc_comment
  already handles doc comments
- Same fix applied to block comments (strip `/* */` delimiters)
- Update all parser snapshots to reflect `content` without the `//` prefix
- Add idempotency tests for hanoi.bt, hello.bt, point.bt via include_str!
- Remove fmt-beamtalk/fmt-check-beamtalk from Justfile fmt/fmt-check
  aggregates until the stdlib and tests directories are formatted (BT-981)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Copy link

@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 (2)
crates/beamtalk-core/src/source_analysis/parser/mod.rs (1)

677-685: Deduplicate line-comment normalization to avoid leading/trailing drift.

The same //-prefix stripping logic is implemented twice. A shared helper will keep behavior consistent as comment rules evolve.

♻️ Proposed refactor
+    fn strip_line_comment_prefix(s: &str) -> &str {
+        s.strip_prefix("// ")
+            .or_else(|| s.strip_prefix("//"))
+            .unwrap_or(s)
+    }
+
     pub(super) fn collect_comment_attachment(&self) -> CommentAttachment {
@@
                 super::Trivia::LineComment(text) => {
-                    let s = text.as_str();
-                    let content = s
-                        .strip_prefix("// ")
-                        .or_else(|| s.strip_prefix("//"))
-                        .unwrap_or(s);
+                    let content = Self::strip_line_comment_prefix(text.as_str());
                     leading.push(Comment::line(content, token_span));
                 }
@@
         for trivia in last_token.trailing_trivia() {
             if let super::Trivia::LineComment(text) = trivia {
-                let s = text.as_str();
-                let content = s
-                    .strip_prefix("// ")
-                    .or_else(|| s.strip_prefix("//"))
-                    .unwrap_or(s);
+                let content = Self::strip_line_comment_prefix(text.as_str());
                 return Some(Comment::line(content, last_token.span()));
             }
         }

Also applies to: 724-729

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

In `@crates/beamtalk-core/src/source_analysis/parser/mod.rs` around lines 677 -
685, The line-comment prefix stripping logic is duplicated; create a small
helper function (e.g., fn strip_line_comment_prefix(s: &str) -> &str) and
replace the inline .strip_prefix("// ").or_else(||
s.strip_prefix("//")).unwrap_or(s) usages with calls to that helper where
Comment::line(...) is constructed (the two duplicated sites around the
leading.push(Comment::line(...)) occurrences and the other block at the 724-729
region), ensuring the helper returns the original slice when no prefix matches
so behavior remains identical to the current collect_doc_comment/Comment::line
usage.
crates/beamtalk-core/src/unparse/mod.rs (1)

1313-1319: Harden idempotency assertions by requiring clean parses.

assert_idempotent can still pass when parsing recovers from errors. Add explicit empty-diagnostics checks for source and first-pass output so this suite validates canonical valid formatting behavior.

🧪 Proposed test hardening
 #[track_caller]
 fn assert_idempotent(source: &str) {
-    let pass1 = unparse_module(&parse_source(source));
-    let pass2 = unparse_module(&parse_source(&pass1));
+    use crate::source_analysis::{lex_with_eof, parse};
+
+    let (module1, diags1) = parse(lex_with_eof(source));
+    assert!(
+        diags1.is_empty(),
+        "expected clean parse for idempotency source, got: {diags1:?}"
+    );
+    let pass1 = unparse_module(&module1);
+
+    let (module2, diags2) = parse(lex_with_eof(&pass1));
+    assert!(
+        diags2.is_empty(),
+        "first-pass output should parse cleanly, got: {diags2:?}"
+    );
+    let pass2 = unparse_module(&module2);
     assert_eq!(
         pass1, pass2,
         "unparser is not idempotent for source:\n{source}\n\npass1:\n{pass1}\n\npass2:\n{pass2}"
     );
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@crates/beamtalk-core/src/unparse/mod.rs` around lines 1313 - 1319, The
idempotency helper assert_idempotent should also verify that parsing produced no
recoverable errors: after calling parse_source(source) and parse_source(&pass1)
(used to create pass1 and pass2 by unparse_module), assert that both parse
results have empty diagnostics (e.g., diagnostics.is_empty()) before comparing
pass1 and pass2; update assert_idempotent to capture the parse results into
local variables (e.g., let parsed1 = parse_source(source); let pass1 =
unparse_module(&parsed1); let parsed2 = parse_source(&pass1); let pass2 =
unparse_module(&parsed2)) and add assertions that parsed1.diagnostics.is_empty()
and parsed2.diagnostics.is_empty() so the test only passes for clean parses.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@crates/beamtalk-core/src/source_analysis/parser/mod.rs`:
- Around line 677-685: The line-comment prefix stripping logic is duplicated;
create a small helper function (e.g., fn strip_line_comment_prefix(s: &str) ->
&str) and replace the inline .strip_prefix("// ").or_else(||
s.strip_prefix("//")).unwrap_or(s) usages with calls to that helper where
Comment::line(...) is constructed (the two duplicated sites around the
leading.push(Comment::line(...)) occurrences and the other block at the 724-729
region), ensuring the helper returns the original slice when no prefix matches
so behavior remains identical to the current collect_doc_comment/Comment::line
usage.

In `@crates/beamtalk-core/src/unparse/mod.rs`:
- Around line 1313-1319: The idempotency helper assert_idempotent should also
verify that parsing produced no recoverable errors: after calling
parse_source(source) and parse_source(&pass1) (used to create pass1 and pass2 by
unparse_module), assert that both parse results have empty diagnostics (e.g.,
diagnostics.is_empty()) before comparing pass1 and pass2; update
assert_idempotent to capture the parse results into local variables (e.g., let
parsed1 = parse_source(source); let pass1 = unparse_module(&parsed1); let
parsed2 = parse_source(&pass1); let pass2 = unparse_module(&parsed2)) and add
assertions that parsed1.diagnostics.is_empty() and
parsed2.diagnostics.is_empty() so the test only passes for clean parses.

ℹ️ Review info

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Disabled knowledge base sources:

  • Linear integration is disabled

You can enable these sources in your CodeRabbit configuration.

📥 Commits

Reviewing files that changed from the base of the PR and between 8a982e4 and 9977950.

⛔ Files ignored due to path filters (75)
  • test-package-compiler/tests/snapshots/compiler_tests__abstract_class_spawn_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__actor_spawn_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__actor_spawn_with_args_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__actor_state_mutation_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__async_keyword_message_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__async_unary_message_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__async_with_await_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__binary_operators_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__blocks_no_args_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__boundary_deeply_nested_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__boundary_long_identifiers_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__boundary_mixed_errors_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__boundary_unicode_identifiers_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__cascade_complex_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__cascades_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__character_literals_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__class_definition_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__class_methods_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__comment_handling_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__control_flow_mutations_errors_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__control_flow_mutations_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__empty_blocks_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__empty_method_body_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__error_message_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__error_recovery_invalid_syntax_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__error_recovery_malformed_message_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__error_recovery_unterminated_string_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__expect_directive_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__future_pattern_matching_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__future_string_interpolation_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__hello_world_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__intrinsic_keyword_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__map_literals_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__method_lookup_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__method_lookup_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__multi_keyword_complex_args_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__nested_blocks_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__nested_keyword_messages_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__sealed_class_violation_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__sealed_method_override_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_dictionary_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_dictionary_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_list_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_list_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_set_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_set_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_tuple_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__stdlib_class_tuple_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__string_operations_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__typed_class_warnings_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__typed_class_warnings_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__typed_methods_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__typed_methods_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__typed_value_type_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__typed_value_type_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__unary_operators_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__unicode_string_literals_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__value_type_multi_expr_method_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__value_type_multi_expr_method_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__value_type_param_collision_codegen.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__value_type_param_collision_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__while_true_simple_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__whitespace_handling_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__workspace_binding_cascade_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__workspace_binding_send_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_array_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_block_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_boolean_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_dictionary_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_integer_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_list_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_nil_object_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_nil_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_set_parser.snap is excluded by !**/*.snap
  • test-package-compiler/tests/snapshots/compiler_tests__ws_stdlib_string_parser.snap is excluded by !**/*.snap
📒 Files selected for processing (3)
  • Justfile
  • crates/beamtalk-core/src/source_analysis/parser/mod.rs
  • crates/beamtalk-core/src/unparse/mod.rs
🚧 Files skipped from review as they are similar to previous changes (1)
  • Justfile

… BT-978

- Fix unparse_literal for String to emit double-quoted strings ("...")
  instead of single-quoted ('...') — single-quoted strings are not
  supported by the parser, causing idempotency failures on pass2
- Update two unparse unit tests to expect double-quoted output
- Accept all parser snapshots reflecting correct comment content:
  - Comments now stored without delimiters: "Copyright 2026..." not
    "// Copyright 2026..." and not " Copyright 2026..."
  - The `// ` prefix (including trailing space) is stripped correctly

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@jamesc jamesc merged commit 88122dc into main Mar 1, 2026
5 checks passed
@jamesc jamesc deleted the worktree-BT-978 branch March 1, 2026 10:04
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