api-core-lib 12.0.67 → 12.0.68
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.cjs +168 -159
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -74,19 +74,17 @@ var import_chalk = __toESM(require("chalk"), 1);
|
|
|
74
74
|
var import_dotenv = __toESM(require("dotenv"), 1);
|
|
75
75
|
var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"), 1);
|
|
76
76
|
var import_openapi_types = __toESM(require_dist(), 1);
|
|
77
|
-
var import_json_schema_to_typescript = require("json-schema-to-typescript");
|
|
78
77
|
var DEBUG_MODE = process.env.DEBUG === "true";
|
|
79
|
-
var debugLog = (title, data) =>
|
|
80
|
-
|
|
81
|
-
console.log(import_chalk.default.yellow(`
|
|
82
|
-
[DEBUG: ${title}]`));
|
|
83
|
-
console.log(import_util.default.inspect(data, { depth: null, colors: true }));
|
|
84
|
-
}
|
|
85
|
-
};
|
|
78
|
+
var debugLog = (title, data) => DEBUG_MODE && console.log(import_chalk.default.yellow(`
|
|
79
|
+
[DEBUG: ${title}]`), import_util.default.inspect(data, { depth: 4, colors: true }));
|
|
86
80
|
var toPascalCase = (str) => str.replace(/[^a-zA-Z0-9_]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (w) => w.toUpperCase()).replace(/\s+/g, "");
|
|
87
|
-
var
|
|
88
|
-
|
|
89
|
-
|
|
81
|
+
var toCamelCase = (str) => {
|
|
82
|
+
const s = toPascalCase(str);
|
|
83
|
+
return s.charAt(0).toLowerCase() + s.slice(1);
|
|
84
|
+
};
|
|
85
|
+
var getModuleName = (opId) => `${opId.split("_")[0].replace(/Controller$/, "")}Api`;
|
|
86
|
+
var getActionName = (opId) => toCamelCase(opId.split("_")[1] || opId);
|
|
87
|
+
var findCommonPath = (paths) => {
|
|
90
88
|
if (!paths || paths.length === 0) return "/";
|
|
91
89
|
const sorted = [...paths].sort();
|
|
92
90
|
const first = sorted[0];
|
|
@@ -96,15 +94,57 @@ var findCommonBasePath = (paths) => {
|
|
|
96
94
|
const prefix = first.substring(0, i);
|
|
97
95
|
return prefix.substring(0, prefix.lastIndexOf("/") + 1) || "/";
|
|
98
96
|
};
|
|
97
|
+
var generateFriendlyMessage = (fieldName, validation) => {
|
|
98
|
+
const friendlyName = fieldName.replace(/([A-Z])/g, " $1").replace(/^./, (str) => str.toUpperCase());
|
|
99
|
+
switch (validation) {
|
|
100
|
+
case "required":
|
|
101
|
+
return `${friendlyName} is required.`;
|
|
102
|
+
case "email":
|
|
103
|
+
return `Please enter a valid email for ${friendlyName}.`;
|
|
104
|
+
default:
|
|
105
|
+
return `Invalid value for ${friendlyName}.`;
|
|
106
|
+
}
|
|
107
|
+
};
|
|
108
|
+
function parseSchema(name, schema) {
|
|
109
|
+
const properties = [];
|
|
110
|
+
if (schema.properties) {
|
|
111
|
+
for (const propName in schema.properties) {
|
|
112
|
+
const propSchema = schema.properties[propName];
|
|
113
|
+
let items = void 0;
|
|
114
|
+
if (propSchema.type === "array" && propSchema.items) {
|
|
115
|
+
items = parseSchema("item", propSchema.items).properties[0];
|
|
116
|
+
}
|
|
117
|
+
properties.push({
|
|
118
|
+
name: propName,
|
|
119
|
+
type: propSchema.type || "object",
|
|
120
|
+
isRequired: (schema.required || []).includes(propName),
|
|
121
|
+
isNullable: propSchema.nullable || false,
|
|
122
|
+
description: propSchema.description,
|
|
123
|
+
example: propSchema.example,
|
|
124
|
+
enum: propSchema.enum,
|
|
125
|
+
format: propSchema.format,
|
|
126
|
+
items,
|
|
127
|
+
// نستخدم المتغير الذي تم حسابه بأمان
|
|
128
|
+
properties: propSchema.properties ? parseSchema("sub-object", propSchema).properties : void 0
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
return { name, description: schema.description, properties };
|
|
133
|
+
}
|
|
99
134
|
function parseSpecToModules(spec) {
|
|
100
135
|
const modules = /* @__PURE__ */ new Map();
|
|
101
136
|
const allSchemas = /* @__PURE__ */ new Map();
|
|
102
137
|
const modulePaths = /* @__PURE__ */ new Map();
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
138
|
+
const registerSchema = (schema, baseName) => {
|
|
139
|
+
if (!schema) return "unknown";
|
|
140
|
+
if (schema.type === "array" && schema.items) return `${registerSchema(schema.items, `${baseName}Item`)}[]`;
|
|
141
|
+
if (schema.type === "object" || schema.properties || schema.allOf || !schema.type) {
|
|
142
|
+
const typeName = toPascalCase(baseName.replace(/_v\d+(Request|Response)$/, "$1"));
|
|
143
|
+
if (!allSchemas.has(typeName)) allSchemas.set(typeName, parseSchema(typeName, schema));
|
|
144
|
+
return typeName;
|
|
106
145
|
}
|
|
107
|
-
|
|
146
|
+
return schema.type === "integer" ? "number" : schema.type || "unknown";
|
|
147
|
+
};
|
|
108
148
|
for (const apiPath in spec.paths) {
|
|
109
149
|
const pathItem = spec.paths[apiPath];
|
|
110
150
|
if (!pathItem) continue;
|
|
@@ -112,85 +152,46 @@ function parseSpecToModules(spec) {
|
|
|
112
152
|
if (!Object.values(import_openapi_types.OpenAPIV3.HttpMethods).includes(method)) continue;
|
|
113
153
|
const endpoint = pathItem[method];
|
|
114
154
|
if (!endpoint.operationId) continue;
|
|
115
|
-
const moduleName =
|
|
155
|
+
const moduleName = getModuleName(endpoint.operationId);
|
|
116
156
|
if (!modules.has(moduleName)) {
|
|
117
157
|
modules.set(moduleName, { moduleName, baseEndpoint: "", actions: {}, schemas: /* @__PURE__ */ new Set() });
|
|
118
158
|
modulePaths.set(moduleName, []);
|
|
119
159
|
}
|
|
120
160
|
const currentModule = modules.get(moduleName);
|
|
121
161
|
modulePaths.get(moduleName).push(apiPath);
|
|
122
|
-
const
|
|
162
|
+
const successKey = Object.keys(endpoint.responses).find((c) => c.startsWith("2"));
|
|
163
|
+
const successRes = successKey ? endpoint.responses[successKey] : void 0;
|
|
164
|
+
const outputType = successKey === "204" ? "void" : registerSchema(successRes?.content?.["application/json"]?.schema, `${endpoint.operationId}Response`);
|
|
165
|
+
const reqBody = endpoint.requestBody;
|
|
166
|
+
let inputType = "undefined";
|
|
167
|
+
if (reqBody?.content?.["application/json"]?.schema) inputType = registerSchema(reqBody.content["application/json"].schema, `${endpoint.operationId}Request`);
|
|
168
|
+
else if ((endpoint.parameters || []).some((p) => p.in === "query")) inputType = "QueryOptions";
|
|
123
169
|
[inputType, outputType].forEach((t) => {
|
|
124
170
|
const cleanType = t.replace("[]", "");
|
|
125
171
|
if (cleanType && !["unknown", "undefined", "void", "any", "QueryOptions", "Promise"].includes(cleanType)) {
|
|
126
172
|
currentModule.schemas.add(cleanType);
|
|
127
173
|
}
|
|
128
174
|
});
|
|
129
|
-
const actionName =
|
|
130
|
-
currentModule.actions[actionName] = {
|
|
131
|
-
method: method.toUpperCase(),
|
|
132
|
-
path: apiPath,
|
|
133
|
-
description: endpoint.summary || "",
|
|
134
|
-
hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"),
|
|
135
|
-
autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"),
|
|
136
|
-
requiresAuth: !!endpoint.security && endpoint.security.length > 0,
|
|
137
|
-
_inputType: inputType,
|
|
138
|
-
_outputType: outputType
|
|
139
|
-
};
|
|
140
|
-
debugLog("Parsed Action", { moduleName, actionName, ...currentModule.actions[actionName] });
|
|
175
|
+
const actionName = getActionName(endpoint.operationId);
|
|
176
|
+
currentModule.actions[actionName] = { name: actionName, method: method.toUpperCase(), path: apiPath, description: endpoint.summary || "", hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"), autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"), requiresAuth: !!endpoint.security && endpoint.security.length > 0, inputType, outputType };
|
|
141
177
|
}
|
|
142
178
|
}
|
|
143
179
|
modules.forEach((mod, name) => {
|
|
144
|
-
const basePath =
|
|
180
|
+
const basePath = findCommonPath(modulePaths.get(name));
|
|
145
181
|
mod.baseEndpoint = basePath;
|
|
146
182
|
Object.values(mod.actions).forEach((action) => {
|
|
147
183
|
const relativePath = action.path.replace(basePath, "").replace(/^\//, "");
|
|
148
184
|
action.path = relativePath === "" ? "/" : relativePath;
|
|
149
185
|
});
|
|
150
186
|
});
|
|
187
|
+
debugLog("Final Parsed Modules", Object.fromEntries(modules));
|
|
151
188
|
return { modules, allSchemas };
|
|
152
189
|
}
|
|
153
|
-
function _extractAndRegisterTypes(endpoint, allSchemas) {
|
|
154
|
-
const opId = endpoint.operationId || "Unnamed";
|
|
155
|
-
const successKey = Object.keys(endpoint.responses).find((c) => c.startsWith("2"));
|
|
156
|
-
const successRes = successKey ? endpoint.responses[successKey] : void 0;
|
|
157
|
-
const resSchema = successRes?.content?.["application/json"]?.schema;
|
|
158
|
-
const outputType = successKey === "204" ? "void" : _schemaToTypeName(resSchema, `${opId}Response`, allSchemas);
|
|
159
|
-
const reqBody = endpoint.requestBody;
|
|
160
|
-
const reqSchema = reqBody?.content?.["application/json"]?.schema;
|
|
161
|
-
let inputType = "undefined";
|
|
162
|
-
if (reqSchema) {
|
|
163
|
-
inputType = _schemaToTypeName(reqSchema, `${opId}Request`, allSchemas);
|
|
164
|
-
} else if ((endpoint.parameters || []).some((p) => p.in === "query")) {
|
|
165
|
-
inputType = "QueryOptions";
|
|
166
|
-
}
|
|
167
|
-
return { inputType, outputType };
|
|
168
|
-
}
|
|
169
|
-
function _schemaToTypeName(schema, name, allSchemas) {
|
|
170
|
-
if (!schema) return "unknown";
|
|
171
|
-
if (schema.type === "array" && schema.items) {
|
|
172
|
-
const itemTypeName = _schemaToTypeName(schema.items, `${name}Item`, allSchemas);
|
|
173
|
-
return `${itemTypeName}[]`;
|
|
174
|
-
}
|
|
175
|
-
if (schema.type === "object" || schema.properties || schema.allOf || !schema.type) {
|
|
176
|
-
const typeName = toPascalCase(name);
|
|
177
|
-
if (!allSchemas.has(typeName)) {
|
|
178
|
-
debugLog("Registering new inline schema", { assignedName: typeName, originalSchema: schema });
|
|
179
|
-
allSchemas.set(typeName, { name: typeName, schema });
|
|
180
|
-
}
|
|
181
|
-
return typeName;
|
|
182
|
-
}
|
|
183
|
-
if (schema.type && ["string", "number", "boolean", "integer"].includes(schema.type)) {
|
|
184
|
-
return schema.type === "integer" ? "number" : schema.type;
|
|
185
|
-
}
|
|
186
|
-
return "unknown";
|
|
187
|
-
}
|
|
188
190
|
async function generateModuleFiles(module2, allSchemas, outputDir) {
|
|
189
|
-
const
|
|
190
|
-
const moduleOutputPath = import_path.default.join(outputDir, moduleName);
|
|
191
|
+
const moduleOutputPath = import_path.default.join(outputDir, module2.moduleName);
|
|
191
192
|
if (!import_fs.default.existsSync(moduleOutputPath)) import_fs.default.mkdirSync(moduleOutputPath, { recursive: true });
|
|
192
193
|
console.log(import_chalk.default.cyan(`
|
|
193
|
-
Generating module: ${import_chalk.default.bold(moduleName)}`));
|
|
194
|
+
Generating module: ${import_chalk.default.bold(module2.moduleName)}`));
|
|
194
195
|
const typesToImport = [...module2.schemas].sort();
|
|
195
196
|
let configContent = `/* eslint-disable */
|
|
196
197
|
// This file is auto-generated.
|
|
@@ -199,13 +200,13 @@ import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core
|
|
|
199
200
|
`;
|
|
200
201
|
if (typesToImport.length > 0) configContent += `import type { ${typesToImport.join(", ")} } from './types';
|
|
201
202
|
`;
|
|
202
|
-
const actionsType = Object.values(module2.actions).map((a) => ` ${
|
|
203
|
+
const actionsType = Object.values(module2.actions).map((a) => ` ${a.name}: ActionConfigModule<${a.inputType}, ${a.outputType}>;`).join("\n");
|
|
203
204
|
const actionsValue = Object.values(module2.actions).map((a) => {
|
|
204
|
-
const {
|
|
205
|
-
return ` ${
|
|
205
|
+
const { inputType, outputType, name, ...c } = a;
|
|
206
|
+
return ` ${name}: ${JSON.stringify(c, null, 2).replace(/\n/g, "\n ")}`;
|
|
206
207
|
}).join(",\n");
|
|
207
208
|
configContent += `
|
|
208
|
-
export const ${moduleName}Module: ApiModuleConfig<{
|
|
209
|
+
export const ${module2.moduleName}Module: ApiModuleConfig<{
|
|
209
210
|
${actionsType}
|
|
210
211
|
}> = {
|
|
211
212
|
baseEndpoint: '${module2.baseEndpoint}',
|
|
@@ -214,154 +215,162 @@ ${actionsValue}
|
|
|
214
215
|
},
|
|
215
216
|
};
|
|
216
217
|
`;
|
|
217
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "config.ts"), configContent.trim()
|
|
218
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "config.ts"), configContent.trim());
|
|
218
219
|
console.log(import_chalk.default.gray(` \u2713 config.ts`));
|
|
219
|
-
|
|
220
|
-
|
|
220
|
+
const indexContent = [`// This file is auto-generated.
|
|
221
|
+
|
|
222
|
+
export * from './config';`];
|
|
223
|
+
if (typesToImport.length > 0) {
|
|
224
|
+
let typesContent = `// This file is auto-generated.
|
|
225
|
+
|
|
226
|
+
`;
|
|
227
|
+
for (const typeName of typesToImport) {
|
|
228
|
+
const parsedSchema = allSchemas.get(typeName);
|
|
229
|
+
if (parsedSchema) {
|
|
230
|
+
if (parsedSchema.description) typesContent += `/**
|
|
231
|
+
* ${parsedSchema.description}
|
|
232
|
+
*/
|
|
233
|
+
`;
|
|
234
|
+
typesContent += `export interface ${typeName} {
|
|
235
|
+
`;
|
|
236
|
+
for (const prop of parsedSchema.properties) {
|
|
237
|
+
if (prop.description) typesContent += ` /**
|
|
238
|
+
* ${prop.description}
|
|
239
|
+
${prop.example ? ` * @example ${JSON.stringify(prop.example)}
|
|
240
|
+
` : ""} */
|
|
241
|
+
`;
|
|
242
|
+
let propType = prop.type;
|
|
243
|
+
if (prop.enum) propType = prop.enum.map((e) => typeof e === "string" ? `'${e}'` : e).join(" | ");
|
|
244
|
+
else if (prop.items) propType = `${toPascalCase(prop.items.name)}[]`;
|
|
245
|
+
typesContent += ` ${prop.name}${prop.isRequired ? "" : "?"}: ${propType};
|
|
246
|
+
`;
|
|
247
|
+
}
|
|
248
|
+
typesContent += `}
|
|
221
249
|
|
|
222
250
|
`;
|
|
223
|
-
const tsOptions = { bannerComment: "", style: { bracketSpacing: true, printWidth: 120, semi: true, singleQuote: true, tabWidth: 2 }, additionalProperties: false };
|
|
224
|
-
for (const typeName of typesToImport) {
|
|
225
|
-
const parsedSchema = allSchemas.get(typeName);
|
|
226
|
-
if (parsedSchema) {
|
|
227
|
-
try {
|
|
228
|
-
const tsType = await (0, import_json_schema_to_typescript.compile)(parsedSchema.schema, typeName, tsOptions);
|
|
229
|
-
typesContent += tsType + "\n";
|
|
230
|
-
} catch (e) {
|
|
231
|
-
console.error(import_chalk.default.red(` - Error compiling type "${typeName}": ${e.message}`));
|
|
232
251
|
}
|
|
233
252
|
}
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
253
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "types.ts"), typesContent);
|
|
254
|
+
console.log(import_chalk.default.gray(` \u2713 types.ts`));
|
|
255
|
+
indexContent.push(`export * from './types';`);
|
|
256
|
+
let validationContent = `// This file is auto-generated.
|
|
238
257
|
import { z } from 'zod';
|
|
239
258
|
|
|
240
259
|
`;
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
260
|
+
for (const typeName of typesToImport) {
|
|
261
|
+
const parsedSchema = allSchemas.get(typeName);
|
|
262
|
+
if (parsedSchema) {
|
|
263
|
+
let zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
|
|
264
|
+
validationContent += `export const ${typeName}Schema = z.object({
|
|
265
|
+
${zodShape}
|
|
266
|
+
});
|
|
245
267
|
|
|
246
268
|
`;
|
|
269
|
+
}
|
|
247
270
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
271
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "validation.ts"), validationContent);
|
|
272
|
+
console.log(import_chalk.default.gray(` \u2713 validation.ts`));
|
|
273
|
+
indexContent.push(`export * from './validation';`);
|
|
274
|
+
let mocksContent = `// This file is auto-generated.
|
|
252
275
|
import type { ${typesToImport.join(", ")} } from './types';
|
|
253
276
|
|
|
254
277
|
`;
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
278
|
+
for (const typeName of typesToImport) {
|
|
279
|
+
const parsedSchema = allSchemas.get(typeName);
|
|
280
|
+
if (parsedSchema) {
|
|
281
|
+
let mockObject = {};
|
|
282
|
+
parsedSchema.properties.forEach((p) => {
|
|
283
|
+
mockObject[p.name] = _propToMock(p);
|
|
284
|
+
});
|
|
285
|
+
mocksContent += `export const mock${typeName}: ${typeName} = ${JSON.stringify(mockObject, null, 2)};
|
|
259
286
|
|
|
260
287
|
`;
|
|
288
|
+
}
|
|
261
289
|
}
|
|
290
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "mocks.ts"), mocksContent);
|
|
291
|
+
console.log(import_chalk.default.gray(` \u2713 mocks.ts`));
|
|
292
|
+
indexContent.push(`export * from './mocks';`);
|
|
262
293
|
}
|
|
263
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "
|
|
264
|
-
console.log(import_chalk.default.gray(` \u2713 mocks.ts`));
|
|
265
|
-
let indexContent = `// This file is auto-generated.
|
|
266
|
-
|
|
267
|
-
export * from './config';
|
|
268
|
-
export * from './types';
|
|
269
|
-
export * from './validation';
|
|
270
|
-
export * from './mocks';
|
|
271
|
-
`;
|
|
272
|
-
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "index.ts"), indexContent, { encoding: "utf-8" });
|
|
294
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "index.ts"), indexContent.join("\n"));
|
|
273
295
|
console.log(import_chalk.default.gray(` \u2713 index.ts`));
|
|
274
296
|
}
|
|
275
|
-
function
|
|
276
|
-
const shape = [];
|
|
277
|
-
if (schema.properties) {
|
|
278
|
-
for (const [key, prop] of Object.entries(schema.properties)) {
|
|
279
|
-
shape.push(` ${key}: ${_propToZod(prop, (schema.required || []).includes(key))}`);
|
|
280
|
-
}
|
|
281
|
-
}
|
|
282
|
-
return `z.object({
|
|
283
|
-
${shape.join(",\n")}
|
|
284
|
-
})`;
|
|
285
|
-
}
|
|
286
|
-
function _propToZod(prop, isRequired) {
|
|
297
|
+
function _propToZod(prop) {
|
|
287
298
|
let zodString = "z.any()";
|
|
299
|
+
const requiredMsg = { required_error: prop.description || generateFriendlyMessage(prop.name, "required") };
|
|
288
300
|
switch (prop.type) {
|
|
289
301
|
case "string":
|
|
290
|
-
zodString =
|
|
291
|
-
if (prop.format === "email") zodString += ".email
|
|
292
|
-
if (prop.format === "uuid") zodString +=
|
|
293
|
-
if (prop.enum) zodString = `z.enum(${JSON.stringify(prop.enum)})`;
|
|
302
|
+
zodString = `z.string(${JSON.stringify(requiredMsg)})`;
|
|
303
|
+
if (prop.format === "email") zodString += `.email({ message: "${generateFriendlyMessage(prop.name, "email")}" })`;
|
|
304
|
+
if (prop.format === "uuid") zodString += `.uuid()`;
|
|
305
|
+
if (prop.enum) zodString = `z.enum(${JSON.stringify(prop.enum)}, ${JSON.stringify(requiredMsg)})`;
|
|
294
306
|
break;
|
|
295
307
|
case "integer":
|
|
296
308
|
case "number":
|
|
297
|
-
zodString =
|
|
298
|
-
if (prop.minimum !== void 0) zodString += `.min(${prop.minimum})`;
|
|
299
|
-
if (prop.maximum !== void 0) zodString += `.max(${prop.maximum})`;
|
|
309
|
+
zodString = `z.number(${JSON.stringify(requiredMsg)})`;
|
|
300
310
|
break;
|
|
301
311
|
case "boolean":
|
|
302
|
-
zodString =
|
|
312
|
+
zodString = `z.boolean(${JSON.stringify(requiredMsg)})`;
|
|
303
313
|
break;
|
|
304
314
|
case "array":
|
|
305
|
-
zodString = `z.array(${prop.items ? _propToZod(prop.items
|
|
315
|
+
zodString = `z.array(${prop.items ? _propToZod(prop.items) : "z.any()"})`;
|
|
306
316
|
break;
|
|
307
317
|
case "object":
|
|
308
|
-
|
|
318
|
+
let shape = "z.any()";
|
|
319
|
+
if (prop.properties) shape = `z.object({
|
|
320
|
+
${prop.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n")}
|
|
321
|
+
})`;
|
|
322
|
+
zodString = shape;
|
|
309
323
|
break;
|
|
310
324
|
}
|
|
311
|
-
|
|
325
|
+
if (!prop.isRequired) zodString += ".optional()";
|
|
326
|
+
if (prop.isNullable) zodString += ".nullable()";
|
|
327
|
+
return zodString;
|
|
312
328
|
}
|
|
313
|
-
function
|
|
314
|
-
if (
|
|
315
|
-
|
|
329
|
+
function _propToMock(prop) {
|
|
330
|
+
if (prop.example) return prop.example;
|
|
331
|
+
if (prop.name.match(/image|avatar|logo|url/i)) return "https://via.placeholder.com/150";
|
|
332
|
+
if (prop.enum) return prop.enum[0];
|
|
333
|
+
switch (prop.type) {
|
|
316
334
|
case "string":
|
|
317
|
-
if (
|
|
318
|
-
if (
|
|
319
|
-
|
|
320
|
-
return "Mock String";
|
|
335
|
+
if (prop.format === "email") return "test@example.com";
|
|
336
|
+
if (prop.format === "uuid") return "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11";
|
|
337
|
+
return `Mock ${toPascalCase(prop.name)}`;
|
|
321
338
|
case "integer":
|
|
322
339
|
case "number":
|
|
323
340
|
return 1;
|
|
324
341
|
case "boolean":
|
|
325
342
|
return true;
|
|
326
343
|
case "array":
|
|
327
|
-
return
|
|
344
|
+
return prop.items ? [_propToMock(prop.items)] : [];
|
|
328
345
|
case "object":
|
|
329
346
|
const mock = {};
|
|
330
|
-
if (
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
}
|
|
334
|
-
}
|
|
347
|
+
if (prop.properties) prop.properties.forEach((p) => {
|
|
348
|
+
mock[p.name] = _propToMock(p);
|
|
349
|
+
});
|
|
335
350
|
return mock;
|
|
336
351
|
default:
|
|
337
352
|
return null;
|
|
338
353
|
}
|
|
339
354
|
}
|
|
340
|
-
async function runGenerator() {
|
|
341
|
-
|
|
342
|
-
output: "src/lib/api",
|
|
343
|
-
envPath: ".env"
|
|
344
|
-
};
|
|
345
|
-
console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator..."));
|
|
355
|
+
async function runGenerator(options) {
|
|
356
|
+
console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator (Phoenix Edition)..."));
|
|
346
357
|
import_dotenv.default.config({ path: options.envPath });
|
|
347
358
|
const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
|
|
348
|
-
console.log(import_chalk.default.blue("\u2713 Step 1: Environment variables loaded."));
|
|
349
359
|
try {
|
|
350
360
|
console.log(import_chalk.default.blue(`
|
|
351
|
-
\u23F3 Step
|
|
361
|
+
\u23F3 Step 1: Dereferencing spec from ${specUrl}...`));
|
|
352
362
|
const spec = await import_swagger_parser.default.dereference(specUrl);
|
|
353
|
-
console.log(import_chalk.default.green("\u2713 Spec
|
|
363
|
+
console.log(import_chalk.default.green("\u2713 Spec fully dereferenced."));
|
|
354
364
|
debugLog("Dereferenced Spec", spec);
|
|
355
|
-
console.log(import_chalk.default.blue("\n\u23F3 Step
|
|
365
|
+
console.log(import_chalk.default.blue("\n\u23F3 Step 2: Parsing spec with intelligent grouping..."));
|
|
356
366
|
const { modules, allSchemas } = parseSpecToModules(spec);
|
|
357
367
|
console.log(import_chalk.default.green(`\u2713 Found and grouped ${modules.size} logical modules.`));
|
|
358
|
-
|
|
359
|
-
console.log(import_chalk.default.blue("\n\u23F3 Step 4: Generating all module files..."));
|
|
368
|
+
console.log(import_chalk.default.blue("\n\u23F3 Step 3: Generating all module files..."));
|
|
360
369
|
for (const module2 of modules.values()) {
|
|
361
370
|
await generateModuleFiles(module2, allSchemas, options.output);
|
|
362
371
|
}
|
|
363
372
|
console.log(import_chalk.default.green("\n\u2713 All module files generated successfully."));
|
|
364
|
-
console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete!"));
|
|
373
|
+
console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete! Your development platform is ready."));
|
|
365
374
|
console.log(import_chalk.default.bold.cyan(` Output directory: ${options.output}`));
|
|
366
375
|
} catch (error) {
|
|
367
376
|
console.error(import_chalk.default.red.bold("\n\u274C An error occurred during generation:"));
|