@amboras-dev/money-gate

中文文档
0.1.5发布于 2026/10/31UNLICENSEDTypeScriptESM + CJS近 30 天下载 6777

The money gate for Amboras repos: a dev-time checker that finds hand-written money code @amboras-dev/money replaces (power-of-ten scaling, float money math, Intl currency formatting, local currency tables, hardcoded currency fallbacks, money SQL, minor-un

原始使用文档
文档目录7 节
  1. Rules
  2. Retired helpers (MG008)
  3. Exemptions
  4. Baseline
  5. Config
  6. Adoption
  7. Commands

@amboras-dev/money-gate

The money gate: a dev-time checker that finds hand-written money code @amboras-dev/money replaces. Every finding names the package function to use instead. One runtime dependency, @amboras-dev/money (its currency registry); Node >= 20.

pnpm add -D @amboras-dev/money-gate
npx money-gate baseline          # once, when a repo adopts the gate
npx money-gate check --ratchet   # in CI
src/checkout.ts:4:30 MG002 hand-rolled x100 / x1000 money scaling -> fromMajor / toMajorDecimal / percentOf
src/checkout.ts MG002: 2 found, baseline allows 1
money-gate: 1 count(s) above the baseline, 0 below it

Rules

IdFindsUse instead
MG00110 **, Math.pow(10,, 1e2, 1e3, 1e7, and 10_000_000 next to a rate (elsewhere it is a limit)storageScale, fromMajor, toMajorDecimal, RATE_REF
MG002 (opt-in)* 100, / 100, * 1000, / 1000 with a money operand (amount, price, total, cost, fee, subtotal, balance, minor, cents, major, stored, value), not a time onefromMajor, toMajorDecimal, percentOf
MG003 (opt-in)toFixed( on, and parseFloat( / Number( of, a money valuetoMajorDecimal, readStored, parseImportAmount
MG004Intl.NumberFormat with style: 'currency' or currencyDisplay, toLocaleString with a currencyformatMoney
MG005an array, Set or object literal holding 3 or more currency codesthe registry, pspCurrencies
MG006?? 'USD', || 'EUR', currency = 'usd' defaults, SQL COALESCE(currency_code, 'usd')firstCurrency
MG007SQL: decimal_digits, THEN 1000 ELSE 100, POWER(10, ...), 10 ^ ..., jsonb_build_object('value', arithmetic on rate_numerator / rate_denominator, ROUND(..., 2) on money@amboras-dev/money/sql builders
MG008imports of retired helpers (table below), a local formatMoney / formatCurrency, big-number toNumber / toNum, the legacy currency shim outside legacyShimAllowthe function each finding names
MG009minor units, in cents, divide by 100, (cents) in strings, outside decorator calls (not when the text forbids the unit: "Never cents or minor units")MONEY_UNIT_SENTENCE, STORAGE_UNIT_SENTENCE
MG000an exemption without a rule id or a reasona complete exemption

Code rules read code only: comments, string literals and regex literals are blanked first by a small tokenizer. JSX closing tags (</p>, </>, <a href={x} />) are not read as regex literals. String rules read string and template literals; SQL rules read string literals and .sql files.

MG002 and MG003 are off by default: on their own they flag percentages, counts named total and DOM .value reads too often. Turn them on per repo with "rules": { "MG002": "on", "MG003": "on" } in the config.

Currency codes (MG005, MG006): an upper-case code always counts. A lower-case code, or a code that is also a common word or abbreviation (ALL, TOP, TRY, PHP, CAD, AMD, BTN and the rest of WORD_COLLISIONS in src/currencies.ts), counts only in a currency context. In code that means the statement before it names a currency (currency, currencies, ZERO_DECIMAL...): store.currency ?? 'usd' and const zeroDecimalCurrencies = ['jpy', ...] count, filter ?? 'all' and ['all', 'top', 'try'] do not. A statement that is the first in a block also reads the block's header, so function normalizeCurrency(code) { return code ?? 'usd' } counts. A fallback inside a template literal (storefront code generated as text) is read in the template's own text. In SQL COALESCE, the first arguments must mention a currency or a code column.

MG009 skips strings inside a decorator call's arguments (@ApiProperty({ description: 'Amount in cents' }), any @Name(...)): those document a wire field for Swagger/OpenAPI, not wording for the model. Strings in tool schemas (z.number().describe('...')) and prompts are still checked.

Retired helpers (MG008)

HelperUse instead
divisorForstorageScale(code)
storageDivisorForDigitsstorageScale(code) (keyed by the code, not the digits); in SQL the @amboras-dev/money/sql builders
fractionDigitsForstorageDigits(code) for how it is stored, displayDigits(code) for what to show
isoFractionDigitspspWireDigits(psp, code) from @amboras-dev/money/wire
toMinorUnitsfromMajor(major, code)
toMajorUnitstoMajorDecimal(roundToUnit(readStoredDecimal(raw), code)): Medusa totals can be fractional (sevDesk, GA4, invoices) and readStored throws on fractions
readAmountNumber, big-number toNumber / toNumreadStoredDecimal(raw) (keeps fractions), or readStored(raw, code) for a whole stored amount
a local formatMoney / formatCurrencyformatMoney(m) from @amboras-dev/money
the legacy currency shimcurrencyCode(value) or firstCurrency(...)
toStorageAmount (@amboras-dev/capability-kit)fromMajor(major, code).amount
fromStorageAmount (@amboras-dev/capability-kit)toMajorDecimal(readStored(stored, code)), or toMajorNumber for a float
storageScale (@amboras-dev/capability-kit)storageScale(code) from @amboras-dev/money
fractionDigits (@amboras-dev/capability-kit)storageDigits(code)
moneyView (@amboras-dev/capability-kit)moneyView(readStored(stored, code)) from @amboras-dev/money/ai

The capability-kit helpers are flagged only when imported from @amboras-dev/capability-kit; the package's own storageScale and moneyView are the replacements.

Exemptions

// money-gate-exempt: MG001 the one legacy scale kept until the wire migration
const LEGACY_SCALE = 10 ** 2;

The marker covers its own line and the two lines below it, for the named rule only. It counts only inside a comment (//, /* */, or -- in SQL); the same text inside a string literal is data and exempts nothing. A rule id and a reason are mandatory; without them the marker is an MG000 violation and exempts nothing. The old money-scale-exempt: <reason> marker counts as an MG001 exemption during migration.

Baseline

money-gate.baseline.json holds the violations a repo had when it adopted the gate, counted per file and rule. check fails on any count above the baseline (a new violation); check --ratchet also fails on a count below it until the baseline is lowered, so the baseline only shrinks. baseline writes the current counts and refuses to raise any count unless --force (which shows up in review).

The baseline (version 2) also stores a fingerprint per file and rule: the source text of each violating line, trimmed, sorted and hashed (SHA-256, first 16 hex digits). It does not change when lines move within a file or the file is renamed; it changes when any violating line is added, removed or edited.

A pure rename or move keeps its counts. A file the baseline does not know inherits the entry of a baseline file that is no longer scanned only when, for every rule, both the count and the fingerprint are equal. Then check passes and prints the rename, and baseline rewrites the entry at the new path without --force. check --ratchet fails until the baseline is refreshed, so a stale path cannot be reused later. Deleting a baselined file and adding an unrelated one with the same counts is not a rename (the lines differ), so its violations fail check as new ones. A rename that also adds, removes or edits a violating line is not carried: fix the violation, or baseline --force. A version 1 baseline (counts only) is still read, but nothing is carried from it; money-gate baseline upgrades it.

Config

money-gate.config.json at the repo root (all keys optional):

{
    "include": ["src/**/*.ts", "scripts/**/*.ts"],
    "sql": ["src/migrations/**/*.sql"],
    "exclude": ["src/generated/**"],
    "legacyShimAllow": ["src/modules/payments/stripe/**"],
    "baseline": "money-gate.baseline.json",
    "rules": { "MG002": "on", "MG003": "on" }
}

include defaults to src/**/*.{ts,tsx,js,jsx,mjs,cjs}. A config that selects no file at all is a config error (exit 2) naming the globs and the root, never an "ok": a repo whose code is not under src/ must set include. rules switches MG001-MG009 "on" or "off" from their defaults (MG002 and MG003 start off).

Never scanned: node_modules, dist, *.generated.ts and test files (*.spec.*, *.test.*), which may build fixtures. Globs support **, *, ? and {a,b}. Negation (!pattern) is not supported and is a config error rather than a silent no-op: list the pattern under exclude.

Adoption

  1. Add a money-gate.config.json whose include (and sql) select the repo's code; the gate refuses to run on an empty selection.
  2. npx money-gate baseline once, commit the baseline, and run npx money-gate check --ratchet in CI.
  3. Retire the repo's own money guards as their rules land here. Medusa: src/common/utils/money-conversion-sites.spec.ts requires the CASE WHEN ... decimal_digits ... THEN 1000 ELSE 100 END storage divisor in analytics.service.ts, which MG007 bans. Its adoption PR rewrites that spec to assert the @amboras-dev/money/sql builders instead, and drops its power-of-ten checks, which MG001 (code) and MG007 (POWER(10, ...), 10 ^ ... in SQL) now cover.

Commands

  • money-gate check [--ratchet] [--json] [--root <dir>] [--config <file>]: exit 0 clean, 1 violations, 2 usage or config error.
  • money-gate baseline [--force] [--root <dir>] [--config <file>].
  • The library exports the same pieces (run, scanSource, scanRepo, RULES, loadConfig, baseline helpers).

版本与发布记录

@amboras-dev/money-gate 共发布 7 个版本,首次发布于 2026/10/26;过去 12 个月发布了 7 个版本。

版本发布日期距今
0.1.5latest2026/10/317 天前
0.1.42026/10/2810 天前
0.1.32026/10/2711 天前
0.1.22026/10/2711 天前
0.1.12026/10/2612 天前
0.1.02026/10/2612 天前

关于 @amboras-dev/money-gate 的常见问题

@amboras-dev/money-gate 是什么?

The money gate for Amboras repos: a dev-time checker that finds hand-written money code @amboras-dev/money replaces (power-of-ten scaling, float money math, Intl currency formatting, local currency tables, hardcoded currency fallbacks, money SQL, minor-un

如何安装 @amboras-dev/money-gate?

在项目目录运行 npm install @amboras-dev/money-gate,或使用 pnpm add / yarn add / bun add。它还提供命令行工具 money-gate,可以用 npx money-gate 直接运行。

@amboras-dev/money-gate 支持 TypeScript 吗?

支持。包内自带 TypeScript 类型声明(package.json 声明了 types 入口),安装后即可获得类型提示,无需再安装 @types 包。

@amboras-dev/money-gate 支持 ESM 还是 CommonJS?

同时提供 ES Module 与 CommonJS 入口,import 和 require() 都可以使用,打包工具会自动选择合适的版本。

@amboras-dev/money-gate 需要什么版本的 Node.js?

package.json 的 engines 字段要求 Node.js >=20。版本不符时 npm 默认只给出警告,开启 engine-strict 后会拒绝安装。

@amboras-dev/money-gate 可以商用吗?

@amboras-dev/money-gate 使用 UNLICENSED 许可。作者声明为 UNLICENSED,即不授予公开使用许可(与公共领域的 Unlicense 不同)。使用前需获得作者授权。以上为概括,不构成法律意见,请以许可原文为准。

@amboras-dev/money-gate 的下载量有多少?

根据 npm 官方下载统计,@amboras-dev/money-gate 在 2026/10/06 – 2026/11/04 这 30 天内被下载 6,777 次,日均约 226 次。下载量会把 CI 构建、镜像同步和作为其他包依赖的安装一并计入,适合横向比较热度,不能直接等同于使用人数。

@amboras-dev/money-gate 还在维护吗?

最新版本 0.1.5 发布于 2026/10/31(7 天前);至今共发布 7 个版本,其中过去 12 个月发布了 7 个;首次发布于 2026/10/26。发布频率只是参考信号:功能稳定的工具可能很少需要更新,建议结合源码仓库的 issue 和提交记录判断。