@uniformdev/transformer 1.1.42 → 1.1.43
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 +202 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +7 -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 Command21 } from "commander";
|
|
5
5
|
|
|
6
6
|
// src/cli/commands/propagate-root-component-property.ts
|
|
7
7
|
import { Command } from "commander";
|
|
@@ -6943,10 +6943,208 @@ function createGenerateMissingProjectMapNodesCommand() {
|
|
|
6943
6943
|
return command;
|
|
6944
6944
|
}
|
|
6945
6945
|
|
|
6946
|
+
// src/cli/commands/split-content-type.ts
|
|
6947
|
+
import { Command as Command20 } from "commander";
|
|
6948
|
+
|
|
6949
|
+
// src/core/services/content-type-splitter.service.ts
|
|
6950
|
+
var ContentTypeSplitterService = class {
|
|
6951
|
+
constructor(fileSystem, logger) {
|
|
6952
|
+
this.fileSystem = fileSystem;
|
|
6953
|
+
this.logger = logger;
|
|
6954
|
+
}
|
|
6955
|
+
async split(options) {
|
|
6956
|
+
const {
|
|
6957
|
+
rootDir,
|
|
6958
|
+
contentTypesDir,
|
|
6959
|
+
entriesDir,
|
|
6960
|
+
contentType,
|
|
6961
|
+
newContentType,
|
|
6962
|
+
fieldId,
|
|
6963
|
+
fieldContains,
|
|
6964
|
+
whatIf,
|
|
6965
|
+
strict
|
|
6966
|
+
} = options;
|
|
6967
|
+
const ctDirFull = this.fileSystem.resolvePath(rootDir, contentTypesDir);
|
|
6968
|
+
const ctDirExists = await this.fileSystem.fileExists(ctDirFull);
|
|
6969
|
+
if (!ctDirExists) {
|
|
6970
|
+
this.logger.warn(`Content types directory not found: ${contentTypesDir}`);
|
|
6971
|
+
return { contentTypeCreated: false, entriesScanned: 0, entriesUpdated: 0 };
|
|
6972
|
+
}
|
|
6973
|
+
const ctFiles = await this.fileSystem.findFiles(ctDirFull, "**/*.{json,yaml,yml}");
|
|
6974
|
+
let sourceCtFilePath;
|
|
6975
|
+
let sourceCt;
|
|
6976
|
+
let newCtExists = false;
|
|
6977
|
+
for (const filePath of ctFiles) {
|
|
6978
|
+
let ct;
|
|
6979
|
+
try {
|
|
6980
|
+
ct = await this.fileSystem.readFile(filePath);
|
|
6981
|
+
} catch {
|
|
6982
|
+
this.logger.warn(`Could not read content type file: ${filePath} \u2014 skipping`);
|
|
6983
|
+
continue;
|
|
6984
|
+
}
|
|
6985
|
+
if (!ct?.id) continue;
|
|
6986
|
+
if (this.matchesId(ct.id, contentType, strict)) {
|
|
6987
|
+
sourceCtFilePath = filePath;
|
|
6988
|
+
sourceCt = ct;
|
|
6989
|
+
}
|
|
6990
|
+
if (this.matchesId(ct.id, newContentType, strict)) {
|
|
6991
|
+
newCtExists = true;
|
|
6992
|
+
}
|
|
6993
|
+
}
|
|
6994
|
+
if (!sourceCtFilePath || !sourceCt) {
|
|
6995
|
+
this.logger.warn(`Content type "${contentType}" not found in ${contentTypesDir}`);
|
|
6996
|
+
return { contentTypeCreated: false, entriesScanned: 0, entriesUpdated: 0 };
|
|
6997
|
+
}
|
|
6998
|
+
let contentTypeCreated = false;
|
|
6999
|
+
if (newCtExists) {
|
|
7000
|
+
this.logger.info(`Content type "${newContentType}" already exists \u2014 skipping creation`);
|
|
7001
|
+
} else {
|
|
7002
|
+
const newCt = {
|
|
7003
|
+
...sourceCt,
|
|
7004
|
+
id: newContentType,
|
|
7005
|
+
name: newContentType
|
|
7006
|
+
};
|
|
7007
|
+
const ext = this.fileSystem.getExtension(sourceCtFilePath) || ".yaml";
|
|
7008
|
+
const newCtFilePath = this.fileSystem.resolvePath(ctDirFull, `${newContentType}${ext}`);
|
|
7009
|
+
const relPath = `${contentTypesDir}/${newContentType}${ext}`;
|
|
7010
|
+
this.logger.action(whatIf, "CREATE", relPath);
|
|
7011
|
+
if (!whatIf) {
|
|
7012
|
+
await this.fileSystem.writeFile(newCtFilePath, newCt);
|
|
7013
|
+
}
|
|
7014
|
+
contentTypeCreated = true;
|
|
7015
|
+
}
|
|
7016
|
+
const entriesDirFull = this.fileSystem.resolvePath(rootDir, entriesDir);
|
|
7017
|
+
const entriesDirExists = await this.fileSystem.fileExists(entriesDirFull);
|
|
7018
|
+
if (!entriesDirExists) {
|
|
7019
|
+
this.logger.warn(`Entries directory not found: ${entriesDir}`);
|
|
7020
|
+
return { contentTypeCreated, entriesScanned: 0, entriesUpdated: 0 };
|
|
7021
|
+
}
|
|
7022
|
+
const entryFiles = await this.fileSystem.findFiles(entriesDirFull, "**/*.{json,yaml,yml}");
|
|
7023
|
+
this.logger.info(`Scanning ${entryFiles.length} entry file(s)`);
|
|
7024
|
+
let entriesScanned = 0;
|
|
7025
|
+
let entriesUpdated = 0;
|
|
7026
|
+
for (const filePath of entryFiles) {
|
|
7027
|
+
let entryData;
|
|
7028
|
+
try {
|
|
7029
|
+
entryData = await this.fileSystem.readFile(filePath);
|
|
7030
|
+
} catch {
|
|
7031
|
+
this.logger.warn(`Could not read entry file: ${filePath} \u2014 skipping`);
|
|
7032
|
+
continue;
|
|
7033
|
+
}
|
|
7034
|
+
if (!entryData?.entry?.type) continue;
|
|
7035
|
+
if (!this.matchesId(entryData.entry.type, contentType, strict)) continue;
|
|
7036
|
+
entriesScanned++;
|
|
7037
|
+
const fields = entryData.entry.fields;
|
|
7038
|
+
if (!fields || typeof fields !== "object") {
|
|
7039
|
+
this.logger.warn(`Entry "${entryData.entry._id}" has no fields \u2014 skipping`);
|
|
7040
|
+
continue;
|
|
7041
|
+
}
|
|
7042
|
+
if (!(fieldId in fields)) {
|
|
7043
|
+
this.logger.warn(
|
|
7044
|
+
`Entry "${entryData.entry._id}" does not have field "${fieldId}" \u2014 skipping`
|
|
7045
|
+
);
|
|
7046
|
+
continue;
|
|
7047
|
+
}
|
|
7048
|
+
const field = fields[fieldId];
|
|
7049
|
+
const fieldValueStr = this.getFieldValueString(field);
|
|
7050
|
+
if (!this.containsValue(fieldValueStr, fieldContains, strict)) continue;
|
|
7051
|
+
const relPath = this.fileSystem.joinPath(
|
|
7052
|
+
entriesDir,
|
|
7053
|
+
this.fileSystem.getBasename(filePath)
|
|
7054
|
+
);
|
|
7055
|
+
this.logger.action(
|
|
7056
|
+
whatIf,
|
|
7057
|
+
"UPDATE",
|
|
7058
|
+
`${relPath}: type ${entryData.entry.type} \u2192 ${newContentType}`
|
|
7059
|
+
);
|
|
7060
|
+
if (!whatIf) {
|
|
7061
|
+
const updatedEntry = {
|
|
7062
|
+
...entryData,
|
|
7063
|
+
entry: { ...entryData.entry, type: newContentType }
|
|
7064
|
+
};
|
|
7065
|
+
await this.fileSystem.writeFile(filePath, updatedEntry);
|
|
7066
|
+
}
|
|
7067
|
+
entriesUpdated++;
|
|
7068
|
+
}
|
|
7069
|
+
return { contentTypeCreated, entriesScanned, entriesUpdated };
|
|
7070
|
+
}
|
|
7071
|
+
matchesId(value, target, strict) {
|
|
7072
|
+
if (strict) return value === target;
|
|
7073
|
+
return value.toLowerCase() === target.toLowerCase();
|
|
7074
|
+
}
|
|
7075
|
+
containsValue(haystack, needle, strict) {
|
|
7076
|
+
if (strict) return haystack.includes(needle);
|
|
7077
|
+
return haystack.toLowerCase().includes(needle.toLowerCase());
|
|
7078
|
+
}
|
|
7079
|
+
getFieldValueString(field) {
|
|
7080
|
+
if (field === null || field === void 0) return "";
|
|
7081
|
+
if (typeof field === "string") return field;
|
|
7082
|
+
if (typeof field === "number" || typeof field === "boolean") return String(field);
|
|
7083
|
+
if (typeof field === "object") {
|
|
7084
|
+
const f = field;
|
|
7085
|
+
if (f.value !== void 0) return String(f.value);
|
|
7086
|
+
return JSON.stringify(f);
|
|
7087
|
+
}
|
|
7088
|
+
return String(field);
|
|
7089
|
+
}
|
|
7090
|
+
};
|
|
7091
|
+
|
|
7092
|
+
// src/cli/commands/split-content-type.ts
|
|
7093
|
+
function createSplitContentTypeCommand() {
|
|
7094
|
+
const command = new Command20("split-content-type");
|
|
7095
|
+
command.description(
|
|
7096
|
+
"Creates a new content type as a copy of an existing one, then reassigns matching entries to it."
|
|
7097
|
+
).option("--contentType <type>", "Source content type ID to split").option("--newContentType <type>", "New content type ID to create").option("--fieldId <id>", "Field ID in entry.fields whose value is checked").option("--fieldContains <value>", "Substring to search for in the field value").hook("preAction", (thisCommand) => {
|
|
7098
|
+
const opts = thisCommand.opts();
|
|
7099
|
+
const requiredOptions = [
|
|
7100
|
+
{ name: "contentType", flag: "--contentType" },
|
|
7101
|
+
{ name: "newContentType", flag: "--newContentType" },
|
|
7102
|
+
{ name: "fieldId", flag: "--fieldId" },
|
|
7103
|
+
{ name: "fieldContains", flag: "--fieldContains" }
|
|
7104
|
+
];
|
|
7105
|
+
const missing = requiredOptions.filter((opt) => !opts[opt.name]).map((opt) => opt.flag);
|
|
7106
|
+
if (missing.length > 0) {
|
|
7107
|
+
console.error(`error: missing required options: ${missing.join(", ")}`);
|
|
7108
|
+
process.exit(1);
|
|
7109
|
+
}
|
|
7110
|
+
}).action(async (opts, cmd) => {
|
|
7111
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
7112
|
+
const options = {
|
|
7113
|
+
...globalOpts,
|
|
7114
|
+
contentType: opts.contentType,
|
|
7115
|
+
newContentType: opts.newContentType,
|
|
7116
|
+
fieldId: opts.fieldId,
|
|
7117
|
+
fieldContains: opts.fieldContains
|
|
7118
|
+
};
|
|
7119
|
+
const logger = new Logger();
|
|
7120
|
+
logger.info(`contentType: ${options.contentType}`);
|
|
7121
|
+
logger.info(`newContentType: ${options.newContentType}`);
|
|
7122
|
+
logger.info(`fieldId: ${options.fieldId}`);
|
|
7123
|
+
logger.info(`fieldContains: ${options.fieldContains}`);
|
|
7124
|
+
const fileSystem = new FileSystemService();
|
|
7125
|
+
const service = new ContentTypeSplitterService(fileSystem, logger);
|
|
7126
|
+
const result = await service.split({
|
|
7127
|
+
rootDir: options.rootDir,
|
|
7128
|
+
contentTypesDir: options.contentTypesDir,
|
|
7129
|
+
entriesDir: options.entriesDir,
|
|
7130
|
+
contentType: options.contentType,
|
|
7131
|
+
newContentType: options.newContentType,
|
|
7132
|
+
fieldId: options.fieldId,
|
|
7133
|
+
fieldContains: options.fieldContains,
|
|
7134
|
+
whatIf: options.whatIf ?? false,
|
|
7135
|
+
strict: options.strict ?? false
|
|
7136
|
+
});
|
|
7137
|
+
logger.success(
|
|
7138
|
+
`Content type created: ${result.contentTypeCreated}. Entries scanned: ${result.entriesScanned}, updated: ${result.entriesUpdated}.`
|
|
7139
|
+
);
|
|
7140
|
+
});
|
|
7141
|
+
return command;
|
|
7142
|
+
}
|
|
7143
|
+
|
|
6946
7144
|
// package.json
|
|
6947
7145
|
var package_default = {
|
|
6948
7146
|
name: "@uniformdev/transformer",
|
|
6949
|
-
version: "1.1.
|
|
7147
|
+
version: "1.1.43",
|
|
6950
7148
|
description: "CLI tool for transforming Uniform.dev serialization files offline",
|
|
6951
7149
|
type: "module",
|
|
6952
7150
|
bin: {
|
|
@@ -7015,7 +7213,7 @@ var package_default = {
|
|
|
7015
7213
|
};
|
|
7016
7214
|
|
|
7017
7215
|
// src/cli/index.ts
|
|
7018
|
-
var program = new
|
|
7216
|
+
var program = new Command21();
|
|
7019
7217
|
var appVersion = package_default.version;
|
|
7020
7218
|
console.error(`uniform-transform v${appVersion}`);
|
|
7021
7219
|
program.name("uniform-transform").description("CLI tool for transforming Uniform.dev serialization files offline").version(appVersion);
|
|
@@ -7050,5 +7248,6 @@ program.addCommand(createRemoveOrphanEntriesCommand());
|
|
|
7050
7248
|
program.addCommand(createRemoveUnusedContentTypesCommand());
|
|
7051
7249
|
program.addCommand(createRemoveUnusedComponentTypesCommand());
|
|
7052
7250
|
program.addCommand(createGenerateMissingProjectMapNodesCommand());
|
|
7251
|
+
program.addCommand(createSplitContentTypeCommand());
|
|
7053
7252
|
program.parse();
|
|
7054
7253
|
//# sourceMappingURL=index.js.map
|