@uniformdev/transformer 1.1.16 → 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 +1049 -1022
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +8 -1
- package/dist/index.js +1343 -1313
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -513,624 +513,869 @@ 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
|
-
if (deleted) {
|
|
752
|
-
this.logger.action(whatIf, "DELETE", `Root overrides from composition/${relativePath}`);
|
|
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;
|
|
756
695
|
}
|
|
696
|
+
if (missingFlattenTypes.includes(flattenType) && !foundMissingFlattenTypes.has(flattenType)) {
|
|
697
|
+
continue;
|
|
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
|
-
|
|
945
|
-
}
|
|
946
|
-
}
|
|
882
|
+
if (Object.keys(dataResources).length > 0) {
|
|
883
|
+
entry.entry._dataResources = {
|
|
884
|
+
...entry.entry._dataResources ?? {},
|
|
885
|
+
...dataResources
|
|
886
|
+
};
|
|
947
887
|
}
|
|
948
|
-
return count;
|
|
949
888
|
}
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
953
|
-
);
|
|
954
|
-
|
|
955
|
-
|
|
956
|
-
|
|
957
|
-
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
|
|
961
|
-
}
|
|
962
|
-
|
|
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);
|
|
899
|
+
}
|
|
900
|
+
} catch {
|
|
901
|
+
continue;
|
|
963
902
|
}
|
|
964
903
|
}
|
|
965
|
-
return
|
|
904
|
+
return sourceItemMap;
|
|
966
905
|
}
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
this.componentService = componentService;
|
|
974
|
-
this.logger = logger;
|
|
906
|
+
findExistingEntryBySourceItem(inst, sourceItemMap) {
|
|
907
|
+
const sourceItemParam = inst.instance.parameters?.sourceItem;
|
|
908
|
+
if (sourceItemParam?.value == null) {
|
|
909
|
+
return void 0;
|
|
910
|
+
}
|
|
911
|
+
return sourceItemMap.get(String(sourceItemParam.value));
|
|
975
912
|
}
|
|
976
|
-
|
|
913
|
+
// --- Utilities ---
|
|
914
|
+
compareTypes(type1, type2, strict) {
|
|
977
915
|
if (strict) {
|
|
978
|
-
return
|
|
916
|
+
return type1 === type2;
|
|
979
917
|
}
|
|
980
|
-
return
|
|
918
|
+
return type1.toLowerCase() === type2.toLowerCase();
|
|
981
919
|
}
|
|
982
|
-
|
|
983
|
-
|
|
984
|
-
|
|
985
|
-
|
|
986
|
-
|
|
987
|
-
|
|
988
|
-
|
|
989
|
-
|
|
990
|
-
|
|
991
|
-
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
|
|
995
|
-
|
|
996
|
-
const
|
|
997
|
-
const
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
|
|
1002
|
-
|
|
1003
|
-
|
|
1004
|
-
|
|
1005
|
-
|
|
1006
|
-
|
|
1007
|
-
|
|
1008
|
-
|
|
1009
|
-
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
"
|
|
1020
|
-
|
|
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);
|
|
998
|
+
} else {
|
|
999
|
+
result[key] = walkAndRegenerate(val, childPath);
|
|
1000
|
+
}
|
|
1001
|
+
}
|
|
1002
|
+
return result;
|
|
1003
|
+
}
|
|
1004
|
+
return value;
|
|
1005
|
+
}
|
|
1006
|
+
|
|
1007
|
+
// src/core/services/property-propagator.service.ts
|
|
1008
|
+
var PropertyPropagatorService = class {
|
|
1009
|
+
constructor(fileSystem, componentService, compositionService, logger) {
|
|
1010
|
+
this.fileSystem = fileSystem;
|
|
1011
|
+
this.componentService = componentService;
|
|
1012
|
+
this.compositionService = compositionService;
|
|
1013
|
+
this.logger = logger;
|
|
1014
|
+
}
|
|
1015
|
+
async propagate(options) {
|
|
1016
|
+
const {
|
|
1017
|
+
rootDir,
|
|
1018
|
+
componentsDir,
|
|
1019
|
+
compositionsDir,
|
|
1020
|
+
compositionType,
|
|
1021
|
+
property,
|
|
1022
|
+
targetComponentType,
|
|
1023
|
+
targetGroup,
|
|
1024
|
+
whatIf,
|
|
1025
|
+
strict,
|
|
1026
|
+
deleteSourceParameter
|
|
1027
|
+
} = options;
|
|
1028
|
+
const findOptions = { strict };
|
|
1029
|
+
const compositionTypes = this.parsePipeSeparatedValues(compositionType, strict);
|
|
1030
|
+
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1031
|
+
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
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 });
|
|
1037
|
+
}
|
|
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
|
+
}
|
|
1061
|
+
}
|
|
1062
|
+
}
|
|
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
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
if (groupSources.length > 0) {
|
|
1076
|
+
this.logger.info(
|
|
1077
|
+
`Resolved properties: ${resolvedNames.join(", ")} (from ${groupSources.join(", ")})`
|
|
1078
|
+
);
|
|
1079
|
+
} else {
|
|
1080
|
+
this.logger.info(`Resolved properties: ${resolvedNames.join(", ")}`);
|
|
1081
|
+
}
|
|
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
|
|
1021
1089
|
);
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
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;
|
|
1025
1099
|
}
|
|
1026
|
-
|
|
1027
|
-
|
|
1100
|
+
for (const param of resolvedParams) {
|
|
1101
|
+
const existingParam = this.componentService.findParameter(
|
|
1102
|
+
modifiedComponent,
|
|
1103
|
+
param.id,
|
|
1104
|
+
findOptions
|
|
1105
|
+
);
|
|
1106
|
+
if (!existingParam) {
|
|
1107
|
+
this.logger.action(
|
|
1108
|
+
whatIf,
|
|
1109
|
+
"COPY",
|
|
1110
|
+
`Parameter "${param.id}" \u2192 ${targetComponentType}.${targetGroup}`
|
|
1111
|
+
);
|
|
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
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
}
|
|
1028
1146
|
}
|
|
1029
|
-
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
|
|
1037
|
-
|
|
1147
|
+
if (componentModified && !whatIf) {
|
|
1148
|
+
await this.componentService.saveComponent(targetFilePath, modifiedComponent);
|
|
1149
|
+
}
|
|
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;
|
|
1166
|
+
}
|
|
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(", ")}`
|
|
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
|
+
}
|
|
1194
|
+
if (!whatIf) {
|
|
1195
|
+
await this.compositionService.saveComposition(filePath, composition);
|
|
1196
|
+
}
|
|
1197
|
+
modifiedCompositions++;
|
|
1198
|
+
}
|
|
1199
|
+
}
|
|
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
|
+
}
|
|
1249
|
+
}
|
|
1250
|
+
}
|
|
1251
|
+
}
|
|
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()
|
|
1038
1264
|
);
|
|
1039
|
-
if (!
|
|
1040
|
-
|
|
1265
|
+
if (!exists) {
|
|
1266
|
+
normalized.push(entry);
|
|
1041
1267
|
}
|
|
1042
|
-
fileRenamed = true;
|
|
1043
1268
|
}
|
|
1044
|
-
|
|
1045
|
-
|
|
1269
|
+
return normalized;
|
|
1270
|
+
}
|
|
1271
|
+
};
|
|
1272
|
+
|
|
1273
|
+
// src/core/services/slot-renamer.service.ts
|
|
1274
|
+
var SlotRenamerService = class {
|
|
1275
|
+
constructor(fileSystem, componentService, logger) {
|
|
1276
|
+
this.fileSystem = fileSystem;
|
|
1277
|
+
this.componentService = componentService;
|
|
1278
|
+
this.logger = logger;
|
|
1279
|
+
}
|
|
1280
|
+
compareIds(id1, id2, strict) {
|
|
1281
|
+
if (strict) {
|
|
1282
|
+
return id1 === id2;
|
|
1283
|
+
}
|
|
1284
|
+
return id1.toLowerCase() === id2.toLowerCase();
|
|
1285
|
+
}
|
|
1286
|
+
async rename(options) {
|
|
1287
|
+
const {
|
|
1288
|
+
rootDir,
|
|
1289
|
+
componentsDir,
|
|
1290
|
+
compositionsDir,
|
|
1291
|
+
compositionPatternsDir,
|
|
1292
|
+
componentPatternsDir,
|
|
1046
1293
|
componentType,
|
|
1047
|
-
|
|
1048
|
-
|
|
1294
|
+
slotId,
|
|
1295
|
+
newSlotId,
|
|
1296
|
+
newSlotName,
|
|
1049
1297
|
whatIf,
|
|
1050
1298
|
strict
|
|
1299
|
+
} = options;
|
|
1300
|
+
const findOptions = { strict };
|
|
1301
|
+
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1302
|
+
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
1303
|
+
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
1304
|
+
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
1305
|
+
if (this.compareIds(slotId, newSlotId, strict)) {
|
|
1306
|
+
throw new TransformError("New slot ID is the same as the current slot ID");
|
|
1307
|
+
}
|
|
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);
|
|
1312
|
+
}
|
|
1313
|
+
const slotIndex = component.slots.findIndex(
|
|
1314
|
+
(s) => this.compareIds(s.id, slotId, strict)
|
|
1051
1315
|
);
|
|
1052
|
-
|
|
1316
|
+
if (slotIndex === -1) {
|
|
1317
|
+
throw new SlotNotFoundError(slotId, componentType);
|
|
1318
|
+
}
|
|
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(
|
|
1053
1338
|
fullCompositionsDir,
|
|
1054
1339
|
componentType,
|
|
1055
|
-
|
|
1340
|
+
slotId,
|
|
1341
|
+
newSlotId,
|
|
1056
1342
|
whatIf,
|
|
1057
1343
|
strict,
|
|
1058
1344
|
"composition"
|
|
1059
1345
|
);
|
|
1060
|
-
const compositionPatternsResult = await this.
|
|
1346
|
+
const compositionPatternsResult = await this.renameSlotInDirectory(
|
|
1061
1347
|
fullCompositionPatternsDir,
|
|
1062
1348
|
componentType,
|
|
1063
|
-
|
|
1349
|
+
slotId,
|
|
1350
|
+
newSlotId,
|
|
1064
1351
|
whatIf,
|
|
1065
1352
|
strict,
|
|
1066
1353
|
"compositionPattern"
|
|
1067
1354
|
);
|
|
1068
|
-
const componentPatternsResult = await this.
|
|
1355
|
+
const componentPatternsResult = await this.renameSlotInDirectory(
|
|
1069
1356
|
fullComponentPatternsDir,
|
|
1070
1357
|
componentType,
|
|
1071
|
-
|
|
1358
|
+
slotId,
|
|
1359
|
+
newSlotId,
|
|
1072
1360
|
whatIf,
|
|
1073
1361
|
strict,
|
|
1074
1362
|
"componentPattern"
|
|
1075
1363
|
);
|
|
1076
|
-
const
|
|
1364
|
+
const totalFiles = compositionsResult.filesModified + compositionPatternsResult.filesModified + componentPatternsResult.filesModified;
|
|
1077
1365
|
const totalInstances = compositionsResult.instancesRenamed + compositionPatternsResult.instancesRenamed + componentPatternsResult.instancesRenamed;
|
|
1078
1366
|
this.logger.info("");
|
|
1079
1367
|
this.logger.info(
|
|
1080
|
-
`Summary: 1 component
|
|
1368
|
+
`Summary: 1 component definition, ${totalFiles} file(s) (${totalInstances} instance(s)) updated.`
|
|
1081
1369
|
);
|
|
1082
1370
|
return {
|
|
1083
|
-
|
|
1084
|
-
fileRenamed,
|
|
1085
|
-
allowedComponentsUpdated,
|
|
1371
|
+
componentDefinitionUpdated: true,
|
|
1086
1372
|
compositionsModified: compositionsResult.filesModified,
|
|
1087
1373
|
compositionPatternsModified: compositionPatternsResult.filesModified,
|
|
1088
1374
|
componentPatternsModified: componentPatternsResult.filesModified,
|
|
1089
1375
|
instancesRenamed: totalInstances
|
|
1090
1376
|
};
|
|
1091
1377
|
}
|
|
1092
|
-
async
|
|
1093
|
-
let files;
|
|
1094
|
-
try {
|
|
1095
|
-
files = await this.fileSystem.findFiles(componentsDir, "*.{json,yaml,yml}");
|
|
1096
|
-
} catch {
|
|
1097
|
-
return 0;
|
|
1098
|
-
}
|
|
1099
|
-
let updatedCount = 0;
|
|
1100
|
-
for (const filePath of files) {
|
|
1101
|
-
if (filePath === sourceFilePath) continue;
|
|
1102
|
-
let comp;
|
|
1103
|
-
try {
|
|
1104
|
-
comp = await this.fileSystem.readFile(filePath);
|
|
1105
|
-
} catch {
|
|
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) {
|
|
1120
|
-
this.logger.action(
|
|
1121
|
-
whatIf,
|
|
1122
|
-
"UPDATE",
|
|
1123
|
-
`allowedComponents in component/${this.fileSystem.getBasename(filePath)}: ${oldType} \u2192 ${newType}`
|
|
1124
|
-
);
|
|
1125
|
-
if (!whatIf) {
|
|
1126
|
-
await this.fileSystem.writeFile(filePath, comp);
|
|
1127
|
-
}
|
|
1128
|
-
updatedCount++;
|
|
1129
|
-
}
|
|
1130
|
-
}
|
|
1131
|
-
return updatedCount;
|
|
1132
|
-
}
|
|
1133
|
-
async renameTypeInDirectory(directory, oldType, newType, whatIf, strict, label) {
|
|
1378
|
+
async renameSlotInDirectory(directory, componentType, oldSlotId, newSlotId, whatIf, strict, label) {
|
|
1134
1379
|
let files;
|
|
1135
1380
|
try {
|
|
1136
1381
|
files = await this.fileSystem.findFiles(directory, "**/*.{json,yaml,yml}");
|
|
@@ -1149,14 +1394,22 @@ var ComponentRenamerService = class {
|
|
|
1149
1394
|
} catch {
|
|
1150
1395
|
continue;
|
|
1151
1396
|
}
|
|
1152
|
-
if (!composition?.composition)
|
|
1153
|
-
|
|
1397
|
+
if (!composition?.composition) {
|
|
1398
|
+
continue;
|
|
1399
|
+
}
|
|
1400
|
+
const count = this.renameSlotInTree(
|
|
1401
|
+
composition.composition,
|
|
1402
|
+
componentType,
|
|
1403
|
+
oldSlotId,
|
|
1404
|
+
newSlotId,
|
|
1405
|
+
strict
|
|
1406
|
+
);
|
|
1154
1407
|
if (count > 0) {
|
|
1155
1408
|
const relativePath = filePath.replace(directory, "").replace(/^[/\\]/, "");
|
|
1156
1409
|
this.logger.action(
|
|
1157
1410
|
whatIf,
|
|
1158
1411
|
"UPDATE",
|
|
1159
|
-
`${label}/${relativePath} (${count} instance(s))`
|
|
1412
|
+
`${label}/${relativePath} (${count} instance(s) of ${componentType})`
|
|
1160
1413
|
);
|
|
1161
1414
|
if (!whatIf) {
|
|
1162
1415
|
await this.fileSystem.writeFile(filePath, composition);
|
|
@@ -1167,949 +1420,725 @@ var ComponentRenamerService = class {
|
|
|
1167
1420
|
}
|
|
1168
1421
|
return { filesModified, instancesRenamed };
|
|
1169
1422
|
}
|
|
1170
|
-
|
|
1423
|
+
renameSlotInTree(node, componentType, oldSlotId, newSlotId, strict) {
|
|
1171
1424
|
let count = 0;
|
|
1172
|
-
if (this.compareIds(node.type,
|
|
1173
|
-
node.
|
|
1174
|
-
|
|
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
|
+
}
|
|
1175
1431
|
}
|
|
1176
1432
|
if (node.slots) {
|
|
1177
1433
|
for (const slotInstances of Object.values(node.slots)) {
|
|
1178
1434
|
if (!Array.isArray(slotInstances)) continue;
|
|
1179
1435
|
for (const instance of slotInstances) {
|
|
1180
|
-
count += this.
|
|
1436
|
+
count += this.renameSlotInTree(instance, componentType, oldSlotId, newSlotId, strict);
|
|
1181
1437
|
}
|
|
1182
1438
|
}
|
|
1183
1439
|
}
|
|
1184
1440
|
return count;
|
|
1185
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
|
+
}
|
|
1186
1459
|
};
|
|
1187
1460
|
|
|
1188
|
-
// src/core/services/component-
|
|
1189
|
-
|
|
1190
|
-
var ComponentAdderService = class {
|
|
1461
|
+
// src/core/services/component-renamer.service.ts
|
|
1462
|
+
var ComponentRenamerService = class {
|
|
1191
1463
|
constructor(fileSystem, componentService, logger) {
|
|
1192
1464
|
this.fileSystem = fileSystem;
|
|
1193
1465
|
this.componentService = componentService;
|
|
1194
1466
|
this.logger = logger;
|
|
1195
1467
|
}
|
|
1196
1468
|
compareIds(id1, id2, strict) {
|
|
1197
|
-
if (strict) {
|
|
1198
|
-
return id1 === id2;
|
|
1199
|
-
}
|
|
1200
|
-
return id1.toLowerCase() === id2.toLowerCase();
|
|
1201
|
-
}
|
|
1202
|
-
parseParentComponentTypes(parentComponentType) {
|
|
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] = [];
|
|
1469
|
+
if (strict) {
|
|
1470
|
+
return id1 === id2;
|
|
1256
1471
|
}
|
|
1257
|
-
|
|
1472
|
+
return id1.toLowerCase() === id2.toLowerCase();
|
|
1258
1473
|
}
|
|
1259
|
-
async
|
|
1474
|
+
async rename(options) {
|
|
1260
1475
|
const {
|
|
1261
1476
|
rootDir,
|
|
1262
1477
|
componentsDir,
|
|
1263
1478
|
compositionsDir,
|
|
1264
1479
|
compositionPatternsDir,
|
|
1265
1480
|
componentPatternsDir,
|
|
1266
|
-
|
|
1267
|
-
slot,
|
|
1481
|
+
componentType,
|
|
1268
1482
|
newComponentType,
|
|
1269
|
-
|
|
1483
|
+
newComponentName,
|
|
1270
1484
|
whatIf,
|
|
1271
1485
|
strict
|
|
1272
1486
|
} = options;
|
|
1273
|
-
if (!newComponentType) {
|
|
1274
|
-
throw new TransformError("newComponentType is required for add-component");
|
|
1275
|
-
}
|
|
1276
1487
|
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1277
1488
|
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
1278
1489
|
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
1279
1490
|
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
1280
1491
|
const findOptions = { strict };
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
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");
|
|
1284
1494
|
}
|
|
1285
|
-
this.logger.info(`
|
|
1495
|
+
this.logger.info(`Loading component: ${componentType}`);
|
|
1496
|
+
const { component, filePath: componentFilePath } = await this.componentService.loadComponent(fullComponentsDir, componentType, findOptions);
|
|
1497
|
+
let targetExists = false;
|
|
1286
1498
|
try {
|
|
1287
1499
|
await this.componentService.loadComponent(fullComponentsDir, newComponentType, findOptions);
|
|
1500
|
+
targetExists = true;
|
|
1288
1501
|
} catch (error) {
|
|
1289
|
-
if (error instanceof ComponentNotFoundError) {
|
|
1290
|
-
throw
|
|
1291
|
-
`Component type "${newComponentType}" not found in ${fullComponentsDir}`
|
|
1292
|
-
);
|
|
1502
|
+
if (!(error instanceof ComponentNotFoundError)) {
|
|
1503
|
+
throw error;
|
|
1293
1504
|
}
|
|
1294
|
-
throw error;
|
|
1295
1505
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
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)}`
|
|
1513
|
+
);
|
|
1514
|
+
component.id = newComponentType;
|
|
1515
|
+
if (newComponentName !== void 0) {
|
|
1516
|
+
component.name = newComponentName;
|
|
1517
|
+
}
|
|
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)}`
|
|
1313
1530
|
);
|
|
1314
|
-
if (
|
|
1315
|
-
|
|
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
|
-
}
|
|
1531
|
+
if (!whatIf) {
|
|
1532
|
+
await this.fileSystem.renameFile(componentFilePath, newFilePath);
|
|
1334
1533
|
}
|
|
1534
|
+
fileRenamed = true;
|
|
1335
1535
|
}
|
|
1336
|
-
const
|
|
1337
|
-
|
|
1338
|
-
|
|
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(
|
|
1339
1545
|
fullCompositionsDir,
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
newInstance,
|
|
1546
|
+
componentType,
|
|
1547
|
+
newComponentType,
|
|
1343
1548
|
whatIf,
|
|
1344
1549
|
strict,
|
|
1345
1550
|
"composition"
|
|
1346
1551
|
);
|
|
1347
|
-
const compositionPatternsResult = await this.
|
|
1552
|
+
const compositionPatternsResult = await this.renameTypeInDirectory(
|
|
1348
1553
|
fullCompositionPatternsDir,
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
newInstance,
|
|
1554
|
+
componentType,
|
|
1555
|
+
newComponentType,
|
|
1352
1556
|
whatIf,
|
|
1353
1557
|
strict,
|
|
1354
1558
|
"compositionPattern"
|
|
1355
1559
|
);
|
|
1356
|
-
const componentPatternsResult = await this.
|
|
1560
|
+
const componentPatternsResult = await this.renameTypeInDirectory(
|
|
1357
1561
|
fullComponentPatternsDir,
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
newInstance,
|
|
1562
|
+
componentType,
|
|
1563
|
+
newComponentType,
|
|
1361
1564
|
whatIf,
|
|
1362
1565
|
strict,
|
|
1363
1566
|
"componentPattern"
|
|
1364
1567
|
);
|
|
1568
|
+
const totalCompositionFiles = compositionsResult.filesModified + compositionPatternsResult.filesModified + componentPatternsResult.filesModified;
|
|
1569
|
+
const totalInstances = compositionsResult.instancesRenamed + compositionPatternsResult.instancesRenamed + componentPatternsResult.instancesRenamed;
|
|
1365
1570
|
this.logger.info("");
|
|
1366
1571
|
this.logger.info(
|
|
1367
|
-
`Summary:
|
|
1572
|
+
`Summary: 1 component renamed, ${allowedComponentsUpdated} component(s) with allowedComponents updated, ${totalCompositionFiles} composition file(s) (${totalInstances} instance(s)) updated.`
|
|
1368
1573
|
);
|
|
1369
1574
|
return {
|
|
1575
|
+
componentRenamed: true,
|
|
1576
|
+
fileRenamed,
|
|
1370
1577
|
allowedComponentsUpdated,
|
|
1371
|
-
compositionsModified: compositionsResult,
|
|
1372
|
-
compositionPatternsModified: compositionPatternsResult,
|
|
1373
|
-
componentPatternsModified: componentPatternsResult,
|
|
1374
|
-
|
|
1578
|
+
compositionsModified: compositionsResult.filesModified,
|
|
1579
|
+
compositionPatternsModified: compositionPatternsResult.filesModified,
|
|
1580
|
+
componentPatternsModified: componentPatternsResult.filesModified,
|
|
1581
|
+
instancesRenamed: totalInstances
|
|
1375
1582
|
};
|
|
1376
1583
|
}
|
|
1377
|
-
async
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
componentsDir,
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
componentPatternsDir,
|
|
1384
|
-
parentComponentType,
|
|
1385
|
-
slot,
|
|
1386
|
-
componentPatternId,
|
|
1387
|
-
whatIf,
|
|
1388
|
-
strict
|
|
1389
|
-
} = options;
|
|
1390
|
-
if (!componentPatternId) {
|
|
1391
|
-
throw new TransformError("componentPatternId is required for add-component-pattern");
|
|
1392
|
-
}
|
|
1393
|
-
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
1394
|
-
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
1395
|
-
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
1396
|
-
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
1397
|
-
const findOptions = { strict };
|
|
1398
|
-
const parentTypes = this.parseParentComponentTypes(parentComponentType);
|
|
1399
|
-
if (parentTypes.length === 0) {
|
|
1400
|
-
throw new TransformError("parentComponentType cannot be empty");
|
|
1401
|
-
}
|
|
1402
|
-
this.logger.info(`Loading component pattern: ${componentPatternId}`);
|
|
1403
|
-
const pattern = await this.loadComponentPattern(
|
|
1404
|
-
fullComponentPatternsDir,
|
|
1405
|
-
componentPatternId,
|
|
1406
|
-
strict
|
|
1407
|
-
);
|
|
1408
|
-
const patternDefinition = pattern.definition;
|
|
1409
|
-
if (!patternDefinition || !patternDefinition.type) {
|
|
1410
|
-
throw new TransformError(
|
|
1411
|
-
`Component pattern "${componentPatternId}" has no valid definition or missing type`
|
|
1412
|
-
);
|
|
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;
|
|
1413
1590
|
}
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
|
|
1417
|
-
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
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;
|
|
1421
1599
|
}
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
)
|
|
1425
|
-
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
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
|
+
}
|
|
1609
|
+
}
|
|
1429
1610
|
}
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
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);
|
|
1437
1619
|
}
|
|
1438
|
-
|
|
1439
|
-
|
|
1620
|
+
updatedCount++;
|
|
1621
|
+
}
|
|
1622
|
+
}
|
|
1623
|
+
return updatedCount;
|
|
1624
|
+
}
|
|
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 };
|
|
1631
|
+
}
|
|
1632
|
+
if (files.length === 0) {
|
|
1633
|
+
return { filesModified: 0, instancesRenamed: 0 };
|
|
1634
|
+
}
|
|
1635
|
+
let filesModified = 0;
|
|
1636
|
+
let instancesRenamed = 0;
|
|
1637
|
+
for (const filePath of files) {
|
|
1638
|
+
let composition;
|
|
1639
|
+
try {
|
|
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))`
|
|
1440
1652
|
);
|
|
1441
|
-
if (!
|
|
1442
|
-
this.
|
|
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;
|
|
1653
|
+
if (!whatIf) {
|
|
1654
|
+
await this.fileSystem.writeFile(filePath, composition);
|
|
1452
1655
|
}
|
|
1656
|
+
filesModified++;
|
|
1657
|
+
instancesRenamed += count;
|
|
1453
1658
|
}
|
|
1454
1659
|
}
|
|
1455
|
-
|
|
1456
|
-
type: componentTypeInPattern,
|
|
1457
|
-
_pattern: pattern.componentPatternId,
|
|
1458
|
-
_id: randomUUID()
|
|
1459
|
-
};
|
|
1460
|
-
const compositionsResult = await this.addComponentToDirectory(
|
|
1461
|
-
fullCompositionsDir,
|
|
1462
|
-
parentTypes,
|
|
1463
|
-
slot,
|
|
1464
|
-
newInstance,
|
|
1465
|
-
whatIf,
|
|
1466
|
-
strict,
|
|
1467
|
-
"composition"
|
|
1468
|
-
);
|
|
1469
|
-
const compositionPatternsResult = await this.addComponentToDirectory(
|
|
1470
|
-
fullCompositionPatternsDir,
|
|
1471
|
-
parentTypes,
|
|
1472
|
-
slot,
|
|
1473
|
-
newInstance,
|
|
1474
|
-
whatIf,
|
|
1475
|
-
strict,
|
|
1476
|
-
"compositionPattern"
|
|
1477
|
-
);
|
|
1478
|
-
const componentPatternsResult = await this.addComponentToDirectory(
|
|
1479
|
-
fullComponentPatternsDir,
|
|
1480
|
-
parentTypes,
|
|
1481
|
-
slot,
|
|
1482
|
-
newInstance,
|
|
1483
|
-
whatIf,
|
|
1484
|
-
strict,
|
|
1485
|
-
"componentPattern"
|
|
1486
|
-
);
|
|
1487
|
-
this.logger.info("");
|
|
1488
|
-
this.logger.info(
|
|
1489
|
-
`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.`
|
|
1490
|
-
);
|
|
1491
|
-
return {
|
|
1492
|
-
allowedComponentsUpdated,
|
|
1493
|
-
compositionsModified: compositionsResult,
|
|
1494
|
-
compositionPatternsModified: compositionPatternsResult,
|
|
1495
|
-
componentPatternsModified: componentPatternsResult,
|
|
1496
|
-
instancesAdded: compositionsResult + compositionPatternsResult + componentPatternsResult
|
|
1497
|
-
};
|
|
1660
|
+
return { filesModified, instancesRenamed };
|
|
1498
1661
|
}
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
if (await this.fileSystem.fileExists(jsonPath)) {
|
|
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);
|
|
1662
|
+
renameTypeInTree(node, oldType, newType, strict) {
|
|
1663
|
+
let count = 0;
|
|
1664
|
+
if (this.compareIds(node.type, oldType, strict)) {
|
|
1665
|
+
node.type = newType;
|
|
1666
|
+
count++;
|
|
1510
1667
|
}
|
|
1511
|
-
if (
|
|
1512
|
-
const
|
|
1513
|
-
|
|
1514
|
-
const
|
|
1515
|
-
|
|
1516
|
-
if (nameWithoutExt.toLowerCase() === patternId.toLowerCase()) {
|
|
1517
|
-
raw = await this.fileSystem.readFile(filePath);
|
|
1518
|
-
break;
|
|
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);
|
|
1519
1673
|
}
|
|
1520
1674
|
}
|
|
1521
1675
|
}
|
|
1522
|
-
|
|
1523
|
-
throw new TransformError(`Component pattern "${patternId}" not found in ${componentPatternsDir}`);
|
|
1524
|
-
}
|
|
1525
|
-
return this.normalizeComponentPattern(raw, patternId);
|
|
1676
|
+
return count;
|
|
1526
1677
|
}
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1678
|
+
};
|
|
1679
|
+
|
|
1680
|
+
// src/core/services/component-adder.service.ts
|
|
1681
|
+
import { randomUUID } from "crypto";
|
|
1682
|
+
var ComponentAdderService = class {
|
|
1683
|
+
constructor(fileSystem, componentService, logger) {
|
|
1684
|
+
this.fileSystem = fileSystem;
|
|
1685
|
+
this.componentService = componentService;
|
|
1686
|
+
this.logger = logger;
|
|
1687
|
+
}
|
|
1688
|
+
compareIds(id1, id2, strict) {
|
|
1689
|
+
if (strict) {
|
|
1690
|
+
return id1 === id2;
|
|
1530
1691
|
}
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
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
|
+
}
|
|
1537
1709
|
}
|
|
1538
|
-
return
|
|
1710
|
+
return result;
|
|
1539
1711
|
}
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
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);
|
|
1545
1718
|
}
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
let composition = null;
|
|
1552
|
-
let isComponentPattern = false;
|
|
1553
|
-
if (dirType === "componentPattern" && content && typeof content === "object" && "definition" in content) {
|
|
1554
|
-
isComponentPattern = true;
|
|
1555
|
-
const pattern = content;
|
|
1556
|
-
if (pattern.definition && pattern.definition.slots) {
|
|
1557
|
-
composition = {
|
|
1558
|
-
composition: {
|
|
1559
|
-
_id: "pattern-root",
|
|
1560
|
-
type: pattern.definition.type,
|
|
1561
|
-
slots: pattern.definition.slots
|
|
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);
|
|
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);
|
|
1608
1724
|
}
|
|
1609
|
-
filesModified++;
|
|
1610
|
-
}
|
|
1611
|
-
} catch (error) {
|
|
1612
|
-
if (error instanceof Error && !error.message.includes("skipping")) {
|
|
1613
|
-
this.logger.detail(`Skipping ${filePath}: ${error.message}`);
|
|
1614
1725
|
}
|
|
1615
1726
|
}
|
|
1616
1727
|
}
|
|
1617
|
-
return filesModified;
|
|
1618
1728
|
}
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1622
|
-
|
|
1623
|
-
|
|
1624
|
-
|
|
1625
|
-
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
|
|
1629
|
-
|
|
1630
|
-
|
|
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
|
-
}
|
|
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
|
+
};
|
|
1645
1741
|
}
|
|
1646
1742
|
}
|
|
1647
|
-
return
|
|
1743
|
+
return instance;
|
|
1648
1744
|
}
|
|
1649
|
-
|
|
1650
|
-
|
|
1651
|
-
|
|
1652
|
-
|
|
1653
|
-
|
|
1654
|
-
constructor(fileSystem, componentService, compositionService, logger) {
|
|
1655
|
-
this.fileSystem = fileSystem;
|
|
1656
|
-
this.componentService = componentService;
|
|
1657
|
-
this.compositionService = compositionService;
|
|
1658
|
-
this.logger = logger;
|
|
1745
|
+
addComponentToSlot(slots, slotId, instance) {
|
|
1746
|
+
if (!slots[slotId]) {
|
|
1747
|
+
slots[slotId] = [];
|
|
1748
|
+
}
|
|
1749
|
+
slots[slotId].push(instance);
|
|
1659
1750
|
}
|
|
1660
|
-
async
|
|
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
|
-
let entriesReused = 0;
|
|
1680
|
-
this.logger.info(`Composition types: ${compositionTypes.join(", ")}`);
|
|
1681
|
-
if (flattenComponentIds.length > 0) {
|
|
1682
|
-
this.logger.info(`Flatten component types: ${flattenComponentIds.join(", ")}`);
|
|
1683
|
-
}
|
|
1684
|
-
const sourceItemMap = flattenComponentIds.length > 0 ? await this.buildSourceItemMap(entriesDirFull) : /* @__PURE__ */ new Map();
|
|
1685
|
-
if (sourceItemMap.size > 0) {
|
|
1686
|
-
this.logger.info(`Found ${sourceItemMap.size} existing entry(ies) with sourceItem values`);
|
|
1687
|
-
}
|
|
1688
|
-
const compositionResults = await this.compositionService.findCompositionsByTypes(
|
|
1689
|
-
compositionsDirFull,
|
|
1690
|
-
compositionTypes,
|
|
1691
|
-
{ strict }
|
|
1692
|
-
);
|
|
1693
|
-
if (compositionResults.length === 0) {
|
|
1694
|
-
this.logger.warn("No compositions found matching the specified types");
|
|
1695
|
-
return { contentTypesWritten: 0, entriesFromCompositions: 0, entriesFromFlattened: 0, entriesReused: 0 };
|
|
1765
|
+
if (!newComponentType) {
|
|
1766
|
+
throw new TransformError("newComponentType is required for add-component");
|
|
1696
1767
|
}
|
|
1697
|
-
this.
|
|
1698
|
-
const
|
|
1699
|
-
|
|
1700
|
-
|
|
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");
|
|
1701
1776
|
}
|
|
1702
|
-
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
|
|
1709
|
-
|
|
1710
|
-
|
|
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;
|
|
1711
1787
|
}
|
|
1712
|
-
|
|
1713
|
-
const
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
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)
|
|
1718
1797
|
);
|
|
1719
|
-
if (
|
|
1720
|
-
|
|
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);
|
|
1721
1802
|
}
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
)
|
|
1728
|
-
|
|
1729
|
-
flattenContentTypeMap.set(flattenType, contentType);
|
|
1730
|
-
} catch (error) {
|
|
1731
|
-
if (error instanceof ComponentNotFoundError) {
|
|
1732
|
-
this.logger.info(`Flatten component type not found: ${flattenType}`);
|
|
1733
|
-
missingFlattenTypes.push(flattenType);
|
|
1734
|
-
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 = [];
|
|
1735
1810
|
}
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
|
|
1744
|
-
const entry = this.generateEntryFromComposition(composition);
|
|
1745
|
-
const flattenedByType = /* @__PURE__ */ new Map();
|
|
1746
|
-
if (flattenComponentIds.length > 0 && comp.slots) {
|
|
1747
|
-
for (const flattenType of flattenComponentIds) {
|
|
1748
|
-
if (this.compareTypes(flattenType, compositionType, strict)) {
|
|
1749
|
-
this.logger.warn(
|
|
1750
|
-
`Skipping flatten of "${flattenType}" \u2014 same as root component type`
|
|
1751
|
-
);
|
|
1752
|
-
continue;
|
|
1753
|
-
}
|
|
1754
|
-
const instances = this.findFlattenTargets(
|
|
1755
|
-
comp.slots,
|
|
1756
|
-
flattenType,
|
|
1757
|
-
compositionId,
|
|
1758
|
-
compositionName,
|
|
1759
|
-
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}"`
|
|
1760
1819
|
);
|
|
1761
|
-
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
foundMissingFlattenTypes.add(flattenType);
|
|
1765
|
-
}
|
|
1820
|
+
actualSlot.allowedComponents.push(newComponentType);
|
|
1821
|
+
if (!whatIf) {
|
|
1822
|
+
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
1766
1823
|
}
|
|
1824
|
+
allowedComponentsUpdated = true;
|
|
1767
1825
|
}
|
|
1768
1826
|
}
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1785
|
-
|
|
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 = [];
|
|
1786
1913
|
}
|
|
1787
|
-
|
|
1788
|
-
|
|
1789
|
-
this.logger.action(
|
|
1790
|
-
whatIf,
|
|
1791
|
-
"WRITE",
|
|
1792
|
-
`${entriesDir}/${entryId}.json (${compositionType}, "${this.truncate(compositionName, 50)}")`
|
|
1914
|
+
let slotDef = parentComponent.slots.find(
|
|
1915
|
+
(s) => this.compareIds(s.id, slot, strict)
|
|
1793
1916
|
);
|
|
1794
|
-
if (!
|
|
1795
|
-
|
|
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);
|
|
1796
1921
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
const flatEntryPath = this.fileSystem.joinPath(
|
|
1810
|
-
entriesDirFull,
|
|
1811
|
-
`${inst.determinisiticId}.json`
|
|
1812
|
-
);
|
|
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) {
|
|
1813
1934
|
this.logger.action(
|
|
1814
1935
|
whatIf,
|
|
1815
|
-
"
|
|
1816
|
-
|
|
1936
|
+
"UPDATE",
|
|
1937
|
+
`Adding "${componentTypeInPattern}" to allowedComponents for slot "${slot}" on component "${parentType}"`
|
|
1817
1938
|
);
|
|
1939
|
+
actualSlot.allowedComponents.push(componentTypeInPattern);
|
|
1818
1940
|
if (!whatIf) {
|
|
1819
|
-
await this.
|
|
1820
|
-
}
|
|
1821
|
-
entriesFromFlattened++;
|
|
1822
|
-
}
|
|
1823
|
-
}
|
|
1824
|
-
}
|
|
1825
|
-
if (flattenComponentIds.length > 0) {
|
|
1826
|
-
for (const contentType of contentTypeMap.values()) {
|
|
1827
|
-
for (const flattenType of flattenComponentIds) {
|
|
1828
|
-
if (this.compareTypes(flattenType, contentType.id, strict)) {
|
|
1829
|
-
continue;
|
|
1830
|
-
}
|
|
1831
|
-
if (missingFlattenTypes.includes(flattenType) && !foundMissingFlattenTypes.has(flattenType)) {
|
|
1832
|
-
continue;
|
|
1941
|
+
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
1833
1942
|
}
|
|
1834
|
-
|
|
1835
|
-
id: flattenType,
|
|
1836
|
-
name: flattenType,
|
|
1837
|
-
type: "contentReference",
|
|
1838
|
-
typeConfig: {
|
|
1839
|
-
isMulti: true,
|
|
1840
|
-
allowedContentTypes: [flattenType]
|
|
1841
|
-
},
|
|
1842
|
-
localizable: false
|
|
1843
|
-
});
|
|
1943
|
+
allowedComponentsUpdated = true;
|
|
1844
1944
|
}
|
|
1845
1945
|
}
|
|
1846
1946
|
}
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
|
|
1853
|
-
|
|
1854
|
-
|
|
1855
|
-
|
|
1856
|
-
|
|
1857
|
-
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
|
|
1862
|
-
|
|
1863
|
-
|
|
1864
|
-
|
|
1865
|
-
|
|
1866
|
-
|
|
1867
|
-
|
|
1868
|
-
|
|
1869
|
-
|
|
1870
|
-
|
|
1871
|
-
|
|
1872
|
-
|
|
1873
|
-
|
|
1874
|
-
|
|
1875
|
-
|
|
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.`
|
|
1876
1982
|
);
|
|
1877
|
-
if (neverFoundMissingTypes.length > 0) {
|
|
1878
|
-
this.logger.warn(
|
|
1879
|
-
`Flatten component type(s) not found in any composition: ${neverFoundMissingTypes.join(", ")}`
|
|
1880
|
-
);
|
|
1881
|
-
}
|
|
1882
|
-
return { contentTypesWritten, entriesFromCompositions, entriesFromFlattened, entriesReused };
|
|
1883
|
-
}
|
|
1884
|
-
// --- Content Type Generation ---
|
|
1885
|
-
generateContentType(component) {
|
|
1886
|
-
const fields = [];
|
|
1887
|
-
if (component.parameters) {
|
|
1888
|
-
for (const param of component.parameters) {
|
|
1889
|
-
fields.push(this.parameterToField(param));
|
|
1890
|
-
}
|
|
1891
|
-
}
|
|
1892
1983
|
return {
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
parameterToField(param) {
|
|
1899
|
-
const field = {
|
|
1900
|
-
id: param.id,
|
|
1901
|
-
name: param.name,
|
|
1902
|
-
type: param.type
|
|
1984
|
+
allowedComponentsUpdated,
|
|
1985
|
+
compositionsModified: compositionsResult,
|
|
1986
|
+
compositionPatternsModified: compositionPatternsResult,
|
|
1987
|
+
componentPatternsModified: componentPatternsResult,
|
|
1988
|
+
instancesAdded: compositionsResult + compositionPatternsResult + componentPatternsResult
|
|
1903
1989
|
};
|
|
1904
|
-
if (param.helpText !== void 0) {
|
|
1905
|
-
field.helpText = param.helpText;
|
|
1906
|
-
}
|
|
1907
|
-
if (param.localizable !== void 0) {
|
|
1908
|
-
field.localizable = param.localizable;
|
|
1909
|
-
}
|
|
1910
|
-
if (param.typeConfig !== void 0) {
|
|
1911
|
-
field.typeConfig = param.typeConfig;
|
|
1912
|
-
}
|
|
1913
|
-
return field;
|
|
1914
1990
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
const
|
|
1918
|
-
const
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
}
|
|
1925
|
-
|
|
1926
|
-
const extraWrapperProps = {};
|
|
1927
|
-
for (const [key, value] of Object.entries(composition)) {
|
|
1928
|
-
if (!wrapperKeys.has(key) && value != null) {
|
|
1929
|
-
extraWrapperProps[key] = value;
|
|
1930
|
-
}
|
|
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);
|
|
1931
2002
|
}
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
},
|
|
1942
|
-
...extraWrapperProps
|
|
1943
|
-
};
|
|
1944
|
-
}
|
|
1945
|
-
generateEntryFromFlattenedInstance(inst) {
|
|
1946
|
-
const entryName = this.truncateName(
|
|
1947
|
-
`${inst.componentType} (from ${inst.compositionName})`,
|
|
1948
|
-
60
|
|
1949
|
-
);
|
|
1950
|
-
return {
|
|
1951
|
-
entry: {
|
|
1952
|
-
_id: inst.determinisiticId,
|
|
1953
|
-
_name: entryName,
|
|
1954
|
-
type: inst.componentType,
|
|
1955
|
-
fields: { ...inst.instance.parameters ?? {} }
|
|
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
|
+
}
|
|
1956
2012
|
}
|
|
1957
|
-
}
|
|
2013
|
+
}
|
|
2014
|
+
if (!raw) {
|
|
2015
|
+
throw new TransformError(`Component pattern "${patternId}" not found in ${componentPatternsDir}`);
|
|
2016
|
+
}
|
|
2017
|
+
return this.normalizeComponentPattern(raw, patternId);
|
|
1958
2018
|
}
|
|
1959
|
-
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
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;
|
|
1964
2031
|
}
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
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) {
|
|
1971
2061
|
continue;
|
|
1972
2062
|
}
|
|
1973
|
-
const
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
1981
|
-
|
|
1982
|
-
|
|
1983
|
-
compositionName
|
|
1984
|
-
});
|
|
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;
|
|
1985
2073
|
}
|
|
1986
|
-
if (
|
|
1987
|
-
this.
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
currentPath,
|
|
1993
|
-
results,
|
|
2074
|
+
if (rootInstance.slots) {
|
|
2075
|
+
const nestedModified = this.addComponentToNestedSlots(
|
|
2076
|
+
rootInstance.slots,
|
|
2077
|
+
parentTypes,
|
|
2078
|
+
slot,
|
|
2079
|
+
newInstance,
|
|
1994
2080
|
strict
|
|
1995
2081
|
);
|
|
2082
|
+
if (nestedModified) {
|
|
2083
|
+
modified = true;
|
|
2084
|
+
}
|
|
1996
2085
|
}
|
|
1997
|
-
|
|
1998
|
-
|
|
1999
|
-
|
|
2000
|
-
|
|
2001
|
-
|
|
2002
|
-
|
|
2003
|
-
|
|
2004
|
-
|
|
2005
|
-
|
|
2006
|
-
|
|
2007
|
-
|
|
2008
|
-
|
|
2009
|
-
|
|
2010
|
-
|
|
2011
|
-
locale: "${locale}",
|
|
2012
|
-
entryIds: entryIds.join(",")
|
|
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);
|
|
2013
2100
|
}
|
|
2014
|
-
|
|
2101
|
+
filesModified++;
|
|
2102
|
+
}
|
|
2103
|
+
} catch (error) {
|
|
2104
|
+
if (error instanceof Error && !error.message.includes("skipping")) {
|
|
2105
|
+
this.logger.detail(`Skipping ${filePath}: ${error.message}`);
|
|
2106
|
+
}
|
|
2015
2107
|
}
|
|
2016
2108
|
}
|
|
2017
|
-
|
|
2018
|
-
entry.entry._dataResources = {
|
|
2019
|
-
...entry.entry._dataResources ?? {},
|
|
2020
|
-
...dataResources
|
|
2021
|
-
};
|
|
2022
|
-
}
|
|
2109
|
+
return filesModified;
|
|
2023
2110
|
}
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
const
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
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 = {};
|
|
2119
|
+
}
|
|
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
|
+
}
|
|
2034
2136
|
}
|
|
2035
|
-
} catch {
|
|
2036
|
-
continue;
|
|
2037
2137
|
}
|
|
2038
2138
|
}
|
|
2039
|
-
return
|
|
2040
|
-
}
|
|
2041
|
-
findExistingEntryBySourceItem(inst, sourceItemMap) {
|
|
2042
|
-
const sourceItemParam = inst.instance.parameters?.sourceItem;
|
|
2043
|
-
if (sourceItemParam?.value == null) {
|
|
2044
|
-
return void 0;
|
|
2045
|
-
}
|
|
2046
|
-
return sourceItemMap.get(String(sourceItemParam.value));
|
|
2047
|
-
}
|
|
2048
|
-
// --- Utilities ---
|
|
2049
|
-
compareTypes(type1, type2, strict) {
|
|
2050
|
-
if (strict) {
|
|
2051
|
-
return type1 === type2;
|
|
2052
|
-
}
|
|
2053
|
-
return type1.toLowerCase() === type2.toLowerCase();
|
|
2054
|
-
}
|
|
2055
|
-
truncate(str, maxLength) {
|
|
2056
|
-
if (str.length <= maxLength) return str;
|
|
2057
|
-
return str.substring(0, maxLength - 3) + "...";
|
|
2058
|
-
}
|
|
2059
|
-
truncateName(name, maxLength) {
|
|
2060
|
-
if (name.length <= maxLength) return name;
|
|
2061
|
-
return name.substring(0, maxLength);
|
|
2139
|
+
return modified;
|
|
2062
2140
|
}
|
|
2063
2141
|
};
|
|
2064
|
-
function computeGuidHash(guidOrSeed) {
|
|
2065
|
-
let uuidStr;
|
|
2066
|
-
if (isValidUuid(guidOrSeed)) {
|
|
2067
|
-
uuidStr = formatAsBracedUuid(guidOrSeed);
|
|
2068
|
-
} else {
|
|
2069
|
-
const hash = crypto.createHash("md5").update(guidOrSeed, "utf-8").digest();
|
|
2070
|
-
const hex = [
|
|
2071
|
-
// First 4 bytes: little-endian in .NET Guid
|
|
2072
|
-
hash[3].toString(16).padStart(2, "0"),
|
|
2073
|
-
hash[2].toString(16).padStart(2, "0"),
|
|
2074
|
-
hash[1].toString(16).padStart(2, "0"),
|
|
2075
|
-
hash[0].toString(16).padStart(2, "0"),
|
|
2076
|
-
"-",
|
|
2077
|
-
// Bytes 4-5: little-endian
|
|
2078
|
-
hash[5].toString(16).padStart(2, "0"),
|
|
2079
|
-
hash[4].toString(16).padStart(2, "0"),
|
|
2080
|
-
"-",
|
|
2081
|
-
// Bytes 6-7: little-endian
|
|
2082
|
-
hash[7].toString(16).padStart(2, "0"),
|
|
2083
|
-
hash[6].toString(16).padStart(2, "0"),
|
|
2084
|
-
"-",
|
|
2085
|
-
// Bytes 8-9: big-endian
|
|
2086
|
-
hash[8].toString(16).padStart(2, "0"),
|
|
2087
|
-
hash[9].toString(16).padStart(2, "0"),
|
|
2088
|
-
"-",
|
|
2089
|
-
// Bytes 10-15: big-endian
|
|
2090
|
-
hash[10].toString(16).padStart(2, "0"),
|
|
2091
|
-
hash[11].toString(16).padStart(2, "0"),
|
|
2092
|
-
hash[12].toString(16).padStart(2, "0"),
|
|
2093
|
-
hash[13].toString(16).padStart(2, "0"),
|
|
2094
|
-
hash[14].toString(16).padStart(2, "0"),
|
|
2095
|
-
hash[15].toString(16).padStart(2, "0")
|
|
2096
|
-
].join("");
|
|
2097
|
-
uuidStr = `{${hex}}`.toUpperCase();
|
|
2098
|
-
}
|
|
2099
|
-
const chars = uuidStr.split("");
|
|
2100
|
-
chars[15] = "4";
|
|
2101
|
-
const arr20 = ["8", "9", "A", "B"];
|
|
2102
|
-
const hexVal = parseInt(chars[20], 16);
|
|
2103
|
-
chars[20] = arr20[hexVal % 4];
|
|
2104
|
-
return chars.join("").slice(1, -1).toLowerCase();
|
|
2105
|
-
}
|
|
2106
|
-
function isValidUuid(str) {
|
|
2107
|
-
return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(str);
|
|
2108
|
-
}
|
|
2109
|
-
function formatAsBracedUuid(uuid) {
|
|
2110
|
-
const clean = uuid.replace(/[{}]/g, "").toUpperCase();
|
|
2111
|
-
return `{${clean}}`;
|
|
2112
|
-
}
|
|
2113
2142
|
|
|
2114
2143
|
// src/core/services/parameter-remover.service.ts
|
|
2115
2144
|
var ParameterRemoverService = class {
|
|
@@ -2583,6 +2612,7 @@ export {
|
|
|
2583
2612
|
SlotNotFoundError,
|
|
2584
2613
|
SlotRenamerService,
|
|
2585
2614
|
TransformError,
|
|
2586
|
-
computeGuidHash
|
|
2615
|
+
computeGuidHash,
|
|
2616
|
+
regenerateIds
|
|
2587
2617
|
};
|
|
2588
2618
|
//# sourceMappingURL=index.js.map
|