@uniformdev/transformer 1.1.3 → 1.1.5
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 +352 -148
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +8 -0
- package/dist/index.js +208 -119
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -372,13 +372,22 @@ var CompositionService = class {
|
|
|
372
372
|
await this.fileSystem.writeFile(filePath, composition);
|
|
373
373
|
}
|
|
374
374
|
async findCompositionsByType(compositionsDir, compositionType, options = {}) {
|
|
375
|
+
return this.findCompositionsByTypes(compositionsDir, [compositionType], options);
|
|
376
|
+
}
|
|
377
|
+
async findCompositionsByTypes(compositionsDir, compositionTypes, options = {}) {
|
|
375
378
|
const { strict = false } = options;
|
|
379
|
+
const normalizedTypes = this.normalizeCompositionTypes(compositionTypes, strict);
|
|
380
|
+
if (normalizedTypes.length === 0) {
|
|
381
|
+
return [];
|
|
382
|
+
}
|
|
376
383
|
const files = await this.fileSystem.findFiles(compositionsDir, "**/*.{json,yaml,yml}");
|
|
377
384
|
const results = [];
|
|
378
385
|
for (const filePath of files) {
|
|
379
386
|
try {
|
|
380
387
|
const composition = await this.loadComposition(filePath);
|
|
381
|
-
if (composition.composition?.type &&
|
|
388
|
+
if (composition.composition?.type && normalizedTypes.some(
|
|
389
|
+
(type) => this.compareTypes(composition.composition.type, type, strict)
|
|
390
|
+
)) {
|
|
382
391
|
results.push({ composition, filePath });
|
|
383
392
|
}
|
|
384
393
|
} catch {
|
|
@@ -386,6 +395,22 @@ var CompositionService = class {
|
|
|
386
395
|
}
|
|
387
396
|
return results;
|
|
388
397
|
}
|
|
398
|
+
normalizeCompositionTypes(compositionTypes, strict) {
|
|
399
|
+
const normalized = [];
|
|
400
|
+
for (const type of compositionTypes) {
|
|
401
|
+
const trimmed = type.trim();
|
|
402
|
+
if (!trimmed) {
|
|
403
|
+
continue;
|
|
404
|
+
}
|
|
405
|
+
const exists = normalized.some(
|
|
406
|
+
(existing) => strict ? existing === trimmed : existing.toLowerCase() === trimmed.toLowerCase()
|
|
407
|
+
);
|
|
408
|
+
if (!exists) {
|
|
409
|
+
normalized.push(trimmed);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
return normalized;
|
|
413
|
+
}
|
|
389
414
|
findComponentInstances(composition, componentType, options = {}) {
|
|
390
415
|
const { strict = false } = options;
|
|
391
416
|
const results = [];
|
|
@@ -510,26 +535,51 @@ var PropertyPropagatorService = class {
|
|
|
510
535
|
deleteSourceParameter
|
|
511
536
|
} = options;
|
|
512
537
|
const findOptions = { strict };
|
|
538
|
+
const compositionTypes = this.parsePipeSeparatedValues(compositionType, strict);
|
|
513
539
|
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
514
540
|
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
515
|
-
|
|
516
|
-
const
|
|
541
|
+
const sourceComponents = [];
|
|
542
|
+
for (const sourceType of compositionTypes) {
|
|
543
|
+
this.logger.info(`Loading component: ${sourceType}`);
|
|
544
|
+
const { component: sourceComponent, filePath: sourceFilePath } = await this.componentService.loadComponent(fullComponentsDir, sourceType, findOptions);
|
|
545
|
+
sourceComponents.push({ sourceType, sourceFilePath, sourceComponent });
|
|
546
|
+
}
|
|
517
547
|
this.logger.info(`Loading component: ${targetComponentType}`);
|
|
518
548
|
const { component: targetComponent, filePath: targetFilePath } = await this.componentService.loadComponent(fullComponentsDir, targetComponentType, findOptions);
|
|
519
|
-
const propertyNames = property.split("|").map((p) => p.trim());
|
|
520
|
-
const
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
549
|
+
const propertyNames = property.split("|").map((p) => p.trim()).filter((p) => p.length > 0);
|
|
550
|
+
const resolvedParams = [];
|
|
551
|
+
const resolvedNames = [];
|
|
552
|
+
for (const { sourceType, sourceComponent } of sourceComponents) {
|
|
553
|
+
const { parameters: sourceParams, notFound } = this.componentService.resolveProperties(
|
|
554
|
+
sourceComponent,
|
|
555
|
+
propertyNames,
|
|
556
|
+
findOptions
|
|
557
|
+
);
|
|
558
|
+
if (notFound.length > 0) {
|
|
559
|
+
throw new PropertyNotFoundError(notFound.join(", "), sourceType);
|
|
560
|
+
}
|
|
561
|
+
for (const param of sourceParams) {
|
|
562
|
+
const exists = resolvedParams.some(
|
|
563
|
+
(existing) => strict ? existing.id === param.id : existing.id.toLowerCase() === param.id.toLowerCase()
|
|
564
|
+
);
|
|
565
|
+
if (!exists) {
|
|
566
|
+
resolvedParams.push(param);
|
|
567
|
+
resolvedNames.push(param.id);
|
|
568
|
+
}
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
const groupSources = [];
|
|
572
|
+
for (const { sourceType, sourceComponent } of sourceComponents) {
|
|
573
|
+
for (const name of propertyNames) {
|
|
574
|
+
const param = this.componentService.findParameter(sourceComponent, name, findOptions);
|
|
575
|
+
if (param && this.componentService.isGroupParameter(param)) {
|
|
576
|
+
const groupSource = `${sourceType}.${name}`;
|
|
577
|
+
if (!groupSources.includes(groupSource)) {
|
|
578
|
+
groupSources.push(groupSource);
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
}
|
|
527
582
|
}
|
|
528
|
-
const resolvedNames = resolvedParams.map((p) => p.id);
|
|
529
|
-
const groupSources = propertyNames.filter((name) => {
|
|
530
|
-
const param = this.componentService.findParameter(sourceComponent, name, findOptions);
|
|
531
|
-
return param && this.componentService.isGroupParameter(param);
|
|
532
|
-
});
|
|
533
583
|
if (groupSources.length > 0) {
|
|
534
584
|
this.logger.info(
|
|
535
585
|
`Resolved properties: ${resolvedNames.join(", ")} (from ${groupSources.join(", ")})`
|
|
@@ -604,9 +654,9 @@ var PropertyPropagatorService = class {
|
|
|
604
654
|
if (componentModified && !whatIf) {
|
|
605
655
|
await this.componentService.saveComponent(targetFilePath, modifiedComponent);
|
|
606
656
|
}
|
|
607
|
-
const compositions = await this.compositionService.
|
|
657
|
+
const compositions = await this.compositionService.findCompositionsByTypes(
|
|
608
658
|
fullCompositionsDir,
|
|
609
|
-
|
|
659
|
+
compositionTypes,
|
|
610
660
|
findOptions
|
|
611
661
|
);
|
|
612
662
|
let modifiedCompositions = 0;
|
|
@@ -653,31 +703,41 @@ var PropertyPropagatorService = class {
|
|
|
653
703
|
modifiedCompositions++;
|
|
654
704
|
}
|
|
655
705
|
}
|
|
656
|
-
let
|
|
706
|
+
let modifiedSourceComponents = 0;
|
|
657
707
|
if (deleteSourceParameter) {
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
671
|
-
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
708
|
+
for (const { sourceType, sourceFilePath, sourceComponent } of sourceComponents) {
|
|
709
|
+
let modifiedSource = { ...sourceComponent };
|
|
710
|
+
let sourceComponentModified = false;
|
|
711
|
+
for (const param of resolvedParams) {
|
|
712
|
+
const exists = this.componentService.findParameter(modifiedSource, param.id, findOptions);
|
|
713
|
+
if (exists) {
|
|
714
|
+
this.logger.action(whatIf, "DELETE", `Parameter "${param.id}" from ${sourceType}`);
|
|
715
|
+
modifiedSource = this.componentService.removeParameter(modifiedSource, param.id, findOptions);
|
|
716
|
+
sourceComponentModified = true;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
const beforeGroupCount = modifiedSource.parameters?.filter(
|
|
720
|
+
(p) => this.componentService.isGroupParameter(p)
|
|
721
|
+
).length ?? 0;
|
|
722
|
+
modifiedSource = this.componentService.removeEmptyGroups(modifiedSource);
|
|
723
|
+
const afterGroupCount = modifiedSource.parameters?.filter(
|
|
724
|
+
(p) => this.componentService.isGroupParameter(p)
|
|
725
|
+
).length ?? 0;
|
|
726
|
+
if (afterGroupCount < beforeGroupCount) {
|
|
727
|
+
const removedCount = beforeGroupCount - afterGroupCount;
|
|
728
|
+
this.logger.action(
|
|
729
|
+
whatIf,
|
|
730
|
+
"DELETE",
|
|
731
|
+
`${removedCount} empty group(s) from ${sourceType}`
|
|
732
|
+
);
|
|
733
|
+
sourceComponentModified = true;
|
|
734
|
+
}
|
|
735
|
+
if (sourceComponentModified) {
|
|
736
|
+
modifiedSourceComponents++;
|
|
737
|
+
}
|
|
738
|
+
if (sourceComponentModified && !whatIf) {
|
|
739
|
+
await this.componentService.saveComponent(sourceFilePath, modifiedSource);
|
|
740
|
+
}
|
|
681
741
|
}
|
|
682
742
|
for (const { composition, filePath } of compositions) {
|
|
683
743
|
const relativePath = filePath.replace(fullCompositionsDir, "").replace(/^[/\\]/, "");
|
|
@@ -696,11 +756,24 @@ var PropertyPropagatorService = class {
|
|
|
696
756
|
}
|
|
697
757
|
}
|
|
698
758
|
return {
|
|
699
|
-
modifiedComponents: (componentModified ? 1 : 0) +
|
|
759
|
+
modifiedComponents: (componentModified ? 1 : 0) + modifiedSourceComponents,
|
|
700
760
|
modifiedCompositions,
|
|
701
761
|
propagatedInstances
|
|
702
762
|
};
|
|
703
763
|
}
|
|
764
|
+
parsePipeSeparatedValues(value, strict) {
|
|
765
|
+
const entries = value.split("|").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
766
|
+
const normalized = [];
|
|
767
|
+
for (const entry of entries) {
|
|
768
|
+
const exists = normalized.some(
|
|
769
|
+
(existing) => strict ? existing === entry : existing.toLowerCase() === entry.toLowerCase()
|
|
770
|
+
);
|
|
771
|
+
if (!exists) {
|
|
772
|
+
normalized.push(entry);
|
|
773
|
+
}
|
|
774
|
+
}
|
|
775
|
+
return normalized;
|
|
776
|
+
}
|
|
704
777
|
};
|
|
705
778
|
|
|
706
779
|
// src/cli/logger.ts
|
|
@@ -732,7 +805,10 @@ function createPropagateRootComponentPropertyCommand() {
|
|
|
732
805
|
const command = new Command("propagate-root-component-property");
|
|
733
806
|
command.description(
|
|
734
807
|
"Copies property definitions from a composition type's root component to a target component type, then propagates the actual values across all matching compositions."
|
|
735
|
-
).option(
|
|
808
|
+
).option(
|
|
809
|
+
"--compositionType <type>",
|
|
810
|
+
"The composition type(s) to process. Supports pipe-separated lists (e.g., HomePage|LandingPage)"
|
|
811
|
+
).option("--property <properties>", "Pipe-separated list of properties and/or groups to copy").option(
|
|
736
812
|
"--targetComponentType <type>",
|
|
737
813
|
"The component type that will receive the copied properties"
|
|
738
814
|
).option(
|
|
@@ -2422,6 +2498,12 @@ var ComponentAdderService = class {
|
|
|
2422
2498
|
}
|
|
2423
2499
|
return id1.toLowerCase() === id2.toLowerCase();
|
|
2424
2500
|
}
|
|
2501
|
+
parseParentComponentTypes(parentComponentType) {
|
|
2502
|
+
return parentComponentType.split("|").map((t) => t.trim()).filter((t) => t.length > 0);
|
|
2503
|
+
}
|
|
2504
|
+
matchesAnyParentType(instanceType, parentTypes, strict) {
|
|
2505
|
+
return parentTypes.some((pt) => this.compareIds(instanceType, pt, strict));
|
|
2506
|
+
}
|
|
2425
2507
|
parseParameters(parameterString) {
|
|
2426
2508
|
const result = {};
|
|
2427
2509
|
if (!parameterString) return result;
|
|
@@ -2495,18 +2577,9 @@ var ComponentAdderService = class {
|
|
|
2495
2577
|
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
2496
2578
|
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
2497
2579
|
const findOptions = { strict };
|
|
2498
|
-
this.
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
parentComponent.slots = [];
|
|
2502
|
-
}
|
|
2503
|
-
let slotDef = parentComponent.slots.find(
|
|
2504
|
-
(s) => this.compareIds(s.id, slot, strict)
|
|
2505
|
-
);
|
|
2506
|
-
if (!slotDef) {
|
|
2507
|
-
this.logger.info(`Slot "${slot}" not found on component "${parentComponentType}", creating it`);
|
|
2508
|
-
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
2509
|
-
parentComponent.slots.push(slotDef);
|
|
2580
|
+
const parentTypes = this.parseParentComponentTypes(parentComponentType);
|
|
2581
|
+
if (parentTypes.length === 0) {
|
|
2582
|
+
throw new TransformError("parentComponentType cannot be empty");
|
|
2510
2583
|
}
|
|
2511
2584
|
this.logger.info(`Validating new component: ${newComponentType}`);
|
|
2512
2585
|
try {
|
|
@@ -2520,35 +2593,50 @@ var ComponentAdderService = class {
|
|
|
2520
2593
|
throw error;
|
|
2521
2594
|
}
|
|
2522
2595
|
let allowedComponentsUpdated = false;
|
|
2523
|
-
const
|
|
2524
|
-
|
|
2525
|
-
|
|
2526
|
-
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2596
|
+
for (const parentType of parentTypes) {
|
|
2597
|
+
this.logger.info(`Loading parent component: ${parentType}`);
|
|
2598
|
+
const { component: parentComponent, filePath: parentComponentFilePath } = await this.componentService.loadComponent(fullComponentsDir, parentType, findOptions);
|
|
2599
|
+
if (!parentComponent.slots) {
|
|
2600
|
+
parentComponent.slots = [];
|
|
2601
|
+
}
|
|
2602
|
+
let slotDef = parentComponent.slots.find(
|
|
2603
|
+
(s) => this.compareIds(s.id, slot, strict)
|
|
2604
|
+
);
|
|
2605
|
+
if (!slotDef) {
|
|
2606
|
+
this.logger.info(`Slot "${slot}" not found on component "${parentType}", creating it`);
|
|
2607
|
+
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
2608
|
+
parentComponent.slots.push(slotDef);
|
|
2530
2609
|
}
|
|
2531
|
-
const
|
|
2532
|
-
(
|
|
2610
|
+
const slotIndex = parentComponent.slots?.findIndex(
|
|
2611
|
+
(s) => this.compareIds(s.id, slotDef.id, strict)
|
|
2533
2612
|
);
|
|
2534
|
-
if (
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2613
|
+
if (slotIndex !== void 0 && slotIndex >= 0) {
|
|
2614
|
+
const actualSlot = parentComponent.slots[slotIndex];
|
|
2615
|
+
if (!actualSlot.allowedComponents) {
|
|
2616
|
+
actualSlot.allowedComponents = [];
|
|
2617
|
+
}
|
|
2618
|
+
const isAlreadyAllowed = actualSlot.allowedComponents.some(
|
|
2619
|
+
(c) => this.compareIds(c, newComponentType, strict)
|
|
2539
2620
|
);
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2621
|
+
if (!isAlreadyAllowed) {
|
|
2622
|
+
this.logger.action(
|
|
2623
|
+
whatIf,
|
|
2624
|
+
"UPDATE",
|
|
2625
|
+
`Adding "${newComponentType}" to allowedComponents for slot "${slot}" on component "${parentType}"`
|
|
2626
|
+
);
|
|
2627
|
+
actualSlot.allowedComponents.push(newComponentType);
|
|
2628
|
+
if (!whatIf) {
|
|
2629
|
+
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
2630
|
+
}
|
|
2631
|
+
allowedComponentsUpdated = true;
|
|
2543
2632
|
}
|
|
2544
|
-
allowedComponentsUpdated = true;
|
|
2545
2633
|
}
|
|
2546
2634
|
}
|
|
2547
2635
|
const parsedParams = this.parseParameters(paramString);
|
|
2548
2636
|
const newInstance = this.createComponentInstance(newComponentType, parsedParams);
|
|
2549
2637
|
const compositionsResult = await this.addComponentToDirectory(
|
|
2550
2638
|
fullCompositionsDir,
|
|
2551
|
-
|
|
2639
|
+
parentTypes,
|
|
2552
2640
|
slot,
|
|
2553
2641
|
newInstance,
|
|
2554
2642
|
whatIf,
|
|
@@ -2557,7 +2645,7 @@ var ComponentAdderService = class {
|
|
|
2557
2645
|
);
|
|
2558
2646
|
const compositionPatternsResult = await this.addComponentToDirectory(
|
|
2559
2647
|
fullCompositionPatternsDir,
|
|
2560
|
-
|
|
2648
|
+
parentTypes,
|
|
2561
2649
|
slot,
|
|
2562
2650
|
newInstance,
|
|
2563
2651
|
whatIf,
|
|
@@ -2566,7 +2654,7 @@ var ComponentAdderService = class {
|
|
|
2566
2654
|
);
|
|
2567
2655
|
const componentPatternsResult = await this.addComponentToDirectory(
|
|
2568
2656
|
fullComponentPatternsDir,
|
|
2569
|
-
|
|
2657
|
+
parentTypes,
|
|
2570
2658
|
slot,
|
|
2571
2659
|
newInstance,
|
|
2572
2660
|
whatIf,
|
|
@@ -2575,7 +2663,7 @@ var ComponentAdderService = class {
|
|
|
2575
2663
|
);
|
|
2576
2664
|
this.logger.info("");
|
|
2577
2665
|
this.logger.info(
|
|
2578
|
-
`Summary: ${allowedComponentsUpdated ?
|
|
2666
|
+
`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.`
|
|
2579
2667
|
);
|
|
2580
2668
|
return {
|
|
2581
2669
|
allowedComponentsUpdated,
|
|
@@ -2606,18 +2694,9 @@ var ComponentAdderService = class {
|
|
|
2606
2694
|
const fullCompositionPatternsDir = this.fileSystem.resolvePath(rootDir, compositionPatternsDir);
|
|
2607
2695
|
const fullComponentPatternsDir = this.fileSystem.resolvePath(rootDir, componentPatternsDir);
|
|
2608
2696
|
const findOptions = { strict };
|
|
2609
|
-
this.
|
|
2610
|
-
|
|
2611
|
-
|
|
2612
|
-
parentComponent.slots = [];
|
|
2613
|
-
}
|
|
2614
|
-
let slotDef = parentComponent.slots.find(
|
|
2615
|
-
(s) => this.compareIds(s.id, slot, strict)
|
|
2616
|
-
);
|
|
2617
|
-
if (!slotDef) {
|
|
2618
|
-
this.logger.info(`Slot "${slot}" not found on component "${parentComponentType}", creating it`);
|
|
2619
|
-
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
2620
|
-
parentComponent.slots.push(slotDef);
|
|
2697
|
+
const parentTypes = this.parseParentComponentTypes(parentComponentType);
|
|
2698
|
+
if (parentTypes.length === 0) {
|
|
2699
|
+
throw new TransformError("parentComponentType cannot be empty");
|
|
2621
2700
|
}
|
|
2622
2701
|
this.logger.info(`Loading component pattern: ${componentPatternId}`);
|
|
2623
2702
|
const pattern = await this.loadComponentPattern(
|
|
@@ -2631,32 +2710,45 @@ var ComponentAdderService = class {
|
|
|
2631
2710
|
`Component pattern "${componentPatternId}" has no valid definition or missing type`
|
|
2632
2711
|
);
|
|
2633
2712
|
}
|
|
2634
|
-
let allowedComponentsUpdated = false;
|
|
2635
2713
|
const componentTypeInPattern = patternDefinition.type;
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2714
|
+
let allowedComponentsUpdated = false;
|
|
2715
|
+
for (const parentType of parentTypes) {
|
|
2716
|
+
this.logger.info(`Loading parent component: ${parentType}`);
|
|
2717
|
+
const { component: parentComponent, filePath: parentComponentFilePath } = await this.componentService.loadComponent(fullComponentsDir, parentType, findOptions);
|
|
2718
|
+
if (!parentComponent.slots) {
|
|
2719
|
+
parentComponent.slots = [];
|
|
2720
|
+
}
|
|
2721
|
+
let slotDef = parentComponent.slots.find(
|
|
2722
|
+
(s) => this.compareIds(s.id, slot, strict)
|
|
2723
|
+
);
|
|
2724
|
+
if (!slotDef) {
|
|
2725
|
+
this.logger.info(`Slot "${slot}" not found on component "${parentType}", creating it`);
|
|
2726
|
+
slotDef = { id: slot, name: slot, allowedComponents: [] };
|
|
2727
|
+
parentComponent.slots.push(slotDef);
|
|
2643
2728
|
}
|
|
2644
|
-
const
|
|
2645
|
-
(
|
|
2729
|
+
const slotIndex = parentComponent.slots?.findIndex(
|
|
2730
|
+
(s) => this.compareIds(s.id, slotDef.id, strict)
|
|
2646
2731
|
);
|
|
2647
|
-
if (
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2732
|
+
if (slotIndex !== void 0 && slotIndex >= 0) {
|
|
2733
|
+
const actualSlot = parentComponent.slots[slotIndex];
|
|
2734
|
+
if (!actualSlot.allowedComponents) {
|
|
2735
|
+
actualSlot.allowedComponents = [];
|
|
2736
|
+
}
|
|
2737
|
+
const isAlreadyAllowed = actualSlot.allowedComponents.some(
|
|
2738
|
+
(c) => this.compareIds(c, componentTypeInPattern, strict)
|
|
2652
2739
|
);
|
|
2653
|
-
|
|
2654
|
-
|
|
2655
|
-
|
|
2656
|
-
|
|
2740
|
+
if (!isAlreadyAllowed) {
|
|
2741
|
+
this.logger.action(
|
|
2742
|
+
whatIf,
|
|
2743
|
+
"UPDATE",
|
|
2744
|
+
`Adding "${componentTypeInPattern}" to allowedComponents for slot "${slot}" on component "${parentType}"`
|
|
2657
2745
|
);
|
|
2746
|
+
actualSlot.allowedComponents.push(componentTypeInPattern);
|
|
2747
|
+
if (!whatIf) {
|
|
2748
|
+
await this.componentService.saveComponent(parentComponentFilePath, parentComponent);
|
|
2749
|
+
}
|
|
2750
|
+
allowedComponentsUpdated = true;
|
|
2658
2751
|
}
|
|
2659
|
-
allowedComponentsUpdated = true;
|
|
2660
2752
|
}
|
|
2661
2753
|
}
|
|
2662
2754
|
const newInstance = {
|
|
@@ -2666,7 +2758,7 @@ var ComponentAdderService = class {
|
|
|
2666
2758
|
};
|
|
2667
2759
|
const compositionsResult = await this.addComponentToDirectory(
|
|
2668
2760
|
fullCompositionsDir,
|
|
2669
|
-
|
|
2761
|
+
parentTypes,
|
|
2670
2762
|
slot,
|
|
2671
2763
|
newInstance,
|
|
2672
2764
|
whatIf,
|
|
@@ -2675,7 +2767,7 @@ var ComponentAdderService = class {
|
|
|
2675
2767
|
);
|
|
2676
2768
|
const compositionPatternsResult = await this.addComponentToDirectory(
|
|
2677
2769
|
fullCompositionPatternsDir,
|
|
2678
|
-
|
|
2770
|
+
parentTypes,
|
|
2679
2771
|
slot,
|
|
2680
2772
|
newInstance,
|
|
2681
2773
|
whatIf,
|
|
@@ -2684,7 +2776,7 @@ var ComponentAdderService = class {
|
|
|
2684
2776
|
);
|
|
2685
2777
|
const componentPatternsResult = await this.addComponentToDirectory(
|
|
2686
2778
|
fullComponentPatternsDir,
|
|
2687
|
-
|
|
2779
|
+
parentTypes,
|
|
2688
2780
|
slot,
|
|
2689
2781
|
newInstance,
|
|
2690
2782
|
whatIf,
|
|
@@ -2693,7 +2785,7 @@ var ComponentAdderService = class {
|
|
|
2693
2785
|
);
|
|
2694
2786
|
this.logger.info("");
|
|
2695
2787
|
this.logger.info(
|
|
2696
|
-
`Summary: ${allowedComponentsUpdated ?
|
|
2788
|
+
`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.`
|
|
2697
2789
|
);
|
|
2698
2790
|
return {
|
|
2699
2791
|
allowedComponentsUpdated,
|
|
@@ -2744,7 +2836,7 @@ var ComponentAdderService = class {
|
|
|
2744
2836
|
}
|
|
2745
2837
|
return raw;
|
|
2746
2838
|
}
|
|
2747
|
-
async addComponentToDirectory(directory,
|
|
2839
|
+
async addComponentToDirectory(directory, parentTypes, slot, newInstance, whatIf, strict, dirType) {
|
|
2748
2840
|
const exists = await this.fileSystem.fileExists(directory);
|
|
2749
2841
|
if (!exists) {
|
|
2750
2842
|
this.logger.detail(`${dirType} directory does not exist, skipping`);
|
|
@@ -2777,7 +2869,7 @@ var ComponentAdderService = class {
|
|
|
2777
2869
|
}
|
|
2778
2870
|
const rootInstance = composition.composition;
|
|
2779
2871
|
let modified = false;
|
|
2780
|
-
if (this.
|
|
2872
|
+
if (this.matchesAnyParentType(rootInstance.type, parentTypes, strict)) {
|
|
2781
2873
|
if (!rootInstance.slots) {
|
|
2782
2874
|
rootInstance.slots = {};
|
|
2783
2875
|
}
|
|
@@ -2789,7 +2881,7 @@ var ComponentAdderService = class {
|
|
|
2789
2881
|
if (rootInstance.slots) {
|
|
2790
2882
|
const nestedModified = this.addComponentToNestedSlots(
|
|
2791
2883
|
rootInstance.slots,
|
|
2792
|
-
|
|
2884
|
+
parentTypes,
|
|
2793
2885
|
slot,
|
|
2794
2886
|
newInstance,
|
|
2795
2887
|
strict
|
|
@@ -2823,12 +2915,12 @@ var ComponentAdderService = class {
|
|
|
2823
2915
|
}
|
|
2824
2916
|
return filesModified;
|
|
2825
2917
|
}
|
|
2826
|
-
addComponentToNestedSlots(slots,
|
|
2918
|
+
addComponentToNestedSlots(slots, parentTypes, slot, newInstance, strict) {
|
|
2827
2919
|
let modified = false;
|
|
2828
2920
|
for (const slotInstances of Object.values(slots)) {
|
|
2829
2921
|
if (!Array.isArray(slotInstances)) continue;
|
|
2830
2922
|
for (const instance of slotInstances) {
|
|
2831
|
-
if (this.
|
|
2923
|
+
if (this.matchesAnyParentType(instance.type, parentTypes, strict)) {
|
|
2832
2924
|
if (!instance.slots) {
|
|
2833
2925
|
instance.slots = {};
|
|
2834
2926
|
}
|
|
@@ -2840,7 +2932,7 @@ var ComponentAdderService = class {
|
|
|
2840
2932
|
if (instance.slots) {
|
|
2841
2933
|
const nestedModified = this.addComponentToNestedSlots(
|
|
2842
2934
|
instance.slots,
|
|
2843
|
-
|
|
2935
|
+
parentTypes,
|
|
2844
2936
|
slot,
|
|
2845
2937
|
newInstance,
|
|
2846
2938
|
strict
|
|
@@ -2991,27 +3083,40 @@ var SlotPropagatorService = class {
|
|
|
2991
3083
|
deleteSourceSlot
|
|
2992
3084
|
} = options;
|
|
2993
3085
|
const findOptions = { strict };
|
|
3086
|
+
const compositionTypes = this.parsePipeSeparatedValues(compositionType, strict);
|
|
2994
3087
|
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
2995
3088
|
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
2996
|
-
|
|
2997
|
-
const
|
|
3089
|
+
const sourceComponents = [];
|
|
3090
|
+
for (const sourceType of compositionTypes) {
|
|
3091
|
+
this.logger.info(`Loading component: ${sourceType}`);
|
|
3092
|
+
const { component: sourceComponent, filePath: sourceFilePath } = await this.componentService.loadComponent(fullComponentsDir, sourceType, findOptions);
|
|
3093
|
+
sourceComponents.push({ sourceType, sourceFilePath, sourceComponent });
|
|
3094
|
+
}
|
|
2998
3095
|
this.logger.info(`Loading component: ${targetComponentType}`);
|
|
2999
3096
|
const { component: targetComponent, filePath: targetFilePath } = await this.componentService.loadComponent(fullComponentsDir, targetComponentType, findOptions);
|
|
3000
|
-
const slotNames = slot.split("|").map((s) => s.trim());
|
|
3097
|
+
const slotNames = slot.split("|").map((s) => s.trim()).filter((s) => s.length > 0);
|
|
3001
3098
|
const resolvedSlots = [];
|
|
3002
|
-
const
|
|
3003
|
-
for (const
|
|
3004
|
-
const
|
|
3005
|
-
|
|
3006
|
-
|
|
3007
|
-
|
|
3008
|
-
|
|
3099
|
+
const resolvedSlotIds = [];
|
|
3100
|
+
for (const { sourceType, sourceComponent } of sourceComponents) {
|
|
3101
|
+
const notFound = [];
|
|
3102
|
+
for (const slotName of slotNames) {
|
|
3103
|
+
const slotDef = this.componentService.findSlot(sourceComponent, slotName, findOptions);
|
|
3104
|
+
if (!slotDef) {
|
|
3105
|
+
notFound.push(slotName);
|
|
3106
|
+
continue;
|
|
3107
|
+
}
|
|
3108
|
+
const exists = resolvedSlots.some(
|
|
3109
|
+
(existing) => strict ? existing.id === slotDef.id : existing.id.toLowerCase() === slotDef.id.toLowerCase()
|
|
3110
|
+
);
|
|
3111
|
+
if (!exists) {
|
|
3112
|
+
resolvedSlots.push(slotDef);
|
|
3113
|
+
resolvedSlotIds.push(slotDef.id);
|
|
3114
|
+
}
|
|
3115
|
+
}
|
|
3116
|
+
if (notFound.length > 0) {
|
|
3117
|
+
throw new PropertyNotFoundError(`Slot "${notFound.join(", ")}"`, sourceType);
|
|
3009
3118
|
}
|
|
3010
3119
|
}
|
|
3011
|
-
if (notFound.length > 0) {
|
|
3012
|
-
throw new PropertyNotFoundError(`Slot "${notFound.join(", ")}"`, compositionType);
|
|
3013
|
-
}
|
|
3014
|
-
const resolvedSlotIds = resolvedSlots.map((s) => s.id);
|
|
3015
3120
|
this.logger.info(`Resolved slots: ${resolvedSlotIds.join(", ")}`);
|
|
3016
3121
|
let modifiedComponent = { ...targetComponent };
|
|
3017
3122
|
let componentModified = false;
|
|
@@ -3048,9 +3153,9 @@ var SlotPropagatorService = class {
|
|
|
3048
3153
|
if (componentModified && !whatIf) {
|
|
3049
3154
|
await this.componentService.saveComponent(targetFilePath, modifiedComponent);
|
|
3050
3155
|
}
|
|
3051
|
-
const compositions = await this.compositionService.
|
|
3156
|
+
const compositions = await this.compositionService.findCompositionsByTypes(
|
|
3052
3157
|
fullCompositionsDir,
|
|
3053
|
-
|
|
3158
|
+
compositionTypes,
|
|
3054
3159
|
findOptions
|
|
3055
3160
|
);
|
|
3056
3161
|
let modifiedCompositions = 0;
|
|
@@ -3097,16 +3202,26 @@ var SlotPropagatorService = class {
|
|
|
3097
3202
|
modifiedCompositions++;
|
|
3098
3203
|
}
|
|
3099
3204
|
}
|
|
3100
|
-
let
|
|
3205
|
+
let modifiedSourceComponents = 0;
|
|
3101
3206
|
if (deleteSourceSlot) {
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3207
|
+
for (const { sourceType, sourceFilePath, sourceComponent } of sourceComponents) {
|
|
3208
|
+
let modifiedSource = { ...sourceComponent };
|
|
3209
|
+
let sourceComponentModified = false;
|
|
3210
|
+
for (const slotDef of resolvedSlots) {
|
|
3211
|
+
const slotToDelete = this.componentService.findSlot(modifiedSource, slotDef.id, findOptions);
|
|
3212
|
+
if (!slotToDelete) {
|
|
3213
|
+
continue;
|
|
3214
|
+
}
|
|
3215
|
+
this.logger.action(whatIf, "DELETE", `Slot "${slotDef.id}" from ${sourceType}`);
|
|
3216
|
+
modifiedSource = this.componentService.removeSlot(modifiedSource, slotDef.id, findOptions);
|
|
3217
|
+
sourceComponentModified = true;
|
|
3218
|
+
}
|
|
3219
|
+
if (sourceComponentModified) {
|
|
3220
|
+
modifiedSourceComponents++;
|
|
3221
|
+
}
|
|
3222
|
+
if (sourceComponentModified && !whatIf) {
|
|
3223
|
+
await this.componentService.saveComponent(sourceFilePath, modifiedSource);
|
|
3224
|
+
}
|
|
3110
3225
|
}
|
|
3111
3226
|
for (const { composition, filePath } of compositions) {
|
|
3112
3227
|
const relativePath = filePath.replace(fullCompositionsDir, "").replace(/^[/\\]/, "");
|
|
@@ -3127,7 +3242,7 @@ var SlotPropagatorService = class {
|
|
|
3127
3242
|
}
|
|
3128
3243
|
}
|
|
3129
3244
|
return {
|
|
3130
|
-
modifiedComponents: (componentModified ? 1 : 0) +
|
|
3245
|
+
modifiedComponents: (componentModified ? 1 : 0) + modifiedSourceComponents,
|
|
3131
3246
|
modifiedCompositions,
|
|
3132
3247
|
propagatedInstances
|
|
3133
3248
|
};
|
|
@@ -3153,6 +3268,19 @@ var SlotPropagatorService = class {
|
|
|
3153
3268
|
}
|
|
3154
3269
|
instance.slots[slotName].push(...components);
|
|
3155
3270
|
}
|
|
3271
|
+
parsePipeSeparatedValues(value, strict) {
|
|
3272
|
+
const entries = value.split("|").map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
3273
|
+
const normalized = [];
|
|
3274
|
+
for (const entry of entries) {
|
|
3275
|
+
const exists = normalized.some(
|
|
3276
|
+
(existing) => strict ? existing === entry : existing.toLowerCase() === entry.toLowerCase()
|
|
3277
|
+
);
|
|
3278
|
+
if (!exists) {
|
|
3279
|
+
normalized.push(entry);
|
|
3280
|
+
}
|
|
3281
|
+
}
|
|
3282
|
+
return normalized;
|
|
3283
|
+
}
|
|
3156
3284
|
};
|
|
3157
3285
|
|
|
3158
3286
|
// src/cli/commands/propagate-root-component-slot.ts
|
|
@@ -3160,7 +3288,10 @@ function createPropagateRootComponentSlotCommand() {
|
|
|
3160
3288
|
const command = new Command9("propagate-root-component-slot");
|
|
3161
3289
|
command.description(
|
|
3162
3290
|
"Copies slot definitions from a composition type's root component to a target component type, then moves all component instances from that slot across all matching compositions."
|
|
3163
|
-
).option(
|
|
3291
|
+
).option(
|
|
3292
|
+
"--compositionType <type>",
|
|
3293
|
+
"The composition type(s) to process. Supports pipe-separated lists (e.g., HomePage|LandingPage)"
|
|
3294
|
+
).option("--slot <slots>", "Pipe-separated list of slot names to copy from the source component").option(
|
|
3164
3295
|
"--targetComponentType <type>",
|
|
3165
3296
|
"The component type that will receive the copied slots"
|
|
3166
3297
|
).option(
|
|
@@ -3229,9 +3360,82 @@ function createPropagateRootComponentSlotCommand() {
|
|
|
3229
3360
|
return command;
|
|
3230
3361
|
}
|
|
3231
3362
|
|
|
3363
|
+
// package.json
|
|
3364
|
+
var package_default = {
|
|
3365
|
+
name: "@uniformdev/transformer",
|
|
3366
|
+
version: "1.1.5",
|
|
3367
|
+
description: "CLI tool for transforming Uniform.dev serialization files offline",
|
|
3368
|
+
type: "module",
|
|
3369
|
+
bin: {
|
|
3370
|
+
"uniform-transform": "./dist/cli/index.js"
|
|
3371
|
+
},
|
|
3372
|
+
main: "./dist/index.js",
|
|
3373
|
+
types: "./dist/index.d.ts",
|
|
3374
|
+
exports: {
|
|
3375
|
+
".": {
|
|
3376
|
+
import: "./dist/index.js",
|
|
3377
|
+
types: "./dist/index.d.ts"
|
|
3378
|
+
}
|
|
3379
|
+
},
|
|
3380
|
+
files: [
|
|
3381
|
+
"dist",
|
|
3382
|
+
"LICENSE",
|
|
3383
|
+
"README.md"
|
|
3384
|
+
],
|
|
3385
|
+
scripts: {
|
|
3386
|
+
build: "tsup",
|
|
3387
|
+
dev: "tsx src/cli/index.ts",
|
|
3388
|
+
test: "vitest run",
|
|
3389
|
+
"test:watch": "vitest",
|
|
3390
|
+
"test:e2e": "vitest run --config vitest.e2e.config.ts",
|
|
3391
|
+
"test:coverage": "vitest run --coverage",
|
|
3392
|
+
lint: "eslint --ext .ts src tests",
|
|
3393
|
+
format: "prettier --write .",
|
|
3394
|
+
prepublishOnly: "npm run build"
|
|
3395
|
+
},
|
|
3396
|
+
keywords: [
|
|
3397
|
+
"uniform",
|
|
3398
|
+
"uniform.dev",
|
|
3399
|
+
"cli",
|
|
3400
|
+
"transform",
|
|
3401
|
+
"content",
|
|
3402
|
+
"cms"
|
|
3403
|
+
],
|
|
3404
|
+
author: "Uniform <https://uniform.dev>",
|
|
3405
|
+
license: "MIT",
|
|
3406
|
+
repository: {
|
|
3407
|
+
type: "git",
|
|
3408
|
+
url: "https://github.com/uniform-collab/transformer.git"
|
|
3409
|
+
},
|
|
3410
|
+
dependencies: {
|
|
3411
|
+
chalk: "^5.3.0",
|
|
3412
|
+
commander: "^12.1.0",
|
|
3413
|
+
glob: "^10.3.10",
|
|
3414
|
+
yaml: "^2.4.1",
|
|
3415
|
+
zod: "^3.22.4"
|
|
3416
|
+
},
|
|
3417
|
+
devDependencies: {
|
|
3418
|
+
"@types/node": "^20.11.24",
|
|
3419
|
+
"@typescript-eslint/eslint-plugin": "^7.18.0",
|
|
3420
|
+
"@typescript-eslint/parser": "^7.18.0",
|
|
3421
|
+
"@vitest/coverage-v8": "^1.3.1",
|
|
3422
|
+
eslint: "^8.57.0",
|
|
3423
|
+
prettier: "^3.2.5",
|
|
3424
|
+
tsup: "^8.0.2",
|
|
3425
|
+
tsx: "^4.7.1",
|
|
3426
|
+
typescript: "^5.4.2",
|
|
3427
|
+
vitest: "^1.3.1"
|
|
3428
|
+
},
|
|
3429
|
+
engines: {
|
|
3430
|
+
node: ">=18"
|
|
3431
|
+
}
|
|
3432
|
+
};
|
|
3433
|
+
|
|
3232
3434
|
// src/cli/index.ts
|
|
3233
3435
|
var program = new Command10();
|
|
3234
|
-
|
|
3436
|
+
var appVersion = package_default.version;
|
|
3437
|
+
console.error(`uniform-transform v${appVersion}`);
|
|
3438
|
+
program.name("uniform-transform").description("CLI tool for transforming Uniform.dev serialization files offline").version(appVersion);
|
|
3235
3439
|
program.requiredOption("--rootDir <path>", "Path to the serialization project root").option("--what-if", "Dry run mode - preview changes without modifying files", false).option("--strict", "Enable strict mode for case-sensitive matching", false).option("--compositionsDir <dir>", "Compositions directory name", "composition").option("--componentsDir <dir>", "Components directory name", "component").option("--contentTypesDir <dir>", "Content types directory name", "contentType").option("--assetsDir <dir>", "Assets directory name", "asset").option("--categoriesDir <dir>", "Categories directory name", "category").option("--componentPatternsDir <dir>", "Component patterns directory name", "componentPattern").option(
|
|
3236
3440
|
"--compositionPatternsDir <dir>",
|
|
3237
3441
|
"Composition patterns directory name",
|