api-farmer 0.1.0 → 0.1.2

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/README.md CHANGED
@@ -153,6 +153,16 @@ export interface Config {
153
153
  * Certain uncountable nouns that do not change from singular to plural
154
154
  */
155
155
  uncountableNouns?: string[]
156
+ /**
157
+ * Whether to clean the output directory before generating.
158
+ * @default false
159
+ */
160
+ clean?: boolean
161
+ /**
162
+ * The options for the openapiTS library.
163
+ * @see https://openapi-ts.dev/node
164
+ */
165
+ openapiTsOptions?: OpenAPITSOptions
156
166
  }
157
167
  ```
158
168
 
@@ -105,7 +105,7 @@ function getResponseMetadataItems(operation, validateStatus) {
105
105
  const validStatusResults = Object.keys(responses).sort((a, b) => Number(a) - Number(b)).filter((key) => validateStatus(Number(key))).map(Number);
106
106
  const metadataItems = validStatusResults.map((status) => {
107
107
  const content = operation.responses?.[status]?.content ?? {};
108
- const responseContentType = findObjectKey(content, ["application/json", "*/*"]);
108
+ const responseContentType = findObjectKey(content, ["application/json", "application/octet-stream", "*/*"]);
109
109
  return {
110
110
  status,
111
111
  responseContentType
@@ -6,7 +6,7 @@ import {
6
6
  isRequiredRequestBody,
7
7
  readSchema,
8
8
  readTemplateFile
9
- } from "./chunk-56NOW5DM.js";
9
+ } from "./chunk-2227C45C.js";
10
10
 
11
11
  // src/generate.ts
12
12
  import { resolve } from "path";
@@ -16,6 +16,7 @@ import openapiTS, { astToString } from "openapi-typescript";
16
16
  import prettier from "prettier";
17
17
  import { groupBy, isArray, merge } from "rattail";
18
18
  import { logger } from "rslog";
19
+ import ts from "typescript";
19
20
 
20
21
  // src/config.ts
21
22
  import { loadConfig } from "unconfig";
@@ -217,7 +218,7 @@ function partitionApiModules(schema, options) {
217
218
  return apiModules;
218
219
  }
219
220
  function renderApiModules(apiModules, options) {
220
- const { output, ts, typesOnly, overrides, preset } = options;
221
+ const { output, ts: ts2, typesOnly, overrides, preset } = options;
221
222
  const templateFile = readTemplateFile(preset);
222
223
  const typesFilename = options.typesFilename.replace(".ts", "");
223
224
  return Promise.all(
@@ -226,7 +227,7 @@ function renderApiModules(apiModules, options) {
226
227
  const data = {
227
228
  apiModule,
228
229
  typesFilename,
229
- ts,
230
+ ts: ts2,
230
231
  typesOnly
231
232
  };
232
233
  prettier.format(ejs.render(templateFile, data), {
@@ -235,7 +236,7 @@ function renderApiModules(apiModules, options) {
235
236
  singleQuote: true,
236
237
  printWidth: 120
237
238
  }).then((content) => {
238
- const path = resolve(output, `${apiModule.name}.${ts ? "ts" : "js"}`);
239
+ const path = resolve(output, `${apiModule.name}.${ts2 ? "ts" : "js"}`);
239
240
  const shouldSkip = (!overrides || isArray(overrides) && !overrides.includes(apiModule.name)) && fse.existsSync(path);
240
241
  if (shouldSkip) {
241
242
  logger.warn(`File already exists, skip: ${path}`);
@@ -250,9 +251,17 @@ function renderApiModules(apiModules, options) {
250
251
  )
251
252
  );
252
253
  }
253
- async function generateTypes(schema, output, typesFilename) {
254
+ async function generateTypes(schema, output, typesFilename, openapiTsOptions) {
255
+ const BLOB = ts.factory.createTypeReferenceNode(ts.factory.createIdentifier("Blob"));
256
+ const NULL = ts.factory.createLiteralTypeNode(ts.factory.createNull());
254
257
  const ast = await openapiTS(schema, {
255
- defaultNonNullable: false
258
+ defaultNonNullable: false,
259
+ transform(schemaObject) {
260
+ if (schemaObject.format === "binary") {
261
+ return schemaObject.nullable ? ts.factory.createUnionTypeNode([BLOB, NULL]) : BLOB;
262
+ }
263
+ },
264
+ ...openapiTsOptions
256
265
  });
257
266
  const contents = astToString(ast);
258
267
  const typesFilepath = resolve(CWD, output, typesFilename);
@@ -264,22 +273,28 @@ async function generate(userOptions = {}) {
264
273
  const options = merge(config, userOptions);
265
274
  const {
266
275
  base,
267
- ts = true,
276
+ ts: ts2 = true,
268
277
  typesOnly = false,
269
278
  overrides = true,
270
279
  preset = "axle",
271
280
  input = "./schema.json",
272
281
  output = "./src/apis/generated",
273
282
  typesFilename = "_types.ts",
283
+ clean = false,
274
284
  validateStatus = (status) => status >= 200 && status < 300,
275
285
  transformer = {},
276
- uncountableNouns = []
286
+ uncountableNouns = [],
287
+ openapiTsOptions = {}
277
288
  } = options;
278
289
  const mergedTransformer = { ...createTransformer(), ...transformer };
279
290
  const schema = await readSchema(input);
291
+ if (clean) {
292
+ fse.removeSync(resolve(CWD, output));
293
+ logger.info(`Cleaned output directory: ${resolve(CWD, output)}`);
294
+ }
280
295
  logger.info("Generating API modules...");
281
- if (ts) {
282
- await generateTypes(schema, output, typesFilename);
296
+ if (ts2) {
297
+ await generateTypes(schema, output, typesFilename, openapiTsOptions);
283
298
  }
284
299
  const apiModules = partitionApiModules(schema, {
285
300
  base,
@@ -287,7 +302,7 @@ async function generate(userOptions = {}) {
287
302
  transformer: mergedTransformer,
288
303
  validateStatus
289
304
  });
290
- await renderApiModules(apiModules, { output, typesFilename, ts, typesOnly, overrides, preset });
305
+ await renderApiModules(apiModules, { output, typesFilename, ts: ts2, typesOnly, overrides, preset });
291
306
  logger.success("Done");
292
307
  }
293
308
 
package/dist/cli.cjs CHANGED
@@ -102,7 +102,7 @@ function getResponseMetadataItems(operation, validateStatus) {
102
102
  const validStatusResults = Object.keys(responses).sort((a, b) => Number(a) - Number(b)).filter((key) => validateStatus(Number(key))).map(Number);
103
103
  const metadataItems = validStatusResults.map((status) => {
104
104
  const content = operation.responses?.[status]?.content ?? {};
105
- const responseContentType = findObjectKey(content, ["application/json", "*/*"]);
105
+ const responseContentType = findObjectKey(content, ["application/json", "application/octet-stream", "*/*"]);
106
106
  return {
107
107
  status,
108
108
  responseContentType
@@ -345,7 +345,7 @@ function partitionApiModules(schema, options) {
345
345
  return apiModules;
346
346
  }
347
347
  function renderApiModules(apiModules, options) {
348
- const { output, ts, typesOnly, overrides, preset } = options;
348
+ const { output, ts: ts2, typesOnly, overrides, preset } = options;
349
349
  const templateFile = readTemplateFile(preset);
350
350
  const typesFilename = options.typesFilename.replace(".ts", "");
351
351
  return Promise.all(
@@ -354,7 +354,7 @@ function renderApiModules(apiModules, options) {
354
354
  const data = {
355
355
  apiModule,
356
356
  typesFilename,
357
- ts,
357
+ ts: ts2,
358
358
  typesOnly
359
359
  };
360
360
  import_prettier.default.format(import_ejs.default.render(templateFile, data), {
@@ -363,7 +363,7 @@ function renderApiModules(apiModules, options) {
363
363
  singleQuote: true,
364
364
  printWidth: 120
365
365
  }).then((content) => {
366
- const path = (0, import_path3.resolve)(output, `${apiModule.name}.${ts ? "ts" : "js"}`);
366
+ const path = (0, import_path3.resolve)(output, `${apiModule.name}.${ts2 ? "ts" : "js"}`);
367
367
  const shouldSkip = (!overrides || (0, import_rattail3.isArray)(overrides) && !overrides.includes(apiModule.name)) && import_fs_extra2.default.existsSync(path);
368
368
  if (shouldSkip) {
369
369
  import_rslog2.logger.warn(`File already exists, skip: ${path}`);
@@ -378,9 +378,17 @@ function renderApiModules(apiModules, options) {
378
378
  )
379
379
  );
380
380
  }
381
- async function generateTypes(schema, output, typesFilename) {
381
+ async function generateTypes(schema, output, typesFilename, openapiTsOptions) {
382
+ const BLOB = import_typescript.default.factory.createTypeReferenceNode(import_typescript.default.factory.createIdentifier("Blob"));
383
+ const NULL = import_typescript.default.factory.createLiteralTypeNode(import_typescript.default.factory.createNull());
382
384
  const ast = await (0, import_openapi_typescript.default)(schema, {
383
- defaultNonNullable: false
385
+ defaultNonNullable: false,
386
+ transform(schemaObject) {
387
+ if (schemaObject.format === "binary") {
388
+ return schemaObject.nullable ? import_typescript.default.factory.createUnionTypeNode([BLOB, NULL]) : BLOB;
389
+ }
390
+ },
391
+ ...openapiTsOptions
384
392
  });
385
393
  const contents = (0, import_openapi_typescript.astToString)(ast);
386
394
  const typesFilepath = (0, import_path3.resolve)(CWD, output, typesFilename);
@@ -392,22 +400,28 @@ async function generate(userOptions = {}) {
392
400
  const options = (0, import_rattail3.merge)(config, userOptions);
393
401
  const {
394
402
  base,
395
- ts = true,
403
+ ts: ts2 = true,
396
404
  typesOnly = false,
397
405
  overrides = true,
398
406
  preset = "axle",
399
407
  input = "./schema.json",
400
408
  output = "./src/apis/generated",
401
409
  typesFilename = "_types.ts",
410
+ clean = false,
402
411
  validateStatus = (status) => status >= 200 && status < 300,
403
412
  transformer = {},
404
- uncountableNouns = []
413
+ uncountableNouns = [],
414
+ openapiTsOptions = {}
405
415
  } = options;
406
416
  const mergedTransformer = { ...createTransformer(), ...transformer };
407
417
  const schema = await readSchema(input);
418
+ if (clean) {
419
+ import_fs_extra2.default.removeSync((0, import_path3.resolve)(CWD, output));
420
+ import_rslog2.logger.info(`Cleaned output directory: ${(0, import_path3.resolve)(CWD, output)}`);
421
+ }
408
422
  import_rslog2.logger.info("Generating API modules...");
409
- if (ts) {
410
- await generateTypes(schema, output, typesFilename);
423
+ if (ts2) {
424
+ await generateTypes(schema, output, typesFilename, openapiTsOptions);
411
425
  }
412
426
  const apiModules = partitionApiModules(schema, {
413
427
  base,
@@ -415,10 +429,10 @@ async function generate(userOptions = {}) {
415
429
  transformer: mergedTransformer,
416
430
  validateStatus
417
431
  });
418
- await renderApiModules(apiModules, { output, typesFilename, ts, typesOnly, overrides, preset });
432
+ await renderApiModules(apiModules, { output, typesFilename, ts: ts2, typesOnly, overrides, preset });
419
433
  import_rslog2.logger.success("Done");
420
434
  }
421
- var import_path3, import_ejs, import_fs_extra2, import_openapi_typescript, import_prettier, import_rattail3, import_rslog2;
435
+ var import_path3, import_ejs, import_fs_extra2, import_openapi_typescript, import_prettier, import_rattail3, import_rslog2, import_typescript;
422
436
  var init_generate = __esm({
423
437
  "src/generate.ts"() {
424
438
  "use strict";
@@ -430,6 +444,7 @@ var init_generate = __esm({
430
444
  import_prettier = __toESM(require("prettier"), 1);
431
445
  import_rattail3 = require("rattail");
432
446
  import_rslog2 = require("rslog");
447
+ import_typescript = __toESM(require("typescript"), 1);
433
448
  init_config();
434
449
  init_constants();
435
450
  init_transformer();
package/dist/cli.js CHANGED
@@ -1,14 +1,14 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  getCliVersion
4
- } from "./chunk-56NOW5DM.js";
4
+ } from "./chunk-2227C45C.js";
5
5
 
6
6
  // src/cli.ts
7
7
  import { Command } from "commander";
8
8
  var program = new Command();
9
9
  program.version(getCliVersion());
10
10
  program.action(async () => {
11
- const { generate } = await import("./generate-BJMNBKQH.js");
11
+ const { generate } = await import("./generate-K6NGTXOH.js");
12
12
  return generate();
13
13
  });
14
14
  program.parse();
@@ -4,8 +4,8 @@ import {
4
4
  partitionApiModules,
5
5
  renderApiModules,
6
6
  transformPayloads
7
- } from "./chunk-XM4XA35S.js";
8
- import "./chunk-56NOW5DM.js";
7
+ } from "./chunk-FOIQWD3Q.js";
8
+ import "./chunk-2227C45C.js";
9
9
  export {
10
10
  generate,
11
11
  generateTypes,
package/dist/index.cjs CHANGED
@@ -185,6 +185,7 @@ var import_openapi_typescript = __toESM(require("openapi-typescript"), 1);
185
185
  var import_prettier = __toESM(require("prettier"), 1);
186
186
  var import_rattail3 = require("rattail");
187
187
  var import_rslog2 = require("rslog");
188
+ var import_typescript = __toESM(require("typescript"), 1);
188
189
 
189
190
  // src/config.ts
190
191
  var import_unconfig = require("unconfig");
@@ -302,7 +303,7 @@ function getResponseMetadataItems(operation, validateStatus) {
302
303
  const validStatusResults = Object.keys(responses).sort((a, b) => Number(a) - Number(b)).filter((key) => validateStatus(Number(key))).map(Number);
303
304
  const metadataItems = validStatusResults.map((status) => {
304
305
  const content = operation.responses?.[status]?.content ?? {};
305
- const responseContentType = findObjectKey(content, ["application/json", "*/*"]);
306
+ const responseContentType = findObjectKey(content, ["application/json", "application/octet-stream", "*/*"]);
306
307
  return {
307
308
  status,
308
309
  responseContentType
@@ -385,7 +386,7 @@ function partitionApiModules(schema, options) {
385
386
  return apiModules;
386
387
  }
387
388
  function renderApiModules(apiModules, options) {
388
- const { output, ts, typesOnly, overrides, preset } = options;
389
+ const { output, ts: ts2, typesOnly, overrides, preset } = options;
389
390
  const templateFile = readTemplateFile(preset);
390
391
  const typesFilename = options.typesFilename.replace(".ts", "");
391
392
  return Promise.all(
@@ -394,7 +395,7 @@ function renderApiModules(apiModules, options) {
394
395
  const data = {
395
396
  apiModule,
396
397
  typesFilename,
397
- ts,
398
+ ts: ts2,
398
399
  typesOnly
399
400
  };
400
401
  import_prettier.default.format(import_ejs.default.render(templateFile, data), {
@@ -403,7 +404,7 @@ function renderApiModules(apiModules, options) {
403
404
  singleQuote: true,
404
405
  printWidth: 120
405
406
  }).then((content) => {
406
- const path = (0, import_path3.resolve)(output, `${apiModule.name}.${ts ? "ts" : "js"}`);
407
+ const path = (0, import_path3.resolve)(output, `${apiModule.name}.${ts2 ? "ts" : "js"}`);
407
408
  const shouldSkip = (!overrides || (0, import_rattail3.isArray)(overrides) && !overrides.includes(apiModule.name)) && import_fs_extra2.default.existsSync(path);
408
409
  if (shouldSkip) {
409
410
  import_rslog2.logger.warn(`File already exists, skip: ${path}`);
@@ -418,9 +419,17 @@ function renderApiModules(apiModules, options) {
418
419
  )
419
420
  );
420
421
  }
421
- async function generateTypes(schema, output, typesFilename) {
422
+ async function generateTypes(schema, output, typesFilename, openapiTsOptions) {
423
+ const BLOB = import_typescript.default.factory.createTypeReferenceNode(import_typescript.default.factory.createIdentifier("Blob"));
424
+ const NULL = import_typescript.default.factory.createLiteralTypeNode(import_typescript.default.factory.createNull());
422
425
  const ast = await (0, import_openapi_typescript.default)(schema, {
423
- defaultNonNullable: false
426
+ defaultNonNullable: false,
427
+ transform(schemaObject) {
428
+ if (schemaObject.format === "binary") {
429
+ return schemaObject.nullable ? import_typescript.default.factory.createUnionTypeNode([BLOB, NULL]) : BLOB;
430
+ }
431
+ },
432
+ ...openapiTsOptions
424
433
  });
425
434
  const contents = (0, import_openapi_typescript.astToString)(ast);
426
435
  const typesFilepath = (0, import_path3.resolve)(CWD, output, typesFilename);
@@ -432,22 +441,28 @@ async function generate(userOptions = {}) {
432
441
  const options = (0, import_rattail3.merge)(config, userOptions);
433
442
  const {
434
443
  base,
435
- ts = true,
444
+ ts: ts2 = true,
436
445
  typesOnly = false,
437
446
  overrides = true,
438
447
  preset = "axle",
439
448
  input = "./schema.json",
440
449
  output = "./src/apis/generated",
441
450
  typesFilename = "_types.ts",
451
+ clean = false,
442
452
  validateStatus = (status) => status >= 200 && status < 300,
443
453
  transformer = {},
444
- uncountableNouns = []
454
+ uncountableNouns = [],
455
+ openapiTsOptions = {}
445
456
  } = options;
446
457
  const mergedTransformer = { ...createTransformer(), ...transformer };
447
458
  const schema = await readSchema(input);
459
+ if (clean) {
460
+ import_fs_extra2.default.removeSync((0, import_path3.resolve)(CWD, output));
461
+ import_rslog2.logger.info(`Cleaned output directory: ${(0, import_path3.resolve)(CWD, output)}`);
462
+ }
448
463
  import_rslog2.logger.info("Generating API modules...");
449
- if (ts) {
450
- await generateTypes(schema, output, typesFilename);
464
+ if (ts2) {
465
+ await generateTypes(schema, output, typesFilename, openapiTsOptions);
451
466
  }
452
467
  const apiModules = partitionApiModules(schema, {
453
468
  base,
@@ -455,7 +470,7 @@ async function generate(userOptions = {}) {
455
470
  transformer: mergedTransformer,
456
471
  validateStatus
457
472
  });
458
- await renderApiModules(apiModules, { output, typesFilename, ts, typesOnly, overrides, preset });
473
+ await renderApiModules(apiModules, { output, typesFilename, ts: ts2, typesOnly, overrides, preset });
459
474
  import_rslog2.logger.success("Done");
460
475
  }
461
476
 
package/dist/index.d.cts CHANGED
@@ -1,4 +1,4 @@
1
- import { OpenAPI3, RequestBodyObject, ReferenceObject, OperationObject } from 'openapi-typescript';
1
+ import { OpenAPI3, RequestBodyObject, ReferenceObject, OperationObject, OpenAPITSOptions } from 'openapi-typescript';
2
2
  export { default as pluralize } from 'pluralize';
3
3
 
4
4
  type Preset = 'axle' | 'axios';
@@ -285,6 +285,15 @@ interface GenerateOptions {
285
285
  * Certain uncountable nouns that do not change from singular to plural
286
286
  */
287
287
  uncountableNouns?: string[];
288
+ /**
289
+ * Whether to clean the output directory before generating.
290
+ * @default false
291
+ */
292
+ clean?: boolean;
293
+ /**
294
+ * A function to transform the generated types AST before printing to string.
295
+ */
296
+ openapiTsOptions?: OpenAPITSOptions;
288
297
  }
289
298
  declare function transformPayloads(pathItems: Record<string, OperationObject>, options: {
290
299
  path: string;
@@ -308,7 +317,7 @@ declare function renderApiModules(apiModules: ApiModule[], options: {
308
317
  overrides: boolean | string[];
309
318
  preset: Preset;
310
319
  }): Promise<unknown[]>;
311
- declare function generateTypes(schema: OpenAPI3, output: string, typesFilename: string): Promise<void>;
320
+ declare function generateTypes(schema: OpenAPI3, output: string, typesFilename: string, openapiTsOptions: OpenAPITSOptions): Promise<void>;
312
321
  declare function generate(userOptions?: GenerateOptions): Promise<void>;
313
322
 
314
323
  type Config = GenerateOptions;
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { OpenAPI3, RequestBodyObject, ReferenceObject, OperationObject } from 'openapi-typescript';
1
+ import { OpenAPI3, RequestBodyObject, ReferenceObject, OperationObject, OpenAPITSOptions } from 'openapi-typescript';
2
2
  export { default as pluralize } from 'pluralize';
3
3
 
4
4
  type Preset = 'axle' | 'axios';
@@ -285,6 +285,15 @@ interface GenerateOptions {
285
285
  * Certain uncountable nouns that do not change from singular to plural
286
286
  */
287
287
  uncountableNouns?: string[];
288
+ /**
289
+ * Whether to clean the output directory before generating.
290
+ * @default false
291
+ */
292
+ clean?: boolean;
293
+ /**
294
+ * A function to transform the generated types AST before printing to string.
295
+ */
296
+ openapiTsOptions?: OpenAPITSOptions;
288
297
  }
289
298
  declare function transformPayloads(pathItems: Record<string, OperationObject>, options: {
290
299
  path: string;
@@ -308,7 +317,7 @@ declare function renderApiModules(apiModules: ApiModule[], options: {
308
317
  overrides: boolean | string[];
309
318
  preset: Preset;
310
319
  }): Promise<unknown[]>;
311
- declare function generateTypes(schema: OpenAPI3, output: string, typesFilename: string): Promise<void>;
320
+ declare function generateTypes(schema: OpenAPI3, output: string, typesFilename: string, openapiTsOptions: OpenAPITSOptions): Promise<void>;
312
321
  declare function generate(userOptions?: GenerateOptions): Promise<void>;
313
322
 
314
323
  type Config = GenerateOptions;
package/dist/index.js CHANGED
@@ -21,7 +21,7 @@ import {
21
21
  transformTypeValue,
22
22
  transformUrl,
23
23
  transformVerb
24
- } from "./chunk-XM4XA35S.js";
24
+ } from "./chunk-FOIQWD3Q.js";
25
25
  import {
26
26
  createStatusCodesByStrategy,
27
27
  findObjectKey,
@@ -34,7 +34,7 @@ import {
34
34
  readSchema,
35
35
  readSchemaContent,
36
36
  readTemplateFile
37
- } from "./chunk-56NOW5DM.js";
37
+ } from "./chunk-2227C45C.js";
38
38
 
39
39
  // src/index.ts
40
40
  import { default as default2 } from "pluralize";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "api-farmer",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "API module generation tool based on Openapi3/Swagger2.",
5
5
  "keywords": [
6
6
  "cli",
@@ -78,7 +78,7 @@
78
78
  "typescript": "5.3.3"
79
79
  },
80
80
  "peerDependencies": {
81
- "eslint": "^9.17.0"
81
+ "typescript": "^5.3.3"
82
82
  },
83
83
  "engines": {
84
84
  "pnpm": ">=9.0"