api-farmer 0.1.3 → 0.1.4

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/index.cjs DELETED
@@ -1,521 +0,0 @@
1
- "use strict";
2
- var __create = Object.create;
3
- var __defProp = Object.defineProperty;
4
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
- var __getOwnPropNames = Object.getOwnPropertyNames;
6
- var __getProtoOf = Object.getPrototypeOf;
7
- var __hasOwnProp = Object.prototype.hasOwnProperty;
8
- var __export = (target, all) => {
9
- for (var name in all)
10
- __defProp(target, name, { get: all[name], enumerable: true });
11
- };
12
- var __copyProps = (to, from, except, desc) => {
13
- if (from && typeof from === "object" || typeof from === "function") {
14
- for (let key of __getOwnPropNames(from))
15
- if (!__hasOwnProp.call(to, key) && key !== except)
16
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
17
- }
18
- return to;
19
- };
20
- var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
21
- // If the importer is in node compatibility mode or this is not an ESM
22
- // file that has been converted to a CommonJS file using a Babel-
23
- // compatible transform (i.e. "__esModule" has not been set), then set
24
- // "default" to the CommonJS "module.exports" for node compatibility.
25
- isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
26
- mod
27
- ));
28
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
29
-
30
- // src/index.ts
31
- var index_exports = {};
32
- __export(index_exports, {
33
- createStatusCodesByStrategy: () => createStatusCodesByStrategy,
34
- createTransformer: () => createTransformer,
35
- defineConfig: () => defineConfig,
36
- findObjectKey: () => findObjectKey,
37
- generate: () => generate,
38
- generateTypes: () => generateTypes,
39
- getCliVersion: () => getCliVersion,
40
- getConfig: () => getConfig,
41
- getRequestBodyContentType: () => getRequestBodyContentType,
42
- getResponseMetadataItems: () => getResponseMetadataItems,
43
- getSchemaNode: () => getSchemaNode,
44
- isRemoteSchema: () => isRemoteSchema,
45
- isRequiredRequestBody: () => isRequiredRequestBody,
46
- partitionApiModules: () => partitionApiModules,
47
- pluralize: () => import_pluralize2.default,
48
- readSchema: () => readSchema,
49
- readSchemaContent: () => readSchemaContent,
50
- readTemplateFile: () => readTemplateFile,
51
- renderApiModules: () => renderApiModules,
52
- transformComment: () => transformComment,
53
- transformEntity: () => transformEntity,
54
- transformFn: () => transformFn,
55
- transformModuleName: () => transformModuleName,
56
- transformPayloads: () => transformPayloads,
57
- transformType: () => transformType,
58
- transformTypeQuery: () => transformTypeQuery,
59
- transformTypeQueryValue: () => transformTypeQueryValue,
60
- transformTypeRequestBody: () => transformTypeRequestBody,
61
- transformTypeRequestBodyValue: () => transformTypeRequestBodyValue,
62
- transformTypeResponseBody: () => transformTypeResponseBody,
63
- transformTypeResponseBodyValue: () => transformTypeResponseBodyValue,
64
- transformTypeValue: () => transformTypeValue,
65
- transformUrl: () => transformUrl,
66
- transformVerb: () => transformVerb
67
- });
68
- module.exports = __toCommonJS(index_exports);
69
-
70
- // src/transformer.ts
71
- var import_pluralize = __toESM(require("pluralize"), 1);
72
- var import_rattail = require("rattail");
73
- function transformModuleName({ name }) {
74
- return (0, import_rattail.camelize)(name);
75
- }
76
- function transformUrl({ path }) {
77
- return path.replace(/{/g, ":").replace(/}/g, "");
78
- }
79
- function transformComment({
80
- summary,
81
- description,
82
- path,
83
- method
84
- }) {
85
- return `
86
- /**${summary ? `
87
- * ${summary}` : ""}${description && summary !== description ? `
88
- * @description ${description}
89
- *` : ""}
90
- * @url ${path}
91
- * @method ${method.toLocaleUpperCase()}
92
- */
93
- `.trim();
94
- }
95
- function transformVerb({ method }) {
96
- switch (method) {
97
- case "post":
98
- return "Create";
99
- case "put":
100
- return "Update";
101
- default:
102
- return (0, import_rattail.pascalCase)(method);
103
- }
104
- }
105
- function transformEntity({ path, method, uncountableNouns }) {
106
- const words = path.split("/").filter(Boolean);
107
- return words.reduce((entity, word, index) => {
108
- if (word.includes("{")) {
109
- return entity;
110
- }
111
- word = word.replace(/\.([a-z])/g, (_, p) => p.toUpperCase());
112
- const isUncountableNoun = uncountableNouns.includes(word);
113
- word = (0, import_rattail.pascalCase)(word);
114
- word = isUncountableNoun ? word : import_pluralize.default.singular(word);
115
- if (method === "get" && index === words.length - 1) {
116
- word = isUncountableNoun ? `${word}List` : import_pluralize.default.plural(word);
117
- }
118
- return `${entity}${word}`;
119
- }, "");
120
- }
121
- function transformFn({ verb, entity }) {
122
- return `api${verb}${entity}`;
123
- }
124
- function transformType({ verb, entity }) {
125
- return `Api${verb}${entity}`;
126
- }
127
- function transformTypeValue({ fullPath, method }) {
128
- return `paths['${fullPath}']['${method}']`;
129
- }
130
- function transformTypeQuery({ type }) {
131
- return `${type}Query`;
132
- }
133
- function transformTypeQueryValue({
134
- type
135
- }) {
136
- return `${type}['parameters']['query']`;
137
- }
138
- function transformTypeRequestBody({
139
- type
140
- }) {
141
- return `${type}RequestBody`;
142
- }
143
- function transformTypeRequestBodyValue({
144
- type,
145
- required,
146
- requestContentType
147
- }) {
148
- return required ? `${type}['requestBody']['content']['${requestContentType}']` : `NonNullable<${type}['requestBody']>['content']['${requestContentType}'] | undefined`;
149
- }
150
- function transformTypeResponseBody({
151
- type
152
- }) {
153
- return `${type}ResponseBody`;
154
- }
155
- function transformTypeResponseBodyValue({
156
- type,
157
- responseMetadataItems
158
- }) {
159
- return responseMetadataItems.map(({ status, responseContentType }) => `${type}['responses']['${status}']['content']['${responseContentType}']`).join(" | ");
160
- }
161
- function createTransformer() {
162
- return {
163
- moduleName: transformModuleName,
164
- verb: transformVerb,
165
- url: transformUrl,
166
- comment: transformComment,
167
- entity: transformEntity,
168
- fn: transformFn,
169
- type: transformType,
170
- typeValue: transformTypeValue,
171
- typeQuery: transformTypeQuery,
172
- typeQueryValue: transformTypeQueryValue,
173
- typeRequestBody: transformTypeRequestBody,
174
- typeRequestBodyValue: transformTypeRequestBodyValue,
175
- typeResponseBody: transformTypeResponseBody,
176
- typeResponseBodyValue: transformTypeResponseBodyValue
177
- };
178
- }
179
-
180
- // src/generate.ts
181
- var import_path3 = require("path");
182
- var import_ejs = __toESM(require("ejs"), 1);
183
- var import_fs_extra2 = __toESM(require("fs-extra"), 1);
184
- var import_openapi_typescript = __toESM(require("openapi-typescript"), 1);
185
- var import_prettier = __toESM(require("prettier"), 1);
186
- var import_rattail3 = require("rattail");
187
- var import_rslog2 = require("rslog");
188
- var import_typescript = __toESM(require("typescript"), 1);
189
-
190
- // src/config.ts
191
- var import_unconfig = require("unconfig");
192
- function defineConfig(config) {
193
- return config;
194
- }
195
- async function getConfig() {
196
- const { config } = await (0, import_unconfig.loadConfig)({
197
- sources: [
198
- {
199
- files: "api-farmer.config"
200
- }
201
- ]
202
- });
203
- return config ?? {};
204
- }
205
-
206
- // src/constants.ts
207
- var import_path = require("path");
208
- var CWD = process.cwd();
209
- var CUSTOM_TEMPLATE_FILE = (0, import_path.resolve)(CWD, `./api-farmer.ejs`);
210
- var CLI_PACKAGE_JSON = (0, import_path.resolve)(__dirname, "../package.json");
211
- var SUPPORTED_HTTP_METHODS = ["get", "post", "put", "delete", "patch", "options", "head"];
212
-
213
- // src/utils.ts
214
- var import_path2 = require("path");
215
- var import_axle = require("@varlet/axle");
216
- var import_fs_extra = __toESM(require("fs-extra"), 1);
217
- var import_rattail2 = require("rattail");
218
- var import_rslog = require("rslog");
219
- var import_swagger2openapi = __toESM(require("swagger2openapi"), 1);
220
- var import_yaml = __toESM(require("yaml"), 1);
221
- function createStatusCodesByStrategy(strategy) {
222
- return {
223
- strict: {
224
- get: 200,
225
- post: 201,
226
- put: 200,
227
- delete: 204,
228
- patch: 200,
229
- options: 204,
230
- head: 200
231
- },
232
- loose: {
233
- get: 200,
234
- post: 200,
235
- put: 200,
236
- delete: 200,
237
- patch: 200,
238
- options: 200,
239
- head: 200
240
- },
241
- smart: {
242
- get: 200,
243
- post: 200,
244
- put: 200,
245
- delete: 200,
246
- patch: 200,
247
- options: 200,
248
- head: 200
249
- }
250
- }[strategy];
251
- }
252
- async function readSchema(input) {
253
- const content = await readSchemaContent(input);
254
- const jsonSchema = (0, import_rattail2.tryParseJSON)(content);
255
- const swaggerOrOpenapiSchema = jsonSchema ? jsonSchema : import_yaml.default.parse(content);
256
- const schema = swaggerOrOpenapiSchema.swagger ? (await import_swagger2openapi.default.convert(swaggerOrOpenapiSchema, {})).openapi : swaggerOrOpenapiSchema;
257
- return schema;
258
- }
259
- function getSchemaNode(schema, path) {
260
- const paths = path.split("/");
261
- return paths.reduce((node, path2) => node[path2], schema);
262
- }
263
- async function readSchemaContent(input) {
264
- if (isRemoteSchema(input)) {
265
- try {
266
- import_rslog.logger.info("Fetching remote schema...");
267
- const { data } = await (0, import_axle.createAxle)().get(input);
268
- return JSON.stringify(data);
269
- } catch {
270
- throw new Error("Failed to fetch remote schema");
271
- }
272
- }
273
- const path = (0, import_path2.resolve)(CWD, input);
274
- const content = import_fs_extra.default.readFileSync(path, "utf-8");
275
- return content;
276
- }
277
- function isRemoteSchema(path) {
278
- return path.startsWith("http://") || path.startsWith("https://");
279
- }
280
- function readTemplateFile(preset = "axle") {
281
- if (import_fs_extra.default.existsSync(CUSTOM_TEMPLATE_FILE)) {
282
- return import_fs_extra.default.readFileSync(CUSTOM_TEMPLATE_FILE, "utf-8");
283
- }
284
- return import_fs_extra.default.readFileSync((0, import_path2.resolve)(__dirname, `../templates/${preset}.ejs`), "utf-8");
285
- }
286
- function getCliVersion() {
287
- return import_fs_extra.default.readJsonSync(CLI_PACKAGE_JSON).version;
288
- }
289
- function isRequiredRequestBody(value) {
290
- return "required" in value && value.required === true;
291
- }
292
- function findObjectKey(object, targetKeys) {
293
- return Object.keys(object).find((key) => targetKeys.includes(key));
294
- }
295
- function getRequestBodyContentType(value) {
296
- if (!("content" in value)) {
297
- return "";
298
- }
299
- return findObjectKey(value.content, ["application/json", "application/x-www-form-urlencoded", "multipart/form-data"]);
300
- }
301
- function getResponseMetadataItems(operation, validateStatus) {
302
- const responses = operation.responses ?? {};
303
- const validStatusResults = Object.keys(responses).sort((a, b) => Number(a) - Number(b)).filter((key) => validateStatus(Number(key))).map(Number);
304
- const metadataItems = validStatusResults.map((status) => {
305
- const content = operation.responses?.[status]?.content ?? {};
306
- const responseContentType = findObjectKey(content, ["application/json", "application/octet-stream", "*/*"]);
307
- return {
308
- status,
309
- responseContentType
310
- };
311
- }).filter((result) => result.responseContentType);
312
- return metadataItems;
313
- }
314
-
315
- // src/generate.ts
316
- function transformPayloads(pathItems, options) {
317
- const { transformer, path, fullPath, base, uncountableNouns, validateStatus, excludeDeprecated } = options;
318
- return Object.entries(pathItems).filter(([key]) => SUPPORTED_HTTP_METHODS.includes(key)).filter(([, operation]) => !(excludeDeprecated && operation.deprecated)).reduce((payloads, [method, operation]) => {
319
- const url = transformer.url({ path, base, fullPath });
320
- const args = { path, base, fullPath, url, method, uncountableNouns, operation };
321
- const entity = transformer.entity(args);
322
- const verb = transformer.verb(args);
323
- const comment = transformer.comment({ ...args, ...operation });
324
- const requestContentType = operation.requestBody ? getRequestBodyContentType(operation.requestBody) : void 0;
325
- const responseMetadataItems = getResponseMetadataItems(operation, validateStatus);
326
- const fn = transformer.fn({ ...args, verb, entity });
327
- const type = transformer.type({ ...args, verb, entity });
328
- const typeValue = transformer.typeValue({ ...args, verb, entity });
329
- const typeQuery = transformer.typeQuery({ ...args, type, verb, entity });
330
- const typeQueryValue = transformer.typeQueryValue({ ...args, type, verb, entity });
331
- const typeRequestBody = transformer.typeRequestBody({ ...args, type, verb, entity });
332
- const typeRequestBodyValue = operation.requestBody && requestContentType ? transformer.typeRequestBodyValue({
333
- ...args,
334
- type,
335
- verb,
336
- entity,
337
- required: isRequiredRequestBody(operation.requestBody),
338
- requestContentType
339
- }) : "undefined";
340
- const typeResponseBody = transformer.typeResponseBody({ ...args, type, verb, entity });
341
- const typeResponseBodyValue = responseMetadataItems.length > 0 ? transformer.typeResponseBodyValue({ ...args, type, verb, entity, responseMetadataItems }) : "undefined";
342
- payloads.push({
343
- comment,
344
- fn,
345
- url,
346
- method,
347
- verb,
348
- entity,
349
- requestContentType,
350
- type,
351
- typeValue,
352
- typeQuery,
353
- typeQueryValue,
354
- typeRequestBody,
355
- typeRequestBodyValue,
356
- typeResponseBody,
357
- typeResponseBodyValue
358
- });
359
- return payloads;
360
- }, []);
361
- }
362
- function partitionApiModules(schema, options) {
363
- const { base, transformer, uncountableNouns, validateStatus, excludeDeprecated } = options;
364
- const schemaPaths = schema.paths ?? {};
365
- const schemaPathKeys = base ? Object.keys(schemaPaths).map((key) => key.replace(base, "")) : Object.keys(schemaPaths);
366
- const keyToPaths = (0, import_rattail3.groupBy)(schemaPathKeys, (key) => key.split("/")[1]);
367
- const apiModules = Object.entries(keyToPaths).reduce((apiModules2, [name, paths]) => {
368
- const payloads = paths.reduce((payloads2, path) => {
369
- const fullPath = base ? base + path : path;
370
- const pathItems = schemaPaths[fullPath];
371
- payloads2.push(
372
- ...transformPayloads(pathItems, {
373
- ...options,
374
- path,
375
- fullPath,
376
- transformer,
377
- uncountableNouns,
378
- validateStatus,
379
- excludeDeprecated
380
- })
381
- );
382
- return payloads2;
383
- }, []);
384
- apiModules2.push({ name: transformer.moduleName({ name }), payloads });
385
- return apiModules2;
386
- }, []);
387
- return apiModules;
388
- }
389
- function renderApiModules(apiModules, options) {
390
- const { output, ts: ts2, typesOnly, overrides, preset } = options;
391
- const templateFile = readTemplateFile(preset);
392
- const typesFilename = options.typesFilename.replace(".ts", "");
393
- return Promise.all(
394
- apiModules.map(
395
- (apiModule) => new Promise((promiseResolve) => {
396
- const data = {
397
- apiModule,
398
- typesFilename,
399
- ts: ts2,
400
- typesOnly
401
- };
402
- import_prettier.default.format(import_ejs.default.render(templateFile, data), {
403
- parser: "typescript",
404
- semi: false,
405
- singleQuote: true,
406
- printWidth: 120
407
- }).then((content) => {
408
- const path = (0, import_path3.resolve)(output, `${apiModule.name}.${ts2 ? "ts" : "js"}`);
409
- const shouldSkip = (!overrides || (0, import_rattail3.isArray)(overrides) && !overrides.includes(apiModule.name)) && import_fs_extra2.default.existsSync(path);
410
- if (shouldSkip) {
411
- import_rslog2.logger.warn(`File already exists, skip: ${path}`);
412
- promiseResolve(content);
413
- return;
414
- }
415
- import_fs_extra2.default.outputFileSync(path, content);
416
- import_rslog2.logger.success(`Generated ${path}`);
417
- promiseResolve(content);
418
- });
419
- })
420
- )
421
- );
422
- }
423
- async function generateTypes(schema, output, typesFilename, openapiTsOptions) {
424
- const BLOB = import_typescript.default.factory.createTypeReferenceNode(import_typescript.default.factory.createIdentifier("Blob"));
425
- const NULL = import_typescript.default.factory.createLiteralTypeNode(import_typescript.default.factory.createNull());
426
- const ast = await (0, import_openapi_typescript.default)(schema, {
427
- defaultNonNullable: false,
428
- transform(schemaObject) {
429
- if (schemaObject.format === "binary") {
430
- return schemaObject.nullable ? import_typescript.default.factory.createUnionTypeNode([BLOB, NULL]) : BLOB;
431
- }
432
- },
433
- ...openapiTsOptions
434
- });
435
- const contents = (0, import_openapi_typescript.astToString)(ast);
436
- const typesFilepath = (0, import_path3.resolve)(CWD, output, typesFilename);
437
- import_fs_extra2.default.outputFileSync(typesFilepath, contents);
438
- import_rslog2.logger.success(`Generated ${typesFilepath}`);
439
- }
440
- async function generate(userOptions = {}) {
441
- const config = await getConfig();
442
- const options = (0, import_rattail3.merge)(config, userOptions);
443
- const {
444
- base,
445
- ts: ts2 = true,
446
- typesOnly = false,
447
- overrides = true,
448
- preset = "axle",
449
- input = "./schema.json",
450
- output = "./src/apis/generated",
451
- typesFilename = "_types.ts",
452
- clean = false,
453
- validateStatus = (status) => status >= 200 && status < 300,
454
- transformer = {},
455
- uncountableNouns = [],
456
- openapiTsOptions = {},
457
- excludeDeprecated = false
458
- } = options;
459
- const mergedTransformer = { ...createTransformer(), ...transformer };
460
- const schema = await readSchema(input);
461
- if (clean) {
462
- import_fs_extra2.default.removeSync((0, import_path3.resolve)(CWD, output));
463
- import_rslog2.logger.info(`Cleaned output directory: ${(0, import_path3.resolve)(CWD, output)}`);
464
- }
465
- import_rslog2.logger.info("Generating API modules...");
466
- if (openapiTsOptions.excludeDeprecated === void 0) {
467
- openapiTsOptions.excludeDeprecated = excludeDeprecated;
468
- }
469
- if (ts2) {
470
- await generateTypes(schema, output, typesFilename, openapiTsOptions);
471
- }
472
- const apiModules = partitionApiModules(schema, {
473
- base,
474
- uncountableNouns,
475
- transformer: mergedTransformer,
476
- validateStatus,
477
- excludeDeprecated
478
- });
479
- await renderApiModules(apiModules, { output, typesFilename, ts: ts2, typesOnly, overrides, preset });
480
- import_rslog2.logger.success("Done");
481
- }
482
-
483
- // src/index.ts
484
- var import_pluralize2 = __toESM(require("pluralize"), 1);
485
- // Annotate the CommonJS export names for ESM import in node:
486
- 0 && (module.exports = {
487
- createStatusCodesByStrategy,
488
- createTransformer,
489
- defineConfig,
490
- findObjectKey,
491
- generate,
492
- generateTypes,
493
- getCliVersion,
494
- getConfig,
495
- getRequestBodyContentType,
496
- getResponseMetadataItems,
497
- getSchemaNode,
498
- isRemoteSchema,
499
- isRequiredRequestBody,
500
- partitionApiModules,
501
- pluralize,
502
- readSchema,
503
- readSchemaContent,
504
- readTemplateFile,
505
- renderApiModules,
506
- transformComment,
507
- transformEntity,
508
- transformFn,
509
- transformModuleName,
510
- transformPayloads,
511
- transformType,
512
- transformTypeQuery,
513
- transformTypeQueryValue,
514
- transformTypeRequestBody,
515
- transformTypeRequestBodyValue,
516
- transformTypeResponseBody,
517
- transformTypeResponseBodyValue,
518
- transformTypeValue,
519
- transformUrl,
520
- transformVerb
521
- });