@cranberry-money/shared-utils 8.1.0 → 8.3.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.
@@ -0,0 +1,72 @@
1
+ import type { AssetAllocation, AssetHolding } from '@cranberry-money/shared-types';
2
+ /**
3
+ * Display item interface for allocation data
4
+ */
5
+ export interface AllocationDisplayItem {
6
+ readonly instrumentUuid: string;
7
+ readonly symbol: string;
8
+ readonly name: string;
9
+ readonly targetPercentage?: number;
10
+ readonly actualPercentage?: number;
11
+ readonly quantity?: number;
12
+ readonly value?: number;
13
+ readonly currentPrice?: number;
14
+ readonly color: string;
15
+ readonly hasTarget: boolean;
16
+ readonly hasActual: boolean;
17
+ }
18
+ /**
19
+ * Processes allocation and holding data for dashboard display
20
+ * Merges target allocations with actual holdings data
21
+ *
22
+ * @param allocations - Target asset allocations
23
+ * @param holdings - Actual asset holdings
24
+ * @returns Array of display items sorted by target/actual percentage
25
+ *
26
+ * @example
27
+ * const allocations = [{ instrument: '123', percentage: '50.00', ... }];
28
+ * const holdings = [{ instrument: { uuid: '123' }, quantity: 100, ... }];
29
+ * processAllocationData(allocations, holdings);
30
+ */
31
+ export declare const processAllocationData: (allocations: readonly AssetAllocation[], holdings: readonly AssetHolding[]) => AllocationDisplayItem[];
32
+ /**
33
+ * Calculates totals from allocation display items
34
+ *
35
+ * @param items - Array of allocation display items
36
+ * @returns Object with total calculations
37
+ *
38
+ * @example
39
+ * const items = [{ targetPercentage: 50, actualPercentage: 45, value: 1000, quantity: 10 }];
40
+ * calculateTotals(items);
41
+ * // returns { totalTarget: 50, totalActual: 45, totalValue: 1000, totalQuantity: 10 }
42
+ */
43
+ export declare const calculateTotals: (items: readonly AllocationDisplayItem[]) => {
44
+ totalTarget: number;
45
+ totalActual: number;
46
+ totalValue: number;
47
+ totalQuantity: number;
48
+ };
49
+ /**
50
+ * Formats a percentage value for display
51
+ *
52
+ * @param value - The percentage value to format
53
+ * @returns Formatted percentage string
54
+ *
55
+ * @example
56
+ * formatPercentage(45.678); // returns "45.7%"
57
+ * formatPercentage(undefined); // returns "0.0%"
58
+ */
59
+ export declare const formatPercentage: (value?: number) => string;
60
+ /**
61
+ * Formats currency value for dashboard display
62
+ *
63
+ * @param value - The numeric value to format
64
+ * @param currency - Currency code (defaults to DEFAULT_CURRENCY)
65
+ * @returns Formatted currency string or "—" for undefined values
66
+ *
67
+ * @example
68
+ * formatDashboardCurrency(1234.56); // returns "$1,234.56"
69
+ * formatDashboardCurrency(undefined); // returns "—"
70
+ */
71
+ export declare const formatDashboardCurrency: (value?: number, currency?: string) => string;
72
+ //# sourceMappingURL=dashboard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dashboard.d.ts","sourceRoot":"","sources":["../src/dashboard.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAMnF;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAC;IAChC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,MAAM,CAAC;IACnC,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,YAAY,CAAC,EAAE,MAAM,CAAC;IAC/B,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;IACvB,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,SAAS,EAAE,OAAO,CAAC;CAC7B;AAED;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,qBAAqB,GAChC,aAAa,SAAS,eAAe,EAAE,EACvC,UAAU,SAAS,YAAY,EAAE,KAChC,qBAAqB,EAwEvB,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,eAAe,GAAI,OAAO,SAAS,qBAAqB,EAAE;;;;;CAOtE,CAAC;AAEF;;;;;;;;;GASG;AACH,eAAO,MAAM,gBAAgB,GAAI,QAAQ,MAAM,KAAG,MAGjD,CAAC;AAEF;;;;;;;;;;GAUG;AACH,eAAO,MAAM,uBAAuB,GAAI,QAAQ,MAAM,EAAE,WAAU,MAAyB,KAAG,MAG7F,CAAC"}
@@ -0,0 +1,121 @@
1
+ import { DEFAULT_CURRENCY } from '@cranberry-money/shared-constants';
2
+ import { getChartColor } from '@cranberry-money/shared-constants';
3
+ import { formatCurrencyWithCode } from './currency';
4
+ import { calculateHoldingAllocations } from './holdings';
5
+ /**
6
+ * Processes allocation and holding data for dashboard display
7
+ * Merges target allocations with actual holdings data
8
+ *
9
+ * @param allocations - Target asset allocations
10
+ * @param holdings - Actual asset holdings
11
+ * @returns Array of display items sorted by target/actual percentage
12
+ *
13
+ * @example
14
+ * const allocations = [{ instrument: '123', percentage: '50.00', ... }];
15
+ * const holdings = [{ instrument: { uuid: '123' }, quantity: 100, ... }];
16
+ * processAllocationData(allocations, holdings);
17
+ */
18
+ export const processAllocationData = (allocations, holdings) => {
19
+ const actualAllocations = calculateHoldingAllocations(holdings);
20
+ const instrumentMap = new Map();
21
+ // Process target allocations
22
+ allocations.forEach((allocation) => {
23
+ instrumentMap.set(allocation.instrument, {
24
+ symbol: allocation.instrumentSymbol,
25
+ name: allocation.instrumentName,
26
+ targetPercentage: parseFloat(allocation.percentage),
27
+ });
28
+ });
29
+ // Process actual holdings
30
+ holdings.forEach((holding) => {
31
+ const existing = instrumentMap.get(holding.instrument.uuid);
32
+ const currentPrice = parseFloat(holding.instrument.currentPrice || '0');
33
+ const value = holding.quantity * currentPrice;
34
+ instrumentMap.set(holding.instrument.uuid, {
35
+ symbol: holding.instrumentSymbol,
36
+ name: holding.instrumentName,
37
+ targetPercentage: existing?.targetPercentage,
38
+ actualPercentage: actualAllocations[holding.instrument.uuid] || 0,
39
+ quantity: holding.quantity,
40
+ currentPrice,
41
+ value,
42
+ });
43
+ });
44
+ // Convert to display items
45
+ const items = [];
46
+ let colorIndex = 0;
47
+ instrumentMap.forEach((data, instrumentUuid) => {
48
+ items.push({
49
+ instrumentUuid,
50
+ symbol: data.symbol,
51
+ name: data.name,
52
+ targetPercentage: data.targetPercentage,
53
+ actualPercentage: data.actualPercentage,
54
+ quantity: data.quantity,
55
+ currentPrice: data.currentPrice,
56
+ value: data.value,
57
+ color: getChartColor(colorIndex++),
58
+ hasTarget: data.targetPercentage !== undefined,
59
+ hasActual: data.actualPercentage !== undefined && data.actualPercentage > 0,
60
+ });
61
+ });
62
+ // Sort by target percentage (highest first), then by actual percentage
63
+ return items.sort((a, b) => {
64
+ const aTarget = a.targetPercentage || 0;
65
+ const bTarget = b.targetPercentage || 0;
66
+ if (aTarget !== bTarget)
67
+ return bTarget - aTarget;
68
+ const aActual = a.actualPercentage || 0;
69
+ const bActual = b.actualPercentage || 0;
70
+ return bActual - aActual;
71
+ });
72
+ };
73
+ /**
74
+ * Calculates totals from allocation display items
75
+ *
76
+ * @param items - Array of allocation display items
77
+ * @returns Object with total calculations
78
+ *
79
+ * @example
80
+ * const items = [{ targetPercentage: 50, actualPercentage: 45, value: 1000, quantity: 10 }];
81
+ * calculateTotals(items);
82
+ * // returns { totalTarget: 50, totalActual: 45, totalValue: 1000, totalQuantity: 10 }
83
+ */
84
+ export const calculateTotals = (items) => {
85
+ const totalTarget = items.reduce((sum, item) => sum + (item.targetPercentage || 0), 0);
86
+ const totalActual = items.reduce((sum, item) => sum + (item.actualPercentage || 0), 0);
87
+ const totalValue = items.reduce((sum, item) => sum + (item.value || 0), 0);
88
+ const totalQuantity = items.reduce((sum, item) => sum + (item.quantity || 0), 0);
89
+ return { totalTarget, totalActual, totalValue, totalQuantity };
90
+ };
91
+ /**
92
+ * Formats a percentage value for display
93
+ *
94
+ * @param value - The percentage value to format
95
+ * @returns Formatted percentage string
96
+ *
97
+ * @example
98
+ * formatPercentage(45.678); // returns "45.7%"
99
+ * formatPercentage(undefined); // returns "0.0%"
100
+ */
101
+ export const formatPercentage = (value) => {
102
+ if (value === undefined)
103
+ return '0.0%';
104
+ return `${value.toFixed(1)}%`;
105
+ };
106
+ /**
107
+ * Formats currency value for dashboard display
108
+ *
109
+ * @param value - The numeric value to format
110
+ * @param currency - Currency code (defaults to DEFAULT_CURRENCY)
111
+ * @returns Formatted currency string or "—" for undefined values
112
+ *
113
+ * @example
114
+ * formatDashboardCurrency(1234.56); // returns "$1,234.56"
115
+ * formatDashboardCurrency(undefined); // returns "—"
116
+ */
117
+ export const formatDashboardCurrency = (value, currency = DEFAULT_CURRENCY) => {
118
+ if (value === undefined || value === null)
119
+ return '—';
120
+ return formatCurrencyWithCode(value, currency, 'en-AU', 2, 2);
121
+ };
@@ -0,0 +1,79 @@
1
+ import type { AssetHolding } from '@cranberry-money/shared-types';
2
+ import { type SortDirection } from '@cranberry-money/shared-constants';
3
+ /**
4
+ * Calculates the total portfolio value based on holdings and instrument prices
5
+ *
6
+ * @param holdings - Array of asset holdings
7
+ * @param prices - Map of instrument UUIDs to their current prices
8
+ * @returns Total portfolio value
9
+ *
10
+ * @example
11
+ * const holdings = [
12
+ * { instrument: { uuid: '123' }, quantity: 100 },
13
+ * { instrument: { uuid: '456' }, quantity: 50 }
14
+ * ];
15
+ * const prices = { '123': 10.50, '456': 25.00 };
16
+ * calculatePortfolioValue(holdings, prices); // returns 2300
17
+ */
18
+ export declare const calculatePortfolioValue: (holdings: readonly AssetHolding[], prices: Record<string, number>) => number;
19
+ /**
20
+ * Calculates holding allocation percentages within a portfolio
21
+ *
22
+ * @param holdings - Array of asset holdings
23
+ * @returns Map of instrument UUIDs to their percentage allocations
24
+ *
25
+ * @example
26
+ * const holdings = [
27
+ * { instrument: { uuid: '123' }, quantity: 100 },
28
+ * { instrument: { uuid: '456' }, quantity: 100 }
29
+ * ];
30
+ * calculateHoldingAllocations(holdings); // returns { '123': 50, '456': 50 }
31
+ */
32
+ export declare const calculateHoldingAllocations: (holdings: readonly AssetHolding[]) => Record<string, number>;
33
+ /**
34
+ * Groups holdings by instrument UUID for aggregated view
35
+ *
36
+ * @param holdings - Array of asset holdings to group
37
+ * @returns Map of instrument UUIDs to their holdings arrays
38
+ *
39
+ * @example
40
+ * const holdings = [
41
+ * { instrument: { uuid: '123' }, quantity: 100 },
42
+ * { instrument: { uuid: '123' }, quantity: 50 },
43
+ * { instrument: { uuid: '456' }, quantity: 200 }
44
+ * ];
45
+ * groupHoldingsByInstrument(holdings);
46
+ * // returns { '123': [holding1, holding2], '456': [holding3] }
47
+ */
48
+ export declare const groupHoldingsByInstrument: (holdings: readonly AssetHolding[]) => Record<string, AssetHolding[]>;
49
+ /**
50
+ * Filters holdings with quantities above a threshold
51
+ *
52
+ * @param holdings - Array of asset holdings
53
+ * @param minQuantity - Minimum quantity threshold
54
+ * @returns Filtered array of holdings
55
+ *
56
+ * @example
57
+ * const holdings = [
58
+ * { quantity: 100 },
59
+ * { quantity: 50 },
60
+ * { quantity: 200 }
61
+ * ];
62
+ * filterHoldingsByMinQuantity(holdings, 75); // returns holdings with quantity >= 75
63
+ */
64
+ export declare const filterHoldingsByMinQuantity: (holdings: readonly AssetHolding[], minQuantity: number) => AssetHolding[];
65
+ /**
66
+ * Sorts holdings by various criteria
67
+ *
68
+ * @param holdings - Array of asset holdings to sort
69
+ * @param sortBy - Field to sort by
70
+ * @param direction - Sort direction (ascending or descending)
71
+ * @returns Sorted array of holdings
72
+ *
73
+ * @example
74
+ * const holdings = [...];
75
+ * sortHoldings(holdings, 'quantity', 'desc'); // Sort by quantity descending
76
+ * sortHoldings(holdings, 'symbol', 'asc'); // Sort by symbol ascending
77
+ */
78
+ export declare const sortHoldings: (holdings: readonly AssetHolding[], sortBy: "quantity" | "symbol" | "name" | "createdAt", direction?: SortDirection) => AssetHolding[];
79
+ //# sourceMappingURL=holdings.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"holdings.d.ts","sourceRoot":"","sources":["../src/holdings.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,+BAA+B,CAAC;AAClE,OAAO,EAAiE,KAAK,aAAa,EAAE,MAAM,mCAAmC,CAAC;AAGtI;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,uBAAuB,GAAI,UAAU,SAAS,YAAY,EAAE,EAAE,QAAQ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,KAAG,MAK3G,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,2BAA2B,GAAI,UAAU,SAAS,YAAY,EAAE,KAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAWpG,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,yBAAyB,GAAI,UAAU,SAAS,YAAY,EAAE,KAAG,MAAM,CAAC,MAAM,EAAE,YAAY,EAAE,CAS1G,CAAC;AAEF;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,2BAA2B,GAAI,UAAU,SAAS,YAAY,EAAE,EAAE,aAAa,MAAM,KAAG,YAAY,EAEhH,CAAC;AAEF;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,YAAY,GACvB,UAAU,SAAS,YAAY,EAAE,EACjC,QAAQ,UAAU,GAAG,QAAQ,GAAG,MAAM,GAAG,WAAW,EACpD,YAAW,aAAmC,KAC7C,YAAY,EA0Cd,CAAC"}
@@ -0,0 +1,139 @@
1
+ import { DEFAULT_NUMERIC_ZERO, SORT_DIRECTION_ASC, SORT_DIRECTION_DESC } from '@cranberry-money/shared-constants';
2
+ import { sortByStringField } from './collections';
3
+ /**
4
+ * Calculates the total portfolio value based on holdings and instrument prices
5
+ *
6
+ * @param holdings - Array of asset holdings
7
+ * @param prices - Map of instrument UUIDs to their current prices
8
+ * @returns Total portfolio value
9
+ *
10
+ * @example
11
+ * const holdings = [
12
+ * { instrument: { uuid: '123' }, quantity: 100 },
13
+ * { instrument: { uuid: '456' }, quantity: 50 }
14
+ * ];
15
+ * const prices = { '123': 10.50, '456': 25.00 };
16
+ * calculatePortfolioValue(holdings, prices); // returns 2300
17
+ */
18
+ export const calculatePortfolioValue = (holdings, prices) => {
19
+ return holdings.reduce((total, holding) => {
20
+ const price = prices[holding.instrument.uuid] || DEFAULT_NUMERIC_ZERO;
21
+ return total + holding.quantity * price;
22
+ }, 0);
23
+ };
24
+ /**
25
+ * Calculates holding allocation percentages within a portfolio
26
+ *
27
+ * @param holdings - Array of asset holdings
28
+ * @returns Map of instrument UUIDs to their percentage allocations
29
+ *
30
+ * @example
31
+ * const holdings = [
32
+ * { instrument: { uuid: '123' }, quantity: 100 },
33
+ * { instrument: { uuid: '456' }, quantity: 100 }
34
+ * ];
35
+ * calculateHoldingAllocations(holdings); // returns { '123': 50, '456': 50 }
36
+ */
37
+ export const calculateHoldingAllocations = (holdings) => {
38
+ const totalQuantity = holdings.reduce((sum, holding) => sum + holding.quantity, 0);
39
+ if (totalQuantity === 0)
40
+ return {};
41
+ const allocations = {};
42
+ holdings.forEach((holding) => {
43
+ allocations[holding.instrument.uuid] = (holding.quantity / totalQuantity) * 100;
44
+ });
45
+ return allocations;
46
+ };
47
+ /**
48
+ * Groups holdings by instrument UUID for aggregated view
49
+ *
50
+ * @param holdings - Array of asset holdings to group
51
+ * @returns Map of instrument UUIDs to their holdings arrays
52
+ *
53
+ * @example
54
+ * const holdings = [
55
+ * { instrument: { uuid: '123' }, quantity: 100 },
56
+ * { instrument: { uuid: '123' }, quantity: 50 },
57
+ * { instrument: { uuid: '456' }, quantity: 200 }
58
+ * ];
59
+ * groupHoldingsByInstrument(holdings);
60
+ * // returns { '123': [holding1, holding2], '456': [holding3] }
61
+ */
62
+ export const groupHoldingsByInstrument = (holdings) => {
63
+ return holdings.reduce((groups, holding) => {
64
+ const instrumentUuid = holding.instrument.uuid;
65
+ if (!groups[instrumentUuid]) {
66
+ groups[instrumentUuid] = [];
67
+ }
68
+ groups[instrumentUuid].push(holding);
69
+ return groups;
70
+ }, {});
71
+ };
72
+ /**
73
+ * Filters holdings with quantities above a threshold
74
+ *
75
+ * @param holdings - Array of asset holdings
76
+ * @param minQuantity - Minimum quantity threshold
77
+ * @returns Filtered array of holdings
78
+ *
79
+ * @example
80
+ * const holdings = [
81
+ * { quantity: 100 },
82
+ * { quantity: 50 },
83
+ * { quantity: 200 }
84
+ * ];
85
+ * filterHoldingsByMinQuantity(holdings, 75); // returns holdings with quantity >= 75
86
+ */
87
+ export const filterHoldingsByMinQuantity = (holdings, minQuantity) => {
88
+ return holdings.filter((holding) => holding.quantity >= minQuantity);
89
+ };
90
+ /**
91
+ * Sorts holdings by various criteria
92
+ *
93
+ * @param holdings - Array of asset holdings to sort
94
+ * @param sortBy - Field to sort by
95
+ * @param direction - Sort direction (ascending or descending)
96
+ * @returns Sorted array of holdings
97
+ *
98
+ * @example
99
+ * const holdings = [...];
100
+ * sortHoldings(holdings, 'quantity', 'desc'); // Sort by quantity descending
101
+ * sortHoldings(holdings, 'symbol', 'asc'); // Sort by symbol ascending
102
+ */
103
+ export const sortHoldings = (holdings, sortBy, direction = SORT_DIRECTION_DESC) => {
104
+ // Use shared utility for string field sorting
105
+ if (sortBy === 'symbol') {
106
+ const sorted = sortByStringField([...holdings], 'instrumentSymbol');
107
+ return direction === SORT_DIRECTION_ASC ? sorted : sorted.reverse();
108
+ }
109
+ if (sortBy === 'name') {
110
+ const sorted = sortByStringField([...holdings], 'instrumentName');
111
+ return direction === SORT_DIRECTION_ASC ? sorted : sorted.reverse();
112
+ }
113
+ // Custom logic for non-string fields
114
+ return [...holdings].sort((a, b) => {
115
+ let valueA;
116
+ let valueB;
117
+ switch (sortBy) {
118
+ case 'quantity':
119
+ valueA = a.quantity;
120
+ valueB = b.quantity;
121
+ break;
122
+ case 'createdAt':
123
+ valueA = a.createdAt;
124
+ valueB = b.createdAt;
125
+ break;
126
+ default:
127
+ return 0;
128
+ }
129
+ if (typeof valueA === 'string' && typeof valueB === 'string') {
130
+ const comparison = valueA.localeCompare(valueB);
131
+ return direction === SORT_DIRECTION_ASC ? comparison : -comparison;
132
+ }
133
+ if (typeof valueA === 'number' && typeof valueB === 'number') {
134
+ const comparison = valueA - valueB;
135
+ return direction === SORT_DIRECTION_ASC ? comparison : -comparison;
136
+ }
137
+ return 0;
138
+ });
139
+ };
package/dist/index.d.ts CHANGED
@@ -20,4 +20,6 @@ export { downloadBlob, downloadTextFile, downloadJsonFile, generateTimestampedFi
20
20
  export { capitalizeFirstLetter, formatStatus, formatRiskLevel, capitalizeFirst, formatLabel, camelToTitle, } from './formatting';
21
21
  export { formatQuantityWithSuffix, formatLargeNumber, formatAsPercentage, formatWithSeparators, roundToDecimals, clampNumber, } from './numbers';
22
22
  export { validateAllocations } from './allocations';
23
+ export { calculatePortfolioValue, calculateHoldingAllocations, groupHoldingsByInstrument, filterHoldingsByMinQuantity, sortHoldings, } from './holdings';
24
+ export { processAllocationData, calculateTotals, formatPercentage, formatDashboardCurrency, type AllocationDisplayItem, } from './dashboard';
23
25
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,YAAY,EAAE,MAAM,QAAQ,CAAC;AAGtC,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,cAAc,EAAE,MAAM,QAAQ,CAAC;AAGjF,OAAO,EACL,8BAA8B,EAC9B,qCAAqC,EACrC,cAAc,EACd,kBAAkB,EAClB,sBAAsB,EACtB,qBAAqB,EACrB,YAAY,GACb,MAAM,YAAY,CAAC;AAGpB,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAGnE,OAAO,EACL,mBAAmB,EACnB,wBAAwB,EACxB,yBAAyB,EACzB,yBAAyB,GAC1B,MAAM,gBAAgB,CAAC;AAGxB,OAAO,EAAE,oBAAoB,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAGhH,OAAO,EACL,sBAAsB,EACtB,sBAAsB,EACtB,oBAAoB,EACpB,4BAA4B,EAC5B,sBAAsB,GACvB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,aAAa,EACb,gBAAgB,EAChB,kBAAkB,EAClB,uBAAuB,EACvB,yBAAyB,EACzB,YAAY,EACZ,YAAY,EACZ,YAAY,EACZ,mBAAmB,EACnB,QAAQ,EACR,wBAAwB,EACxB,kBAAkB,EAClB,kBAAkB,EAClB,UAAU,EACV,WAAW,EACX,mBAAmB,EACnB,cAAc,EACd,cAAc,EACd,SAAS,EACT,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EACjB,uBAAuB,EACvB,mBAAmB,EACnB,UAAU,EAEV,qBAAqB,EACrB,qBAAqB,EACrB,eAAe,EACf,iBAAiB,GAClB,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,gBAAgB,EAChB,kBAAkB,EAClB,eAAe,EACf,aAAa,EACb,aAAa,EACb,kBAAkB,EAClB,YAAY,EACZ,eAAe,EACf,qBAAqB,EAErB,0BAA0B,EAC1B,4BAA4B,EAC5B,qBAAqB,EACrB,uBAAuB,EACvB,2BAA2B,EAC3B,6BAA6B,EAC7B,2BAA2B,EAC3B,6BAA6B,GAC9B,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,qBAAqB,EACrB,eAAe,EACf,gBAAgB,EAChB,sBAAsB,EACtB,wBAAwB,GACzB,MAAM,QAAQ,CAAC;AAGhB,OAAO,EACL,qBAAqB,EACrB,iBAAiB,EACjB,iBAAiB,EACjB,oBAAoB,EACpB,oBAAoB,EACpB,iBAAiB,EACjB,qBAAqB,EACrB,eAAe,EACf,YAAY,EACZ,aAAa,GACd,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,WAAW,EACX,iBAAiB,EACjB,mBAAmB,EACnB,kBAAkB,EAClB,YAAY,EACZ,qBAAqB,EACrB,iBAAiB,GAClB,MAAM,eAAe,CAAC;AAGvB,OAAO,EACL,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EAChB,2BAA2B,EAC3B,eAAe,EACf,eAAe,GAChB,MAAM,aAAa,CAAC;AAGrB,OAAO,EACL,qBAAqB,EACrB,YAAY,EACZ,eAAe,EACf,eAAe,EACf,WAAW,EACX,YAAY,GACb,MAAM,cAAc,CAAC;AAGtB,OAAO,EACL,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,EAClB,oBAAoB,EACpB,eAAe,EACf,WAAW,GACZ,MAAM,WAAW,CAAC;AAGnB,OAAO,EAAE,mBAAmB,EAAE,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
package/dist/index.js CHANGED
@@ -40,3 +40,7 @@ export { capitalizeFirstLetter, formatStatus, formatRiskLevel, capitalizeFirst,
40
40
  export { formatQuantityWithSuffix, formatLargeNumber, formatAsPercentage, formatWithSeparators, roundToDecimals, clampNumber, } from './numbers';
41
41
  // Allocation utilities
42
42
  export { validateAllocations } from './allocations';
43
+ // Holdings utilities
44
+ export { calculatePortfolioValue, calculateHoldingAllocations, groupHoldingsByInstrument, filterHoldingsByMinQuantity, sortHoldings, } from './holdings';
45
+ // Dashboard utilities
46
+ export { processAllocationData, calculateTotals, formatPercentage, formatDashboardCurrency, } from './dashboard';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@cranberry-money/shared-utils",
3
- "version": "8.1.0",
3
+ "version": "8.3.0",
4
4
  "description": "Shared utility functions for MyPortfolio platform",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",