@uniformdev/transformer 1.1.43 → 1.1.45
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 +291 -5
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +6 -1
- package/package.json +1 -1
package/dist/cli/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/cli/index.ts
|
|
4
|
-
import { Command as
|
|
4
|
+
import { Command as Command22 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/cli/commands/propagate-root-component-property.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -6908,12 +6908,12 @@ var GenerateMissingProjectMapNodesService = class {
|
|
|
6908
6908
|
}
|
|
6909
6909
|
pathToNodeId(nodePath) {
|
|
6910
6910
|
if (nodePath === "/") return "pmn-group-root";
|
|
6911
|
-
const slug = nodePath.split("/").filter((s) => s.length > 0).join("-");
|
|
6911
|
+
const slug = nodePath.split("/").filter((s) => s.length > 0).join("-").replace(/[\\:*?"<>|]/g, "_");
|
|
6912
6912
|
return `pmn-group-${slug}`;
|
|
6913
6913
|
}
|
|
6914
6914
|
pathToFileName(nodePath) {
|
|
6915
6915
|
if (nodePath === "/") return "root-node.yaml";
|
|
6916
|
-
const slug = nodePath.split("/").filter((s) => s.length > 0).join("-");
|
|
6916
|
+
const slug = nodePath.split("/").filter((s) => s.length > 0).join("-").replace(/[\\:*?"<>|]/g, "_");
|
|
6917
6917
|
return `${slug}-node.yaml`;
|
|
6918
6918
|
}
|
|
6919
6919
|
};
|
|
@@ -7141,10 +7141,295 @@ function createSplitContentTypeCommand() {
|
|
|
7141
7141
|
return command;
|
|
7142
7142
|
}
|
|
7143
7143
|
|
|
7144
|
+
// src/cli/commands/propagate-root-slot.ts
|
|
7145
|
+
import { Command as Command21 } from "commander";
|
|
7146
|
+
|
|
7147
|
+
// src/core/services/root-slot-propagator.service.ts
|
|
7148
|
+
var RootSlotPropagatorService = class {
|
|
7149
|
+
constructor(fileSystem, componentService, compositionService, logger) {
|
|
7150
|
+
this.fileSystem = fileSystem;
|
|
7151
|
+
this.componentService = componentService;
|
|
7152
|
+
this.compositionService = compositionService;
|
|
7153
|
+
this.logger = logger;
|
|
7154
|
+
}
|
|
7155
|
+
async propagate(options) {
|
|
7156
|
+
const {
|
|
7157
|
+
rootDir,
|
|
7158
|
+
componentsDir,
|
|
7159
|
+
compositionsDir,
|
|
7160
|
+
compositionType,
|
|
7161
|
+
slot,
|
|
7162
|
+
targetComponentType,
|
|
7163
|
+
whatIf,
|
|
7164
|
+
strict
|
|
7165
|
+
} = options;
|
|
7166
|
+
const findOptions = { strict };
|
|
7167
|
+
const compositionTypes = this.parseSeparatedValues(compositionType, strict);
|
|
7168
|
+
const slotNames = splitList(slot);
|
|
7169
|
+
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
7170
|
+
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
7171
|
+
const sourceComponents = [];
|
|
7172
|
+
for (const sourceType of compositionTypes) {
|
|
7173
|
+
this.logger.info(`Loading component: ${sourceType}`);
|
|
7174
|
+
try {
|
|
7175
|
+
const { component: sourceComponent, filePath: sourceFilePath } = await this.componentService.loadComponent(fullComponentsDir, sourceType, findOptions);
|
|
7176
|
+
for (const slotName of slotNames) {
|
|
7177
|
+
const slotDef = this.componentService.findSlot(sourceComponent, slotName, findOptions);
|
|
7178
|
+
if (!slotDef) {
|
|
7179
|
+
this.logger.warn(`Slot "${slotName}" not found on component "${sourceType}" \u2014 skipping`);
|
|
7180
|
+
}
|
|
7181
|
+
}
|
|
7182
|
+
sourceComponents.push({ sourceType, sourceFilePath, sourceComponent });
|
|
7183
|
+
this.logger.debug(`Loaded source component "${sourceType}" from ${sourceFilePath}`);
|
|
7184
|
+
} catch (error) {
|
|
7185
|
+
if (error instanceof ComponentNotFoundError) {
|
|
7186
|
+
this.logger.warn(`Component not found: ${sourceType} (searched: ${fullComponentsDir})`);
|
|
7187
|
+
continue;
|
|
7188
|
+
}
|
|
7189
|
+
throw error;
|
|
7190
|
+
}
|
|
7191
|
+
}
|
|
7192
|
+
this.logger.info(`Loading component: ${targetComponentType}`);
|
|
7193
|
+
const { component: targetComponent, filePath: targetFilePath } = await this.componentService.loadComponent(fullComponentsDir, targetComponentType, findOptions);
|
|
7194
|
+
this.logger.debug(`Loaded target component "${targetComponentType}" from ${targetFilePath}`);
|
|
7195
|
+
const compositions = await this.compositionService.findCompositionsByTypes(
|
|
7196
|
+
fullCompositionsDir,
|
|
7197
|
+
compositionTypes,
|
|
7198
|
+
findOptions
|
|
7199
|
+
);
|
|
7200
|
+
this.logger.debug(
|
|
7201
|
+
`Found ${compositions.length} composition(s) matching types [${compositionTypes.join(", ")}]`
|
|
7202
|
+
);
|
|
7203
|
+
const componentTypesInSlot = /* @__PURE__ */ new Set();
|
|
7204
|
+
for (const { composition } of compositions) {
|
|
7205
|
+
const rootSlots = composition.composition.slots ?? {};
|
|
7206
|
+
for (const slotName of slotNames) {
|
|
7207
|
+
const slotContent = rootSlots[slotName] ?? [];
|
|
7208
|
+
for (const instance of slotContent) {
|
|
7209
|
+
if (instance.type) {
|
|
7210
|
+
componentTypesInSlot.add(instance.type);
|
|
7211
|
+
}
|
|
7212
|
+
}
|
|
7213
|
+
}
|
|
7214
|
+
}
|
|
7215
|
+
const collectedTypes = Array.from(componentTypesInSlot).sort();
|
|
7216
|
+
this.logger.info(
|
|
7217
|
+
`Collected component types from slot contents: [${collectedTypes.join(", ")}]`
|
|
7218
|
+
);
|
|
7219
|
+
let modifiedComponent = { ...targetComponent };
|
|
7220
|
+
let componentModified = false;
|
|
7221
|
+
for (const slotName of slotNames) {
|
|
7222
|
+
const existingSlot = this.componentService.findSlot(modifiedComponent, slotName, findOptions);
|
|
7223
|
+
if (!existingSlot) {
|
|
7224
|
+
this.logger.action(whatIf, "CREATE", `Slot "${slotName}" on ${targetComponentType}`);
|
|
7225
|
+
modifiedComponent = this.componentService.addSlot(modifiedComponent, {
|
|
7226
|
+
id: slotName,
|
|
7227
|
+
name: slotName,
|
|
7228
|
+
allowedComponents: collectedTypes
|
|
7229
|
+
});
|
|
7230
|
+
this.logger.debug(
|
|
7231
|
+
`Slot "${slotName}" created on "${targetComponentType}" with allowedComponents: [${collectedTypes.join(", ")}]`
|
|
7232
|
+
);
|
|
7233
|
+
componentModified = true;
|
|
7234
|
+
} else {
|
|
7235
|
+
const existingAllowed = existingSlot.allowedComponents ?? [];
|
|
7236
|
+
const newTypes = collectedTypes.filter(
|
|
7237
|
+
(t) => !existingAllowed.some(
|
|
7238
|
+
(a) => strict ? a === t : a.toLowerCase() === t.toLowerCase()
|
|
7239
|
+
)
|
|
7240
|
+
);
|
|
7241
|
+
if (newTypes.length > 0) {
|
|
7242
|
+
const merged = [...existingAllowed, ...newTypes].sort();
|
|
7243
|
+
this.logger.action(
|
|
7244
|
+
whatIf,
|
|
7245
|
+
"UPDATE",
|
|
7246
|
+
`Slot "${slotName}" allowedComponents on ${targetComponentType}`
|
|
7247
|
+
);
|
|
7248
|
+
this.logger.detail(`\u2192 Adding: ${newTypes.join(", ")}`);
|
|
7249
|
+
modifiedComponent = this.componentService.updateSlotAllowedComponents(
|
|
7250
|
+
modifiedComponent,
|
|
7251
|
+
slotName,
|
|
7252
|
+
merged,
|
|
7253
|
+
findOptions
|
|
7254
|
+
);
|
|
7255
|
+
componentModified = true;
|
|
7256
|
+
} else {
|
|
7257
|
+
this.logger.info(
|
|
7258
|
+
`Slot "${slotName}" on "${targetComponentType}" already has all required allowedComponents`
|
|
7259
|
+
);
|
|
7260
|
+
}
|
|
7261
|
+
}
|
|
7262
|
+
}
|
|
7263
|
+
if (componentModified && !whatIf) {
|
|
7264
|
+
await this.componentService.saveComponent(targetFilePath, modifiedComponent);
|
|
7265
|
+
}
|
|
7266
|
+
let modifiedCompositions = 0;
|
|
7267
|
+
let propagatedInstances = 0;
|
|
7268
|
+
for (const { composition, filePath } of compositions) {
|
|
7269
|
+
const rootSlots = composition.composition.slots ?? {};
|
|
7270
|
+
const instances = this.compositionService.findComponentInstances(
|
|
7271
|
+
composition,
|
|
7272
|
+
targetComponentType,
|
|
7273
|
+
findOptions
|
|
7274
|
+
);
|
|
7275
|
+
if (instances.length === 0) {
|
|
7276
|
+
this.logger.debug(
|
|
7277
|
+
`Skipping "${filePath}": no instances of ${targetComponentType} found`
|
|
7278
|
+
);
|
|
7279
|
+
continue;
|
|
7280
|
+
}
|
|
7281
|
+
const componentsToPropagate = [];
|
|
7282
|
+
for (const slotName of slotNames) {
|
|
7283
|
+
const slotContent = rootSlots[slotName] ?? [];
|
|
7284
|
+
componentsToPropagate.push(...slotContent);
|
|
7285
|
+
}
|
|
7286
|
+
if (componentsToPropagate.length === 0) {
|
|
7287
|
+
this.logger.debug(
|
|
7288
|
+
`Skipping "${filePath}": slot(s) [${slotNames.join(", ")}] are empty`
|
|
7289
|
+
);
|
|
7290
|
+
continue;
|
|
7291
|
+
}
|
|
7292
|
+
let compositionModified = false;
|
|
7293
|
+
const relativePath = filePath.replace(fullCompositionsDir, "").replace(/^[/\\]/, "");
|
|
7294
|
+
const instanceUpdates = [];
|
|
7295
|
+
for (const { instance, instanceId } of instances) {
|
|
7296
|
+
const instanceName = instance._id ?? instanceId;
|
|
7297
|
+
for (const slotName of slotNames) {
|
|
7298
|
+
const slotContent = rootSlots[slotName] ?? [];
|
|
7299
|
+
if (slotContent.length === 0) continue;
|
|
7300
|
+
const clonedComponents = regenerateIds(
|
|
7301
|
+
slotContent,
|
|
7302
|
+
`${instanceName}.${slotName}`
|
|
7303
|
+
);
|
|
7304
|
+
this.addComponentsToInstanceSlot(instance, slotName, clonedComponents);
|
|
7305
|
+
}
|
|
7306
|
+
compositionModified = true;
|
|
7307
|
+
propagatedInstances++;
|
|
7308
|
+
instanceUpdates.push(
|
|
7309
|
+
`${targetComponentType} "${instanceName}": ${componentsToPropagate.length} component(s) \u2192 [${slotNames.join(", ")}]`
|
|
7310
|
+
);
|
|
7311
|
+
this.logger.debug(
|
|
7312
|
+
`Component ${targetComponentType} "${instanceName}": slot(s) [${slotNames.join(", ")}] updated`
|
|
7313
|
+
);
|
|
7314
|
+
}
|
|
7315
|
+
if (compositionModified) {
|
|
7316
|
+
this.logger.action(whatIf, "UPDATE", `composition/${relativePath}`);
|
|
7317
|
+
for (const update of instanceUpdates) {
|
|
7318
|
+
this.logger.detail(`\u2192 ${update}`);
|
|
7319
|
+
}
|
|
7320
|
+
if (!whatIf) {
|
|
7321
|
+
await this.compositionService.saveComposition(filePath, composition);
|
|
7322
|
+
}
|
|
7323
|
+
modifiedCompositions++;
|
|
7324
|
+
}
|
|
7325
|
+
}
|
|
7326
|
+
return {
|
|
7327
|
+
modifiedComponents: componentModified ? 1 : 0,
|
|
7328
|
+
modifiedCompositions,
|
|
7329
|
+
propagatedInstances
|
|
7330
|
+
};
|
|
7331
|
+
}
|
|
7332
|
+
addComponentsToInstanceSlot(instance, slotName, components) {
|
|
7333
|
+
if (!instance.slots) {
|
|
7334
|
+
instance.slots = {};
|
|
7335
|
+
}
|
|
7336
|
+
if (!instance.slots[slotName]) {
|
|
7337
|
+
instance.slots[slotName] = [];
|
|
7338
|
+
}
|
|
7339
|
+
instance.slots[slotName].push(...components);
|
|
7340
|
+
}
|
|
7341
|
+
parseSeparatedValues(value, strict) {
|
|
7342
|
+
const entries = splitList(value);
|
|
7343
|
+
const normalized = [];
|
|
7344
|
+
for (const entry of entries) {
|
|
7345
|
+
const exists = normalized.some(
|
|
7346
|
+
(existing) => strict ? existing === entry : existing.toLowerCase() === entry.toLowerCase()
|
|
7347
|
+
);
|
|
7348
|
+
if (!exists) {
|
|
7349
|
+
normalized.push(entry);
|
|
7350
|
+
}
|
|
7351
|
+
}
|
|
7352
|
+
return normalized;
|
|
7353
|
+
}
|
|
7354
|
+
};
|
|
7355
|
+
|
|
7356
|
+
// src/cli/commands/propagate-root-slot.ts
|
|
7357
|
+
function createPropagateRootSlotCommand() {
|
|
7358
|
+
const command = new Command21("propagate-root-slot");
|
|
7359
|
+
command.description(
|
|
7360
|
+
"Propagates a named slot (with all its component instances) from the root of compositions to every instance of a target component type, keeping the same slot name and updating allowedComponents based on actual slot contents."
|
|
7361
|
+
).option(
|
|
7362
|
+
"--compositionType <type>",
|
|
7363
|
+
"The composition type(s) to process. Supports pipe-separated lists (e.g., RelatedTopicPage|LandingPage)"
|
|
7364
|
+
).option(
|
|
7365
|
+
"--slot <slot>",
|
|
7366
|
+
"The slot name to propagate. The same slot name is used on both the source root and the target component. Supports pipe-separated lists."
|
|
7367
|
+
).option(
|
|
7368
|
+
"--targetComponentType <type>",
|
|
7369
|
+
"The component type that will receive the slot contents"
|
|
7370
|
+
).option("--verbose", "Enable verbose output with detailed progress information").hook("preAction", (thisCommand) => {
|
|
7371
|
+
const opts = thisCommand.opts();
|
|
7372
|
+
const requiredOptions = [
|
|
7373
|
+
{ name: "compositionType", flag: "--compositionType" },
|
|
7374
|
+
{ name: "slot", flag: "--slot" },
|
|
7375
|
+
{ name: "targetComponentType", flag: "--targetComponentType" }
|
|
7376
|
+
];
|
|
7377
|
+
const missing = requiredOptions.filter((opt) => !opts[opt.name]).map((opt) => opt.flag);
|
|
7378
|
+
if (missing.length > 0) {
|
|
7379
|
+
console.error(`error: missing required options: ${missing.join(", ")}`);
|
|
7380
|
+
process.exit(1);
|
|
7381
|
+
}
|
|
7382
|
+
}).action(async (opts, cmd) => {
|
|
7383
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7384
|
+
const options = {
|
|
7385
|
+
...globalOpts,
|
|
7386
|
+
compositionType: opts.compositionType,
|
|
7387
|
+
slot: opts.slot,
|
|
7388
|
+
targetComponentType: opts.targetComponentType
|
|
7389
|
+
};
|
|
7390
|
+
const logger = new Logger(opts.verbose ?? false);
|
|
7391
|
+
const fileSystem = new FileSystemService();
|
|
7392
|
+
const componentService = new ComponentService(fileSystem);
|
|
7393
|
+
const compositionService = new CompositionService(fileSystem);
|
|
7394
|
+
const propagator = new RootSlotPropagatorService(
|
|
7395
|
+
fileSystem,
|
|
7396
|
+
componentService,
|
|
7397
|
+
compositionService,
|
|
7398
|
+
logger
|
|
7399
|
+
);
|
|
7400
|
+
try {
|
|
7401
|
+
const result = await propagator.propagate({
|
|
7402
|
+
rootDir: options.rootDir,
|
|
7403
|
+
componentsDir: options.componentsDir,
|
|
7404
|
+
compositionsDir: options.compositionsDir,
|
|
7405
|
+
compositionType: options.compositionType,
|
|
7406
|
+
slot: options.slot,
|
|
7407
|
+
targetComponentType: options.targetComponentType,
|
|
7408
|
+
whatIf: options.whatIf ?? false,
|
|
7409
|
+
strict: options.strict ?? false
|
|
7410
|
+
});
|
|
7411
|
+
logger.success(
|
|
7412
|
+
`Modified ${result.modifiedComponents} component(s), ${result.modifiedCompositions} composition(s), propagated to ${result.propagatedInstances} instance(s)`
|
|
7413
|
+
);
|
|
7414
|
+
} catch (error) {
|
|
7415
|
+
if (error instanceof ComponentNotFoundError) {
|
|
7416
|
+
logger.warn(error.message);
|
|
7417
|
+
return;
|
|
7418
|
+
}
|
|
7419
|
+
if (error instanceof TransformError) {
|
|
7420
|
+
logger.error(error.message);
|
|
7421
|
+
process.exit(1);
|
|
7422
|
+
}
|
|
7423
|
+
throw error;
|
|
7424
|
+
}
|
|
7425
|
+
});
|
|
7426
|
+
return command;
|
|
7427
|
+
}
|
|
7428
|
+
|
|
7144
7429
|
// package.json
|
|
7145
7430
|
var package_default = {
|
|
7146
7431
|
name: "@uniformdev/transformer",
|
|
7147
|
-
version: "1.1.
|
|
7432
|
+
version: "1.1.45",
|
|
7148
7433
|
description: "CLI tool for transforming Uniform.dev serialization files offline",
|
|
7149
7434
|
type: "module",
|
|
7150
7435
|
bin: {
|
|
@@ -7213,7 +7498,7 @@ var package_default = {
|
|
|
7213
7498
|
};
|
|
7214
7499
|
|
|
7215
7500
|
// src/cli/index.ts
|
|
7216
|
-
var program = new
|
|
7501
|
+
var program = new Command22();
|
|
7217
7502
|
var appVersion = package_default.version;
|
|
7218
7503
|
console.error(`uniform-transform v${appVersion}`);
|
|
7219
7504
|
program.name("uniform-transform").description("CLI tool for transforming Uniform.dev serialization files offline").version(appVersion);
|
|
@@ -7249,5 +7534,6 @@ program.addCommand(createRemoveUnusedContentTypesCommand());
|
|
|
7249
7534
|
program.addCommand(createRemoveUnusedComponentTypesCommand());
|
|
7250
7535
|
program.addCommand(createGenerateMissingProjectMapNodesCommand());
|
|
7251
7536
|
program.addCommand(createSplitContentTypeCommand());
|
|
7537
|
+
program.addCommand(createPropagateRootSlotCommand());
|
|
7252
7538
|
program.parse();
|
|
7253
7539
|
//# sourceMappingURL=index.js.map
|