@uniformdev/transformer 1.1.44 → 1.1.46
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 +326 -22
- 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";
|
|
@@ -6173,7 +6173,7 @@ function createFlattenBlockFieldCommand() {
|
|
|
6173
6173
|
const command = new Command15("flatten-block-field");
|
|
6174
6174
|
command.description(
|
|
6175
6175
|
"Dissolves a $block parameter by lifting the block content type fields onto the component and extracting block item values into composition instances directly."
|
|
6176
|
-
).option("--componentId <id>", "The ID of the component that
|
|
6176
|
+
).option("--componentId <id>", "The ID (or ,;|-separated list of IDs) of the component(s) that own the block parameter").option("--parameterId <id>", "The ID of the $block parameter to flatten").option("--excludeFields <ids>", "Comma-separated list of block content type field IDs to skip when flattening").hook("preAction", (thisCommand) => {
|
|
6177
6177
|
const opts = thisCommand.opts();
|
|
6178
6178
|
const requiredOptions = [
|
|
6179
6179
|
{ name: "componentId", flag: "--componentId" },
|
|
@@ -6193,31 +6193,49 @@ function createFlattenBlockFieldCommand() {
|
|
|
6193
6193
|
excludeFields: opts.excludeFields
|
|
6194
6194
|
};
|
|
6195
6195
|
const logger = new Logger();
|
|
6196
|
+
logger.info(`componentId: ${options.componentId}`);
|
|
6197
|
+
logger.info(`parameterId: ${options.parameterId}`);
|
|
6198
|
+
logger.info(`excludeFields: ${options.excludeFields ?? ""}`);
|
|
6196
6199
|
const fileSystem = new FileSystemService();
|
|
6197
6200
|
const componentService = new ComponentService(fileSystem);
|
|
6198
6201
|
const flattener = new BlockFieldFlattenerService(fileSystem, componentService, logger);
|
|
6202
|
+
const componentIds = splitList(options.componentId);
|
|
6203
|
+
const aggregate = {
|
|
6204
|
+
compositionsModified: 0,
|
|
6205
|
+
compositionPatternsModified: 0,
|
|
6206
|
+
componentPatternsModified: 0
|
|
6207
|
+
};
|
|
6199
6208
|
try {
|
|
6200
|
-
const
|
|
6201
|
-
|
|
6202
|
-
|
|
6203
|
-
|
|
6204
|
-
|
|
6205
|
-
|
|
6206
|
-
|
|
6207
|
-
|
|
6208
|
-
|
|
6209
|
-
|
|
6210
|
-
|
|
6211
|
-
|
|
6212
|
-
|
|
6209
|
+
for (const componentId of componentIds) {
|
|
6210
|
+
try {
|
|
6211
|
+
const result = await flattener.flatten({
|
|
6212
|
+
rootDir: options.rootDir,
|
|
6213
|
+
componentsDir: options.componentsDir,
|
|
6214
|
+
compositionsDir: options.compositionsDir,
|
|
6215
|
+
compositionPatternsDir: options.compositionPatternsDir,
|
|
6216
|
+
componentPatternsDir: options.componentPatternsDir,
|
|
6217
|
+
contentTypesDir: options.contentTypesDir,
|
|
6218
|
+
componentId,
|
|
6219
|
+
parameterId: options.parameterId,
|
|
6220
|
+
whatIf: options.whatIf ?? false,
|
|
6221
|
+
strict: options.strict ?? false,
|
|
6222
|
+
excludeFields: options.excludeFields ? options.excludeFields.split(",").map((s) => s.trim()) : []
|
|
6223
|
+
});
|
|
6224
|
+
aggregate.compositionsModified += result.compositionsModified;
|
|
6225
|
+
aggregate.compositionPatternsModified += result.compositionPatternsModified;
|
|
6226
|
+
aggregate.componentPatternsModified += result.componentPatternsModified;
|
|
6227
|
+
} catch (error) {
|
|
6228
|
+
if (error instanceof ComponentNotFoundError || error instanceof PropertyNotFoundError) {
|
|
6229
|
+
logger.warn(error.message);
|
|
6230
|
+
continue;
|
|
6231
|
+
}
|
|
6232
|
+
throw error;
|
|
6233
|
+
}
|
|
6234
|
+
}
|
|
6213
6235
|
logger.success(
|
|
6214
|
-
`Flattened parameter "${options.parameterId}" on component "${options.componentId}": ${
|
|
6236
|
+
`Flattened parameter "${options.parameterId}" on component "${options.componentId}": ${aggregate.compositionsModified} composition(s), ${aggregate.compositionPatternsModified} composition pattern(s), ${aggregate.componentPatternsModified} component pattern(s) updated`
|
|
6215
6237
|
);
|
|
6216
6238
|
} catch (error) {
|
|
6217
|
-
if (error instanceof ComponentNotFoundError || error instanceof PropertyNotFoundError) {
|
|
6218
|
-
logger.warn(error.message);
|
|
6219
|
-
return;
|
|
6220
|
-
}
|
|
6221
6239
|
if (error instanceof TransformError) {
|
|
6222
6240
|
logger.error(error.message);
|
|
6223
6241
|
process.exit(1);
|
|
@@ -7141,10 +7159,295 @@ function createSplitContentTypeCommand() {
|
|
|
7141
7159
|
return command;
|
|
7142
7160
|
}
|
|
7143
7161
|
|
|
7162
|
+
// src/cli/commands/propagate-root-slot.ts
|
|
7163
|
+
import { Command as Command21 } from "commander";
|
|
7164
|
+
|
|
7165
|
+
// src/core/services/root-slot-propagator.service.ts
|
|
7166
|
+
var RootSlotPropagatorService = class {
|
|
7167
|
+
constructor(fileSystem, componentService, compositionService, logger) {
|
|
7168
|
+
this.fileSystem = fileSystem;
|
|
7169
|
+
this.componentService = componentService;
|
|
7170
|
+
this.compositionService = compositionService;
|
|
7171
|
+
this.logger = logger;
|
|
7172
|
+
}
|
|
7173
|
+
async propagate(options) {
|
|
7174
|
+
const {
|
|
7175
|
+
rootDir,
|
|
7176
|
+
componentsDir,
|
|
7177
|
+
compositionsDir,
|
|
7178
|
+
compositionType,
|
|
7179
|
+
slot,
|
|
7180
|
+
targetComponentType,
|
|
7181
|
+
whatIf,
|
|
7182
|
+
strict
|
|
7183
|
+
} = options;
|
|
7184
|
+
const findOptions = { strict };
|
|
7185
|
+
const compositionTypes = this.parseSeparatedValues(compositionType, strict);
|
|
7186
|
+
const slotNames = splitList(slot);
|
|
7187
|
+
const fullComponentsDir = this.fileSystem.resolvePath(rootDir, componentsDir);
|
|
7188
|
+
const fullCompositionsDir = this.fileSystem.resolvePath(rootDir, compositionsDir);
|
|
7189
|
+
const sourceComponents = [];
|
|
7190
|
+
for (const sourceType of compositionTypes) {
|
|
7191
|
+
this.logger.info(`Loading component: ${sourceType}`);
|
|
7192
|
+
try {
|
|
7193
|
+
const { component: sourceComponent, filePath: sourceFilePath } = await this.componentService.loadComponent(fullComponentsDir, sourceType, findOptions);
|
|
7194
|
+
for (const slotName of slotNames) {
|
|
7195
|
+
const slotDef = this.componentService.findSlot(sourceComponent, slotName, findOptions);
|
|
7196
|
+
if (!slotDef) {
|
|
7197
|
+
this.logger.warn(`Slot "${slotName}" not found on component "${sourceType}" \u2014 skipping`);
|
|
7198
|
+
}
|
|
7199
|
+
}
|
|
7200
|
+
sourceComponents.push({ sourceType, sourceFilePath, sourceComponent });
|
|
7201
|
+
this.logger.debug(`Loaded source component "${sourceType}" from ${sourceFilePath}`);
|
|
7202
|
+
} catch (error) {
|
|
7203
|
+
if (error instanceof ComponentNotFoundError) {
|
|
7204
|
+
this.logger.warn(`Component not found: ${sourceType} (searched: ${fullComponentsDir})`);
|
|
7205
|
+
continue;
|
|
7206
|
+
}
|
|
7207
|
+
throw error;
|
|
7208
|
+
}
|
|
7209
|
+
}
|
|
7210
|
+
this.logger.info(`Loading component: ${targetComponentType}`);
|
|
7211
|
+
const { component: targetComponent, filePath: targetFilePath } = await this.componentService.loadComponent(fullComponentsDir, targetComponentType, findOptions);
|
|
7212
|
+
this.logger.debug(`Loaded target component "${targetComponentType}" from ${targetFilePath}`);
|
|
7213
|
+
const compositions = await this.compositionService.findCompositionsByTypes(
|
|
7214
|
+
fullCompositionsDir,
|
|
7215
|
+
compositionTypes,
|
|
7216
|
+
findOptions
|
|
7217
|
+
);
|
|
7218
|
+
this.logger.debug(
|
|
7219
|
+
`Found ${compositions.length} composition(s) matching types [${compositionTypes.join(", ")}]`
|
|
7220
|
+
);
|
|
7221
|
+
const componentTypesInSlot = /* @__PURE__ */ new Set();
|
|
7222
|
+
for (const { composition } of compositions) {
|
|
7223
|
+
const rootSlots = composition.composition.slots ?? {};
|
|
7224
|
+
for (const slotName of slotNames) {
|
|
7225
|
+
const slotContent = rootSlots[slotName] ?? [];
|
|
7226
|
+
for (const instance of slotContent) {
|
|
7227
|
+
if (instance.type) {
|
|
7228
|
+
componentTypesInSlot.add(instance.type);
|
|
7229
|
+
}
|
|
7230
|
+
}
|
|
7231
|
+
}
|
|
7232
|
+
}
|
|
7233
|
+
const collectedTypes = Array.from(componentTypesInSlot).sort();
|
|
7234
|
+
this.logger.info(
|
|
7235
|
+
`Collected component types from slot contents: [${collectedTypes.join(", ")}]`
|
|
7236
|
+
);
|
|
7237
|
+
let modifiedComponent = { ...targetComponent };
|
|
7238
|
+
let componentModified = false;
|
|
7239
|
+
for (const slotName of slotNames) {
|
|
7240
|
+
const existingSlot = this.componentService.findSlot(modifiedComponent, slotName, findOptions);
|
|
7241
|
+
if (!existingSlot) {
|
|
7242
|
+
this.logger.action(whatIf, "CREATE", `Slot "${slotName}" on ${targetComponentType}`);
|
|
7243
|
+
modifiedComponent = this.componentService.addSlot(modifiedComponent, {
|
|
7244
|
+
id: slotName,
|
|
7245
|
+
name: slotName,
|
|
7246
|
+
allowedComponents: collectedTypes
|
|
7247
|
+
});
|
|
7248
|
+
this.logger.debug(
|
|
7249
|
+
`Slot "${slotName}" created on "${targetComponentType}" with allowedComponents: [${collectedTypes.join(", ")}]`
|
|
7250
|
+
);
|
|
7251
|
+
componentModified = true;
|
|
7252
|
+
} else {
|
|
7253
|
+
const existingAllowed = existingSlot.allowedComponents ?? [];
|
|
7254
|
+
const newTypes = collectedTypes.filter(
|
|
7255
|
+
(t) => !existingAllowed.some(
|
|
7256
|
+
(a) => strict ? a === t : a.toLowerCase() === t.toLowerCase()
|
|
7257
|
+
)
|
|
7258
|
+
);
|
|
7259
|
+
if (newTypes.length > 0) {
|
|
7260
|
+
const merged = [...existingAllowed, ...newTypes].sort();
|
|
7261
|
+
this.logger.action(
|
|
7262
|
+
whatIf,
|
|
7263
|
+
"UPDATE",
|
|
7264
|
+
`Slot "${slotName}" allowedComponents on ${targetComponentType}`
|
|
7265
|
+
);
|
|
7266
|
+
this.logger.detail(`\u2192 Adding: ${newTypes.join(", ")}`);
|
|
7267
|
+
modifiedComponent = this.componentService.updateSlotAllowedComponents(
|
|
7268
|
+
modifiedComponent,
|
|
7269
|
+
slotName,
|
|
7270
|
+
merged,
|
|
7271
|
+
findOptions
|
|
7272
|
+
);
|
|
7273
|
+
componentModified = true;
|
|
7274
|
+
} else {
|
|
7275
|
+
this.logger.info(
|
|
7276
|
+
`Slot "${slotName}" on "${targetComponentType}" already has all required allowedComponents`
|
|
7277
|
+
);
|
|
7278
|
+
}
|
|
7279
|
+
}
|
|
7280
|
+
}
|
|
7281
|
+
if (componentModified && !whatIf) {
|
|
7282
|
+
await this.componentService.saveComponent(targetFilePath, modifiedComponent);
|
|
7283
|
+
}
|
|
7284
|
+
let modifiedCompositions = 0;
|
|
7285
|
+
let propagatedInstances = 0;
|
|
7286
|
+
for (const { composition, filePath } of compositions) {
|
|
7287
|
+
const rootSlots = composition.composition.slots ?? {};
|
|
7288
|
+
const instances = this.compositionService.findComponentInstances(
|
|
7289
|
+
composition,
|
|
7290
|
+
targetComponentType,
|
|
7291
|
+
findOptions
|
|
7292
|
+
);
|
|
7293
|
+
if (instances.length === 0) {
|
|
7294
|
+
this.logger.debug(
|
|
7295
|
+
`Skipping "${filePath}": no instances of ${targetComponentType} found`
|
|
7296
|
+
);
|
|
7297
|
+
continue;
|
|
7298
|
+
}
|
|
7299
|
+
const componentsToPropagate = [];
|
|
7300
|
+
for (const slotName of slotNames) {
|
|
7301
|
+
const slotContent = rootSlots[slotName] ?? [];
|
|
7302
|
+
componentsToPropagate.push(...slotContent);
|
|
7303
|
+
}
|
|
7304
|
+
if (componentsToPropagate.length === 0) {
|
|
7305
|
+
this.logger.debug(
|
|
7306
|
+
`Skipping "${filePath}": slot(s) [${slotNames.join(", ")}] are empty`
|
|
7307
|
+
);
|
|
7308
|
+
continue;
|
|
7309
|
+
}
|
|
7310
|
+
let compositionModified = false;
|
|
7311
|
+
const relativePath = filePath.replace(fullCompositionsDir, "").replace(/^[/\\]/, "");
|
|
7312
|
+
const instanceUpdates = [];
|
|
7313
|
+
for (const { instance, instanceId } of instances) {
|
|
7314
|
+
const instanceName = instance._id ?? instanceId;
|
|
7315
|
+
for (const slotName of slotNames) {
|
|
7316
|
+
const slotContent = rootSlots[slotName] ?? [];
|
|
7317
|
+
if (slotContent.length === 0) continue;
|
|
7318
|
+
const clonedComponents = regenerateIds(
|
|
7319
|
+
slotContent,
|
|
7320
|
+
`${instanceName}.${slotName}`
|
|
7321
|
+
);
|
|
7322
|
+
this.addComponentsToInstanceSlot(instance, slotName, clonedComponents);
|
|
7323
|
+
}
|
|
7324
|
+
compositionModified = true;
|
|
7325
|
+
propagatedInstances++;
|
|
7326
|
+
instanceUpdates.push(
|
|
7327
|
+
`${targetComponentType} "${instanceName}": ${componentsToPropagate.length} component(s) \u2192 [${slotNames.join(", ")}]`
|
|
7328
|
+
);
|
|
7329
|
+
this.logger.debug(
|
|
7330
|
+
`Component ${targetComponentType} "${instanceName}": slot(s) [${slotNames.join(", ")}] updated`
|
|
7331
|
+
);
|
|
7332
|
+
}
|
|
7333
|
+
if (compositionModified) {
|
|
7334
|
+
this.logger.action(whatIf, "UPDATE", `composition/${relativePath}`);
|
|
7335
|
+
for (const update of instanceUpdates) {
|
|
7336
|
+
this.logger.detail(`\u2192 ${update}`);
|
|
7337
|
+
}
|
|
7338
|
+
if (!whatIf) {
|
|
7339
|
+
await this.compositionService.saveComposition(filePath, composition);
|
|
7340
|
+
}
|
|
7341
|
+
modifiedCompositions++;
|
|
7342
|
+
}
|
|
7343
|
+
}
|
|
7344
|
+
return {
|
|
7345
|
+
modifiedComponents: componentModified ? 1 : 0,
|
|
7346
|
+
modifiedCompositions,
|
|
7347
|
+
propagatedInstances
|
|
7348
|
+
};
|
|
7349
|
+
}
|
|
7350
|
+
addComponentsToInstanceSlot(instance, slotName, components) {
|
|
7351
|
+
if (!instance.slots) {
|
|
7352
|
+
instance.slots = {};
|
|
7353
|
+
}
|
|
7354
|
+
if (!instance.slots[slotName]) {
|
|
7355
|
+
instance.slots[slotName] = [];
|
|
7356
|
+
}
|
|
7357
|
+
instance.slots[slotName].push(...components);
|
|
7358
|
+
}
|
|
7359
|
+
parseSeparatedValues(value, strict) {
|
|
7360
|
+
const entries = splitList(value);
|
|
7361
|
+
const normalized = [];
|
|
7362
|
+
for (const entry of entries) {
|
|
7363
|
+
const exists = normalized.some(
|
|
7364
|
+
(existing) => strict ? existing === entry : existing.toLowerCase() === entry.toLowerCase()
|
|
7365
|
+
);
|
|
7366
|
+
if (!exists) {
|
|
7367
|
+
normalized.push(entry);
|
|
7368
|
+
}
|
|
7369
|
+
}
|
|
7370
|
+
return normalized;
|
|
7371
|
+
}
|
|
7372
|
+
};
|
|
7373
|
+
|
|
7374
|
+
// src/cli/commands/propagate-root-slot.ts
|
|
7375
|
+
function createPropagateRootSlotCommand() {
|
|
7376
|
+
const command = new Command21("propagate-root-slot");
|
|
7377
|
+
command.description(
|
|
7378
|
+
"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."
|
|
7379
|
+
).option(
|
|
7380
|
+
"--compositionType <type>",
|
|
7381
|
+
"The composition type(s) to process. Supports pipe-separated lists (e.g., RelatedTopicPage|LandingPage)"
|
|
7382
|
+
).option(
|
|
7383
|
+
"--slot <slot>",
|
|
7384
|
+
"The slot name to propagate. The same slot name is used on both the source root and the target component. Supports pipe-separated lists."
|
|
7385
|
+
).option(
|
|
7386
|
+
"--targetComponentType <type>",
|
|
7387
|
+
"The component type that will receive the slot contents"
|
|
7388
|
+
).option("--verbose", "Enable verbose output with detailed progress information").hook("preAction", (thisCommand) => {
|
|
7389
|
+
const opts = thisCommand.opts();
|
|
7390
|
+
const requiredOptions = [
|
|
7391
|
+
{ name: "compositionType", flag: "--compositionType" },
|
|
7392
|
+
{ name: "slot", flag: "--slot" },
|
|
7393
|
+
{ name: "targetComponentType", flag: "--targetComponentType" }
|
|
7394
|
+
];
|
|
7395
|
+
const missing = requiredOptions.filter((opt) => !opts[opt.name]).map((opt) => opt.flag);
|
|
7396
|
+
if (missing.length > 0) {
|
|
7397
|
+
console.error(`error: missing required options: ${missing.join(", ")}`);
|
|
7398
|
+
process.exit(1);
|
|
7399
|
+
}
|
|
7400
|
+
}).action(async (opts, cmd) => {
|
|
7401
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7402
|
+
const options = {
|
|
7403
|
+
...globalOpts,
|
|
7404
|
+
compositionType: opts.compositionType,
|
|
7405
|
+
slot: opts.slot,
|
|
7406
|
+
targetComponentType: opts.targetComponentType
|
|
7407
|
+
};
|
|
7408
|
+
const logger = new Logger(opts.verbose ?? false);
|
|
7409
|
+
const fileSystem = new FileSystemService();
|
|
7410
|
+
const componentService = new ComponentService(fileSystem);
|
|
7411
|
+
const compositionService = new CompositionService(fileSystem);
|
|
7412
|
+
const propagator = new RootSlotPropagatorService(
|
|
7413
|
+
fileSystem,
|
|
7414
|
+
componentService,
|
|
7415
|
+
compositionService,
|
|
7416
|
+
logger
|
|
7417
|
+
);
|
|
7418
|
+
try {
|
|
7419
|
+
const result = await propagator.propagate({
|
|
7420
|
+
rootDir: options.rootDir,
|
|
7421
|
+
componentsDir: options.componentsDir,
|
|
7422
|
+
compositionsDir: options.compositionsDir,
|
|
7423
|
+
compositionType: options.compositionType,
|
|
7424
|
+
slot: options.slot,
|
|
7425
|
+
targetComponentType: options.targetComponentType,
|
|
7426
|
+
whatIf: options.whatIf ?? false,
|
|
7427
|
+
strict: options.strict ?? false
|
|
7428
|
+
});
|
|
7429
|
+
logger.success(
|
|
7430
|
+
`Modified ${result.modifiedComponents} component(s), ${result.modifiedCompositions} composition(s), propagated to ${result.propagatedInstances} instance(s)`
|
|
7431
|
+
);
|
|
7432
|
+
} catch (error) {
|
|
7433
|
+
if (error instanceof ComponentNotFoundError) {
|
|
7434
|
+
logger.warn(error.message);
|
|
7435
|
+
return;
|
|
7436
|
+
}
|
|
7437
|
+
if (error instanceof TransformError) {
|
|
7438
|
+
logger.error(error.message);
|
|
7439
|
+
process.exit(1);
|
|
7440
|
+
}
|
|
7441
|
+
throw error;
|
|
7442
|
+
}
|
|
7443
|
+
});
|
|
7444
|
+
return command;
|
|
7445
|
+
}
|
|
7446
|
+
|
|
7144
7447
|
// package.json
|
|
7145
7448
|
var package_default = {
|
|
7146
7449
|
name: "@uniformdev/transformer",
|
|
7147
|
-
version: "1.1.
|
|
7450
|
+
version: "1.1.46",
|
|
7148
7451
|
description: "CLI tool for transforming Uniform.dev serialization files offline",
|
|
7149
7452
|
type: "module",
|
|
7150
7453
|
bin: {
|
|
@@ -7213,7 +7516,7 @@ var package_default = {
|
|
|
7213
7516
|
};
|
|
7214
7517
|
|
|
7215
7518
|
// src/cli/index.ts
|
|
7216
|
-
var program = new
|
|
7519
|
+
var program = new Command22();
|
|
7217
7520
|
var appVersion = package_default.version;
|
|
7218
7521
|
console.error(`uniform-transform v${appVersion}`);
|
|
7219
7522
|
program.name("uniform-transform").description("CLI tool for transforming Uniform.dev serialization files offline").version(appVersion);
|
|
@@ -7249,5 +7552,6 @@ program.addCommand(createRemoveUnusedContentTypesCommand());
|
|
|
7249
7552
|
program.addCommand(createRemoveUnusedComponentTypesCommand());
|
|
7250
7553
|
program.addCommand(createGenerateMissingProjectMapNodesCommand());
|
|
7251
7554
|
program.addCommand(createSplitContentTypeCommand());
|
|
7555
|
+
program.addCommand(createPropagateRootSlotCommand());
|
|
7252
7556
|
program.parse();
|
|
7253
7557
|
//# sourceMappingURL=index.js.map
|