api-core-lib 12.0.63 → 12.0.65
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 +58 -146
- package/package.json +1 -1
package/dist/cli.cjs
CHANGED
|
@@ -74,77 +74,10 @@ var import_dotenv = __toESM(require("dotenv"), 1);
|
|
|
74
74
|
var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"), 1);
|
|
75
75
|
var import_openapi_types = __toESM(require_dist(), 1);
|
|
76
76
|
var import_json_schema_to_typescript = require("json-schema-to-typescript");
|
|
77
|
-
function preprocessSpec(spec) {
|
|
78
|
-
if (!spec.components) spec.components = {};
|
|
79
|
-
if (!spec.components.schemas) spec.components.schemas = {};
|
|
80
|
-
const schemas = spec.components.schemas;
|
|
81
|
-
for (const apiPath in spec.paths) {
|
|
82
|
-
const pathItem = spec.paths[apiPath];
|
|
83
|
-
if (!pathItem) continue;
|
|
84
|
-
for (const method in pathItem) {
|
|
85
|
-
if (!Object.values(import_openapi_types.OpenAPIV3.HttpMethods).includes(method)) continue;
|
|
86
|
-
const endpoint = pathItem[method];
|
|
87
|
-
const baseName = _generateBaseNameForSchema(method, apiPath, endpoint.operationId);
|
|
88
|
-
const requestBody = endpoint.requestBody;
|
|
89
|
-
if (requestBody?.content?.["application/json"]?.schema) {
|
|
90
|
-
requestBody.content["application/json"].schema = _normalizeSchema(
|
|
91
|
-
requestBody.content["application/json"].schema,
|
|
92
|
-
schemas,
|
|
93
|
-
baseName,
|
|
94
|
-
"Request"
|
|
95
|
-
);
|
|
96
|
-
}
|
|
97
|
-
if (endpoint.responses) {
|
|
98
|
-
for (const statusCode in endpoint.responses) {
|
|
99
|
-
const response = endpoint.responses[statusCode];
|
|
100
|
-
const mediaTypeObject = response.content?.["application/json"];
|
|
101
|
-
if (mediaTypeObject?.schema) {
|
|
102
|
-
mediaTypeObject.schema = _normalizeSchema(
|
|
103
|
-
mediaTypeObject.schema,
|
|
104
|
-
// مرر المخطط الأصلي
|
|
105
|
-
schemas,
|
|
106
|
-
baseName,
|
|
107
|
-
`Response${statusCode}`
|
|
108
|
-
);
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
}
|
|
113
|
-
}
|
|
114
|
-
return spec;
|
|
115
|
-
}
|
|
116
|
-
function _normalizeSchema(schema, schemas, baseName, suffix) {
|
|
117
|
-
if (!schema || "$ref" in schema) {
|
|
118
|
-
return schema;
|
|
119
|
-
}
|
|
120
|
-
if (schema.type === "array" && schema.items) {
|
|
121
|
-
schema.items = _normalizeSchema(schema.items, schemas, baseName, suffix.replace("[]", "Item"));
|
|
122
|
-
return schema;
|
|
123
|
-
}
|
|
124
|
-
if (schema.type === "object" && schema.properties) {
|
|
125
|
-
const typeName = `${_toPascalCase(baseName)}${_toPascalCase(suffix)}Dto`;
|
|
126
|
-
if (!schemas[typeName]) {
|
|
127
|
-
schemas[typeName] = schema;
|
|
128
|
-
for (const propName in schema.properties) {
|
|
129
|
-
schema.properties[propName] = _normalizeSchema(
|
|
130
|
-
schema.properties[propName],
|
|
131
|
-
schemas,
|
|
132
|
-
baseName,
|
|
133
|
-
`${_toPascalCase(propName)}Property`
|
|
134
|
-
);
|
|
135
|
-
}
|
|
136
|
-
}
|
|
137
|
-
return { $ref: `#/components/schemas/${typeName}` };
|
|
138
|
-
}
|
|
139
|
-
return schema;
|
|
140
|
-
}
|
|
141
|
-
function _generateBaseNameForSchema(method, path3, operationId) {
|
|
142
|
-
if (operationId) return _toPascalCase(operationId.replace(/_v\d+$/, ""));
|
|
143
|
-
const pathPart = path3.replace(/[\/{}]/g, " ").trim();
|
|
144
|
-
return `${_toPascalCase(method)} ${_toPascalCase(pathPart)}`;
|
|
145
|
-
}
|
|
146
77
|
function parseSpecToModules(spec) {
|
|
147
78
|
const modules = {};
|
|
79
|
+
if (!spec.components) spec.components = {};
|
|
80
|
+
if (!spec.components.schemas) spec.components.schemas = {};
|
|
148
81
|
for (const apiPath in spec.paths) {
|
|
149
82
|
const pathItem = spec.paths[apiPath];
|
|
150
83
|
if (!pathItem) continue;
|
|
@@ -158,18 +91,7 @@ function parseSpecToModules(spec) {
|
|
|
158
91
|
modules[moduleName] = { baseEndpoint: _findCommonBasePath(spec, tagName), actions: {}, types: /* @__PURE__ */ new Set() };
|
|
159
92
|
}
|
|
160
93
|
const currentModule = modules[moduleName];
|
|
161
|
-
const
|
|
162
|
-
const successResponse = successResponseKey ? endpoint.responses[successResponseKey] : void 0;
|
|
163
|
-
const responseSchema = successResponse?.content?.["application/json"]?.schema;
|
|
164
|
-
const outputType = successResponseKey === "204" ? "void" : _extractTypeNameFromSchema(responseSchema);
|
|
165
|
-
const requestBody = endpoint.requestBody;
|
|
166
|
-
const requestSchema = requestBody?.content?.["application/json"]?.schema;
|
|
167
|
-
let inputType = "undefined";
|
|
168
|
-
if (requestSchema) {
|
|
169
|
-
inputType = _extractTypeNameFromSchema(requestSchema);
|
|
170
|
-
} else if ((endpoint.parameters || []).some((p) => p.in === "query")) {
|
|
171
|
-
inputType = "QueryOptions";
|
|
172
|
-
}
|
|
94
|
+
const { inputType, outputType } = _extractInputOutputTypes(endpoint, spec.components.schemas);
|
|
173
95
|
[inputType, outputType].forEach((t) => {
|
|
174
96
|
if (t && !["unknown", "undefined", "void", "any", "QueryOptions", "Promise"].includes(t)) {
|
|
175
97
|
currentModule.types.add(t.replace("[]", ""));
|
|
@@ -191,66 +113,66 @@ function parseSpecToModules(spec) {
|
|
|
191
113
|
}
|
|
192
114
|
return modules;
|
|
193
115
|
}
|
|
194
|
-
function
|
|
116
|
+
function _extractInputOutputTypes(endpoint, schemas) {
|
|
117
|
+
const operationId = endpoint.operationId || "UnnamedOperation";
|
|
118
|
+
const successResponseKey = Object.keys(endpoint.responses).find((code) => code.startsWith("2"));
|
|
119
|
+
const successResponse = successResponseKey ? endpoint.responses[successResponseKey] : void 0;
|
|
120
|
+
const responseSchema = successResponse?.content?.["application/json"]?.schema;
|
|
121
|
+
const outputType = successResponseKey === "204" ? "void" : _schemaToTypeName(responseSchema, `${operationId}Response`, schemas);
|
|
122
|
+
const requestBody = endpoint.requestBody;
|
|
123
|
+
const requestSchema = requestBody?.content?.["application/json"]?.schema;
|
|
124
|
+
let inputType = "undefined";
|
|
125
|
+
if (requestSchema) {
|
|
126
|
+
inputType = _schemaToTypeName(requestSchema, `${operationId}Request`, schemas);
|
|
127
|
+
} else if ((endpoint.parameters || []).some((p) => p.in === "query")) {
|
|
128
|
+
inputType = "QueryOptions";
|
|
129
|
+
}
|
|
130
|
+
return { inputType, outputType };
|
|
131
|
+
}
|
|
132
|
+
function _schemaToTypeName(schema, name, schemas) {
|
|
195
133
|
if (!schema) return "unknown";
|
|
196
|
-
if ("
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
if (
|
|
203
|
-
|
|
134
|
+
if (schema.type === "array" && schema.items) {
|
|
135
|
+
const itemTypeName = _schemaToTypeName(schema.items, `${name}Item`, schemas);
|
|
136
|
+
return `${itemTypeName}[]`;
|
|
137
|
+
}
|
|
138
|
+
if (schema.type === "object" || schema.properties || schema.allOf) {
|
|
139
|
+
const typeName = _toPascalCase(name) + "Dto";
|
|
140
|
+
if (!schemas[typeName]) {
|
|
141
|
+
schemas[typeName] = schema;
|
|
204
142
|
}
|
|
143
|
+
return typeName;
|
|
144
|
+
}
|
|
145
|
+
if (schema.type && ["string", "number", "boolean", "integer"].includes(schema.type)) {
|
|
146
|
+
return schema.type === "integer" ? "number" : schema.type;
|
|
205
147
|
}
|
|
206
148
|
return "unknown";
|
|
207
149
|
}
|
|
208
|
-
async function generateModuleFiles(moduleName, moduleData,
|
|
150
|
+
async function generateModuleFiles(moduleName, moduleData, allSchemas, outputDir) {
|
|
209
151
|
console.log(import_chalk.default.gray(` Generating files for module: ${import_chalk.default.bold(moduleName)}...`));
|
|
210
152
|
const moduleFolderPath = import_path.default.join(outputDir, moduleName);
|
|
211
|
-
if (!import_fs.default.existsSync(moduleFolderPath)) {
|
|
212
|
-
|
|
213
|
-
}
|
|
214
|
-
await _generateTypesFile(moduleFolderPath, moduleName, moduleData.types, spec);
|
|
153
|
+
if (!import_fs.default.existsSync(moduleFolderPath)) import_fs.default.mkdirSync(moduleFolderPath, { recursive: true });
|
|
154
|
+
await _generateTypesFile(moduleFolderPath, moduleName, moduleData.types, allSchemas);
|
|
215
155
|
await _generateConfigFile(moduleFolderPath, moduleName, moduleData);
|
|
216
156
|
}
|
|
217
|
-
async function _generateTypesFile(moduleFolderPath, moduleName, typeNames,
|
|
157
|
+
async function _generateTypesFile(moduleFolderPath, moduleName, typeNames, allSchemas) {
|
|
218
158
|
if (typeNames.size === 0) {
|
|
219
159
|
console.log(import_chalk.default.yellow(` - No types found for module "${moduleName}". Skipping types.ts generation.`));
|
|
220
|
-
const typesFilePath2 = import_path.default.join(moduleFolderPath, "types.ts");
|
|
221
|
-
import_fs.default.writeFileSync(typesFilePath2, `// No types found for this module.
|
|
222
|
-
`);
|
|
223
160
|
return;
|
|
224
161
|
}
|
|
225
162
|
console.log(import_chalk.default.gray(` - Generating types.ts with ${typeNames.size} types...`));
|
|
226
163
|
let typesContent = `// This file is auto-generated by the API generator. Do not edit.
|
|
227
164
|
|
|
228
165
|
`;
|
|
229
|
-
const allSchemas = spec.components?.schemas || {};
|
|
230
166
|
const compilationOptions = {
|
|
231
167
|
bannerComment: "",
|
|
232
168
|
style: { bracketSpacing: true, printWidth: 120, semi: true, singleQuote: true, tabWidth: 2, trailingComma: "es5", useTabs: false },
|
|
233
|
-
additionalProperties: false
|
|
234
|
-
declareExternallyReferenced: true
|
|
235
|
-
};
|
|
236
|
-
const schemaContainer = {
|
|
237
|
-
components: {
|
|
238
|
-
schemas: allSchemas
|
|
239
|
-
}
|
|
169
|
+
additionalProperties: false
|
|
240
170
|
};
|
|
241
171
|
for (const typeName of Array.from(typeNames).sort()) {
|
|
242
|
-
|
|
172
|
+
const schema = allSchemas[typeName];
|
|
173
|
+
if (schema) {
|
|
243
174
|
try {
|
|
244
|
-
const
|
|
245
|
-
$ref: `#/components/schemas/${typeName}`
|
|
246
|
-
};
|
|
247
|
-
const finalSchema = { ...schemaContainer, ...tempSchemaToCompile };
|
|
248
|
-
const tsType = await (0, import_json_schema_to_typescript.compile)(
|
|
249
|
-
finalSchema,
|
|
250
|
-
typeName,
|
|
251
|
-
// <-- هذا الاسم سيُستخدم الآن بنجاح!
|
|
252
|
-
compilationOptions
|
|
253
|
-
);
|
|
175
|
+
const tsType = await (0, import_json_schema_to_typescript.compile)(schema, typeName, compilationOptions);
|
|
254
176
|
typesContent += tsType + "\n";
|
|
255
177
|
} catch (compileError) {
|
|
256
178
|
console.error(import_chalk.default.red(` - Error compiling type "${typeName}": ${compileError.message}`));
|
|
@@ -266,26 +188,24 @@ async function _generateConfigFile(moduleFolderPath, moduleName, moduleData) {
|
|
|
266
188
|
const actionsCount = Object.keys(moduleData.actions).length;
|
|
267
189
|
console.log(import_chalk.default.gray(` - Generating config.ts with ${actionsCount} actions...`));
|
|
268
190
|
const typeNamesArray = [...moduleData.types].sort();
|
|
269
|
-
const typesImportStatement = typeNamesArray.length > 0 ? `import type { ${typeNamesArray.join(", ")} } from './types';` :
|
|
191
|
+
const typesImportStatement = typeNamesArray.length > 0 ? `import type { ${typeNamesArray.join(", ")} } from './types';` : ``;
|
|
270
192
|
const actionsTypeParts = Object.entries(moduleData.actions).map(
|
|
271
|
-
([actionName, actionData]) => ` ${actionName}: ActionConfigModule<${actionData._inputType
|
|
193
|
+
([actionName, actionData]) => ` ${actionName}: ActionConfigModule<${actionData._inputType}, ${actionData._outputType}>;`
|
|
272
194
|
);
|
|
273
195
|
const actionsTypeDefinition = `{
|
|
274
196
|
${actionsTypeParts.join("\n")}
|
|
275
197
|
}`;
|
|
276
|
-
const actionsValueParts = Object.entries(moduleData.actions).map(
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
}
|
|
281
|
-
);
|
|
198
|
+
const actionsValueParts = Object.entries(moduleData.actions).map(([actionName, actionData]) => {
|
|
199
|
+
const { _inputType, _outputType, ...config } = actionData;
|
|
200
|
+
return ` ${actionName}: ${JSON.stringify(config, null, 2).replace(/\n/g, "\n ")}`;
|
|
201
|
+
});
|
|
282
202
|
const actionsValueDefinition = `{
|
|
283
203
|
${actionsValueParts.join(",\n")}
|
|
284
204
|
}`;
|
|
285
205
|
const configContent = `/* eslint-disable */
|
|
286
|
-
// This file is auto-generated
|
|
206
|
+
// This file is auto-generated...
|
|
287
207
|
|
|
288
|
-
import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
|
|
208
|
+
import type { ApiModuleConfig, ActionConfigModule, QueryOptions } from 'api-core-lib';
|
|
289
209
|
${typesImportStatement}
|
|
290
210
|
|
|
291
211
|
export const ${moduleName}Module: ApiModuleConfig<${actionsTypeDefinition}> = {
|
|
@@ -297,11 +217,7 @@ export const ${moduleName}Module: ApiModuleConfig<${actionsTypeDefinition}> = {
|
|
|
297
217
|
import_fs.default.writeFileSync(configFilePath, configContent.trim(), { encoding: "utf-8" });
|
|
298
218
|
}
|
|
299
219
|
function _toPascalCase(str) {
|
|
300
|
-
return str.replace(/[^a-zA-Z0-9]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (
|
|
301
|
-
}
|
|
302
|
-
function _refToTypeName(ref) {
|
|
303
|
-
if (!ref) return "unknown";
|
|
304
|
-
return ref.split("/").pop() || "unknown";
|
|
220
|
+
return str.replace(/[^a-zA-Z0-9]/g, " ").replace(/(?:^\w|[A-Z]|\b\w)/g, (w) => w.toUpperCase()).replace(/\s+/g, "");
|
|
305
221
|
}
|
|
306
222
|
function _sanitizeTagName(tagName) {
|
|
307
223
|
return tagName.replace(/[^a-zA-Z0-9]/g, "").replace(/Central|Tenant/g, "");
|
|
@@ -341,26 +257,22 @@ async function runGenerator(options) {
|
|
|
341
257
|
console.log(import_chalk.default.blue("\u2713 Step 1: Environment variables loaded."));
|
|
342
258
|
try {
|
|
343
259
|
console.log(import_chalk.default.blue(`
|
|
344
|
-
\u23F3 Step 2: Fetching and
|
|
345
|
-
const
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
console.log(import_chalk.default.blue("\n\u23F3 Step 3: Preprocessing spec to normalize inline schemas..."));
|
|
350
|
-
const normalizedSpec = preprocessSpec(initialSpec);
|
|
351
|
-
console.log(import_chalk.default.green("\u2713 Spec has been normalized successfully."));
|
|
352
|
-
console.log(import_chalk.default.blue("\n\u23F3 Step 4: Parsing spec and generating API modules structure..."));
|
|
353
|
-
const modules = parseSpecToModules(normalizedSpec);
|
|
260
|
+
\u23F3 Step 2: Fetching and fully dereferencing spec from ${specUrl}...`));
|
|
261
|
+
const dereferencedSpec = await import_swagger_parser.default.dereference(specUrl);
|
|
262
|
+
console.log(import_chalk.default.green("\u2713 Spec fetched and fully dereferenced successfully."));
|
|
263
|
+
console.log(import_chalk.default.blue("\n\u23F3 Step 3: Parsing spec and generating API modules structure..."));
|
|
264
|
+
const modules = parseSpecToModules(dereferencedSpec);
|
|
354
265
|
const modulesCount = Object.keys(modules).length;
|
|
355
266
|
console.log(import_chalk.default.green(`\u2713 Found ${modulesCount} modules to generate.`));
|
|
356
267
|
if (modulesCount === 0) {
|
|
357
268
|
console.log(import_chalk.default.yellow("Warning: No modules were found in the spec."));
|
|
358
269
|
}
|
|
359
|
-
console.log(import_chalk.default.blue("\n\u23F3 Step
|
|
270
|
+
console.log(import_chalk.default.blue("\n\u23F3 Step 4: Generating module files..."));
|
|
360
271
|
const modulesOutputPath = import_path.default.join(options.output, "modules");
|
|
272
|
+
const allSchemas = dereferencedSpec.components?.schemas || {};
|
|
361
273
|
for (const moduleName in modules) {
|
|
362
274
|
const moduleData = modules[moduleName];
|
|
363
|
-
await generateModuleFiles(moduleName, moduleData,
|
|
275
|
+
await generateModuleFiles(moduleName, moduleData, allSchemas, modulesOutputPath);
|
|
364
276
|
}
|
|
365
277
|
console.log(import_chalk.default.green("\u2713 All module files generated."));
|
|
366
278
|
console.log(import_chalk.default.bold.green("\n\u{1F389} API generation complete!"));
|
|
@@ -370,7 +282,7 @@ async function runGenerator(options) {
|
|
|
370
282
|
}
|
|
371
283
|
}
|
|
372
284
|
function getSpecUrl() {
|
|
373
|
-
const specUrl = process.env.OPENAPI_SPEC_URL ||
|
|
285
|
+
const specUrl = process.env.OPENAPI_SPEC_URL || "./swagger.json";
|
|
374
286
|
if (!specUrl) {
|
|
375
287
|
console.error(import_chalk.default.red.bold("\n\u274C Error: API specification URL not found."));
|
|
376
288
|
process.exit(1);
|