@uniformdev/transformer 1.1.41 → 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 +203 -64
- package/dist/cli/index.js.map +1 -1
- package/dist/index.d.ts +7 -2
- 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";
|
|
@@ -6829,7 +6829,7 @@ var GenerateMissingProjectMapNodesService = class {
|
|
|
6829
6829
|
this.logger = logger;
|
|
6830
6830
|
}
|
|
6831
6831
|
async generate(options) {
|
|
6832
|
-
const { rootDir, projectMapNodesDir,
|
|
6832
|
+
const { rootDir, projectMapNodesDir, whatIf } = options;
|
|
6833
6833
|
const nodesDirFull = this.fileSystem.resolvePath(rootDir, projectMapNodesDir);
|
|
6834
6834
|
const nodesDirExists = await this.fileSystem.fileExists(nodesDirFull);
|
|
6835
6835
|
if (!nodesDirExists) {
|
|
@@ -6858,41 +6858,8 @@ var GenerateMissingProjectMapNodesService = class {
|
|
|
6858
6858
|
allNodes.push({ filePath, node });
|
|
6859
6859
|
}
|
|
6860
6860
|
const existingPaths = new Set(allNodes.map(({ node }) => node.path));
|
|
6861
|
-
const
|
|
6862
|
-
|
|
6863
|
-
const compositionsDirExists = await this.fileSystem.fileExists(compositionsDirFull);
|
|
6864
|
-
if (!compositionsDirExists) {
|
|
6865
|
-
this.logger.warn(`Compositions directory not found: ${compositionsDir} \u2014 no source nodes will match`);
|
|
6866
|
-
} else {
|
|
6867
|
-
const compositionFiles = await this.fileSystem.findFiles(
|
|
6868
|
-
compositionsDirFull,
|
|
6869
|
-
"**/*.{json,yaml,yml}"
|
|
6870
|
-
);
|
|
6871
|
-
for (const filePath of compositionFiles) {
|
|
6872
|
-
let comp;
|
|
6873
|
-
try {
|
|
6874
|
-
comp = await this.fileSystem.readFile(filePath);
|
|
6875
|
-
} catch {
|
|
6876
|
-
this.logger.warn(`Could not read composition file: ${filePath} \u2014 skipping`);
|
|
6877
|
-
continue;
|
|
6878
|
-
}
|
|
6879
|
-
if (comp?.composition?._id && comp?.composition?.type) {
|
|
6880
|
-
compositionIdToType.set(comp.composition._id, comp.composition.type);
|
|
6881
|
-
}
|
|
6882
|
-
}
|
|
6883
|
-
}
|
|
6884
|
-
const sourceNodes = allNodes.filter(({ node }) => {
|
|
6885
|
-
if (!node.compositionId) return false;
|
|
6886
|
-
const rootType = compositionIdToType.get(node.compositionId);
|
|
6887
|
-
if (!rootType) {
|
|
6888
|
-
this.logger.warn(
|
|
6889
|
-
`No composition found for compositionId "${node.compositionId}" (node path: ${node.path}) \u2014 skipping`
|
|
6890
|
-
);
|
|
6891
|
-
return false;
|
|
6892
|
-
}
|
|
6893
|
-
return this.matchesContentType(rootType, rootContentTypes, strict);
|
|
6894
|
-
});
|
|
6895
|
-
this.logger.info(`${sourceNodes.length} node(s) match root content types`);
|
|
6861
|
+
const sourceNodes = allNodes.filter(({ node }) => !!node.compositionId);
|
|
6862
|
+
this.logger.info(`${sourceNodes.length} node(s) selected as sources`);
|
|
6896
6863
|
const ancestorPaths = /* @__PURE__ */ new Set();
|
|
6897
6864
|
for (const { node } of sourceNodes) {
|
|
6898
6865
|
for (const ancestor of this.computeAncestorPaths(node.path)) {
|
|
@@ -6949,29 +6916,192 @@ var GenerateMissingProjectMapNodesService = class {
|
|
|
6949
6916
|
const slug = nodePath.split("/").filter((s) => s.length > 0).join("-");
|
|
6950
6917
|
return `${slug}-node.yaml`;
|
|
6951
6918
|
}
|
|
6952
|
-
matchesContentType(rootType, rootContentTypes, strict) {
|
|
6953
|
-
for (const ct of rootContentTypes) {
|
|
6954
|
-
if (strict) {
|
|
6955
|
-
if (rootType === ct) return true;
|
|
6956
|
-
} else {
|
|
6957
|
-
if (rootType.toLowerCase() === ct.toLowerCase()) return true;
|
|
6958
|
-
}
|
|
6959
|
-
}
|
|
6960
|
-
return false;
|
|
6961
|
-
}
|
|
6962
6919
|
};
|
|
6963
6920
|
|
|
6964
6921
|
// src/cli/commands/generate-missing-project-map-nodes.ts
|
|
6965
6922
|
function createGenerateMissingProjectMapNodesCommand() {
|
|
6966
6923
|
const command = new Command19("generate-missing-project-map-nodes");
|
|
6967
6924
|
command.description(
|
|
6968
|
-
"Creates group project map nodes for ancestor path segments that are missing from the project map.
|
|
6969
|
-
).
|
|
6970
|
-
|
|
6971
|
-
|
|
6972
|
-
|
|
6925
|
+
"Creates group project map nodes for ancestor path segments that are missing from the project map. All project map nodes with a compositionId are used as sources."
|
|
6926
|
+
).action(async (opts, cmd) => {
|
|
6927
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
6928
|
+
const options = {
|
|
6929
|
+
...globalOpts
|
|
6930
|
+
};
|
|
6931
|
+
const logger = new Logger();
|
|
6932
|
+
const fileSystem = new FileSystemService();
|
|
6933
|
+
const service = new GenerateMissingProjectMapNodesService(fileSystem, logger);
|
|
6934
|
+
const result = await service.generate({
|
|
6935
|
+
rootDir: options.rootDir,
|
|
6936
|
+
projectMapNodesDir: options.projectMapNodesDir,
|
|
6937
|
+
whatIf: options.whatIf ?? false
|
|
6938
|
+
});
|
|
6939
|
+
logger.success(
|
|
6940
|
+
`Created ${result.generatedCount} missing project map node(s). ${result.alreadyCoveredCount} ancestor path(s) already existed.`
|
|
6941
|
+
);
|
|
6942
|
+
});
|
|
6943
|
+
return command;
|
|
6944
|
+
}
|
|
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) => {
|
|
6973
7098
|
const opts = thisCommand.opts();
|
|
6974
|
-
const requiredOptions = [
|
|
7099
|
+
const requiredOptions = [
|
|
7100
|
+
{ name: "contentType", flag: "--contentType" },
|
|
7101
|
+
{ name: "newContentType", flag: "--newContentType" },
|
|
7102
|
+
{ name: "fieldId", flag: "--fieldId" },
|
|
7103
|
+
{ name: "fieldContains", flag: "--fieldContains" }
|
|
7104
|
+
];
|
|
6975
7105
|
const missing = requiredOptions.filter((opt) => !opts[opt.name]).map((opt) => opt.flag);
|
|
6976
7106
|
if (missing.length > 0) {
|
|
6977
7107
|
console.error(`error: missing required options: ${missing.join(", ")}`);
|
|
@@ -6981,23 +7111,31 @@ function createGenerateMissingProjectMapNodesCommand() {
|
|
|
6981
7111
|
const globalOpts = cmd.optsWithGlobals();
|
|
6982
7112
|
const options = {
|
|
6983
7113
|
...globalOpts,
|
|
6984
|
-
|
|
7114
|
+
contentType: opts.contentType,
|
|
7115
|
+
newContentType: opts.newContentType,
|
|
7116
|
+
fieldId: opts.fieldId,
|
|
7117
|
+
fieldContains: opts.fieldContains
|
|
6985
7118
|
};
|
|
6986
7119
|
const logger = new Logger();
|
|
6987
|
-
logger.info(`
|
|
6988
|
-
|
|
7120
|
+
logger.info(`contentType: ${options.contentType}`);
|
|
7121
|
+
logger.info(`newContentType: ${options.newContentType}`);
|
|
7122
|
+
logger.info(`fieldId: ${options.fieldId}`);
|
|
7123
|
+
logger.info(`fieldContains: ${options.fieldContains}`);
|
|
6989
7124
|
const fileSystem = new FileSystemService();
|
|
6990
|
-
const service = new
|
|
6991
|
-
const result = await service.
|
|
7125
|
+
const service = new ContentTypeSplitterService(fileSystem, logger);
|
|
7126
|
+
const result = await service.split({
|
|
6992
7127
|
rootDir: options.rootDir,
|
|
6993
|
-
|
|
6994
|
-
|
|
6995
|
-
|
|
7128
|
+
contentTypesDir: options.contentTypesDir,
|
|
7129
|
+
entriesDir: options.entriesDir,
|
|
7130
|
+
contentType: options.contentType,
|
|
7131
|
+
newContentType: options.newContentType,
|
|
7132
|
+
fieldId: options.fieldId,
|
|
7133
|
+
fieldContains: options.fieldContains,
|
|
6996
7134
|
whatIf: options.whatIf ?? false,
|
|
6997
7135
|
strict: options.strict ?? false
|
|
6998
7136
|
});
|
|
6999
7137
|
logger.success(
|
|
7000
|
-
`
|
|
7138
|
+
`Content type created: ${result.contentTypeCreated}. Entries scanned: ${result.entriesScanned}, updated: ${result.entriesUpdated}.`
|
|
7001
7139
|
);
|
|
7002
7140
|
});
|
|
7003
7141
|
return command;
|
|
@@ -7006,7 +7144,7 @@ function createGenerateMissingProjectMapNodesCommand() {
|
|
|
7006
7144
|
// package.json
|
|
7007
7145
|
var package_default = {
|
|
7008
7146
|
name: "@uniformdev/transformer",
|
|
7009
|
-
version: "1.1.
|
|
7147
|
+
version: "1.1.43",
|
|
7010
7148
|
description: "CLI tool for transforming Uniform.dev serialization files offline",
|
|
7011
7149
|
type: "module",
|
|
7012
7150
|
bin: {
|
|
@@ -7075,7 +7213,7 @@ var package_default = {
|
|
|
7075
7213
|
};
|
|
7076
7214
|
|
|
7077
7215
|
// src/cli/index.ts
|
|
7078
|
-
var program = new
|
|
7216
|
+
var program = new Command21();
|
|
7079
7217
|
var appVersion = package_default.version;
|
|
7080
7218
|
console.error(`uniform-transform v${appVersion}`);
|
|
7081
7219
|
program.name("uniform-transform").description("CLI tool for transforming Uniform.dev serialization files offline").version(appVersion);
|
|
@@ -7110,5 +7248,6 @@ program.addCommand(createRemoveOrphanEntriesCommand());
|
|
|
7110
7248
|
program.addCommand(createRemoveUnusedContentTypesCommand());
|
|
7111
7249
|
program.addCommand(createRemoveUnusedComponentTypesCommand());
|
|
7112
7250
|
program.addCommand(createGenerateMissingProjectMapNodesCommand());
|
|
7251
|
+
program.addCommand(createSplitContentTypeCommand());
|
|
7113
7252
|
program.parse();
|
|
7114
7253
|
//# sourceMappingURL=index.js.map
|