Skip to content

chore: allow string or number amount in format price#2

Merged
pnodet merged 1 commit into
mainfrom
format-price-update
Sep 11, 2025
Merged

chore: allow string or number amount in format price#2
pnodet merged 1 commit into
mainfrom
format-price-update

Conversation

@pnwatin

@pnwatin pnwatin commented Sep 11, 2025

Copy link
Copy Markdown
Member

Summary by CodeRabbit

  • New Features

    • Price formatting now accepts amounts provided as numbers in addition to strings, with consistent output across locales, currencies, quantity scaling, and cents-handling options.
  • Tests

    • Added tests to verify identical results when amounts are provided as strings vs. numbers.
    • Updated existing test cases to use numeric amounts across scenarios (default/custom locale, quantity multipliers, cents disabled, fractional retention, different currencies, large quantities).

@pnwatin pnwatin requested a review from pnodet September 11, 2025 11:24
@coderabbitai

coderabbitai Bot commented Sep 11, 2025

Copy link
Copy Markdown

Walkthrough

Widened Currency.amount type to accept number in addition to string and updated formatPrice to handle numeric amounts directly. Adjusted unit tests to use numeric amounts and added a parity test ensuring identical formatting for string vs number inputs.

Changes

Cohort / File(s) Summary
Currency API and logic
src/currency/index.ts
Expanded Currency.amount type from string to string | number. In formatPrice, if amount is a number, use it directly; if string, parse via parseFloat. Existing fractional-digit logic remains unchanged.
Tests
src/currency/index.spec.ts
Updated tests to primarily use numeric amounts. Added a test asserting identical formatPrice output for string vs number amounts across the same currency/locale context.

Sequence Diagram(s)

sequenceDiagram
  autonumber
  participant C as Caller
  participant F as formatPrice
  participant P as Intl.NumberFormat

  C->>F: formatPrice({ amount, currencyCode, ... })
  alt amount is number
    Note right of F: Use amount directly
  else amount is string
    F->>F: parseFloat(amount)
    Note right of F: Convert to numeric price
  end
  F->>P: format(price, options)
  P-->>F: formatted string
  F-->>C: return formatted price
Loading

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

Pre-merge checks (3 passed)

✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title Check ✅ Passed The PR title "chore: allow string or number amount in format price" accurately summarizes the primary change—widening the amount type and updating formatPrice/tests to accept string or number—so it is concise and directly related to the changeset.
Docstring Coverage ✅ Passed No functions found in the changes. Docstring coverage check skipped.

Poem

I twitch my ears at numbers’ song,
Strings or digits, both belong—
A hop, a skip, formats align,
Euros gleam with tidy shine.
Tests all nibble, parity won,
Price hops true, and then we’re done. 🐇💶

Tip

👮 Agentic pre-merge checks are now available in preview!

Pro plan users can now enable pre-merge checks in their settings to enforce checklists before merging PRs.

  • Built-in checks – Quickly apply ready-made checks to enforce title conventions, require pull request descriptions that follow templates, validate linked issues for compliance, and more.
  • Custom agentic checks – Define your own rules using CodeRabbit’s advanced agentic capabilities to enforce organization-specific policies and workflows. For example, you can instruct CodeRabbit’s agent to verify that API documentation is updated whenever API schema files are modified in a PR. Note: Upto 5 custom checks are currently allowed during the preview period. Pricing for this feature will be announced in a few weeks.

Please see the documentation for more information.

Example:

reviews:
  pre_merge_checks:
    custom_checks:
      - name: "Undocumented Breaking Changes"
        mode: "warning"
        instructions: |
          Pass/fail criteria: All breaking changes to public APIs, CLI flags, environment variables, configuration keys, database schemas, or HTTP/GraphQL endpoints must be documented in the "Breaking Change" section of the PR description and in CHANGELOG.md. Exclude purely internal or private changes (e.g., code not exported from package entry points or explicitly marked as internal).

Please share your feedback with us on this Discord post.

✨ Finishing touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch format-price-update

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.

@pkg-pr-new

pkg-pr-new Bot commented Sep 11, 2025

Copy link
Copy Markdown

Open in StackBlitz

npm i https://pkg.pr.new/nivalis-studio/nivalis-std/@nivalis/std@2

commit: f658d8e

@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: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/currency/index.ts (1)

14-23: Guard parsing and base “no-cents” on the final amount, not the unit price

  • parseFloat is permissive (“12.3abc” → 12.3) and may yield NaN silently.
  • The cents toggle checks price % 1 but formatting uses price * quantity; this misbehaves for non-integer quantities or when floating error creeps in.

Apply:

-  const price = typeof amount === 'number' ? amount : Number.parseFloat(amount);
-
-  return new Intl.NumberFormat(locale, {
+  const price =
+    typeof amount === 'number' ? amount : Number(amount);
+  if (!Number.isFinite(price)) {
+    throw new TypeError(`Invalid amount: ${amount as unknown as string}`);
+  }
+  const total = price * quantity;
+  const isIntegerTotal =
+    Number.isInteger(total) || Math.abs(total - Math.round(total)) < 1e-9;
+
+  return new Intl.NumberFormat(locale, {
     style: 'currency',
     currency: currencyCode,
     // eslint-disable-next-line @typescript-eslint/no-magic-numbers
-    maximumFractionDigits: disableCents && price % 1 === 0 ? 0 : 2,
+    maximumFractionDigits: disableCents && isIntegerTotal ? 0 : 2,
     // eslint-disable-next-line @typescript-eslint/no-magic-numbers
-    minimumFractionDigits: disableCents && price % 1 === 0 ? 0 : 2,
-  }).format(price * quantity);
+    minimumFractionDigits: disableCents && isIntegerTotal ? 0 : 2,
+  }).format(total);
🧹 Nitpick comments (2)
src/currency/index.ts (1)

16-23: Optional: respect currency-specific fraction digits

If you want JPY/CLP (0 decimals) or TND (3 decimals) to follow CLDR defaults, omit explicit min/max digits when disableCents is false, or derive them from Intl.NumberFormat(...).resolvedOptions().

src/currency/index.spec.ts (1)

6-19: Optional: validate bad string inputs

If you adopt input validation (throw on non-numeric strings), add a negative test.

Add:

test('throws on invalid amount string', () => {
  const money = { amount: '12.34abc', currencyCode: 'USD' } satisfies Currency;
  expect(() => formatPrice(money, 'en-US')).toThrow(TypeError);
});

If localized strings (e.g., '1 234,56') must be accepted, we should normalize per-locale before parsing and add tests accordingly.

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bfe9bfa and f658d8e.

📒 Files selected for processing (2)
  • src/currency/index.spec.ts (1 hunks)
  • src/currency/index.ts (2 hunks)
🧰 Additional context used
🧬 Code graph analysis (1)
src/currency/index.spec.ts (1)
src/currency/index.ts (2)
  • Currency (3-6)
  • formatPrice (8-24)
🔇 Additional comments (3)
src/currency/index.ts (1)

4-4: Type widening to support numbers looks good

Non-breaking for TS consumers and improves ergonomics.

src/currency/index.spec.ts (2)

6-19: Parity test (string vs number) is solid

Good guard to ensure behavior remains identical.


41-46: Add a test for disableCents with non-integer quantities

Current implementation bases the cents decision on the unit price, not the final total; the test below will catch that and validate the proposed fix.

Add:

test('disableCents bases decision on final total', () => {
  const money = { amount: 10, currencyCode: 'USD' } satisfies Currency;
  expect(formatPrice(money, 'en-US', 1.5, true)).toBe('$15.00'); // cents shown
  expect(formatPrice(money, 'en-US', 2, true)).toBe('$20');      // no cents
});

@pnodet pnodet merged commit 7ae3bec into main Sep 11, 2025
4 checks passed
@pnodet pnodet deleted the format-price-update branch September 11, 2025 13:21
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