| 574 | * the original shared enum so the merge phase can match them correctly. |
| 575 | */ |
| 576 | export function consolidateEnums({ |
| 577 | newModel, |
| 578 | oldModel, |
| 579 | }: { |
| 580 | newModel: Model; |
| 581 | oldModel: Model; |
| 582 | }) { |
| 583 | const newEnums = newModel.declarations.filter((d) => isEnum(d)) as Enum[]; |
| 584 | const newDataModels = newModel.declarations.filter((d) => d.$type === 'DataModel') as DataModel[]; |
| 585 | const oldDataModels = oldModel.declarations.filter((d) => d.$type === 'DataModel') as DataModel[]; |
| 586 | |
| 587 | // For each new enum, find which old enum it corresponds to (via field references) |
| 588 | const enumMapping = new Map<Enum, Enum>(); // newEnum -> oldEnum |
| 589 | |
| 590 | for (const newEnum of newEnums) { |
| 591 | for (const newDM of newDataModels) { |
| 592 | for (const field of newDM.fields) { |
| 593 | if (field.$type !== 'DataField' || field.type.reference?.ref !== newEnum) continue; |
| 594 | |
| 595 | // Find matching model in old model by db name |
| 596 | const oldDM = oldDataModels.find((d) => getDbName(d) === getDbName(newDM)); |
| 597 | if (!oldDM) continue; |
| 598 | |
| 599 | // Find matching field in old model by db name |
| 600 | const oldField = oldDM.fields.find((f) => getDbName(f) === getDbName(field)); |
| 601 | if (!oldField || oldField.$type !== 'DataField' || !oldField.type.reference?.ref) continue; |
| 602 | |
| 603 | const oldEnum = oldField.type.reference.ref; |
| 604 | if (!isEnum(oldEnum)) continue; |
| 605 | |
| 606 | enumMapping.set(newEnum, oldEnum as Enum); |
| 607 | break; |
| 608 | } |
| 609 | if (enumMapping.has(newEnum)) break; |
| 610 | } |
| 611 | } |
| 612 | |
| 613 | // Group by old enum: oldEnum -> [newEnum1, newEnum2, ...] |
| 614 | const reverseMapping = new Map<Enum, Enum[]>(); |
| 615 | for (const [newEnum, oldEnum] of enumMapping) { |
| 616 | if (!reverseMapping.has(oldEnum)) { |
| 617 | reverseMapping.set(oldEnum, []); |
| 618 | } |
| 619 | reverseMapping.get(oldEnum)!.push(newEnum); |
| 620 | } |
| 621 | |
| 622 | // Consolidate: when new enums map to the same old enum with matching values |
| 623 | for (const [oldEnum, newEnumsGroup] of reverseMapping) { |
| 624 | const keepEnum = newEnumsGroup[0]!; |
| 625 | |
| 626 | // Skip if already correct (single enum with matching name) |
| 627 | if (newEnumsGroup.length === 1 && keepEnum.name === oldEnum.name) continue; |
| 628 | |
| 629 | // Check that all new enums have the same values as the old enum |
| 630 | const oldValues = new Set(oldEnum.fields.map((f) => getDbName(f))); |
| 631 | const allMatch = newEnumsGroup.every((ne) => { |
| 632 | const newValues = new Set(ne.fields.map((f) => getDbName(f))); |
| 633 | return oldValues.size === newValues.size && [...oldValues].every((v) => newValues.has(v)); |