Skip to content

Add type-based auto-alignment and formula format inference#27

Merged
hackerwins merged 2 commits into
mainfrom
type-align
Apr 18, 2026
Merged

Add type-based auto-alignment and formula format inference#27
hackerwins merged 2 commits into
mainfrom
type-align

Conversation

@ggyuchive

@ggyuchive ggyuchive commented Mar 9, 2026

Copy link
Copy Markdown
Member

Summary

Formula results now inherit inferred format metadata (date, percent, currency) via inferInput + applyInferredFormat in the calculator. The rendering layer uses a new defaultAlign() function to implicitly align cells: numbers and dates right-align, booleans center-align, and text left-aligns — matching Excel/Google Sheets behavior.

Also extracts applyInferredFormat from Sheet into a standalone utility and adds datetime parsing for NOW() output format.

Why

Linked Issues

Fixes #

Verification

CI automatically posts a verification summary comment on this PR with
per-lane results for both verify:self and verify:integration.

  • verify:self — CI comment shows ✅
  • verify:integration — CI comment shows ✅ (or explicit skip reason below)

Skip reason (if applicable):

Risk Assessment

  • User-facing risk:
  • Data/security risk:
  • Rollback plan:

Notes for Reviewers

  • UI changes (screenshots/gifs if applicable):
  • Follow-up work (if any):

Summary by CodeRabbit

  • New Features

    • Cells automatically apply inferred formatting for dates, percentages and currencies; datetime inputs (YYYY-MM-DD HH:MM:SS) are recognized and preserved when relevant.
    • Default alignment now adapts by content: numbers/dates right, text left, booleans centered.
  • Tests

    • Added coverage for inferred formatting and datetime input handling.

@coderabbitai

coderabbitai Bot commented Mar 9, 2026

Copy link
Copy Markdown
📝 Walkthrough

Walkthrough

Adds datetime parsing and format inference export, moves format-application logic into a shared function used by Sheet and Calculator, updates calculator to apply inferred formatting after synchronous formula evaluation, adjusts date parsing/formatting shape, and infers horizontal alignment in the grid renderer.

Changes

Cohort / File(s) Summary
Input Format Inference Core
packages/sheet/src/model/input.ts
Adds parseDatetime, extends inferInput to detect datetimes, and exports applyInferredFormat(existing, inferred) to produce CellStyle (date, percent, currency) while preserving other style properties.
Date Parsing & Formatting
packages/sheet/src/model/format.ts
parseDateValue now returns `{ date: Date; hasTime: boolean }
Calculator Integration
packages/sheet/src/model/calculator.ts
Imports inferInput and applyInferredFormat; evaluates formulas synchronously via evaluate(cell.f!, grid) and applies inferred formatting (when no explicit nf) to nextCell.s using the shared applyInferredFormat.
Sheet Integration
packages/sheet/src/model/sheet.ts
Removes Sheet's private applyInferredFormat and replaces internal calls with the imported applyInferredFormat from input.ts; delegation centralizes inference logic.
Grid Rendering Alignment
packages/sheet/src/view/gridcanvas.ts
Adds defaultAlign(rawData, nf) and uses inferInput to choose implicit alignment (booleans center, numbers/dates right, text left) as fallback instead of a fixed 'left'.
Tests
packages/sheet/test/model/input.test.ts
Exports/imports updated to include applyInferredFormat; new tests cover applyInferredFormat behavior (date, datetime, percent, currency, and preservation/override scenarios) and a datetime inference case for inferInput.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • hackerwins

Poem

🐰 I sniffed the bytes and found a date,
From strings that used to simply wait,
Formats now bloom where none were set,
Alignment hops to the place it met,
A tiny rabbit’s tidy update. 🥕✨

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 57.14% 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 accurately describes the main changes: type-based auto-alignment (in gridcanvas.ts via defaultAlign) and formula format inference (in calculator.ts and input.ts with inferInput and applyInferredFormat).
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ 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 type-align

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.

@github-actions

github-actions Bot commented Mar 9, 2026

Copy link
Copy Markdown
Contributor

Verification: verify:self

Result: ✅ PASS in 119.9s

Lane Status Duration
sheets:build ✅ pass 13.9s
docs:build ✅ pass 8.0s
verify:fast ✅ pass 60.4s
frontend:build ✅ pass 15.6s
verify:frontend:chunks ✅ pass 0.3s
backend:build ✅ pass 4.7s
cli:build ✅ pass 1.8s
verify:entropy ✅ pass 15.2s

Verification: verify:integration

Result: ✅ PASS

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 5

🤖 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/sheet/src/model/calculator.ts`:
- Around line 67-69: The recalculation currently always overwrites explicit
number/currency formats by calling applyInferredFormat(cell.s, inferred); change
this so inference only seeds formatting when the cell has no explicit number
format: check the cell's style number-format fields (e.g., cell.s.nf and
cell.s.cu) before applying inference and skip calling applyInferredFormat (or
call it with a flag) if an explicit nf/cu exists; update the evaluate ->
inferInput -> applyInferredFormat flow (the evaluate, inferInput,
applyInferredFormat call sites and the cell.s object) to preserve any
user-provided nf/cu and only set inferred formatting when those fields are
empty/undefined.

In `@packages/sheet/src/model/input.ts`:
- Around line 159-166: The parseDatetime function currently only validates the
YYYY-MM-DD portion and lets invalid clock values like "99:99:99" through; update
parseDatetime to capture hours, minutes, and seconds (e.g., extend the regex to
/^(\d{4})-(\d{2})-(\d{2}) (\d{2}):(\d{2}):(\d{2})$/), parse Number(match[4..6])
as hour/minute/second, and explicitly reject values outside valid ranges (hour
0–23, minute 0–59, second 0–59) in addition to the existing toIsoDate(year,
month, day) check so only fully valid datetimes return the input string.

In `@packages/sheet/src/view/gridcanvas.ts`:
- Line 1241: Overflow detection uses style?.al || 'left' while
renderCellContent() uses defaultAlign(rawData, style?.nf), causing mismatched
alignment for implicit cases; update buildTextOverflowRenderData() call to use
the same computed align as renderCellContent by calling defaultAlign(rawData,
style?.nf) (or reuse the existing const align = style?.al ||
defaultAlign(rawData, style?.nf)) instead of relying on style?.al || 'left', and
pass that align into buildTextOverflowRenderData so overflow/reserved columns
match visual alignment.
- Around line 58-67: The defaultAlign function currently uses Number(rawData) to
decide right alignment, which wrongly treats leading-zero/ID-like strings (e.g.,
"00123") as numeric; change defaultAlign to reuse the same inference used by
inferInput (call or replicate inferInput(rawData)) and only right-align when the
inference indicates a numeric value (or nf === 'date'), otherwise keep left
alignment for inferred text/IDs so leading zeros are preserved; reference the
defaultAlign and inferInput symbols and ensure you import or call inferInput in
this function rather than using Number(rawData).

In `@packages/sheet/test/model/input.test.ts`:
- Around line 66-80: The new datetime parser test lacks invalid-time coverage:
add assertions to the test case in input.test.ts that verify inferInput rejects
datetime strings with invalid time components (e.g., '2025-01-01 99:99:99' and
other hour/minute/second out-of-range values) so that parseDatetime() behavior
is guarded; update the 'infers datetime (NOW() output format)' spec to include
expect(inferInput('2025-01-01 99:99:99').type).toBe('text') (and similar
assertions for seconds >59 and minutes >59) to ensure inferInput/parseDatetime
treat those as text.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: d36f7bbc-10e5-4fde-b118-ba8b5849480f

📥 Commits

Reviewing files that changed from the base of the PR and between af3dc4e and cbe2e51.

📒 Files selected for processing (5)
  • packages/sheet/src/model/calculator.ts
  • packages/sheet/src/model/input.ts
  • packages/sheet/src/model/sheet.ts
  • packages/sheet/src/view/gridcanvas.ts
  • packages/sheet/test/model/input.test.ts

Comment thread packages/sheet/src/model/calculator.ts Outdated
Comment on lines +67 to +69
const value = evaluate(cell.f!, grid);
const inferred = inferInput(value);
const style = applyInferredFormat(cell.s, inferred);

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don't clobber explicit cell formats during recalculation.

applyInferredFormat(cell.s, inferred) overwrites nf/cu every time the formula runs. That means a user-formatted formula cell can snap back to the inferred date/percent/currency format on each dependency change. This needs a guard so inference only seeds formatting when the cell does not already have an explicit number format.

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

In `@packages/sheet/src/model/calculator.ts` around lines 67 - 69, The
recalculation currently always overwrites explicit number/currency formats by
calling applyInferredFormat(cell.s, inferred); change this so inference only
seeds formatting when the cell has no explicit number format: check the cell's
style number-format fields (e.g., cell.s.nf and cell.s.cu) before applying
inference and skip calling applyInferredFormat (or call it with a flag) if an
explicit nf/cu exists; update the evaluate -> inferInput -> applyInferredFormat
flow (the evaluate, inferInput, applyInferredFormat call sites and the cell.s
object) to preserve any user-provided nf/cu and only set inferred formatting
when those fields are empty/undefined.

Comment thread packages/sheets/src/model/worksheet/input.ts
Comment thread packages/sheets/src/view/gridcanvas.ts
Comment thread packages/sheets/src/view/gridcanvas.ts
Comment thread packages/sheets/test/model/input.test.ts
@ggyuchive
ggyuchive marked this pull request as draft March 9, 2026 14:20
@ggyuchive
ggyuchive marked this pull request as ready for review March 10, 2026 11:58

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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/sheet/test/model/input.test.ts (1)

128-158: Consider adding test coverage for currency format.

The test suite covers date, datetime, percent, and plain text scenarios, but does not test the currency branch of applyInferredFormat (lines 326-336 in input.ts). Adding a test would ensure the nf: 'currency' and cu properties are correctly set.

Suggested test case
it('sets nf: currency and cu for currency input', () => {
  const result = applyInferredFormat(undefined, inferInput('$100'));
  expect(result).toEqual({ nf: 'currency', cu: 'USD' });
});
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@packages/sheet/test/model/input.test.ts` around lines 128 - 158, Add a test
covering the currency branch of applyInferredFormat: call
applyInferredFormat(undefined, inferInput('$100')) and assert the returned
format equals { nf: 'currency', cu: 'USD' } (use the same test file and describe
block as other cases); reference the functions applyInferredFormat and
inferInput and add this single it(...) case to ensure currency symbol parsing
sets nf to 'currency' and cu to the expected currency code.
🤖 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/sheet/src/model/format.ts`:
- Around line 51-56: The datetime branch currently only checks year/month/day
against localDate and can accept invalid times; before returning { date:
localDate, hasTime: true } validate the parsed time components (e.g. hour,
minute, second — the variables used to build localDate) enforcing 0 <= hour <=
23, 0 <= minute <= 59, 0 <= second <= 59 (and millisecond if present), and if
any component is out of range do not treat it as a valid datetime (return null
or the function's failure value) instead of returning hasTime: true; update the
code around the localDate/year/month/day checks in this datetime parsing branch
(the block referencing localDate.getFullYear(), getMonth(), getDate() and
returning { date: localDate, hasTime: true }) to include these explicit bounds
checks.
- Around line 68-85: Add unit tests for safeFormatDate to cover the datetime
branch (when parseDateValue returns hasTime=true) in addition to the existing
date-only case: create tests that call safeFormatDate with valid datetime
strings (e.g., "2023-08-15T13:45:30" or equivalent input that parseDateValue
recognizes) and assert the returned string equals "YYYY-MM-DD HH:mm:ss"; include
edge cases like midnight ("00:00:00") and seconds rounding/zero-padding (e.g.,
"2023-01-05T00:00:05"), and also add tests for invalid datetime inputs that
should fall back to returning the original value; locate tests around the module
that imports safeFormatDate/parseDateValue (or in the same test file as other
format tests) and name them to indicate datetime-format coverage.

---

Nitpick comments:
In `@packages/sheet/test/model/input.test.ts`:
- Around line 128-158: Add a test covering the currency branch of
applyInferredFormat: call applyInferredFormat(undefined, inferInput('$100')) and
assert the returned format equals { nf: 'currency', cu: 'USD' } (use the same
test file and describe block as other cases); reference the functions
applyInferredFormat and inferInput and add this single it(...) case to ensure
currency symbol parsing sets nf to 'currency' and cu to the expected currency
code.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: bc9584c9-4fe9-4f93-b6c6-984b770fd6d9

📥 Commits

Reviewing files that changed from the base of the PR and between cbe2e51 and e959f87.

📒 Files selected for processing (5)
  • packages/sheet/src/model/calculator.ts
  • packages/sheet/src/model/format.ts
  • packages/sheet/src/model/input.ts
  • packages/sheet/src/view/gridcanvas.ts
  • packages/sheet/test/model/input.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
  • packages/sheet/src/model/calculator.ts
  • packages/sheet/src/view/gridcanvas.ts

Comment thread packages/sheets/src/model/worksheet/format.ts
Comment thread packages/sheets/src/model/worksheet/format.ts
@ggyuchive
ggyuchive marked this pull request as draft March 10, 2026 12:21
@ggyuchive
ggyuchive marked this pull request as ready for review April 18, 2026 07:53
@codecov

codecov Bot commented Apr 18, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 84.68468% with 17 lines in your changes missing coverage. Please review.

Files with missing lines Patch % Lines
packages/sheets/src/view/gridcanvas.ts 18.75% 13 Missing ⚠️
packages/sheets/src/model/worksheet/format.ts 91.66% 3 Missing ⚠️
packages/sheets/src/model/worksheet/calculator.ts 85.71% 1 Missing ⚠️

📢 Thoughts on this report? Let us know!

The auto-alignment feature changes default cell rendering (e.g.
numbers right-aligned), so harness screenshots need refreshing.

Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
@hackerwins
hackerwins merged commit c713e9a into main Apr 18, 2026
4 checks passed
@hackerwins
hackerwins deleted the type-align branch April 18, 2026 08:28
@hackerwins hackerwins mentioned this pull request Apr 19, 2026
1 task
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