@fintekkers/ledger-models 0.4.38 → 0.4.39

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 (61) hide show
  1. package/node/fintekkers/models/util/decimal_value_pb.d.ts +2 -0
  2. package/node/wrappers/models/position/position.d.ts +1 -1
  3. package/node/wrappers/models/position/position.js.map +1 -1
  4. package/node/wrappers/models/position/position.test.js +2 -2
  5. package/node/wrappers/models/position/position.test.js.map +1 -1
  6. package/node/wrappers/models/position/position.test.ts +2 -2
  7. package/node/wrappers/models/position/position.ts +2 -2
  8. package/node/wrappers/models/price/Price.js +16 -8
  9. package/node/wrappers/models/price/Price.js.map +1 -1
  10. package/node/wrappers/models/price/Price.ts +15 -6
  11. package/node/wrappers/models/price/price_rules.d.ts +2 -2
  12. package/node/wrappers/models/price/price_rules.js +6 -4
  13. package/node/wrappers/models/price/price_rules.js.map +1 -1
  14. package/node/wrappers/models/price/price_rules.ts +5 -3
  15. package/node/wrappers/models/security/BondSecurity.d.ts +1 -1
  16. package/node/wrappers/models/security/BondSecurity.js +5 -5
  17. package/node/wrappers/models/security/BondSecurity.js.map +1 -1
  18. package/node/wrappers/models/security/BondSecurity.ts +5 -4
  19. package/node/wrappers/models/security/FloatingRateNote.js +2 -2
  20. package/node/wrappers/models/security/FloatingRateNote.js.map +1 -1
  21. package/node/wrappers/models/security/FloatingRateNote.ts +2 -1
  22. package/node/wrappers/models/security/Issuance.js +3 -6
  23. package/node/wrappers/models/security/Issuance.js.map +1 -1
  24. package/node/wrappers/models/security/Issuance.ts +3 -2
  25. package/node/wrappers/models/security/MortgageBackedSecurity.js +7 -7
  26. package/node/wrappers/models/security/MortgageBackedSecurity.js.map +1 -1
  27. package/node/wrappers/models/security/MortgageBackedSecurity.ts +7 -6
  28. package/node/wrappers/models/security/TIPSBond.js +2 -2
  29. package/node/wrappers/models/security/TIPSBond.js.map +1 -1
  30. package/node/wrappers/models/security/TIPSBond.ts +2 -1
  31. package/node/wrappers/models/security/security_rules.js +10 -12
  32. package/node/wrappers/models/security/security_rules.js.map +1 -1
  33. package/node/wrappers/models/security/security_rules.ts +9 -9
  34. package/node/wrappers/models/transaction/transaction.js +16 -10
  35. package/node/wrappers/models/transaction/transaction.js.map +1 -1
  36. package/node/wrappers/models/transaction/transaction.ts +16 -7
  37. package/node/wrappers/models/utils/decimal.d.ts +96 -0
  38. package/node/wrappers/models/utils/decimal.js +328 -0
  39. package/node/wrappers/models/utils/decimal.js.map +1 -0
  40. package/node/wrappers/models/utils/decimal.legacy.test.d.ts +1 -0
  41. package/node/wrappers/models/utils/decimal.legacy.test.js +174 -0
  42. package/node/wrappers/models/utils/decimal.legacy.test.js.map +1 -0
  43. package/node/wrappers/models/utils/decimal.legacy.test.ts +158 -0
  44. package/node/wrappers/models/utils/decimal.test.d.ts +1 -0
  45. package/node/wrappers/models/utils/decimal.test.js +258 -0
  46. package/node/wrappers/models/utils/decimal.test.js.map +1 -0
  47. package/node/wrappers/models/utils/decimal.test.ts +272 -0
  48. package/node/wrappers/models/utils/decimal.ts +335 -0
  49. package/node/wrappers/models/utils/decimal.typings.test.d.ts +1 -0
  50. package/node/wrappers/models/utils/decimal.typings.test.js +39 -0
  51. package/node/wrappers/models/utils/decimal.typings.test.js.map +1 -0
  52. package/node/wrappers/models/utils/decimal.typings.test.ts +16 -0
  53. package/node/wrappers/models/utils/serialization.d.ts +2 -1
  54. package/node/wrappers/models/utils/serialization.js +12 -2
  55. package/node/wrappers/models/utils/serialization.js.map +1 -1
  56. package/node/wrappers/models/utils/serialization.ts +14 -3
  57. package/node/wrappers/services/security-service/security.maturityLadder.test.js +1 -1
  58. package/node/wrappers/services/security-service/security.maturityLadder.test.js.map +1 -1
  59. package/node/wrappers/services/security-service/security.maturityLadder.test.ts +3 -2
  60. package/package.json +1 -1
  61. package/tsconfig.json +1 -0
@@ -0,0 +1,158 @@
1
+ import * as fs from 'fs';
2
+ import * as path from 'path';
3
+ import { Decimal } from 'decimal.js';
4
+ import { Message } from 'google-protobuf';
5
+ import { PriceProto } from '../../../fintekkers/models/price/price_pb';
6
+ import { SecurityProto } from '../../../fintekkers/models/security/security_pb';
7
+ import { TransactionProto } from '../../../fintekkers/models/transaction/transaction_pb';
8
+ import { DecimalValueProto } from '../../../fintekkers/models/util/decimal_value_pb';
9
+ import Price from '../price/Price';
10
+ import Security from '../security/security';
11
+ import MortgageBackedSecurity from '../security/MortgageBackedSecurity';
12
+ import Transaction from '../transaction/transaction';
13
+ import { ProtoSerializationUtil } from './serialization';
14
+ import { UUID } from './uuid';
15
+ import Portfolio from '../portfolio/portfolio';
16
+ import { PortfolioProto } from '../../../fintekkers/models/portfolio/portfolio_pb';
17
+ import { decodeDecimal, reencodeDecimal, setDecimalLogger } from './decimal';
18
+
19
+ /**
20
+ * Metric 2 (LM-306): bytes written by ledger-models v0.4.33 carry only the
21
+ * string form. They load through the wrappers to the same value and scale,
22
+ * and re-saving them writes both forms.
23
+ */
24
+
25
+ const LEGACY = path.join(__dirname, '../../../../../ledger-models-protos/fixtures/legacy_v0433');
26
+
27
+ interface LegacyDecimal { path: string; stored_string: string; unscaled: string; scale: number; read_by: string }
28
+ interface LegacyFixture { bin: string; message: string; decimals: LegacyDecimal[] }
29
+
30
+ const DESERIALIZERS: Record<string, (b: Uint8Array) => Message> = {
31
+ PriceProto: b => PriceProto.deserializeBinary(b),
32
+ SecurityProto: b => SecurityProto.deserializeBinary(b),
33
+ TransactionProto: b => TransactionProto.deserializeBinary(b),
34
+ };
35
+
36
+ function load(name: string): { fixture: LegacyFixture; message: Message } {
37
+ const fixture: LegacyFixture = JSON.parse(fs.readFileSync(path.join(LEGACY, `${name}.json`), 'utf8'));
38
+ const deserialize = DESERIALIZERS[fixture.message];
39
+ if (!deserialize) throw new Error(`no deserializer for ${fixture.message}`);
40
+ return { fixture, message: deserialize(new Uint8Array(fs.readFileSync(path.join(LEGACY, fixture.bin)))) };
41
+ }
42
+
43
+ const pascal = (segment: string) => segment.split('_').map(w => w[0].toUpperCase() + w.slice(1)).join('');
44
+
45
+ /** Walks `a.b_c` with getA().getBC(). */
46
+ function walk(message: Message, dotted: string): any {
47
+ return dotted.split('.').reduce((m: any, segment) => {
48
+ const value = m[`get${pascal(segment)}`]();
49
+ if (value === undefined) throw new Error(`${dotted}: ${segment} is unset`);
50
+ return value;
51
+ }, message);
52
+ }
53
+
54
+ /** The wrapper getter that reads each path, as Rust's `read_by` names it. */
55
+ function readByWrapper(message: Message, dotted: string): Decimal {
56
+ const mbs = (security: SecurityProto) => {
57
+ const wrapped = Security.create(security);
58
+ expect(wrapped).toBeInstanceOf(MortgageBackedSecurity);
59
+ return wrapped as MortgageBackedSecurity;
60
+ };
61
+ const parts = dotted.split('.');
62
+ const field = parts[parts.length - 1];
63
+ if (dotted === 'price') return new Price(message as PriceProto).getPrice();
64
+ if (dotted === 'quantity') return new Transaction(message as TransactionProto).getQuantity();
65
+ if (dotted === 'price.price') return new Price(new Transaction(message as TransactionProto).getPrice()).getPrice();
66
+ const security = parts[0] === 'security' ? walk(message, 'security') as SecurityProto : message as SecurityProto;
67
+ const getter = `get${pascal(field)}`;
68
+ const value = (mbs(security) as any)[getter]();
69
+ if (!(value instanceof Decimal)) throw new Error(`${dotted}: ${getter} did not return a Decimal`);
70
+ return value;
71
+ }
72
+
73
+ beforeAll(() => {
74
+ setDecimalLogger({ warn: jest.fn() });
75
+ });
76
+
77
+ describe.each(['price', 'security', 'transaction'])('legacy_v0433/%s', (name) => {
78
+ const { fixture } = load(name);
79
+
80
+ test.each(fixture.decimals.map(d => [d.path, d] as [string, LegacyDecimal]))('%s reads through the wrapper', (_p, d) => {
81
+ const { message } = load(name);
82
+ const proto = walk(message, d.path) as DecimalValueProto;
83
+ // Really string-only bytes.
84
+ expect(proto.getUnscaledValue_asU8().length).toBe(0);
85
+ expect(proto.getArbitraryPrecisionValue()).toBe(d.stored_string);
86
+
87
+ // Same value and scale as the fixture.
88
+ expect(decodeDecimal(proto)).toEqual({ unscaled: BigInt(d.unscaled), scale: d.scale });
89
+
90
+ // The wrapper getter returns that exact value.
91
+ const expected = new Decimal(d.unscaled).div(new Decimal(10).pow(d.scale));
92
+ expect(readByWrapper(message, d.path).equals(expected)).toBe(true);
93
+ if (d.read_by.startsWith('ProtoSerializationUtil')) {
94
+ expect((ProtoSerializationUtil.deserialize(proto) as Decimal).equals(expected)).toBe(true);
95
+ }
96
+ });
97
+
98
+ test('re-saving writes both forms with the same value and scale', () => {
99
+ const { message } = load(name);
100
+ for (const d of fixture.decimals) {
101
+ const parentPath = d.path.split('.').slice(0, -1).join('.');
102
+ const parent = parentPath ? walk(message, parentPath) : message;
103
+ const field = d.path.split('.').pop()!;
104
+ const setter = `set${pascal(field)}`;
105
+ (parent as any)[setter](reencodeDecimal(walk(message, d.path)));
106
+ }
107
+ const reread = DESERIALIZERS[fixture.message](message.serializeBinary());
108
+ for (const d of fixture.decimals) {
109
+ const proto = walk(reread, d.path) as DecimalValueProto;
110
+ expect(proto.getUnscaledValue_asU8().length).toBeGreaterThan(0);
111
+ expect(proto.getArbitraryPrecisionValue()).not.toBe('');
112
+ const expected = { unscaled: BigInt(d.unscaled), scale: d.scale };
113
+ const stringOnly = new DecimalValueProto().setArbitraryPrecisionValue(proto.getArbitraryPrecisionValue());
114
+ const compactOnly = new DecimalValueProto().setUnscaledValue(proto.getUnscaledValue_asU8()).setScale(proto.getScale());
115
+ expect(decodeDecimal(compactOnly)).toEqual(expected);
116
+ expect(decodeDecimal(stringOnly)).toEqual(expected);
117
+ }
118
+ });
119
+ });
120
+
121
+ describe('wrapper writers set both forms (metrics 2 and 5)', () => {
122
+ const bothForms = (proto: DecimalValueProto | undefined, expected: Decimal) => {
123
+ expect(proto).toBeDefined();
124
+ const p = proto as DecimalValueProto;
125
+ const stringOnly = new DecimalValueProto().setArbitraryPrecisionValue(p.getArbitraryPrecisionValue());
126
+ const compactOnly = new DecimalValueProto().setUnscaledValue(p.getUnscaledValue_asU8()).setScale(p.getScale());
127
+ expect(p.getUnscaledValue_asU8().length).toBeGreaterThan(0);
128
+ expect(decodeDecimal(compactOnly)).toEqual(decodeDecimal(stringOnly));
129
+ expect(new Decimal(p.getArbitraryPrecisionValue()).equals(expected)).toBe(true);
130
+ };
131
+
132
+ test('a legacy Price re-created through Price.create', () => {
133
+ const legacy = new Price(load('price').message as PriceProto);
134
+ const saved = Price.create(legacy.getPrice(), legacy.getSecurity(), legacy.getAsOf());
135
+ const reread = PriceProto.deserializeBinary(saved.proto.serializeBinary());
136
+ bothForms(reread.getPrice(), new Decimal('100.25'));
137
+ });
138
+
139
+ test('a legacy Transaction re-created through the Transaction constructor', () => {
140
+ const legacy = new Transaction(load('transaction').message as TransactionProto);
141
+ const legacyPrice = new Price(legacy.getPrice());
142
+ const saved = new Transaction({
143
+ tradeDate: new Date(2026, 0, 2),
144
+ settlementDate: new Date(2026, 0, 4),
145
+ security: legacy.getSecurity(),
146
+ transactionType: legacy.getTransactionType(),
147
+ portfolio: new Portfolio(new PortfolioProto()
148
+ .setObjectClass('Portfolio').setVersion('0.0.1')
149
+ .setUuid(UUID.random().toUUIDProto()).setPortfolioName('LM-306')),
150
+ quantity: legacy.getQuantity(),
151
+ price: legacyPrice.getPrice(),
152
+ asOfDate: new Date(2026, 0, 2),
153
+ });
154
+ const reread = TransactionProto.deserializeBinary(saved.proto.serializeBinary());
155
+ bothForms(reread.getQuantity(), new Decimal(1000));
156
+ bothForms(reread.getPrice()?.getPrice(), new Decimal('-0.50'));
157
+ });
158
+ });
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,258 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || function (mod) {
19
+ if (mod && mod.__esModule) return mod;
20
+ var result = {};
21
+ if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
22
+ __setModuleDefault(result, mod);
23
+ return result;
24
+ };
25
+ Object.defineProperty(exports, "__esModule", { value: true });
26
+ const fs = __importStar(require("fs"));
27
+ const path = __importStar(require("path"));
28
+ const decimal_js_1 = require("decimal.js");
29
+ const decimal_value_pb_1 = require("../../../fintekkers/models/util/decimal_value_pb");
30
+ const errors_1 = require("../errors");
31
+ const serialization_1 = require("./serialization");
32
+ const decimal_1 = require("./decimal");
33
+ /** Codec tests against the shared fixture (LM-306, JS side of LM-294). */
34
+ const FIXTURE = JSON.parse(fs.readFileSync(path.join(__dirname, '../../../../../ledger-models-protos/fixtures/decimal_compact.json'), 'utf8'));
35
+ const CASES = FIXTURE.cases;
36
+ const hex = (bytes) => Buffer.from(bytes).toString('hex');
37
+ const unhex = (s) => new Uint8Array(Buffer.from(s, 'hex'));
38
+ /** Two's-complement big-endian, written independently of the codec. */
39
+ function expectedUnscaled(unscaledHex) {
40
+ const unsigned = BigInt('0x' + unscaledHex);
41
+ const negative = parseInt(unscaledHex.slice(0, 2), 16) >= 0x80;
42
+ return negative ? unsigned - (BigInt(1) << BigInt(unscaledHex.length * 4)) : unsigned;
43
+ }
44
+ /** Only fields 11 and 12 set. */
45
+ function compactOnly(c) {
46
+ return new decimal_value_pb_1.DecimalValueProto().setUnscaledValue(unhex(c.unscaled_hex)).setScale(c.scale);
47
+ }
48
+ function expectInvalid(fn) {
49
+ expect(fn).toThrow(errors_1.ModelValidationError);
50
+ }
51
+ beforeAll(() => {
52
+ // String-only decodes below would warn once; keep the test output quiet.
53
+ (0, decimal_1.setDecimalLogger)({ warn: jest.fn() });
54
+ });
55
+ describe('metric 1: shared fixture', () => {
56
+ test('fixture limits match the codec', () => {
57
+ expect(FIXTURE.limits).toEqual({
58
+ max_digits: decimal_1.MAX_DIGITS, max_scale: decimal_1.MAX_SCALE, max_unscaled_bytes: decimal_1.MAX_UNSCALED_BYTES,
59
+ });
60
+ expect(CASES.length).toBeGreaterThanOrEqual(12);
61
+ });
62
+ test.each(CASES.map(c => [c.name, c]))('%s encodes to wire_hex and decodes exactly', (_name, c) => {
63
+ const parsed = (0, decimal_1.parseDecimalString)(c.string);
64
+ expect(parsed).toEqual({ unscaled: expectedUnscaled(c.unscaled_hex), scale: c.scale });
65
+ expect((0, decimal_1.toCanonicalString)(parsed)).toBe(c.canonical);
66
+ const proto = (0, decimal_1.encodeDecimal)(parsed);
67
+ expect(hex(proto.getUnscaledValue_asU8())).toBe(c.unscaled_hex);
68
+ expect(proto.getScale()).toBe(c.scale);
69
+ expect(hex(proto.serializeBinary())).toBe(c.wire_hex);
70
+ // The proto alone is enough to decode (metric 3).
71
+ const decoded = (0, decimal_1.decodeDecimal)(decimal_value_pb_1.DecimalValueProto.deserializeBinary(unhex(c.wire_hex)));
72
+ expect(decoded).toEqual({ unscaled: expectedUnscaled(c.unscaled_hex), scale: c.scale });
73
+ });
74
+ const stringErrors = FIXTURE.string_errors.map((c) => [c.name, c.string]);
75
+ test.each(stringErrors)('string error %s is a ModelValidationError', (_name, s) => {
76
+ expectInvalid(() => (0, decimal_1.parseDecimalString)(s));
77
+ expectInvalid(() => (0, decimal_1.decodeDecimal)(new decimal_value_pb_1.DecimalValueProto().setArbitraryPrecisionValue(s)));
78
+ });
79
+ const decodeErrors = FIXTURE.decode_errors.map((c) => [c.name, c]);
80
+ test.each(decodeErrors)('decode error %s is a ModelValidationError', (_name, c) => {
81
+ const bytes = c.unscaled_hex_repeat
82
+ ? unhex(c.unscaled_hex_repeat.hex.repeat(c.unscaled_hex_repeat.count))
83
+ : unhex(c.unscaled_hex);
84
+ expectInvalid(() => (0, decimal_1.decodeDecimal)(new decimal_value_pb_1.DecimalValueProto().setUnscaledValue(bytes).setScale(c.scale)));
85
+ });
86
+ test('the 1702-byte case passes the byte check and fails on digits; 1703 fails on bytes', () => {
87
+ const message = (n) => {
88
+ try {
89
+ (0, decimal_1.decodeDecimal)(new decimal_value_pb_1.DecimalValueProto().setUnscaledValue(unhex('7f'.repeat(n))));
90
+ }
91
+ catch (e) {
92
+ return e.message;
93
+ }
94
+ return '';
95
+ };
96
+ expect(message(1702)).toContain(`more than ${decimal_1.MAX_DIGITS} digits`);
97
+ expect(message(1703)).toContain('1703-byte');
98
+ });
99
+ test('the committed decimal.js (what npm publishes) encodes and decodes fixture cases', () => {
100
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
101
+ const shipped = require(path.join(__dirname, 'decimal.js'));
102
+ for (const name of ['zero', 'two_pow_127', 'tiny_fraction']) {
103
+ const c = CASES.find(x => x.name === name);
104
+ const proto = shipped.encodeDecimal(shipped.parseDecimalString(c.string));
105
+ expect(hex(proto.serializeBinary())).toBe(c.wire_hex);
106
+ expect(shipped.decodeDecimal(decimal_value_pb_1.DecimalValueProto.deserializeBinary(unhex(c.wire_hex))))
107
+ .toEqual({ unscaled: expectedUnscaled(c.unscaled_hex), scale: c.scale });
108
+ }
109
+ });
110
+ test('compact form wins over a conflicting string and does not warn', () => {
111
+ jest.isolateModules(() => {
112
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
113
+ const codec = require('./decimal');
114
+ const warn = jest.fn();
115
+ codec.setDecimalLogger({ warn });
116
+ const proto = new decimal_value_pb_1.DecimalValueProto()
117
+ .setArbitraryPrecisionValue('9')
118
+ .setUnscaledValue(unhex('0096'))
119
+ .setScale(2);
120
+ expect(codec.toCanonicalString(codec.decodeDecimal(proto))).toBe('1.50');
121
+ expect(warn).not.toHaveBeenCalled();
122
+ });
123
+ });
124
+ test('negative zero from decimal.js encodes to 0x00 at scale 0', () => {
125
+ const v = (0, decimal_1.fromDecimalJs)(new decimal_js_1.Decimal('-0'));
126
+ expect(v).toEqual({ unscaled: BigInt(0), scale: 0 });
127
+ const proto = (0, decimal_1.encodeDecimal)(v);
128
+ expect(hex(proto.getUnscaledValue_asU8())).toBe('00');
129
+ expect(proto.getScale()).toBe(0);
130
+ expect(proto.getArbitraryPrecisionValue()).toBe('0');
131
+ });
132
+ });
133
+ describe('metric 3: decodeDecimal takes the proto only', () => {
134
+ test('a type or field argument does not type-check', () => {
135
+ const p = (0, decimal_1.encodeDecimal)((0, decimal_1.parseDecimalString)('1.50'));
136
+ // ts-jest type-checks this file: an unused @ts-expect-error fails it.
137
+ const typeChecked = () => {
138
+ // @ts-expect-error decodeDecimal takes no type argument
139
+ (0, decimal_1.decodeDecimal)(p);
140
+ // @ts-expect-error decodeDecimal takes no field argument
141
+ (0, decimal_1.decodeDecimal)(p, 'price');
142
+ };
143
+ expect(typeof typeChecked).toBe('function');
144
+ expect(decimal_1.decodeDecimal.length).toBe(1);
145
+ });
146
+ test('withField names the field on a codec error', () => {
147
+ try {
148
+ (0, decimal_1.withField)('price', () => (0, decimal_1.decodeDecimal)(new decimal_value_pb_1.DecimalValueProto()));
149
+ throw new Error('expected a ModelValidationError');
150
+ }
151
+ catch (e) {
152
+ expect(e).toBeInstanceOf(errors_1.ModelValidationError);
153
+ expect(e.field).toBe('price');
154
+ }
155
+ });
156
+ });
157
+ describe('metric 4: one deprecation warning per process', () => {
158
+ test('a compact-only decode does not warn', () => {
159
+ jest.isolateModules(() => {
160
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
161
+ const codec = require('./decimal');
162
+ const warn = jest.fn();
163
+ codec.setDecimalLogger({ warn });
164
+ for (const c of CASES)
165
+ codec.decodeDecimal(compactOnly(c));
166
+ expect(warn).toHaveBeenCalledTimes(0);
167
+ });
168
+ });
169
+ test('three string-only prices read through the Price wrapper warn exactly once', () => {
170
+ jest.isolateModules(() => {
171
+ // The same isolated registry: Price loads this codec instance.
172
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
173
+ const codec = require('./decimal');
174
+ const warn = jest.fn();
175
+ codec.setDecimalLogger({ warn });
176
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
177
+ const { PriceProto } = require('../../../fintekkers/models/price/price_pb');
178
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
179
+ const Price = require('../price/Price').default;
180
+ const values = ['100.25', '-0.50', '1E+3'];
181
+ const read = values.map(s => new Price(new PriceProto().setPrice(new decimal_value_pb_1.DecimalValueProto().setArbitraryPrecisionValue(s))).getPrice());
182
+ expect(read.map((d) => d.toString())).toEqual(['100.25', '-0.5', '1000']);
183
+ expect(warn).toHaveBeenCalledTimes(1);
184
+ expect(warn.mock.calls[0][0]).toContain('arbitrary_precision_value');
185
+ });
186
+ });
187
+ });
188
+ describe('metric 5: writers set both forms', () => {
189
+ test.each(CASES.map(c => [c.name, c]))('%s: both forms are set and decode equal', (_name, c) => {
190
+ const proto = (0, decimal_1.encodeDecimal)((0, decimal_1.parseDecimalString)(c.string));
191
+ expect(proto.getArbitraryPrecisionValue()).toBe(c.canonical);
192
+ expect(proto.getUnscaledValue_asU8().length).toBeGreaterThan(0);
193
+ const stringOnly = new decimal_value_pb_1.DecimalValueProto().setArbitraryPrecisionValue(proto.getArbitraryPrecisionValue());
194
+ const compact = new decimal_value_pb_1.DecimalValueProto()
195
+ .setUnscaledValue(proto.getUnscaledValue_asU8())
196
+ .setScale(proto.getScale());
197
+ const expected = { unscaled: expectedUnscaled(c.unscaled_hex), scale: c.scale };
198
+ expect((0, decimal_1.decodeDecimal)(stringOnly)).toEqual(expected);
199
+ expect((0, decimal_1.decodeDecimal)(compact)).toEqual(expected);
200
+ });
201
+ });
202
+ describe('guardrail: lossless', () => {
203
+ const NODE = path.join(__dirname, '../../..');
204
+ const SCANNED = [
205
+ 'wrappers/models/utils/decimal.ts',
206
+ 'wrappers/models/utils/serialization.ts',
207
+ 'wrappers/models/price/Price.ts',
208
+ 'wrappers/models/price/price_rules.ts',
209
+ 'wrappers/models/transaction/transaction.ts',
210
+ 'wrappers/models/security/BondSecurity.ts',
211
+ 'wrappers/models/security/Issuance.ts',
212
+ 'wrappers/models/security/MortgageBackedSecurity.ts',
213
+ 'wrappers/models/security/TIPSBond.ts',
214
+ 'wrappers/models/security/FloatingRateNote.ts',
215
+ 'wrappers/models/security/security_rules.ts',
216
+ ];
217
+ test.each(SCANNED)('%s has no float conversion on the decimal path', (file) => {
218
+ const lines = fs.readFileSync(path.join(NODE, file), 'utf8').split('\n');
219
+ const allowed = [];
220
+ lines.forEach((line, n) => {
221
+ // Comment lines don't count.
222
+ const code = /^\s*(\*|\/\*)/.test(line) ? '' : line.split('//')[0];
223
+ expect({ file, line: n + 1, code, banned: /parseFloat|parseInt|\.toNumber\(/.test(code) })
224
+ .toEqual({ file, line: n + 1, code, banned: false });
225
+ if (/\bNumber\(/.test(code))
226
+ allowed.push(n + 1);
227
+ });
228
+ // The one documented, range-checked conversion in smallInt().
229
+ const expectedNumberCalls = file.endsWith('utils/decimal.ts') ? 1 : 0;
230
+ expect(allowed.length).toBe(expectedNumberCalls);
231
+ if (expectedNumberCalls)
232
+ expect(lines[allowed[0] - 1]).toContain('lossless-allow');
233
+ });
234
+ test('serialize(number) accepts only safe integers', () => {
235
+ expectInvalid(() => serialization_1.ProtoSerializationUtil.serialize(0.1));
236
+ expectInvalid(() => serialization_1.ProtoSerializationUtil.serialize(2 ** 53));
237
+ const proto = serialization_1.ProtoSerializationUtil.serialize(42);
238
+ expect(proto.getArbitraryPrecisionValue()).toBe('42');
239
+ expect(hex(proto.getUnscaledValue_asU8())).toBe('2a');
240
+ expect(proto.getScale()).toBe(0);
241
+ });
242
+ test('serialize(Decimal) writes both forms; deserialize returns a Decimal', () => {
243
+ const proto = serialization_1.ProtoSerializationUtil.serialize(new decimal_js_1.Decimal('-123.45'));
244
+ expect(proto.getArbitraryPrecisionValue()).toBe('-123.45');
245
+ expect(hex(proto.getUnscaledValue_asU8())).toBe('cfc7');
246
+ const big = CASES.find(c => c.name === 'two_pow_127');
247
+ const read = serialization_1.ProtoSerializationUtil.deserialize(compactOnly(big));
248
+ expect(read).toBeInstanceOf(decimal_js_1.Decimal);
249
+ expect(read.toFixed()).toBe(big.canonical);
250
+ });
251
+ test('a value over the limits is an error, never rounded', () => {
252
+ expectInvalid(() => (0, decimal_1.fromDecimalJs)(new decimal_js_1.Decimal('1e-5000')));
253
+ expectInvalid(() => (0, decimal_1.fromDecimalJs)(new decimal_js_1.Decimal('1e+5000')));
254
+ expectInvalid(() => (0, decimal_1.fromDecimalJs)(new decimal_js_1.Decimal(NaN)));
255
+ expectInvalid(() => (0, decimal_1.encodeDecimal)({ unscaled: BigInt(1), scale: 1.5 }));
256
+ });
257
+ });
258
+ //# sourceMappingURL=decimal.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"decimal.test.js","sourceRoot":"","sources":["decimal.test.ts"],"names":[],"mappings":"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"}