rps-flagforge 1.0.7 ā 1.0.9
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/bin/mergeSchema.js +90 -51
- package/dist/bin/mergeSchema.js.map +1 -1
- package/package.json +1 -1
package/dist/bin/mergeSchema.js
CHANGED
|
@@ -37,26 +37,56 @@ function extractBlocks(schema, type) {
|
|
|
37
37
|
const regex = new RegExp(`${type}\\s+\\w+\\s+{[\\s\\S]*?}\\n?`, "g");
|
|
38
38
|
return schema.match(regex) || [];
|
|
39
39
|
}
|
|
40
|
-
function extractNames(schema, type) {
|
|
41
|
-
const regex = new RegExp(`${type}\\s+(\\w+)\\s+{`, "g");
|
|
42
|
-
const names = [];
|
|
43
|
-
let match;
|
|
44
|
-
while ((match = regex.exec(schema)) !== null) {
|
|
45
|
-
names.push(match[1]);
|
|
46
|
-
}
|
|
47
|
-
return names;
|
|
48
|
-
}
|
|
49
40
|
function stripNonStructuralBlocks(schema) {
|
|
50
41
|
return schema.replace(/generator\s+\w+\s+{[\s\S]*?}\n?/g, "").replace(/datasource\s+\w+\s+{[\s\S]*?}\n?/g, "");
|
|
51
42
|
}
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
43
|
+
function parseBlockFields(block) {
|
|
44
|
+
return block.split("\n").map((l) => l.trim()).filter(
|
|
45
|
+
(l) => l && !l.startsWith("//") && !l.startsWith("model") && !l.startsWith("enum") && !l.startsWith("{") && !l.startsWith("}")
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
function mergeModelFields(existing, incoming) {
|
|
49
|
+
const existingFields = parseBlockFields(existing);
|
|
50
|
+
const incomingFields = parseBlockFields(incoming);
|
|
51
|
+
const mergedFields = [...existingFields];
|
|
52
|
+
const newLines = [];
|
|
53
|
+
const existingMap = new Map(existingFields.map((f) => [f.split(" ")[0], f]));
|
|
54
|
+
for (const line of incomingFields) {
|
|
55
|
+
const name = line.split(" ")[0];
|
|
56
|
+
if (!existingMap.has(name)) {
|
|
57
|
+
mergedFields.push(line);
|
|
58
|
+
newLines.push(`+ ${line}`);
|
|
59
|
+
} else if (existingMap.get(name) !== line) {
|
|
60
|
+
const index = mergedFields.findIndex((f) => f.split(" ")[0] === name);
|
|
61
|
+
mergedFields[index] = line;
|
|
62
|
+
newLines.push(`~ ${line}`);
|
|
63
|
+
}
|
|
56
64
|
}
|
|
57
|
-
|
|
58
|
-
|
|
65
|
+
const mergedBlock = existing.replace(/\{[\s\S]*\}/, `{
|
|
66
|
+
${mergedFields.join("\n ")}
|
|
67
|
+
}`);
|
|
68
|
+
return { mergedBlock, newLines };
|
|
69
|
+
}
|
|
70
|
+
function mergeEnumValues(existing, incoming) {
|
|
71
|
+
const existingValues = parseBlockFields(existing);
|
|
72
|
+
const incomingValues = parseBlockFields(incoming);
|
|
73
|
+
const mergedValues = [...existingValues];
|
|
74
|
+
const newLines = [];
|
|
75
|
+
for (const v of incomingValues) {
|
|
76
|
+
if (!existingValues.includes(v)) {
|
|
77
|
+
mergedValues.push(v);
|
|
78
|
+
newLines.push(`+ ${v}`);
|
|
79
|
+
}
|
|
59
80
|
}
|
|
81
|
+
const mergedBlock = existing.replace(/\{[\s\S]*\}/, `{
|
|
82
|
+
${mergedValues.join("\n ")}
|
|
83
|
+
}`);
|
|
84
|
+
return { mergedBlock, newLines };
|
|
85
|
+
}
|
|
86
|
+
async function main() {
|
|
87
|
+
console.log(import_chalk.default.blueBright.bold("\n\u26A1 FlagsForge Prisma Schema Smart Merger\n"));
|
|
88
|
+
if (isDryRun) console.log(import_chalk.default.cyan("\u{1F50D} Dry run: preview all changes\n"));
|
|
89
|
+
if (isForce) console.log(import_chalk.default.yellow("\u26A0\uFE0F Force mode enabled (skipping backup prompts)\n"));
|
|
60
90
|
if (!import_fs.default.existsSync(appSchema)) {
|
|
61
91
|
console.error(import_chalk.default.red("\u274C App schema not found at prisma/schema.prisma"));
|
|
62
92
|
process.exit(1);
|
|
@@ -68,42 +98,56 @@ async function main() {
|
|
|
68
98
|
const appContent = import_fs.default.readFileSync(appSchema, "utf-8");
|
|
69
99
|
const packageRaw = import_fs.default.readFileSync(packageSchema, "utf-8");
|
|
70
100
|
const packageContent = stripNonStructuralBlocks(packageRaw);
|
|
71
|
-
const
|
|
72
|
-
const
|
|
101
|
+
const appModels = extractBlocks(appContent, "model");
|
|
102
|
+
const appEnums = extractBlocks(appContent, "enum");
|
|
73
103
|
const packageModels = extractBlocks(packageContent, "model");
|
|
74
104
|
const packageEnums = extractBlocks(packageContent, "enum");
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
105
|
+
const mergedModels = [...appModels];
|
|
106
|
+
const modelDiffs = [];
|
|
107
|
+
for (const pModel of packageModels) {
|
|
108
|
+
const match = pModel.match(/model\s+(\w+)\s+{/);
|
|
109
|
+
if (!match) continue;
|
|
110
|
+
const name = match[1];
|
|
111
|
+
const existingIndex = mergedModels.findIndex((m) => m.match(new RegExp(`model\\s+${name}\\s+{`)));
|
|
112
|
+
if (existingIndex >= 0) {
|
|
113
|
+
const { mergedBlock, newLines } = mergeModelFields(mergedModels[existingIndex], pModel);
|
|
114
|
+
mergedModels[existingIndex] = mergedBlock;
|
|
115
|
+
modelDiffs.push(...newLines);
|
|
116
|
+
} else {
|
|
117
|
+
mergedModels.push(pModel);
|
|
118
|
+
modelDiffs.push(`+ New model: ${name}`);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
const mergedEnums = [...appEnums];
|
|
122
|
+
const enumDiffs = [];
|
|
123
|
+
for (const pEnum of packageEnums) {
|
|
124
|
+
const match = pEnum.match(/enum\s+(\w+)\s+{/);
|
|
125
|
+
if (!match) continue;
|
|
126
|
+
const name = match[1];
|
|
127
|
+
const existingIndex = mergedEnums.findIndex((e) => e.match(new RegExp(`enum\\s+${name}\\s+{`)));
|
|
128
|
+
if (existingIndex >= 0) {
|
|
129
|
+
const { mergedBlock, newLines } = mergeEnumValues(mergedEnums[existingIndex], pEnum);
|
|
130
|
+
mergedEnums[existingIndex] = mergedBlock;
|
|
131
|
+
enumDiffs.push(...newLines);
|
|
132
|
+
} else {
|
|
133
|
+
mergedEnums.push(pEnum);
|
|
134
|
+
enumDiffs.push(`+ New enum: ${name}`);
|
|
135
|
+
}
|
|
91
136
|
}
|
|
92
|
-
if (
|
|
93
|
-
console.log(import_chalk.default.yellow("\u26A0\uFE0F No
|
|
137
|
+
if (modelDiffs.length === 0 && enumDiffs.length === 0) {
|
|
138
|
+
console.log(import_chalk.default.yellow("\u26A0\uFE0F No changes detected.\n"));
|
|
94
139
|
process.exit(0);
|
|
95
140
|
}
|
|
96
|
-
|
|
97
|
-
import_chalk.default.green(
|
|
98
|
-
`\u{1F4E6} Found ${newModels.length} model(s) and ${newEnums.length} enum(s) to merge.
|
|
99
|
-
`
|
|
100
|
-
)
|
|
101
|
-
);
|
|
141
|
+
const mergedContent = appContent.trim() + "\n\n// ------------------------------\n// FlagsForge Schema Extensions\n// ------------------------------\n\n" + [...mergedEnums, ...mergedModels].join("\n\n");
|
|
102
142
|
if (isDryRun) {
|
|
103
|
-
console.log(import_chalk.default.gray("-----
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
143
|
+
console.log(import_chalk.default.gray("----- FULL MERGE DIFF -----\n"));
|
|
144
|
+
[...enumDiffs, ...modelDiffs].forEach((line) => {
|
|
145
|
+
if (line.startsWith("+")) console.log(import_chalk.default.green(line));
|
|
146
|
+
else if (line.startsWith("~")) console.log(import_chalk.default.yellow(line));
|
|
147
|
+
else console.log(line);
|
|
148
|
+
});
|
|
149
|
+
console.log(import_chalk.default.gray("\n------------------------------"));
|
|
150
|
+
console.log(import_chalk.default.cyan("\u2728 Dry run complete. No changes were made.\n"));
|
|
107
151
|
process.exit(0);
|
|
108
152
|
}
|
|
109
153
|
let shouldBackup = true;
|
|
@@ -123,12 +167,7 @@ async function main() {
|
|
|
123
167
|
console.log(import_chalk.default.green(`\u2705 Backup created: ${backupPath}
|
|
124
168
|
`));
|
|
125
169
|
}
|
|
126
|
-
|
|
127
|
-
if (isForce) {
|
|
128
|
-
finalContent = stripNonStructuralBlocks(appContent);
|
|
129
|
-
}
|
|
130
|
-
finalContent += "\n\n// ------------------------------\n// FlagsForge Schema Extensions\n// ------------------------------\n\n" + [...newEnums, ...newModels].join("\n\n");
|
|
131
|
-
import_fs.default.writeFileSync(appSchema, finalContent);
|
|
170
|
+
import_fs.default.writeFileSync(appSchema, mergedContent);
|
|
132
171
|
console.log(import_chalk.default.green.bold("\u2705 Prisma schema merged successfully!"));
|
|
133
172
|
console.log(import_chalk.default.yellow("Run `npx prisma generate` to update your client.\n"));
|
|
134
173
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../bin/mergeSchema.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport fs from \"fs\"\r\nimport path from \"path\"\r\nimport chalk from \"chalk\"\r\nimport prompts from \"prompts\"\r\n\r\n// -----------------------------\r\n// CLI Flags\r\n// -----------------------------\r\n\r\nconst args = process.argv.slice(2)\r\nconst isDryRun = args.includes(\"--dry-run\")\r\nconst isForce = args.includes(\"--force\")\r\n\r\n// -----------------------------\r\n// Paths\r\n// -----------------------------\r\n\r\nconst appSchema = path.resolve(process.cwd(), \"prisma/schema.prisma\")\r\nconst packageSchema = path.resolve(__dirname, \"../../prisma/schema.prisma\")\r\n\r\n// -----------------------------\r\n// Helpers\r\n// -----------------------------\r\n\r\nfunction extractBlocks(schema: string, type: \"model\" | \"enum\"): string[] {\r\n const regex = new RegExp(`${type}\\\\s+\\\\w+\\\\s+{[\\\\s\\\\S]*?}\\\\n?`, \"g\")\r\n return schema.match(regex) || []\r\n}\r\n\r\nfunction extractNames(schema: string, type: \"model\" | \"enum\"): string[] {\r\n const regex = new RegExp(`${type}\\\\s+(\\\\w+)\\\\s+{`, \"g\")\r\n const names: string[] = []\r\n let match\r\n while ((match = regex.exec(schema)) !== null) {\r\n names.push(match[1])\r\n }\r\n return names\r\n}\r\n\r\nfunction stripNonStructuralBlocks(schema: string) {\r\n return schema\r\n .replace(/generator\\s+\\w+\\s+{[\\s\\S]*?}\\n?/g, \"\")\r\n .replace(/datasource\\s+\\w+\\s+{[\\s\\S]*?}\\n?/g, \"\")\r\n}\r\n\r\n// -----------------------------\r\n// Main\r\n// -----------------------------\r\n\r\nasync function main() {\r\n console.log(chalk.blueBright.bold(\"\\nā” FlagsForge Prisma Schema Merger\\n\"))\r\n\r\n if (isDryRun) {\r\n console.log(chalk.cyan(\"š Running in DRY RUN mode (no files will be modified)\\n\"))\r\n }\r\n\r\n if (isForce) {\r\n console.log(chalk.yellow(\"ā ļø Force mode enabled (existing models will be replaced)\\n\"))\r\n }\r\n\r\n // Validate files\r\n if (!fs.existsSync(appSchema)) {\r\n console.error(chalk.red(\"ā App schema not found at prisma/schema.prisma\"))\r\n process.exit(1)\r\n }\r\n\r\n if (!fs.existsSync(packageSchema)) {\r\n console.error(chalk.red(\"ā Package Prisma models not found\"))\r\n process.exit(1)\r\n }\r\n\r\n const appContent = fs.readFileSync(appSchema, \"utf-8\")\r\n const packageRaw = fs.readFileSync(packageSchema, \"utf-8\")\r\n\r\n const packageContent = stripNonStructuralBlocks(packageRaw)\r\n\r\n const appModelNames = extractNames(appContent, \"model\")\r\n const appEnumNames = extractNames(appContent, \"enum\")\r\n\r\n const packageModels = extractBlocks(packageContent, \"model\")\r\n const packageEnums = extractBlocks(packageContent, \"enum\")\r\n\r\n let newModels: string[] = []\r\n let newEnums: string[] = []\r\n\r\n if (isForce) {\r\n newModels = packageModels\r\n newEnums = packageEnums\r\n } else {\r\n newModels = packageModels.filter(block => {\r\n const match = block.match(/model\\s+(\\w+)\\s+{/)\r\n if (!match) return false\r\n return !appModelNames.includes(match[1])\r\n })\r\n\r\n newEnums = packageEnums.filter(block => {\r\n const match = block.match(/enum\\s+(\\w+)\\s+{/)\r\n if (!match) return false\r\n return !appEnumNames.includes(match[1])\r\n })\r\n }\r\n\r\n if (newModels.length === 0 && newEnums.length === 0) {\r\n console.log(chalk.yellow(\"ā ļø No new models or enums to merge.\\n\"))\r\n process.exit(0)\r\n }\r\n\r\n console.log(\r\n chalk.green(\r\n `š¦ Found ${newModels.length} model(s) and ${newEnums.length} enum(s) to merge.\\n`\r\n )\r\n )\r\n\r\n if (isDryRun) {\r\n console.log(chalk.gray(\"----- PREVIEW -----\\n\"))\r\n console.log([...newEnums, ...newModels].join(\"\\n\\n\"))\r\n console.log(chalk.gray(\"\\n-------------------\"))\r\n console.log(chalk.cyan(\"\\n⨠Dry run complete. No changes were made.\\n\"))\r\n process.exit(0)\r\n }\r\n\r\n // Backup (skip prompt in force mode)\r\n let shouldBackup = true\r\n\r\n if (!isForce) {\r\n const response = await prompts({\r\n type: \"confirm\",\r\n name: \"backup\",\r\n message: \"Create a backup of your current schema?\",\r\n initial: true\r\n })\r\n\r\n shouldBackup = response.backup\r\n }\r\n\r\n if (shouldBackup) {\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\")\r\n const backupPath = `${appSchema}.bak-${timestamp}`\r\n fs.copyFileSync(appSchema, backupPath)\r\n console.log(chalk.green(`ā
Backup created: ${backupPath}\\n`))\r\n }\r\n\r\n let finalContent = appContent.trim()\r\n\r\n if (isForce) {\r\n // Remove existing models/enums before re-adding\r\n finalContent = stripNonStructuralBlocks(appContent)\r\n }\r\n\r\n finalContent +=\r\n \"\\n\\n// ------------------------------\\n\" +\r\n \"// FlagsForge Schema Extensions\\n\" +\r\n \"// ------------------------------\\n\\n\" +\r\n [...newEnums, ...newModels].join(\"\\n\\n\")\r\n\r\n fs.writeFileSync(appSchema, finalContent)\r\n\r\n console.log(chalk.green.bold(\"ā
Prisma schema merged successfully!\"))\r\n console.log(chalk.yellow(\"Run `npx prisma generate` to update your client.\\n\"))\r\n}\r\n\r\nmain().catch(err => {\r\n console.error(chalk.red(\"ā Error merging schemas:\"), err)\r\n process.exit(1)\r\n})\r\n"],"mappings":"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","names":["path","chalk","fs","prompts"]}
|
|
1
|
+
{"version":3,"sources":["../../bin/mergeSchema.ts"],"sourcesContent":["#!/usr/bin/env node\r\nimport fs from \"fs\";\r\nimport path from \"path\";\r\nimport chalk from \"chalk\";\r\nimport prompts from \"prompts\";\r\n\r\n// -----------------------------\r\n// CLI Flags\r\n// -----------------------------\r\nconst args = process.argv.slice(2);\r\nconst isDryRun = args.includes(\"--dry-run\");\r\nconst isForce = args.includes(\"--force\");\r\n\r\n// -----------------------------\r\n// Paths\r\n// -----------------------------\r\nconst appSchema = path.resolve(process.cwd(), \"prisma/schema.prisma\");\r\nconst packageSchema = path.resolve(__dirname, \"../../prisma/schema.prisma\");\r\n\r\n// -----------------------------\r\n// Helpers\r\n// -----------------------------\r\nfunction extractBlocks(schema: string, type: \"model\" | \"enum\"): string[] {\r\n const regex = new RegExp(`${type}\\\\s+\\\\w+\\\\s+{[\\\\s\\\\S]*?}\\\\n?`, \"g\");\r\n return schema.match(regex) || [];\r\n}\r\n\r\nfunction extractNames(schema: string, type: \"model\" | \"enum\"): string[] {\r\n const regex = new RegExp(`${type}\\\\s+(\\\\w+)\\\\s+{`, \"g\");\r\n const names: string[] = [];\r\n let match;\r\n while ((match = regex.exec(schema)) !== null) {\r\n names.push(match[1]);\r\n }\r\n return names;\r\n}\r\n\r\nfunction stripNonStructuralBlocks(schema: string) {\r\n return schema\r\n .replace(/generator\\s+\\w+\\s+{[\\s\\S]*?}\\n?/g, \"\")\r\n .replace(/datasource\\s+\\w+\\s+{[\\s\\S]*?}\\n?/g, \"\");\r\n}\r\n\r\n// Returns array of trimmed field lines\r\nfunction parseBlockFields(block: string) {\r\n return block\r\n .split(\"\\n\")\r\n .map(l => l.trim())\r\n .filter(\r\n l =>\r\n l &&\r\n !l.startsWith(\"//\") &&\r\n !l.startsWith(\"model\") &&\r\n !l.startsWith(\"enum\") &&\r\n !l.startsWith(\"{\") &&\r\n !l.startsWith(\"}\")\r\n );\r\n}\r\n\r\n// Merge model fields: updates changed fields, adds new fields\r\nfunction mergeModelFields(existing: string, incoming: string) {\r\n const existingFields = parseBlockFields(existing);\r\n const incomingFields = parseBlockFields(incoming);\r\n\r\n const mergedFields: string[] = [...existingFields];\r\n const newLines: string[] = [];\r\n\r\n const existingMap = new Map(existingFields.map(f => [f.split(\" \")[0], f]));\r\n\r\n for (const line of incomingFields) {\r\n const name = line.split(\" \")[0];\r\n if (!existingMap.has(name)) {\r\n mergedFields.push(line);\r\n newLines.push(`+ ${line}`);\r\n } else if (existingMap.get(name) !== line) {\r\n // Update changed field\r\n const index = mergedFields.findIndex(f => f.split(\" \")[0] === name);\r\n mergedFields[index] = line;\r\n newLines.push(`~ ${line}`);\r\n }\r\n }\r\n\r\n const mergedBlock = existing.replace(/\\{[\\s\\S]*\\}/, `{ \\n ${mergedFields.join(\"\\n \")} \\n}`);\r\n return { mergedBlock, newLines };\r\n}\r\n\r\n// Merge enum values\r\nfunction mergeEnumValues(existing: string, incoming: string) {\r\n const existingValues = parseBlockFields(existing);\r\n const incomingValues = parseBlockFields(incoming);\r\n\r\n const mergedValues = [...existingValues];\r\n const newLines: string[] = [];\r\n\r\n for (const v of incomingValues) {\r\n if (!existingValues.includes(v)) {\r\n mergedValues.push(v);\r\n newLines.push(`+ ${v}`);\r\n }\r\n }\r\n\r\n const mergedBlock = existing.replace(/\\{[\\s\\S]*\\}/, `{ \\n ${mergedValues.join(\"\\n \")} \\n}`);\r\n return { mergedBlock, newLines };\r\n}\r\n\r\n// -----------------------------\r\n// Main\r\n// -----------------------------\r\nasync function main() {\r\n console.log(chalk.blueBright.bold(\"\\nā” FlagsForge Prisma Schema Smart Merger\\n\"));\r\n\r\n if (isDryRun) console.log(chalk.cyan(\"š Dry run: preview all changes\\n\"));\r\n if (isForce) console.log(chalk.yellow(\"ā ļø Force mode enabled (skipping backup prompts)\\n\"));\r\n\r\n if (!fs.existsSync(appSchema)) {\r\n console.error(chalk.red(\"ā App schema not found at prisma/schema.prisma\"));\r\n process.exit(1);\r\n }\r\n\r\n if (!fs.existsSync(packageSchema)) {\r\n console.error(chalk.red(\"ā Package Prisma models not found\"));\r\n process.exit(1);\r\n }\r\n\r\n const appContent = fs.readFileSync(appSchema, \"utf-8\");\r\n const packageRaw = fs.readFileSync(packageSchema, \"utf-8\");\r\n const packageContent = stripNonStructuralBlocks(packageRaw);\r\n\r\n const appModels = extractBlocks(appContent, \"model\");\r\n const appEnums = extractBlocks(appContent, \"enum\");\r\n const packageModels = extractBlocks(packageContent, \"model\");\r\n const packageEnums = extractBlocks(packageContent, \"enum\");\r\n\r\n // Merge models\r\n const mergedModels = [...appModels];\r\n const modelDiffs: string[] = [];\r\n\r\n for (const pModel of packageModels) {\r\n const match = pModel.match(/model\\s+(\\w+)\\s+{/);\r\n if (!match) continue;\r\n const name = match[1];\r\n const existingIndex = mergedModels.findIndex(m => m.match(new RegExp(`model\\\\s+${name}\\\\s+{`)));\r\n if (existingIndex >= 0) {\r\n const { mergedBlock, newLines } = mergeModelFields(mergedModels[existingIndex], pModel);\r\n mergedModels[existingIndex] = mergedBlock;\r\n modelDiffs.push(...newLines);\r\n } else {\r\n mergedModels.push(pModel);\r\n modelDiffs.push(`+ New model: ${name}`);\r\n }\r\n }\r\n\r\n // Merge enums\r\n const mergedEnums = [...appEnums];\r\n const enumDiffs: string[] = [];\r\n\r\n for (const pEnum of packageEnums) {\r\n const match = pEnum.match(/enum\\s+(\\w+)\\s+{/);\r\n if (!match) continue;\r\n const name = match[1];\r\n const existingIndex = mergedEnums.findIndex(e => e.match(new RegExp(`enum\\\\s+${name}\\\\s+{`)));\r\n if (existingIndex >= 0) {\r\n const { mergedBlock, newLines } = mergeEnumValues(mergedEnums[existingIndex], pEnum);\r\n mergedEnums[existingIndex] = mergedBlock;\r\n enumDiffs.push(...newLines);\r\n } else {\r\n mergedEnums.push(pEnum);\r\n enumDiffs.push(`+ New enum: ${name}`);\r\n }\r\n }\r\n\r\n if (modelDiffs.length === 0 && enumDiffs.length === 0) {\r\n console.log(chalk.yellow(\"ā ļø No changes detected.\\n\"));\r\n process.exit(0);\r\n }\r\n\r\n const mergedContent =\r\n appContent.trim() +\r\n \"\\n\\n// ------------------------------\\n\" +\r\n \"// FlagsForge Schema Extensions\\n\" +\r\n \"// ------------------------------\\n\\n\" +\r\n [...mergedEnums, ...mergedModels].join(\"\\n\\n\");\r\n\r\n // Dry-run preview\r\n if (isDryRun) {\r\n console.log(chalk.gray(\"----- FULL MERGE DIFF -----\\n\"));\r\n [...enumDiffs, ...modelDiffs].forEach(line => {\r\n if (line.startsWith(\"+\")) console.log(chalk.green(line));\r\n else if (line.startsWith(\"~\")) console.log(chalk.yellow(line));\r\n else console.log(line);\r\n });\r\n console.log(chalk.gray(\"\\n------------------------------\"));\r\n console.log(chalk.cyan(\"⨠Dry run complete. No changes were made.\\n\"));\r\n process.exit(0);\r\n }\r\n\r\n // Backup prompt\r\n let shouldBackup = true;\r\n if (!isForce) {\r\n const response = await prompts({\r\n type: \"confirm\",\r\n name: \"backup\",\r\n message: \"Create a backup of your current schema?\",\r\n initial: true\r\n });\r\n shouldBackup = response.backup;\r\n }\r\n\r\n if (shouldBackup) {\r\n const timestamp = new Date().toISOString().replace(/[:.]/g, \"-\");\r\n const backupPath = `${appSchema}.bak-${timestamp}`;\r\n fs.copyFileSync(appSchema, backupPath);\r\n console.log(chalk.green(`ā
Backup created: ${backupPath}\\n`));\r\n }\r\n\r\n fs.writeFileSync(appSchema, mergedContent);\r\n console.log(chalk.green.bold(\"ā
Prisma schema merged successfully!\"));\r\n console.log(chalk.yellow(\"Run `npx prisma generate` to update your client.\\n\"));\r\n}\r\n\r\nmain().catch(err => {\r\n console.error(chalk.red(\"ā Error merging schemas:\"), err);\r\n process.exit(1);\r\n});\r\n"],"mappings":"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","names":["path","chalk","fs","prompts"]}
|