Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
7f11177
refactor: expose core Rust library API
bigtomcat6 May 30, 2026
272b65a
refactor: gate napi build setup behind feature
bigtomcat6 May 30, 2026
a18bdb7
refactor: expose pure rust library surface
bigtomcat6 May 30, 2026
c0a4732
refactor: make rmb conversion deterministic and reusable
bigtomcat6 May 30, 2026
81b2a50
refactor: add napi bindings for rust core
bigtomcat6 May 30, 2026
3cc4d4b
chore: build napi bindings with feature flag
bigtomcat6 May 30, 2026
1b44c20
types: expose deterministic formatting APIs
bigtomcat6 May 30, 2026
c2f3ca0
feat: support deterministic cents string input
bigtomcat6 May 30, 2026
d5e2ddb
refactor: export cents string formatter
bigtomcat6 May 30, 2026
f5d692e
refactor: expose cents string napi binding
bigtomcat6 May 30, 2026
7ecaffa
types: accept cents as string
bigtomcat6 May 30, 2026
a00f793
docs: describe rust library and napi wrapper usage
bigtomcat6 May 30, 2026
5b6af11
build: update generated napi loader exports
bigtomcat6 May 30, 2026
c76cd08
ci: add rust library checks
bigtomcat6 May 30, 2026
66040b6
style: apply rustfmt indentation
bigtomcat6 May 30, 2026
58ab7f6
style: format rust library exports
bigtomcat6 May 30, 2026
1a9d247
style: format napi bindings
bigtomcat6 May 30, 2026
2428fbe
style: align rustfmt config with project indentation
bigtomcat6 May 30, 2026
53c5efe
style: align library exports with project indentation
bigtomcat6 May 30, 2026
79e9862
style: align napi bindings with project indentation
bigtomcat6 May 30, 2026
216ab7c
refactor: split rmb core into smaller modules
bigtomcat6 May 30, 2026
7fc1841
refactor: add formatter module placeholder
bigtomcat6 May 30, 2026
e773083
refactor: add rmb symbol helpers
bigtomcat6 May 30, 2026
eb62ee1
refactor: implement formatter module
bigtomcat6 May 30, 2026
35b33f0
refactor: add parser module placeholder
bigtomcat6 May 30, 2026
ef6da1c
refactor: implement amount parser module
bigtomcat6 May 30, 2026
fc4f17c
test: add rust formatter coverage
bigtomcat6 May 30, 2026
5c8a875
style: wrap parser lines for rustfmt
bigtomcat6 May 30, 2026
7dee831
style: wrap rmb error display line
bigtomcat6 May 30, 2026
7cf1d3b
style: wrap formatter digit array
bigtomcat6 May 30, 2026
d8ef0ee
style: wrap rmb test assertions
bigtomcat6 May 30, 2026
48b55b8
chore: remove unused placeholder symbols module
bigtomcat6 May 30, 2026
3246e55
style: wrap remaining rmb assertions
bigtomcat6 May 30, 2026
d18ebdc
fix: remove build dependency from feature list
bigtomcat6 May 30, 2026
6e259d7
fix: make napi-build a normal build dependency
bigtomcat6 May 30, 2026
e06f8d9
ci: ignore generated-style rmb modules in rustfmt
bigtomcat6 May 30, 2026
d56edd7
style: use default rustfmt configuration
bigtomcat6 May 30, 2026
a31eaac
style: apply default rustfmt to build script
bigtomcat6 May 30, 2026
4c3adf8
style: format lib rs
bigtomcat6 May 30, 2026
db13d1b
style: apply default rustfmt to napi bindings
bigtomcat6 May 30, 2026
1a363ba
style: apply default rustfmt to rmb core
bigtomcat6 May 30, 2026
77d4aca
style: apply default rustfmt to formatter module
bigtomcat6 May 30, 2026
79e5342
style: apply default rustfmt to parser module
bigtomcat6 May 30, 2026
f0f518b
ci: tighten PR Rust checks
bigtomcat6 May 30, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 36 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
name: CI

on:
pull_request:
branches:
- main
- 'refactor/**'

jobs:
rust:
name: Rust
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v4

- name: Install Rust toolchain
uses: dtolnay/rust-toolchain@stable
with:
components: rustfmt, clippy

- name: Check formatting
run: cargo fmt --all -- --check

- name: Compile check
run: cargo check --all-targets

- name: Run clippy
run: cargo clippy --all-targets -- -D warnings

- name: Run Rust tests
run: cargo test

- name: Check N-API feature build
run: cargo test --features napi
21 changes: 15 additions & 6 deletions Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,15 +1,24 @@
[package]
edition = "2021"
name = "rs-rmbtormb"
version = "0.0.0"
name = "rmb-upper"
version = "0.1.0"
description = "Convert RMB/CNY amounts to Chinese uppercase financial text."
license = "MIT"
repository = "https://github.com/bigtomcat6/rmbToRMB-rs"
readme = "README.md"
keywords = ["rmb", "cny", "chinese", "currency", "uppercase"]
categories = ["value-formatting", "internationalization"]

[lib]
crate-type = ["cdylib"]
crate-type = ["rlib", "cdylib"]

[features]
default = []
napi = ["dep:napi", "dep:napi-derive"]

[dependencies]
# Default enable napi4 feature, see https://nodejs.org/api/n-api.html#node-api-version-matrix
napi = { version = "2.12.2", default-features = false, features = ["napi4"] }
napi-derive = "2.12.2"
napi = { version = "2.12.2", default-features = false, features = ["napi4"], optional = true }
napi-derive = { version = "2.12.2", optional = true }

[build-dependencies]
napi-build = "2.0.1"
Expand Down
110 changes: 90 additions & 20 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,51 +1,121 @@
# rmbToRMB-rs
`Napi` to convert numbers into Chinese format based on `Rust`

这是一个基于`Rust`编写的数字转人民币大写形式的`N-API`库。
Convert RMB/CNY amounts into Chinese uppercase financial text.

## Building
这个项目现在由两层组成:

1. Using `pnpm` to install dependencies.
1. **Pure Rust library**: 可直接被 Rust backend、CLI、WASM 或其他 binding 复用。
2. **N-API wrapper**: 保留原来的 Node.js 原生扩展能力。

```bash
pnpm i
## Rust usage

The recommended API is `to_rmb_upper_from_cents`, because it represents money as an integer number of cents and avoids floating-point precision issues.

```rust
use rmb_upper::to_rmb_upper_from_cents;

fn main() {
let value = to_rmb_upper_from_cents(12_345).unwrap();
assert_eq!(value, "壹佰贰拾叁元肆角伍分");
}
```

```bash
pnpm add --save-dev @types/node
For decimal strings, use `to_rmb_upper_from_str`:

```rust
use rmb_upper::to_rmb_upper_from_str;

assert_eq!(to_rmb_upper_from_str("123.45").unwrap(), "壹佰贰拾叁元肆角伍分");
assert_eq!(to_rmb_upper_from_str("0.01").unwrap(), "零元壹分");
```

2. And Using `pnpm build` to build the project.
For cross-language bindings or platforms where large integers may lose precision, use `to_rmb_upper_from_cents_str`:

```bash
pnpm build
```rust
use rmb_upper::to_rmb_upper_from_cents_str;

assert_eq!(to_rmb_upper_from_cents_str("12345").unwrap(), "壹佰贰拾叁元肆角伍分");
```

The base code from `src/rmb_to_rmb.rs` will be compiled into `RS-rmbToRMB.SYSTEM_NAME.node`
The `f64` adapter exists for compatibility only:

So far, the `RS-rmbToRMB` has only been tested on `macOS`.
```rust
use rmb_upper::to_rmb_upper_from_f64;

assert_eq!(to_rmb_upper_from_f64(123.45).unwrap(), "壹佰贰拾叁元肆角伍分");
```

## Testing
Prefer the cents or string APIs for financial code.

## Supported range

The maximum supported integer part is:

```text
9999兆9999亿9999万9999
```

The maximum supported amount in cents is exposed as `MAX_CENTS`.

## Errors

The Rust APIs return `Result<String, RmbError>`. Possible error variants include:

Because the test code depends on `ts-jest`, you need to use `pnpm` to configure `ts-jest` first.
- `NegativeAmount`
- `NonFiniteAmount`
- `InvalidFormat`
- `TooManyDecimalPlaces`
- `TooLarge`

## Node.js / N-API usage

The original `rmbToRmb(number)` API is still available for compatibility. It accepts a JavaScript number and rounds to the nearest cent.

```ts
import { rmbToRmb } from '@rs/rmb-to-rmb'

rmbToRmb(123.45) // "壹佰贰拾叁元肆角伍分"
```

For deterministic formatting, prefer string-based APIs:

```ts
import { rmbToRmbFromCents, rmbToRmbFromString } from '@rs/rmb-to-rmb'

rmbToRmbFromCents('12345') // "壹佰贰拾叁元肆角伍分"
rmbToRmbFromString('123.45') // "壹佰贰拾叁元肆角伍分"
```

## Building

### Rust library

```bash
cargo build
cargo test
```

### N-API wrapper

```bash
pnpm add --save-dev @types/node @types/jest jest ts-jest nzh
pnpm i
pnpm build
```

The N-API build enables the `napi` feature and compiles the Rust core into a Node.js native addon.

## Testing

```bash
pnpm ts-jest config:init
cargo test
```

Then, you can run the test with `pnpm test`.
For JavaScript tests:

```bash
pnpm test
pnpm test:js
```

## Related projects

- [napi-rs](https://github.com/napi-rs/napi-rs)

8 changes: 5 additions & 3 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
extern crate napi_build;

#[cfg(feature = "napi")]
fn main() {
napi_build::setup();
napi_build::setup();
}

#[cfg(not(feature = "napi"))]
fn main() {}
17 changes: 16 additions & 1 deletion index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,20 @@

/* auto-generated by NAPI-RS */

/**
* Backward-compatible API that accepts a JavaScript number and rounds to the nearest cent.
* Prefer `rmbToRmbFromString` for deterministic financial formatting.
*/
export function rmbToRmb(n: number): string
export function sum(a: number, b: number): number

/**
* Converts an amount represented in cents into uppercase RMB text.
* The cents value is accepted as a string for large integer amounts.
*/
export function rmbToRmbFromCents(cents: string): string

/**
* Parses a decimal amount string and converts it into uppercase RMB text.
* This function rejects inputs with more than two decimal places instead of rounding.
*/
export function rmbToRmbFromString(amount: string): string
Loading
Loading