diff options
| author | 2026-02-25 02:06:07 +0800 | |
|---|---|---|
| committer | 2026-02-25 02:06:07 +0800 | |
| commit | 78ac61904d78d558d092eff08c9f261cbdb187e8 (patch) | |
| tree | 96f68d1f1554ee3a0532793afaaa52b0c73dcbec /packages/ui/src/lib/tsrs-utils.ts | |
| parent | 8ff3af6cb908fd824b512379dd21ed4f595ab6bb (diff) | |
| parent | 329734b23957b84cde2af459fa61c7385fb5b5f1 (diff) | |
| download | DropOut-78ac61904d78d558d092eff08c9f261cbdb187e8.tar.gz DropOut-78ac61904d78d558d092eff08c9f261cbdb187e8.zip | |
feat(ui): partial react rewrite (#77)
## Summary by Sourcery
Export backend data structures to TypeScript for the new React-based UI
and update CI to build additional targets.
New Features:
- Generate TypeScript definitions for core backend structs and enums
used by the UI.
- Now use our own Azure app(_DropOut_) to finish the authorize process.
Enhancements:
- Annotate existing Rust models with ts-rs metadata to control exported
TypeScript shapes, including tagged enums and opaque JSON fields.
Build:
- Add ts-rs as a dependency for generating TypeScript bindings from Rust
types.
CI:
- Extend the Semifold CI workflow to run on the dev branch and build
additional Linux musl and Windows GNU targets using cross where needed.
Diffstat (limited to 'packages/ui/src/lib/tsrs-utils.ts')
| -rw-r--r-- | packages/ui/src/lib/tsrs-utils.ts | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/packages/ui/src/lib/tsrs-utils.ts b/packages/ui/src/lib/tsrs-utils.ts new file mode 100644 index 0000000..f48f851 --- /dev/null +++ b/packages/ui/src/lib/tsrs-utils.ts @@ -0,0 +1,67 @@ +export type Maybe<T> = T | null | undefined; + +export function toNumber( + value: Maybe<number | bigint | string>, + fallback = 0, +): number { + if (value === null || value === undefined) return fallback; + + if (typeof value === "number") { + if (Number.isFinite(value)) return value; + return fallback; + } + + if (typeof value === "bigint") { + // safe conversion for typical values (timestamps, sizes). Might overflow for huge bigint. + return Number(value); + } + + if (typeof value === "string") { + const n = Number(value); + return Number.isFinite(n) ? n : fallback; + } + + return fallback; +} + +/** + * Like `toNumber` but ensures non-negative result (clamps at 0). + */ +export function toNonNegativeNumber( + value: Maybe<number | bigint | string>, + fallback = 0, +): number { + const n = toNumber(value, fallback); + return n < 0 ? 0 : n; +} + +export function toDate( + value: Maybe<number | bigint | string>, + opts?: { isSeconds?: boolean }, +): Date | null { + if (value === null || value === undefined) return null; + + const isSeconds = opts?.isSeconds ?? true; + + // accept bigint, number, numeric string + const n = toNumber(value, NaN); + if (Number.isNaN(n)) return null; + + const ms = isSeconds ? Math.floor(n) * 1000 : Math.floor(n); + return new Date(ms); +} + +/** + * Convert a binding boolean-ish value (0/1, "true"/"false", boolean) to boolean. + */ +export function toBoolean(value: unknown, fallback = false): boolean { + if (value === null || value === undefined) return fallback; + if (typeof value === "boolean") return value; + if (typeof value === "number") return value !== 0; + if (typeof value === "string") { + const s = value.toLowerCase().trim(); + if (s === "true" || s === "1") return true; + if (s === "false" || s === "0") return false; + } + return fallback; +} |