@uniformdev/transformer 1.1.35 → 1.1.37

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -148,6 +148,8 @@ interface ConvertCompositionsToEntriesOptions extends GlobalOptions {
148
148
  compositionTypes: string;
149
149
  componentsToReferences?: string;
150
150
  componentsToBlocks?: string;
151
+ slotsToReferences?: string;
152
+ slotsToBlocks?: string;
151
153
  }
152
154
  interface RemoveParameterOptions extends GlobalOptions {
153
155
  componentType: string;
@@ -307,7 +309,10 @@ declare class CompositionService {
307
309
  }
308
310
 
309
311
  declare class Logger {
312
+ private verbose;
313
+ constructor(verbose?: boolean);
310
314
  info(message: string): void;
315
+ debug(message: string): void;
311
316
  success(message: string): void;
312
317
  error(message: string): void;
313
318
  warn(message: string): void;
@@ -458,6 +463,8 @@ interface ConvertCompositionsToEntriesInternalOptions {
458
463
  compositionTypes: string[];
459
464
  componentsToReferences: string[];
460
465
  componentsToBlocks: string[];
466
+ slotsToReferences: string[];
467
+ slotsToBlocks: string[];
461
468
  whatIf: boolean;
462
469
  strict: boolean;
463
470
  }
@@ -518,6 +525,7 @@ declare class CompositionConverterService {
518
525
  generateEntryFromFlattenedInstance(inst: FlattenedInstance): EntryDefinition;
519
526
  findFlattenTargets(slots: Record<string, ComponentInstance[]>, targetType: string, compositionId: string, compositionName: string, strict: boolean): FlattenedInstance[];
520
527
  private walkSlots;
528
+ findInstancesInSlot(slots: Record<string, ComponentInstance[]>, slotName: string, compositionId: string, compositionName: string, strict: boolean): FlattenedInstance[];
521
529
  private transformContentReferences;
522
530
  buildEntryIdMap(entriesDirFull: string): Promise<Map<string, string>>;
523
531
  buildSourceItemMap(entriesDirFull: string): Promise<Map<string, string>>;
@@ -525,6 +533,7 @@ declare class CompositionConverterService {
525
533
  private matchesType;
526
534
  private compareTypes;
527
535
  private expandWildcardTypes;
536
+ private expandWildcardSlots;
528
537
  private collectMatchingTypes;
529
538
  private truncate;
530
539
  private truncateName;
package/dist/index.js CHANGED
@@ -597,11 +597,15 @@ var CompositionConverterService = class {
597
597
  compositionTypes,
598
598
  componentsToReferences: rawComponentsToReferences,
599
599
  componentsToBlocks: rawComponentsToBlocks,
600
+ slotsToReferences: rawSlotsToReferences,
601
+ slotsToBlocks: rawSlotsToBlocks,
600
602
  whatIf,
601
603
  strict
602
604
  } = options;
603
605
  const initialComponentsToReferences = [...new Set(rawComponentsToReferences)];
604
606
  const initialComponentsToBlocks = [...new Set(rawComponentsToBlocks)];
607
+ const initialSlotsToReferences = [...new Set(rawSlotsToReferences)];
608
+ const initialSlotsToBlocks = [...new Set(rawSlotsToBlocks)];
605
609
  const compositionsDirFull = this.fileSystem.resolvePath(rootDir, compositionsDir);
606
610
  const componentsDirFull = this.fileSystem.resolvePath(rootDir, componentsDir);
607
611
  const contentTypesDirFull = this.fileSystem.resolvePath(rootDir, contentTypesDir);
@@ -618,7 +622,13 @@ var CompositionConverterService = class {
618
622
  if (initialComponentsToBlocks.length > 0) {
619
623
  this.logger.info(`Components to blocks: ${initialComponentsToBlocks.join(", ")}`);
620
624
  }
621
- const sourceItemMap = initialComponentsToReferences.length > 0 ? await this.buildSourceItemMap(entriesDirFull) : /* @__PURE__ */ new Map();
625
+ if (initialSlotsToReferences.length > 0) {
626
+ this.logger.info(`Slots to references: ${initialSlotsToReferences.join(", ")}`);
627
+ }
628
+ if (initialSlotsToBlocks.length > 0) {
629
+ this.logger.info(`Slots to blocks: ${initialSlotsToBlocks.join(", ")}`);
630
+ }
631
+ const sourceItemMap = initialComponentsToReferences.length > 0 || initialSlotsToReferences.length > 0 ? await this.buildSourceItemMap(entriesDirFull) : /* @__PURE__ */ new Map();
622
632
  if (sourceItemMap.size > 0) {
623
633
  this.logger.info(`Found ${sourceItemMap.size} existing entry(ies) with sourceItem values`);
624
634
  }
@@ -635,6 +645,8 @@ var CompositionConverterService = class {
635
645
  this.logger.info(`Found ${compositionResults.length} composition(s)`);
636
646
  const componentsToReferences = this.expandWildcardTypes(compositionResults, initialComponentsToReferences, strict);
637
647
  const componentsToBlocks = this.expandWildcardTypes(compositionResults, initialComponentsToBlocks, strict);
648
+ const slotsToReferences = this.expandWildcardSlots(compositionResults, initialSlotsToReferences, strict);
649
+ const slotsToBlocks = this.expandWildcardSlots(compositionResults, initialSlotsToBlocks, strict);
638
650
  const rootComponentTypes = /* @__PURE__ */ new Set();
639
651
  for (const { composition } of compositionResults) {
640
652
  rootComponentTypes.add(composition.composition.type);
@@ -649,6 +661,7 @@ var CompositionConverterService = class {
649
661
  );
650
662
  const contentType = this.generateContentType(component);
651
663
  contentTypeMap.set(rootType, contentType);
664
+ this.logger.debug(`Generated content type "${rootType}" with ${contentType.fields.length} field(s): ${contentType.fields.map((f) => f.id).join(", ")}`);
652
665
  } catch (error) {
653
666
  if (error instanceof ComponentNotFoundError) {
654
667
  this.logger.warn(`Component not found: ${rootType} \u2014 skipping content type generation`);
@@ -684,6 +697,7 @@ var CompositionConverterService = class {
684
697
  if (isRefType) {
685
698
  const contentType = this.generateContentType(component);
686
699
  targetContentTypeMap.set(targetType, contentType);
700
+ this.logger.debug(`Generated reference content type "${targetType}" with ${contentType.fields.length} field(s): ${contentType.fields.map((f) => f.id).join(", ")}`);
687
701
  }
688
702
  if (isBlockType) {
689
703
  let blockId = targetType;
@@ -713,6 +727,7 @@ var CompositionConverterService = class {
713
727
  blockContentType.id = blockId;
714
728
  blockContentType.name = needsRename ? `${blockContentType.name} Block` : blockContentType.name;
715
729
  targetContentTypeMap.set(blockId, blockContentType);
730
+ this.logger.debug(`Generated block content type "${blockId}" with ${blockContentType.fields.length} field(s): ${blockContentType.fields.map((f) => f.id).join(", ")}`);
716
731
  }
717
732
  if (!isBlockType) {
718
733
  if (!isRefType) {
@@ -732,6 +747,83 @@ var CompositionConverterService = class {
732
747
  throw error;
733
748
  }
734
749
  }
750
+ const slotToRefTypes = /* @__PURE__ */ new Map();
751
+ const slotToBlockTypes = /* @__PURE__ */ new Map();
752
+ for (const slotName of slotsToReferences) slotToRefTypes.set(slotName, /* @__PURE__ */ new Set());
753
+ for (const slotName of slotsToBlocks) slotToBlockTypes.set(slotName, /* @__PURE__ */ new Set());
754
+ for (const { composition: discoverComp } of compositionResults) {
755
+ const dc = discoverComp.composition;
756
+ if (!dc.slots) continue;
757
+ const dcName = dc._name ?? dc._id;
758
+ for (const slotName of slotsToReferences) {
759
+ const instances = this.findInstancesInSlot(dc.slots, slotName, dc._id, dcName, strict);
760
+ for (const inst of instances) {
761
+ if (!this.compareTypes(inst.componentType, dc.type, strict)) {
762
+ slotToRefTypes.get(slotName).add(inst.componentType);
763
+ }
764
+ }
765
+ }
766
+ for (const slotName of slotsToBlocks) {
767
+ const instances = this.findInstancesInSlot(dc.slots, slotName, dc._id, dcName, strict);
768
+ for (const inst of instances) {
769
+ if (!this.compareTypes(inst.componentType, dc.type, strict)) {
770
+ slotToBlockTypes.get(slotName).add(inst.componentType);
771
+ }
772
+ }
773
+ }
774
+ }
775
+ const allSlotRefTypes = /* @__PURE__ */ new Set();
776
+ for (const types of slotToRefTypes.values()) for (const t of types) allSlotRefTypes.add(t);
777
+ const allSlotBlockTypes = /* @__PURE__ */ new Set();
778
+ for (const types of slotToBlockTypes.values()) for (const t of types) allSlotBlockTypes.add(t);
779
+ const allSlotTargetTypes = /* @__PURE__ */ new Set([...allSlotRefTypes, ...allSlotBlockTypes]);
780
+ for (const targetType of allSlotTargetTypes) {
781
+ if (targetContentTypeMap.has(targetType) || missingTargetTypes.includes(targetType)) continue;
782
+ const isRootType = [...rootComponentTypes].some((rt) => this.compareTypes(rt, targetType, strict));
783
+ if (isRootType) continue;
784
+ const isSlotBlockType = allSlotBlockTypes.has(targetType);
785
+ const isSlotRefType = allSlotRefTypes.has(targetType);
786
+ try {
787
+ const { component } = await this.componentService.loadComponent(componentsDirFull, targetType, { strict });
788
+ if (isSlotRefType) {
789
+ const contentType = this.generateContentType(component);
790
+ targetContentTypeMap.set(targetType, contentType);
791
+ this.logger.debug(`Generated slot reference content type "${targetType}" with ${contentType.fields.length} field(s)`);
792
+ }
793
+ if (isSlotBlockType && !blockTypeIdMap.has(targetType)) {
794
+ let blockId = targetType;
795
+ let needsRename = isSlotRefType;
796
+ if (!needsRename) {
797
+ const existingPath = this.fileSystem.joinPath(contentTypesDirFull, `${targetType}.json`);
798
+ if (await this.fileSystem.fileExists(existingPath)) {
799
+ try {
800
+ const existing = await this.fileSystem.readFile(existingPath);
801
+ if (existing?.type !== "block") needsRename = true;
802
+ } catch {
803
+ }
804
+ }
805
+ }
806
+ if (needsRename) {
807
+ blockId = `${targetType}Block`;
808
+ this.logger.info(`Content type "${targetType}" already exists as non-block, using "${blockId}" for block`);
809
+ }
810
+ blockTypeIdMap.set(targetType, blockId);
811
+ const blockContentType = this.generateContentType(component);
812
+ blockContentType.type = "block";
813
+ blockContentType.id = blockId;
814
+ blockContentType.name = needsRename ? `${blockContentType.name} Block` : blockContentType.name;
815
+ targetContentTypeMap.set(blockId, blockContentType);
816
+ this.logger.debug(`Generated slot block content type "${blockId}" with ${blockContentType.fields.length} field(s)`);
817
+ }
818
+ } catch (error) {
819
+ if (error instanceof ComponentNotFoundError) {
820
+ this.logger.info(`Component type not found: ${targetType}`);
821
+ if (isSlotBlockType && !blockTypeIdMap.has(targetType)) blockTypeIdMap.set(targetType, targetType);
822
+ continue;
823
+ }
824
+ throw error;
825
+ }
826
+ }
735
827
  for (const { composition } of compositionResults) {
736
828
  const comp = composition.composition;
737
829
  const compositionId = comp._id;
@@ -754,6 +846,7 @@ var CompositionConverterService = class {
754
846
  }
755
847
  } else {
756
848
  entry = this.generateEntryFromComposition(composition);
849
+ this.logger.debug(`Generated entry "${entry.entry._id}" from composition "${compositionName}" (${compositionType}) with fields: ${Object.keys(entry.entry.fields).join(", ") || "(none)"}`);
757
850
  }
758
851
  const refsByType = /* @__PURE__ */ new Map();
759
852
  if (componentsToReferences.length > 0 && comp.slots) {
@@ -771,6 +864,7 @@ var CompositionConverterService = class {
771
864
  compositionName,
772
865
  strict
773
866
  );
867
+ this.logger.debug(`Composition "${compositionName}": found ${instances.length} instance(s) of reference type "${refType}"`);
774
868
  if (instances.length > 0) {
775
869
  refsByType.set(refType, instances);
776
870
  if (missingTargetTypes.includes(refType)) {
@@ -784,6 +878,7 @@ var CompositionConverterService = class {
784
878
  const refIds = [];
785
879
  for (const inst of instances) {
786
880
  const existingId = this.findExistingEntryBySourceItem(inst, sourceItemMap);
881
+ this.logger.debug(`Reference instance "${inst.determinisiticId}" (${refType}): ${existingId ? `reusing existing entry "${existingId}"` : `assigned new ID "${inst.determinisiticId}"`}`);
787
882
  refIds.push(existingId ?? inst.determinisiticId);
788
883
  }
789
884
  resolvedRefIds.set(refType, refIds);
@@ -794,7 +889,43 @@ var CompositionConverterService = class {
794
889
  value: resolvedRefIds.get(refType)
795
890
  };
796
891
  }
797
- if (componentsToReferences.length > 0) {
892
+ const refsBySlot = /* @__PURE__ */ new Map();
893
+ if (slotsToReferences.length > 0 && comp.slots) {
894
+ for (const slotName of slotsToReferences) {
895
+ const instances = this.findInstancesInSlot(
896
+ comp.slots,
897
+ slotName,
898
+ compositionId,
899
+ compositionName,
900
+ strict
901
+ );
902
+ const filtered = instances.filter((inst) => {
903
+ if (this.compareTypes(inst.componentType, compositionType, strict)) {
904
+ this.logger.warn(`Skipping reference of "${inst.componentType}" in slot "${slotName}" \u2014 same as root component type`);
905
+ return false;
906
+ }
907
+ return true;
908
+ });
909
+ this.logger.debug(`Composition "${compositionName}": found ${filtered.length} instance(s) in reference slot "${slotName}"`);
910
+ if (filtered.length > 0) refsBySlot.set(slotName, filtered);
911
+ }
912
+ }
913
+ const resolvedSlotRefIds = /* @__PURE__ */ new Map();
914
+ for (const [slotName, instances] of refsBySlot) {
915
+ const refIds = [];
916
+ for (const inst of instances) {
917
+ const existingId = this.findExistingEntryBySourceItem(inst, sourceItemMap);
918
+ refIds.push(existingId ?? inst.determinisiticId);
919
+ }
920
+ resolvedSlotRefIds.set(slotName, refIds);
921
+ }
922
+ for (const [slotName] of refsBySlot) {
923
+ entry.entry.fields[slotName] = {
924
+ type: "contentReference",
925
+ value: resolvedSlotRefIds.get(slotName)
926
+ };
927
+ }
928
+ if (componentsToReferences.length > 0 || slotsToReferences.length > 0) {
798
929
  this.transformContentReferences(entry);
799
930
  }
800
931
  const blocksByType = /* @__PURE__ */ new Map();
@@ -813,6 +944,7 @@ var CompositionConverterService = class {
813
944
  compositionName,
814
945
  strict
815
946
  );
947
+ this.logger.debug(`Composition "${compositionName}": found ${instances.length} instance(s) of block type "${blockType}"`);
816
948
  if (instances.length > 0) {
817
949
  blocksByType.set(blockType, instances);
818
950
  if (missingTargetTypes.includes(blockType)) {
@@ -833,6 +965,35 @@ var CompositionConverterService = class {
833
965
  };
834
966
  blocksEmbedded += instances.length;
835
967
  }
968
+ const blocksBySlot = /* @__PURE__ */ new Map();
969
+ if (slotsToBlocks.length > 0 && comp.slots) {
970
+ for (const slotName of slotsToBlocks) {
971
+ const instances = this.findInstancesInSlot(
972
+ comp.slots,
973
+ slotName,
974
+ compositionId,
975
+ compositionName,
976
+ strict
977
+ );
978
+ const filtered = instances.filter((inst) => {
979
+ if (this.compareTypes(inst.componentType, compositionType, strict)) {
980
+ this.logger.warn(`Skipping block of "${inst.componentType}" in slot "${slotName}" \u2014 same as root component type`);
981
+ return false;
982
+ }
983
+ return true;
984
+ });
985
+ this.logger.debug(`Composition "${compositionName}": found ${filtered.length} instance(s) in block slot "${slotName}"`);
986
+ if (filtered.length > 0) blocksBySlot.set(slotName, filtered);
987
+ }
988
+ }
989
+ for (const [slotName, instances] of blocksBySlot) {
990
+ const blockValues = instances.map((inst) => ({
991
+ type: blockTypeIdMap.get(inst.componentType) ?? inst.componentType,
992
+ fields: { ...inst.instance.parameters ?? {} }
993
+ }));
994
+ entry.entry.fields[slotName] = { type: "$block", value: blockValues };
995
+ blocksEmbedded += instances.length;
996
+ }
836
997
  const entryId = entry.entry._id;
837
998
  if (isExistingEntry) {
838
999
  this.logger.action(
@@ -869,6 +1030,7 @@ var CompositionConverterService = class {
869
1030
  "UPDATE",
870
1031
  `${entriesDir}/${existingId}.json (${refType}, merged fields from "${this.truncate(compositionName, 50)}")`
871
1032
  );
1033
+ this.logger.debug(`Merging fields [${Object.keys(inst.instance.parameters ?? {}).join(", ") || "(none)"}] into existing reference entry "${existingId}"`);
872
1034
  if (!whatIf) {
873
1035
  const existingEntry = await this.fileSystem.readFile(existingEntryPath2);
874
1036
  if (existingEntry?.entry) {
@@ -893,6 +1055,43 @@ var CompositionConverterService = class {
893
1055
  "WRITE",
894
1056
  `${entriesDir}/${inst.determinisiticId}.json (${refType} from "${this.truncate(compositionName, 50)}")`
895
1057
  );
1058
+ this.logger.debug(`Writing reference entry "${inst.determinisiticId}" (${refType}) with fields: ${Object.keys(flatEntry.entry.fields).join(", ") || "(none)"}`);
1059
+ if (!whatIf) {
1060
+ await this.fileSystem.writeFile(flatEntryPath, flatEntry);
1061
+ }
1062
+ entriesFromReferences++;
1063
+ }
1064
+ }
1065
+ for (const [, instances] of refsBySlot) {
1066
+ for (const inst of instances) {
1067
+ const existingId = this.findExistingEntryBySourceItem(inst, sourceItemMap);
1068
+ if (existingId) {
1069
+ const existingSlotEntryPath = this.fileSystem.joinPath(entriesDirFull, `${existingId}.json`);
1070
+ this.logger.action(
1071
+ whatIf,
1072
+ "UPDATE",
1073
+ `${entriesDir}/${existingId}.json (${inst.componentType}, merged fields from "${this.truncate(compositionName, 50)}")`
1074
+ );
1075
+ if (!whatIf) {
1076
+ const existingEntry = await this.fileSystem.readFile(existingSlotEntryPath);
1077
+ if (existingEntry?.entry) {
1078
+ existingEntry.entry.fields = {
1079
+ ...existingEntry.entry.fields,
1080
+ ...inst.instance.parameters ?? {}
1081
+ };
1082
+ await this.fileSystem.writeFile(existingSlotEntryPath, existingEntry);
1083
+ }
1084
+ }
1085
+ entriesReused++;
1086
+ continue;
1087
+ }
1088
+ const flatEntry = this.generateEntryFromFlattenedInstance(inst);
1089
+ const flatEntryPath = this.fileSystem.joinPath(entriesDirFull, `${inst.determinisiticId}.json`);
1090
+ this.logger.action(
1091
+ whatIf,
1092
+ "WRITE",
1093
+ `${entriesDir}/${inst.determinisiticId}.json (${inst.componentType} from "${this.truncate(compositionName, 50)}")`
1094
+ );
896
1095
  if (!whatIf) {
897
1096
  await this.fileSystem.writeFile(flatEntryPath, flatEntry);
898
1097
  }
@@ -919,6 +1118,7 @@ var CompositionConverterService = class {
919
1118
  },
920
1119
  localizable: false
921
1120
  });
1121
+ this.logger.debug(`Field "${refType}" (contentReference) added to content type "${contentType.id}"`);
922
1122
  }
923
1123
  }
924
1124
  }
@@ -941,6 +1141,43 @@ var CompositionConverterService = class {
941
1141
  },
942
1142
  localizable: false
943
1143
  });
1144
+ this.logger.debug(`Field "${resolvedBlockId}" ($block) added to content type "${contentType.id}"`);
1145
+ }
1146
+ }
1147
+ }
1148
+ if (slotsToReferences.length > 0) {
1149
+ for (const contentType of contentTypeMap.values()) {
1150
+ for (const slotName of slotsToReferences) {
1151
+ const typesInSlot = slotToRefTypes.get(slotName) ?? /* @__PURE__ */ new Set();
1152
+ const allowedTypes = [...typesInSlot].filter(
1153
+ (t) => !this.compareTypes(t, contentType.id, strict)
1154
+ );
1155
+ if (allowedTypes.length === 0) continue;
1156
+ contentType.fields.push({
1157
+ id: slotName,
1158
+ name: slotName,
1159
+ type: "contentReference",
1160
+ typeConfig: { isMulti: true, allowedTypes },
1161
+ localizable: false
1162
+ });
1163
+ this.logger.debug(`Field "${slotName}" (contentReference, allowedTypes: ${allowedTypes.join(", ")}) added to content type "${contentType.id}"`);
1164
+ }
1165
+ }
1166
+ }
1167
+ if (slotsToBlocks.length > 0) {
1168
+ for (const contentType of contentTypeMap.values()) {
1169
+ for (const slotName of slotsToBlocks) {
1170
+ const typesInSlot = slotToBlockTypes.get(slotName) ?? /* @__PURE__ */ new Set();
1171
+ const resolvedBlockIds = [...typesInSlot].filter((t) => !this.compareTypes(t, contentType.id, strict)).map((t) => blockTypeIdMap.get(t) ?? t);
1172
+ if (resolvedBlockIds.length === 0) continue;
1173
+ contentType.fields.push({
1174
+ id: slotName,
1175
+ name: slotName,
1176
+ type: "$block",
1177
+ typeConfig: { allowedTypes: resolvedBlockIds },
1178
+ localizable: false
1179
+ });
1180
+ this.logger.debug(`Field "${slotName}" ($block, allowedTypes: ${resolvedBlockIds.join(", ")}) added to content type "${contentType.id}"`);
944
1181
  }
945
1182
  }
946
1183
  }
@@ -965,6 +1202,7 @@ var CompositionConverterService = class {
965
1202
  "WRITE",
966
1203
  `${contentTypesDir}/${typeName}.json (${baseFieldCount} fields${extrasInfo})`
967
1204
  );
1205
+ this.logger.debug(`Content type "${typeName}" fields: ${contentType.fields.map((f) => `${f.id}:${f.type}`).join(", ")}`);
968
1206
  if (!whatIf) {
969
1207
  await this.fileSystem.writeFile(filePath, contentType);
970
1208
  }
@@ -977,6 +1215,7 @@ var CompositionConverterService = class {
977
1215
  "WRITE",
978
1216
  `${contentTypesDir}/${typeName}.json (${contentType.fields.length} fields)`
979
1217
  );
1218
+ this.logger.debug(`Content type "${typeName}" fields: ${contentType.fields.map((f) => `${f.id}:${f.type}`).join(", ")}`);
980
1219
  if (!whatIf) {
981
1220
  await this.fileSystem.writeFile(filePath, contentType);
982
1221
  }
@@ -1108,6 +1347,29 @@ var CompositionConverterService = class {
1108
1347
  }
1109
1348
  }
1110
1349
  }
1350
+ // --- Slot-Based Instance Finding ---
1351
+ findInstancesInSlot(slots, slotName, compositionId, compositionName, strict) {
1352
+ const results = [];
1353
+ for (const [name, instances] of Object.entries(slots)) {
1354
+ const matches = strict ? name === slotName : name.toLowerCase() === slotName.toLowerCase();
1355
+ if (!matches) continue;
1356
+ if (!Array.isArray(instances)) continue;
1357
+ for (let i = 0; i < instances.length; i++) {
1358
+ const instance = instances[i];
1359
+ if (instance._pattern) continue;
1360
+ const path2 = `${compositionId}-${name}-[${i}]-${instance.type}`;
1361
+ results.push({
1362
+ instance,
1363
+ path: path2,
1364
+ determinisiticId: computeGuidHash(path2),
1365
+ componentType: instance.type,
1366
+ compositionId,
1367
+ compositionName
1368
+ });
1369
+ }
1370
+ }
1371
+ return results;
1372
+ }
1111
1373
  // --- Content Reference Transformation ---
1112
1374
  transformContentReferences(entry) {
1113
1375
  const dataResources = {};
@@ -1210,6 +1472,34 @@ var CompositionConverterService = class {
1210
1472
  }
1211
1473
  return [...new Set(expanded)];
1212
1474
  }
1475
+ expandWildcardSlots(compositionResults, patterns, strict) {
1476
+ const expanded = [];
1477
+ for (const pattern of patterns) {
1478
+ if (!pattern.includes("*")) {
1479
+ expanded.push(pattern);
1480
+ continue;
1481
+ }
1482
+ const matched = /* @__PURE__ */ new Set();
1483
+ for (const { composition } of compositionResults) {
1484
+ if (composition.composition.slots) {
1485
+ for (const slotName of Object.keys(composition.composition.slots)) {
1486
+ if (this.matchesType(slotName, pattern, strict)) {
1487
+ matched.add(slotName);
1488
+ }
1489
+ }
1490
+ }
1491
+ }
1492
+ if (matched.size === 0) {
1493
+ this.logger.warn(`Wildcard pattern "${pattern}" did not match any slot names`);
1494
+ } else {
1495
+ this.logger.info(`Wildcard "${pattern}" expanded to: ${[...matched].join(", ")}`);
1496
+ }
1497
+ for (const name of matched) {
1498
+ expanded.push(name);
1499
+ }
1500
+ }
1501
+ return [...new Set(expanded)];
1502
+ }
1213
1503
  collectMatchingTypes(slots, pattern, strict, matched) {
1214
1504
  for (const instances of Object.values(slots)) {
1215
1505
  if (!Array.isArray(instances)) continue;
@@ -1342,6 +1632,7 @@ var PropertyPropagatorService = class {
1342
1632
  try {
1343
1633
  const { component: sourceComponent, filePath: sourceFilePath } = await this.componentService.loadComponent(fullComponentsDir, sourceType, findOptions);
1344
1634
  sourceComponents.push({ sourceType, sourceFilePath, sourceComponent });
1635
+ this.logger.debug(`Loaded source component "${sourceType}" from ${sourceFilePath}`);
1345
1636
  } catch (error) {
1346
1637
  if (error instanceof ComponentNotFoundError) {
1347
1638
  this.logger.warn(`Component not found: ${sourceType} (searched: ${fullComponentsDir})`);
@@ -1352,6 +1643,7 @@ var PropertyPropagatorService = class {
1352
1643
  }
1353
1644
  this.logger.info(`Loading component: ${targetComponentType}`);
1354
1645
  const { component: targetComponent, filePath: targetFilePath } = await this.componentService.loadComponent(fullComponentsDir, targetComponentType, findOptions);
1646
+ this.logger.debug(`Loaded target component "${targetComponentType}" from ${targetFilePath}`);
1355
1647
  const propertyNames = property.split("|").map((p) => p.trim()).filter((p) => p.length > 0);
1356
1648
  const resolvedParams = [];
1357
1649
  const resolvedNames = [];
@@ -1372,6 +1664,8 @@ var PropertyPropagatorService = class {
1372
1664
  if (!exists) {
1373
1665
  resolvedParams.push(param);
1374
1666
  resolvedNames.push(param.id);
1667
+ } else {
1668
+ this.logger.debug(`Parameter "${param.id}" already collected from another source \u2014 skipping duplicate`);
1375
1669
  }
1376
1670
  }
1377
1671
  }
@@ -1410,7 +1704,10 @@ var PropertyPropagatorService = class {
1410
1704
  targetGroup,
1411
1705
  findOptions
1412
1706
  );
1707
+ this.logger.debug(`Group "${targetGroup}" (id: ${groupId}) created on component ${targetComponentType}`);
1413
1708
  componentModified = true;
1709
+ } else {
1710
+ this.logger.debug(`Group "${targetGroup}" (id: ${groupId}) already exists on ${targetComponentType}`);
1414
1711
  }
1415
1712
  for (const param of resolvedParams) {
1416
1713
  const existingParam = this.componentService.findParameter(
@@ -1435,6 +1732,7 @@ var PropertyPropagatorService = class {
1435
1732
  param.id,
1436
1733
  findOptions
1437
1734
  );
1735
+ this.logger.debug(`Parameter "${param.id}" (type: ${param.type}) added to component ${targetComponentType} in group "${targetGroup}"`);
1438
1736
  componentModified = true;
1439
1737
  } else {
1440
1738
  this.logger.info(`Parameter "${param.id}" already exists on ${targetComponentType}`);
@@ -1454,7 +1752,10 @@ var PropertyPropagatorService = class {
1454
1752
  param.id,
1455
1753
  findOptions
1456
1754
  );
1755
+ this.logger.debug(`Parameter "${param.id}" added to group "${targetGroup}" on ${targetComponentType} (was missing from group)`);
1457
1756
  componentModified = true;
1757
+ } else {
1758
+ this.logger.debug(`Parameter "${param.id}" already in group "${targetGroup}" on ${targetComponentType} \u2014 no change`);
1458
1759
  }
1459
1760
  }
1460
1761
  }
@@ -1467,6 +1768,7 @@ var PropertyPropagatorService = class {
1467
1768
  compositionTypes,
1468
1769
  findOptions
1469
1770
  );
1771
+ this.logger.debug(`Found ${compositions.length} composition(s) matching types [${compositionTypes.join(", ")}]`);
1470
1772
  let modifiedCompositions = 0;
1471
1773
  let propagatedInstances = 0;
1472
1774
  for (const { composition, filePath } of compositions) {
@@ -1477,6 +1779,7 @@ var PropertyPropagatorService = class {
1477
1779
  findOptions
1478
1780
  );
1479
1781
  if (instances.length === 0) {
1782
+ this.logger.debug(`Skipping "${filePath}": no instances of ${targetComponentType} found`);
1480
1783
  continue;
1481
1784
  }
1482
1785
  const valuesToPropagate = {};
@@ -1486,6 +1789,7 @@ var PropertyPropagatorService = class {
1486
1789
  }
1487
1790
  }
1488
1791
  if (Object.keys(valuesToPropagate).length === 0) {
1792
+ this.logger.debug(`Skipping "${filePath}": ${instances.length} instance(s) of ${targetComponentType} found but none of [${resolvedNames.join(", ")}] present in root overrides`);
1489
1793
  continue;
1490
1794
  }
1491
1795
  let compositionModified = false;
@@ -1497,9 +1801,11 @@ var PropertyPropagatorService = class {
1497
1801
  this.compositionService.setInstanceParameters(instance, clonedValues);
1498
1802
  compositionModified = true;
1499
1803
  propagatedInstances++;
1804
+ const updatedParamNames = Object.keys(valuesToPropagate).join(", ");
1500
1805
  instanceUpdates.push(
1501
- `${targetComponentType} "${instanceName}": ${Object.keys(valuesToPropagate).join(", ")}`
1806
+ `${targetComponentType} "${instanceName}": ${updatedParamNames}`
1502
1807
  );
1808
+ this.logger.debug(`Component ${targetComponentType} "${instanceName}": parameters ${updatedParamNames} updated`);
1503
1809
  }
1504
1810
  if (compositionModified) {
1505
1811
  this.logger.action(whatIf, "UPDATE", `composition/${relativePath}`);
@@ -1522,7 +1828,10 @@ var PropertyPropagatorService = class {
1522
1828
  if (exists) {
1523
1829
  this.logger.action(whatIf, "DELETE", `Parameter "${param.id}" from ${sourceType}`);
1524
1830
  modifiedSource = this.componentService.removeParameter(modifiedSource, param.id, findOptions);
1831
+ this.logger.debug(`Parameter "${param.id}" removed from component ${sourceType}`);
1525
1832
  sourceComponentModified = true;
1833
+ } else {
1834
+ this.logger.debug(`Parameter "${param.id}" not found on source component "${sourceType}" \u2014 nothing to delete`);
1526
1835
  }
1527
1836
  }
1528
1837
  const beforeGroupCount = modifiedSource.parameters?.filter(
@@ -1561,6 +1870,8 @@ var PropertyPropagatorService = class {
1561
1870
  if (!whatIf) {
1562
1871
  await this.compositionService.saveComposition(filePath, composition);
1563
1872
  }
1873
+ } else {
1874
+ this.logger.debug(`No root overrides matching [${resolvedNames.join(", ")}] in composition/${relativePath}`);
1564
1875
  }
1565
1876
  }
1566
1877
  }
@@ -2934,9 +3245,16 @@ var FieldRemoverService = class {
2934
3245
  // src/cli/logger.ts
2935
3246
  import chalk from "chalk";
2936
3247
  var Logger = class {
3248
+ constructor(verbose = false) {
3249
+ this.verbose = verbose;
3250
+ }
2937
3251
  info(message) {
2938
3252
  console.log(`${chalk.blue("[INFO]")} ${message}`);
2939
3253
  }
3254
+ debug(message) {
3255
+ if (!this.verbose) return;
3256
+ console.log(`${chalk.magenta("[DEBUG]")} ${message}`);
3257
+ }
2940
3258
  success(message) {
2941
3259
  console.log(`${chalk.green("[DONE]")} ${message}`);
2942
3260
  }