Skip to content

fix: normalize escaped sheet range separators#207

Merged
caojie0621 merged 1 commit intomainfrom
fix/sheet_cli
Apr 2, 2026
Merged

fix: normalize escaped sheet range separators#207
caojie0621 merged 1 commit intomainfrom
fix/sheet_cli

Conversation

@caojie0621
Copy link
Copy Markdown
Collaborator

@caojie0621 caojie0621 commented Apr 2, 2026

Summary

Accept escaped and full-width sheet/range separators in sheets shortcuts. Normalize range parsing in the shared sheets helper so read, find, write, and append handle !, \!, and ! consistently.
Add regression tests for separator normalization in dry-run paths.

Changes

  • Normalize escaped and full-width sheet/range separators in the shared sheets range helper.
  • Apply the normalization through the shared parsing path used by sheets shortcuts such as +read, +find, +write, and +append.
  • Add regression tests covering separator normalization in sheets dry-run paths.

Test Plan

  • Unit tests pass
  • Manual local verification confirms the lark-cli sheets +read/+find/+write/+append command works as expected

Related Issues

  • None

Summary by CodeRabbit

  • Bug Fixes
    • Sheet range inputs now properly normalize and accept different separator character variants, including escaped and fullwidth characters.

Accept escaped and full-width sheet/range separators in sheets shortcuts.
Normalize range parsing in the shared sheets helper so read, find, write,
and append handle \!, \!, and ! consistently.
Add regression tests for separator normalization in dry-run paths.
@github-actions github-actions bot added domain/ccm PR touches the ccm domain size/M Single-domain feat or fix with limited business impact labels Apr 2, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 2, 2026

📝 Walkthrough

Walkthrough

The changes add separator normalization to handle non-ASCII and escaped exclamation mark variants in sheet ranges. A new helper function normalizes fullwidth (\!, ) and escaped ASCII (\!) variants to standard !, integrated into existing range-parsing functions. Supporting test coverage validates normalization behavior and dry-run JSON output.

Changes

Cohort / File(s) Summary
Separator Normalization
shortcuts/sheets/helpers.go
Added sheetRangeSeparatorReplacer and normalizeSheetRangeSeparators() helper to trim whitespace and convert fullwidth/escaped exclamation variants to !. Updated five range-related functions (normalizeSheetRange, normalizeWriteRange, validateSheetRangeInput, looksLikeRelativeRange, splitSheetRange) to apply separator normalization before processing.
Test Coverage
shortcuts/sheets/sheet_ranges_test.go
New test file with test helper utilities (mustMarshalSheetsDryRun, newSheetsTestRuntime) and parallelized unit tests validating separator normalization (escaped ASCII \! and fullwidth \! variants), range input validation, and dry-run JSON output for sheet operations (SheetRead, SheetWrite, SheetAppend, SheetFind).

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Poem

🐰 Hop hop, a fix for the separators!
Fullwidth marks now dance with ASCII mates,
Escaped or bare, they all align—
One ! to rule them, tests that shine.
The sheets shall parse with grace divine!

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.76% 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 clearly and accurately describes the main change: normalizing escaped sheet range separators across the sheets shortcuts.
Description check ✅ Passed The description comprehensively covers the summary, changes, test plan with checkmarks, and related issues sections matching the template structure.

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

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/sheet_cli

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.

🧹 Nitpick comments (4)
shortcuts/sheets/helpers.go (2)

83-99: Minor redundancy: double normalization.

normalizeSheetRangeSeparators is called at line 85, then normalizeSheetRange at line 90 internally calls it again. Since the operation is idempotent this is functionally correct, but consider normalizing once and passing the result through to avoid redundant string allocations.

♻️ Optional: avoid double normalization
 func normalizeWriteRange(sheetID, input string, values interface{}) string {
 	rows, cols := matrixDimensions(values)
 	input = normalizeSheetRangeSeparators(input)
 	if input == "" {
 		return buildRectRange(sheetID, "A1", rows, cols)
 	}
 
-	input = normalizeSheetRange(sheetID, input)
+	// Input already normalized; inline the logic from normalizeSheetRange
+	if !strings.Contains(input, "!") && sheetID != "" && looksLikeRelativeRange(input) {
+		input = sheetID + "!" + input
+	}
 	rangeSheetID, subRange, ok := splitSheetRange(input)

Alternatively, refactor normalizeSheetRange to accept a pre-normalized flag or extract the core logic.

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

In `@shortcuts/sheets/helpers.go` around lines 83 - 99, In normalizeWriteRange,
avoid the redundant call to normalizeSheetRangeSeparators by removing the
standalone call at the top and letting normalizeSheetRange(handle the
normalization internally); update normalizeWriteRange to call
normalizeSheetRange once (keeping the subsequent use of splitSheetRange,
buildRectRange and singleCellRangePattern unchanged) so you don't perform
duplicate string normalization and extra allocations.

101-110: Same double-normalization pattern as noted above.

looksLikeRelativeRange at line 106 will normalize again. This is correct but redundant.

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

In `@shortcuts/sheets/helpers.go` around lines 101 - 110, The function
validateSheetRangeInput currently calls normalizeSheetRangeSeparators and then
calls looksLikeRelativeRange which normalizes again, causing redundant work;
remove the initial normalizeSheetRangeSeparators call in validateSheetRangeInput
so the function uses the original input for the empty and "!" checks and relies
on looksLikeRelativeRange to perform normalization internally, keeping the
checks and error message behavior identical while eliminating
double-normalization.
shortcuts/sheets/sheet_ranges_test.go (2)

44-48: Consider using strconv.FormatBool for cleaner bool-to-string conversion.

The inline map works but strconv.FormatBool(value) is more idiomatic.

♻️ Simpler bool-to-string conversion
+	"strconv"
 	for name, value := range boolFlags {
-		if err := cmd.Flags().Set(name, map[bool]string{true: "true", false: "false"}[value]); err != nil {
+		if err := cmd.Flags().Set(name, strconv.FormatBool(value)); err != nil {
 			t.Fatalf("Flags().Set(%q) error = %v", name, err)
 		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/sheets/sheet_ranges_test.go` around lines 44 - 48, Replace the
inline map boolean-to-string conversion in the loop that sets flag values (the
for name, value := range boolFlags { ... cmd.Flags().Set(...) } block) with
strconv.FormatBool(value) for clarity and idiomatic code; add/import strconv if
missing and use cmd.Flags().Set(name, strconv.FormatBool(value)), keeping the
existing error handling (t.Fatalf) unchanged.

52-74: Good coverage of separator variants.

Consider adding edge cases for completeness: empty string, whitespace-only input, and multiple separators in a single range string.

♻️ Additional test cases
 	tests := []struct {
 		name  string
 		input string
 		want  string
 	}{
 		{name: "standard", input: "sheet_123!A1:B2", want: "sheet_123!A1:B2"},
 		{name: "escaped ascii", input: `sheet_123\!A1:B2`, want: "sheet_123!A1:B2"},
 		{name: "fullwidth", input: "sheet_123!A1:B2", want: "sheet_123!A1:B2"},
 		{name: "escaped fullwidth", input: `sheet_123\!A1:B2`, want: "sheet_123!A1:B2"},
+		{name: "empty", input: "", want: ""},
+		{name: "whitespace only", input: "   ", want: ""},
+		{name: "with leading/trailing whitespace", input: "  sheet_123!A1:B2  ", want: "sheet_123!A1:B2"},
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@shortcuts/sheets/sheet_ranges_test.go` around lines 52 - 74, Add tests for
edge cases to TestNormalizeSheetRangeSeparators: include an empty string input,
a whitespace-only input (e.g., "   "), and inputs containing multiple separator
characters (e.g., "sheet!A1!B2" and "sheet!!A1:B2") to verify
normalizeSheetRangeSeparators handles or normalizes these cases; use t.Run
subtests, keep t.Parallel() and assert that the returned value matches expected
normalization behavior (decide expected outcomes such as returning input
unchanged, trimming whitespace, or collapsing multiple separators) referencing
the normalizeSheetRangeSeparators function to locate where behavior should be
validated.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@shortcuts/sheets/helpers.go`:
- Around line 83-99: In normalizeWriteRange, avoid the redundant call to
normalizeSheetRangeSeparators by removing the standalone call at the top and
letting normalizeSheetRange(handle the normalization internally); update
normalizeWriteRange to call normalizeSheetRange once (keeping the subsequent use
of splitSheetRange, buildRectRange and singleCellRangePattern unchanged) so you
don't perform duplicate string normalization and extra allocations.
- Around line 101-110: The function validateSheetRangeInput currently calls
normalizeSheetRangeSeparators and then calls looksLikeRelativeRange which
normalizes again, causing redundant work; remove the initial
normalizeSheetRangeSeparators call in validateSheetRangeInput so the function
uses the original input for the empty and "!" checks and relies on
looksLikeRelativeRange to perform normalization internally, keeping the checks
and error message behavior identical while eliminating double-normalization.

In `@shortcuts/sheets/sheet_ranges_test.go`:
- Around line 44-48: Replace the inline map boolean-to-string conversion in the
loop that sets flag values (the for name, value := range boolFlags { ...
cmd.Flags().Set(...) } block) with strconv.FormatBool(value) for clarity and
idiomatic code; add/import strconv if missing and use cmd.Flags().Set(name,
strconv.FormatBool(value)), keeping the existing error handling (t.Fatalf)
unchanged.
- Around line 52-74: Add tests for edge cases to
TestNormalizeSheetRangeSeparators: include an empty string input, a
whitespace-only input (e.g., "   "), and inputs containing multiple separator
characters (e.g., "sheet!A1!B2" and "sheet!!A1:B2") to verify
normalizeSheetRangeSeparators handles or normalizes these cases; use t.Run
subtests, keep t.Parallel() and assert that the returned value matches expected
normalization behavior (decide expected outcomes such as returning input
unchanged, trimming whitespace, or collapsing multiple separators) referencing
the normalizeSheetRangeSeparators function to locate where behavior should be
validated.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 2d7bb7fe-74ee-454b-a906-d79a512ffe99

📥 Commits

Reviewing files that changed from the base of the PR and between 79f43dc and e173aeb.

📒 Files selected for processing (2)
  • shortcuts/sheets/helpers.go
  • shortcuts/sheets/sheet_ranges_test.go

@greptile-apps
Copy link
Copy Markdown

greptile-apps bot commented Apr 2, 2026

Greptile Summary

This PR fixes a usability gap in the lark-cli sheets shortcuts (+read, +find, +write, +append) where users on non-US keyboards or shells that escape the ! separator could not specify ranges in the expected <sheetId>!<range> format. The fix introduces a single strings.NewReplacer-backed helper (normalizeSheetRangeSeparators) that canonicalises three problematic variants — escaped ASCII (\!), full-width (), and escaped full-width (\!) — to a standard ASCII ! before any parsing occurs.

Key changes:

  • New package-level strings.NewReplacer (sheetRangeSeparatorReplacer) handles all three separator variants efficiently with a single linear pass.
  • normalizeSheetRangeSeparators subsumes the previous bare strings.TrimSpace calls in normalizeSheetRange, normalizeWriteRange, validateSheetRangeInput, looksLikeRelativeRange, and splitSheetRange, preserving existing whitespace-trimming behaviour.
  • The new function is called early in normalizeWriteRange and validateSheetRangeInput so that whitespace-only inputs still fall through to the empty-range default path (the first call is load-bearing, not purely defensive).
  • New test file sheet_ranges_test.go adds a unit test for all four separator variants and integration dry-run tests for each shortcut command.

Minor observation:

  • For non-empty inputs, normalizeSheetRangeSeparators runs twice in normalizeWriteRange (once explicitly, once inside normalizeSheetRange) and in looksLikeRelativeRange (once inside it, once in its callers). This is harmless due to idempotency, but a short comment at the first call site would clarify the intent (see inline comment).

Confidence Score: 4/5

Safe to merge; the change is additive normalisation with no impact on well-formed inputs, and the new tests verify all expected variants.

The implementation is logically correct and the strings.NewReplacer ordering properly handles all overlap cases (\! takes precedence over ). All five functions that previously used raw TrimSpace are updated consistently, and dry-run tests confirm end-to-end normalisation through each shortcut. The only finding is a minor style point about the double normalisation in normalizeWriteRange/looksLikeRelativeRange, which has no runtime impact.

No files require special attention; shortcuts/sheets/helpers.go is the only logic change and it is straightforward.

Important Files Changed

Filename Overview
shortcuts/sheets/helpers.go Introduces normalizeSheetRangeSeparators to handle \!, \!, and variants; replaces bare TrimSpace calls with the new helper. Logic is sound but two call sites result in the replacer running twice for non-empty inputs (harmless but redundant).
shortcuts/sheets/sheet_ranges_test.go New test file covering normalizeSheetRangeSeparators unit tests and dry-run integration tests for read/write/append/find; test helper construction is correct. Missing an explicit dry-run test for plain escaped-ASCII \! (covered only in the unit test).

Flowchart

%%{init: {'theme': 'neutral'}}%%
flowchart TD
    A["User input\n(e.g. sheet_123\\!A1:B2)"] --> B["normalizeSheetRangeSeparators\n(TrimSpace + replace \\! \\! ! → !)"]
    B --> C{input empty?}
    C -- Yes --> D["Return / default range"]
    C -- No --> E["Caller-specific logic"]

    E --> F["normalizeSheetRange\n(also calls normalizeSheetRangeSeparators)"]
    E --> G["normalizeWriteRange\n(also calls normalizeSheetRangeSeparators)"]
    E --> H["validateSheetRangeInput\n(also calls normalizeSheetRangeSeparators)"]
    E --> I["splitSheetRange\n(normalizes then splits on '!')"]
    E --> J["looksLikeRelativeRange\n(normalizes, then regex match)"]

    F --> I
    F --> J
    H --> J
Loading

Reviews (1): Last reviewed commit: "fix: normalize escaped sheet range separ..." | Re-trigger Greptile

@github-actions
Copy link
Copy Markdown

github-actions bot commented Apr 2, 2026

🚀 PR Preview Install Guide

🧰 CLI update

npm i -g https://pkg.pr.new/larksuite/cli/@larksuite/cli@e173aeb6d0e4677669ef81468f318158c2befeed

🧩 Skill update

npx skills add larksuite/cli#fix/sheet_cli -y -g

@caojie0621 caojie0621 merged commit 0f96bdf into main Apr 2, 2026
13 checks passed
@caojie0621 caojie0621 deleted the fix/sheet_cli branch April 2, 2026 07:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

domain/ccm PR touches the ccm domain size/M Single-domain feat or fix with limited business impact

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants