@uniformdev/transformer 1.1.15 → 1.1.17
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/cli/index.js +2883 -2809
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +11 -1
- package/dist/index.js +1360 -1284
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -513,681 +513,765 @@ var CompositionService = class {
|
|
|
513
513
|
}
|
|
514
514
|
};
|
|
515
515
|
|
|
516
|
-
// src/core/services/
|
|
517
|
-
|
|
516
|
+
// src/core/services/composition-converter.service.ts
|
|
517
|
+
import * as crypto from "crypto";
|
|
518
|
+
var CompositionConverterService = class {
|
|
518
519
|
constructor(fileSystem, componentService, compositionService, logger) {
|
|
519
520
|
this.fileSystem = fileSystem;
|
|
520
521
|
this.componentService = componentService;
|
|
521
522
|
this.compositionService = compositionService;
|
|
522
523
|
this.logger = logger;
|
|
523
524
|
}
|
|
524
|
-
async
|
|
525
|
+
async convert(options) {
|
|
525
526
|
const {
|
|
526
527
|
rootDir,
|
|
527
|
-
componentsDir,
|
|
528
528
|
compositionsDir,
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
529
|
+
componentsDir,
|
|
530
|
+
contentTypesDir,
|
|
531
|
+
entriesDir,
|
|
532
|
+
compositionTypes,
|
|
533
|
+
flattenComponentIds,
|
|
533
534
|
whatIf,
|
|
534
|
-
strict
|
|
535
|
-
deleteSourceParameter
|
|
535
|
+
strict
|
|
536
536
|
} = options;
|
|
537
|
-
const
|
|
538
|
-
const
|
|
539
|
-
const
|
|
540
|
-
const
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
537
|
+
const compositionsDirFull = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
538
|
+
const componentsDirFull = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
539
|
+
const contentTypesDirFull = this.fileSystem.resolvePath(rootDir, contentTypesDir);
|
|
540
|
+
const entriesDirFull = this.fileSystem.resolvePath(rootDir, entriesDir);
|
|
541
|
+
let contentTypesWritten = 0;
|
|
542
|
+
let entriesFromCompositions = 0;
|
|
543
|
+
let entriesFromFlattened = 0;
|
|
544
|
+
let entriesReused = 0;
|
|
545
|
+
this.logger.info(`Composition types: ${compositionTypes.join(", ")}`);
|
|
546
|
+
if (flattenComponentIds.length > 0) {
|
|
547
|
+
this.logger.info(`Flatten component types: ${flattenComponentIds.join(", ")}`);
|
|
546
548
|
}
|
|
547
|
-
this.
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
const
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
549
|
+
const sourceItemMap = flattenComponentIds.length > 0 ? await this.buildSourceItemMap(entriesDirFull) : /* @__PURE__ */ new Map();
|
|
550
|
+
if (sourceItemMap.size > 0) {
|
|
551
|
+
this.logger.info(`Found ${sourceItemMap.size} existing entry(ies) with sourceItem values`);
|
|
552
|
+
}
|
|
553
|
+
const compositionResults = await this.compositionService.findCompositionsByTypes(
|
|
554
|
+
compositionsDirFull,
|
|
555
|
+
compositionTypes,
|
|
556
|
+
{ strict }
|
|
557
|
+
);
|
|
558
|
+
if (compositionResults.length === 0) {
|
|
559
|
+
this.logger.warn("No compositions found matching the specified types");
|
|
560
|
+
return { contentTypesWritten: 0, entriesFromCompositions: 0, entriesFromFlattened: 0, entriesReused: 0 };
|
|
561
|
+
}
|
|
562
|
+
this.logger.info(`Found ${compositionResults.length} composition(s)`);
|
|
563
|
+
const rootComponentTypes = /* @__PURE__ */ new Set();
|
|
564
|
+
for (const { composition } of compositionResults) {
|
|
565
|
+
rootComponentTypes.add(composition.composition.type);
|
|
566
|
+
}
|
|
567
|
+
const contentTypeMap = /* @__PURE__ */ new Map();
|
|
568
|
+
for (const rootType of rootComponentTypes) {
|
|
569
|
+
const { component } = await this.componentService.loadComponent(
|
|
570
|
+
componentsDirFull,
|
|
571
|
+
rootType,
|
|
572
|
+
{ strict }
|
|
557
573
|
);
|
|
558
|
-
|
|
559
|
-
|
|
574
|
+
const contentType = this.generateContentType(component);
|
|
575
|
+
contentTypeMap.set(rootType, contentType);
|
|
576
|
+
}
|
|
577
|
+
const flattenContentTypeMap = /* @__PURE__ */ new Map();
|
|
578
|
+
const missingFlattenTypes = [];
|
|
579
|
+
const foundMissingFlattenTypes = /* @__PURE__ */ new Set();
|
|
580
|
+
for (const flattenType of flattenComponentIds) {
|
|
581
|
+
const isRootType = [...rootComponentTypes].some(
|
|
582
|
+
(rt) => this.compareTypes(rt, flattenType, strict)
|
|
583
|
+
);
|
|
584
|
+
if (isRootType) {
|
|
560
585
|
continue;
|
|
561
586
|
}
|
|
562
|
-
|
|
563
|
-
const
|
|
564
|
-
|
|
587
|
+
try {
|
|
588
|
+
const { component } = await this.componentService.loadComponent(
|
|
589
|
+
componentsDirFull,
|
|
590
|
+
flattenType,
|
|
591
|
+
{ strict }
|
|
565
592
|
);
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
593
|
+
const contentType = this.generateContentType(component);
|
|
594
|
+
flattenContentTypeMap.set(flattenType, contentType);
|
|
595
|
+
} catch (error) {
|
|
596
|
+
if (error instanceof ComponentNotFoundError) {
|
|
597
|
+
this.logger.info(`Flatten component type not found: ${flattenType}`);
|
|
598
|
+
missingFlattenTypes.push(flattenType);
|
|
599
|
+
continue;
|
|
569
600
|
}
|
|
601
|
+
throw error;
|
|
570
602
|
}
|
|
571
603
|
}
|
|
572
|
-
const
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
604
|
+
for (const { composition } of compositionResults) {
|
|
605
|
+
const comp = composition.composition;
|
|
606
|
+
const compositionId = comp._id;
|
|
607
|
+
const compositionName = comp._name ?? compositionId;
|
|
608
|
+
const compositionType = comp.type;
|
|
609
|
+
const entry = this.generateEntryFromComposition(composition);
|
|
610
|
+
const flattenedByType = /* @__PURE__ */ new Map();
|
|
611
|
+
if (flattenComponentIds.length > 0 && comp.slots) {
|
|
612
|
+
for (const flattenType of flattenComponentIds) {
|
|
613
|
+
if (this.compareTypes(flattenType, compositionType, strict)) {
|
|
614
|
+
this.logger.warn(
|
|
615
|
+
`Skipping flatten of "${flattenType}" \u2014 same as root component type`
|
|
616
|
+
);
|
|
617
|
+
continue;
|
|
580
618
|
}
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
);
|
|
588
|
-
} else {
|
|
589
|
-
this.logger.info(`Resolved properties: ${resolvedNames.join(", ")}`);
|
|
590
|
-
}
|
|
591
|
-
let modifiedComponent = { ...targetComponent };
|
|
592
|
-
let componentModified = false;
|
|
593
|
-
const groupId = this.componentService.generateGroupId(targetGroup);
|
|
594
|
-
const existingGroup = this.componentService.findParameter(
|
|
595
|
-
modifiedComponent,
|
|
596
|
-
groupId,
|
|
597
|
-
findOptions
|
|
598
|
-
);
|
|
599
|
-
if (!existingGroup) {
|
|
600
|
-
this.logger.action(whatIf, "CREATE", `Group "${targetGroup}" on ${targetComponentType}`);
|
|
601
|
-
modifiedComponent = this.componentService.ensureGroupExists(
|
|
602
|
-
modifiedComponent,
|
|
603
|
-
groupId,
|
|
604
|
-
targetGroup,
|
|
605
|
-
findOptions
|
|
606
|
-
);
|
|
607
|
-
componentModified = true;
|
|
608
|
-
}
|
|
609
|
-
for (const param of resolvedParams) {
|
|
610
|
-
const existingParam = this.componentService.findParameter(
|
|
611
|
-
modifiedComponent,
|
|
612
|
-
param.id,
|
|
613
|
-
findOptions
|
|
614
|
-
);
|
|
615
|
-
if (!existingParam) {
|
|
616
|
-
this.logger.action(
|
|
617
|
-
whatIf,
|
|
618
|
-
"COPY",
|
|
619
|
-
`Parameter "${param.id}" \u2192 ${targetComponentType}.${targetGroup}`
|
|
620
|
-
);
|
|
621
|
-
modifiedComponent = this.componentService.addParameterToComponent(
|
|
622
|
-
modifiedComponent,
|
|
623
|
-
param,
|
|
624
|
-
findOptions
|
|
625
|
-
);
|
|
626
|
-
modifiedComponent = this.componentService.addParameterToGroup(
|
|
627
|
-
modifiedComponent,
|
|
628
|
-
groupId,
|
|
629
|
-
param.id,
|
|
630
|
-
findOptions
|
|
631
|
-
);
|
|
632
|
-
componentModified = true;
|
|
633
|
-
} else {
|
|
634
|
-
this.logger.info(`Parameter "${param.id}" already exists on ${targetComponentType}`);
|
|
635
|
-
const group = this.componentService.findParameter(
|
|
636
|
-
modifiedComponent,
|
|
637
|
-
groupId,
|
|
638
|
-
findOptions
|
|
639
|
-
);
|
|
640
|
-
if (group && this.componentService.isGroupParameter(group)) {
|
|
641
|
-
const isInGroup = group.typeConfig?.childrenParams?.some(
|
|
642
|
-
(id) => strict ? id === param.id : id.toLowerCase() === param.id.toLowerCase()
|
|
619
|
+
const instances = this.findFlattenTargets(
|
|
620
|
+
comp.slots,
|
|
621
|
+
flattenType,
|
|
622
|
+
compositionId,
|
|
623
|
+
compositionName,
|
|
624
|
+
strict
|
|
643
625
|
);
|
|
644
|
-
if (
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
findOptions
|
|
650
|
-
);
|
|
651
|
-
componentModified = true;
|
|
626
|
+
if (instances.length > 0) {
|
|
627
|
+
flattenedByType.set(flattenType, instances);
|
|
628
|
+
if (missingFlattenTypes.includes(flattenType)) {
|
|
629
|
+
foundMissingFlattenTypes.add(flattenType);
|
|
630
|
+
}
|
|
652
631
|
}
|
|
653
632
|
}
|
|
654
633
|
}
|
|
655
|
-
|
|
656
|
-
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
compositionTypes,
|
|
662
|
-
findOptions
|
|
663
|
-
);
|
|
664
|
-
let modifiedCompositions = 0;
|
|
665
|
-
let propagatedInstances = 0;
|
|
666
|
-
for (const { composition, filePath } of compositions) {
|
|
667
|
-
const rootOverrides = this.compositionService.getRootOverrides(composition);
|
|
668
|
-
const instances = this.compositionService.findComponentInstances(
|
|
669
|
-
composition,
|
|
670
|
-
targetComponentType,
|
|
671
|
-
findOptions
|
|
672
|
-
);
|
|
673
|
-
if (instances.length === 0) {
|
|
674
|
-
continue;
|
|
675
|
-
}
|
|
676
|
-
const valuesToPropagate = {};
|
|
677
|
-
for (const param of resolvedParams) {
|
|
678
|
-
if (rootOverrides[param.id]) {
|
|
679
|
-
valuesToPropagate[param.id] = rootOverrides[param.id];
|
|
634
|
+
const resolvedRefIds = /* @__PURE__ */ new Map();
|
|
635
|
+
for (const [flattenType, instances] of flattenedByType) {
|
|
636
|
+
const refIds = [];
|
|
637
|
+
for (const inst of instances) {
|
|
638
|
+
const existingId = this.findExistingEntryBySourceItem(inst, sourceItemMap);
|
|
639
|
+
refIds.push(existingId ?? inst.determinisiticId);
|
|
680
640
|
}
|
|
641
|
+
resolvedRefIds.set(flattenType, refIds);
|
|
681
642
|
}
|
|
682
|
-
|
|
683
|
-
|
|
643
|
+
for (const [flattenType] of flattenedByType) {
|
|
644
|
+
entry.entry.fields[flattenType] = {
|
|
645
|
+
type: "contentReference",
|
|
646
|
+
value: resolvedRefIds.get(flattenType)
|
|
647
|
+
};
|
|
684
648
|
}
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
const instanceUpdates = [];
|
|
688
|
-
for (const { instance, instanceId } of instances) {
|
|
689
|
-
const instanceName = instance._id ?? instanceId;
|
|
690
|
-
this.compositionService.setInstanceParameters(instance, valuesToPropagate);
|
|
691
|
-
compositionModified = true;
|
|
692
|
-
propagatedInstances++;
|
|
693
|
-
instanceUpdates.push(
|
|
694
|
-
`${targetComponentType} "${instanceName}": ${Object.keys(valuesToPropagate).join(", ")}`
|
|
695
|
-
);
|
|
649
|
+
if (flattenComponentIds.length > 0) {
|
|
650
|
+
this.transformContentReferences(entry);
|
|
696
651
|
}
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
652
|
+
const entryId = entry.entry._id;
|
|
653
|
+
const entryFilePath = this.fileSystem.joinPath(entriesDirFull, `${entryId}.json`);
|
|
654
|
+
this.logger.action(
|
|
655
|
+
whatIf,
|
|
656
|
+
"WRITE",
|
|
657
|
+
`${entriesDir}/${entryId}.json (${compositionType}, "${this.truncate(compositionName, 50)}")`
|
|
658
|
+
);
|
|
659
|
+
if (!whatIf) {
|
|
660
|
+
await this.fileSystem.writeFile(entryFilePath, entry);
|
|
706
661
|
}
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
710
|
-
|
|
711
|
-
|
|
712
|
-
|
|
713
|
-
|
|
714
|
-
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
modifiedSource = this.componentService.removeParameter(modifiedSource, param.id, findOptions);
|
|
718
|
-
sourceComponentModified = true;
|
|
662
|
+
entriesFromCompositions++;
|
|
663
|
+
for (const [flattenType, instances] of flattenedByType) {
|
|
664
|
+
for (const inst of instances) {
|
|
665
|
+
const existingId = this.findExistingEntryBySourceItem(inst, sourceItemMap);
|
|
666
|
+
if (existingId) {
|
|
667
|
+
this.logger.info(
|
|
668
|
+
`Reusing existing entry ${existingId} for ${flattenType} (sourceItem match)`
|
|
669
|
+
);
|
|
670
|
+
entriesReused++;
|
|
671
|
+
continue;
|
|
719
672
|
}
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
const afterGroupCount = modifiedSource.parameters?.filter(
|
|
726
|
-
(p) => this.componentService.isGroupParameter(p)
|
|
727
|
-
).length ?? 0;
|
|
728
|
-
if (afterGroupCount < beforeGroupCount) {
|
|
729
|
-
const removedCount = beforeGroupCount - afterGroupCount;
|
|
673
|
+
const flatEntry = this.generateEntryFromFlattenedInstance(inst);
|
|
674
|
+
const flatEntryPath = this.fileSystem.joinPath(
|
|
675
|
+
entriesDirFull,
|
|
676
|
+
`${inst.determinisiticId}.json`
|
|
677
|
+
);
|
|
730
678
|
this.logger.action(
|
|
731
679
|
whatIf,
|
|
732
|
-
"
|
|
733
|
-
`${
|
|
680
|
+
"WRITE",
|
|
681
|
+
`${entriesDir}/${inst.determinisiticId}.json (${flattenType} from "${this.truncate(compositionName, 50)}")`
|
|
734
682
|
);
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
}
|
|
740
|
-
if (sourceComponentModified && !whatIf) {
|
|
741
|
-
await this.componentService.saveComponent(sourceFilePath, modifiedSource);
|
|
683
|
+
if (!whatIf) {
|
|
684
|
+
await this.fileSystem.writeFile(flatEntryPath, flatEntry);
|
|
685
|
+
}
|
|
686
|
+
entriesFromFlattened++;
|
|
742
687
|
}
|
|
743
688
|
}
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
|
|
753
|
-
this.logger.detail(`\u2192 Removed: ${resolvedNames.join(", ")}`);
|
|
754
|
-
if (!whatIf) {
|
|
755
|
-
await this.compositionService.saveComposition(filePath, composition);
|
|
689
|
+
}
|
|
690
|
+
if (flattenComponentIds.length > 0) {
|
|
691
|
+
for (const contentType of contentTypeMap.values()) {
|
|
692
|
+
for (const flattenType of flattenComponentIds) {
|
|
693
|
+
if (this.compareTypes(flattenType, contentType.id, strict)) {
|
|
694
|
+
continue;
|
|
695
|
+
}
|
|
696
|
+
if (missingFlattenTypes.includes(flattenType) && !foundMissingFlattenTypes.has(flattenType)) {
|
|
697
|
+
continue;
|
|
756
698
|
}
|
|
699
|
+
contentType.fields.push({
|
|
700
|
+
id: flattenType,
|
|
701
|
+
name: flattenType,
|
|
702
|
+
type: "contentReference",
|
|
703
|
+
typeConfig: {
|
|
704
|
+
isMulti: true,
|
|
705
|
+
allowedContentTypes: [flattenType]
|
|
706
|
+
},
|
|
707
|
+
localizable: false
|
|
708
|
+
});
|
|
757
709
|
}
|
|
758
710
|
}
|
|
759
711
|
}
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
769
|
-
for (const entry of entries) {
|
|
770
|
-
const exists = normalized.some(
|
|
771
|
-
(existing) => strict ? existing === entry : existing.toLowerCase() === entry.toLowerCase()
|
|
712
|
+
for (const [typeName, contentType] of contentTypeMap) {
|
|
713
|
+
const filePath = this.fileSystem.joinPath(contentTypesDirFull, `${typeName}.json`);
|
|
714
|
+
const fieldCount = contentType.fields.filter((f) => f.type !== "contentReference").length;
|
|
715
|
+
const refCount = contentType.fields.filter((f) => f.type === "contentReference").length;
|
|
716
|
+
const refInfo = refCount > 0 ? ` + ${refCount} reference(s)` : "";
|
|
717
|
+
this.logger.action(
|
|
718
|
+
whatIf,
|
|
719
|
+
"WRITE",
|
|
720
|
+
`${contentTypesDir}/${typeName}.json (${fieldCount} fields${refInfo})`
|
|
772
721
|
);
|
|
773
|
-
if (!
|
|
774
|
-
|
|
722
|
+
if (!whatIf) {
|
|
723
|
+
await this.fileSystem.writeFile(filePath, contentType);
|
|
775
724
|
}
|
|
725
|
+
contentTypesWritten++;
|
|
776
726
|
}
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
compareIds(id1, id2, strict) {
|
|
789
|
-
if (strict) {
|
|
790
|
-
return id1 === id2;
|
|
727
|
+
for (const [typeName, contentType] of flattenContentTypeMap) {
|
|
728
|
+
const filePath = this.fileSystem.joinPath(contentTypesDirFull, `${typeName}.json`);
|
|
729
|
+
this.logger.action(
|
|
730
|
+
whatIf,
|
|
731
|
+
"WRITE",
|
|
732
|
+
`${contentTypesDir}/${typeName}.json (${contentType.fields.length} fields)`
|
|
733
|
+
);
|
|
734
|
+
if (!whatIf) {
|
|
735
|
+
await this.fileSystem.writeFile(filePath, contentType);
|
|
736
|
+
}
|
|
737
|
+
contentTypesWritten++;
|
|
791
738
|
}
|
|
792
|
-
|
|
739
|
+
const neverFoundMissingTypes = missingFlattenTypes.filter(
|
|
740
|
+
(type) => !foundMissingFlattenTypes.has(type)
|
|
741
|
+
);
|
|
742
|
+
if (neverFoundMissingTypes.length > 0) {
|
|
743
|
+
this.logger.warn(
|
|
744
|
+
`Flatten component type(s) not found in any composition: ${neverFoundMissingTypes.join(", ")}`
|
|
745
|
+
);
|
|
746
|
+
}
|
|
747
|
+
return { contentTypesWritten, entriesFromCompositions, entriesFromFlattened, entriesReused };
|
|
793
748
|
}
|
|
794
|
-
|
|
795
|
-
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
800
|
-
|
|
801
|
-
componentType,
|
|
802
|
-
slotId,
|
|
803
|
-
newSlotId,
|
|
804
|
-
newSlotName,
|
|
805
|
-
whatIf,
|
|
806
|
-
strict
|
|
807
|
-
} = options;
|
|
808
|
-
const findOptions = { strict };
|
|
809
|
-
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
810
|
-
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
811
|
-
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
812
|
-
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
813
|
-
if (this.compareIds(slotId, newSlotId, strict)) {
|
|
814
|
-
throw new TransformError("New slot ID is the same as the current slot ID");
|
|
749
|
+
// --- Content Type Generation ---
|
|
750
|
+
generateContentType(component) {
|
|
751
|
+
const fields = [];
|
|
752
|
+
if (component.parameters) {
|
|
753
|
+
for (const param of component.parameters) {
|
|
754
|
+
fields.push(this.parameterToField(param));
|
|
755
|
+
}
|
|
815
756
|
}
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
757
|
+
return {
|
|
758
|
+
id: component.id,
|
|
759
|
+
name: component.name,
|
|
760
|
+
fields
|
|
761
|
+
};
|
|
762
|
+
}
|
|
763
|
+
parameterToField(param) {
|
|
764
|
+
const field = {
|
|
765
|
+
id: param.id,
|
|
766
|
+
name: param.name,
|
|
767
|
+
type: param.type
|
|
768
|
+
};
|
|
769
|
+
if (param.helpText !== void 0) {
|
|
770
|
+
field.helpText = param.helpText;
|
|
820
771
|
}
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
);
|
|
824
|
-
if (slotIndex === -1) {
|
|
825
|
-
throw new SlotNotFoundError(slotId, componentType);
|
|
772
|
+
if (param.localizable !== void 0) {
|
|
773
|
+
field.localizable = param.localizable;
|
|
826
774
|
}
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
);
|
|
830
|
-
if (existingNewSlot) {
|
|
831
|
-
throw new SlotAlreadyExistsError(newSlotId, componentType);
|
|
775
|
+
if (param.typeConfig !== void 0) {
|
|
776
|
+
field.typeConfig = param.typeConfig;
|
|
832
777
|
}
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
778
|
+
return field;
|
|
779
|
+
}
|
|
780
|
+
// --- Entry Generation ---
|
|
781
|
+
generateEntryFromComposition(composition) {
|
|
782
|
+
const comp = composition.composition;
|
|
783
|
+
const compositionSpecificKeys = /* @__PURE__ */ new Set(["_id", "_name", "type", "parameters", "slots", "_overrides"]);
|
|
784
|
+
const extraRootProps = {};
|
|
785
|
+
for (const [key, value] of Object.entries(comp)) {
|
|
786
|
+
if (!compositionSpecificKeys.has(key) && value != null) {
|
|
787
|
+
extraRootProps[key] = value;
|
|
788
|
+
}
|
|
841
789
|
}
|
|
842
|
-
|
|
843
|
-
|
|
790
|
+
const wrapperKeys = /* @__PURE__ */ new Set(["composition"]);
|
|
791
|
+
const extraWrapperProps = {};
|
|
792
|
+
for (const [key, value] of Object.entries(composition)) {
|
|
793
|
+
if (!wrapperKeys.has(key) && value != null) {
|
|
794
|
+
extraWrapperProps[key] = value;
|
|
795
|
+
}
|
|
844
796
|
}
|
|
845
|
-
const
|
|
846
|
-
|
|
847
|
-
componentType,
|
|
848
|
-
slotId,
|
|
849
|
-
newSlotId,
|
|
850
|
-
whatIf,
|
|
851
|
-
strict,
|
|
852
|
-
"composition"
|
|
853
|
-
);
|
|
854
|
-
const compositionPatternsResult = await this.renameSlotInDirectory(
|
|
855
|
-
fullCompositionPatternsDir,
|
|
856
|
-
componentType,
|
|
857
|
-
slotId,
|
|
858
|
-
newSlotId,
|
|
859
|
-
whatIf,
|
|
860
|
-
strict,
|
|
861
|
-
"compositionPattern"
|
|
862
|
-
);
|
|
863
|
-
const componentPatternsResult = await this.renameSlotInDirectory(
|
|
864
|
-
fullComponentPatternsDir,
|
|
865
|
-
componentType,
|
|
866
|
-
slotId,
|
|
867
|
-
newSlotId,
|
|
868
|
-
whatIf,
|
|
869
|
-
strict,
|
|
870
|
-
"componentPattern"
|
|
871
|
-
);
|
|
872
|
-
const totalFiles = compositionsResult.filesModified + compositionPatternsResult.filesModified + componentPatternsResult.filesModified;
|
|
873
|
-
const totalInstances = compositionsResult.instancesRenamed + compositionPatternsResult.instancesRenamed + componentPatternsResult.instancesRenamed;
|
|
874
|
-
this.logger.info("");
|
|
875
|
-
this.logger.info(
|
|
876
|
-
`Summary: 1 component definition, ${totalFiles} file(s) (${totalInstances} instance(s)) updated.`
|
|
877
|
-
);
|
|
797
|
+
const entryId = computeGuidHash(`entry${comp._id}`);
|
|
798
|
+
const entryName = this.truncateName(comp._name ?? comp._id, 60);
|
|
878
799
|
return {
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
800
|
+
entry: {
|
|
801
|
+
_id: entryId,
|
|
802
|
+
_name: entryName,
|
|
803
|
+
type: comp.type,
|
|
804
|
+
fields: { ...comp.parameters ?? {} },
|
|
805
|
+
...extraRootProps
|
|
806
|
+
},
|
|
807
|
+
...extraWrapperProps
|
|
884
808
|
};
|
|
885
809
|
}
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
let instancesRenamed = 0;
|
|
898
|
-
for (const filePath of files) {
|
|
899
|
-
let composition;
|
|
900
|
-
try {
|
|
901
|
-
composition = await this.fileSystem.readFile(filePath);
|
|
902
|
-
} catch {
|
|
903
|
-
continue;
|
|
904
|
-
}
|
|
905
|
-
if (!composition?.composition) {
|
|
906
|
-
continue;
|
|
810
|
+
generateEntryFromFlattenedInstance(inst) {
|
|
811
|
+
const entryName = this.truncateName(
|
|
812
|
+
`${inst.componentType} (from ${inst.compositionName})`,
|
|
813
|
+
60
|
|
814
|
+
);
|
|
815
|
+
return {
|
|
816
|
+
entry: {
|
|
817
|
+
_id: inst.determinisiticId,
|
|
818
|
+
_name: entryName,
|
|
819
|
+
type: inst.componentType,
|
|
820
|
+
fields: { ...inst.instance.parameters ?? {} }
|
|
907
821
|
}
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
)
|
|
922
|
-
|
|
923
|
-
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
// --- Flatten Tree Walking ---
|
|
825
|
+
findFlattenTargets(slots, targetType, compositionId, compositionName, strict) {
|
|
826
|
+
const results = [];
|
|
827
|
+
this.walkSlots(slots, targetType, compositionId, compositionName, "", results, strict);
|
|
828
|
+
return results;
|
|
829
|
+
}
|
|
830
|
+
walkSlots(slots, targetType, compositionId, compositionName, pathPrefix, results, strict) {
|
|
831
|
+
for (const [slotName, instances] of Object.entries(slots)) {
|
|
832
|
+
if (!Array.isArray(instances)) continue;
|
|
833
|
+
for (let i = 0; i < instances.length; i++) {
|
|
834
|
+
const instance = instances[i];
|
|
835
|
+
if (instance._pattern) {
|
|
836
|
+
continue;
|
|
837
|
+
}
|
|
838
|
+
const currentPath = pathPrefix ? `${pathPrefix}-${slotName}-[${i}]-${instance.type}` : `${slotName}-[${i}]-${instance.type}`;
|
|
839
|
+
if (this.compareTypes(instance.type, targetType, strict)) {
|
|
840
|
+
const fullPath = `${compositionId}-${currentPath}`;
|
|
841
|
+
const deterministicId = computeGuidHash(fullPath);
|
|
842
|
+
results.push({
|
|
843
|
+
instance,
|
|
844
|
+
path: fullPath,
|
|
845
|
+
determinisiticId: deterministicId,
|
|
846
|
+
componentType: instance.type,
|
|
847
|
+
compositionId,
|
|
848
|
+
compositionName
|
|
849
|
+
});
|
|
850
|
+
}
|
|
851
|
+
if (instance.slots) {
|
|
852
|
+
this.walkSlots(
|
|
853
|
+
instance.slots,
|
|
854
|
+
targetType,
|
|
855
|
+
compositionId,
|
|
856
|
+
compositionName,
|
|
857
|
+
currentPath,
|
|
858
|
+
results,
|
|
859
|
+
strict
|
|
860
|
+
);
|
|
924
861
|
}
|
|
925
|
-
filesModified++;
|
|
926
|
-
instancesRenamed += count;
|
|
927
862
|
}
|
|
928
863
|
}
|
|
929
|
-
return { filesModified, instancesRenamed };
|
|
930
864
|
}
|
|
931
|
-
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
if (
|
|
936
|
-
|
|
937
|
-
|
|
865
|
+
// --- Content Reference Transformation ---
|
|
866
|
+
transformContentReferences(entry) {
|
|
867
|
+
const dataResources = {};
|
|
868
|
+
for (const [fieldName, field] of Object.entries(entry.entry.fields)) {
|
|
869
|
+
if (field.type === "contentReference" && Array.isArray(field.value)) {
|
|
870
|
+
const entryIds = field.value;
|
|
871
|
+
const resourceKey = `ref-${entry.entry._id}-${fieldName}`;
|
|
872
|
+
field.value = `\${#jptr:/${resourceKey}/entries}`;
|
|
873
|
+
dataResources[resourceKey] = {
|
|
874
|
+
type: "uniformContentInternalReference",
|
|
875
|
+
variables: {
|
|
876
|
+
locale: "${locale}",
|
|
877
|
+
entryIds: entryIds.join(",")
|
|
878
|
+
}
|
|
879
|
+
};
|
|
938
880
|
}
|
|
939
881
|
}
|
|
940
|
-
if (
|
|
941
|
-
|
|
942
|
-
|
|
943
|
-
|
|
944
|
-
|
|
882
|
+
if (Object.keys(dataResources).length > 0) {
|
|
883
|
+
entry.entry._dataResources = {
|
|
884
|
+
...entry.entry._dataResources ?? {},
|
|
885
|
+
...dataResources
|
|
886
|
+
};
|
|
887
|
+
}
|
|
888
|
+
}
|
|
889
|
+
// --- Source Item Matching ---
|
|
890
|
+
async buildSourceItemMap(entriesDirFull) {
|
|
891
|
+
const sourceItemMap = /* @__PURE__ */ new Map();
|
|
892
|
+
const entryFiles = await this.fileSystem.findFiles(entriesDirFull, "*.json");
|
|
893
|
+
for (const filePath of entryFiles) {
|
|
894
|
+
try {
|
|
895
|
+
const entryData = await this.fileSystem.readFile(filePath);
|
|
896
|
+
const sourceItemField = entryData?.entry?.fields?.sourceItem;
|
|
897
|
+
if (sourceItemField?.value != null) {
|
|
898
|
+
sourceItemMap.set(String(sourceItemField.value), entryData.entry._id);
|
|
945
899
|
}
|
|
900
|
+
} catch {
|
|
901
|
+
continue;
|
|
946
902
|
}
|
|
947
903
|
}
|
|
948
|
-
return
|
|
904
|
+
return sourceItemMap;
|
|
949
905
|
}
|
|
950
|
-
|
|
951
|
-
const
|
|
952
|
-
|
|
953
|
-
|
|
954
|
-
if (!matchingKey) {
|
|
955
|
-
return { renamed: false, slots };
|
|
906
|
+
findExistingEntryBySourceItem(inst, sourceItemMap) {
|
|
907
|
+
const sourceItemParam = inst.instance.parameters?.sourceItem;
|
|
908
|
+
if (sourceItemParam?.value == null) {
|
|
909
|
+
return void 0;
|
|
956
910
|
}
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
911
|
+
return sourceItemMap.get(String(sourceItemParam.value));
|
|
912
|
+
}
|
|
913
|
+
// --- Utilities ---
|
|
914
|
+
compareTypes(type1, type2, strict) {
|
|
915
|
+
if (strict) {
|
|
916
|
+
return type1 === type2;
|
|
917
|
+
}
|
|
918
|
+
return type1.toLowerCase() === type2.toLowerCase();
|
|
919
|
+
}
|
|
920
|
+
truncate(str, maxLength) {
|
|
921
|
+
if (str.length <= maxLength) return str;
|
|
922
|
+
return str.substring(0, maxLength - 3) + "...";
|
|
923
|
+
}
|
|
924
|
+
truncateName(name, maxLength) {
|
|
925
|
+
if (name.length <= maxLength) return name;
|
|
926
|
+
return name.substring(0, maxLength);
|
|
927
|
+
}
|
|
928
|
+
};
|
|
929
|
+
function computeGuidHash(guidOrSeed) {
|
|
930
|
+
let uuidStr;
|
|
931
|
+
if (isValidUuid(guidOrSeed)) {
|
|
932
|
+
uuidStr = formatAsBracedUuid(guidOrSeed);
|
|
933
|
+
} else {
|
|
934
|
+
const hash = crypto.createHash("md5").update(guidOrSeed, "utf-8").digest();
|
|
935
|
+
const hex = [
|
|
936
|
+
// First 4 bytes: little-endian in .NET Guid
|
|
937
|
+
hash[3].toString(16).padStart(2, "0"),
|
|
938
|
+
hash[2].toString(16).padStart(2, "0"),
|
|
939
|
+
hash[1].toString(16).padStart(2, "0"),
|
|
940
|
+
hash[0].toString(16).padStart(2, "0"),
|
|
941
|
+
"-",
|
|
942
|
+
// Bytes 4-5: little-endian
|
|
943
|
+
hash[5].toString(16).padStart(2, "0"),
|
|
944
|
+
hash[4].toString(16).padStart(2, "0"),
|
|
945
|
+
"-",
|
|
946
|
+
// Bytes 6-7: little-endian
|
|
947
|
+
hash[7].toString(16).padStart(2, "0"),
|
|
948
|
+
hash[6].toString(16).padStart(2, "0"),
|
|
949
|
+
"-",
|
|
950
|
+
// Bytes 8-9: big-endian
|
|
951
|
+
hash[8].toString(16).padStart(2, "0"),
|
|
952
|
+
hash[9].toString(16).padStart(2, "0"),
|
|
953
|
+
"-",
|
|
954
|
+
// Bytes 10-15: big-endian
|
|
955
|
+
hash[10].toString(16).padStart(2, "0"),
|
|
956
|
+
hash[11].toString(16).padStart(2, "0"),
|
|
957
|
+
hash[12].toString(16).padStart(2, "0"),
|
|
958
|
+
hash[13].toString(16).padStart(2, "0"),
|
|
959
|
+
hash[14].toString(16).padStart(2, "0"),
|
|
960
|
+
hash[15].toString(16).padStart(2, "0")
|
|
961
|
+
].join("");
|
|
962
|
+
uuidStr = `{${hex}}`.toUpperCase();
|
|
963
|
+
}
|
|
964
|
+
const chars = uuidStr.split("");
|
|
965
|
+
chars[15] = "4";
|
|
966
|
+
const arr20 = ["8", "9", "A", "B"];
|
|
967
|
+
const hexVal = parseInt(chars[20], 16);
|
|
968
|
+
chars[20] = arr20[hexVal % 4];
|
|
969
|
+
return chars.join("").slice(1, -1).toLowerCase();
|
|
970
|
+
}
|
|
971
|
+
function isValidUuid(str) {
|
|
972
|
+
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
|
|
973
|
+
}
|
|
974
|
+
function formatAsBracedUuid(uuid) {
|
|
975
|
+
const clean = uuid.replace(/[{}]/g, "").toUpperCase();
|
|
976
|
+
return `{${clean}}`;
|
|
977
|
+
}
|
|
978
|
+
|
|
979
|
+
// src/core/services/id-regenerator.ts
|
|
980
|
+
var UUID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
981
|
+
function regenerateIds(value, basePath) {
|
|
982
|
+
return walkAndRegenerate(value, basePath);
|
|
983
|
+
}
|
|
984
|
+
function walkAndRegenerate(value, currentPath) {
|
|
985
|
+
if (value === null || value === void 0) {
|
|
986
|
+
return value;
|
|
987
|
+
}
|
|
988
|
+
if (Array.isArray(value)) {
|
|
989
|
+
return value.map((item, index) => walkAndRegenerate(item, `${currentPath}[${index}]`));
|
|
990
|
+
}
|
|
991
|
+
if (typeof value === "object") {
|
|
992
|
+
const obj = value;
|
|
993
|
+
const result = {};
|
|
994
|
+
for (const [key, val] of Object.entries(obj)) {
|
|
995
|
+
const childPath = `${currentPath}.${key}`;
|
|
996
|
+
if (key === "_id" && typeof val === "string" && UUID_PATTERN.test(val)) {
|
|
997
|
+
result[key] = computeGuidHash(val + childPath);
|
|
961
998
|
} else {
|
|
962
|
-
|
|
999
|
+
result[key] = walkAndRegenerate(val, childPath);
|
|
963
1000
|
}
|
|
964
1001
|
}
|
|
965
|
-
return
|
|
1002
|
+
return result;
|
|
966
1003
|
}
|
|
967
|
-
|
|
1004
|
+
return value;
|
|
1005
|
+
}
|
|
968
1006
|
|
|
969
|
-
// src/core/services/
|
|
970
|
-
var
|
|
971
|
-
constructor(fileSystem, componentService, logger) {
|
|
1007
|
+
// src/core/services/property-propagator.service.ts
|
|
1008
|
+
var PropertyPropagatorService = class {
|
|
1009
|
+
constructor(fileSystem, componentService, compositionService, logger) {
|
|
972
1010
|
this.fileSystem = fileSystem;
|
|
973
1011
|
this.componentService = componentService;
|
|
1012
|
+
this.compositionService = compositionService;
|
|
974
1013
|
this.logger = logger;
|
|
975
1014
|
}
|
|
976
|
-
|
|
977
|
-
if (strict) {
|
|
978
|
-
return id1 === id2;
|
|
979
|
-
}
|
|
980
|
-
return id1.toLowerCase() === id2.toLowerCase();
|
|
981
|
-
}
|
|
982
|
-
async rename(options) {
|
|
1015
|
+
async propagate(options) {
|
|
983
1016
|
const {
|
|
984
1017
|
rootDir,
|
|
985
1018
|
componentsDir,
|
|
986
1019
|
compositionsDir,
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
newComponentName,
|
|
1020
|
+
compositionType,
|
|
1021
|
+
property,
|
|
1022
|
+
targetComponentType,
|
|
1023
|
+
targetGroup,
|
|
992
1024
|
whatIf,
|
|
993
|
-
strict
|
|
1025
|
+
strict,
|
|
1026
|
+
deleteSourceParameter
|
|
994
1027
|
} = options;
|
|
1028
|
+
const findOptions = { strict };
|
|
1029
|
+
const compositionTypes = this.parsePipeSeparatedValues(compositionType, strict);
|
|
995
1030
|
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
996
1031
|
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
997
|
-
const
|
|
998
|
-
const
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1032
|
+
const sourceComponents = [];
|
|
1033
|
+
for (const sourceType of compositionTypes) {
|
|
1034
|
+
this.logger.info(`Loading component: ${sourceType}`);
|
|
1035
|
+
const { component: sourceComponent, filePath: sourceFilePath } = await this.componentService.loadComponent(fullComponentsDir, sourceType, findOptions);
|
|
1036
|
+
sourceComponents.push({ sourceType, sourceFilePath, sourceComponent });
|
|
1002
1037
|
}
|
|
1003
|
-
this.logger.info(`Loading component: ${
|
|
1004
|
-
const { component, filePath:
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1038
|
+
this.logger.info(`Loading component: ${targetComponentType}`);
|
|
1039
|
+
const { component: targetComponent, filePath: targetFilePath } = await this.componentService.loadComponent(fullComponentsDir, targetComponentType, findOptions);
|
|
1040
|
+
const propertyNames = property.split("|").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
1041
|
+
const resolvedParams = [];
|
|
1042
|
+
const resolvedNames = [];
|
|
1043
|
+
for (const { sourceType, sourceComponent } of sourceComponents) {
|
|
1044
|
+
const { parameters: sourceParams, notFound } = this.componentService.resolveProperties(
|
|
1045
|
+
sourceComponent,
|
|
1046
|
+
propertyNames,
|
|
1047
|
+
findOptions
|
|
1048
|
+
);
|
|
1049
|
+
if (notFound.length > 0) {
|
|
1050
|
+
this.logger.warn(`Property "${notFound.join(", ")}" not found on component "${sourceType}"`);
|
|
1051
|
+
continue;
|
|
1052
|
+
}
|
|
1053
|
+
for (const param of sourceParams) {
|
|
1054
|
+
const exists = resolvedParams.some(
|
|
1055
|
+
(existing) => strict ? existing.id === param.id : existing.id.toLowerCase() === param.id.toLowerCase()
|
|
1056
|
+
);
|
|
1057
|
+
if (!exists) {
|
|
1058
|
+
resolvedParams.push(param);
|
|
1059
|
+
resolvedNames.push(param.id);
|
|
1060
|
+
}
|
|
1012
1061
|
}
|
|
1013
1062
|
}
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
}
|
|
1026
|
-
if (!whatIf) {
|
|
1027
|
-
await this.componentService.saveComponent(componentFilePath, component);
|
|
1063
|
+
const groupSources = [];
|
|
1064
|
+
for (const { sourceType, sourceComponent } of sourceComponents) {
|
|
1065
|
+
for (const name of propertyNames) {
|
|
1066
|
+
const param = this.componentService.findParameter(sourceComponent, name, findOptions);
|
|
1067
|
+
if (param && this.componentService.isGroupParameter(param)) {
|
|
1068
|
+
const groupSource = `${sourceType}.${name}`;
|
|
1069
|
+
if (!groupSources.includes(groupSource)) {
|
|
1070
|
+
groupSources.push(groupSource);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
}
|
|
1028
1074
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
let fileRenamed = false;
|
|
1033
|
-
if (componentFilePath !== newFilePath) {
|
|
1034
|
-
this.logger.action(
|
|
1035
|
-
whatIf,
|
|
1036
|
-
"RENAME",
|
|
1037
|
-
`component/${this.fileSystem.getBasename(componentFilePath)} \u2192 component/${this.fileSystem.getBasename(newFilePath)}`
|
|
1075
|
+
if (groupSources.length > 0) {
|
|
1076
|
+
this.logger.info(
|
|
1077
|
+
`Resolved properties: ${resolvedNames.join(", ")} (from ${groupSources.join(", ")})`
|
|
1038
1078
|
);
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
}
|
|
1042
|
-
fileRenamed = true;
|
|
1079
|
+
} else {
|
|
1080
|
+
this.logger.info(`Resolved properties: ${resolvedNames.join(", ")}`);
|
|
1043
1081
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1046
|
-
|
|
1047
|
-
|
|
1048
|
-
|
|
1049
|
-
|
|
1050
|
-
|
|
1051
|
-
);
|
|
1052
|
-
const compositionsResult = await this.renameTypeInDirectory(
|
|
1053
|
-
fullCompositionsDir,
|
|
1054
|
-
componentType,
|
|
1055
|
-
newComponentType,
|
|
1056
|
-
whatIf,
|
|
1057
|
-
strict,
|
|
1058
|
-
"composition"
|
|
1059
|
-
);
|
|
1060
|
-
const compositionPatternsResult = await this.renameTypeInDirectory(
|
|
1061
|
-
fullCompositionPatternsDir,
|
|
1062
|
-
componentType,
|
|
1063
|
-
newComponentType,
|
|
1064
|
-
whatIf,
|
|
1065
|
-
strict,
|
|
1066
|
-
"compositionPattern"
|
|
1067
|
-
);
|
|
1068
|
-
const componentPatternsResult = await this.renameTypeInDirectory(
|
|
1069
|
-
fullComponentPatternsDir,
|
|
1070
|
-
componentType,
|
|
1071
|
-
newComponentType,
|
|
1072
|
-
whatIf,
|
|
1073
|
-
strict,
|
|
1074
|
-
"componentPattern"
|
|
1075
|
-
);
|
|
1076
|
-
const totalCompositionFiles = compositionsResult.filesModified + compositionPatternsResult.filesModified + componentPatternsResult.filesModified;
|
|
1077
|
-
const totalInstances = compositionsResult.instancesRenamed + compositionPatternsResult.instancesRenamed + componentPatternsResult.instancesRenamed;
|
|
1078
|
-
this.logger.info("");
|
|
1079
|
-
this.logger.info(
|
|
1080
|
-
`Summary: 1 component renamed, ${allowedComponentsUpdated} component(s) with allowedComponents updated, ${totalCompositionFiles} composition file(s) (${totalInstances} instance(s)) updated.`
|
|
1082
|
+
let modifiedComponent = { ...targetComponent };
|
|
1083
|
+
let componentModified = false;
|
|
1084
|
+
const groupId = this.componentService.generateGroupId(targetGroup);
|
|
1085
|
+
const existingGroup = this.componentService.findParameter(
|
|
1086
|
+
modifiedComponent,
|
|
1087
|
+
groupId,
|
|
1088
|
+
findOptions
|
|
1081
1089
|
);
|
|
1082
|
-
|
|
1083
|
-
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
}
|
|
1092
|
-
async updateAllowedComponents(componentsDir, oldType, newType, sourceFilePath, whatIf, strict) {
|
|
1093
|
-
let files;
|
|
1094
|
-
try {
|
|
1095
|
-
files = await this.fileSystem.findFiles(componentsDir, "*.{json,yaml,yml}");
|
|
1096
|
-
} catch {
|
|
1097
|
-
return 0;
|
|
1090
|
+
if (!existingGroup) {
|
|
1091
|
+
this.logger.action(whatIf, "CREATE", `Group "${targetGroup}" on ${targetComponentType}`);
|
|
1092
|
+
modifiedComponent = this.componentService.ensureGroupExists(
|
|
1093
|
+
modifiedComponent,
|
|
1094
|
+
groupId,
|
|
1095
|
+
targetGroup,
|
|
1096
|
+
findOptions
|
|
1097
|
+
);
|
|
1098
|
+
componentModified = true;
|
|
1098
1099
|
}
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
continue;
|
|
1107
|
-
}
|
|
1108
|
-
if (!comp.slots || comp.slots.length === 0) continue;
|
|
1109
|
-
let fileModified = false;
|
|
1110
|
-
for (const slot of comp.slots) {
|
|
1111
|
-
if (!slot.allowedComponents) continue;
|
|
1112
|
-
for (let i = 0; i < slot.allowedComponents.length; i++) {
|
|
1113
|
-
if (this.compareIds(slot.allowedComponents[i], oldType, strict)) {
|
|
1114
|
-
slot.allowedComponents[i] = newType;
|
|
1115
|
-
fileModified = true;
|
|
1116
|
-
}
|
|
1117
|
-
}
|
|
1118
|
-
}
|
|
1119
|
-
if (fileModified) {
|
|
1100
|
+
for (const param of resolvedParams) {
|
|
1101
|
+
const existingParam = this.componentService.findParameter(
|
|
1102
|
+
modifiedComponent,
|
|
1103
|
+
param.id,
|
|
1104
|
+
findOptions
|
|
1105
|
+
);
|
|
1106
|
+
if (!existingParam) {
|
|
1120
1107
|
this.logger.action(
|
|
1121
1108
|
whatIf,
|
|
1122
|
-
"
|
|
1123
|
-
`
|
|
1109
|
+
"COPY",
|
|
1110
|
+
`Parameter "${param.id}" \u2192 ${targetComponentType}.${targetGroup}`
|
|
1124
1111
|
);
|
|
1125
|
-
|
|
1126
|
-
|
|
1112
|
+
modifiedComponent = this.componentService.addParameterToComponent(
|
|
1113
|
+
modifiedComponent,
|
|
1114
|
+
param,
|
|
1115
|
+
findOptions
|
|
1116
|
+
);
|
|
1117
|
+
modifiedComponent = this.componentService.addParameterToGroup(
|
|
1118
|
+
modifiedComponent,
|
|
1119
|
+
groupId,
|
|
1120
|
+
param.id,
|
|
1121
|
+
findOptions
|
|
1122
|
+
);
|
|
1123
|
+
componentModified = true;
|
|
1124
|
+
} else {
|
|
1125
|
+
this.logger.info(`Parameter "${param.id}" already exists on ${targetComponentType}`);
|
|
1126
|
+
const group = this.componentService.findParameter(
|
|
1127
|
+
modifiedComponent,
|
|
1128
|
+
groupId,
|
|
1129
|
+
findOptions
|
|
1130
|
+
);
|
|
1131
|
+
if (group && this.componentService.isGroupParameter(group)) {
|
|
1132
|
+
const isInGroup = group.typeConfig?.childrenParams?.some(
|
|
1133
|
+
(id) => strict ? id === param.id : id.toLowerCase() === param.id.toLowerCase()
|
|
1134
|
+
);
|
|
1135
|
+
if (!isInGroup) {
|
|
1136
|
+
modifiedComponent = this.componentService.addParameterToGroup(
|
|
1137
|
+
modifiedComponent,
|
|
1138
|
+
groupId,
|
|
1139
|
+
param.id,
|
|
1140
|
+
findOptions
|
|
1141
|
+
);
|
|
1142
|
+
componentModified = true;
|
|
1143
|
+
}
|
|
1127
1144
|
}
|
|
1128
|
-
updatedCount++;
|
|
1129
1145
|
}
|
|
1130
1146
|
}
|
|
1131
|
-
|
|
1132
|
-
|
|
1133
|
-
async renameTypeInDirectory(directory, oldType, newType, whatIf, strict, label) {
|
|
1134
|
-
let files;
|
|
1135
|
-
try {
|
|
1136
|
-
files = await this.fileSystem.findFiles(directory, "**/*.{json,yaml,yml}");
|
|
1137
|
-
} catch {
|
|
1138
|
-
return { filesModified: 0, instancesRenamed: 0 };
|
|
1139
|
-
}
|
|
1140
|
-
if (files.length === 0) {
|
|
1141
|
-
return { filesModified: 0, instancesRenamed: 0 };
|
|
1147
|
+
if (componentModified && !whatIf) {
|
|
1148
|
+
await this.componentService.saveComponent(targetFilePath, modifiedComponent);
|
|
1142
1149
|
}
|
|
1143
|
-
|
|
1144
|
-
|
|
1145
|
-
|
|
1146
|
-
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1150
|
+
const compositions = await this.compositionService.findCompositionsByTypes(
|
|
1151
|
+
fullCompositionsDir,
|
|
1152
|
+
compositionTypes,
|
|
1153
|
+
findOptions
|
|
1154
|
+
);
|
|
1155
|
+
let modifiedCompositions = 0;
|
|
1156
|
+
let propagatedInstances = 0;
|
|
1157
|
+
for (const { composition, filePath } of compositions) {
|
|
1158
|
+
const rootOverrides = this.compositionService.getRootOverrides(composition);
|
|
1159
|
+
const instances = this.compositionService.findComponentInstances(
|
|
1160
|
+
composition,
|
|
1161
|
+
targetComponentType,
|
|
1162
|
+
findOptions
|
|
1163
|
+
);
|
|
1164
|
+
if (instances.length === 0) {
|
|
1165
|
+
continue;
|
|
1151
1166
|
}
|
|
1152
|
-
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
|
|
1158
|
-
|
|
1159
|
-
|
|
1167
|
+
const valuesToPropagate = {};
|
|
1168
|
+
for (const param of resolvedParams) {
|
|
1169
|
+
if (rootOverrides[param.id]) {
|
|
1170
|
+
valuesToPropagate[param.id] = rootOverrides[param.id];
|
|
1171
|
+
}
|
|
1172
|
+
}
|
|
1173
|
+
if (Object.keys(valuesToPropagate).length === 0) {
|
|
1174
|
+
continue;
|
|
1175
|
+
}
|
|
1176
|
+
let compositionModified = false;
|
|
1177
|
+
const relativePath = filePath.replace(fullCompositionsDir, "").replace(/^[/\\]/, "");
|
|
1178
|
+
const instanceUpdates = [];
|
|
1179
|
+
for (const { instance, instanceId } of instances) {
|
|
1180
|
+
const instanceName = instance._id ?? instanceId;
|
|
1181
|
+
const clonedValues = regenerateIds(valuesToPropagate, instanceName);
|
|
1182
|
+
this.compositionService.setInstanceParameters(instance, clonedValues);
|
|
1183
|
+
compositionModified = true;
|
|
1184
|
+
propagatedInstances++;
|
|
1185
|
+
instanceUpdates.push(
|
|
1186
|
+
`${targetComponentType} "${instanceName}": ${Object.keys(valuesToPropagate).join(", ")}`
|
|
1160
1187
|
);
|
|
1188
|
+
}
|
|
1189
|
+
if (compositionModified) {
|
|
1190
|
+
this.logger.action(whatIf, "UPDATE", `composition/${relativePath}`);
|
|
1191
|
+
for (const update of instanceUpdates) {
|
|
1192
|
+
this.logger.detail(`\u2192 ${update}`);
|
|
1193
|
+
}
|
|
1161
1194
|
if (!whatIf) {
|
|
1162
|
-
await this.
|
|
1195
|
+
await this.compositionService.saveComposition(filePath, composition);
|
|
1163
1196
|
}
|
|
1164
|
-
|
|
1165
|
-
instancesRenamed += count;
|
|
1197
|
+
modifiedCompositions++;
|
|
1166
1198
|
}
|
|
1167
1199
|
}
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
|
|
1176
|
-
|
|
1177
|
-
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1200
|
+
let modifiedSourceComponents = 0;
|
|
1201
|
+
if (deleteSourceParameter) {
|
|
1202
|
+
for (const { sourceType, sourceFilePath, sourceComponent } of sourceComponents) {
|
|
1203
|
+
let modifiedSource = { ...sourceComponent };
|
|
1204
|
+
let sourceComponentModified = false;
|
|
1205
|
+
for (const param of resolvedParams) {
|
|
1206
|
+
const exists = this.componentService.findParameter(modifiedSource, param.id, findOptions);
|
|
1207
|
+
if (exists) {
|
|
1208
|
+
this.logger.action(whatIf, "DELETE", `Parameter "${param.id}" from ${sourceType}`);
|
|
1209
|
+
modifiedSource = this.componentService.removeParameter(modifiedSource, param.id, findOptions);
|
|
1210
|
+
sourceComponentModified = true;
|
|
1211
|
+
}
|
|
1212
|
+
}
|
|
1213
|
+
const beforeGroupCount = modifiedSource.parameters?.filter(
|
|
1214
|
+
(p) => this.componentService.isGroupParameter(p)
|
|
1215
|
+
).length ?? 0;
|
|
1216
|
+
modifiedSource = this.componentService.removeEmptyGroups(modifiedSource);
|
|
1217
|
+
const afterGroupCount = modifiedSource.parameters?.filter(
|
|
1218
|
+
(p) => this.componentService.isGroupParameter(p)
|
|
1219
|
+
).length ?? 0;
|
|
1220
|
+
if (afterGroupCount < beforeGroupCount) {
|
|
1221
|
+
const removedCount = beforeGroupCount - afterGroupCount;
|
|
1222
|
+
this.logger.action(
|
|
1223
|
+
whatIf,
|
|
1224
|
+
"DELETE",
|
|
1225
|
+
`${removedCount} empty group(s) from ${sourceType}`
|
|
1226
|
+
);
|
|
1227
|
+
sourceComponentModified = true;
|
|
1228
|
+
}
|
|
1229
|
+
if (sourceComponentModified) {
|
|
1230
|
+
modifiedSourceComponents++;
|
|
1231
|
+
}
|
|
1232
|
+
if (sourceComponentModified && !whatIf) {
|
|
1233
|
+
await this.componentService.saveComponent(sourceFilePath, modifiedSource);
|
|
1234
|
+
}
|
|
1235
|
+
}
|
|
1236
|
+
for (const { composition, filePath } of compositions) {
|
|
1237
|
+
const relativePath = filePath.replace(fullCompositionsDir, "").replace(/^[/\\]/, "");
|
|
1238
|
+
const deleted = this.compositionService.deleteRootOverrides(
|
|
1239
|
+
composition,
|
|
1240
|
+
resolvedNames,
|
|
1241
|
+
findOptions
|
|
1242
|
+
);
|
|
1243
|
+
if (deleted) {
|
|
1244
|
+
this.logger.action(whatIf, "DELETE", `Root overrides from composition/${relativePath}`);
|
|
1245
|
+
this.logger.detail(`\u2192 Removed: ${resolvedNames.join(", ")}`);
|
|
1246
|
+
if (!whatIf) {
|
|
1247
|
+
await this.compositionService.saveComposition(filePath, composition);
|
|
1248
|
+
}
|
|
1181
1249
|
}
|
|
1182
1250
|
}
|
|
1183
1251
|
}
|
|
1184
|
-
return
|
|
1252
|
+
return {
|
|
1253
|
+
modifiedComponents: (componentModified ? 1 : 0) + modifiedSourceComponents,
|
|
1254
|
+
modifiedCompositions,
|
|
1255
|
+
propagatedInstances
|
|
1256
|
+
};
|
|
1257
|
+
}
|
|
1258
|
+
parsePipeSeparatedValues(value, strict) {
|
|
1259
|
+
const entries = value.split("|").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
1260
|
+
const normalized = [];
|
|
1261
|
+
for (const entry of entries) {
|
|
1262
|
+
const exists = normalized.some(
|
|
1263
|
+
(existing) => strict ? existing === entry : existing.toLowerCase() === entry.toLowerCase()
|
|
1264
|
+
);
|
|
1265
|
+
if (!exists) {
|
|
1266
|
+
normalized.push(entry);
|
|
1267
|
+
}
|
|
1268
|
+
}
|
|
1269
|
+
return normalized;
|
|
1185
1270
|
}
|
|
1186
1271
|
};
|
|
1187
1272
|
|
|
1188
|
-
// src/core/services/
|
|
1189
|
-
|
|
1190
|
-
var ComponentAdderService = class {
|
|
1273
|
+
// src/core/services/slot-renamer.service.ts
|
|
1274
|
+
var SlotRenamerService = class {
|
|
1191
1275
|
constructor(fileSystem, componentService, logger) {
|
|
1192
1276
|
this.fileSystem = fileSystem;
|
|
1193
1277
|
this.componentService = componentService;
|
|
@@ -1199,871 +1283,862 @@ var ComponentAdderService = class {
|
|
|
1199
1283
|
}
|
|
1200
1284
|
return id1.toLowerCase() === id2.toLowerCase();
|
|
1201
1285
|
}
|
|
1202
|
-
|
|
1203
|
-
return parentComponentType.split("|").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
1204
|
-
}
|
|
1205
|
-
matchesAnyParentType(instanceType, parentTypes, strict) {
|
|
1206
|
-
return parentTypes.some((pt) => this.compareIds(instanceType, pt, strict));
|
|
1207
|
-
}
|
|
1208
|
-
parseParameters(parameterString) {
|
|
1209
|
-
const result = {};
|
|
1210
|
-
if (!parameterString) return result;
|
|
1211
|
-
const pairs = parameterString.split("|");
|
|
1212
|
-
for (const pair of pairs) {
|
|
1213
|
-
const [key, ...valueParts] = pair.split(":");
|
|
1214
|
-
if (key && valueParts.length > 0) {
|
|
1215
|
-
result[key.trim()] = valueParts.join(":").trim();
|
|
1216
|
-
}
|
|
1217
|
-
}
|
|
1218
|
-
return result;
|
|
1219
|
-
}
|
|
1220
|
-
generateId(baseName) {
|
|
1221
|
-
return `${baseName}-${randomUUID().slice(0, 8)}`;
|
|
1222
|
-
}
|
|
1223
|
-
regenerateInstanceIds(instance) {
|
|
1224
|
-
if (instance._id) {
|
|
1225
|
-
instance._id = instance._pattern ? randomUUID() : this.generateId(instance.type);
|
|
1226
|
-
}
|
|
1227
|
-
if (instance.slots) {
|
|
1228
|
-
for (const slotInstances of Object.values(instance.slots)) {
|
|
1229
|
-
if (Array.isArray(slotInstances)) {
|
|
1230
|
-
for (const nestedInstance of slotInstances) {
|
|
1231
|
-
this.regenerateInstanceIds(nestedInstance);
|
|
1232
|
-
}
|
|
1233
|
-
}
|
|
1234
|
-
}
|
|
1235
|
-
}
|
|
1236
|
-
}
|
|
1237
|
-
createComponentInstance(componentType, parameters) {
|
|
1238
|
-
const instance = {
|
|
1239
|
-
type: componentType,
|
|
1240
|
-
_id: this.generateId(componentType)
|
|
1241
|
-
};
|
|
1242
|
-
if (Object.keys(parameters).length > 0) {
|
|
1243
|
-
instance.parameters = {};
|
|
1244
|
-
for (const [key, value] of Object.entries(parameters)) {
|
|
1245
|
-
instance.parameters[key] = {
|
|
1246
|
-
type: "text",
|
|
1247
|
-
value
|
|
1248
|
-
};
|
|
1249
|
-
}
|
|
1250
|
-
}
|
|
1251
|
-
return instance;
|
|
1252
|
-
}
|
|
1253
|
-
addComponentToSlot(slots, slotId, instance) {
|
|
1254
|
-
if (!slots[slotId]) {
|
|
1255
|
-
slots[slotId] = [];
|
|
1256
|
-
}
|
|
1257
|
-
slots[slotId].push(instance);
|
|
1258
|
-
}
|
|
1259
|
-
async addComponent(options) {
|
|
1286
|
+
async rename(options) {
|
|
1260
1287
|
const {
|
|
1261
1288
|
rootDir,
|
|
1262
1289
|
componentsDir,
|
|
1263
1290
|
compositionsDir,
|
|
1264
1291
|
compositionPatternsDir,
|
|
1265
1292
|
componentPatternsDir,
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1293
|
+
componentType,
|
|
1294
|
+
slotId,
|
|
1295
|
+
newSlotId,
|
|
1296
|
+
newSlotName,
|
|
1270
1297
|
whatIf,
|
|
1271
1298
|
strict
|
|
1272
1299
|
} = options;
|
|
1273
|
-
|
|
1274
|
-
throw new TransformError("newComponentType is required for add-component");
|
|
1275
|
-
}
|
|
1300
|
+
const findOptions = { strict };
|
|
1276
1301
|
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1277
1302
|
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
1278
1303
|
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
1279
1304
|
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
if (parentTypes.length === 0) {
|
|
1283
|
-
throw new TransformError("parentComponentType cannot be empty");
|
|
1305
|
+
if (this.compareIds(slotId, newSlotId, strict)) {
|
|
1306
|
+
throw new TransformError("New slot ID is the same as the current slot ID");
|
|
1284
1307
|
}
|
|
1285
|
-
this.logger.info(`
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
if (error instanceof ComponentNotFoundError) {
|
|
1290
|
-
throw new TransformError(
|
|
1291
|
-
`Component type "${newComponentType}" not found in ${fullComponentsDir}`
|
|
1292
|
-
);
|
|
1293
|
-
}
|
|
1294
|
-
throw error;
|
|
1308
|
+
this.logger.info(`Loading component: ${componentType}`);
|
|
1309
|
+
const { component, filePath: componentFilePath } = await this.componentService.loadComponent(fullComponentsDir, componentType, findOptions);
|
|
1310
|
+
if (!component.slots || component.slots.length === 0) {
|
|
1311
|
+
throw new SlotNotFoundError(slotId, componentType);
|
|
1295
1312
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
parentComponent.slots = [];
|
|
1302
|
-
}
|
|
1303
|
-
let slotDef = parentComponent.slots.find(
|
|
1304
|
-
(s) => this.compareIds(s.id, slot, strict)
|
|
1305
|
-
);
|
|
1306
|
-
if (!slotDef) {
|
|
1307
|
-
this.logger.info(`Slot "${slot}" not found on component "${parentType}", creating it`);
|
|
1308
|
-
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
1309
|
-
parentComponent.slots.push(slotDef);
|
|
1310
|
-
}
|
|
1311
|
-
const slotIndex = parentComponent.slots?.findIndex(
|
|
1312
|
-
(s) => this.compareIds(s.id, slotDef.id, strict)
|
|
1313
|
-
);
|
|
1314
|
-
if (slotIndex !== void 0 && slotIndex >= 0) {
|
|
1315
|
-
const actualSlot = parentComponent.slots[slotIndex];
|
|
1316
|
-
if (!actualSlot.allowedComponents) {
|
|
1317
|
-
actualSlot.allowedComponents = [];
|
|
1318
|
-
}
|
|
1319
|
-
const isAlreadyAllowed = actualSlot.allowedComponents.some(
|
|
1320
|
-
(c) => this.compareIds(c, newComponentType, strict)
|
|
1321
|
-
);
|
|
1322
|
-
if (!isAlreadyAllowed) {
|
|
1323
|
-
this.logger.action(
|
|
1324
|
-
whatIf,
|
|
1325
|
-
"UPDATE",
|
|
1326
|
-
`Adding "${newComponentType}" to allowedComponents for slot "${slot}" on component "${parentType}"`
|
|
1327
|
-
);
|
|
1328
|
-
actualSlot.allowedComponents.push(newComponentType);
|
|
1329
|
-
if (!whatIf) {
|
|
1330
|
-
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
1331
|
-
}
|
|
1332
|
-
allowedComponentsUpdated = true;
|
|
1333
|
-
}
|
|
1334
|
-
}
|
|
1313
|
+
const slotIndex = component.slots.findIndex(
|
|
1314
|
+
(s) => this.compareIds(s.id, slotId, strict)
|
|
1315
|
+
);
|
|
1316
|
+
if (slotIndex === -1) {
|
|
1317
|
+
throw new SlotNotFoundError(slotId, componentType);
|
|
1335
1318
|
}
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
1319
|
+
const existingNewSlot = component.slots.find(
|
|
1320
|
+
(s) => this.compareIds(s.id, newSlotId, strict)
|
|
1321
|
+
);
|
|
1322
|
+
if (existingNewSlot) {
|
|
1323
|
+
throw new SlotAlreadyExistsError(newSlotId, componentType);
|
|
1324
|
+
}
|
|
1325
|
+
this.logger.action(
|
|
1326
|
+
whatIf,
|
|
1327
|
+
"UPDATE",
|
|
1328
|
+
`Slot "${slotId}" \u2192 "${newSlotId}" in component/${this.fileSystem.getBasename(componentFilePath)}`
|
|
1329
|
+
);
|
|
1330
|
+
component.slots[slotIndex].id = newSlotId;
|
|
1331
|
+
if (newSlotName !== void 0) {
|
|
1332
|
+
component.slots[slotIndex].name = newSlotName;
|
|
1333
|
+
}
|
|
1334
|
+
if (!whatIf) {
|
|
1335
|
+
await this.componentService.saveComponent(componentFilePath, component);
|
|
1336
|
+
}
|
|
1337
|
+
const compositionsResult = await this.renameSlotInDirectory(
|
|
1339
1338
|
fullCompositionsDir,
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1339
|
+
componentType,
|
|
1340
|
+
slotId,
|
|
1341
|
+
newSlotId,
|
|
1343
1342
|
whatIf,
|
|
1344
1343
|
strict,
|
|
1345
1344
|
"composition"
|
|
1346
1345
|
);
|
|
1347
|
-
const compositionPatternsResult = await this.
|
|
1346
|
+
const compositionPatternsResult = await this.renameSlotInDirectory(
|
|
1348
1347
|
fullCompositionPatternsDir,
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1348
|
+
componentType,
|
|
1349
|
+
slotId,
|
|
1350
|
+
newSlotId,
|
|
1352
1351
|
whatIf,
|
|
1353
1352
|
strict,
|
|
1354
1353
|
"compositionPattern"
|
|
1355
1354
|
);
|
|
1356
|
-
const componentPatternsResult = await this.
|
|
1355
|
+
const componentPatternsResult = await this.renameSlotInDirectory(
|
|
1357
1356
|
fullComponentPatternsDir,
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1357
|
+
componentType,
|
|
1358
|
+
slotId,
|
|
1359
|
+
newSlotId,
|
|
1361
1360
|
whatIf,
|
|
1362
1361
|
strict,
|
|
1363
1362
|
"componentPattern"
|
|
1364
1363
|
);
|
|
1364
|
+
const totalFiles = compositionsResult.filesModified + compositionPatternsResult.filesModified + componentPatternsResult.filesModified;
|
|
1365
|
+
const totalInstances = compositionsResult.instancesRenamed + compositionPatternsResult.instancesRenamed + componentPatternsResult.instancesRenamed;
|
|
1365
1366
|
this.logger.info("");
|
|
1366
1367
|
this.logger.info(
|
|
1367
|
-
`Summary:
|
|
1368
|
+
`Summary: 1 component definition, ${totalFiles} file(s) (${totalInstances} instance(s)) updated.`
|
|
1368
1369
|
);
|
|
1369
1370
|
return {
|
|
1370
|
-
|
|
1371
|
-
compositionsModified: compositionsResult,
|
|
1372
|
-
compositionPatternsModified: compositionPatternsResult,
|
|
1373
|
-
componentPatternsModified: componentPatternsResult,
|
|
1374
|
-
|
|
1371
|
+
componentDefinitionUpdated: true,
|
|
1372
|
+
compositionsModified: compositionsResult.filesModified,
|
|
1373
|
+
compositionPatternsModified: compositionPatternsResult.filesModified,
|
|
1374
|
+
componentPatternsModified: componentPatternsResult.filesModified,
|
|
1375
|
+
instancesRenamed: totalInstances
|
|
1375
1376
|
};
|
|
1376
1377
|
}
|
|
1377
|
-
async
|
|
1378
|
+
async renameSlotInDirectory(directory, componentType, oldSlotId, newSlotId, whatIf, strict, label) {
|
|
1379
|
+
let files;
|
|
1380
|
+
try {
|
|
1381
|
+
files = await this.fileSystem.findFiles(directory, "**/*.{json,yaml,yml}");
|
|
1382
|
+
} catch {
|
|
1383
|
+
return { filesModified: 0, instancesRenamed: 0 };
|
|
1384
|
+
}
|
|
1385
|
+
if (files.length === 0) {
|
|
1386
|
+
return { filesModified: 0, instancesRenamed: 0 };
|
|
1387
|
+
}
|
|
1388
|
+
let filesModified = 0;
|
|
1389
|
+
let instancesRenamed = 0;
|
|
1390
|
+
for (const filePath of files) {
|
|
1391
|
+
let composition;
|
|
1392
|
+
try {
|
|
1393
|
+
composition = await this.fileSystem.readFile(filePath);
|
|
1394
|
+
} catch {
|
|
1395
|
+
continue;
|
|
1396
|
+
}
|
|
1397
|
+
if (!composition?.composition) {
|
|
1398
|
+
continue;
|
|
1399
|
+
}
|
|
1400
|
+
const count = this.renameSlotInTree(
|
|
1401
|
+
composition.composition,
|
|
1402
|
+
componentType,
|
|
1403
|
+
oldSlotId,
|
|
1404
|
+
newSlotId,
|
|
1405
|
+
strict
|
|
1406
|
+
);
|
|
1407
|
+
if (count > 0) {
|
|
1408
|
+
const relativePath = filePath.replace(directory, "").replace(/^[/\\]/, "");
|
|
1409
|
+
this.logger.action(
|
|
1410
|
+
whatIf,
|
|
1411
|
+
"UPDATE",
|
|
1412
|
+
`${label}/${relativePath} (${count} instance(s) of ${componentType})`
|
|
1413
|
+
);
|
|
1414
|
+
if (!whatIf) {
|
|
1415
|
+
await this.fileSystem.writeFile(filePath, composition);
|
|
1416
|
+
}
|
|
1417
|
+
filesModified++;
|
|
1418
|
+
instancesRenamed += count;
|
|
1419
|
+
}
|
|
1420
|
+
}
|
|
1421
|
+
return { filesModified, instancesRenamed };
|
|
1422
|
+
}
|
|
1423
|
+
renameSlotInTree(node, componentType, oldSlotId, newSlotId, strict) {
|
|
1424
|
+
let count = 0;
|
|
1425
|
+
if (this.compareIds(node.type, componentType, strict) && node.slots) {
|
|
1426
|
+
const result = this.renameSlotKey(node.slots, oldSlotId, newSlotId, strict);
|
|
1427
|
+
if (result.renamed) {
|
|
1428
|
+
node.slots = result.slots;
|
|
1429
|
+
count++;
|
|
1430
|
+
}
|
|
1431
|
+
}
|
|
1432
|
+
if (node.slots) {
|
|
1433
|
+
for (const slotInstances of Object.values(node.slots)) {
|
|
1434
|
+
if (!Array.isArray(slotInstances)) continue;
|
|
1435
|
+
for (const instance of slotInstances) {
|
|
1436
|
+
count += this.renameSlotInTree(instance, componentType, oldSlotId, newSlotId, strict);
|
|
1437
|
+
}
|
|
1438
|
+
}
|
|
1439
|
+
}
|
|
1440
|
+
return count;
|
|
1441
|
+
}
|
|
1442
|
+
renameSlotKey(slots, oldSlotId, newSlotId, strict) {
|
|
1443
|
+
const matchingKey = Object.keys(slots).find(
|
|
1444
|
+
(key) => this.compareIds(key, oldSlotId, strict)
|
|
1445
|
+
);
|
|
1446
|
+
if (!matchingKey) {
|
|
1447
|
+
return { renamed: false, slots };
|
|
1448
|
+
}
|
|
1449
|
+
const newSlots = {};
|
|
1450
|
+
for (const key of Object.keys(slots)) {
|
|
1451
|
+
if (key === matchingKey) {
|
|
1452
|
+
newSlots[newSlotId] = slots[key];
|
|
1453
|
+
} else {
|
|
1454
|
+
newSlots[key] = slots[key];
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
return { renamed: true, slots: newSlots };
|
|
1458
|
+
}
|
|
1459
|
+
};
|
|
1460
|
+
|
|
1461
|
+
// src/core/services/component-renamer.service.ts
|
|
1462
|
+
var ComponentRenamerService = class {
|
|
1463
|
+
constructor(fileSystem, componentService, logger) {
|
|
1464
|
+
this.fileSystem = fileSystem;
|
|
1465
|
+
this.componentService = componentService;
|
|
1466
|
+
this.logger = logger;
|
|
1467
|
+
}
|
|
1468
|
+
compareIds(id1, id2, strict) {
|
|
1469
|
+
if (strict) {
|
|
1470
|
+
return id1 === id2;
|
|
1471
|
+
}
|
|
1472
|
+
return id1.toLowerCase() === id2.toLowerCase();
|
|
1473
|
+
}
|
|
1474
|
+
async rename(options) {
|
|
1378
1475
|
const {
|
|
1379
1476
|
rootDir,
|
|
1380
1477
|
componentsDir,
|
|
1381
1478
|
compositionsDir,
|
|
1382
1479
|
compositionPatternsDir,
|
|
1383
1480
|
componentPatternsDir,
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1481
|
+
componentType,
|
|
1482
|
+
newComponentType,
|
|
1483
|
+
newComponentName,
|
|
1387
1484
|
whatIf,
|
|
1388
1485
|
strict
|
|
1389
1486
|
} = options;
|
|
1390
|
-
if (!componentPatternId) {
|
|
1391
|
-
throw new TransformError("componentPatternId is required for add-component-pattern");
|
|
1392
|
-
}
|
|
1393
1487
|
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1394
1488
|
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
1395
1489
|
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
1396
1490
|
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
1397
1491
|
const findOptions = { strict };
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
throw new TransformError("parentComponentType cannot be empty");
|
|
1492
|
+
if (this.compareIds(componentType, newComponentType, strict)) {
|
|
1493
|
+
throw new TransformError("New component type is the same as the current component type");
|
|
1401
1494
|
}
|
|
1402
|
-
this.logger.info(`Loading component
|
|
1403
|
-
const
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1495
|
+
this.logger.info(`Loading component: ${componentType}`);
|
|
1496
|
+
const { component, filePath: componentFilePath } = await this.componentService.loadComponent(fullComponentsDir, componentType, findOptions);
|
|
1497
|
+
let targetExists = false;
|
|
1498
|
+
try {
|
|
1499
|
+
await this.componentService.loadComponent(fullComponentsDir, newComponentType, findOptions);
|
|
1500
|
+
targetExists = true;
|
|
1501
|
+
} catch (error) {
|
|
1502
|
+
if (!(error instanceof ComponentNotFoundError)) {
|
|
1503
|
+
throw error;
|
|
1504
|
+
}
|
|
1505
|
+
}
|
|
1506
|
+
if (targetExists) {
|
|
1507
|
+
throw new ComponentAlreadyExistsError(newComponentType, fullComponentsDir);
|
|
1508
|
+
}
|
|
1509
|
+
this.logger.action(
|
|
1510
|
+
whatIf,
|
|
1511
|
+
"UPDATE",
|
|
1512
|
+
`Component ID "${componentType}" \u2192 "${newComponentType}" in component/${this.fileSystem.getBasename(componentFilePath)}`
|
|
1407
1513
|
);
|
|
1408
|
-
|
|
1409
|
-
if (
|
|
1410
|
-
|
|
1411
|
-
`Component pattern "${componentPatternId}" has no valid definition or missing type`
|
|
1412
|
-
);
|
|
1514
|
+
component.id = newComponentType;
|
|
1515
|
+
if (newComponentName !== void 0) {
|
|
1516
|
+
component.name = newComponentName;
|
|
1413
1517
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1518
|
+
if (!whatIf) {
|
|
1519
|
+
await this.componentService.saveComponent(componentFilePath, component);
|
|
1520
|
+
}
|
|
1521
|
+
const ext = this.fileSystem.getExtension(componentFilePath);
|
|
1522
|
+
const dir = this.fileSystem.getDirname(componentFilePath);
|
|
1523
|
+
const newFilePath = this.fileSystem.joinPath(dir, `${newComponentType}${ext}`);
|
|
1524
|
+
let fileRenamed = false;
|
|
1525
|
+
if (componentFilePath !== newFilePath) {
|
|
1526
|
+
this.logger.action(
|
|
1527
|
+
whatIf,
|
|
1528
|
+
"RENAME",
|
|
1529
|
+
`component/${this.fileSystem.getBasename(componentFilePath)} \u2192 component/${this.fileSystem.getBasename(newFilePath)}`
|
|
1424
1530
|
);
|
|
1425
|
-
if (!
|
|
1426
|
-
this.
|
|
1427
|
-
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
1428
|
-
parentComponent.slots.push(slotDef);
|
|
1429
|
-
}
|
|
1430
|
-
const slotIndex = parentComponent.slots?.findIndex(
|
|
1431
|
-
(s) => this.compareIds(s.id, slotDef.id, strict)
|
|
1432
|
-
);
|
|
1433
|
-
if (slotIndex !== void 0 && slotIndex >= 0) {
|
|
1434
|
-
const actualSlot = parentComponent.slots[slotIndex];
|
|
1435
|
-
if (!actualSlot.allowedComponents) {
|
|
1436
|
-
actualSlot.allowedComponents = [];
|
|
1437
|
-
}
|
|
1438
|
-
const isAlreadyAllowed = actualSlot.allowedComponents.some(
|
|
1439
|
-
(c) => this.compareIds(c, componentTypeInPattern, strict)
|
|
1440
|
-
);
|
|
1441
|
-
if (!isAlreadyAllowed) {
|
|
1442
|
-
this.logger.action(
|
|
1443
|
-
whatIf,
|
|
1444
|
-
"UPDATE",
|
|
1445
|
-
`Adding "${componentTypeInPattern}" to allowedComponents for slot "${slot}" on component "${parentType}"`
|
|
1446
|
-
);
|
|
1447
|
-
actualSlot.allowedComponents.push(componentTypeInPattern);
|
|
1448
|
-
if (!whatIf) {
|
|
1449
|
-
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
1450
|
-
}
|
|
1451
|
-
allowedComponentsUpdated = true;
|
|
1452
|
-
}
|
|
1531
|
+
if (!whatIf) {
|
|
1532
|
+
await this.fileSystem.renameFile(componentFilePath, newFilePath);
|
|
1453
1533
|
}
|
|
1534
|
+
fileRenamed = true;
|
|
1454
1535
|
}
|
|
1455
|
-
const
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1536
|
+
const allowedComponentsUpdated = await this.updateAllowedComponents(
|
|
1537
|
+
fullComponentsDir,
|
|
1538
|
+
componentType,
|
|
1539
|
+
newComponentType,
|
|
1540
|
+
componentFilePath,
|
|
1541
|
+
whatIf,
|
|
1542
|
+
strict
|
|
1543
|
+
);
|
|
1544
|
+
const compositionsResult = await this.renameTypeInDirectory(
|
|
1461
1545
|
fullCompositionsDir,
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
newInstance,
|
|
1546
|
+
componentType,
|
|
1547
|
+
newComponentType,
|
|
1465
1548
|
whatIf,
|
|
1466
1549
|
strict,
|
|
1467
1550
|
"composition"
|
|
1468
1551
|
);
|
|
1469
|
-
const compositionPatternsResult = await this.
|
|
1552
|
+
const compositionPatternsResult = await this.renameTypeInDirectory(
|
|
1470
1553
|
fullCompositionPatternsDir,
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
newInstance,
|
|
1554
|
+
componentType,
|
|
1555
|
+
newComponentType,
|
|
1474
1556
|
whatIf,
|
|
1475
1557
|
strict,
|
|
1476
1558
|
"compositionPattern"
|
|
1477
1559
|
);
|
|
1478
|
-
const componentPatternsResult = await this.
|
|
1560
|
+
const componentPatternsResult = await this.renameTypeInDirectory(
|
|
1479
1561
|
fullComponentPatternsDir,
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
newInstance,
|
|
1562
|
+
componentType,
|
|
1563
|
+
newComponentType,
|
|
1483
1564
|
whatIf,
|
|
1484
1565
|
strict,
|
|
1485
1566
|
"componentPattern"
|
|
1486
1567
|
);
|
|
1568
|
+
const totalCompositionFiles = compositionsResult.filesModified + compositionPatternsResult.filesModified + componentPatternsResult.filesModified;
|
|
1569
|
+
const totalInstances = compositionsResult.instancesRenamed + compositionPatternsResult.instancesRenamed + componentPatternsResult.instancesRenamed;
|
|
1487
1570
|
this.logger.info("");
|
|
1488
1571
|
this.logger.info(
|
|
1489
|
-
`Summary:
|
|
1572
|
+
`Summary: 1 component renamed, ${allowedComponentsUpdated} component(s) with allowedComponents updated, ${totalCompositionFiles} composition file(s) (${totalInstances} instance(s)) updated.`
|
|
1490
1573
|
);
|
|
1491
1574
|
return {
|
|
1575
|
+
componentRenamed: true,
|
|
1576
|
+
fileRenamed,
|
|
1492
1577
|
allowedComponentsUpdated,
|
|
1493
|
-
compositionsModified: compositionsResult,
|
|
1494
|
-
compositionPatternsModified: compositionPatternsResult,
|
|
1495
|
-
componentPatternsModified: componentPatternsResult,
|
|
1496
|
-
|
|
1578
|
+
compositionsModified: compositionsResult.filesModified,
|
|
1579
|
+
compositionPatternsModified: compositionPatternsResult.filesModified,
|
|
1580
|
+
componentPatternsModified: componentPatternsResult.filesModified,
|
|
1581
|
+
instancesRenamed: totalInstances
|
|
1497
1582
|
};
|
|
1498
1583
|
}
|
|
1499
|
-
async
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
raw = await this.fileSystem.readFile(jsonPath);
|
|
1506
|
-
} else if (await this.fileSystem.fileExists(yamlPath)) {
|
|
1507
|
-
raw = await this.fileSystem.readFile(yamlPath);
|
|
1508
|
-
} else if (await this.fileSystem.fileExists(ymlPath)) {
|
|
1509
|
-
raw = await this.fileSystem.readFile(ymlPath);
|
|
1584
|
+
async updateAllowedComponents(componentsDir, oldType, newType, sourceFilePath, whatIf, strict) {
|
|
1585
|
+
let files;
|
|
1586
|
+
try {
|
|
1587
|
+
files = await this.fileSystem.findFiles(componentsDir, "*.{json,yaml,yml}");
|
|
1588
|
+
} catch {
|
|
1589
|
+
return 0;
|
|
1510
1590
|
}
|
|
1511
|
-
|
|
1512
|
-
|
|
1513
|
-
|
|
1514
|
-
|
|
1515
|
-
|
|
1516
|
-
|
|
1517
|
-
|
|
1518
|
-
|
|
1591
|
+
let updatedCount = 0;
|
|
1592
|
+
for (const filePath of files) {
|
|
1593
|
+
if (filePath === sourceFilePath) continue;
|
|
1594
|
+
let comp;
|
|
1595
|
+
try {
|
|
1596
|
+
comp = await this.fileSystem.readFile(filePath);
|
|
1597
|
+
} catch {
|
|
1598
|
+
continue;
|
|
1599
|
+
}
|
|
1600
|
+
if (!comp.slots || comp.slots.length === 0) continue;
|
|
1601
|
+
let fileModified = false;
|
|
1602
|
+
for (const slot of comp.slots) {
|
|
1603
|
+
if (!slot.allowedComponents) continue;
|
|
1604
|
+
for (let i = 0; i < slot.allowedComponents.length; i++) {
|
|
1605
|
+
if (this.compareIds(slot.allowedComponents[i], oldType, strict)) {
|
|
1606
|
+
slot.allowedComponents[i] = newType;
|
|
1607
|
+
fileModified = true;
|
|
1608
|
+
}
|
|
1519
1609
|
}
|
|
1520
1610
|
}
|
|
1611
|
+
if (fileModified) {
|
|
1612
|
+
this.logger.action(
|
|
1613
|
+
whatIf,
|
|
1614
|
+
"UPDATE",
|
|
1615
|
+
`allowedComponents in component/${this.fileSystem.getBasename(filePath)}: ${oldType} \u2192 ${newType}`
|
|
1616
|
+
);
|
|
1617
|
+
if (!whatIf) {
|
|
1618
|
+
await this.fileSystem.writeFile(filePath, comp);
|
|
1619
|
+
}
|
|
1620
|
+
updatedCount++;
|
|
1621
|
+
}
|
|
1521
1622
|
}
|
|
1522
|
-
|
|
1523
|
-
throw new TransformError(`Component pattern "${patternId}" not found in ${componentPatternsDir}`);
|
|
1524
|
-
}
|
|
1525
|
-
return this.normalizeComponentPattern(raw, patternId);
|
|
1623
|
+
return updatedCount;
|
|
1526
1624
|
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
return {
|
|
1534
|
-
componentPatternId: patternId,
|
|
1535
|
-
definition: composition
|
|
1536
|
-
};
|
|
1625
|
+
async renameTypeInDirectory(directory, oldType, newType, whatIf, strict, label) {
|
|
1626
|
+
let files;
|
|
1627
|
+
try {
|
|
1628
|
+
files = await this.fileSystem.findFiles(directory, "**/*.{json,yaml,yml}");
|
|
1629
|
+
} catch {
|
|
1630
|
+
return { filesModified: 0, instancesRenamed: 0 };
|
|
1537
1631
|
}
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
async addComponentToDirectory(directory, parentTypes, slot, newInstance, whatIf, strict, dirType) {
|
|
1541
|
-
const exists = await this.fileSystem.fileExists(directory);
|
|
1542
|
-
if (!exists) {
|
|
1543
|
-
this.logger.detail(`${dirType} directory does not exist, skipping`);
|
|
1544
|
-
return 0;
|
|
1632
|
+
if (files.length === 0) {
|
|
1633
|
+
return { filesModified: 0, instancesRenamed: 0 };
|
|
1545
1634
|
}
|
|
1546
|
-
const files = await this.fileSystem.findFiles(directory, "**/*.{json,yaml,yml}");
|
|
1547
1635
|
let filesModified = 0;
|
|
1636
|
+
let instancesRenamed = 0;
|
|
1548
1637
|
for (const filePath of files) {
|
|
1638
|
+
let composition;
|
|
1549
1639
|
try {
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
} else {
|
|
1566
|
-
composition = content;
|
|
1567
|
-
}
|
|
1568
|
-
if (!composition?.composition) {
|
|
1569
|
-
continue;
|
|
1570
|
-
}
|
|
1571
|
-
const rootInstance = composition.composition;
|
|
1572
|
-
let modified = false;
|
|
1573
|
-
if (this.matchesAnyParentType(rootInstance.type, parentTypes, strict)) {
|
|
1574
|
-
if (!rootInstance.slots) {
|
|
1575
|
-
rootInstance.slots = {};
|
|
1576
|
-
}
|
|
1577
|
-
const instanceCopy = JSON.parse(JSON.stringify(newInstance));
|
|
1578
|
-
this.regenerateInstanceIds(instanceCopy);
|
|
1579
|
-
this.addComponentToSlot(rootInstance.slots, slot, instanceCopy);
|
|
1580
|
-
modified = true;
|
|
1581
|
-
}
|
|
1582
|
-
if (rootInstance.slots) {
|
|
1583
|
-
const nestedModified = this.addComponentToNestedSlots(
|
|
1584
|
-
rootInstance.slots,
|
|
1585
|
-
parentTypes,
|
|
1586
|
-
slot,
|
|
1587
|
-
newInstance,
|
|
1588
|
-
strict
|
|
1589
|
-
);
|
|
1590
|
-
if (nestedModified) {
|
|
1591
|
-
modified = true;
|
|
1592
|
-
}
|
|
1593
|
-
}
|
|
1594
|
-
if (modified) {
|
|
1595
|
-
this.logger.action(
|
|
1596
|
-
whatIf,
|
|
1597
|
-
"UPDATE",
|
|
1598
|
-
`Adding "${newInstance.type}" to slot "${slot}" in ${dirType}/${this.fileSystem.getBasename(filePath)}`
|
|
1599
|
-
);
|
|
1600
|
-
if (!whatIf) {
|
|
1601
|
-
if (isComponentPattern && content && typeof content === "object" && "definition" in content) {
|
|
1602
|
-
const pattern = content;
|
|
1603
|
-
if (rootInstance.slots) {
|
|
1604
|
-
pattern.definition.slots = rootInstance.slots;
|
|
1605
|
-
}
|
|
1606
|
-
}
|
|
1607
|
-
await this.fileSystem.writeFile(filePath, content);
|
|
1608
|
-
}
|
|
1609
|
-
filesModified++;
|
|
1640
|
+
composition = await this.fileSystem.readFile(filePath);
|
|
1641
|
+
} catch {
|
|
1642
|
+
continue;
|
|
1643
|
+
}
|
|
1644
|
+
if (!composition?.composition) continue;
|
|
1645
|
+
const count = this.renameTypeInTree(composition.composition, oldType, newType, strict);
|
|
1646
|
+
if (count > 0) {
|
|
1647
|
+
const relativePath = filePath.replace(directory, "").replace(/^[/\\]/, "");
|
|
1648
|
+
this.logger.action(
|
|
1649
|
+
whatIf,
|
|
1650
|
+
"UPDATE",
|
|
1651
|
+
`${label}/${relativePath} (${count} instance(s))`
|
|
1652
|
+
);
|
|
1653
|
+
if (!whatIf) {
|
|
1654
|
+
await this.fileSystem.writeFile(filePath, composition);
|
|
1610
1655
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1656
|
+
filesModified++;
|
|
1657
|
+
instancesRenamed += count;
|
|
1658
|
+
}
|
|
1659
|
+
}
|
|
1660
|
+
return { filesModified, instancesRenamed };
|
|
1661
|
+
}
|
|
1662
|
+
renameTypeInTree(node, oldType, newType, strict) {
|
|
1663
|
+
let count = 0;
|
|
1664
|
+
if (this.compareIds(node.type, oldType, strict)) {
|
|
1665
|
+
node.type = newType;
|
|
1666
|
+
count++;
|
|
1667
|
+
}
|
|
1668
|
+
if (node.slots) {
|
|
1669
|
+
for (const slotInstances of Object.values(node.slots)) {
|
|
1670
|
+
if (!Array.isArray(slotInstances)) continue;
|
|
1671
|
+
for (const instance of slotInstances) {
|
|
1672
|
+
count += this.renameTypeInTree(instance, oldType, newType, strict);
|
|
1614
1673
|
}
|
|
1615
1674
|
}
|
|
1616
1675
|
}
|
|
1617
|
-
return
|
|
1618
|
-
}
|
|
1619
|
-
addComponentToNestedSlots(slots, parentTypes, slot, newInstance, strict) {
|
|
1620
|
-
let modified = false;
|
|
1621
|
-
for (const slotInstances of Object.values(slots)) {
|
|
1622
|
-
if (!Array.isArray(slotInstances)) continue;
|
|
1623
|
-
for (const instance of slotInstances) {
|
|
1624
|
-
if (this.matchesAnyParentType(instance.type, parentTypes, strict)) {
|
|
1625
|
-
if (!instance.slots) {
|
|
1626
|
-
instance.slots = {};
|
|
1627
|
-
}
|
|
1628
|
-
const instanceCopy = JSON.parse(JSON.stringify(newInstance));
|
|
1629
|
-
this.regenerateInstanceIds(instanceCopy);
|
|
1630
|
-
this.addComponentToSlot(instance.slots, slot, instanceCopy);
|
|
1631
|
-
modified = true;
|
|
1632
|
-
}
|
|
1633
|
-
if (instance.slots) {
|
|
1634
|
-
const nestedModified = this.addComponentToNestedSlots(
|
|
1635
|
-
instance.slots,
|
|
1636
|
-
parentTypes,
|
|
1637
|
-
slot,
|
|
1638
|
-
newInstance,
|
|
1639
|
-
strict
|
|
1640
|
-
);
|
|
1641
|
-
if (nestedModified) {
|
|
1642
|
-
modified = true;
|
|
1643
|
-
}
|
|
1644
|
-
}
|
|
1645
|
-
}
|
|
1646
|
-
}
|
|
1647
|
-
return modified;
|
|
1676
|
+
return count;
|
|
1648
1677
|
}
|
|
1649
1678
|
};
|
|
1650
1679
|
|
|
1651
|
-
// src/core/services/
|
|
1652
|
-
import
|
|
1653
|
-
var
|
|
1654
|
-
constructor(fileSystem, componentService,
|
|
1680
|
+
// src/core/services/component-adder.service.ts
|
|
1681
|
+
import { randomUUID } from "crypto";
|
|
1682
|
+
var ComponentAdderService = class {
|
|
1683
|
+
constructor(fileSystem, componentService, logger) {
|
|
1655
1684
|
this.fileSystem = fileSystem;
|
|
1656
1685
|
this.componentService = componentService;
|
|
1657
|
-
this.compositionService = compositionService;
|
|
1658
1686
|
this.logger = logger;
|
|
1659
1687
|
}
|
|
1660
|
-
|
|
1688
|
+
compareIds(id1, id2, strict) {
|
|
1689
|
+
if (strict) {
|
|
1690
|
+
return id1 === id2;
|
|
1691
|
+
}
|
|
1692
|
+
return id1.toLowerCase() === id2.toLowerCase();
|
|
1693
|
+
}
|
|
1694
|
+
parseParentComponentTypes(parentComponentType) {
|
|
1695
|
+
return parentComponentType.split("|").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
1696
|
+
}
|
|
1697
|
+
matchesAnyParentType(instanceType, parentTypes, strict) {
|
|
1698
|
+
return parentTypes.some((pt) => this.compareIds(instanceType, pt, strict));
|
|
1699
|
+
}
|
|
1700
|
+
parseParameters(parameterString) {
|
|
1701
|
+
const result = {};
|
|
1702
|
+
if (!parameterString) return result;
|
|
1703
|
+
const pairs = parameterString.split("|");
|
|
1704
|
+
for (const pair of pairs) {
|
|
1705
|
+
const [key, ...valueParts] = pair.split(":");
|
|
1706
|
+
if (key && valueParts.length > 0) {
|
|
1707
|
+
result[key.trim()] = valueParts.join(":").trim();
|
|
1708
|
+
}
|
|
1709
|
+
}
|
|
1710
|
+
return result;
|
|
1711
|
+
}
|
|
1712
|
+
generateId(baseName) {
|
|
1713
|
+
return `${baseName}-${randomUUID().slice(0, 8)}`;
|
|
1714
|
+
}
|
|
1715
|
+
regenerateInstanceIds(instance) {
|
|
1716
|
+
if (instance._id) {
|
|
1717
|
+
instance._id = instance._pattern ? randomUUID() : this.generateId(instance.type);
|
|
1718
|
+
}
|
|
1719
|
+
if (instance.slots) {
|
|
1720
|
+
for (const slotInstances of Object.values(instance.slots)) {
|
|
1721
|
+
if (Array.isArray(slotInstances)) {
|
|
1722
|
+
for (const nestedInstance of slotInstances) {
|
|
1723
|
+
this.regenerateInstanceIds(nestedInstance);
|
|
1724
|
+
}
|
|
1725
|
+
}
|
|
1726
|
+
}
|
|
1727
|
+
}
|
|
1728
|
+
}
|
|
1729
|
+
createComponentInstance(componentType, parameters) {
|
|
1730
|
+
const instance = {
|
|
1731
|
+
type: componentType,
|
|
1732
|
+
_id: this.generateId(componentType)
|
|
1733
|
+
};
|
|
1734
|
+
if (Object.keys(parameters).length > 0) {
|
|
1735
|
+
instance.parameters = {};
|
|
1736
|
+
for (const [key, value] of Object.entries(parameters)) {
|
|
1737
|
+
instance.parameters[key] = {
|
|
1738
|
+
type: "text",
|
|
1739
|
+
value
|
|
1740
|
+
};
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
return instance;
|
|
1744
|
+
}
|
|
1745
|
+
addComponentToSlot(slots, slotId, instance) {
|
|
1746
|
+
if (!slots[slotId]) {
|
|
1747
|
+
slots[slotId] = [];
|
|
1748
|
+
}
|
|
1749
|
+
slots[slotId].push(instance);
|
|
1750
|
+
}
|
|
1751
|
+
async addComponent(options) {
|
|
1661
1752
|
const {
|
|
1662
1753
|
rootDir,
|
|
1663
|
-
compositionsDir,
|
|
1664
1754
|
componentsDir,
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1755
|
+
compositionsDir,
|
|
1756
|
+
compositionPatternsDir,
|
|
1757
|
+
componentPatternsDir,
|
|
1758
|
+
parentComponentType,
|
|
1759
|
+
slot,
|
|
1760
|
+
newComponentType,
|
|
1761
|
+
parameters: paramString,
|
|
1669
1762
|
whatIf,
|
|
1670
1763
|
strict
|
|
1671
1764
|
} = options;
|
|
1672
|
-
|
|
1673
|
-
|
|
1674
|
-
const contentTypesDirFull = this.fileSystem.resolvePath(rootDir, contentTypesDir);
|
|
1675
|
-
const entriesDirFull = this.fileSystem.resolvePath(rootDir, entriesDir);
|
|
1676
|
-
let contentTypesWritten = 0;
|
|
1677
|
-
let entriesFromCompositions = 0;
|
|
1678
|
-
let entriesFromFlattened = 0;
|
|
1679
|
-
this.logger.info(`Composition types: ${compositionTypes.join(", ")}`);
|
|
1680
|
-
if (flattenComponentIds.length > 0) {
|
|
1681
|
-
this.logger.info(`Flatten component types: ${flattenComponentIds.join(", ")}`);
|
|
1682
|
-
}
|
|
1683
|
-
const compositionResults = await this.compositionService.findCompositionsByTypes(
|
|
1684
|
-
compositionsDirFull,
|
|
1685
|
-
compositionTypes,
|
|
1686
|
-
{ strict }
|
|
1687
|
-
);
|
|
1688
|
-
if (compositionResults.length === 0) {
|
|
1689
|
-
this.logger.warn("No compositions found matching the specified types");
|
|
1690
|
-
return { contentTypesWritten: 0, entriesFromCompositions: 0, entriesFromFlattened: 0 };
|
|
1765
|
+
if (!newComponentType) {
|
|
1766
|
+
throw new TransformError("newComponentType is required for add-component");
|
|
1691
1767
|
}
|
|
1692
|
-
this.
|
|
1693
|
-
const
|
|
1694
|
-
|
|
1695
|
-
|
|
1768
|
+
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1769
|
+
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
1770
|
+
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
1771
|
+
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
1772
|
+
const findOptions = { strict };
|
|
1773
|
+
const parentTypes = this.parseParentComponentTypes(parentComponentType);
|
|
1774
|
+
if (parentTypes.length === 0) {
|
|
1775
|
+
throw new TransformError("parentComponentType cannot be empty");
|
|
1696
1776
|
}
|
|
1697
|
-
|
|
1698
|
-
|
|
1699
|
-
|
|
1700
|
-
|
|
1701
|
-
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1777
|
+
this.logger.info(`Validating new component: ${newComponentType}`);
|
|
1778
|
+
try {
|
|
1779
|
+
await this.componentService.loadComponent(fullComponentsDir, newComponentType, findOptions);
|
|
1780
|
+
} catch (error) {
|
|
1781
|
+
if (error instanceof ComponentNotFoundError) {
|
|
1782
|
+
throw new TransformError(
|
|
1783
|
+
`Component type "${newComponentType}" not found in ${fullComponentsDir}`
|
|
1784
|
+
);
|
|
1785
|
+
}
|
|
1786
|
+
throw error;
|
|
1706
1787
|
}
|
|
1707
|
-
|
|
1708
|
-
const
|
|
1709
|
-
|
|
1710
|
-
|
|
1711
|
-
|
|
1712
|
-
|
|
1788
|
+
let allowedComponentsUpdated = false;
|
|
1789
|
+
for (const parentType of parentTypes) {
|
|
1790
|
+
this.logger.info(`Loading parent component: ${parentType}`);
|
|
1791
|
+
const { component: parentComponent, filePath: parentComponentFilePath } = await this.componentService.loadComponent(fullComponentsDir, parentType, findOptions);
|
|
1792
|
+
if (!parentComponent.slots) {
|
|
1793
|
+
parentComponent.slots = [];
|
|
1794
|
+
}
|
|
1795
|
+
let slotDef = parentComponent.slots.find(
|
|
1796
|
+
(s) => this.compareIds(s.id, slot, strict)
|
|
1713
1797
|
);
|
|
1714
|
-
if (
|
|
1715
|
-
|
|
1798
|
+
if (!slotDef) {
|
|
1799
|
+
this.logger.info(`Slot "${slot}" not found on component "${parentType}", creating it`);
|
|
1800
|
+
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
1801
|
+
parentComponent.slots.push(slotDef);
|
|
1716
1802
|
}
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
)
|
|
1723
|
-
|
|
1724
|
-
flattenContentTypeMap.set(flattenType, contentType);
|
|
1725
|
-
} catch (error) {
|
|
1726
|
-
if (error instanceof ComponentNotFoundError) {
|
|
1727
|
-
this.logger.info(`Flatten component type not found: ${flattenType}`);
|
|
1728
|
-
missingFlattenTypes.push(flattenType);
|
|
1729
|
-
continue;
|
|
1803
|
+
const slotIndex = parentComponent.slots?.findIndex(
|
|
1804
|
+
(s) => this.compareIds(s.id, slotDef.id, strict)
|
|
1805
|
+
);
|
|
1806
|
+
if (slotIndex !== void 0 && slotIndex >= 0) {
|
|
1807
|
+
const actualSlot = parentComponent.slots[slotIndex];
|
|
1808
|
+
if (!actualSlot.allowedComponents) {
|
|
1809
|
+
actualSlot.allowedComponents = [];
|
|
1730
1810
|
}
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
const entry = this.generateEntryFromComposition(composition);
|
|
1740
|
-
const flattenedByType = /* @__PURE__ */ new Map();
|
|
1741
|
-
if (flattenComponentIds.length > 0 && comp.slots) {
|
|
1742
|
-
for (const flattenType of flattenComponentIds) {
|
|
1743
|
-
if (this.compareTypes(flattenType, compositionType, strict)) {
|
|
1744
|
-
this.logger.warn(
|
|
1745
|
-
`Skipping flatten of "${flattenType}" \u2014 same as root component type`
|
|
1746
|
-
);
|
|
1747
|
-
continue;
|
|
1748
|
-
}
|
|
1749
|
-
const instances = this.findFlattenTargets(
|
|
1750
|
-
comp.slots,
|
|
1751
|
-
flattenType,
|
|
1752
|
-
compositionId,
|
|
1753
|
-
compositionName,
|
|
1754
|
-
strict
|
|
1811
|
+
const isAlreadyAllowed = actualSlot.allowedComponents.some(
|
|
1812
|
+
(c) => this.compareIds(c, newComponentType, strict)
|
|
1813
|
+
);
|
|
1814
|
+
if (!isAlreadyAllowed) {
|
|
1815
|
+
this.logger.action(
|
|
1816
|
+
whatIf,
|
|
1817
|
+
"UPDATE",
|
|
1818
|
+
`Adding "${newComponentType}" to allowedComponents for slot "${slot}" on component "${parentType}"`
|
|
1755
1819
|
);
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
foundMissingFlattenTypes.add(flattenType);
|
|
1760
|
-
}
|
|
1820
|
+
actualSlot.allowedComponents.push(newComponentType);
|
|
1821
|
+
if (!whatIf) {
|
|
1822
|
+
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
1761
1823
|
}
|
|
1824
|
+
allowedComponentsUpdated = true;
|
|
1762
1825
|
}
|
|
1763
1826
|
}
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1827
|
+
}
|
|
1828
|
+
const parsedParams = this.parseParameters(paramString);
|
|
1829
|
+
const newInstance = this.createComponentInstance(newComponentType, parsedParams);
|
|
1830
|
+
const compositionsResult = await this.addComponentToDirectory(
|
|
1831
|
+
fullCompositionsDir,
|
|
1832
|
+
parentTypes,
|
|
1833
|
+
slot,
|
|
1834
|
+
newInstance,
|
|
1835
|
+
whatIf,
|
|
1836
|
+
strict,
|
|
1837
|
+
"composition"
|
|
1838
|
+
);
|
|
1839
|
+
const compositionPatternsResult = await this.addComponentToDirectory(
|
|
1840
|
+
fullCompositionPatternsDir,
|
|
1841
|
+
parentTypes,
|
|
1842
|
+
slot,
|
|
1843
|
+
newInstance,
|
|
1844
|
+
whatIf,
|
|
1845
|
+
strict,
|
|
1846
|
+
"compositionPattern"
|
|
1847
|
+
);
|
|
1848
|
+
const componentPatternsResult = await this.addComponentToDirectory(
|
|
1849
|
+
fullComponentPatternsDir,
|
|
1850
|
+
parentTypes,
|
|
1851
|
+
slot,
|
|
1852
|
+
newInstance,
|
|
1853
|
+
whatIf,
|
|
1854
|
+
strict,
|
|
1855
|
+
"componentPattern"
|
|
1856
|
+
);
|
|
1857
|
+
this.logger.info("");
|
|
1858
|
+
this.logger.info(
|
|
1859
|
+
`Summary: ${allowedComponentsUpdated ? `${parentTypes.length} component definition(s) updated, ` : ""}${compositionsResult} composition(s), ${compositionPatternsResult} composition pattern(s), ${componentPatternsResult} component pattern(s) updated. ${compositionsResult + compositionPatternsResult + componentPatternsResult} instance(s) added.`
|
|
1860
|
+
);
|
|
1861
|
+
return {
|
|
1862
|
+
allowedComponentsUpdated,
|
|
1863
|
+
compositionsModified: compositionsResult,
|
|
1864
|
+
compositionPatternsModified: compositionPatternsResult,
|
|
1865
|
+
componentPatternsModified: componentPatternsResult,
|
|
1866
|
+
instancesAdded: compositionsResult + compositionPatternsResult + componentPatternsResult
|
|
1867
|
+
};
|
|
1868
|
+
}
|
|
1869
|
+
async addComponentPattern(options) {
|
|
1870
|
+
const {
|
|
1871
|
+
rootDir,
|
|
1872
|
+
componentsDir,
|
|
1873
|
+
compositionsDir,
|
|
1874
|
+
compositionPatternsDir,
|
|
1875
|
+
componentPatternsDir,
|
|
1876
|
+
parentComponentType,
|
|
1877
|
+
slot,
|
|
1878
|
+
componentPatternId,
|
|
1879
|
+
whatIf,
|
|
1880
|
+
strict
|
|
1881
|
+
} = options;
|
|
1882
|
+
if (!componentPatternId) {
|
|
1883
|
+
throw new TransformError("componentPatternId is required for add-component-pattern");
|
|
1884
|
+
}
|
|
1885
|
+
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1886
|
+
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
1887
|
+
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
1888
|
+
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
1889
|
+
const findOptions = { strict };
|
|
1890
|
+
const parentTypes = this.parseParentComponentTypes(parentComponentType);
|
|
1891
|
+
if (parentTypes.length === 0) {
|
|
1892
|
+
throw new TransformError("parentComponentType cannot be empty");
|
|
1893
|
+
}
|
|
1894
|
+
this.logger.info(`Loading component pattern: ${componentPatternId}`);
|
|
1895
|
+
const pattern = await this.loadComponentPattern(
|
|
1896
|
+
fullComponentPatternsDir,
|
|
1897
|
+
componentPatternId,
|
|
1898
|
+
strict
|
|
1899
|
+
);
|
|
1900
|
+
const patternDefinition = pattern.definition;
|
|
1901
|
+
if (!patternDefinition || !patternDefinition.type) {
|
|
1902
|
+
throw new TransformError(
|
|
1903
|
+
`Component pattern "${componentPatternId}" has no valid definition or missing type`
|
|
1904
|
+
);
|
|
1905
|
+
}
|
|
1906
|
+
const componentTypeInPattern = patternDefinition.type;
|
|
1907
|
+
let allowedComponentsUpdated = false;
|
|
1908
|
+
for (const parentType of parentTypes) {
|
|
1909
|
+
this.logger.info(`Loading parent component: ${parentType}`);
|
|
1910
|
+
const { component: parentComponent, filePath: parentComponentFilePath } = await this.componentService.loadComponent(fullComponentsDir, parentType, findOptions);
|
|
1911
|
+
if (!parentComponent.slots) {
|
|
1912
|
+
parentComponent.slots = [];
|
|
1782
1913
|
}
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
1786
|
-
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1914
|
+
let slotDef = parentComponent.slots.find(
|
|
1915
|
+
(s) => this.compareIds(s.id, slot, strict)
|
|
1916
|
+
);
|
|
1917
|
+
if (!slotDef) {
|
|
1918
|
+
this.logger.info(`Slot "${slot}" not found on component "${parentType}", creating it`);
|
|
1919
|
+
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
1920
|
+
parentComponent.slots.push(slotDef);
|
|
1921
|
+
}
|
|
1922
|
+
const slotIndex = parentComponent.slots?.findIndex(
|
|
1923
|
+
(s) => this.compareIds(s.id, slotDef.id, strict)
|
|
1924
|
+
);
|
|
1925
|
+
if (slotIndex !== void 0 && slotIndex >= 0) {
|
|
1926
|
+
const actualSlot = parentComponent.slots[slotIndex];
|
|
1927
|
+
if (!actualSlot.allowedComponents) {
|
|
1928
|
+
actualSlot.allowedComponents = [];
|
|
1929
|
+
}
|
|
1930
|
+
const isAlreadyAllowed = actualSlot.allowedComponents.some(
|
|
1931
|
+
(c) => this.compareIds(c, componentTypeInPattern, strict)
|
|
1932
|
+
);
|
|
1933
|
+
if (!isAlreadyAllowed) {
|
|
1791
1934
|
this.logger.action(
|
|
1792
1935
|
whatIf,
|
|
1793
|
-
"
|
|
1794
|
-
|
|
1936
|
+
"UPDATE",
|
|
1937
|
+
`Adding "${componentTypeInPattern}" to allowedComponents for slot "${slot}" on component "${parentType}"`
|
|
1795
1938
|
);
|
|
1939
|
+
actualSlot.allowedComponents.push(componentTypeInPattern);
|
|
1796
1940
|
if (!whatIf) {
|
|
1797
|
-
await this.
|
|
1798
|
-
}
|
|
1799
|
-
entriesFromFlattened++;
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
}
|
|
1803
|
-
if (flattenComponentIds.length > 0) {
|
|
1804
|
-
for (const contentType of contentTypeMap.values()) {
|
|
1805
|
-
for (const flattenType of flattenComponentIds) {
|
|
1806
|
-
if (this.compareTypes(flattenType, contentType.id, strict)) {
|
|
1807
|
-
continue;
|
|
1808
|
-
}
|
|
1809
|
-
if (missingFlattenTypes.includes(flattenType) && !foundMissingFlattenTypes.has(flattenType)) {
|
|
1810
|
-
continue;
|
|
1941
|
+
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
1811
1942
|
}
|
|
1812
|
-
|
|
1813
|
-
id: flattenType,
|
|
1814
|
-
name: flattenType,
|
|
1815
|
-
type: "contentReference",
|
|
1816
|
-
typeConfig: {
|
|
1817
|
-
isMulti: true,
|
|
1818
|
-
allowedContentTypes: [flattenType]
|
|
1819
|
-
},
|
|
1820
|
-
localizable: false
|
|
1821
|
-
});
|
|
1943
|
+
allowedComponentsUpdated = true;
|
|
1822
1944
|
}
|
|
1823
1945
|
}
|
|
1824
1946
|
}
|
|
1825
|
-
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1831
|
-
|
|
1832
|
-
|
|
1833
|
-
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
|
|
1840
|
-
|
|
1841
|
-
|
|
1842
|
-
|
|
1843
|
-
|
|
1844
|
-
|
|
1845
|
-
|
|
1846
|
-
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1947
|
+
const newInstance = {
|
|
1948
|
+
type: componentTypeInPattern,
|
|
1949
|
+
_pattern: pattern.componentPatternId,
|
|
1950
|
+
_id: randomUUID()
|
|
1951
|
+
};
|
|
1952
|
+
const compositionsResult = await this.addComponentToDirectory(
|
|
1953
|
+
fullCompositionsDir,
|
|
1954
|
+
parentTypes,
|
|
1955
|
+
slot,
|
|
1956
|
+
newInstance,
|
|
1957
|
+
whatIf,
|
|
1958
|
+
strict,
|
|
1959
|
+
"composition"
|
|
1960
|
+
);
|
|
1961
|
+
const compositionPatternsResult = await this.addComponentToDirectory(
|
|
1962
|
+
fullCompositionPatternsDir,
|
|
1963
|
+
parentTypes,
|
|
1964
|
+
slot,
|
|
1965
|
+
newInstance,
|
|
1966
|
+
whatIf,
|
|
1967
|
+
strict,
|
|
1968
|
+
"compositionPattern"
|
|
1969
|
+
);
|
|
1970
|
+
const componentPatternsResult = await this.addComponentToDirectory(
|
|
1971
|
+
fullComponentPatternsDir,
|
|
1972
|
+
parentTypes,
|
|
1973
|
+
slot,
|
|
1974
|
+
newInstance,
|
|
1975
|
+
whatIf,
|
|
1976
|
+
strict,
|
|
1977
|
+
"componentPattern"
|
|
1978
|
+
);
|
|
1979
|
+
this.logger.info("");
|
|
1980
|
+
this.logger.info(
|
|
1981
|
+
`Summary: ${allowedComponentsUpdated ? `${parentTypes.length} component definition(s) updated, ` : ""}${compositionsResult} composition(s), ${compositionPatternsResult} composition pattern(s), ${componentPatternsResult} component pattern(s) updated. ${compositionsResult + compositionPatternsResult + componentPatternsResult} instance(s) added.`
|
|
1854
1982
|
);
|
|
1855
|
-
if (neverFoundMissingTypes.length > 0) {
|
|
1856
|
-
this.logger.warn(
|
|
1857
|
-
`Flatten component type(s) not found in any composition: ${neverFoundMissingTypes.join(", ")}`
|
|
1858
|
-
);
|
|
1859
|
-
}
|
|
1860
|
-
return { contentTypesWritten, entriesFromCompositions, entriesFromFlattened };
|
|
1861
|
-
}
|
|
1862
|
-
// --- Content Type Generation ---
|
|
1863
|
-
generateContentType(component) {
|
|
1864
|
-
const fields = [];
|
|
1865
|
-
if (component.parameters) {
|
|
1866
|
-
for (const param of component.parameters) {
|
|
1867
|
-
fields.push(this.parameterToField(param));
|
|
1868
|
-
}
|
|
1869
|
-
}
|
|
1870
1983
|
return {
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
1876
|
-
parameterToField(param) {
|
|
1877
|
-
const field = {
|
|
1878
|
-
id: param.id,
|
|
1879
|
-
name: param.name,
|
|
1880
|
-
type: param.type
|
|
1984
|
+
allowedComponentsUpdated,
|
|
1985
|
+
compositionsModified: compositionsResult,
|
|
1986
|
+
compositionPatternsModified: compositionPatternsResult,
|
|
1987
|
+
componentPatternsModified: componentPatternsResult,
|
|
1988
|
+
instancesAdded: compositionsResult + compositionPatternsResult + componentPatternsResult
|
|
1881
1989
|
};
|
|
1882
|
-
if (param.helpText !== void 0) {
|
|
1883
|
-
field.helpText = param.helpText;
|
|
1884
|
-
}
|
|
1885
|
-
if (param.localizable !== void 0) {
|
|
1886
|
-
field.localizable = param.localizable;
|
|
1887
|
-
}
|
|
1888
|
-
if (param.typeConfig !== void 0) {
|
|
1889
|
-
field.typeConfig = param.typeConfig;
|
|
1890
|
-
}
|
|
1891
|
-
return field;
|
|
1892
1990
|
}
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
const
|
|
1896
|
-
const
|
|
1897
|
-
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1991
|
+
async loadComponentPattern(componentPatternsDir, patternId, strict) {
|
|
1992
|
+
const jsonPath = this.fileSystem.joinPath(componentPatternsDir, `${patternId}.json`);
|
|
1993
|
+
const yamlPath = this.fileSystem.joinPath(componentPatternsDir, `${patternId}.yaml`);
|
|
1994
|
+
const ymlPath = this.fileSystem.joinPath(componentPatternsDir, `${patternId}.yml`);
|
|
1995
|
+
let raw;
|
|
1996
|
+
if (await this.fileSystem.fileExists(jsonPath)) {
|
|
1997
|
+
raw = await this.fileSystem.readFile(jsonPath);
|
|
1998
|
+
} else if (await this.fileSystem.fileExists(yamlPath)) {
|
|
1999
|
+
raw = await this.fileSystem.readFile(yamlPath);
|
|
2000
|
+
} else if (await this.fileSystem.fileExists(ymlPath)) {
|
|
2001
|
+
raw = await this.fileSystem.readFile(ymlPath);
|
|
1902
2002
|
}
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1906
|
-
|
|
1907
|
-
|
|
2003
|
+
if (!raw && !strict) {
|
|
2004
|
+
const files = await this.fileSystem.findFiles(componentPatternsDir, "*.{json,yaml,yml}");
|
|
2005
|
+
for (const filePath of files) {
|
|
2006
|
+
const basename2 = this.fileSystem.getBasename(filePath);
|
|
2007
|
+
const nameWithoutExt = basename2.replace(/\.(json|yaml|yml)$/i, "");
|
|
2008
|
+
if (nameWithoutExt.toLowerCase() === patternId.toLowerCase()) {
|
|
2009
|
+
raw = await this.fileSystem.readFile(filePath);
|
|
2010
|
+
break;
|
|
2011
|
+
}
|
|
1908
2012
|
}
|
|
1909
2013
|
}
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1914
|
-
_id: entryId,
|
|
1915
|
-
_name: entryName,
|
|
1916
|
-
type: comp.type,
|
|
1917
|
-
fields: { ...comp.parameters ?? {} },
|
|
1918
|
-
...extraRootProps
|
|
1919
|
-
},
|
|
1920
|
-
...extraWrapperProps
|
|
1921
|
-
};
|
|
1922
|
-
}
|
|
1923
|
-
generateEntryFromFlattenedInstance(inst) {
|
|
1924
|
-
const entryName = this.truncateName(
|
|
1925
|
-
`${inst.componentType} (from ${inst.compositionName})`,
|
|
1926
|
-
60
|
|
1927
|
-
);
|
|
1928
|
-
return {
|
|
1929
|
-
entry: {
|
|
1930
|
-
_id: inst.determinisiticId,
|
|
1931
|
-
_name: entryName,
|
|
1932
|
-
type: inst.componentType,
|
|
1933
|
-
fields: { ...inst.instance.parameters ?? {} }
|
|
1934
|
-
}
|
|
1935
|
-
};
|
|
2014
|
+
if (!raw) {
|
|
2015
|
+
throw new TransformError(`Component pattern "${patternId}" not found in ${componentPatternsDir}`);
|
|
2016
|
+
}
|
|
2017
|
+
return this.normalizeComponentPattern(raw, patternId);
|
|
1936
2018
|
}
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
2019
|
+
normalizeComponentPattern(raw, patternId) {
|
|
2020
|
+
if (raw.definition && typeof raw.definition === "object" && raw.definition.type) {
|
|
2021
|
+
return raw;
|
|
2022
|
+
}
|
|
2023
|
+
if (raw.composition && typeof raw.composition === "object" && raw.composition.type) {
|
|
2024
|
+
const composition = raw.composition;
|
|
2025
|
+
return {
|
|
2026
|
+
componentPatternId: patternId,
|
|
2027
|
+
definition: composition
|
|
2028
|
+
};
|
|
2029
|
+
}
|
|
2030
|
+
return raw;
|
|
1942
2031
|
}
|
|
1943
|
-
|
|
1944
|
-
|
|
1945
|
-
|
|
1946
|
-
|
|
1947
|
-
|
|
1948
|
-
|
|
2032
|
+
async addComponentToDirectory(directory, parentTypes, slot, newInstance, whatIf, strict, dirType) {
|
|
2033
|
+
const exists = await this.fileSystem.fileExists(directory);
|
|
2034
|
+
if (!exists) {
|
|
2035
|
+
this.logger.detail(`${dirType} directory does not exist, skipping`);
|
|
2036
|
+
return 0;
|
|
2037
|
+
}
|
|
2038
|
+
const files = await this.fileSystem.findFiles(directory, "**/*.{json,yaml,yml}");
|
|
2039
|
+
let filesModified = 0;
|
|
2040
|
+
for (const filePath of files) {
|
|
2041
|
+
try {
|
|
2042
|
+
const content = await this.fileSystem.readFile(filePath);
|
|
2043
|
+
let composition = null;
|
|
2044
|
+
let isComponentPattern = false;
|
|
2045
|
+
if (dirType === "componentPattern" && content && typeof content === "object" && "definition" in content) {
|
|
2046
|
+
isComponentPattern = true;
|
|
2047
|
+
const pattern = content;
|
|
2048
|
+
if (pattern.definition && pattern.definition.slots) {
|
|
2049
|
+
composition = {
|
|
2050
|
+
composition: {
|
|
2051
|
+
_id: "pattern-root",
|
|
2052
|
+
type: pattern.definition.type,
|
|
2053
|
+
slots: pattern.definition.slots
|
|
2054
|
+
}
|
|
2055
|
+
};
|
|
2056
|
+
}
|
|
2057
|
+
} else {
|
|
2058
|
+
composition = content;
|
|
2059
|
+
}
|
|
2060
|
+
if (!composition?.composition) {
|
|
1949
2061
|
continue;
|
|
1950
2062
|
}
|
|
1951
|
-
const
|
|
1952
|
-
|
|
1953
|
-
|
|
1954
|
-
|
|
1955
|
-
|
|
1956
|
-
|
|
1957
|
-
|
|
1958
|
-
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
compositionName
|
|
1962
|
-
});
|
|
2063
|
+
const rootInstance = composition.composition;
|
|
2064
|
+
let modified = false;
|
|
2065
|
+
if (this.matchesAnyParentType(rootInstance.type, parentTypes, strict)) {
|
|
2066
|
+
if (!rootInstance.slots) {
|
|
2067
|
+
rootInstance.slots = {};
|
|
2068
|
+
}
|
|
2069
|
+
const instanceCopy = JSON.parse(JSON.stringify(newInstance));
|
|
2070
|
+
this.regenerateInstanceIds(instanceCopy);
|
|
2071
|
+
this.addComponentToSlot(rootInstance.slots, slot, instanceCopy);
|
|
2072
|
+
modified = true;
|
|
1963
2073
|
}
|
|
1964
|
-
if (
|
|
1965
|
-
this.
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
currentPath,
|
|
1971
|
-
results,
|
|
2074
|
+
if (rootInstance.slots) {
|
|
2075
|
+
const nestedModified = this.addComponentToNestedSlots(
|
|
2076
|
+
rootInstance.slots,
|
|
2077
|
+
parentTypes,
|
|
2078
|
+
slot,
|
|
2079
|
+
newInstance,
|
|
1972
2080
|
strict
|
|
1973
2081
|
);
|
|
2082
|
+
if (nestedModified) {
|
|
2083
|
+
modified = true;
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
if (modified) {
|
|
2087
|
+
this.logger.action(
|
|
2088
|
+
whatIf,
|
|
2089
|
+
"UPDATE",
|
|
2090
|
+
`Adding "${newInstance.type}" to slot "${slot}" in ${dirType}/${this.fileSystem.getBasename(filePath)}`
|
|
2091
|
+
);
|
|
2092
|
+
if (!whatIf) {
|
|
2093
|
+
if (isComponentPattern && content && typeof content === "object" && "definition" in content) {
|
|
2094
|
+
const pattern = content;
|
|
2095
|
+
if (rootInstance.slots) {
|
|
2096
|
+
pattern.definition.slots = rootInstance.slots;
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
2099
|
+
await this.fileSystem.writeFile(filePath, content);
|
|
2100
|
+
}
|
|
2101
|
+
filesModified++;
|
|
2102
|
+
}
|
|
2103
|
+
} catch (error) {
|
|
2104
|
+
if (error instanceof Error && !error.message.includes("skipping")) {
|
|
2105
|
+
this.logger.detail(`Skipping ${filePath}: ${error.message}`);
|
|
1974
2106
|
}
|
|
1975
2107
|
}
|
|
1976
2108
|
}
|
|
2109
|
+
return filesModified;
|
|
1977
2110
|
}
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
const
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
|
|
1984
|
-
|
|
1985
|
-
|
|
1986
|
-
dataResources[resourceKey] = {
|
|
1987
|
-
type: "uniformContentInternalReference",
|
|
1988
|
-
variables: {
|
|
1989
|
-
locale: "${locale}",
|
|
1990
|
-
entryIds: entryIds.join(",")
|
|
2111
|
+
addComponentToNestedSlots(slots, parentTypes, slot, newInstance, strict) {
|
|
2112
|
+
let modified = false;
|
|
2113
|
+
for (const slotInstances of Object.values(slots)) {
|
|
2114
|
+
if (!Array.isArray(slotInstances)) continue;
|
|
2115
|
+
for (const instance of slotInstances) {
|
|
2116
|
+
if (this.matchesAnyParentType(instance.type, parentTypes, strict)) {
|
|
2117
|
+
if (!instance.slots) {
|
|
2118
|
+
instance.slots = {};
|
|
1991
2119
|
}
|
|
1992
|
-
|
|
2120
|
+
const instanceCopy = JSON.parse(JSON.stringify(newInstance));
|
|
2121
|
+
this.regenerateInstanceIds(instanceCopy);
|
|
2122
|
+
this.addComponentToSlot(instance.slots, slot, instanceCopy);
|
|
2123
|
+
modified = true;
|
|
2124
|
+
}
|
|
2125
|
+
if (instance.slots) {
|
|
2126
|
+
const nestedModified = this.addComponentToNestedSlots(
|
|
2127
|
+
instance.slots,
|
|
2128
|
+
parentTypes,
|
|
2129
|
+
slot,
|
|
2130
|
+
newInstance,
|
|
2131
|
+
strict
|
|
2132
|
+
);
|
|
2133
|
+
if (nestedModified) {
|
|
2134
|
+
modified = true;
|
|
2135
|
+
}
|
|
2136
|
+
}
|
|
1993
2137
|
}
|
|
1994
2138
|
}
|
|
1995
|
-
|
|
1996
|
-
entry.entry._dataResources = {
|
|
1997
|
-
...entry.entry._dataResources ?? {},
|
|
1998
|
-
...dataResources
|
|
1999
|
-
};
|
|
2000
|
-
}
|
|
2001
|
-
}
|
|
2002
|
-
// --- Utilities ---
|
|
2003
|
-
compareTypes(type1, type2, strict) {
|
|
2004
|
-
if (strict) {
|
|
2005
|
-
return type1 === type2;
|
|
2006
|
-
}
|
|
2007
|
-
return type1.toLowerCase() === type2.toLowerCase();
|
|
2008
|
-
}
|
|
2009
|
-
truncate(str, maxLength) {
|
|
2010
|
-
if (str.length <= maxLength) return str;
|
|
2011
|
-
return str.substring(0, maxLength - 3) + "...";
|
|
2012
|
-
}
|
|
2013
|
-
truncateName(name, maxLength) {
|
|
2014
|
-
if (name.length <= maxLength) return name;
|
|
2015
|
-
return name.substring(0, maxLength);
|
|
2139
|
+
return modified;
|
|
2016
2140
|
}
|
|
2017
2141
|
};
|
|
2018
|
-
function computeGuidHash(guidOrSeed) {
|
|
2019
|
-
let uuidStr;
|
|
2020
|
-
if (isValidUuid(guidOrSeed)) {
|
|
2021
|
-
uuidStr = formatAsBracedUuid(guidOrSeed);
|
|
2022
|
-
} else {
|
|
2023
|
-
const hash = crypto.createHash("md5").update(guidOrSeed, "utf-8").digest();
|
|
2024
|
-
const hex = [
|
|
2025
|
-
// First 4 bytes: little-endian in .NET Guid
|
|
2026
|
-
hash[3].toString(16).padStart(2, "0"),
|
|
2027
|
-
hash[2].toString(16).padStart(2, "0"),
|
|
2028
|
-
hash[1].toString(16).padStart(2, "0"),
|
|
2029
|
-
hash[0].toString(16).padStart(2, "0"),
|
|
2030
|
-
"-",
|
|
2031
|
-
// Bytes 4-5: little-endian
|
|
2032
|
-
hash[5].toString(16).padStart(2, "0"),
|
|
2033
|
-
hash[4].toString(16).padStart(2, "0"),
|
|
2034
|
-
"-",
|
|
2035
|
-
// Bytes 6-7: little-endian
|
|
2036
|
-
hash[7].toString(16).padStart(2, "0"),
|
|
2037
|
-
hash[6].toString(16).padStart(2, "0"),
|
|
2038
|
-
"-",
|
|
2039
|
-
// Bytes 8-9: big-endian
|
|
2040
|
-
hash[8].toString(16).padStart(2, "0"),
|
|
2041
|
-
hash[9].toString(16).padStart(2, "0"),
|
|
2042
|
-
"-",
|
|
2043
|
-
// Bytes 10-15: big-endian
|
|
2044
|
-
hash[10].toString(16).padStart(2, "0"),
|
|
2045
|
-
hash[11].toString(16).padStart(2, "0"),
|
|
2046
|
-
hash[12].toString(16).padStart(2, "0"),
|
|
2047
|
-
hash[13].toString(16).padStart(2, "0"),
|
|
2048
|
-
hash[14].toString(16).padStart(2, "0"),
|
|
2049
|
-
hash[15].toString(16).padStart(2, "0")
|
|
2050
|
-
].join("");
|
|
2051
|
-
uuidStr = `{${hex}}`.toUpperCase();
|
|
2052
|
-
}
|
|
2053
|
-
const chars = uuidStr.split("");
|
|
2054
|
-
chars[15] = "4";
|
|
2055
|
-
const arr20 = ["8", "9", "A", "B"];
|
|
2056
|
-
const hexVal = parseInt(chars[20], 16);
|
|
2057
|
-
chars[20] = arr20[hexVal % 4];
|
|
2058
|
-
return chars.join("").slice(1, -1).toLowerCase();
|
|
2059
|
-
}
|
|
2060
|
-
function isValidUuid(str) {
|
|
2061
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
|
|
2062
|
-
}
|
|
2063
|
-
function formatAsBracedUuid(uuid) {
|
|
2064
|
-
const clean = uuid.replace(/[{}]/g, "").toUpperCase();
|
|
2065
|
-
return `{${clean}}`;
|
|
2066
|
-
}
|
|
2067
2142
|
|
|
2068
2143
|
// src/core/services/parameter-remover.service.ts
|
|
2069
2144
|
var ParameterRemoverService = class {
|
|
@@ -2537,6 +2612,7 @@ export {
|
|
|
2537
2612
|
SlotNotFoundError,
|
|
2538
2613
|
SlotRenamerService,
|
|
2539
2614
|
TransformError,
|
|
2540
|
-
computeGuidHash
|
|
2615
|
+
computeGuidHash,
|
|
2616
|
+
regenerateIds
|
|
2541
2617
|
};
|
|
2542
2618
|
//# sourceMappingURL=index.js.map
|