@open-captable-protocol/canton 0.2.230 → 0.2.232

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 (100) hide show
  1. package/dist/functions/OpenCapTable/capTable/CapTableBatch.d.ts.map +1 -1
  2. package/dist/functions/OpenCapTable/capTable/CapTableBatch.js +2 -4
  3. package/dist/functions/OpenCapTable/capTable/CapTableBatch.js.map +1 -1
  4. package/dist/functions/OpenCapTable/capTable/getCapTableState.d.ts.map +1 -1
  5. package/dist/functions/OpenCapTable/capTable/getCapTableState.js +1 -4
  6. package/dist/functions/OpenCapTable/capTable/getCapTableState.js.map +1 -1
  7. package/dist/functions/OpenCapTable/capTable/ocfToDaml.d.ts +2 -7
  8. package/dist/functions/OpenCapTable/capTable/ocfToDaml.d.ts.map +1 -1
  9. package/dist/functions/OpenCapTable/capTable/ocfToDaml.js +3 -18
  10. package/dist/functions/OpenCapTable/capTable/ocfToDaml.js.map +1 -1
  11. package/dist/functions/OpenCapTable/convertibleIssuance/createConvertibleIssuance.d.ts +1 -1
  12. package/dist/functions/OpenCapTable/convertibleIssuance/createConvertibleIssuance.d.ts.map +1 -1
  13. package/dist/functions/OpenCapTable/convertibleIssuance/createConvertibleIssuance.js +2 -4
  14. package/dist/functions/OpenCapTable/convertibleIssuance/createConvertibleIssuance.js.map +1 -1
  15. package/dist/functions/OpenCapTable/equityCompensationIssuance/createEquityCompensationIssuance.js +1 -1
  16. package/dist/functions/OpenCapTable/equityCompensationIssuance/createEquityCompensationIssuance.js.map +1 -1
  17. package/dist/functions/OpenCapTable/issuer/createIssuer.d.ts.map +1 -1
  18. package/dist/functions/OpenCapTable/issuer/createIssuer.js +1 -13
  19. package/dist/functions/OpenCapTable/issuer/createIssuer.js.map +1 -1
  20. package/dist/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.d.ts.map +1 -1
  21. package/dist/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.js +1 -2
  22. package/dist/functions/OpenCapTable/issuerAuthorization/authorizeIssuer.js.map +1 -1
  23. package/dist/functions/OpenCapTable/issuerAuthorization/withdrawAuthorization.d.ts.map +1 -1
  24. package/dist/functions/OpenCapTable/issuerAuthorization/withdrawAuthorization.js +1 -2
  25. package/dist/functions/OpenCapTable/issuerAuthorization/withdrawAuthorization.js.map +1 -1
  26. package/dist/functions/OpenCapTable/stakeholder/getStakeholderAsOcf.d.ts.map +1 -1
  27. package/dist/functions/OpenCapTable/stakeholder/getStakeholderAsOcf.js.map +1 -1
  28. package/dist/functions/OpenCapTable/stakeholder/stakeholderDataToDaml.d.ts.map +1 -1
  29. package/dist/functions/OpenCapTable/stakeholder/stakeholderDataToDaml.js +1 -7
  30. package/dist/functions/OpenCapTable/stakeholder/stakeholderDataToDaml.js.map +1 -1
  31. package/dist/functions/OpenCapTable/stakeholderStatusChangeEvent/damlToOcf.d.ts +2 -1
  32. package/dist/functions/OpenCapTable/stakeholderStatusChangeEvent/damlToOcf.d.ts.map +1 -1
  33. package/dist/functions/OpenCapTable/stakeholderStatusChangeEvent/damlToOcf.js +1 -9
  34. package/dist/functions/OpenCapTable/stakeholderStatusChangeEvent/damlToOcf.js.map +1 -1
  35. package/dist/functions/OpenCapTable/stakeholderStatusChangeEvent/getStakeholderStatusChangeEventAsOcf.d.ts.map +1 -1
  36. package/dist/functions/OpenCapTable/stakeholderStatusChangeEvent/getStakeholderStatusChangeEventAsOcf.js +1 -8
  37. package/dist/functions/OpenCapTable/stakeholderStatusChangeEvent/getStakeholderStatusChangeEventAsOcf.js.map +1 -1
  38. package/dist/functions/OpenCapTable/stockClass/stockClassDataToDaml.d.ts.map +1 -1
  39. package/dist/functions/OpenCapTable/stockClass/stockClassDataToDaml.js +9 -31
  40. package/dist/functions/OpenCapTable/stockClass/stockClassDataToDaml.js.map +1 -1
  41. package/dist/functions/OpenCapTable/stockClassAuthorizedSharesAdjustment/getStockClassAuthorizedSharesAdjustmentAsOcf.d.ts.map +1 -1
  42. package/dist/functions/OpenCapTable/stockClassAuthorizedSharesAdjustment/getStockClassAuthorizedSharesAdjustmentAsOcf.js +0 -4
  43. package/dist/functions/OpenCapTable/stockClassAuthorizedSharesAdjustment/getStockClassAuthorizedSharesAdjustmentAsOcf.js.map +1 -1
  44. package/dist/functions/OpenCapTable/stockPlan/createStockPlan.d.ts.map +1 -1
  45. package/dist/functions/OpenCapTable/stockPlan/createStockPlan.js +2 -6
  46. package/dist/functions/OpenCapTable/stockPlan/createStockPlan.js.map +1 -1
  47. package/dist/functions/OpenCapTable/vestingTerms/createVestingTerms.js +3 -3
  48. package/dist/functions/OpenCapTable/vestingTerms/createVestingTerms.js.map +1 -1
  49. package/dist/functions/OpenCapTable/warrantExercise/getWarrantExerciseAsOcf.js.map +1 -1
  50. package/dist/functions/OpenCapTable/warrantIssuance/createWarrantIssuance.d.ts +5 -5
  51. package/dist/functions/OpenCapTable/warrantIssuance/createWarrantIssuance.d.ts.map +1 -1
  52. package/dist/functions/OpenCapTable/warrantIssuance/createWarrantIssuance.js +4 -2
  53. package/dist/functions/OpenCapTable/warrantIssuance/createWarrantIssuance.js.map +1 -1
  54. package/dist/functions/OpenCapTableReports/companyValuationReport/addObserversToCompanyValuationReport.d.ts.map +1 -1
  55. package/dist/functions/OpenCapTableReports/companyValuationReport/addObserversToCompanyValuationReport.js +1 -2
  56. package/dist/functions/OpenCapTableReports/companyValuationReport/addObserversToCompanyValuationReport.js.map +1 -1
  57. package/dist/functions/OpenCapTableReports/companyValuationReport/createCompanyValuationReport.d.ts.map +1 -1
  58. package/dist/functions/OpenCapTableReports/companyValuationReport/createCompanyValuationReport.js +1 -2
  59. package/dist/functions/OpenCapTableReports/companyValuationReport/createCompanyValuationReport.js.map +1 -1
  60. package/dist/functions/OpenCapTableReports/companyValuationReport/updateCompanyValuationReport.d.ts.map +1 -1
  61. package/dist/functions/OpenCapTableReports/companyValuationReport/updateCompanyValuationReport.js +1 -2
  62. package/dist/functions/OpenCapTableReports/companyValuationReport/updateCompanyValuationReport.js.map +1 -1
  63. package/dist/types/native.d.ts +76 -78
  64. package/dist/types/native.d.ts.map +1 -1
  65. package/dist/utils/entityValidators.d.ts.map +1 -1
  66. package/dist/utils/entityValidators.js +37 -26
  67. package/dist/utils/entityValidators.js.map +1 -1
  68. package/dist/utils/enumConversions.d.ts +6 -9
  69. package/dist/utils/enumConversions.d.ts.map +1 -1
  70. package/dist/utils/enumConversions.js +21 -18
  71. package/dist/utils/enumConversions.js.map +1 -1
  72. package/dist/utils/index.d.ts +0 -1
  73. package/dist/utils/index.d.ts.map +1 -1
  74. package/dist/utils/index.js +0 -1
  75. package/dist/utils/index.js.map +1 -1
  76. package/dist/utils/planSecurityAliases.d.ts +8 -4
  77. package/dist/utils/planSecurityAliases.d.ts.map +1 -1
  78. package/dist/utils/planSecurityAliases.js +51 -8
  79. package/dist/utils/planSecurityAliases.js.map +1 -1
  80. package/dist/utils/replicationHelpers.d.ts +0 -4
  81. package/dist/utils/replicationHelpers.d.ts.map +1 -1
  82. package/dist/utils/replicationHelpers.js +7 -9
  83. package/dist/utils/replicationHelpers.js.map +1 -1
  84. package/dist/utils/typeConversions.d.ts +32 -30
  85. package/dist/utils/typeConversions.d.ts.map +1 -1
  86. package/dist/utils/typeConversions.js +82 -90
  87. package/dist/utils/typeConversions.js.map +1 -1
  88. package/dist/utils/typeGuards.d.ts +4 -4
  89. package/dist/utils/typeGuards.d.ts.map +1 -1
  90. package/dist/utils/typeGuards.js +5 -10
  91. package/dist/utils/typeGuards.js.map +1 -1
  92. package/dist/utils/validation.d.ts +17 -17
  93. package/dist/utils/validation.d.ts.map +1 -1
  94. package/dist/utils/validation.js +48 -57
  95. package/dist/utils/validation.js.map +1 -1
  96. package/package.json +2 -2
  97. package/dist/utils/deprecatedFieldNormalization.d.ts +0 -881
  98. package/dist/utils/deprecatedFieldNormalization.d.ts.map +0 -1
  99. package/dist/utils/deprecatedFieldNormalization.js +0 -1462
  100. package/dist/utils/deprecatedFieldNormalization.js.map +0 -1
@@ -1,1462 +0,0 @@
1
- "use strict";
2
- /**
3
- * Utilities for normalizing deprecated OCF fields to their current equivalents.
4
- *
5
- * OCF schema evolves over time, and some fields are deprecated in favor of new ones.
6
- * These utilities provide type-safe normalization and verification helpers.
7
- *
8
- * @example
9
- * ```typescript
10
- * import { normalizeSingularToArray, normalizeDeprecatedStockPlanFields } from './deprecatedFieldNormalization';
11
- *
12
- * // Generic singular → array normalization
13
- * const stockClassIds = normalizeSingularToArray({
14
- * singularValue: data.stock_class_id,
15
- * arrayValue: data.stock_class_ids,
16
- * });
17
- *
18
- * // Stock plan specific helper
19
- * const normalized = normalizeDeprecatedStockPlanFields(inputData);
20
- * ```
21
- */
22
- Object.defineProperty(exports, "__esModule", { value: true });
23
- exports.REQUIRED_ARRAY_FIELDS = exports.DEFAULT_INTERNAL_FIELDS = exports.DEFAULT_DEPRECATED_FIELDS = exports.OCF_DEPRECATED_FIELDS = exports.OPTION_GRANT_TYPE_TO_COMPENSATION_TYPE = exports.deprecationWarningConfig = void 0;
24
- exports.emitDeprecationWarning = emitDeprecationWarning;
25
- exports.normalizeSingularToArray = normalizeSingularToArray;
26
- exports.normalizeDeprecatedStockPlanFields = normalizeDeprecatedStockPlanFields;
27
- exports.normalizeDeprecatedStakeholderFields = normalizeDeprecatedStakeholderFields;
28
- exports.checkStakeholderDeprecatedFieldUsage = checkStakeholderDeprecatedFieldUsage;
29
- exports.migrateStakeholderFields = migrateStakeholderFields;
30
- exports.migrateStakeholderFieldsBatch = migrateStakeholderFieldsBatch;
31
- exports.convertOptionGrantTypeToCompensationType = convertOptionGrantTypeToCompensationType;
32
- exports.normalizeDeprecatedEquityCompensationIssuanceFields = normalizeDeprecatedEquityCompensationIssuanceFields;
33
- exports.checkEquityCompensationIssuanceDeprecatedFieldUsage = checkEquityCompensationIssuanceDeprecatedFieldUsage;
34
- exports.migrateEquityCompensationIssuanceFields = migrateEquityCompensationIssuanceFields;
35
- exports.migrateEquityCompensationIssuanceFieldsBatch = migrateEquityCompensationIssuanceFieldsBatch;
36
- exports.checkStockPlanDeprecatedFieldUsage = checkStockPlanDeprecatedFieldUsage;
37
- exports.getDeprecatedFieldMappings = getDeprecatedFieldMappings;
38
- exports.getFieldDeprecation = getFieldDeprecation;
39
- exports.checkDeprecatedFields = checkDeprecatedFields;
40
- exports.checkDeprecatedFieldsBatch = checkDeprecatedFieldsBatch;
41
- exports.checkDeprecatedFieldsForType = checkDeprecatedFieldsForType;
42
- exports.migrateStockPlanFields = migrateStockPlanFields;
43
- exports.migrateStockPlanFieldsBatch = migrateStockPlanFieldsBatch;
44
- exports.generateDeprecationReport = generateDeprecationReport;
45
- exports.validateDeprecatedFields = validateDeprecatedFields;
46
- exports.createDeprecatedFieldsValidator = createDeprecatedFieldsValidator;
47
- exports.assertNoDeprecatedFields = assertNoDeprecatedFields;
48
- exports.registerDeprecatedFieldMapping = registerDeprecatedFieldMapping;
49
- exports.getRegisteredObjectTypes = getRegisteredObjectTypes;
50
- exports.getAllDeprecatedFieldMappings = getAllDeprecatedFieldMappings;
51
- exports.normalizeDeprecatedOcfFields = normalizeDeprecatedOcfFields;
52
- exports.hasDeprecationsForEntityType = hasDeprecationsForEntityType;
53
- exports.registerEntityTypeMapping = registerEntityTypeMapping;
54
- exports.normalizeOcfObject = normalizeOcfObject;
55
- exports.areOcfObjectsEquivalent = areOcfObjectsEquivalent;
56
- exports.compareOcfObjects = compareOcfObjects;
57
- exports.normalizeRequiredArrayFields = normalizeRequiredArrayFields;
58
- exports.registerRequiredArrayFields = registerRequiredArrayFields;
59
- exports.getRequiredArrayFields = getRequiredArrayFields;
60
- const ocfComparison_1 = require("./ocfComparison");
61
- Object.defineProperty(exports, "DEFAULT_DEPRECATED_FIELDS", { enumerable: true, get: function () { return ocfComparison_1.DEFAULT_DEPRECATED_FIELDS; } });
62
- Object.defineProperty(exports, "DEFAULT_INTERNAL_FIELDS", { enumerable: true, get: function () { return ocfComparison_1.DEFAULT_INTERNAL_FIELDS; } });
63
- const planSecurityAliases_1 = require("./planSecurityAliases");
64
- /**
65
- * Global deprecation warning configuration.
66
- * Can be modified for testing or to customize warning behavior.
67
- */
68
- exports.deprecationWarningConfig = {
69
- enabled: process.env.NODE_ENV !== 'test',
70
- handler: undefined,
71
- };
72
- /**
73
- * Emit a deprecation warning.
74
- *
75
- * @param details - Details about the deprecated field usage
76
- */
77
- function emitDeprecationWarning(details) {
78
- if (!exports.deprecationWarningConfig.enabled) {
79
- return;
80
- }
81
- const message = `[OCF Deprecation] Field '${details.deprecatedField}' is deprecated and was auto-converted to '${details.replacementField}'.` +
82
- `${details.context ? ` Context: ${details.context}` : ''}`;
83
- if (exports.deprecationWarningConfig.handler) {
84
- exports.deprecationWarningConfig.handler(message, details);
85
- }
86
- else {
87
- // eslint-disable-next-line no-console -- Intentional deprecation warning to help developers migrate to current API
88
- console.warn(message);
89
- }
90
- }
91
- /**
92
- * Normalize a deprecated singular field to an array field.
93
- *
94
- * When both singular and array values are provided, the array takes precedence.
95
- * If the array is empty/undefined but singular has a value, wraps it in an array.
96
- *
97
- * @param params - Parameters for the normalization
98
- * @returns The normalized array value (empty array if both inputs are empty/undefined)
99
- *
100
- * @example
101
- * ```typescript
102
- * // Only deprecated field provided
103
- * normalizeSingularToArray({
104
- * singularValue: 'class-1',
105
- * arrayValue: undefined,
106
- * }); // Returns ['class-1']
107
- *
108
- * // Both provided - array takes precedence
109
- * normalizeSingularToArray({
110
- * singularValue: 'class-1',
111
- * arrayValue: ['class-2', 'class-3'],
112
- * }); // Returns ['class-2', 'class-3']
113
- *
114
- * // Neither provided
115
- * normalizeSingularToArray({
116
- * singularValue: undefined,
117
- * arrayValue: undefined,
118
- * }); // Returns []
119
- * ```
120
- */
121
- function normalizeSingularToArray(params) {
122
- const { singularValue, arrayValue, deprecatedFieldName, replacementFieldName, context } = params;
123
- // If array has values, use it (ignoring deprecated singular)
124
- if (Array.isArray(arrayValue) && arrayValue.length > 0) {
125
- return arrayValue;
126
- }
127
- // If singular value exists, convert to array and emit warning
128
- // Also exclude empty strings to match original truthy-check behavior
129
- if (singularValue !== undefined && singularValue !== null && singularValue !== '') {
130
- if (deprecatedFieldName && replacementFieldName) {
131
- emitDeprecationWarning({
132
- deprecatedField: deprecatedFieldName,
133
- replacementField: replacementFieldName,
134
- deprecatedValue: singularValue,
135
- context,
136
- });
137
- }
138
- return [singularValue];
139
- }
140
- // Neither provided - return empty array
141
- return [];
142
- }
143
- /**
144
- * Normalize deprecated stock plan fields.
145
- *
146
- * Handles the OCF deprecation of `stock_class_id` (singular) → `stock_class_ids` (array).
147
- *
148
- * @param data - Stock plan data that may contain deprecated fields
149
- * @param context - Optional context for deprecation warnings (e.g., "stockPlan.create")
150
- * @returns Object containing normalized stock_class_ids and deprecation usage flag
151
- *
152
- * @example
153
- * ```typescript
154
- * // Old format (deprecated)
155
- * const result = normalizeDeprecatedStockPlanFields({
156
- * stock_class_id: 'sc-1',
157
- * });
158
- * // Returns { stock_class_ids: ['sc-1'], usedDeprecatedField: true }
159
- *
160
- * // New format
161
- * const result = normalizeDeprecatedStockPlanFields({
162
- * stock_class_ids: ['sc-1', 'sc-2'],
163
- * });
164
- * // Returns { stock_class_ids: ['sc-1', 'sc-2'], usedDeprecatedField: false }
165
- * ```
166
- */
167
- function normalizeDeprecatedStockPlanFields(data, context) {
168
- // Also exclude empty strings to match original truthy-check behavior
169
- const hasDeprecatedField = data.stock_class_id !== undefined && data.stock_class_id !== null && data.stock_class_id !== '';
170
- const hasCurrentField = Array.isArray(data.stock_class_ids) && data.stock_class_ids.length > 0;
171
- // Only count as using deprecated field if deprecated is present and current is not
172
- const usedDeprecatedField = hasDeprecatedField && !hasCurrentField;
173
- // Normalize null to undefined for the generic function, then filter results
174
- const singularValue = data.stock_class_id ?? undefined;
175
- const arrayValue = data.stock_class_ids ?? undefined;
176
- const stock_class_ids = normalizeSingularToArray({
177
- singularValue,
178
- arrayValue,
179
- deprecatedFieldName: 'stock_class_id',
180
- replacementFieldName: 'stock_class_ids',
181
- context: context ?? 'StockPlan',
182
- });
183
- return {
184
- stock_class_ids,
185
- usedDeprecatedField,
186
- };
187
- }
188
- /**
189
- * Normalize deprecated stakeholder relationship fields to their canonical form.
190
- *
191
- * This helper accepts stakeholder data that may use the legacy singular
192
- * `current_relationship` field or the newer array-based `current_relationships`
193
- * field and returns a normalized representation plus metadata about deprecation use.
194
- *
195
- * Behavior:
196
- * - If only `current_relationship` is provided, it is converted to a single-element
197
- * `current_relationships` array and `usedDeprecatedField` is set to `true`.
198
- * - If `current_relationships` is provided and non-empty, it is used as-is and
199
- * `usedDeprecatedField` is set to `false`, even if `current_relationship` is
200
- * also present.
201
- * - If neither field is provided, `current_relationships` will be an empty array
202
- * and `usedDeprecatedField` will be `false`.
203
- *
204
- * The input object is not mutated.
205
- *
206
- * @param data - Stakeholder data that may contain either the deprecated
207
- * `current_relationship` field, the newer `current_relationships` field, or both.
208
- * @param context - Optional human-readable context used when emitting deprecation
209
- * warnings. Defaults to `"Stakeholder"` when not provided.
210
- * @returns Normalized stakeholder relationship fields, including
211
- * `current_relationships` (always an array) and a `usedDeprecatedField` flag
212
- * indicating whether only the deprecated field was relied upon.
213
- *
214
- * @example
215
- * ```typescript
216
- * const normalized = normalizeDeprecatedStakeholderFields({
217
- * current_relationship: 'EMPLOYEE',
218
- * });
219
- * normalized.current_relationships; // ['EMPLOYEE']
220
- * normalized.usedDeprecatedField; // true
221
- * ```
222
- *
223
- * @example
224
- * ```typescript
225
- * const normalized = normalizeDeprecatedStakeholderFields({
226
- * current_relationship: 'ADVISOR',
227
- * current_relationships: ['FOUNDER', 'DIRECTOR'],
228
- * });
229
- * // The array field takes precedence when both are present.
230
- * normalized.current_relationships; // ['FOUNDER', 'DIRECTOR']
231
- * normalized.usedDeprecatedField; // false
232
- * ```
233
- */
234
- function normalizeDeprecatedStakeholderFields(data, context) {
235
- const hasDeprecatedField = data.current_relationship !== undefined && data.current_relationship !== null && data.current_relationship !== '';
236
- const hasCurrentField = Array.isArray(data.current_relationships) && data.current_relationships.length > 0;
237
- const usedDeprecatedField = hasDeprecatedField && !hasCurrentField;
238
- const singularValue = data.current_relationship ?? undefined;
239
- const arrayValue = data.current_relationships ?? undefined;
240
- const current_relationships = normalizeSingularToArray({
241
- singularValue,
242
- arrayValue,
243
- deprecatedFieldName: 'current_relationship',
244
- replacementFieldName: 'current_relationships',
245
- context: context ?? 'Stakeholder',
246
- });
247
- return { current_relationships, usedDeprecatedField };
248
- }
249
- /**
250
- * Check stakeholder data for deprecated field usage without modifying the data.
251
- */
252
- function checkStakeholderDeprecatedFieldUsage(data) {
253
- const deprecatedFieldsUsed = [];
254
- if (data.current_relationship !== undefined &&
255
- data.current_relationship !== null &&
256
- data.current_relationship !== '') {
257
- deprecatedFieldsUsed.push('current_relationship');
258
- }
259
- return { hasDeprecatedFields: deprecatedFieldsUsed.length > 0, deprecatedFieldsUsed };
260
- }
261
- /**
262
- * Migrate deprecated stakeholder fields to their current equivalents.
263
- */
264
- function migrateStakeholderFields(data) {
265
- const warnings = [];
266
- const migratedFields = [];
267
- const hasDeprecatedField = data.current_relationship !== undefined && data.current_relationship !== null && data.current_relationship !== '';
268
- const hasCurrentField = Array.isArray(data.current_relationships) && data.current_relationships.length > 0;
269
- if (hasDeprecatedField && hasCurrentField) {
270
- warnings.push(`Both 'current_relationship' (deprecated) and 'current_relationships' are present. Using 'current_relationships' value.`);
271
- }
272
- const { current_relationships, usedDeprecatedField } = normalizeDeprecatedStakeholderFields(data);
273
- if (usedDeprecatedField)
274
- migratedFields.push('current_relationship');
275
- const { current_relationship: _removed, ...rest } = data;
276
- return {
277
- data: { ...rest, current_relationships },
278
- migrated: migratedFields.length > 0,
279
- migratedFields,
280
- warnings,
281
- };
282
- }
283
- /**
284
- * Migrate deprecated fields in multiple stakeholder objects.
285
- */
286
- function migrateStakeholderFieldsBatch(items) {
287
- const migratedFieldsSummary = {};
288
- let itemsMigrated = 0;
289
- let itemsWithWarnings = 0;
290
- const migratedItems = items.map((item) => {
291
- const result = migrateStakeholderFields(item);
292
- if (result.migrated) {
293
- itemsMigrated++;
294
- for (const field of result.migratedFields) {
295
- migratedFieldsSummary[field] = (migratedFieldsSummary[field] ?? 0) + 1;
296
- }
297
- }
298
- if (result.warnings.length > 0)
299
- itemsWithWarnings++;
300
- return result;
301
- });
302
- return {
303
- items: migratedItems,
304
- totalProcessed: items.length,
305
- itemsMigrated,
306
- itemsWithWarnings,
307
- migratedFieldsSummary,
308
- };
309
- }
310
- /**
311
- * Convert deprecated option_grant_type value to current compensation_type value.
312
- */
313
- function convertOptionGrantTypeToCompensationType(optionGrantType) {
314
- return exports.OPTION_GRANT_TYPE_TO_COMPENSATION_TYPE[optionGrantType] ?? optionGrantType;
315
- }
316
- /**
317
- * Normalize deprecated equity compensation issuance fields to their canonical form.
318
- *
319
- * This helper converts the legacy `option_grant_type` field to the current
320
- * `compensation_type` field, applying value mappings as needed:
321
- * - `NSO` → `OPTION_NSO`
322
- * - `ISO` → `OPTION_ISO`
323
- * - `INTL` → `OPTION`
324
- * - Unknown values are passed through unchanged
325
- *
326
- * Behavior:
327
- * - If only `option_grant_type` is provided, it is converted to `compensation_type`
328
- * with the appropriate value mapping and `usedDeprecatedField` is set to `true`.
329
- * - If `compensation_type` is provided and non-empty, it is used as-is and
330
- * `usedDeprecatedField` is set to `false`, even if `option_grant_type` is
331
- * also present.
332
- * - If neither field is provided, `compensation_type` will be `null`.
333
- *
334
- * The input object is not mutated.
335
- *
336
- * @param data - Equity compensation issuance data that may contain either the deprecated
337
- * `option_grant_type` field, the newer `compensation_type` field, or both.
338
- * @param context - Optional human-readable context used when emitting deprecation
339
- * warnings. Defaults to `"EquityCompensationIssuance"` when not provided.
340
- * @returns Normalized fields including `compensation_type`, a `usedDeprecatedField` flag,
341
- * and optionally the `originalDeprecatedValue` if conversion occurred.
342
- *
343
- * @example
344
- * ```typescript
345
- * const normalized = normalizeDeprecatedEquityCompensationIssuanceFields({
346
- * option_grant_type: 'NSO',
347
- * });
348
- * normalized.compensation_type; // 'OPTION_NSO'
349
- * normalized.usedDeprecatedField; // true
350
- * normalized.originalDeprecatedValue; // 'NSO'
351
- * ```
352
- *
353
- * @example
354
- * ```typescript
355
- * const normalized = normalizeDeprecatedEquityCompensationIssuanceFields({
356
- * option_grant_type: 'ISO',
357
- * compensation_type: 'RSU',
358
- * });
359
- * // The current field takes precedence when both are present.
360
- * normalized.compensation_type; // 'RSU'
361
- * normalized.usedDeprecatedField; // false
362
- * ```
363
- */
364
- function normalizeDeprecatedEquityCompensationIssuanceFields(data, context) {
365
- const hasDeprecatedField = data.option_grant_type !== undefined && data.option_grant_type !== null && data.option_grant_type !== '';
366
- const hasCurrentField = data.compensation_type !== undefined && data.compensation_type !== null && data.compensation_type !== '';
367
- const usedDeprecatedField = hasDeprecatedField && !hasCurrentField;
368
- let compensation_type = null;
369
- let originalDeprecatedValue;
370
- if (hasCurrentField) {
371
- compensation_type = data.compensation_type ?? null;
372
- }
373
- else if (hasDeprecatedField && data.option_grant_type) {
374
- // Re-check in condition to narrow type for TypeScript
375
- originalDeprecatedValue = data.option_grant_type;
376
- compensation_type = convertOptionGrantTypeToCompensationType(data.option_grant_type);
377
- emitDeprecationWarning({
378
- deprecatedField: 'option_grant_type',
379
- replacementField: 'compensation_type',
380
- deprecatedValue: data.option_grant_type,
381
- context: context ?? 'EquityCompensationIssuance',
382
- });
383
- }
384
- return { compensation_type, usedDeprecatedField, originalDeprecatedValue };
385
- }
386
- /**
387
- * Check equity compensation issuance data for deprecated field usage.
388
- */
389
- function checkEquityCompensationIssuanceDeprecatedFieldUsage(data) {
390
- const deprecatedFieldsUsed = [];
391
- if (data.option_grant_type !== undefined && data.option_grant_type !== null && data.option_grant_type !== '') {
392
- deprecatedFieldsUsed.push('option_grant_type');
393
- }
394
- return { hasDeprecatedFields: deprecatedFieldsUsed.length > 0, deprecatedFieldsUsed };
395
- }
396
- /**
397
- * Migrate deprecated equity compensation issuance fields.
398
- */
399
- function migrateEquityCompensationIssuanceFields(data) {
400
- const warnings = [];
401
- const migratedFields = [];
402
- const hasDeprecatedField = data.option_grant_type !== undefined && data.option_grant_type !== null && data.option_grant_type !== '';
403
- const hasCurrentField = data.compensation_type !== undefined && data.compensation_type !== null && data.compensation_type !== '';
404
- if (hasDeprecatedField && hasCurrentField) {
405
- warnings.push(`Both 'option_grant_type' (deprecated) and 'compensation_type' are present. Using 'compensation_type' value.`);
406
- }
407
- const { compensation_type, usedDeprecatedField } = normalizeDeprecatedEquityCompensationIssuanceFields(data);
408
- if (usedDeprecatedField)
409
- migratedFields.push('option_grant_type');
410
- const { option_grant_type: _removed, ...rest } = data;
411
- return {
412
- data: { ...rest, compensation_type },
413
- migrated: migratedFields.length > 0,
414
- migratedFields,
415
- warnings,
416
- };
417
- }
418
- /**
419
- * Migrate deprecated fields in multiple equity compensation issuance objects.
420
- */
421
- function migrateEquityCompensationIssuanceFieldsBatch(items) {
422
- const migratedFieldsSummary = {};
423
- let itemsMigrated = 0;
424
- let itemsWithWarnings = 0;
425
- const migratedItems = items.map((item) => {
426
- const result = migrateEquityCompensationIssuanceFields(item);
427
- if (result.migrated) {
428
- itemsMigrated++;
429
- for (const field of result.migratedFields) {
430
- migratedFieldsSummary[field] = (migratedFieldsSummary[field] ?? 0) + 1;
431
- }
432
- }
433
- if (result.warnings.length > 0)
434
- itemsWithWarnings++;
435
- return result;
436
- });
437
- return {
438
- items: migratedItems,
439
- totalProcessed: items.length,
440
- itemsMigrated,
441
- itemsWithWarnings,
442
- migratedFieldsSummary,
443
- };
444
- }
445
- /**
446
- * Check stock plan data for deprecated field usage without modifying the data.
447
- *
448
- * @param data - Stock plan data to check
449
- * @returns Result indicating whether deprecated fields were used
450
- *
451
- * @example
452
- * ```typescript
453
- * const result = checkStockPlanDeprecatedFieldUsage({
454
- * stock_class_id: 'sc-1', // deprecated
455
- * });
456
- * // Returns { hasDeprecatedFields: true, deprecatedFieldsUsed: ['stock_class_id'] }
457
- * ```
458
- */
459
- function checkStockPlanDeprecatedFieldUsage(data) {
460
- const deprecatedFieldsUsed = [];
461
- // Check for deprecated stock_class_id field (exclude empty strings to match original truthy-check behavior)
462
- if (data.stock_class_id !== undefined && data.stock_class_id !== null && data.stock_class_id !== '') {
463
- deprecatedFieldsUsed.push('stock_class_id');
464
- }
465
- return {
466
- hasDeprecatedFields: deprecatedFieldsUsed.length > 0,
467
- deprecatedFieldsUsed,
468
- };
469
- }
470
- /**
471
- * Value mapping for option_grant_type -> compensation_type conversion.
472
- */
473
- exports.OPTION_GRANT_TYPE_TO_COMPENSATION_TYPE = {
474
- NSO: 'OPTION_NSO',
475
- ISO: 'OPTION_ISO',
476
- INTL: 'OPTION',
477
- };
478
- /**
479
- * Known OCF deprecated field mappings.
480
- * Add new deprecations here as they are discovered.
481
- */
482
- exports.OCF_DEPRECATED_FIELDS = {
483
- StockPlan: [
484
- {
485
- deprecatedField: 'stock_class_id',
486
- replacementField: 'stock_class_ids',
487
- deprecationType: 'singular_to_array',
488
- },
489
- ],
490
- Stakeholder: [
491
- {
492
- deprecatedField: 'current_relationship',
493
- replacementField: 'current_relationships',
494
- deprecationType: 'singular_to_array',
495
- },
496
- ],
497
- EquityCompensationIssuance: [
498
- {
499
- deprecatedField: 'option_grant_type',
500
- replacementField: 'compensation_type',
501
- deprecationType: 'value_mapped',
502
- valueMap: exports.OPTION_GRANT_TYPE_TO_COMPENSATION_TYPE,
503
- },
504
- ],
505
- };
506
- /**
507
- * Get the list of deprecated field mappings for an OCF object type.
508
- *
509
- * @param objectType - The OCF object type name (e.g., 'StockPlan')
510
- * @returns Array of deprecated field mappings for the object type
511
- */
512
- function getDeprecatedFieldMappings(objectType) {
513
- return exports.OCF_DEPRECATED_FIELDS[objectType] ?? [];
514
- }
515
- /**
516
- * Check if a specific field is deprecated for an OCF object type.
517
- *
518
- * @param objectType - The OCF object type name
519
- * @param fieldName - The field name to check
520
- * @returns The deprecation mapping if the field is deprecated, undefined otherwise
521
- */
522
- function getFieldDeprecation(objectType, fieldName) {
523
- const mappings = getDeprecatedFieldMappings(objectType);
524
- return mappings.find((m) => m.deprecatedField === fieldName);
525
- }
526
- /**
527
- * Check an object for any deprecated field usage based on known deprecations.
528
- *
529
- * @param objectType - The OCF object type name
530
- * @param data - The object data to check
531
- * @returns Result indicating which deprecated fields were used
532
- *
533
- * @example
534
- * ```typescript
535
- * const result = checkDeprecatedFields('StockPlan', {
536
- * stock_class_id: 'sc-1', // deprecated
537
- * plan_name: 'Equity Plan',
538
- * });
539
- * // Returns { hasDeprecatedFields: true, deprecatedFieldsUsed: ['stock_class_id'] }
540
- * ```
541
- */
542
- function checkDeprecatedFields(objectType, data) {
543
- const mappings = getDeprecatedFieldMappings(objectType);
544
- const deprecatedFieldsUsed = [];
545
- for (const mapping of mappings) {
546
- const value = data[mapping.deprecatedField];
547
- // Also exclude empty strings to match original truthy-check behavior
548
- if (value !== undefined && value !== null && value !== '') {
549
- deprecatedFieldsUsed.push(mapping.deprecatedField);
550
- }
551
- }
552
- return {
553
- hasDeprecatedFields: deprecatedFieldsUsed.length > 0,
554
- deprecatedFieldsUsed,
555
- };
556
- }
557
- /**
558
- * Check multiple objects for deprecated field usage in a single batch operation.
559
- *
560
- * @param items - Array of items to check, each with objectType and data
561
- * @returns Aggregated result with summary statistics and per-item details
562
- *
563
- * @example
564
- * ```typescript
565
- * const result = checkDeprecatedFieldsBatch([
566
- * { objectType: 'StockPlan', data: { stock_class_id: 'sc-1', plan_name: 'Plan A' }, id: 'plan-1' },
567
- * { objectType: 'StockPlan', data: { stock_class_ids: ['sc-2'], plan_name: 'Plan B' }, id: 'plan-2' },
568
- * ]);
569
- * // result.objectsWithDeprecatedFields === 1
570
- * // result.deprecatedFieldSummary === { stock_class_id: 1 }
571
- * ```
572
- */
573
- function checkDeprecatedFieldsBatch(items) {
574
- var _a;
575
- const itemsWithDeprecatedFields = [];
576
- const deprecatedFieldSummary = {};
577
- const objectTypeSummary = {};
578
- for (let i = 0; i < items.length; i++) {
579
- const item = items[i];
580
- const itemId = item.id ?? `index:${i}`;
581
- const result = checkDeprecatedFields(item.objectType, item.data);
582
- // Update object type summary
583
- objectTypeSummary[_a = item.objectType] ?? (objectTypeSummary[_a] = { total: 0, withDeprecated: 0 });
584
- objectTypeSummary[item.objectType].total++;
585
- if (result.hasDeprecatedFields) {
586
- objectTypeSummary[item.objectType].withDeprecated++;
587
- itemsWithDeprecatedFields.push({
588
- itemId,
589
- objectType: item.objectType,
590
- ...result,
591
- });
592
- // Update field summary
593
- for (const field of result.deprecatedFieldsUsed) {
594
- deprecatedFieldSummary[field] = (deprecatedFieldSummary[field] ?? 0) + 1;
595
- }
596
- }
597
- }
598
- return {
599
- totalChecked: items.length,
600
- objectsWithDeprecatedFields: itemsWithDeprecatedFields.length,
601
- objectsWithoutDeprecatedFields: items.length - itemsWithDeprecatedFields.length,
602
- hasDeprecatedFields: itemsWithDeprecatedFields.length > 0,
603
- itemsWithDeprecatedFields,
604
- deprecatedFieldSummary,
605
- objectTypeSummary,
606
- };
607
- }
608
- /**
609
- * Check an array of objects of the same type for deprecated field usage.
610
- *
611
- * @param objectType - The OCF object type for all items
612
- * @param items - Array of data objects to check
613
- * @returns Aggregated result with summary statistics
614
- *
615
- * @example
616
- * ```typescript
617
- * const stockPlans = [
618
- * { id: 'plan-1', stock_class_id: 'sc-1', plan_name: 'Plan A' },
619
- * { id: 'plan-2', stock_class_ids: ['sc-2'], plan_name: 'Plan B' },
620
- * ];
621
- * const result = checkDeprecatedFieldsForType('StockPlan', stockPlans);
622
- * ```
623
- */
624
- function checkDeprecatedFieldsForType(objectType, items) {
625
- const batchItems = items.map((data, index) => ({
626
- objectType,
627
- data,
628
- id: typeof data.id === 'string' ? data.id : `index:${index}`,
629
- }));
630
- return checkDeprecatedFieldsBatch(batchItems);
631
- }
632
- /**
633
- * Migrate deprecated stock plan fields to their current equivalents.
634
- *
635
- * This function creates a new object with deprecated fields converted to current format.
636
- * The original object is not modified.
637
- *
638
- * @param data - Stock plan data that may contain deprecated fields
639
- * @returns Migration result with normalized data and migration details
640
- *
641
- * @example
642
- * ```typescript
643
- * const result = migrateStockPlanFields({
644
- * id: 'plan-1',
645
- * stock_class_id: 'sc-1', // deprecated
646
- * plan_name: 'Equity Plan',
647
- * });
648
- * // result.data.stock_class_ids === ['sc-1']
649
- * // result.migrated === true
650
- * // result.migratedFields === ['stock_class_id']
651
- * ```
652
- */
653
- function migrateStockPlanFields(data) {
654
- const warnings = [];
655
- const migratedFields = [];
656
- const hasDeprecatedField = data.stock_class_id !== undefined && data.stock_class_id !== null && data.stock_class_id !== '';
657
- const hasCurrentField = Array.isArray(data.stock_class_ids) && data.stock_class_ids.length > 0;
658
- // Check for both fields present
659
- if (hasDeprecatedField && hasCurrentField) {
660
- warnings.push(`Both 'stock_class_id' (deprecated) and 'stock_class_ids' are present. Using 'stock_class_ids' value.`);
661
- }
662
- // Normalize using existing helper
663
- const { stock_class_ids, usedDeprecatedField } = normalizeDeprecatedStockPlanFields(data);
664
- if (usedDeprecatedField) {
665
- migratedFields.push('stock_class_id');
666
- }
667
- // Create new object without the deprecated field
668
- const { stock_class_id: _removed, ...rest } = data;
669
- return {
670
- data: {
671
- ...rest,
672
- stock_class_ids,
673
- },
674
- migrated: migratedFields.length > 0,
675
- migratedFields,
676
- warnings,
677
- };
678
- }
679
- /**
680
- * Migrate deprecated fields in multiple stock plan objects.
681
- *
682
- * @param items - Array of stock plan data objects
683
- * @returns Batch migration result with all migrated items
684
- *
685
- * @example
686
- * ```typescript
687
- * const plans = [
688
- * { id: 'plan-1', stock_class_id: 'sc-1' },
689
- * { id: 'plan-2', stock_class_ids: ['sc-2'] },
690
- * ];
691
- * const result = migrateStockPlanFieldsBatch(plans);
692
- * // result.itemsMigrated === 1
693
- * ```
694
- */
695
- function migrateStockPlanFieldsBatch(items) {
696
- const migratedFieldsSummary = {};
697
- let itemsMigrated = 0;
698
- let itemsWithWarnings = 0;
699
- const migratedItems = items.map((item) => {
700
- const result = migrateStockPlanFields(item);
701
- if (result.migrated) {
702
- itemsMigrated++;
703
- for (const field of result.migratedFields) {
704
- migratedFieldsSummary[field] = (migratedFieldsSummary[field] ?? 0) + 1;
705
- }
706
- }
707
- if (result.warnings.length > 0) {
708
- itemsWithWarnings++;
709
- }
710
- return result;
711
- });
712
- return {
713
- items: migratedItems,
714
- totalProcessed: items.length,
715
- itemsMigrated,
716
- itemsWithWarnings,
717
- migratedFieldsSummary,
718
- };
719
- }
720
- /**
721
- * Generate a detailed deprecation report from batch verification results.
722
- *
723
- * @param batchResult - Result from checkDeprecatedFieldsBatch or checkDeprecatedFieldsForType
724
- * @param options - Options for report generation
725
- * @returns Detailed deprecation report
726
- *
727
- * @example
728
- * ```typescript
729
- * const items = [
730
- * { objectType: 'StockPlan', data: { stock_class_id: 'sc-1' }, id: 'plan-1' },
731
- * ];
732
- * const batchResult = checkDeprecatedFieldsBatch(items);
733
- * const report = generateDeprecationReport(batchResult);
734
- * console.log(`${report.summary.deprecationPercentage}% of objects use deprecated fields`);
735
- * ```
736
- */
737
- function generateDeprecationReport(batchResult, options = {}) {
738
- const { includeAffectedItems = false, maxAffectedItems = 100 } = options;
739
- // Calculate summary
740
- const deprecationPercentage = batchResult.totalChecked > 0
741
- ? Math.round((batchResult.objectsWithDeprecatedFields / batchResult.totalChecked) * 10000) / 100
742
- : 0;
743
- const totalDeprecatedFieldUsages = Object.values(batchResult.deprecatedFieldSummary).reduce((sum, count) => sum + count, 0);
744
- // Build by-object-type breakdown
745
- const byObjectType = {};
746
- for (const [objectType, stats] of Object.entries(batchResult.objectTypeSummary)) {
747
- const fieldsUsed = {};
748
- // Count field usages for this object type
749
- for (const item of batchResult.itemsWithDeprecatedFields) {
750
- if (item.objectType === objectType) {
751
- for (const field of item.deprecatedFieldsUsed) {
752
- fieldsUsed[field] = (fieldsUsed[field] ?? 0) + 1;
753
- }
754
- }
755
- }
756
- byObjectType[objectType] = {
757
- total: stats.total,
758
- withDeprecatedFields: stats.withDeprecated,
759
- deprecationPercentage: stats.total > 0 ? Math.round((stats.withDeprecated / stats.total) * 10000) / 100 : 0,
760
- fieldsUsed,
761
- };
762
- }
763
- // Build by-field breakdown
764
- const byField = {};
765
- for (const [field, count] of Object.entries(batchResult.deprecatedFieldSummary)) {
766
- const objectTypesAffected = new Set();
767
- for (const item of batchResult.itemsWithDeprecatedFields) {
768
- if (item.deprecatedFieldsUsed.includes(field)) {
769
- objectTypesAffected.add(item.objectType);
770
- }
771
- }
772
- // Find the mapping for this field to get replacement info
773
- let foundMapping;
774
- for (const objectType of objectTypesAffected) {
775
- const mapping = getFieldDeprecation(objectType, field);
776
- if (mapping) {
777
- foundMapping = mapping;
778
- break;
779
- }
780
- }
781
- const { replacementField = 'unknown', deprecationType = 'unknown' } = foundMapping ?? {};
782
- byField[field] = {
783
- totalUsages: count,
784
- objectTypesAffected: Array.from(objectTypesAffected),
785
- replacementField,
786
- deprecationType,
787
- };
788
- }
789
- // Build affected items list if requested
790
- let affectedItems;
791
- if (includeAffectedItems) {
792
- affectedItems = batchResult.itemsWithDeprecatedFields.slice(0, maxAffectedItems).map((item) => ({
793
- itemId: item.itemId,
794
- objectType: item.objectType,
795
- deprecatedFieldsUsed: item.deprecatedFieldsUsed,
796
- }));
797
- }
798
- return {
799
- generatedAt: new Date().toISOString(),
800
- summary: {
801
- totalObjects: batchResult.totalChecked,
802
- objectsWithDeprecatedFields: batchResult.objectsWithDeprecatedFields,
803
- deprecationPercentage,
804
- totalDeprecatedFieldUsages,
805
- },
806
- byObjectType,
807
- byField,
808
- affectedItems,
809
- };
810
- }
811
- /**
812
- * Validate an object for deprecated field usage.
813
- *
814
- * This is useful for validation pipelines where you want to:
815
- * - Warn users about deprecated field usage
816
- * - Optionally fail validation on deprecated fields
817
- * - Generate clear validation messages
818
- *
819
- * @param objectType - The OCF object type
820
- * @param data - The data to validate
821
- * @param options - Validation options
822
- * @returns Validation result
823
- *
824
- * @example
825
- * ```typescript
826
- * const result = validateDeprecatedFields('StockPlan', {
827
- * stock_class_id: 'sc-1',
828
- * }, { treatAsError: false });
829
- *
830
- * if (!result.valid) {
831
- * console.error(result.errors.join('\n'));
832
- * } else if (result.warnings.length > 0) {
833
- * console.warn(result.warnings.join('\n'));
834
- * }
835
- * ```
836
- */
837
- function validateDeprecatedFields(objectType, data, options = {}) {
838
- const { treatAsError = false, ignoreFields = [], errorMessagePrefix = '' } = options;
839
- const checkResult = checkDeprecatedFields(objectType, data);
840
- const errors = [];
841
- const warnings = [];
842
- // Filter out ignored fields
843
- const relevantFields = checkResult.deprecatedFieldsUsed.filter((field) => !ignoreFields.includes(field));
844
- if (relevantFields.length > 0) {
845
- const messages = relevantFields.map((field) => {
846
- const mapping = getFieldDeprecation(objectType, field);
847
- const replacement = mapping?.replacementField ?? 'unknown';
848
- const prefix = errorMessagePrefix ? `${errorMessagePrefix}: ` : '';
849
- return `${prefix}Field '${field}' is deprecated. Use '${replacement}' instead.`;
850
- });
851
- if (treatAsError) {
852
- errors.push(...messages);
853
- }
854
- else {
855
- warnings.push(...messages);
856
- }
857
- }
858
- return {
859
- valid: errors.length === 0,
860
- errors,
861
- warnings,
862
- checkResult: {
863
- hasDeprecatedFields: relevantFields.length > 0,
864
- deprecatedFieldsUsed: relevantFields,
865
- },
866
- };
867
- }
868
- /**
869
- * Create a validator function for use in validation pipelines.
870
- *
871
- * @param objectType - The OCF object type to validate
872
- * @param options - Validation options
873
- * @returns A validator function that returns DeprecationValidationResult
874
- *
875
- * @example
876
- * ```typescript
877
- * const validateStockPlan = createDeprecatedFieldsValidator('StockPlan', {
878
- * treatAsError: false,
879
- * });
880
- *
881
- * // Use in a validation pipeline
882
- * const result = validateStockPlan(stockPlanData);
883
- * ```
884
- */
885
- function createDeprecatedFieldsValidator(objectType, options = {}) {
886
- return (data) => validateDeprecatedFields(objectType, data, options);
887
- }
888
- /**
889
- * Assert that an object does not use deprecated fields.
890
- * Throws an error if deprecated fields are detected.
891
- *
892
- * @param objectType - The OCF object type
893
- * @param data - The data to check
894
- * @param options - Validation options (ignoreFields only)
895
- * @throws Error if deprecated fields are detected
896
- *
897
- * @example
898
- * ```typescript
899
- * try {
900
- * assertNoDeprecatedFields('StockPlan', stockPlanData);
901
- * // Proceed with operation
902
- * } catch (error) {
903
- * // Handle deprecated field usage
904
- * }
905
- * ```
906
- */
907
- function assertNoDeprecatedFields(objectType, data, options = {}) {
908
- const result = validateDeprecatedFields(objectType, data, {
909
- ...options,
910
- treatAsError: true,
911
- });
912
- if (!result.valid) {
913
- throw new Error(`Deprecated field usage detected: ${result.errors.join('; ')}`);
914
- }
915
- }
916
- // ===== Helper to Register New Deprecations =====
917
- /**
918
- * Register a new deprecated field mapping.
919
- *
920
- * This is useful for extending the built-in deprecation registry with
921
- * custom or newly discovered deprecations.
922
- *
923
- * @param objectType - The OCF object type
924
- * @param mapping - The deprecation mapping to register
925
- *
926
- * @example
927
- * ```typescript
928
- * // Register a new deprecation
929
- * registerDeprecatedFieldMapping('SomeOcfType', {
930
- * deprecatedField: 'old_field',
931
- * replacementField: 'new_fields',
932
- * deprecationType: 'singular_to_array',
933
- * });
934
- * ```
935
- */
936
- function registerDeprecatedFieldMapping(objectType, mapping) {
937
- exports.OCF_DEPRECATED_FIELDS[objectType] ?? (exports.OCF_DEPRECATED_FIELDS[objectType] = []);
938
- // Check if mapping already exists
939
- const existing = exports.OCF_DEPRECATED_FIELDS[objectType].find((m) => m.deprecatedField === mapping.deprecatedField);
940
- if (!existing) {
941
- exports.OCF_DEPRECATED_FIELDS[objectType].push(mapping);
942
- }
943
- }
944
- /**
945
- * Get all registered object types that have deprecated field mappings.
946
- *
947
- * @returns Array of object type names
948
- */
949
- function getRegisteredObjectTypes() {
950
- return Object.keys(exports.OCF_DEPRECATED_FIELDS);
951
- }
952
- /**
953
- * Get all registered deprecated field mappings.
954
- *
955
- * @returns Copy of the deprecated fields registry
956
- */
957
- function getAllDeprecatedFieldMappings() {
958
- // Return a deep copy to prevent external modification
959
- const result = {};
960
- for (const [key, value] of Object.entries(exports.OCF_DEPRECATED_FIELDS)) {
961
- result[key] = value.map((m) => ({ ...m }));
962
- }
963
- return result;
964
- }
965
- // ===== Automatic Normalization for SDK Integration =====
966
- /**
967
- * Map from OcfEntityType (used in batch API) to the object type name used in deprecation registry.
968
- * This allows the SDK to automatically look up deprecations based on entity type.
969
- */
970
- const ENTITY_TYPE_TO_OBJECT_TYPE = {
971
- stockPlan: 'StockPlan',
972
- stakeholder: 'Stakeholder',
973
- equityCompensationIssuance: 'EquityCompensationIssuance',
974
- // Add more mappings as deprecations are discovered for other types
975
- };
976
- /**
977
- * Automatically normalize deprecated fields in OCF data based on entity type.
978
- *
979
- * This function is designed to be called by the SDK internally when processing
980
- * OCF data, making deprecated field handling transparent to end-users.
981
- *
982
- * @param entityType - The OCF entity type (e.g., 'stockPlan')
983
- * @param data - The OCF data that may contain deprecated fields
984
- * @param options - Optional configuration
985
- * @returns The normalized data with deprecated fields converted to current format
986
- *
987
- * @example
988
- * ```typescript
989
- * // SDK automatically normalizes deprecated fields
990
- * const result = normalizeDeprecatedOcfFields('stockPlan', {
991
- * id: 'plan-1',
992
- * stock_class_id: 'sc-1', // deprecated, automatically converted
993
- * plan_name: 'Equity Plan',
994
- * });
995
- * // result.data.stock_class_ids === ['sc-1']
996
- * ```
997
- */
998
- function normalizeDeprecatedOcfFields(entityType, data, options = {}) {
999
- const { emitWarnings = true, context } = options;
1000
- const normalizedFields = [];
1001
- const warnings = [];
1002
- // Step 1: Normalize required array fields to empty arrays if null/undefined
1003
- // This uses lazy cloning internally - only clones if normalization is needed
1004
- const arrayNormResult = normalizeRequiredArrayFields(entityType, data);
1005
- let result = arrayNormResult.data;
1006
- normalizedFields.push(...arrayNormResult.normalizedFields);
1007
- // Track whether we've cloned the result (arrayNormResult.data may be the original or a clone)
1008
- let hasCloned = arrayNormResult.normalizedFields.length > 0;
1009
- // Step 2: Look up the object type for deprecated field mappings
1010
- const objectType = ENTITY_TYPE_TO_OBJECT_TYPE[entityType];
1011
- // If no deprecation mappings exist for this type, return with just array normalization
1012
- if (!objectType) {
1013
- return {
1014
- data: result,
1015
- normalized: normalizedFields.length > 0,
1016
- normalizedFields,
1017
- warnings: [],
1018
- };
1019
- }
1020
- const mappings = getDeprecatedFieldMappings(objectType);
1021
- if (mappings.length === 0) {
1022
- return {
1023
- data: result,
1024
- normalized: normalizedFields.length > 0,
1025
- normalizedFields,
1026
- warnings: [],
1027
- };
1028
- }
1029
- // Helper to ensure we have a mutable clone
1030
- const ensureCloned = () => {
1031
- if (!hasCloned) {
1032
- result = { ...result };
1033
- hasCloned = true;
1034
- }
1035
- };
1036
- // Track which deprecated fields we normalized (for removal at the end)
1037
- const deprecatedFieldsToRemove = [];
1038
- for (const mapping of mappings) {
1039
- const deprecatedValue = result[mapping.deprecatedField];
1040
- const hasDeprecated = deprecatedValue !== undefined && deprecatedValue !== null && deprecatedValue !== '';
1041
- if (!hasDeprecated) {
1042
- continue;
1043
- }
1044
- switch (mapping.deprecationType) {
1045
- case 'singular_to_array': {
1046
- const currentValue = result[mapping.replacementField];
1047
- const hasCurrentArray = Array.isArray(currentValue) && currentValue.length > 0;
1048
- if (!hasCurrentArray) {
1049
- // Convert singular to array
1050
- ensureCloned();
1051
- result[mapping.replacementField] = [deprecatedValue];
1052
- normalizedFields.push(mapping.deprecatedField);
1053
- deprecatedFieldsToRemove.push(mapping.deprecatedField);
1054
- if (emitWarnings) {
1055
- emitDeprecationWarning({
1056
- deprecatedField: mapping.deprecatedField,
1057
- replacementField: mapping.replacementField,
1058
- deprecatedValue,
1059
- context: context ?? `${entityType}.create`,
1060
- });
1061
- }
1062
- }
1063
- else {
1064
- // Both present - current takes precedence, emit warning
1065
- warnings.push(`Both '${mapping.deprecatedField}' (deprecated) and '${mapping.replacementField}' are present. ` +
1066
- `Using '${mapping.replacementField}' value.`);
1067
- }
1068
- break;
1069
- }
1070
- case 'renamed': {
1071
- const currentValue = result[mapping.replacementField];
1072
- const hasCurrent = currentValue !== undefined && currentValue !== null;
1073
- if (!hasCurrent) {
1074
- // Copy deprecated value to new field
1075
- ensureCloned();
1076
- result[mapping.replacementField] = deprecatedValue;
1077
- normalizedFields.push(mapping.deprecatedField);
1078
- deprecatedFieldsToRemove.push(mapping.deprecatedField);
1079
- if (emitWarnings) {
1080
- emitDeprecationWarning({
1081
- deprecatedField: mapping.deprecatedField,
1082
- replacementField: mapping.replacementField,
1083
- deprecatedValue,
1084
- context: context ?? `${entityType}.create`,
1085
- });
1086
- }
1087
- }
1088
- else {
1089
- warnings.push(`Both '${mapping.deprecatedField}' (deprecated) and '${mapping.replacementField}' are present. ` +
1090
- `Using '${mapping.replacementField}' value.`);
1091
- }
1092
- break;
1093
- }
1094
- case 'value_mapped': {
1095
- const currentValue = result[mapping.replacementField];
1096
- const hasCurrent = currentValue !== undefined && currentValue !== null && currentValue !== '';
1097
- if (!hasCurrent) {
1098
- // value_mapped requires string values; skip non-string types
1099
- if (typeof deprecatedValue !== 'string') {
1100
- warnings.push(`Expected string value for '${mapping.deprecatedField}', got ${typeof deprecatedValue}`);
1101
- break;
1102
- }
1103
- const valueMap = mapping.valueMap ?? {};
1104
- const mappedValue = valueMap[deprecatedValue] ?? deprecatedValue;
1105
- ensureCloned();
1106
- result[mapping.replacementField] = mappedValue;
1107
- normalizedFields.push(mapping.deprecatedField);
1108
- deprecatedFieldsToRemove.push(mapping.deprecatedField);
1109
- if (emitWarnings) {
1110
- emitDeprecationWarning({
1111
- deprecatedField: mapping.deprecatedField,
1112
- replacementField: mapping.replacementField,
1113
- deprecatedValue,
1114
- context: context ?? `${entityType}.create`,
1115
- });
1116
- }
1117
- }
1118
- else {
1119
- warnings.push(`Both '${mapping.deprecatedField}' (deprecated) and '${mapping.replacementField}' are present. ` +
1120
- `Using '${mapping.replacementField}' value.`);
1121
- }
1122
- break;
1123
- }
1124
- case 'removed': {
1125
- // Field is removed, just warn
1126
- warnings.push(`Field '${mapping.deprecatedField}' is deprecated and will be ignored. ` +
1127
- `It has been removed in the current schema.`);
1128
- normalizedFields.push(mapping.deprecatedField);
1129
- deprecatedFieldsToRemove.push(mapping.deprecatedField);
1130
- break;
1131
- }
1132
- }
1133
- }
1134
- // Remove deprecated fields from the result to keep data clean
1135
- // (They've been migrated to their replacements, or removed entirely for 'removed' type)
1136
- if (deprecatedFieldsToRemove.length > 0) {
1137
- ensureCloned();
1138
- for (const field of deprecatedFieldsToRemove) {
1139
- delete result[field];
1140
- }
1141
- }
1142
- return {
1143
- data: result,
1144
- normalized: normalizedFields.length > 0,
1145
- normalizedFields,
1146
- warnings,
1147
- };
1148
- }
1149
- /**
1150
- * Check if an entity type has registered deprecations.
1151
- *
1152
- * @param entityType - The OCF entity type (e.g., 'stockPlan')
1153
- * @returns true if the entity type has deprecation mappings
1154
- */
1155
- function hasDeprecationsForEntityType(entityType) {
1156
- const objectType = ENTITY_TYPE_TO_OBJECT_TYPE[entityType];
1157
- if (!objectType) {
1158
- return false;
1159
- }
1160
- return getDeprecatedFieldMappings(objectType).length > 0;
1161
- }
1162
- /**
1163
- * Register a mapping from entity type to object type for automatic normalization.
1164
- *
1165
- * @param entityType - The OcfEntityType used in batch API (e.g., 'stockPlan')
1166
- * @param objectType - The object type name used in deprecation registry (e.g., 'StockPlan')
1167
- */
1168
- function registerEntityTypeMapping(entityType, objectType) {
1169
- ENTITY_TYPE_TO_OBJECT_TYPE[entityType] = objectType;
1170
- }
1171
- // ===== Unified OCF Object Normalization =====
1172
- /**
1173
- * Map from OCF object_type to the object type name used in deprecation registry.
1174
- */
1175
- const OBJECT_TYPE_TO_REGISTRY_TYPE = {
1176
- STOCK_PLAN: 'StockPlan',
1177
- STAKEHOLDER: 'Stakeholder',
1178
- TX_EQUITY_COMPENSATION_ISSUANCE: 'EquityCompensationIssuance',
1179
- TX_PLAN_SECURITY_ISSUANCE: 'EquityCompensationIssuance',
1180
- };
1181
- /**
1182
- * Normalize quantity_source field for OCF objects.
1183
- *
1184
- * Handles two scenarios to ensure consistent comparison:
1185
- *
1186
- * 1. When quantity is NOT present (null/undefined): quantity_source is meaningless
1187
- * and should be stripped. This ensures:
1188
- * - DB with { quantity_source: 'UNSPECIFIED' } (no quantity)
1189
- * - Canton readback with {} (no quantity, no quantity_source)
1190
- * are treated as semantically equivalent.
1191
- *
1192
- * 2. When quantity IS present but quantity_source is missing: quantity_source should
1193
- * be set to 'UNSPECIFIED' because the OCF-to-DAML converter defaults to 'UNSPECIFIED'
1194
- * when quantity is present without quantity_source. This ensures:
1195
- * - DB with { quantity: '1000' } (no quantity_source)
1196
- * - Canton readback with { quantity: '1000', quantity_source: 'UNSPECIFIED' }
1197
- * are treated as semantically equivalent.
1198
- *
1199
- * @param data - OCF object that may have quantity and quantity_source fields
1200
- * @returns Object with quantity_source normalized based on quantity presence
1201
- */
1202
- function normalizeQuantitySource(data) {
1203
- const { quantity, quantity_source: quantitySource } = data;
1204
- // Case 1: Strip quantity_source if quantity is not present (null/undefined)
1205
- // and quantity_source is 'UNSPECIFIED' (which is equivalent to "don't know")
1206
- if ((quantity === null || quantity === undefined) && quantitySource === 'UNSPECIFIED') {
1207
- const { quantity_source: _, ...rest } = data;
1208
- return rest;
1209
- }
1210
- // Case 2: Add quantity_source: 'UNSPECIFIED' if quantity IS present but quantity_source is missing
1211
- // This matches the OCF-to-DAML converter behavior that defaults to 'UNSPECIFIED'
1212
- if (quantity !== null && quantity !== undefined && quantitySource === undefined) {
1213
- return { ...data, quantity_source: 'UNSPECIFIED' };
1214
- }
1215
- return data;
1216
- }
1217
- /**
1218
- * Normalize an OCF object by applying all deprecation normalizations.
1219
- *
1220
- * This function auto-detects the object type from the `object_type` field and applies:
1221
- * 1. PlanSecurity -> EquityCompensation object_type normalization
1222
- * 2. Deprecated field normalizations (singular->array, value mappings, etc.)
1223
- * 3. Semantic normalizations (e.g., quantity_source: 'UNSPECIFIED' when quantity is absent)
1224
- */
1225
- function normalizeOcfObject(data, options = {}) {
1226
- const { emitWarnings = true, context } = options;
1227
- const normalizedFields = [];
1228
- const warnings = [];
1229
- // Step 0: Normalize quantity_source (strip if UNSPECIFIED and no quantity)
1230
- // This must happen before other normalizations to ensure consistent comparison
1231
- let result = normalizeQuantitySource(data);
1232
- // Step 1: Normalize PlanSecurity object_type to EquityCompensation
1233
- result = (0, planSecurityAliases_1.normalizeOcfData)(result);
1234
- const originalObjectType = data.object_type;
1235
- const normalizedObjectType = result.object_type;
1236
- if (originalObjectType !== normalizedObjectType && typeof originalObjectType === 'string') {
1237
- normalizedFields.push('object_type');
1238
- if (emitWarnings) {
1239
- emitDeprecationWarning({
1240
- deprecatedField: 'object_type',
1241
- replacementField: 'object_type',
1242
- deprecatedValue: originalObjectType,
1243
- context: context ?? 'normalizeOcfObject',
1244
- });
1245
- }
1246
- }
1247
- // Step 2: Determine the registry type from object_type
1248
- const objectType = typeof normalizedObjectType === 'string' ? normalizedObjectType : undefined;
1249
- const registryType = objectType ? OBJECT_TYPE_TO_REGISTRY_TYPE[objectType] : undefined;
1250
- if (!registryType) {
1251
- return { data: result, normalized: normalizedFields.length > 0, normalizedFields, warnings };
1252
- }
1253
- // Step 3: Apply deprecated field normalizations
1254
- const mappings = getDeprecatedFieldMappings(registryType);
1255
- for (const mapping of mappings) {
1256
- const deprecatedValue = result[mapping.deprecatedField];
1257
- const hasDeprecated = deprecatedValue !== undefined && deprecatedValue !== null && deprecatedValue !== '';
1258
- if (!hasDeprecated)
1259
- continue;
1260
- switch (mapping.deprecationType) {
1261
- case 'singular_to_array': {
1262
- const currentValue = result[mapping.replacementField];
1263
- const hasCurrentArray = Array.isArray(currentValue) && currentValue.length > 0;
1264
- if (!hasCurrentArray) {
1265
- result = { ...result, [mapping.replacementField]: [deprecatedValue] };
1266
- normalizedFields.push(mapping.deprecatedField);
1267
- if (emitWarnings) {
1268
- emitDeprecationWarning({
1269
- deprecatedField: mapping.deprecatedField,
1270
- replacementField: mapping.replacementField,
1271
- deprecatedValue,
1272
- context: context ?? registryType,
1273
- });
1274
- }
1275
- }
1276
- else {
1277
- warnings.push(`Both '${mapping.deprecatedField}' (deprecated) and '${mapping.replacementField}' are present. Using '${mapping.replacementField}' value.`);
1278
- }
1279
- break;
1280
- }
1281
- case 'value_mapped': {
1282
- const currentValue = result[mapping.replacementField];
1283
- const hasCurrent = currentValue !== undefined && currentValue !== null && currentValue !== '';
1284
- if (!hasCurrent) {
1285
- // value_mapped requires string values; skip non-string types
1286
- if (typeof deprecatedValue !== 'string') {
1287
- warnings.push(`Expected string value for '${mapping.deprecatedField}', got ${typeof deprecatedValue}`);
1288
- break;
1289
- }
1290
- const valueMap = mapping.valueMap ?? {};
1291
- const mappedValue = valueMap[deprecatedValue] ?? deprecatedValue;
1292
- result = { ...result, [mapping.replacementField]: mappedValue };
1293
- normalizedFields.push(mapping.deprecatedField);
1294
- if (emitWarnings) {
1295
- emitDeprecationWarning({
1296
- deprecatedField: mapping.deprecatedField,
1297
- replacementField: mapping.replacementField,
1298
- deprecatedValue,
1299
- context: context ?? registryType,
1300
- });
1301
- }
1302
- }
1303
- else {
1304
- warnings.push(`Both '${mapping.deprecatedField}' (deprecated) and '${mapping.replacementField}' are present. Using '${mapping.replacementField}' value.`);
1305
- }
1306
- break;
1307
- }
1308
- case 'renamed': {
1309
- const currentValue = result[mapping.replacementField];
1310
- const hasCurrent = currentValue !== undefined && currentValue !== null;
1311
- if (!hasCurrent) {
1312
- result = { ...result, [mapping.replacementField]: deprecatedValue };
1313
- normalizedFields.push(mapping.deprecatedField);
1314
- if (emitWarnings) {
1315
- emitDeprecationWarning({
1316
- deprecatedField: mapping.deprecatedField,
1317
- replacementField: mapping.replacementField,
1318
- deprecatedValue,
1319
- context: context ?? registryType,
1320
- });
1321
- }
1322
- }
1323
- else {
1324
- warnings.push(`Both '${mapping.deprecatedField}' (deprecated) and '${mapping.replacementField}' are present. Using '${mapping.replacementField}' value.`);
1325
- }
1326
- break;
1327
- }
1328
- case 'removed': {
1329
- warnings.push(`Field '${mapping.deprecatedField}' is deprecated and will be ignored.`);
1330
- normalizedFields.push(mapping.deprecatedField);
1331
- break;
1332
- }
1333
- }
1334
- }
1335
- // Step 4: Remove deprecated fields from the result
1336
- // Note: The `as T` assertion is intentional - TypeScript cannot track field removal through
1337
- // computed property spread. The result type may differ from T (deprecated fields removed),
1338
- // but this is the expected behavior and callers handle it via Record<string, unknown>.
1339
- for (const mapping of mappings) {
1340
- if (normalizedFields.includes(mapping.deprecatedField) && mapping.deprecatedField !== 'object_type') {
1341
- const { [mapping.deprecatedField]: _removed, ...rest } = result;
1342
- result = rest;
1343
- }
1344
- }
1345
- return { data: result, normalized: normalizedFields.length > 0, normalizedFields, warnings };
1346
- }
1347
- /**
1348
- * Compare two OCF objects for semantic equivalence after normalizing deprecated fields.
1349
- */
1350
- function areOcfObjectsEquivalent(dbObject, chainObject, options = {}) {
1351
- const result = compareOcfObjects(dbObject, chainObject, options);
1352
- return result.equivalent;
1353
- }
1354
- /**
1355
- * Compare two OCF objects with detailed results.
1356
- */
1357
- function compareOcfObjects(dbObject, chainObject, options = {}) {
1358
- const { normalizeBeforeCompare = true, emitNormalizationWarnings = false, ignoredFields = [...ocfComparison_1.DEFAULT_INTERNAL_FIELDS], deprecatedFields = [...ocfComparison_1.DEFAULT_DEPRECATED_FIELDS], reportDifferences, } = options;
1359
- let normalizedA = dbObject;
1360
- let normalizedB = chainObject;
1361
- let normResultA = { normalized: false, normalizedFields: [], warnings: [] };
1362
- let normResultB = { normalized: false, normalizedFields: [], warnings: [] };
1363
- if (normalizeBeforeCompare) {
1364
- const resultA = normalizeOcfObject(dbObject, { emitWarnings: emitNormalizationWarnings });
1365
- normalizedA = resultA.data;
1366
- normResultA = {
1367
- normalized: resultA.normalized,
1368
- normalizedFields: resultA.normalizedFields,
1369
- warnings: resultA.warnings,
1370
- };
1371
- const resultB = normalizeOcfObject(chainObject, { emitWarnings: emitNormalizationWarnings });
1372
- normalizedB = resultB.data;
1373
- normResultB = {
1374
- normalized: resultB.normalized,
1375
- normalizedFields: resultB.normalizedFields,
1376
- warnings: resultB.warnings,
1377
- };
1378
- }
1379
- const equivalent = (0, ocfComparison_1.ocfDeepEqual)(normalizedA, normalizedB, { ignoredFields, deprecatedFields, reportDifferences });
1380
- return {
1381
- equivalent,
1382
- normalizationA: {
1383
- wasNormalized: normResultA.normalized,
1384
- normalizedFields: normResultA.normalizedFields,
1385
- warnings: normResultA.warnings,
1386
- },
1387
- normalizationB: {
1388
- wasNormalized: normResultB.normalized,
1389
- normalizedFields: normResultB.normalizedFields,
1390
- warnings: normResultB.warnings,
1391
- },
1392
- };
1393
- }
1394
- // ===== Required Array Field Normalization =====
1395
- /**
1396
- * Configuration for required array fields by entity type.
1397
- * These fields must be arrays (empty or populated), but raw data might have them as null/undefined.
1398
- * The SDK normalizes these to empty arrays automatically.
1399
- */
1400
- exports.REQUIRED_ARRAY_FIELDS = {
1401
- // issuer is handled separately in createIssuer.ts
1402
- stockPlan: ['stock_class_ids'],
1403
- convertibleIssuance: ['conversion_triggers', 'security_law_exemptions'],
1404
- warrantIssuance: ['exercise_triggers', 'security_law_exemptions'],
1405
- stakeholderRelationshipChangeEvent: ['new_relationships'],
1406
- // vestingTerms.vesting_conditions requires at least one condition, so we don't auto-normalize to empty
1407
- // resulting_security_ids must be explicitly provided, not auto-normalized
1408
- };
1409
- /**
1410
- * Normalize required array fields in OCF data.
1411
- * This ensures array fields that are null/undefined become empty arrays.
1412
- *
1413
- * Uses lazy cloning - only creates a copy when modification is actually needed,
1414
- * and clones once then mutates the clone for efficiency.
1415
- *
1416
- * @param entityType - The OCF entity type
1417
- * @param data - The OCF data that may have null/undefined array fields
1418
- * @returns The normalized data with array fields as arrays
1419
- */
1420
- function normalizeRequiredArrayFields(entityType, data) {
1421
- const requiredArrays = exports.REQUIRED_ARRAY_FIELDS[entityType];
1422
- if (!requiredArrays || requiredArrays.length === 0) {
1423
- return { data, normalizedFields: [] };
1424
- }
1425
- // First pass: identify which fields need normalization
1426
- const fieldsToNormalize = [];
1427
- for (const field of requiredArrays) {
1428
- const value = data[field];
1429
- if (value === null || value === undefined) {
1430
- fieldsToNormalize.push(field);
1431
- }
1432
- }
1433
- // If no fields need normalization, return original data (no clone)
1434
- if (fieldsToNormalize.length === 0) {
1435
- return { data, normalizedFields: [] };
1436
- }
1437
- // Clone once, then mutate the clone for all fields
1438
- const result = { ...data };
1439
- for (const field of fieldsToNormalize) {
1440
- result[field] = [];
1441
- }
1442
- return { data: result, normalizedFields: fieldsToNormalize };
1443
- }
1444
- /**
1445
- * Register required array fields for an entity type.
1446
- *
1447
- * @param entityType - The OCF entity type (e.g., 'stockPlan')
1448
- * @param fields - Array of field names that must be arrays
1449
- */
1450
- function registerRequiredArrayFields(entityType, fields) {
1451
- exports.REQUIRED_ARRAY_FIELDS[entityType] = fields;
1452
- }
1453
- /**
1454
- * Get required array fields for an entity type.
1455
- *
1456
- * @param entityType - The OCF entity type
1457
- * @returns Array of field names that must be arrays
1458
- */
1459
- function getRequiredArrayFields(entityType) {
1460
- return exports.REQUIRED_ARRAY_FIELDS[entityType] ?? [];
1461
- }
1462
- //# sourceMappingURL=deprecatedFieldNormalization.js.map