@fintekkers/ledger-models 0.4.27 → 0.4.29
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.
- package/hierarchy.json +8 -7
- package/node/wrappers/models/position/position_matcher.d.ts +27 -0
- package/node/wrappers/models/position/position_matcher.js +53 -0
- package/node/wrappers/models/position/position_matcher.test.d.ts +1 -0
- package/node/wrappers/models/position/position_matcher.test.js +77 -0
- package/node/wrappers/models/position/position_matcher.test.ts +96 -0
- package/node/wrappers/models/position/position_matcher.ts +71 -0
- package/node/wrappers/models/security/asset_class_vocabulary.test.js +35 -0
- package/node/wrappers/models/security/asset_class_vocabulary.test.js.map +1 -1
- package/node/wrappers/models/security/asset_class_vocabulary.test.ts +44 -0
- package/node/wrappers/models/security/product_hierarchy.d.ts +7 -1
- package/node/wrappers/models/security/product_hierarchy.js +34 -5
- package/node/wrappers/models/security/product_hierarchy.js.map +1 -1
- package/node/wrappers/models/security/product_hierarchy.ts +37 -4
- package/package.json +1 -1
package/hierarchy.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
|
-
"schema_version": "1.
|
|
3
|
-
"_doc": "Single source of truth for the FinTekkers product hierarchy. See ../docs/product-hierarchy.md for narrative description, hierarchy-examples.md for worked examples, and registry-versioning.md for compatibility rules. Each leaf product_type carries (asset_class, instrument_type). Abstract nodes carry only hierarchy. status=active entries must have a matching ProductTypeProto enum value (CI-enforced). status=planned entries are aspirational and not yet wired into the proto enum. NOTE: M1 ships a 3-dimensional registry (productType + asset_class + instrument_type). The 4th dimension (index_type — single_name vs index) is intentionally deferred and will be added in a future milestone. Option strategy leaves (butterfly, vertical spread, calendar spread, condor, straddle, ...) are also intentionally absent — strategies are derived from the legs field on SecurityProto, not from a productType enum value. asset_classes is the one canonical asset-class vocabulary (codes and tree); an entry's optional aliases list names legacy values that resolve to it. enum_labels holds display labels (and identifier-type input placeholders) for proto enum values with no entry elsewhere, keyed by proto enum name then value name. See ../docs/adr/asset_class_vocabulary.md.",
|
|
2
|
+
"schema_version": "1.2",
|
|
3
|
+
"_doc": "Single source of truth for the FinTekkers product hierarchy. See ../docs/product-hierarchy.md for narrative description, hierarchy-examples.md for worked examples, and registry-versioning.md for compatibility rules. Each leaf product_type carries (asset_class, instrument_type). Abstract nodes carry only hierarchy. status=active entries must have a matching ProductTypeProto enum value (CI-enforced). status=planned entries are aspirational and not yet wired into the proto enum. NOTE: M1 ships a 3-dimensional registry (productType + asset_class + instrument_type). The 4th dimension (index_type — single_name vs index) is intentionally deferred and will be added in a future milestone. Option strategy leaves (butterfly, vertical spread, calendar spread, condor, straddle, ...) are also intentionally absent — strategies are derived from the legs field on SecurityProto, not from a productType enum value. asset_classes is the one canonical asset-class vocabulary (codes and tree); an entry's optional aliases list names legacy values that resolve to it. instrument_types maps each instrument-type code to {label}, in display order; every code must have a matching INSTRUMENT_TYPE_<CODE> InstrumentTypeProto value (checked at load), and that enum value takes its label from here. enum_labels holds display labels (and identifier-type input placeholders) for proto enum values with no entry elsewhere, keyed by proto enum name then value name. See ../docs/adr/asset_class_vocabulary.md.",
|
|
4
4
|
|
|
5
5
|
"product_types": {
|
|
6
6
|
"BOND": { "parent": null, "abstract": true, "label": "Bond" },
|
|
@@ -127,7 +127,11 @@
|
|
|
127
127
|
"ALTERNATIVE": { "parent": null, "label": "Alternative" }
|
|
128
128
|
},
|
|
129
129
|
|
|
130
|
-
"instrument_types":
|
|
130
|
+
"instrument_types": {
|
|
131
|
+
"CASH": { "label": "Cash" },
|
|
132
|
+
"DERIVATIVE": { "label": "Derivative" },
|
|
133
|
+
"REFERENCE_INDEX": { "label": "Reference Index" }
|
|
134
|
+
},
|
|
131
135
|
|
|
132
136
|
"enum_labels": {
|
|
133
137
|
"IdentifierTypeProto": {
|
|
@@ -142,10 +146,7 @@
|
|
|
142
146
|
"CASH": { "label": "Currency Code", "placeholder": "e.g. USD" }
|
|
143
147
|
},
|
|
144
148
|
"InstrumentTypeProto": {
|
|
145
|
-
"INSTRUMENT_TYPE_UNKNOWN":
|
|
146
|
-
"INSTRUMENT_TYPE_CASH": { "label": "Cash" },
|
|
147
|
-
"INSTRUMENT_TYPE_DERIVATIVE": { "label": "Derivative" },
|
|
148
|
-
"INSTRUMENT_TYPE_REFERENCE_INDEX": { "label": "Reference Index" }
|
|
149
|
+
"INSTRUMENT_TYPE_UNKNOWN": { "label": "Unknown" }
|
|
149
150
|
},
|
|
150
151
|
"ProductTypeProto": {
|
|
151
152
|
"PRODUCT_TYPE_UNKNOWN": { "label": "Unknown" }
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { FieldProto } from '../../../fintekkers/models/position/field_pb';
|
|
2
|
+
import { PositionFilterOperator } from '../../../fintekkers/models/position/position_util_pb';
|
|
3
|
+
/** A single filter clause: the field, operator and filter value. */
|
|
4
|
+
export interface FilterSpec {
|
|
5
|
+
field: FieldProto;
|
|
6
|
+
operator: PositionFilterOperator;
|
|
7
|
+
value: any;
|
|
8
|
+
}
|
|
9
|
+
/** A row the matcher can read: the Security and Position wrappers qualify. */
|
|
10
|
+
export interface FilterableRow {
|
|
11
|
+
getField(field: FieldProto): any;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Single-field evaluator (LM-281), mirroring Java's PositionFilter.matches:
|
|
15
|
+
* ASSET_CLASS with EQUALS / NOT_EQUALS uses the shared assetClassMatches
|
|
16
|
+
* rule, so a group code such as FIXED_INCOME matches its members and labels;
|
|
17
|
+
* every other field compares exactly. A null or undefined stored value never
|
|
18
|
+
* throws: EQUALS and the ordering operators drop the row, NOT_EQUALS keeps
|
|
19
|
+
* it. An unknown operator matches nothing. Errors raised by row.getField
|
|
20
|
+
* propagate (a row represents an absent value by returning null).
|
|
21
|
+
*/
|
|
22
|
+
export declare function matches(field: FieldProto, operator: PositionFilterOperator, filterValue: any, storedValue: any): boolean;
|
|
23
|
+
/**
|
|
24
|
+
* Keep the rows matching every clause in `filters` (AND semantics, input
|
|
25
|
+
* order preserved).
|
|
26
|
+
*/
|
|
27
|
+
export declare function filterRows<T extends FilterableRow>(rows: T[], filters: FilterSpec[]): T[];
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.filterRows = exports.matches = void 0;
|
|
4
|
+
const field_pb_1 = require("../../../fintekkers/models/position/field_pb");
|
|
5
|
+
const position_util_pb_1 = require("../../../fintekkers/models/position/position_util_pb");
|
|
6
|
+
const product_hierarchy_1 = require("../security/product_hierarchy");
|
|
7
|
+
/**
|
|
8
|
+
* Single-field evaluator (LM-281), mirroring Java's PositionFilter.matches:
|
|
9
|
+
* ASSET_CLASS with EQUALS / NOT_EQUALS uses the shared assetClassMatches
|
|
10
|
+
* rule, so a group code such as FIXED_INCOME matches its members and labels;
|
|
11
|
+
* every other field compares exactly. A null or undefined stored value never
|
|
12
|
+
* throws: EQUALS and the ordering operators drop the row, NOT_EQUALS keeps
|
|
13
|
+
* it. An unknown operator matches nothing. Errors raised by row.getField
|
|
14
|
+
* propagate (a row represents an absent value by returning null).
|
|
15
|
+
*/
|
|
16
|
+
function matches(field, operator, filterValue, storedValue) {
|
|
17
|
+
if (storedValue === null || storedValue === undefined) {
|
|
18
|
+
return operator === position_util_pb_1.PositionFilterOperator.NOT_EQUALS;
|
|
19
|
+
}
|
|
20
|
+
if (field === field_pb_1.FieldProto.ASSET_CLASS &&
|
|
21
|
+
(operator === position_util_pb_1.PositionFilterOperator.EQUALS ||
|
|
22
|
+
operator === position_util_pb_1.PositionFilterOperator.NOT_EQUALS)) {
|
|
23
|
+
const equals = (0, product_hierarchy_1.assetClassMatches)(filterValue, storedValue);
|
|
24
|
+
return operator === position_util_pb_1.PositionFilterOperator.EQUALS ? equals : !equals;
|
|
25
|
+
}
|
|
26
|
+
switch (operator) {
|
|
27
|
+
case position_util_pb_1.PositionFilterOperator.EQUALS:
|
|
28
|
+
return storedValue === filterValue;
|
|
29
|
+
case position_util_pb_1.PositionFilterOperator.NOT_EQUALS:
|
|
30
|
+
return storedValue !== filterValue;
|
|
31
|
+
case position_util_pb_1.PositionFilterOperator.LESS_THAN:
|
|
32
|
+
return storedValue < filterValue;
|
|
33
|
+
case position_util_pb_1.PositionFilterOperator.LESS_THAN_OR_EQUALS:
|
|
34
|
+
return storedValue <= filterValue;
|
|
35
|
+
case position_util_pb_1.PositionFilterOperator.MORE_THAN:
|
|
36
|
+
return storedValue > filterValue;
|
|
37
|
+
case position_util_pb_1.PositionFilterOperator.MORE_THAN_OR_EQUALS:
|
|
38
|
+
return storedValue >= filterValue;
|
|
39
|
+
default:
|
|
40
|
+
return false;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
exports.matches = matches;
|
|
44
|
+
/**
|
|
45
|
+
* Keep the rows matching every clause in `filters` (AND semantics, input
|
|
46
|
+
* order preserved).
|
|
47
|
+
*/
|
|
48
|
+
function filterRows(rows, filters) {
|
|
49
|
+
return rows.filter((row) => {
|
|
50
|
+
return filters.every((spec) => matches(spec.field, spec.operator, spec.value, row.getField(spec.field)));
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
exports.filterRows = filterRows;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* LM-281: the JS filter helper matches Java's PositionFilter row for row.
|
|
4
|
+
*
|
|
5
|
+
* ASSET_CLASS EQUALS / NOT_EQUALS use the shared assetClassMatches rule;
|
|
6
|
+
* every other field compares exactly. A null stored value never throws.
|
|
7
|
+
*/
|
|
8
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
9
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
10
|
+
};
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
const field_pb_1 = require("../../../fintekkers/models/position/field_pb");
|
|
13
|
+
const position_util_pb_1 = require("../../../fintekkers/models/position/position_util_pb");
|
|
14
|
+
const security_pb_1 = require("../../../fintekkers/models/security/security_pb");
|
|
15
|
+
const security_1 = __importDefault(require("../security/security"));
|
|
16
|
+
const position_matcher_1 = require("./position_matcher");
|
|
17
|
+
function securityRow(assetClass) {
|
|
18
|
+
const proto = new security_pb_1.SecurityProto();
|
|
19
|
+
proto.setAssetClass(assetClass);
|
|
20
|
+
return new security_1.default(proto);
|
|
21
|
+
}
|
|
22
|
+
function stubRow(assetClass) {
|
|
23
|
+
return {
|
|
24
|
+
getField: (_field) => assetClass,
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
function assetClasses(rows) {
|
|
28
|
+
return rows.map((row) => row.getField(field_pb_1.FieldProto.ASSET_CLASS));
|
|
29
|
+
}
|
|
30
|
+
function assetClassFilter(operator) {
|
|
31
|
+
return [{ field: field_pb_1.FieldProto.ASSET_CLASS, operator, value: 'FIXED_INCOME' }];
|
|
32
|
+
}
|
|
33
|
+
describe('position_matcher', () => {
|
|
34
|
+
test('ASSET_CLASS EQUALS FIXED_INCOME matches group members', () => {
|
|
35
|
+
const rows = ['RATES', 'CREDIT', 'Fixed Income', 'EQUITY'].map(securityRow);
|
|
36
|
+
const result = (0, position_matcher_1.filterRows)(rows, assetClassFilter(position_util_pb_1.PositionFilterOperator.EQUALS));
|
|
37
|
+
expect(assetClasses(result)).toEqual(['RATES', 'CREDIT', 'Fixed Income']);
|
|
38
|
+
});
|
|
39
|
+
test('ASSET_CLASS NOT_EQUALS FIXED_INCOME keeps only non-members', () => {
|
|
40
|
+
const rows = ['RATES', 'CREDIT', 'Fixed Income', 'EQUITY'].map(securityRow);
|
|
41
|
+
const result = (0, position_matcher_1.filterRows)(rows, assetClassFilter(position_util_pb_1.PositionFilterOperator.NOT_EQUALS));
|
|
42
|
+
expect(assetClasses(result)).toEqual(['EQUITY']);
|
|
43
|
+
});
|
|
44
|
+
test('null, empty and unknown stored values never throw', () => {
|
|
45
|
+
const rows = [stubRow(null), securityRow(''), securityRow('NOT_A_CLASS')];
|
|
46
|
+
const equals = assetClassFilter(position_util_pb_1.PositionFilterOperator.EQUALS);
|
|
47
|
+
const notEquals = assetClassFilter(position_util_pb_1.PositionFilterOperator.NOT_EQUALS);
|
|
48
|
+
expect(() => (0, position_matcher_1.filterRows)(rows, equals)).not.toThrow();
|
|
49
|
+
expect((0, position_matcher_1.filterRows)(rows, equals)).toEqual([]);
|
|
50
|
+
expect(() => (0, position_matcher_1.filterRows)(rows, notEquals)).not.toThrow();
|
|
51
|
+
expect(assetClasses((0, position_matcher_1.filterRows)(rows, notEquals))).toEqual([null, '', 'NOT_A_CLASS']);
|
|
52
|
+
});
|
|
53
|
+
test('other fields compare exactly', () => {
|
|
54
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.EQUALS, 'a', 'a')).toBe(true);
|
|
55
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.EQUALS, 'a', 'b')).toBe(false);
|
|
56
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'a', 'b')).toBe(true);
|
|
57
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'a', 'a')).toBe(false);
|
|
58
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.MATURITY_DATE, position_util_pb_1.PositionFilterOperator.MORE_THAN, 1, 2)).toBe(true);
|
|
59
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.MATURITY_DATE, position_util_pb_1.PositionFilterOperator.MORE_THAN, 2, 1)).toBe(false);
|
|
60
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.EQUALS, 'a', null)).toBe(false);
|
|
61
|
+
expect((0, position_matcher_1.matches)(field_pb_1.FieldProto.PORTFOLIO_NAME, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'a', null)).toBe(true);
|
|
62
|
+
});
|
|
63
|
+
});
|
|
64
|
+
describe('the published (compiled) position_matcher.js', () => {
|
|
65
|
+
// npm publish runs no tsc: the tracked .js is what consumers get.
|
|
66
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
67
|
+
const compiled = require('./position_matcher.js');
|
|
68
|
+
test('exports working matches and filterRows', () => {
|
|
69
|
+
expect(typeof compiled.matches).toBe('function');
|
|
70
|
+
expect(typeof compiled.filterRows).toBe('function');
|
|
71
|
+
expect(compiled.matches(field_pb_1.FieldProto.ASSET_CLASS, position_util_pb_1.PositionFilterOperator.EQUALS, 'FIXED_INCOME', 'RATES')).toBe(true);
|
|
72
|
+
expect(compiled.matches(field_pb_1.FieldProto.ASSET_CLASS, position_util_pb_1.PositionFilterOperator.NOT_EQUALS, 'FIXED_INCOME', 'EQUITY')).toBe(true);
|
|
73
|
+
const rows = ['RATES', 'EQUITY'].map(securityRow);
|
|
74
|
+
const kept = compiled.filterRows(rows, assetClassFilter(position_util_pb_1.PositionFilterOperator.EQUALS));
|
|
75
|
+
expect(assetClasses(kept)).toEqual(['RATES']);
|
|
76
|
+
});
|
|
77
|
+
});
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LM-281: the JS filter helper matches Java's PositionFilter row for row.
|
|
3
|
+
*
|
|
4
|
+
* ASSET_CLASS EQUALS / NOT_EQUALS use the shared assetClassMatches rule;
|
|
5
|
+
* every other field compares exactly. A null stored value never throws.
|
|
6
|
+
*/
|
|
7
|
+
import { FieldProto } from '../../../fintekkers/models/position/field_pb';
|
|
8
|
+
import { PositionFilterOperator } from '../../../fintekkers/models/position/position_util_pb';
|
|
9
|
+
import { SecurityProto } from '../../../fintekkers/models/security/security_pb';
|
|
10
|
+
import Security from '../security/security';
|
|
11
|
+
import { FilterableRow, FilterSpec, filterRows, matches } from './position_matcher';
|
|
12
|
+
|
|
13
|
+
function securityRow(assetClass: string): Security {
|
|
14
|
+
const proto = new SecurityProto();
|
|
15
|
+
proto.setAssetClass(assetClass);
|
|
16
|
+
return new Security(proto);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function stubRow(assetClass: string | null): FilterableRow {
|
|
20
|
+
return {
|
|
21
|
+
getField: (_field: FieldProto) => assetClass,
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function assetClasses(rows: FilterableRow[]): Array<string | null> {
|
|
26
|
+
return rows.map((row) => row.getField(FieldProto.ASSET_CLASS));
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function assetClassFilter(operator: PositionFilterOperator): FilterSpec[] {
|
|
30
|
+
return [{ field: FieldProto.ASSET_CLASS, operator, value: 'FIXED_INCOME' }];
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
describe('position_matcher', () => {
|
|
34
|
+
test('ASSET_CLASS EQUALS FIXED_INCOME matches group members', () => {
|
|
35
|
+
const rows = ['RATES', 'CREDIT', 'Fixed Income', 'EQUITY'].map(securityRow);
|
|
36
|
+
const result = filterRows(rows, assetClassFilter(PositionFilterOperator.EQUALS));
|
|
37
|
+
expect(assetClasses(result)).toEqual(['RATES', 'CREDIT', 'Fixed Income']);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
test('ASSET_CLASS NOT_EQUALS FIXED_INCOME keeps only non-members', () => {
|
|
41
|
+
const rows = ['RATES', 'CREDIT', 'Fixed Income', 'EQUITY'].map(securityRow);
|
|
42
|
+
const result = filterRows(rows, assetClassFilter(PositionFilterOperator.NOT_EQUALS));
|
|
43
|
+
expect(assetClasses(result)).toEqual(['EQUITY']);
|
|
44
|
+
});
|
|
45
|
+
|
|
46
|
+
test('null, empty and unknown stored values never throw', () => {
|
|
47
|
+
const rows = [stubRow(null), securityRow(''), securityRow('NOT_A_CLASS')];
|
|
48
|
+
const equals = assetClassFilter(PositionFilterOperator.EQUALS);
|
|
49
|
+
const notEquals = assetClassFilter(PositionFilterOperator.NOT_EQUALS);
|
|
50
|
+
expect(() => filterRows(rows, equals)).not.toThrow();
|
|
51
|
+
expect(filterRows(rows, equals)).toEqual([]);
|
|
52
|
+
expect(() => filterRows(rows, notEquals)).not.toThrow();
|
|
53
|
+
expect(assetClasses(filterRows(rows, notEquals))).toEqual([null, '', 'NOT_A_CLASS']);
|
|
54
|
+
});
|
|
55
|
+
|
|
56
|
+
test('other fields compare exactly', () => {
|
|
57
|
+
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.EQUALS, 'a', 'a')).toBe(true);
|
|
58
|
+
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.EQUALS, 'a', 'b')).toBe(false);
|
|
59
|
+
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.NOT_EQUALS, 'a', 'b')).toBe(true);
|
|
60
|
+
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.NOT_EQUALS, 'a', 'a')).toBe(false);
|
|
61
|
+
expect(matches(FieldProto.MATURITY_DATE, PositionFilterOperator.MORE_THAN, 1, 2)).toBe(true);
|
|
62
|
+
expect(matches(FieldProto.MATURITY_DATE, PositionFilterOperator.MORE_THAN, 2, 1)).toBe(false);
|
|
63
|
+
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.EQUALS, 'a', null)).toBe(false);
|
|
64
|
+
expect(matches(FieldProto.PORTFOLIO_NAME, PositionFilterOperator.NOT_EQUALS, 'a', null)).toBe(true);
|
|
65
|
+
});
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
describe('the published (compiled) position_matcher.js', () => {
|
|
69
|
+
// npm publish runs no tsc: the tracked .js is what consumers get.
|
|
70
|
+
// eslint-disable-next-line @typescript-eslint/no-var-requires
|
|
71
|
+
const compiled = require('./position_matcher.js');
|
|
72
|
+
|
|
73
|
+
test('exports working matches and filterRows', () => {
|
|
74
|
+
expect(typeof compiled.matches).toBe('function');
|
|
75
|
+
expect(typeof compiled.filterRows).toBe('function');
|
|
76
|
+
expect(
|
|
77
|
+
compiled.matches(
|
|
78
|
+
FieldProto.ASSET_CLASS,
|
|
79
|
+
PositionFilterOperator.EQUALS,
|
|
80
|
+
'FIXED_INCOME',
|
|
81
|
+
'RATES',
|
|
82
|
+
),
|
|
83
|
+
).toBe(true);
|
|
84
|
+
expect(
|
|
85
|
+
compiled.matches(
|
|
86
|
+
FieldProto.ASSET_CLASS,
|
|
87
|
+
PositionFilterOperator.NOT_EQUALS,
|
|
88
|
+
'FIXED_INCOME',
|
|
89
|
+
'EQUITY',
|
|
90
|
+
),
|
|
91
|
+
).toBe(true);
|
|
92
|
+
const rows = ['RATES', 'EQUITY'].map(securityRow);
|
|
93
|
+
const kept = compiled.filterRows(rows, assetClassFilter(PositionFilterOperator.EQUALS));
|
|
94
|
+
expect(assetClasses(kept)).toEqual(['RATES']);
|
|
95
|
+
});
|
|
96
|
+
});
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { FieldProto } from '../../../fintekkers/models/position/field_pb';
|
|
2
|
+
import { PositionFilterOperator } from '../../../fintekkers/models/position/position_util_pb';
|
|
3
|
+
import { assetClassMatches } from '../security/product_hierarchy';
|
|
4
|
+
|
|
5
|
+
/** A single filter clause: the field, operator and filter value. */
|
|
6
|
+
export interface FilterSpec {
|
|
7
|
+
field: FieldProto;
|
|
8
|
+
operator: PositionFilterOperator;
|
|
9
|
+
value: any;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** A row the matcher can read: the Security and Position wrappers qualify. */
|
|
13
|
+
export interface FilterableRow {
|
|
14
|
+
getField(field: FieldProto): any;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Single-field evaluator (LM-281), mirroring Java's PositionFilter.matches:
|
|
19
|
+
* ASSET_CLASS with EQUALS / NOT_EQUALS uses the shared assetClassMatches
|
|
20
|
+
* rule, so a group code such as FIXED_INCOME matches its members and labels;
|
|
21
|
+
* every other field compares exactly. A null or undefined stored value never
|
|
22
|
+
* throws: EQUALS and the ordering operators drop the row, NOT_EQUALS keeps
|
|
23
|
+
* it. An unknown operator matches nothing. Errors raised by row.getField
|
|
24
|
+
* propagate (a row represents an absent value by returning null).
|
|
25
|
+
*/
|
|
26
|
+
export function matches(
|
|
27
|
+
field: FieldProto,
|
|
28
|
+
operator: PositionFilterOperator,
|
|
29
|
+
filterValue: any,
|
|
30
|
+
storedValue: any,
|
|
31
|
+
): boolean {
|
|
32
|
+
if (storedValue === null || storedValue === undefined) {
|
|
33
|
+
return operator === PositionFilterOperator.NOT_EQUALS;
|
|
34
|
+
}
|
|
35
|
+
if (
|
|
36
|
+
field === FieldProto.ASSET_CLASS &&
|
|
37
|
+
(operator === PositionFilterOperator.EQUALS ||
|
|
38
|
+
operator === PositionFilterOperator.NOT_EQUALS)
|
|
39
|
+
) {
|
|
40
|
+
const equals = assetClassMatches(filterValue, storedValue);
|
|
41
|
+
return operator === PositionFilterOperator.EQUALS ? equals : !equals;
|
|
42
|
+
}
|
|
43
|
+
switch (operator) {
|
|
44
|
+
case PositionFilterOperator.EQUALS:
|
|
45
|
+
return storedValue === filterValue;
|
|
46
|
+
case PositionFilterOperator.NOT_EQUALS:
|
|
47
|
+
return storedValue !== filterValue;
|
|
48
|
+
case PositionFilterOperator.LESS_THAN:
|
|
49
|
+
return storedValue < filterValue;
|
|
50
|
+
case PositionFilterOperator.LESS_THAN_OR_EQUALS:
|
|
51
|
+
return storedValue <= filterValue;
|
|
52
|
+
case PositionFilterOperator.MORE_THAN:
|
|
53
|
+
return storedValue > filterValue;
|
|
54
|
+
case PositionFilterOperator.MORE_THAN_OR_EQUALS:
|
|
55
|
+
return storedValue >= filterValue;
|
|
56
|
+
default:
|
|
57
|
+
return false;
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Keep the rows matching every clause in `filters` (AND semantics, input
|
|
63
|
+
* order preserved).
|
|
64
|
+
*/
|
|
65
|
+
export function filterRows<T extends FilterableRow>(rows: T[], filters: FilterSpec[]): T[] {
|
|
66
|
+
return rows.filter((row) => {
|
|
67
|
+
return filters.every((spec) =>
|
|
68
|
+
matches(spec.field, spec.operator, spec.value, row.getField(spec.field)),
|
|
69
|
+
);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
@@ -39,6 +39,8 @@ const instrument_type_pb_1 = require("../../../fintekkers/models/security/instru
|
|
|
39
39
|
const product_type_pb_1 = require("../../../fintekkers/models/security/product_type_pb");
|
|
40
40
|
const PROTOS = path.resolve(__dirname, '../../../../../ledger-models-protos');
|
|
41
41
|
const rows = JSON.parse(fs.readFileSync(path.join(PROTOS, 'fixtures/asset_class_matches.json'), 'utf-8')).cases;
|
|
42
|
+
// LM-282: instrument-type code labels, shared with the Java, Python and Rust tests.
|
|
43
|
+
const instrumentTypeFixture = JSON.parse(fs.readFileSync(path.join(PROTOS, 'fixtures/instrument_type_labels.json'), 'utf-8'));
|
|
42
44
|
const hierarchy = JSON.parse(fs.readFileSync(path.join(PROTOS, 'hierarchy.json'), 'utf-8'));
|
|
43
45
|
describe('assetClassMatches shared fixture', () => {
|
|
44
46
|
test.each(rows)('assetClassMatches($filter, $stored) === $expected', ({ filter, stored, expected }) => {
|
|
@@ -142,5 +144,38 @@ describe('the published (compiled) product_hierarchy.js', () => {
|
|
|
142
144
|
expect(compiled.productTypeLabelOf(product_type_pb_1.ProductTypeProto.TBILL)).toBe('Treasury Bill');
|
|
143
145
|
expect(compiled.assetClassProtoLabelOf(asset_class_pb_1.AssetClassProto.CASH_ASSET_CLASS)).toBe('Cash');
|
|
144
146
|
});
|
|
147
|
+
test('instrument-type code labels match the .ts results', () => {
|
|
148
|
+
expect(compiled.allInstrumentTypes()).toEqual((0, product_hierarchy_1.allInstrumentTypes)());
|
|
149
|
+
for (const code of [...instrumentTypeFixture.codes, ...instrumentTypeFixture.unknown]) {
|
|
150
|
+
expect([code, compiled.instrumentTypeCodeLabelOf(code)]).toEqual([code, (0, product_hierarchy_1.instrumentTypeCodeLabelOf)(code)]);
|
|
151
|
+
}
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
describe('LM-282: instrument-type code labels', () => {
|
|
155
|
+
test('allInstrumentTypes() is the fixture codes, in order', () => {
|
|
156
|
+
expect(instrumentTypeFixture.codes).toEqual(['CASH', 'DERIVATIVE', 'REFERENCE_INDEX']);
|
|
157
|
+
expect((0, product_hierarchy_1.allInstrumentTypes)()).toEqual(instrumentTypeFixture.codes);
|
|
158
|
+
});
|
|
159
|
+
test('every code has a label; unknown codes and prototype keys get null', () => {
|
|
160
|
+
var _a;
|
|
161
|
+
for (const code of instrumentTypeFixture.codes) {
|
|
162
|
+
expect([code, ((_a = (0, product_hierarchy_1.instrumentTypeCodeLabelOf)(code)) !== null && _a !== void 0 ? _a : '').trim().length > 0]).toEqual([code, true]);
|
|
163
|
+
}
|
|
164
|
+
for (const code of [...instrumentTypeFixture.unknown, '__proto__', 'toString', 'constructor']) {
|
|
165
|
+
expect([code, (0, product_hierarchy_1.instrumentTypeCodeLabelOf)(code)]).toEqual([code, null]);
|
|
166
|
+
}
|
|
167
|
+
expect((0, product_hierarchy_1.instrumentTypeCodeLabelOf)(null)).toBeNull();
|
|
168
|
+
expect((0, product_hierarchy_1.instrumentTypeCodeLabelOf)(undefined)).toBeNull();
|
|
169
|
+
});
|
|
170
|
+
test('each code label equals instrumentTypeLabelOf(INSTRUMENT_TYPE_<CODE>)', () => {
|
|
171
|
+
for (const code of instrumentTypeFixture.codes) {
|
|
172
|
+
const v = instrument_type_pb_1.InstrumentTypeProto[`INSTRUMENT_TYPE_${code}`];
|
|
173
|
+
expect(v).toBeDefined();
|
|
174
|
+
expect([code, (0, product_hierarchy_1.instrumentTypeCodeLabelOf)(code)]).toEqual([code, (0, product_hierarchy_1.instrumentTypeLabelOf)(v)]);
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
test('INSTRUMENT_TYPE_UNKNOWN keeps its label', () => {
|
|
178
|
+
expect((0, product_hierarchy_1.instrumentTypeLabelOf)(instrument_type_pb_1.InstrumentTypeProto.INSTRUMENT_TYPE_UNKNOWN)).toBe('Unknown');
|
|
179
|
+
});
|
|
145
180
|
});
|
|
146
181
|
//# sourceMappingURL=asset_class_vocabulary.test.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"asset_class_vocabulary.test.js","sourceRoot":"","sources":["asset_class_vocabulary.test.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;AAAA;;;;;;GAMG;AACH,uCAAyB;AACzB,2CAA6B;AAE7B,
|
|
1
|
+
{"version":3,"file":"asset_class_vocabulary.test.js","sourceRoot":"","sources":["asset_class_vocabulary.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -9,11 +9,13 @@ import * as fs from 'fs';
|
|
|
9
9
|
import * as path from 'path';
|
|
10
10
|
|
|
11
11
|
import {
|
|
12
|
+
allInstrumentTypes,
|
|
12
13
|
assetClassMatches,
|
|
13
14
|
assetClassProtoLabelOf,
|
|
14
15
|
buildAssetClassLookup,
|
|
15
16
|
identifierTypeLabelOf,
|
|
16
17
|
identifierTypePlaceholderOf,
|
|
18
|
+
instrumentTypeCodeLabelOf,
|
|
17
19
|
instrumentTypeLabelOf,
|
|
18
20
|
productTypeLabelOf,
|
|
19
21
|
} from './product_hierarchy';
|
|
@@ -34,6 +36,11 @@ const rows: FixtureRow[] = JSON.parse(
|
|
|
34
36
|
fs.readFileSync(path.join(PROTOS, 'fixtures/asset_class_matches.json'), 'utf-8'),
|
|
35
37
|
).cases;
|
|
36
38
|
|
|
39
|
+
// LM-282: instrument-type code labels, shared with the Java, Python and Rust tests.
|
|
40
|
+
const instrumentTypeFixture: { codes: string[]; unknown: string[] } = JSON.parse(
|
|
41
|
+
fs.readFileSync(path.join(PROTOS, 'fixtures/instrument_type_labels.json'), 'utf-8'),
|
|
42
|
+
);
|
|
43
|
+
|
|
37
44
|
const hierarchy = JSON.parse(fs.readFileSync(path.join(PROTOS, 'hierarchy.json'), 'utf-8'));
|
|
38
45
|
|
|
39
46
|
describe('assetClassMatches shared fixture', () => {
|
|
@@ -149,4 +156,41 @@ describe('the published (compiled) product_hierarchy.js', () => {
|
|
|
149
156
|
expect(compiled.productTypeLabelOf(ProductTypeProto.TBILL)).toBe('Treasury Bill');
|
|
150
157
|
expect(compiled.assetClassProtoLabelOf(AssetClassProto.CASH_ASSET_CLASS)).toBe('Cash');
|
|
151
158
|
});
|
|
159
|
+
|
|
160
|
+
test('instrument-type code labels match the .ts results', () => {
|
|
161
|
+
expect(compiled.allInstrumentTypes()).toEqual(allInstrumentTypes());
|
|
162
|
+
for (const code of [...instrumentTypeFixture.codes, ...instrumentTypeFixture.unknown]) {
|
|
163
|
+
expect([code, compiled.instrumentTypeCodeLabelOf(code)]).toEqual([code, instrumentTypeCodeLabelOf(code)]);
|
|
164
|
+
}
|
|
165
|
+
});
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
describe('LM-282: instrument-type code labels', () => {
|
|
169
|
+
test('allInstrumentTypes() is the fixture codes, in order', () => {
|
|
170
|
+
expect(instrumentTypeFixture.codes).toEqual(['CASH', 'DERIVATIVE', 'REFERENCE_INDEX']);
|
|
171
|
+
expect(allInstrumentTypes()).toEqual(instrumentTypeFixture.codes);
|
|
172
|
+
});
|
|
173
|
+
|
|
174
|
+
test('every code has a label; unknown codes and prototype keys get null', () => {
|
|
175
|
+
for (const code of instrumentTypeFixture.codes) {
|
|
176
|
+
expect([code, (instrumentTypeCodeLabelOf(code) ?? '').trim().length > 0]).toEqual([code, true]);
|
|
177
|
+
}
|
|
178
|
+
for (const code of [...instrumentTypeFixture.unknown, '__proto__', 'toString', 'constructor']) {
|
|
179
|
+
expect([code, instrumentTypeCodeLabelOf(code)]).toEqual([code, null]);
|
|
180
|
+
}
|
|
181
|
+
expect(instrumentTypeCodeLabelOf(null)).toBeNull();
|
|
182
|
+
expect(instrumentTypeCodeLabelOf(undefined)).toBeNull();
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
test('each code label equals instrumentTypeLabelOf(INSTRUMENT_TYPE_<CODE>)', () => {
|
|
186
|
+
for (const code of instrumentTypeFixture.codes) {
|
|
187
|
+
const v = (InstrumentTypeProto as unknown as Record<string, InstrumentTypeProto>)[`INSTRUMENT_TYPE_${code}`];
|
|
188
|
+
expect(v).toBeDefined();
|
|
189
|
+
expect([code, instrumentTypeCodeLabelOf(code)]).toEqual([code, instrumentTypeLabelOf(v)]);
|
|
190
|
+
}
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
test('INSTRUMENT_TYPE_UNKNOWN keeps its label', () => {
|
|
194
|
+
expect(instrumentTypeLabelOf(InstrumentTypeProto.INSTRUMENT_TYPE_UNKNOWN)).toBe('Unknown');
|
|
195
|
+
});
|
|
152
196
|
});
|
|
@@ -71,7 +71,13 @@ export declare function identifierTypeLabelOf(v: IdentifierTypeProto): string |
|
|
|
71
71
|
/** Input placeholder (e.g. "e.g. US0378331005") for an IdentifierTypeProto
|
|
72
72
|
* value, or null if unknown. */
|
|
73
73
|
export declare function identifierTypePlaceholderOf(v: IdentifierTypeProto): string | null;
|
|
74
|
-
/** Display label for an
|
|
74
|
+
/** Display label for an instrument-type code from allInstrumentTypes()
|
|
75
|
+
* (e.g. CASH -> "Cash"). null for null/undefined or an unknown code; the match
|
|
76
|
+
* is exact. */
|
|
77
|
+
export declare function instrumentTypeCodeLabelOf(code: string | null | undefined): string | null;
|
|
78
|
+
/** Display label for an InstrumentTypeProto value: the instrument_types label
|
|
79
|
+
* of its code (INSTRUMENT_TYPE_CASH -> CASH -> "Cash"), else enum_labels
|
|
80
|
+
* (e.g. INSTRUMENT_TYPE_UNKNOWN). null if unknown. */
|
|
75
81
|
export declare function instrumentTypeLabelOf(v: InstrumentTypeProto): string | null;
|
|
76
82
|
/** Display label for a ProductTypeProto value: the product_types label, else
|
|
77
83
|
* enum_labels (e.g. PRODUCT_TYPE_UNKNOWN). null if unknown. */
|
|
@@ -28,7 +28,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
28
28
|
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
29
29
|
};
|
|
30
30
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
31
|
-
exports.allInstrumentTypes = exports.allAssetClasses = exports.activeProductTypes = exports.allProductTypes = exports.assetClassProtoLabelOf = exports.productTypeLabelOf = exports.instrumentTypeLabelOf = exports.identifierTypePlaceholderOf = exports.identifierTypeLabelOf = exports.assetClassMatches = exports.resolveAssetClass = exports.buildAssetClassLookup = exports.assetClassLabelOf = exports.isAssetClassDescendantOf = exports.assetClassDescendantsOf = exports.assetClassParentOf = exports.instrumentTypeOf = exports.assetClassOf = exports.labelOf = exports.isDescendantOf = exports.descendantsOf = exports.parentOf = void 0;
|
|
31
|
+
exports.allInstrumentTypes = exports.allAssetClasses = exports.activeProductTypes = exports.allProductTypes = exports.assetClassProtoLabelOf = exports.productTypeLabelOf = exports.instrumentTypeLabelOf = exports.instrumentTypeCodeLabelOf = exports.identifierTypePlaceholderOf = exports.identifierTypeLabelOf = exports.assetClassMatches = exports.resolveAssetClass = exports.buildAssetClassLookup = exports.assetClassLabelOf = exports.isAssetClassDescendantOf = exports.assetClassDescendantsOf = exports.assetClassParentOf = exports.instrumentTypeOf = exports.assetClassOf = exports.labelOf = exports.isDescendantOf = exports.descendantsOf = exports.parentOf = void 0;
|
|
32
32
|
// hierarchy.json is bundled into the npm package via the package's `files`
|
|
33
33
|
// list (see package.json). Bundlers handle this `import` at build time
|
|
34
34
|
// (TypeScript's resolveJsonModule is enabled).
|
|
@@ -41,6 +41,14 @@ const registry = hierarchy_json_1.default;
|
|
|
41
41
|
function hasOwn(o, key) {
|
|
42
42
|
return o !== undefined && Object.prototype.hasOwnProperty.call(o, key);
|
|
43
43
|
}
|
|
44
|
+
/** Prefix that turns an instrument-type code into its InstrumentTypeProto value name. */
|
|
45
|
+
const INSTRUMENT_TYPE_PREFIX = 'INSTRUMENT_TYPE_';
|
|
46
|
+
// Every instrument_types code needs an INSTRUMENT_TYPE_<CODE> enum value.
|
|
47
|
+
for (const code of Object.keys(registry.instrument_types)) {
|
|
48
|
+
if (!hasOwn(instrument_type_pb_1.InstrumentTypeProto, INSTRUMENT_TYPE_PREFIX + code)) {
|
|
49
|
+
throw new Error(`hierarchy.json instrument_types: no InstrumentTypeProto value for '${code}'`);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
44
52
|
// ---------- product_type tree ----------
|
|
45
53
|
/** Parent product_type node (abstract or leaf). null for top-level nodes;
|
|
46
54
|
* null for unknown nodes. */
|
|
@@ -228,10 +236,31 @@ function identifierTypePlaceholderOf(v) {
|
|
|
228
236
|
return (_b = (_a = enumEntry('IdentifierTypeProto', enumValueName(identifier_type_pb_1.IdentifierTypeProto, v))) === null || _a === void 0 ? void 0 : _a.placeholder) !== null && _b !== void 0 ? _b : null;
|
|
229
237
|
}
|
|
230
238
|
exports.identifierTypePlaceholderOf = identifierTypePlaceholderOf;
|
|
231
|
-
/**
|
|
239
|
+
/** Instrument-type code for an enum value name (INSTRUMENT_TYPE_CASH -> CASH), or null. */
|
|
240
|
+
function instrumentTypeCode(valueName) {
|
|
241
|
+
return valueName.startsWith(INSTRUMENT_TYPE_PREFIX)
|
|
242
|
+
? valueName.slice(INSTRUMENT_TYPE_PREFIX.length)
|
|
243
|
+
: null;
|
|
244
|
+
}
|
|
245
|
+
/** Display label for an instrument-type code from allInstrumentTypes()
|
|
246
|
+
* (e.g. CASH -> "Cash"). null for null/undefined or an unknown code; the match
|
|
247
|
+
* is exact. */
|
|
248
|
+
function instrumentTypeCodeLabelOf(code) {
|
|
249
|
+
var _a;
|
|
250
|
+
if (typeof code !== 'string' || !hasOwn(registry.instrument_types, code))
|
|
251
|
+
return null;
|
|
252
|
+
return (_a = registry.instrument_types[code].label) !== null && _a !== void 0 ? _a : null;
|
|
253
|
+
}
|
|
254
|
+
exports.instrumentTypeCodeLabelOf = instrumentTypeCodeLabelOf;
|
|
255
|
+
/** Display label for an InstrumentTypeProto value: the instrument_types label
|
|
256
|
+
* of its code (INSTRUMENT_TYPE_CASH -> CASH -> "Cash"), else enum_labels
|
|
257
|
+
* (e.g. INSTRUMENT_TYPE_UNKNOWN). null if unknown. */
|
|
232
258
|
function instrumentTypeLabelOf(v) {
|
|
233
|
-
var _a, _b;
|
|
234
|
-
|
|
259
|
+
var _a, _b, _c;
|
|
260
|
+
const name = enumValueName(instrument_type_pb_1.InstrumentTypeProto, v);
|
|
261
|
+
if (name === null)
|
|
262
|
+
return null;
|
|
263
|
+
return (_c = (_a = instrumentTypeCodeLabelOf(instrumentTypeCode(name))) !== null && _a !== void 0 ? _a : (_b = enumEntry('InstrumentTypeProto', name)) === null || _b === void 0 ? void 0 : _b.label) !== null && _c !== void 0 ? _c : null;
|
|
235
264
|
}
|
|
236
265
|
exports.instrumentTypeLabelOf = instrumentTypeLabelOf;
|
|
237
266
|
/** Display label for a ProductTypeProto value: the product_types label, else
|
|
@@ -276,7 +305,7 @@ function allAssetClasses() {
|
|
|
276
305
|
}
|
|
277
306
|
exports.allAssetClasses = allAssetClasses;
|
|
278
307
|
function allInstrumentTypes() {
|
|
279
|
-
return
|
|
308
|
+
return Object.keys(registry.instrument_types);
|
|
280
309
|
}
|
|
281
310
|
exports.allInstrumentTypes = allInstrumentTypes;
|
|
282
311
|
//# sourceMappingURL=product_hierarchy.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product_hierarchy.js","sourceRoot":"","sources":["product_hierarchy.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;;;;;;AAEH,2EAA2E;AAC3E,uEAAuE;AACvE,+CAA+C;AAC/C,gFAAmD;AACnD,uFAAqF;AACrF,0GAAwG;AACxG,+FAA6F;AAC7F,yFAAuF;
|
|
1
|
+
{"version":3,"file":"product_hierarchy.js","sourceRoot":"","sources":["product_hierarchy.ts"],"names":[],"mappings":"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"}
|
|
@@ -48,6 +48,10 @@ interface AssetClassEntry {
|
|
|
48
48
|
aliases?: string[];
|
|
49
49
|
}
|
|
50
50
|
|
|
51
|
+
interface InstrumentTypeEntry {
|
|
52
|
+
label?: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
51
55
|
interface EnumLabelEntry {
|
|
52
56
|
label?: string;
|
|
53
57
|
placeholder?: string;
|
|
@@ -56,7 +60,7 @@ interface EnumLabelEntry {
|
|
|
56
60
|
interface Registry {
|
|
57
61
|
product_types: Record<string, ProductTypeEntry>;
|
|
58
62
|
asset_classes: Record<string, AssetClassEntry>;
|
|
59
|
-
instrument_types: string
|
|
63
|
+
instrument_types: Record<string, InstrumentTypeEntry>;
|
|
60
64
|
enum_labels?: Record<string, Record<string, EnumLabelEntry>>;
|
|
61
65
|
}
|
|
62
66
|
|
|
@@ -66,6 +70,16 @@ function hasOwn(o: object | undefined, key: string): boolean {
|
|
|
66
70
|
return o !== undefined && Object.prototype.hasOwnProperty.call(o, key);
|
|
67
71
|
}
|
|
68
72
|
|
|
73
|
+
/** Prefix that turns an instrument-type code into its InstrumentTypeProto value name. */
|
|
74
|
+
const INSTRUMENT_TYPE_PREFIX = 'INSTRUMENT_TYPE_';
|
|
75
|
+
|
|
76
|
+
// Every instrument_types code needs an INSTRUMENT_TYPE_<CODE> enum value.
|
|
77
|
+
for (const code of Object.keys(registry.instrument_types)) {
|
|
78
|
+
if (!hasOwn(InstrumentTypeProto, INSTRUMENT_TYPE_PREFIX + code)) {
|
|
79
|
+
throw new Error(`hierarchy.json instrument_types: no InstrumentTypeProto value for '${code}'`);
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
|
|
69
83
|
// ---------- product_type tree ----------
|
|
70
84
|
|
|
71
85
|
/** Parent product_type node (abstract or leaf). null for top-level nodes;
|
|
@@ -240,9 +254,28 @@ export function identifierTypePlaceholderOf(v: IdentifierTypeProto): string | nu
|
|
|
240
254
|
return enumEntry('IdentifierTypeProto', enumValueName(IdentifierTypeProto, v))?.placeholder ?? null;
|
|
241
255
|
}
|
|
242
256
|
|
|
243
|
-
/**
|
|
257
|
+
/** Instrument-type code for an enum value name (INSTRUMENT_TYPE_CASH -> CASH), or null. */
|
|
258
|
+
function instrumentTypeCode(valueName: string): string | null {
|
|
259
|
+
return valueName.startsWith(INSTRUMENT_TYPE_PREFIX)
|
|
260
|
+
? valueName.slice(INSTRUMENT_TYPE_PREFIX.length)
|
|
261
|
+
: null;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/** Display label for an instrument-type code from allInstrumentTypes()
|
|
265
|
+
* (e.g. CASH -> "Cash"). null for null/undefined or an unknown code; the match
|
|
266
|
+
* is exact. */
|
|
267
|
+
export function instrumentTypeCodeLabelOf(code: string | null | undefined): string | null {
|
|
268
|
+
if (typeof code !== 'string' || !hasOwn(registry.instrument_types, code)) return null;
|
|
269
|
+
return registry.instrument_types[code].label ?? null;
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
/** Display label for an InstrumentTypeProto value: the instrument_types label
|
|
273
|
+
* of its code (INSTRUMENT_TYPE_CASH -> CASH -> "Cash"), else enum_labels
|
|
274
|
+
* (e.g. INSTRUMENT_TYPE_UNKNOWN). null if unknown. */
|
|
244
275
|
export function instrumentTypeLabelOf(v: InstrumentTypeProto): string | null {
|
|
245
|
-
|
|
276
|
+
const name = enumValueName(InstrumentTypeProto, v);
|
|
277
|
+
if (name === null) return null;
|
|
278
|
+
return instrumentTypeCodeLabelOf(instrumentTypeCode(name)) ?? enumEntry('InstrumentTypeProto', name)?.label ?? null;
|
|
246
279
|
}
|
|
247
280
|
|
|
248
281
|
/** Display label for a ProductTypeProto value: the product_types label, else
|
|
@@ -283,5 +316,5 @@ export function allAssetClasses(): string[] {
|
|
|
283
316
|
}
|
|
284
317
|
|
|
285
318
|
export function allInstrumentTypes(): string[] {
|
|
286
|
-
return
|
|
319
|
+
return Object.keys(registry.instrument_types);
|
|
287
320
|
}
|