api-core-lib 12.12.102 → 12.12.103
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 +320 -70
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -74,7 +74,7 @@ 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
|
|
77
|
+
var import_inquirer = __toESM(require("inquirer"), 1);
|
|
78
78
|
var DEBUG_MODE = process.env.DEBUG === "true";
|
|
79
79
|
var debugLog = (title, data) => DEBUG_MODE && console.log(import_chalk.default.yellow(`
|
|
80
80
|
[DEBUG: ${title}]`), import_util.default.inspect(data, { depth: 5, colors: true }));
|
|
@@ -88,19 +88,93 @@ function findCommonPath(paths) {
|
|
|
88
88
|
const first = sortedPaths[0].split("/");
|
|
89
89
|
const last = sortedPaths[sortedPaths.length - 1].split("/");
|
|
90
90
|
let i = 0;
|
|
91
|
-
while (i < first.length && first[i] === last[i])
|
|
92
|
-
i++;
|
|
93
|
-
}
|
|
91
|
+
while (i < first.length && first[i] === last[i]) i++;
|
|
94
92
|
return first.slice(0, i).join("/") || "/";
|
|
95
93
|
}
|
|
94
|
+
function _propToZod(prop) {
|
|
95
|
+
let zodChain;
|
|
96
|
+
const getMsg = (key) => `{ "message": "validation.${key}" }`;
|
|
97
|
+
switch (prop.type) {
|
|
98
|
+
case "string":
|
|
99
|
+
if (prop.enumName) {
|
|
100
|
+
zodChain = `z.enum(${prop.enumName})`;
|
|
101
|
+
} else {
|
|
102
|
+
zodChain = "z.string()";
|
|
103
|
+
if (prop.isRequired) zodChain += `.min(1, ${getMsg("string.nonempty")})`;
|
|
104
|
+
if (prop.maxLength !== void 0) zodChain += `.max(${prop.maxLength}, ${getMsg("string.max")})`;
|
|
105
|
+
if (prop.pattern) zodChain += `.regex(/${prop.pattern}/, ${getMsg("string.regex")})`;
|
|
106
|
+
if (prop.format === "email") zodChain += `.email(${getMsg("string.email")})`;
|
|
107
|
+
if (prop.format === "url") zodChain += `.url(${getMsg("string.url")})`;
|
|
108
|
+
if (prop.format === "uuid") zodChain += `.uuid(${getMsg("string.uuid")})`;
|
|
109
|
+
}
|
|
110
|
+
break;
|
|
111
|
+
case "integer":
|
|
112
|
+
case "number":
|
|
113
|
+
zodChain = prop.type === "integer" ? `z.number().int(${getMsg("number.integer")})` : "z.number()";
|
|
114
|
+
if (prop.minimum !== void 0) zodChain += `.min(${prop.minimum}, ${getMsg("number.min")})`;
|
|
115
|
+
if (prop.maximum !== void 0) zodChain += `.max(${prop.maximum}, ${getMsg("number.max")})`;
|
|
116
|
+
break;
|
|
117
|
+
case "boolean":
|
|
118
|
+
zodChain = `z.boolean()`;
|
|
119
|
+
break;
|
|
120
|
+
case "array":
|
|
121
|
+
const itemSchema = prop.items ? _propToZod(prop.items) : "z.any()";
|
|
122
|
+
zodChain = `z.array(${itemSchema})`;
|
|
123
|
+
if (prop.minItems !== void 0) zodChain += `.min(${prop.minItems}, ${getMsg("array.min")})`;
|
|
124
|
+
if (prop.maxItems !== void 0) zodChain += `.max(${prop.maxItems}, ${getMsg("array.max")})`;
|
|
125
|
+
break;
|
|
126
|
+
case "object":
|
|
127
|
+
if (prop.properties && prop.properties.length > 0) {
|
|
128
|
+
const shape = prop.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
|
|
129
|
+
zodChain = `z.object({
|
|
130
|
+
${shape}
|
|
131
|
+
})`;
|
|
132
|
+
} else {
|
|
133
|
+
zodChain = "z.record(z.unknown())";
|
|
134
|
+
}
|
|
135
|
+
break;
|
|
136
|
+
default:
|
|
137
|
+
zodChain = "z.any()";
|
|
138
|
+
break;
|
|
139
|
+
}
|
|
140
|
+
if (prop.description) zodChain += `.describe(${JSON.stringify(prop.description)})`;
|
|
141
|
+
if (!prop.isRequired) zodChain += ".optional()";
|
|
142
|
+
if (prop.isNullable) zodChain += ".nullable()";
|
|
143
|
+
return zodChain;
|
|
144
|
+
}
|
|
145
|
+
function _propToMock(prop) {
|
|
146
|
+
if (prop.example) return prop.example;
|
|
147
|
+
if (prop.name.match(/image|avatar|logo|url/i)) return "https://via.placeholder.com/150";
|
|
148
|
+
if (prop.enum) return prop.enum[0];
|
|
149
|
+
switch (prop.type) {
|
|
150
|
+
case "string":
|
|
151
|
+
if (prop.format === "email") return "test@example.com";
|
|
152
|
+
if (prop.format === "uuid") return "a0eebc99-9c0b-4ef8-bb6d-6bb9bd380a11";
|
|
153
|
+
return `Mock ${toPascalCase(prop.name)}`;
|
|
154
|
+
case "integer":
|
|
155
|
+
case "number":
|
|
156
|
+
return 1;
|
|
157
|
+
case "boolean":
|
|
158
|
+
return true;
|
|
159
|
+
case "array":
|
|
160
|
+
return prop.items ? [_propToMock(prop.items)] : [];
|
|
161
|
+
case "object":
|
|
162
|
+
const mock = {};
|
|
163
|
+
if (prop.properties) prop.properties.forEach((p) => {
|
|
164
|
+
mock[p.name] = _propToMock(p);
|
|
165
|
+
});
|
|
166
|
+
return mock;
|
|
167
|
+
default:
|
|
168
|
+
return null;
|
|
169
|
+
}
|
|
170
|
+
}
|
|
96
171
|
function parseSchema(name, schema, allEnums) {
|
|
97
172
|
const properties = [];
|
|
98
173
|
const enums = {};
|
|
99
174
|
if (schema.properties) {
|
|
100
175
|
for (const propName in schema.properties) {
|
|
101
176
|
const propSchema = schema.properties[propName];
|
|
102
|
-
let itemSchema;
|
|
103
|
-
let generatedEnumName;
|
|
177
|
+
let itemSchema, generatedEnumName;
|
|
104
178
|
if (propSchema.type === "array" && propSchema.items) {
|
|
105
179
|
const itemTypeName = `${toPascalCase(name)}${toPascalCase(propName)}Item`;
|
|
106
180
|
itemSchema = parseSchema(itemTypeName, propSchema.items, allEnums).properties[0];
|
|
@@ -113,55 +187,25 @@ function parseSchema(name, schema, allEnums) {
|
|
|
113
187
|
}
|
|
114
188
|
generatedEnumName = enumName;
|
|
115
189
|
}
|
|
116
|
-
properties.push({
|
|
117
|
-
name: propName,
|
|
118
|
-
type: propSchema.type || "object",
|
|
119
|
-
isRequired: (schema.required || []).includes(propName),
|
|
120
|
-
isNullable: propSchema.nullable || false,
|
|
121
|
-
description: propSchema.description,
|
|
122
|
-
example: propSchema.example,
|
|
123
|
-
enum: propSchema.enum,
|
|
124
|
-
enumName: generatedEnumName,
|
|
125
|
-
format: propSchema.format,
|
|
126
|
-
items: itemSchema,
|
|
127
|
-
properties: propSchema.properties ? parseSchema(`${name}${toPascalCase(propName)}`, propSchema, allEnums).properties : void 0,
|
|
128
|
-
minLength: propSchema.minLength,
|
|
129
|
-
maxLength: propSchema.maxLength,
|
|
130
|
-
pattern: propSchema.pattern,
|
|
131
|
-
minimum: propSchema.minimum,
|
|
132
|
-
maximum: propSchema.maximum,
|
|
133
|
-
minItems: propSchema.minItems,
|
|
134
|
-
maxItems: propSchema.maxItems
|
|
135
|
-
});
|
|
190
|
+
properties.push({ name: propName, type: propSchema.type || "object", isRequired: (schema.required || []).includes(propName), isNullable: propSchema.nullable || false, description: propSchema.description, example: propSchema.example, enum: propSchema.enum, enumName: generatedEnumName, format: propSchema.format, items: itemSchema, properties: propSchema.properties ? parseSchema(`${name}${toPascalCase(propName)}`, propSchema, allEnums).properties : void 0, minLength: propSchema.minLength, maxLength: propSchema.maxLength, pattern: propSchema.pattern, minimum: propSchema.minimum, maximum: propSchema.maximum, minItems: propSchema.minItems, maxItems: propSchema.maxItems });
|
|
136
191
|
}
|
|
137
192
|
}
|
|
138
193
|
return { name, description: schema.description, properties, enums };
|
|
139
194
|
}
|
|
140
195
|
function parseSpecToModules(spec) {
|
|
141
|
-
const modules = /* @__PURE__ */ new Map();
|
|
142
|
-
const allSchemas = /* @__PURE__ */ new Map();
|
|
143
|
-
const allEnums = /* @__PURE__ */ new Map();
|
|
144
|
-
const modulePaths = /* @__PURE__ */ new Map();
|
|
196
|
+
const modules = /* @__PURE__ */ new Map(), allSchemas = /* @__PURE__ */ new Map(), allEnums = /* @__PURE__ */ new Map(), modulePaths = /* @__PURE__ */ new Map();
|
|
145
197
|
const BUILT_IN_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "void", "undefined", "unknown", "any", "Date", "Promise", "QueryOptions", "Record<string, any>", "Record<string, unknown>"]);
|
|
146
198
|
const registerSchema = (schema, baseName) => {
|
|
147
199
|
if (!schema) return "Record<string, any>";
|
|
148
200
|
if (schema.type === "array" && schema.items) {
|
|
149
|
-
const itemSchema = schema.items
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
return `${registerSchema(itemSchema, itemBaseName)}[]`;
|
|
153
|
-
}
|
|
154
|
-
const primitiveType = itemSchema.type === "integer" ? "number" : itemSchema.type || "any";
|
|
155
|
-
return `${primitiveType}[]`;
|
|
201
|
+
const itemSchema = schema.items, itemBaseName = `${baseName}Item`;
|
|
202
|
+
if (itemSchema.properties || itemSchema.type === "object") return `${registerSchema(itemSchema, itemBaseName)}[]`;
|
|
203
|
+
return `${itemSchema.type === "integer" ? "number" : itemSchema.type || "any"}[]`;
|
|
156
204
|
}
|
|
157
205
|
if (schema.type === "object" || schema.properties || schema.allOf || !schema.type) {
|
|
158
|
-
if (!schema.properties && !schema.allOf)
|
|
159
|
-
return "Record<string, any>";
|
|
160
|
-
}
|
|
206
|
+
if (!schema.properties && !schema.allOf) return "Record<string, any>";
|
|
161
207
|
const typeName = toPascalCase(baseName.replace(/_v\d+(Request|Response)$/, "$1"));
|
|
162
|
-
if (!allSchemas.has(typeName))
|
|
163
|
-
allSchemas.set(typeName, parseSchema(typeName, schema, allEnums));
|
|
164
|
-
}
|
|
208
|
+
if (!allSchemas.has(typeName)) allSchemas.set(typeName, parseSchema(typeName, schema, allEnums));
|
|
165
209
|
return typeName;
|
|
166
210
|
}
|
|
167
211
|
return schema.type === "integer" ? "number" : schema.type || "any";
|
|
@@ -173,8 +217,7 @@ function parseSpecToModules(spec) {
|
|
|
173
217
|
if (!Object.values(import_openapi_types.OpenAPIV3.HttpMethods).includes(method)) continue;
|
|
174
218
|
const endpoint = pathItem[method];
|
|
175
219
|
if (!endpoint.tags || endpoint.tags.length === 0 || !endpoint.operationId) continue;
|
|
176
|
-
const
|
|
177
|
-
const moduleName = sanitizeForModuleName(tagName);
|
|
220
|
+
const moduleName = sanitizeForModuleName(endpoint.tags[0]);
|
|
178
221
|
if (!modules.has(moduleName)) {
|
|
179
222
|
modules.set(moduleName, { moduleName, baseEndpoint: "", actions: {}, schemas: /* @__PURE__ */ new Set(), enums: /* @__PURE__ */ new Set() });
|
|
180
223
|
modulePaths.set(moduleName, []);
|
|
@@ -186,11 +229,8 @@ function parseSpecToModules(spec) {
|
|
|
186
229
|
const outputType = successKey === "204" ? "void" : registerSchema(successRes?.content?.["application/json"]?.schema, `${endpoint.operationId}Response`);
|
|
187
230
|
const reqBody = endpoint.requestBody;
|
|
188
231
|
let inputType = "undefined";
|
|
189
|
-
if (reqBody?.content?.["application/json"]?.schema) {
|
|
190
|
-
|
|
191
|
-
} else if ((endpoint.parameters || []).some((p) => p.in === "query")) {
|
|
192
|
-
inputType = "QueryOptions";
|
|
193
|
-
}
|
|
232
|
+
if (reqBody?.content?.["application/json"]?.schema) inputType = registerSchema(reqBody.content["application/json"].schema, `${endpoint.operationId}Request`);
|
|
233
|
+
else if ((endpoint.parameters || []).some((p) => p.in === "query")) inputType = "QueryOptions";
|
|
194
234
|
[inputType, outputType].forEach((t) => {
|
|
195
235
|
const cleanType = t.replace("[]", "");
|
|
196
236
|
if (cleanType && !BUILT_IN_TYPES.has(cleanType)) {
|
|
@@ -199,20 +239,7 @@ function parseSpecToModules(spec) {
|
|
|
199
239
|
if (schemaDef) Object.keys(schemaDef.enums).forEach((propName) => currentModule.enums.add(`${toPascalCase(cleanType)}${toPascalCase(propName)}Enum`));
|
|
200
240
|
}
|
|
201
241
|
});
|
|
202
|
-
|
|
203
|
-
const pathParams = (apiPath.match(/{(\w+)}/g) || []).map((p) => p.slice(1, -1));
|
|
204
|
-
currentModule.actions[actionName] = {
|
|
205
|
-
name: actionName,
|
|
206
|
-
method: method.toUpperCase(),
|
|
207
|
-
path: apiPath,
|
|
208
|
-
description: endpoint.summary || "",
|
|
209
|
-
hasQuery: (endpoint.parameters || []).some((p) => p.in === "query"),
|
|
210
|
-
autoFetch: method.toUpperCase() === "GET" && !apiPath.includes("{"),
|
|
211
|
-
requiresAuth: !!endpoint.security && endpoint.security.length > 0,
|
|
212
|
-
inputType,
|
|
213
|
-
outputType,
|
|
214
|
-
pathParams
|
|
215
|
-
};
|
|
242
|
+
currentModule.actions[getActionName(endpoint.operationId)] = { name: getActionName(endpoint.operationId), 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, pathParams: (apiPath.match(/{(\w+)}/g) || []).map((p) => p.slice(1, -1)) };
|
|
216
243
|
}
|
|
217
244
|
}
|
|
218
245
|
modules.forEach((mod, name) => {
|
|
@@ -227,10 +254,233 @@ async function generateModuleFiles(module2, allSchemas, allEnums, outputDir) {
|
|
|
227
254
|
if (!import_fs.default.existsSync(moduleOutputPath)) import_fs.default.mkdirSync(moduleOutputPath, { recursive: true });
|
|
228
255
|
console.log(import_chalk.default.cyan(`
|
|
229
256
|
Generating module: ${import_chalk.default.bold(module2.moduleName)}`));
|
|
230
|
-
|
|
257
|
+
const BUILT_IN_TYPES = /* @__PURE__ */ new Set(["string", "number", "boolean", "void", "undefined", "unknown", "any", "Date", "Promise", "QueryOptions", "Record<string, any>", "Record<string, unknown>"]);
|
|
258
|
+
const schemasToImport = [...module2.schemas].filter((name) => !BUILT_IN_TYPES.has(name)).sort();
|
|
259
|
+
const enumsToImport = [...module2.enums].sort();
|
|
260
|
+
const createdFileExports = ["config"];
|
|
261
|
+
let configContent = `// Auto-generated file. Do not edit.
|
|
262
|
+
|
|
263
|
+
import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
|
|
264
|
+
`;
|
|
265
|
+
if (schemasToImport.length > 0) configContent += `import type { ${schemasToImport.join(", ")} } from './types';
|
|
266
|
+
`;
|
|
267
|
+
const actionsType = Object.values(module2.actions).map((a) => ` ${a.name}: ActionConfigModule<${a.inputType}, ${a.outputType}>;`).join("\n");
|
|
268
|
+
const actionsValue = Object.values(module2.actions).map((a) => {
|
|
269
|
+
const { inputType, outputType, name, ...c } = a;
|
|
270
|
+
return ` ${name}: ${JSON.stringify(c, null, 2).replace(/\n/g, "\n ")}`;
|
|
271
|
+
}).join(",\n");
|
|
272
|
+
configContent += `
|
|
273
|
+
export const ${module2.moduleName}: ApiModuleConfig<{
|
|
274
|
+
${actionsType}
|
|
275
|
+
}> = {
|
|
276
|
+
baseEndpoint: '${module2.baseEndpoint}',
|
|
277
|
+
actions: {
|
|
278
|
+
${actionsValue}
|
|
279
|
+
},
|
|
280
|
+
};
|
|
281
|
+
`;
|
|
282
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "config.ts"), configContent.trim());
|
|
283
|
+
console.log(import_chalk.default.gray(` \u2713 config.ts`));
|
|
284
|
+
if (schemasToImport.length > 0) {
|
|
285
|
+
if (enumsToImport.length > 0) {
|
|
286
|
+
let enumsContent = `// Auto-generated file. Do not edit.
|
|
287
|
+
|
|
288
|
+
`;
|
|
289
|
+
enumsToImport.forEach((enumName) => {
|
|
290
|
+
const enumDef = allEnums.get(enumName);
|
|
291
|
+
if (enumDef) {
|
|
292
|
+
enumsContent += `export const ${enumName} = ${JSON.stringify(enumDef.values)} as const;
|
|
293
|
+
`;
|
|
294
|
+
enumsContent += `export type ${enumName} = typeof ${enumName}[number];
|
|
295
|
+
|
|
296
|
+
`;
|
|
297
|
+
}
|
|
298
|
+
});
|
|
299
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "enums.ts"), enumsContent.trim());
|
|
300
|
+
console.log(import_chalk.default.gray(` \u2713 enums.ts`));
|
|
301
|
+
createdFileExports.push("enums");
|
|
302
|
+
}
|
|
303
|
+
let typesContent = `// Auto-generated file. Do not edit.
|
|
304
|
+
|
|
305
|
+
`;
|
|
306
|
+
if (enumsToImport.length > 0) typesContent += `import type { ${enumsToImport.join(", ")} } from './enums';
|
|
307
|
+
|
|
308
|
+
`;
|
|
309
|
+
schemasToImport.forEach((typeName) => {
|
|
310
|
+
const parsedSchema = allSchemas.get(typeName);
|
|
311
|
+
if (parsedSchema) {
|
|
312
|
+
if (parsedSchema.description) typesContent += `/** ${parsedSchema.description} */
|
|
313
|
+
`;
|
|
314
|
+
typesContent += `export interface ${typeName} {
|
|
315
|
+
`;
|
|
316
|
+
parsedSchema.properties.forEach((prop) => {
|
|
317
|
+
if (prop.description) typesContent += ` /** ${prop.description} */
|
|
318
|
+
`;
|
|
319
|
+
let propType = prop.enumName || (prop.items ? `${prop.items.type || "any"}[]` : prop.type);
|
|
320
|
+
if (propType === "integer") propType = "number";
|
|
321
|
+
if (propType === "object") propType = "Record<string, any>";
|
|
322
|
+
typesContent += ` ${prop.name}${prop.isRequired ? "" : "?"}: ${propType};
|
|
323
|
+
`;
|
|
324
|
+
});
|
|
325
|
+
typesContent += `}
|
|
326
|
+
|
|
327
|
+
`;
|
|
328
|
+
}
|
|
329
|
+
});
|
|
330
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "types.ts"), typesContent.trim());
|
|
331
|
+
console.log(import_chalk.default.gray(` \u2713 types.ts`));
|
|
332
|
+
createdFileExports.push("types");
|
|
333
|
+
let validationContent = `// Auto-generated file. Do not edit.
|
|
334
|
+
|
|
335
|
+
import { z } from 'zod';
|
|
336
|
+
`;
|
|
337
|
+
if (enumsToImport.length > 0) validationContent += `import { ${enumsToImport.join(", ")} } from './enums';
|
|
338
|
+
`;
|
|
339
|
+
schemasToImport.forEach((typeName) => {
|
|
340
|
+
const parsedSchema = allSchemas.get(typeName);
|
|
341
|
+
if (parsedSchema) {
|
|
342
|
+
const zodShape = parsedSchema.properties.map((p) => ` ${p.name}: ${_propToZod(p)}`).join(",\n");
|
|
343
|
+
validationContent += `
|
|
344
|
+
/** Zod schema for {@link ${typeName}}. */
|
|
345
|
+
`;
|
|
346
|
+
validationContent += `export const ${typeName}Schema = z.object({
|
|
347
|
+
${zodShape}
|
|
348
|
+
});
|
|
349
|
+
|
|
350
|
+
`;
|
|
351
|
+
validationContent += `export type ${typeName}Validated = z.infer<typeof ${typeName}Schema>;
|
|
352
|
+
`;
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "validation.ts"), validationContent.trim());
|
|
356
|
+
console.log(import_chalk.default.gray(` \u2713 validation.ts`));
|
|
357
|
+
createdFileExports.push("validation");
|
|
358
|
+
let mocksContent = `// Auto-generated file. Do not edit.
|
|
359
|
+
import type { ${schemasToImport.join(", ")} } from './types';
|
|
360
|
+
`;
|
|
361
|
+
if (enumsToImport.length > 0) mocksContent += `import { ${enumsToImport.join(", ")} } from './enums';
|
|
362
|
+
|
|
363
|
+
`;
|
|
364
|
+
schemasToImport.forEach((typeName) => {
|
|
365
|
+
const parsedSchema = allSchemas.get(typeName);
|
|
366
|
+
if (parsedSchema) {
|
|
367
|
+
const mockObject = {};
|
|
368
|
+
parsedSchema.properties.forEach((p) => {
|
|
369
|
+
mockObject[p.name] = _propToMock(p);
|
|
370
|
+
});
|
|
371
|
+
mocksContent += `export const mock${typeName}: ${typeName} = ${JSON.stringify(mockObject, null, 2)};
|
|
372
|
+
|
|
373
|
+
`;
|
|
374
|
+
}
|
|
375
|
+
});
|
|
376
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "mocks.ts"), mocksContent.trim());
|
|
377
|
+
console.log(import_chalk.default.gray(` \u2713 mocks.ts`));
|
|
378
|
+
createdFileExports.push("mocks");
|
|
379
|
+
}
|
|
380
|
+
const indexFilePath = import_path.default.join(moduleOutputPath, "index.ts");
|
|
381
|
+
const initialIndexContent = `// Auto-generated file. Do not edit.
|
|
382
|
+
` + createdFileExports.map((e) => `export * from './${e}';`).join("\n");
|
|
383
|
+
import_fs.default.writeFileSync(indexFilePath, initialIndexContent);
|
|
384
|
+
console.log(import_chalk.default.gray(` \u2713 index.ts (Initial Entry Point)`));
|
|
385
|
+
const moduleBaseName = module2.moduleName.replace(/Api$/, "");
|
|
386
|
+
const camelCaseModuleName = toCamelCase(moduleBaseName);
|
|
387
|
+
let endpointsContent = `// Auto-generated file. Do not edit.
|
|
388
|
+
|
|
389
|
+
`;
|
|
390
|
+
endpointsContent += `import type { QueryOptions } from 'api-core-lib';
|
|
391
|
+
`;
|
|
392
|
+
const endpointTypesToImport = /* @__PURE__ */ new Set();
|
|
393
|
+
Object.values(module2.actions).forEach((action) => {
|
|
394
|
+
if (action.inputType !== "undefined" && action.inputType !== "QueryOptions" && !BUILT_IN_TYPES.has(action.inputType)) {
|
|
395
|
+
endpointTypesToImport.add(action.inputType);
|
|
396
|
+
}
|
|
397
|
+
});
|
|
398
|
+
if (endpointTypesToImport.size > 0) {
|
|
399
|
+
endpointsContent += `import type { ${[...endpointTypesToImport].join(", ")} } from './types';
|
|
400
|
+
|
|
401
|
+
`;
|
|
402
|
+
}
|
|
403
|
+
endpointsContent += `export const ${camelCaseModuleName}Endpoints = {
|
|
404
|
+
`;
|
|
405
|
+
for (const action of Object.values(module2.actions)) {
|
|
406
|
+
const params = [];
|
|
407
|
+
if (action.pathParams.length > 0) params.push(`params: { ${action.pathParams.map((p) => `${p}: string | number`).join("; ")} }`);
|
|
408
|
+
if (action.inputType !== "undefined" && action.inputType !== "QueryOptions") params.push(`body: ${action.inputType}`);
|
|
409
|
+
if (action.hasQuery) params.push(`query?: QueryOptions`);
|
|
410
|
+
endpointsContent += ` /**
|
|
411
|
+
* ${action.method} ${module2.baseEndpoint}${action.path}
|
|
412
|
+
* ${action.description}
|
|
413
|
+
*/
|
|
414
|
+
`;
|
|
415
|
+
endpointsContent += ` ${action.name}: (${params.join(", ")}) => ({
|
|
416
|
+
`;
|
|
417
|
+
endpointsContent += ` action: '${action.name}' as const,
|
|
418
|
+
`;
|
|
419
|
+
if (action.pathParams.length > 0) endpointsContent += ` pathParams: params,
|
|
420
|
+
`;
|
|
421
|
+
if (action.inputType !== "undefined" && action.inputType !== "QueryOptions") endpointsContent += ` input: body,
|
|
422
|
+
`;
|
|
423
|
+
else if (action.hasQuery) endpointsContent += ` input: query,
|
|
424
|
+
`;
|
|
425
|
+
endpointsContent += ` }),
|
|
426
|
+
|
|
427
|
+
`;
|
|
428
|
+
}
|
|
429
|
+
endpointsContent += `};
|
|
430
|
+
`;
|
|
431
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.endpoints.ts`), endpointsContent.trim());
|
|
432
|
+
console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.endpoints.ts`));
|
|
433
|
+
const contextFileContent = `// Auto-generated file. Do not edit.
|
|
434
|
+
'use client';
|
|
435
|
+
|
|
436
|
+
import React from 'react';
|
|
437
|
+
import { createApiModuleContext, useApiModule } from 'api-core-lib/client';
|
|
438
|
+
import { apiClient } from '@/lib/api-core/clientApi';
|
|
439
|
+
import { ${module2.moduleName}, ${module2.moduleName} as TModuleType } from './config';
|
|
440
|
+
|
|
441
|
+
const { Provider, useContext: use${moduleBaseName}Context } = createApiModuleContext<typeof TModuleType['actions']>();
|
|
442
|
+
|
|
443
|
+
export { use${moduleBaseName}Context };
|
|
444
|
+
|
|
445
|
+
type Options = Parameters<typeof useApiModule>[2];
|
|
446
|
+
|
|
447
|
+
interface ${moduleBaseName}ProviderProps {
|
|
448
|
+
children: React.ReactNode;
|
|
449
|
+
options?: Options;
|
|
450
|
+
}
|
|
451
|
+
|
|
452
|
+
export function ${moduleBaseName}Provider({ children, options = {} }: ${moduleBaseName}ProviderProps) {
|
|
453
|
+
const api = useApiModule(apiClient, ${module2.moduleName}, options);
|
|
454
|
+
return <Provider value={api}>{children}</Provider>;
|
|
455
|
+
}`;
|
|
456
|
+
const contextFileName = `${camelCaseModuleName}.context.tsx`;
|
|
457
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, contextFileName), contextFileContent.trim());
|
|
458
|
+
console.log(import_chalk.default.gray(` \u2713 ${contextFileName}`));
|
|
459
|
+
const serverHelperContent = `// Auto-generated file. For server-side use only.
|
|
460
|
+
|
|
461
|
+
import { createServerApi } from 'api-core-lib/server';
|
|
462
|
+
import { serverApiClient } from '@/lib/api-core/serverApi';
|
|
463
|
+
import { ${module2.moduleName} } from './config';
|
|
464
|
+
|
|
465
|
+
export const create${moduleBaseName}ServerApi = () => {
|
|
466
|
+
return createServerApi(serverApiClient, ${module2.moduleName});
|
|
467
|
+
};`;
|
|
468
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, `${camelCaseModuleName}.server.ts`), serverHelperContent.trim());
|
|
469
|
+
console.log(import_chalk.default.gray(` \u2713 ${camelCaseModuleName}.server.ts`));
|
|
470
|
+
const clientExports = `
|
|
471
|
+
export * from './${camelCaseModuleName}.endpoints';
|
|
472
|
+
export * from './${camelCaseModuleName}.context';`;
|
|
473
|
+
import_fs.default.appendFileSync(indexFilePath, clientExports);
|
|
474
|
+
console.log(import_chalk.default.gray(` \u2713 index.ts (Updated)`));
|
|
475
|
+
const serverEntryPointContent = `// Auto-generated file. For server-side use only.
|
|
476
|
+
|
|
477
|
+
export * from './${camelCaseModuleName}.server';
|
|
478
|
+
export * from './${camelCaseModuleName}.endpoints';`;
|
|
479
|
+
import_fs.default.writeFileSync(import_path.default.join(moduleOutputPath, "server.ts"), serverEntryPointContent);
|
|
480
|
+
console.log(import_chalk.default.gray(` \u2713 server.ts (Server Entry Point)`));
|
|
231
481
|
}
|
|
232
482
|
async function runGeneratorV1(options) {
|
|
233
|
-
console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator
|
|
483
|
+
console.log(import_chalk.default.cyan.bold("\u{1F680} Starting API Development Platform Generator..."));
|
|
234
484
|
import_dotenv.default.config({ path: options.envPath });
|
|
235
485
|
const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
|
|
236
486
|
try {
|
|
@@ -246,7 +496,7 @@ async function runGeneratorV1(options) {
|
|
|
246
496
|
if (import_fs.default.existsSync(outputDir)) {
|
|
247
497
|
console.log(import_chalk.default.yellow.bold(`
|
|
248
498
|
\u26A0\uFE0F An existing generation has been found at: ${outputDir}`));
|
|
249
|
-
const { action } = await
|
|
499
|
+
const { action } = await import_inquirer.default.prompt([{
|
|
250
500
|
type: "list",
|
|
251
501
|
name: "action",
|
|
252
502
|
message: "What would you like to do?",
|
|
@@ -261,7 +511,7 @@ async function runGeneratorV1(options) {
|
|
|
261
511
|
return;
|
|
262
512
|
}
|
|
263
513
|
if (action === "full") {
|
|
264
|
-
const { confirm } = await
|
|
514
|
+
const { confirm } = await import_inquirer.default.prompt([{
|
|
265
515
|
type: "confirm",
|
|
266
516
|
name: "confirm",
|
|
267
517
|
message: import_chalk.default.red.bold("Are you sure? This will permanently delete all files in the output directory."),
|
|
@@ -287,7 +537,7 @@ async function runGeneratorV1(options) {
|
|
|
287
537
|
console.log(import_chalk.default.yellow("No modules found in the spec to update. Exiting."));
|
|
288
538
|
return;
|
|
289
539
|
}
|
|
290
|
-
const { modulesToRegenerate } = await
|
|
540
|
+
const { modulesToRegenerate } = await import_inquirer.default.prompt([{
|
|
291
541
|
type: "checkbox",
|
|
292
542
|
name: "modulesToRegenerate",
|
|
293
543
|
message: "Select the modules to generate or update:",
|
|
@@ -296,7 +546,7 @@ async function runGeneratorV1(options) {
|
|
|
296
546
|
...existingModulesToUpdate.map((name) => ({ name, value: name, checked: false }))
|
|
297
547
|
]
|
|
298
548
|
}]);
|
|
299
|
-
if (modulesToRegenerate.length === 0) {
|
|
549
|
+
if (!modulesToRegenerate || modulesToRegenerate.length === 0) {
|
|
300
550
|
console.log(import_chalk.default.gray("No modules selected. Operation cancelled."));
|
|
301
551
|
return;
|
|
302
552
|
}
|