@ryuzaki13/react-foundation-lib 2.9.0 → 2.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (33) hide show
  1. package/README.md +1 -0
  2. package/dist/decimal/addDecimals.d.ts +4 -0
  3. package/dist/decimal/addDecimals.d.ts.map +1 -0
  4. package/dist/decimal/alignDecimalParts.d.ts +8 -0
  5. package/dist/decimal/alignDecimalParts.d.ts.map +1 -0
  6. package/dist/decimal/compareDecimalRatios.d.ts +4 -0
  7. package/dist/decimal/compareDecimalRatios.d.ts.map +1 -0
  8. package/dist/decimal/compareDecimals.d.ts +4 -0
  9. package/dist/decimal/compareDecimals.d.ts.map +1 -0
  10. package/dist/decimal/index.d.ts +10 -0
  11. package/dist/decimal/index.d.ts.map +1 -0
  12. package/dist/decimal/index.js +108 -0
  13. package/dist/decimal/index.js.map +1 -0
  14. package/dist/decimal/isCanonicalDecimal.d.ts +4 -0
  15. package/dist/decimal/isCanonicalDecimal.d.ts.map +1 -0
  16. package/dist/decimal/multiplyDecimals.d.ts +4 -0
  17. package/dist/decimal/multiplyDecimals.d.ts.map +1 -0
  18. package/dist/decimal/normalizeDecimal.d.ts +4 -0
  19. package/dist/decimal/normalizeDecimal.d.ts.map +1 -0
  20. package/dist/decimal/readDecimalParts.d.ts +4 -0
  21. package/dist/decimal/readDecimalParts.d.ts.map +1 -0
  22. package/dist/decimal/resolveDecimalMaxLength.d.ts +4 -0
  23. package/dist/decimal/resolveDecimalMaxLength.d.ts.map +1 -0
  24. package/dist/decimal/subtractDecimals.d.ts +4 -0
  25. package/dist/decimal/subtractDecimals.d.ts.map +1 -0
  26. package/dist/decimal/sumDecimals.d.ts +4 -0
  27. package/dist/decimal/sumDecimals.d.ts.map +1 -0
  28. package/dist/decimal/types.d.ts +16 -0
  29. package/dist/decimal/types.d.ts.map +1 -0
  30. package/dist/decimal/writeDecimalParts.d.ts +4 -0
  31. package/dist/decimal/writeDecimalParts.d.ts.map +1 -0
  32. package/package.json +5 -1
  33. package/src/decimal/README.md +43 -0
package/README.md CHANGED
@@ -111,6 +111,7 @@ npm run pack:dry-run
111
111
  | `/crypto` | [`crypto/README.mdx`](./src/crypto/README.mdx) |
112
112
  | `/currency` | [`currency/README.mdx`](./src/currency/README.mdx) |
113
113
  | `/date-segments` | [`date-segments/README.mdx`](./src/date-segments/README.mdx) |
114
+ | `/decimal` | [Точная десятичная арифметика](./src/decimal/README.md) |
114
115
  | `/dom` | [`dom/README.mdx`](./src/dom/README.mdx) |
115
116
  | `/error` | [`error/README.mdx`](./src/error/README.mdx) |
116
117
  | `/error-report` | [`error-report/README.mdx`](./src/error-report/README.mdx) |
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions } from "./types";
2
+ /** Складывает значения без IEEE 754 и возвращает каноническую строку. */
3
+ export declare function addDecimals(left: string, right: string, options?: DecimalOptions): string;
4
+ //# sourceMappingURL=addDecimals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"addDecimals.d.ts","sourceRoot":"","sources":["../../src/decimal/addDecimals.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,yEAAyE;AACzE,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAIzF"}
@@ -0,0 +1,8 @@
1
+ import type { DecimalParts } from "./types";
2
+ /** Выравнивает только разрядность ограниченных операндов; глобального кеша степеней нет. */
3
+ export declare function alignDecimalParts(left: DecimalParts, right: DecimalParts): Readonly<{
4
+ left: bigint;
5
+ right: bigint;
6
+ scale: number;
7
+ }>;
8
+ //# sourceMappingURL=alignDecimalParts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"alignDecimalParts.d.ts","sourceRoot":"","sources":["../../src/decimal/alignDecimalParts.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5C,4FAA4F;AAC5F,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,GAAG,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAQnI"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalComparison, DecimalOptions, DecimalRatio } from "./types";
2
+ /** Сравнивает отношения перекрёстным умножением. Периодическая дробь не делится и не округляется. */
3
+ export declare function compareDecimalRatios(left: DecimalRatio, right: DecimalRatio, options?: DecimalOptions): DecimalComparison;
4
+ //# sourceMappingURL=compareDecimalRatios.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compareDecimalRatios.d.ts","sourceRoot":"","sources":["../../src/decimal/compareDecimalRatios.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE/E,qGAAqG;AACrG,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,iBAAiB,CAkBzH"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalComparison, DecimalOptions } from "./types";
2
+ /** Сравнивает исходные значения, включая разрядность за пределами безопасного number. */
3
+ export declare function compareDecimals(left: string, right: string, options?: DecimalOptions): DecimalComparison;
4
+ //# sourceMappingURL=compareDecimals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compareDecimals.d.ts","sourceRoot":"","sources":["../../src/decimal/compareDecimals.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,iBAAiB,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAEjE,yFAAyF;AACzF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,iBAAiB,CAIxG"}
@@ -0,0 +1,10 @@
1
+ export { addDecimals } from "./addDecimals";
2
+ export { compareDecimalRatios } from "./compareDecimalRatios";
3
+ export { compareDecimals } from "./compareDecimals";
4
+ export { isCanonicalDecimal } from "./isCanonicalDecimal";
5
+ export { multiplyDecimals } from "./multiplyDecimals";
6
+ export { normalizeDecimal } from "./normalizeDecimal";
7
+ export { subtractDecimals } from "./subtractDecimals";
8
+ export { sumDecimals } from "./sumDecimals";
9
+ export type { DecimalComparison, DecimalOptions, DecimalRatio } from "./types";
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/decimal/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,kBAAkB,EAAE,MAAM,sBAAsB,CAAC;AAC1D,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAC;AACtD,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC5C,YAAY,EAAE,iBAAiB,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC"}
@@ -0,0 +1,108 @@
1
+ //#region src/decimal/alignDecimalParts.ts
2
+ function e(e, t) {
3
+ let n = Math.max(e.scale, t.scale);
4
+ return {
5
+ left: e.coefficient * 10n ** BigInt(n - e.scale),
6
+ right: t.coefficient * 10n ** BigInt(n - t.scale),
7
+ scale: n
8
+ };
9
+ }
10
+ //#endregion
11
+ //#region src/decimal/resolveDecimalMaxLength.ts
12
+ function t(e) {
13
+ let t = e?.maxLength ?? 512;
14
+ if (!Number.isSafeInteger(t) || t <= 0) throw RangeError("Предел длины десятичного значения должен быть положительным безопасным целым числом.");
15
+ return t;
16
+ }
17
+ //#endregion
18
+ //#region src/decimal/isCanonicalDecimal.ts
19
+ function n(e, n) {
20
+ let r = t(n);
21
+ return typeof e == "string" && e.length <= r && /^(?:0|-?(?:[1-9]\d*(?:\.\d*[1-9])?|0\.\d*[1-9]))(?![\s\S])/u.test(e);
22
+ }
23
+ //#endregion
24
+ //#region src/decimal/readDecimalParts.ts
25
+ function r(e, t) {
26
+ if (!n(e, t)) throw TypeError("Ожидалась каноническая десятичная строка в пределах допустимой длины.");
27
+ let r = e.indexOf(".");
28
+ return {
29
+ coefficient: BigInt(e.replace(".", "")),
30
+ scale: r === -1 ? 0 : e.length - r - 1
31
+ };
32
+ }
33
+ //#endregion
34
+ //#region src/decimal/writeDecimalParts.ts
35
+ function i(e, n) {
36
+ let r = t(n);
37
+ if (e.coefficient === 0n) return "0";
38
+ let i = e.coefficient < 0n, a = (i ? -e.coefficient : e.coefficient).toString().padStart(e.scale + 1, "0"), o = a.length - e.scale, s = e.scale === 0 ? a : `${a.slice(0, o)}.${a.slice(o)}`.replace(/\.?0+$/u, ""), c = i ? `-${s}` : s;
39
+ if (c.length > r) throw RangeError("Результат десятичного вычисления превысил допустимую длину.");
40
+ return c;
41
+ }
42
+ //#endregion
43
+ //#region src/decimal/addDecimals.ts
44
+ function a(t, n, a) {
45
+ let o = e(r(t, a), r(n, a));
46
+ return i({
47
+ coefficient: o.left + o.right,
48
+ scale: o.scale
49
+ }, a);
50
+ }
51
+ //#endregion
52
+ //#region src/decimal/compareDecimalRatios.ts
53
+ function o(t, n, i) {
54
+ let a = r(t.numerator, i), o = r(t.denominator, i), s = r(n.numerator, i), c = r(n.denominator, i);
55
+ if (o.coefficient <= 0n || c.coefficient <= 0n) throw RangeError("Знаменатель отношения должен быть строго положительным.");
56
+ let l = e({
57
+ coefficient: a.coefficient * c.coefficient,
58
+ scale: a.scale + c.scale
59
+ }, {
60
+ coefficient: s.coefficient * o.coefficient,
61
+ scale: s.scale + o.scale
62
+ });
63
+ return l.left < l.right ? -1 : +(l.left > l.right);
64
+ }
65
+ //#endregion
66
+ //#region src/decimal/compareDecimals.ts
67
+ function s(t, n, i) {
68
+ let a = e(r(t, i), r(n, i));
69
+ return a.left < a.right ? -1 : +(a.left > a.right);
70
+ }
71
+ //#endregion
72
+ //#region src/decimal/multiplyDecimals.ts
73
+ function c(e, t, n) {
74
+ let a = r(e, n), o = r(t, n);
75
+ return i({
76
+ coefficient: a.coefficient * o.coefficient,
77
+ scale: a.scale + o.scale
78
+ }, n);
79
+ }
80
+ //#endregion
81
+ //#region src/decimal/normalizeDecimal.ts
82
+ function l(e, n) {
83
+ let r = t(n);
84
+ if (typeof e != "string" || e.length > r || !/^-?\d+(?:\.\d+)?(?![\s\S])/u.test(e)) throw TypeError("Ожидалась ограниченная конечная десятичная строка с точкой.");
85
+ let i = e.startsWith("-"), [a, o = ""] = (i ? e.slice(1) : e).split("."), s = a.replace(/^0+(?=\d)/u, ""), c = o.replace(/0+$/u, ""), l = c ? `${s}.${c}` : s;
86
+ return i && l !== "0" ? `-${l}` : l;
87
+ }
88
+ //#endregion
89
+ //#region src/decimal/subtractDecimals.ts
90
+ function u(t, n, a) {
91
+ let o = e(r(t, a), r(n, a));
92
+ return i({
93
+ coefficient: o.left - o.right,
94
+ scale: o.scale
95
+ }, a);
96
+ }
97
+ //#endregion
98
+ //#region src/decimal/sumDecimals.ts
99
+ function d(e, n) {
100
+ t(n);
101
+ let r = "0";
102
+ for (let t of e) r = a(r, t, n);
103
+ return r;
104
+ }
105
+ //#endregion
106
+ export { a as addDecimals, o as compareDecimalRatios, s as compareDecimals, n as isCanonicalDecimal, c as multiplyDecimals, l as normalizeDecimal, u as subtractDecimals, d as sumDecimals };
107
+
108
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","names":[],"sources":["../../src/decimal/alignDecimalParts.ts","../../src/decimal/resolveDecimalMaxLength.ts","../../src/decimal/isCanonicalDecimal.ts","../../src/decimal/readDecimalParts.ts","../../src/decimal/writeDecimalParts.ts","../../src/decimal/addDecimals.ts","../../src/decimal/compareDecimalRatios.ts","../../src/decimal/compareDecimals.ts","../../src/decimal/multiplyDecimals.ts","../../src/decimal/normalizeDecimal.ts","../../src/decimal/subtractDecimals.ts","../../src/decimal/sumDecimals.ts"],"sourcesContent":["import type { DecimalParts } from \"./types\";\n\n/** Выравнивает только разрядность ограниченных операндов; глобального кеша степеней нет. */\nexport function alignDecimalParts(left: DecimalParts, right: DecimalParts): Readonly<{ left: bigint; right: bigint; scale: number }> {\n\tconst scale = Math.max(left.scale, right.scale);\n\n\treturn {\n\t\tleft: left.coefficient * 10n ** BigInt(scale - left.scale),\n\t\tright: right.coefficient * 10n ** BigInt(scale - right.scale),\n\t\tscale\n\t};\n}\n","import type { DecimalOptions } from \"./types\";\n\n/** Проверяет предел до разбора числа и выделения вычислительных буферов. */\nexport function resolveDecimalMaxLength(options?: DecimalOptions): number {\n\tconst maxLength = options?.maxLength ?? 512;\n\n\tif (!Number.isSafeInteger(maxLength) || maxLength <= 0) {\n\t\tthrow new RangeError(\"Предел длины десятичного значения должен быть положительным безопасным целым числом.\");\n\t}\n\n\treturn maxLength;\n}\n","import { resolveDecimalMaxLength } from \"./resolveDecimalMaxLength\";\n\nimport type { DecimalOptions } from \"./types\";\n\n/** Runtime-проверка для внешних данных без преобразования значащих цифр в number. */\nexport function isCanonicalDecimal(value: unknown, options?: DecimalOptions): value is string {\n\tconst maxLength = resolveDecimalMaxLength(options);\n\n\treturn (\n\t\ttypeof value === \"string\" && value.length <= maxLength && /^(?:0|-?(?:[1-9]\\d*(?:\\.\\d*[1-9])?|0\\.\\d*[1-9]))(?![\\s\\S])/u.test(value)\n\t);\n}\n","import { isCanonicalDecimal } from \"./isCanonicalDecimal\";\n\nimport type { DecimalOptions, DecimalParts } from \"./types\";\n\n/** Арифметика принимает только канонические строки; нормализация принадлежит входной границе. */\nexport function readDecimalParts(value: string, options?: DecimalOptions): DecimalParts {\n\tif (!isCanonicalDecimal(value, options)) {\n\t\tthrow new TypeError(\"Ожидалась каноническая десятичная строка в пределах допустимой длины.\");\n\t}\n\n\tconst point = value.indexOf(\".\");\n\n\treturn {\n\t\tcoefficient: BigInt(value.replace(\".\", \"\")),\n\t\tscale: point === -1 ? 0 : value.length - point - 1\n\t};\n}\n","import { resolveDecimalMaxLength } from \"./resolveDecimalMaxLength\";\n\nimport type { DecimalOptions, DecimalParts } from \"./types\";\n\n/** Канонизирует результат после точного вычисления и отклоняет overflow вместо округления. */\nexport function writeDecimalParts(parts: DecimalParts, options?: DecimalOptions): string {\n\tconst maxLength = resolveDecimalMaxLength(options);\n\n\tif (parts.coefficient === 0n) {\n\t\treturn \"0\";\n\t}\n\n\tconst negative = parts.coefficient < 0n;\n\tconst magnitude = negative ? -parts.coefficient : parts.coefficient;\n\tconst digits = magnitude.toString().padStart(parts.scale + 1, \"0\");\n\tconst point = digits.length - parts.scale;\n\tconst unsigned = parts.scale === 0 ? digits : `${digits.slice(0, point)}.${digits.slice(point)}`.replace(/\\.?0+$/u, \"\");\n\tconst result = negative ? `-${unsigned}` : unsigned;\n\n\tif (result.length > maxLength) {\n\t\tthrow new RangeError(\"Результат десятичного вычисления превысил допустимую длину.\");\n\t}\n\n\treturn result;\n}\n","import { alignDecimalParts } from \"./alignDecimalParts\";\nimport { readDecimalParts } from \"./readDecimalParts\";\nimport { writeDecimalParts } from \"./writeDecimalParts\";\n\nimport type { DecimalOptions } from \"./types\";\n\n/** Складывает значения без IEEE 754 и возвращает каноническую строку. */\nexport function addDecimals(left: string, right: string, options?: DecimalOptions): string {\n\tconst aligned = alignDecimalParts(readDecimalParts(left, options), readDecimalParts(right, options));\n\n\treturn writeDecimalParts({ coefficient: aligned.left + aligned.right, scale: aligned.scale }, options);\n}\n","import { alignDecimalParts } from \"./alignDecimalParts\";\nimport { readDecimalParts } from \"./readDecimalParts\";\n\nimport type { DecimalComparison, DecimalOptions, DecimalRatio } from \"./types\";\n\n/** Сравнивает отношения перекрёстным умножением. Периодическая дробь не делится и не округляется. */\nexport function compareDecimalRatios(left: DecimalRatio, right: DecimalRatio, options?: DecimalOptions): DecimalComparison {\n\tconst leftNumerator = readDecimalParts(left.numerator, options);\n\tconst leftDenominator = readDecimalParts(left.denominator, options);\n\tconst rightNumerator = readDecimalParts(right.numerator, options);\n\tconst rightDenominator = readDecimalParts(right.denominator, options);\n\n\tif (leftDenominator.coefficient <= 0n || rightDenominator.coefficient <= 0n) {\n\t\tthrow new RangeError(\"Знаменатель отношения должен быть строго положительным.\");\n\t}\n\n\t// Произведения приватные: их разрядность ограничена четырьмя проверенными операндами,\n\t// но может превышать длину сериализуемого числа. Проверять их как внешний результат нельзя.\n\tconst aligned = alignDecimalParts(\n\t\t{ coefficient: leftNumerator.coefficient * rightDenominator.coefficient, scale: leftNumerator.scale + rightDenominator.scale },\n\t\t{ coefficient: rightNumerator.coefficient * leftDenominator.coefficient, scale: rightNumerator.scale + leftDenominator.scale }\n\t);\n\n\treturn aligned.left < aligned.right ? -1 : aligned.left > aligned.right ? 1 : 0;\n}\n","import { alignDecimalParts } from \"./alignDecimalParts\";\nimport { readDecimalParts } from \"./readDecimalParts\";\n\nimport type { DecimalComparison, DecimalOptions } from \"./types\";\n\n/** Сравнивает исходные значения, включая разрядность за пределами безопасного number. */\nexport function compareDecimals(left: string, right: string, options?: DecimalOptions): DecimalComparison {\n\tconst aligned = alignDecimalParts(readDecimalParts(left, options), readDecimalParts(right, options));\n\n\treturn aligned.left < aligned.right ? -1 : aligned.left > aligned.right ? 1 : 0;\n}\n","import { readDecimalParts } from \"./readDecimalParts\";\nimport { writeDecimalParts } from \"./writeDecimalParts\";\n\nimport type { DecimalOptions } from \"./types\";\n\n/** Точное умножение не устанавливает фиксированную сетку дробности. */\nexport function multiplyDecimals(left: string, right: string, options?: DecimalOptions): string {\n\tconst first = readDecimalParts(left, options);\n\tconst second = readDecimalParts(right, options);\n\n\treturn writeDecimalParts({ coefficient: first.coefficient * second.coefficient, scale: first.scale + second.scale }, options);\n}\n","import { resolveDecimalMaxLength } from \"./resolveDecimalMaxLength\";\n\nimport type { DecimalOptions } from \"./types\";\n\n/** Убирает лишние нули. Пробелы, запятую, плюс и экспоненту обрабатывает владелец внешнего формата. */\nexport function normalizeDecimal(value: string, options?: DecimalOptions): string {\n\tconst maxLength = resolveDecimalMaxLength(options);\n\n\tif (typeof value !== \"string\" || value.length > maxLength || !/^-?\\d+(?:\\.\\d+)?(?![\\s\\S])/u.test(value)) {\n\t\tthrow new TypeError(\"Ожидалась ограниченная конечная десятичная строка с точкой.\");\n\t}\n\n\tconst negative = value.startsWith(\"-\");\n\tconst unsigned = negative ? value.slice(1) : value;\n\tconst [integer, fraction = \"\"] = unsigned.split(\".\");\n\tconst whole = integer.replace(/^0+(?=\\d)/u, \"\");\n\tconst fractional = fraction.replace(/0+$/u, \"\");\n\tconst magnitude = fractional ? `${whole}.${fractional}` : whole;\n\n\treturn negative && magnitude !== \"0\" ? `-${magnitude}` : magnitude;\n}\n","import { alignDecimalParts } from \"./alignDecimalParts\";\nimport { readDecimalParts } from \"./readDecimalParts\";\nimport { writeDecimalParts } from \"./writeDecimalParts\";\n\nimport type { DecimalOptions } from \"./types\";\n\n/** Сохраняет знак остатка; предметные ограничения отрицательных значений находятся у consumer. */\nexport function subtractDecimals(left: string, right: string, options?: DecimalOptions): string {\n\tconst aligned = alignDecimalParts(readDecimalParts(left, options), readDecimalParts(right, options));\n\n\treturn writeDecimalParts({ coefficient: aligned.left - aligned.right, scale: aligned.scale }, options);\n}\n","import { addDecimals } from \"./addDecimals\";\nimport { resolveDecimalMaxLength } from \"./resolveDecimalMaxLength\";\n\nimport type { DecimalOptions } from \"./types\";\n\n/** Читает iterable один раз и проверяет каждый промежуточный итог; пустой набор даёт ноль. */\nexport function sumDecimals(values: Iterable<string>, options?: DecimalOptions): string {\n\tresolveDecimalMaxLength(options);\n\tlet total = \"0\";\n\n\tfor (const value of values) {\n\t\ttotal = addDecimals(total, value, options);\n\t}\n\n\treturn total;\n}\n"],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions } from "./types";
2
+ /** Runtime-проверка для внешних данных без преобразования значащих цифр в number. */
3
+ export declare function isCanonicalDecimal(value: unknown, options?: DecimalOptions): value is string;
4
+ //# sourceMappingURL=isCanonicalDecimal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"isCanonicalDecimal.d.ts","sourceRoot":"","sources":["../../src/decimal/isCanonicalDecimal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,qFAAqF;AACrF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,KAAK,IAAI,MAAM,CAM5F"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions } from "./types";
2
+ /** Точное умножение не устанавливает фиксированную сетку дробности. */
3
+ export declare function multiplyDecimals(left: string, right: string, options?: DecimalOptions): string;
4
+ //# sourceMappingURL=multiplyDecimals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"multiplyDecimals.d.ts","sourceRoot":"","sources":["../../src/decimal/multiplyDecimals.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,uEAAuE;AACvE,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAK9F"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions } from "./types";
2
+ /** Убирает лишние нули. Пробелы, запятую, плюс и экспоненту обрабатывает владелец внешнего формата. */
3
+ export declare function normalizeDecimal(value: string, options?: DecimalOptions): string;
4
+ //# sourceMappingURL=normalizeDecimal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"normalizeDecimal.d.ts","sourceRoot":"","sources":["../../src/decimal/normalizeDecimal.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,uGAAuG;AACvG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAehF"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions, DecimalParts } from "./types";
2
+ /** Арифметика принимает только канонические строки; нормализация принадлежит входной границе. */
3
+ export declare function readDecimalParts(value: string, options?: DecimalOptions): DecimalParts;
4
+ //# sourceMappingURL=readDecimalParts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"readDecimalParts.d.ts","sourceRoot":"","sources":["../../src/decimal/readDecimalParts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5D,iGAAiG;AACjG,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,YAAY,CAWtF"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions } from "./types";
2
+ /** Проверяет предел до разбора числа и выделения вычислительных буферов. */
3
+ export declare function resolveDecimalMaxLength(options?: DecimalOptions): number;
4
+ //# sourceMappingURL=resolveDecimalMaxLength.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"resolveDecimalMaxLength.d.ts","sourceRoot":"","sources":["../../src/decimal/resolveDecimalMaxLength.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,4EAA4E;AAC5E,wBAAgB,uBAAuB,CAAC,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAQxE"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions } from "./types";
2
+ /** Сохраняет знак остатка; предметные ограничения отрицательных значений находятся у consumer. */
3
+ export declare function subtractDecimals(left: string, right: string, options?: DecimalOptions): string;
4
+ //# sourceMappingURL=subtractDecimals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"subtractDecimals.d.ts","sourceRoot":"","sources":["../../src/decimal/subtractDecimals.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,kGAAkG;AAClG,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAI9F"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions } from "./types";
2
+ /** Читает iterable один раз и проверяет каждый промежуточный итог; пустой набор даёт ноль. */
3
+ export declare function sumDecimals(values: Iterable<string>, options?: DecimalOptions): string;
4
+ //# sourceMappingURL=sumDecimals.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sumDecimals.d.ts","sourceRoot":"","sources":["../../src/decimal/sumDecimals.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,8FAA8F;AAC9F,wBAAgB,WAAW,CAAC,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAStF"}
@@ -0,0 +1,16 @@
1
+ /** Лимит относится к строке целиком, включая знак и точку; точность не округляется. */
2
+ export type DecimalOptions = Readonly<{
3
+ maxLength?: number;
4
+ }>;
5
+ export type DecimalComparison = -1 | 0 | 1;
6
+ /** Отношение сохраняется без деления: знаменатель должен быть строго положительным. */
7
+ export type DecimalRatio = Readonly<{
8
+ numerator: string;
9
+ denominator: string;
10
+ }>;
11
+ /** Приватное вычислительное представление, не входящее в публичный entrypoint. */
12
+ export type DecimalParts = Readonly<{
13
+ coefficient: bigint;
14
+ scale: number;
15
+ }>;
16
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/decimal/types.ts"],"names":[],"mappings":"AAAA,uFAAuF;AACvF,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAAE,SAAS,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAE9D,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAE3C,uFAAuF;AACvF,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAAE,SAAS,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEhF,kFAAkF;AAClF,MAAM,MAAM,YAAY,GAAG,QAAQ,CAAC;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC"}
@@ -0,0 +1,4 @@
1
+ import type { DecimalOptions, DecimalParts } from "./types";
2
+ /** Канонизирует результат после точного вычисления и отклоняет overflow вместо округления. */
3
+ export declare function writeDecimalParts(parts: DecimalParts, options?: DecimalOptions): string;
4
+ //# sourceMappingURL=writeDecimalParts.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"writeDecimalParts.d.ts","sourceRoot":"","sources":["../../src/decimal/writeDecimalParts.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AAE5D,8FAA8F;AAC9F,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,YAAY,EAAE,OAAO,CAAC,EAAE,cAAc,GAAG,MAAM,CAmBvF"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ryuzaki13/react-foundation-lib",
3
- "version": "2.9.0",
3
+ "version": "2.10.0",
4
4
  "description": "Reusable React and TypeScript foundation utilities, hooks, and primitives.",
5
5
  "license": "MIT",
6
6
  "author": "Ryuzaki13",
@@ -61,6 +61,10 @@
61
61
  "types": "./dist/date-segments/index.d.ts",
62
62
  "import": "./dist/date-segments/index.js"
63
63
  },
64
+ "./decimal": {
65
+ "types": "./dist/decimal/index.d.ts",
66
+ "import": "./dist/decimal/index.js"
67
+ },
64
68
  "./dom": {
65
69
  "types": "./dist/dom/index.d.ts",
66
70
  "import": "./dist/dom/index.js"
@@ -0,0 +1,43 @@
1
+ # Точные десятичные значения
2
+
3
+ Публичный импорт: `@ryuzaki13/react-foundation-lib/decimal`.
4
+ Модуль вычисляет конечные десятичные значения как целый коэффициент и число
5
+ десятичных разрядов. Строки не переводятся в `number`; округления нет.
6
+ React, browser API и дополнительные зависимости не требуются.
7
+
8
+ ```ts
9
+ import { addDecimals, compareDecimalRatios } from "@ryuzaki13/react-foundation-lib/decimal";
10
+
11
+ addDecimals("0.1", "0.2"); // "0.3"
12
+ compareDecimalRatios({ numerator: "10", denominator: "3" }, { numerator: "3.33", denominator: "1" }); // 1
13
+ ```
14
+
15
+ | API | Назначение |
16
+ | ----------------------------------------------------- | --------------------------------------------------------------------- |
17
+ | `isCanonicalDecimal(unknown, options?)` | Проверить внешнее значение без преобразования |
18
+ | `normalizeDecimal(string, options?)` | Убрать начальные и конечные нули; привести отрицательный ноль к `"0"` |
19
+ | `addDecimals`, `subtractDecimals`, `multiplyDecimals` | Получить точный канонический результат двух операндов |
20
+ | `sumDecimals(iterable, options?)` | Суммировать за один проход; пустой набор даёт `"0"` |
21
+ | `compareDecimals` | Вернуть `-1`, `0` или `1` |
22
+ | `compareDecimalRatios` | Сравнить отношения без деления; знаменатели строго положительные |
23
+
24
+ Каноническая строка содержит знак минус при необходимости, цифры и точку:
25
+ `"0"`, `"0.3"`, `"-12.05"`. Пробелы, плюс, экспонента, запятая, начальные
26
+ нули и конечные нули дробной части в арифметике отклоняются. Нормализация
27
+ допускает только лишние нули; обработка локализованного ввода и внешних JSON
28
+ чисел принадлежит соответствующей входной границе.
29
+
30
+ `DecimalOptions.maxLength` задаёт положительный безопасный целый предел длины
31
+ входа и результата, включая знак и точку; по умолчанию — 512 символов.
32
+ Вход отклоняется до создания `bigint` и выравнивания разрядов. Неверная форма
33
+ даёт `TypeError`, неверный предел, overflow результата и недопустимый знаменатель
34
+ — `RangeError`. `isCanonicalDecimal` возвращает `false` для неверного значения,
35
+ но неверная конфигурация предела также даёт `RangeError`.
36
+
37
+ Суммирование проверяет каждый промежуточный результат: даже последующее
38
+ взаимное сокращение не отменяет уже возникшее переполнение. При сравнении
39
+ отношений произведения не сериализуются; они могут превышать предел строки,
40
+ оставаясь ограниченными длиной проверенных операндов.
41
+
42
+ Предметные правила положительности, единиц измерения и допустимости нуля
43
+ остаются у приложения. Приватные коэффициенты и разрядность не входят в API.