api 6.1.0 → 7.0.0-alpha.0

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.
Files changed (69) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +0 -12
  3. package/package.json +18 -38
  4. package/src/bin.ts +1 -1
  5. package/src/{cli/codegen → codegen}/index.ts +1 -1
  6. package/src/{cli/codegen → codegen}/language.ts +4 -3
  7. package/src/{cli/codegen → codegen}/languages/typescript/util.ts +1 -10
  8. package/src/{cli/codegen → codegen}/languages/typescript.ts +40 -41
  9. package/src/{cli/commands → commands}/install.ts +3 -3
  10. package/src/fetcher.ts +6 -8
  11. package/src/{cli/lib → lib}/prompt.ts +1 -1
  12. package/src/packageInfo.ts +1 -1
  13. package/src/{cli/storage.ts → storage.ts} +13 -9
  14. package/tsconfig.json +3 -13
  15. package/dist/bin.d.ts +0 -1
  16. package/dist/bin.js +0 -91
  17. package/dist/cache.d.ts +0 -68
  18. package/dist/cache.js +0 -198
  19. package/dist/cli/codegen/index.d.ts +0 -4
  20. package/dist/cli/codegen/index.js +0 -23
  21. package/dist/cli/codegen/language.d.ts +0 -27
  22. package/dist/cli/codegen/language.js +0 -32
  23. package/dist/cli/codegen/languages/typescript/util.d.ts +0 -21
  24. package/dist/cli/codegen/languages/typescript/util.js +0 -185
  25. package/dist/cli/codegen/languages/typescript.d.ts +0 -111
  26. package/dist/cli/codegen/languages/typescript.js +0 -821
  27. package/dist/cli/commands/index.d.ts +0 -4
  28. package/dist/cli/commands/index.js +0 -9
  29. package/dist/cli/commands/install.d.ts +0 -3
  30. package/dist/cli/commands/install.js +0 -236
  31. package/dist/cli/lib/prompt.d.ts +0 -9
  32. package/dist/cli/lib/prompt.js +0 -81
  33. package/dist/cli/logger.d.ts +0 -1
  34. package/dist/cli/logger.js +0 -16
  35. package/dist/cli/storage.d.ts +0 -105
  36. package/dist/cli/storage.js +0 -277
  37. package/dist/core/errors/fetchError.d.ts +0 -12
  38. package/dist/core/errors/fetchError.js +0 -36
  39. package/dist/core/getJSONSchemaDefaults.d.ts +0 -14
  40. package/dist/core/getJSONSchemaDefaults.js +0 -61
  41. package/dist/core/index.d.ts +0 -40
  42. package/dist/core/index.js +0 -168
  43. package/dist/core/parseResponse.d.ts +0 -6
  44. package/dist/core/parseResponse.js +0 -71
  45. package/dist/core/prepareAuth.d.ts +0 -5
  46. package/dist/core/prepareAuth.js +0 -84
  47. package/dist/core/prepareParams.d.ts +0 -21
  48. package/dist/core/prepareParams.js +0 -422
  49. package/dist/core/prepareServer.d.ts +0 -10
  50. package/dist/core/prepareServer.js +0 -47
  51. package/dist/fetcher.d.ts +0 -54
  52. package/dist/fetcher.js +0 -165
  53. package/dist/index.d.ts +0 -6
  54. package/dist/index.js +0 -259
  55. package/dist/packageInfo.d.ts +0 -2
  56. package/dist/packageInfo.js +0 -6
  57. package/src/.sink.d.ts +0 -1
  58. package/src/cache.ts +0 -193
  59. package/src/core/errors/fetchError.ts +0 -31
  60. package/src/core/getJSONSchemaDefaults.ts +0 -74
  61. package/src/core/index.ts +0 -148
  62. package/src/core/parseResponse.ts +0 -26
  63. package/src/core/prepareAuth.ts +0 -109
  64. package/src/core/prepareParams.ts +0 -410
  65. package/src/core/prepareServer.ts +0 -48
  66. package/src/index.ts +0 -203
  67. package/src/typings.d.ts +0 -2
  68. /package/src/{cli/commands → commands}/index.ts +0 -0
  69. /package/src/{cli/logger.ts → logger.ts} +0 -0
package/LICENSE CHANGED
@@ -1,4 +1,4 @@
1
- Copyright © 2022 ReadMe
1
+ Copyright © 2023 ReadMe
2
2
 
3
3
  Permission is hereby granted, free of charge, to any person obtaining a copy of
4
4
  this software and associated documentation files (the “Software”), to deal in
package/README.md CHANGED
@@ -36,18 +36,6 @@ petstore.listPets().then(({ data }) => {
36
36
  });
37
37
  ```
38
38
 
39
- Or you can use it dynamically (though you won't have fancy TypeScript types to help you out!):
40
-
41
- ```js
42
- const petstore = require('api')(
43
- 'https://raw.githubusercontent.com/OAI/OpenAPI-Specification/main/examples/v3.0/petstore.json'
44
- );
45
-
46
- petstore.listPets().then(({ data }) => {
47
- console.log(`My pets name is ${data[0].name}!`);
48
- });
49
- ```
50
-
51
39
  The ESM syntax is supported as well:
52
40
 
53
41
  ```js
package/package.json CHANGED
@@ -1,19 +1,18 @@
1
1
  {
2
2
  "name": "api",
3
- "version": "6.1.0",
3
+ "version": "7.0.0-alpha.0",
4
4
  "description": "Magical SDK generation from an OpenAPI definition 🪄",
5
- "main": "./dist/index.js",
6
- "types": "./dist/index.d.ts",
7
5
  "bin": {
8
6
  "api": "./bin/api"
9
7
  },
10
8
  "scripts": {
11
9
  "build": "tsc",
12
10
  "debug:bin": "node -r ts-node/register src/bin.ts",
11
+ "lint:types": "tsc --noEmit",
13
12
  "prebuild": "rm -rf dist/; npm run version",
14
13
  "prepack": "npm run build",
15
- "test": "jest --coverage $(find test -name '*.test.ts' -not -path '*/smoketest.test.ts')",
16
- "test:smoke": "npx jest test/cli/codegen/languages/typescript/smoketest.test.ts",
14
+ "test": "vitest run --coverage",
15
+ "test:smoke": "vitest --config=vitest-smoketest.config.ts ",
17
16
  "version": "node -p \"'// This file is automatically updated by the build script.\\nexport const PACKAGE_NAME = \\'' + require('./package.json').name + '\\';\\nexport const PACKAGE_VERSION = \\'' + require('./package.json').version + '\\';'\" > src/packageInfo.ts; git add src/packageInfo.ts"
18
17
  },
19
18
  "repository": {
@@ -28,7 +27,7 @@
28
27
  "author": "Jon Ursenbach <jon@readme.io>",
29
28
  "license": "MIT",
30
29
  "engines": {
31
- "node": ">=16"
30
+ "node": ">=18"
32
31
  },
33
32
  "keywords": [
34
33
  "api",
@@ -37,65 +36,46 @@
37
36
  "swagger"
38
37
  ],
39
38
  "dependencies": {
40
- "@readme/oas-to-har": "^20.0.2",
41
39
  "@readme/openapi-parser": "^2.4.0",
42
- "caseless": "^0.12.0",
43
40
  "chalk": "^4.1.2",
44
- "commander": "^10.0.0",
45
- "datauri": "^4.1.0",
41
+ "commander": "^11.0.0",
46
42
  "execa": "^5.1.1",
47
- "fetch-har": "^8.1.5",
48
43
  "figures": "^3.2.0",
49
- "find-cache-dir": "^3.3.1",
50
- "form-data-encoder": "^1.7.2",
51
- "formdata-node": "^4.3.2",
52
- "get-stream": "^6.0.1",
53
- "isomorphic-fetch": "^3.0.0",
54
44
  "js-yaml": "^4.1.0",
55
- "json-schema-to-ts": "^2.6.2-beta.0",
56
- "json-schema-traverse": "^1.0.0",
45
+ "json-schema-to-ts": "^2.9.2",
57
46
  "lodash.camelcase": "^4.3.0",
58
47
  "lodash.deburr": "^4.1.0",
59
- "lodash.merge": "^4.6.2",
60
48
  "lodash.setwith": "^4.3.2",
61
49
  "lodash.startcase": "^4.4.0",
62
50
  "make-dir": "^3.1.0",
63
- "node-abort-controller": "^3.1.1",
64
51
  "oas": "^20.4.0",
65
52
  "ora": "^5.4.1",
66
- "prettier": "^2.8.3",
67
53
  "prompts": "^2.4.2",
68
- "remove-undefined-objects": "^2.0.2",
69
54
  "semver": "^7.3.8",
70
55
  "ssri": "^10.0.1",
71
56
  "ts-morph": "^17.0.1",
72
57
  "validate-npm-package-name": "^5.0.0"
73
58
  },
74
59
  "devDependencies": {
75
- "@readme/oas-examples": "^5.9.0",
76
- "@types/caseless": "^0.12.2",
77
- "@types/find-cache-dir": "^3.2.1",
78
- "@types/jest": "^29.5.2",
60
+ "@api/test-utils": "file:../test-utils",
61
+ "@readme/oas-examples": "^5.12.0",
79
62
  "@types/js-yaml": "^4.0.5",
80
63
  "@types/lodash.camelcase": "^4.3.7",
81
64
  "@types/lodash.deburr": "^4.1.7",
82
- "@types/lodash.merge": "^4.6.7",
83
65
  "@types/lodash.setwith": "^4.3.7",
84
66
  "@types/lodash.startcase": "^4.4.7",
85
- "@types/prettier": "^2.7.2",
86
- "@types/prompts": "^2.4.2",
87
- "@types/semver": "^7.3.13",
67
+ "@types/prompts": "^2.4.4",
68
+ "@types/semver": "^7.5.1",
88
69
  "@types/ssri": "^7.1.1",
89
70
  "@types/validate-npm-package-name": "^4.0.0",
71
+ "@vitest/coverage-v8": "^0.34.4",
72
+ "api.core": "file:../core",
90
73
  "fetch-mock": "^9.11.0",
91
- "jest": "^29.6.1",
92
- "jest-extended": "^4.0.0",
93
74
  "oas-normalize": "^8.3.2",
94
- "ts-jest": "^29.1.1",
95
- "type-fest": "^3.5.4",
96
- "typescript": "^4.9.5",
97
- "unique-temp-dir": "^1.0.0"
75
+ "type-fest": "^4.3.1",
76
+ "typescript": "^5.2.2",
77
+ "unique-temp-dir": "^1.0.0",
78
+ "vitest": "^0.34.1"
98
79
  },
99
- "prettier": "@readme/eslint-config/prettier",
100
- "gitHead": "244093f2ad00e5ea527420f49bdb541bc2095806"
80
+ "prettier": "@readme/eslint-config/prettier"
101
81
  }
package/src/bin.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { Command } from 'commander';
2
2
 
3
- import commands from './cli/commands';
3
+ import commands from './commands';
4
4
  import * as pkg from './packageInfo';
5
5
 
6
6
  (async () => {
@@ -9,7 +9,7 @@ export default function codegen(
9
9
  language: SupportedLanguages,
10
10
  spec: Oas,
11
11
  specPath: string,
12
- identifier: string
12
+ identifier: string,
13
13
  ): CodeGeneratorLanguage {
14
14
  switch (language) {
15
15
  case 'js':
@@ -1,7 +1,7 @@
1
1
  import type Storage from '../storage';
2
2
  import type Oas from 'oas';
3
3
 
4
- import { PACKAGE_NAME, PACKAGE_VERSION } from '../../packageInfo';
4
+ import { PACKAGE_NAME, PACKAGE_VERSION } from '../packageInfo';
5
5
 
6
6
  export interface InstallerOptions {
7
7
  /**
@@ -25,11 +25,12 @@ export default abstract class CodeGeneratorLanguage {
25
25
 
26
26
  userAgent: string;
27
27
 
28
- requiredPackages: Record<string, { reason: string; url: string }>;
28
+ requiredPackages!: Record<string, { reason: string; url: string }>;
29
29
 
30
30
  constructor(spec: Oas, specPath: string, identifier: string) {
31
31
  this.spec = spec;
32
32
  this.specPath = specPath;
33
+ this.identifier = identifier;
33
34
 
34
35
  // User agents should be contextual to the spec in question and the version of `api` that was
35
36
  // used to generate the SDK. For example, this'll look like `petstore/1.0.0 (api/4.2.0)` for
@@ -49,7 +50,7 @@ export default abstract class CodeGeneratorLanguage {
49
50
  */
50
51
  if (JSON.stringify(spec.api).includes('"$ref":"#/')) {
51
52
  throw new Error(
52
- 'Sorry, this library does not yet support generating an SDK for an OpenAPI definition that contains circular references.'
53
+ 'Sorry, this library does not yet support generating an SDK for an OpenAPI definition that contains circular references.',
53
54
  );
54
55
  }
55
56
  }
@@ -1,7 +1,6 @@
1
1
  import camelCase from 'lodash.camelcase';
2
2
  import deburr from 'lodash.deburr';
3
3
  import startCase from 'lodash.startcase';
4
- import { format as prettier } from 'prettier';
5
4
 
6
5
  /**
7
6
  * This is a mix of reserved JS words and keywords in TypeScript that might be reserved or
@@ -100,14 +99,6 @@ const RESERVED_WORDS = [
100
99
  'window',
101
100
  ];
102
101
 
103
- export function formatter(content: string) {
104
- return prettier(content, {
105
- parser: 'typescript',
106
- printWidth: 100,
107
- singleQuote: true,
108
- });
109
- }
110
-
111
102
  /**
112
103
  * @see {@link https://www.30secondsofcode.org/js/s/word-wrap}
113
104
  */
@@ -132,7 +123,7 @@ export function docblockEscape(str: string) {
132
123
  * @license MIT
133
124
  * @see {@link https://github.com/bcherny/json-schema-to-typescript}
134
125
  */
135
- export function toSafeString(str: string) {
126
+ function toSafeString(str: string) {
136
127
  // identifiers in javaScript/ts:
137
128
  // First character: a-zA-Z | _ | $
138
129
  // Rest: a-zA-Z | _ | $ | 0-9
@@ -3,6 +3,7 @@ import type { InstallerOptions } from '../language';
3
3
  import type Oas from 'oas';
4
4
  import type { Operation } from 'oas';
5
5
  import type { HttpMethods, SchemaObject } from 'oas/dist/rmoas.types';
6
+ import type { SemVer } from 'semver';
6
7
  import type {
7
8
  ClassDeclaration,
8
9
  JSDocStructure,
@@ -12,8 +13,8 @@ import type {
12
13
  } from 'ts-morph';
13
14
  import type { PackageJson } from 'type-fest';
14
15
 
15
- import fs from 'fs';
16
- import path from 'path';
16
+ import fs from 'node:fs';
17
+ import path from 'node:path';
17
18
 
18
19
  import execa from 'execa';
19
20
  import setWith from 'lodash.setwith';
@@ -23,7 +24,7 @@ import { IndentationText, Project, QuoteKind, ScriptTarget, VariableDeclarationK
23
24
  import logger from '../../logger';
24
25
  import CodeGeneratorLanguage from '../language';
25
26
 
26
- import { docblockEscape, formatter, generateTypeName, wordWrap } from './typescript/util';
27
+ import { docblockEscape, generateTypeName, wordWrap } from './typescript/util';
27
28
 
28
29
  export interface TSGeneratorOptions {
29
30
  compilerTarget?: 'cjs' | 'esm';
@@ -53,20 +54,18 @@ export default class TSGenerator extends CodeGeneratorLanguage {
53
54
 
54
55
  types: Map<string, string>;
55
56
 
56
- files: Record<string, string>;
57
-
58
- sdk: ClassDeclaration;
57
+ sdk!: ClassDeclaration;
59
58
 
60
59
  schemas: Record<
61
60
  string,
62
61
  // Operation-level type
63
62
  | {
64
- body?: any;
65
- metadata?: any;
66
- response?: Record<string, any>;
63
+ body?: unknown;
64
+ metadata?: unknown;
65
+ response?: Record<string, unknown>;
67
66
  }
68
67
  // Wholesale collection of `$ref` pointer types
69
- | Record<string, any>
68
+ | Record<string, unknown>
70
69
  >;
71
70
 
72
71
  usesHTTPMethodRangeInterface = false;
@@ -87,15 +86,15 @@ export default class TSGenerator extends CodeGeneratorLanguage {
87
86
 
88
87
  this.requiredPackages = {
89
88
  api: {
90
- reason: "Required for the `api/dist/core` library that the codegen'd SDK uses for making requests.",
89
+ reason: "Required for the `api.core` library that the codegen'd SDK uses for making requests.",
91
90
  url: 'https://npm.im/api',
92
91
  },
93
- 'json-schema-to-ts@beta': {
92
+ 'json-schema-to-ts': {
94
93
  reason: 'Required for TypeScript type handling.',
95
94
  url: 'https://npm.im/json-schema-to-ts',
96
95
  },
97
96
  oas: {
98
- reason: 'Used within `api/dist/core` and is also loaded for TypeScript types.',
97
+ reason: 'Used within `api.core` and is also loaded for TypeScript types.',
99
98
  url: 'https://npm.im/oas',
100
99
  },
101
100
  };
@@ -138,7 +137,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
138
137
  if (!pkgVersion) {
139
138
  // If the version that's in `info.version` isn't compatible with semver NPM won't be able to
140
139
  // handle it properly so we need to fallback to something it can.
141
- pkgVersion = semver.coerce('0.0.0');
140
+ pkgVersion = semver.coerce('0.0.0') as SemVer;
142
141
  }
143
142
 
144
143
  const pkg: PackageJson = {
@@ -221,7 +220,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
221
220
  sdkSource
222
221
  .getImportDeclarations()
223
222
  .find(id => id.getText() === "import type * as types from './types';")
224
- .remove();
223
+ ?.remove();
225
224
  }
226
225
 
227
226
  // If this SDK doesn't use the `HTTPMethodRange` interface for handling `2XX` response status
@@ -230,7 +229,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
230
229
  sdkSource
231
230
  .getImportDeclarations()
232
231
  .find(id => id.getText().includes('HTTPMethodRange'))
233
- .replaceWithText("import type { ConfigOptions, FetchResponse } from 'api/dist/core'");
232
+ ?.replaceWithText("import type { ConfigOptions, FetchResponse } from 'api.core';");
234
233
  }
235
234
 
236
235
  if (this.outputJS) {
@@ -245,7 +244,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
245
244
  return {};
246
245
  }
247
246
 
248
- let code = formatter(sourceFile.text);
247
+ let code = sourceFile.text;
249
248
  if (file === 'index.js' && this.compilerTarget === 'cjs') {
250
249
  /**
251
250
  * There's an annoying quirk with `ts-morph` where if we're exporting a default export
@@ -271,7 +270,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
271
270
 
272
271
  return [
273
272
  ...this.project.getSourceFiles().map(sourceFile => ({
274
- [sourceFile.getBaseName()]: formatter(sourceFile.getFullText()),
273
+ [sourceFile.getBaseName()]: sourceFile.getFullText(),
275
274
  })),
276
275
 
277
276
  // Because we're returning the raw source files for TS generation we also need to separately
@@ -281,7 +280,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
281
280
  .emitToMemory({ emitOnlyDtsFiles: true })
282
281
  .getFiles()
283
282
  .map(sourceFile => ({
284
- [path.basename(sourceFile.filePath)]: formatter(sourceFile.text),
283
+ [path.basename(sourceFile.filePath)]: sourceFile.text,
285
284
  })),
286
285
  ].reduce((prev, next) => Object.assign(prev, next));
287
286
  }
@@ -301,10 +300,10 @@ export default class TSGenerator extends CodeGeneratorLanguage {
301
300
  {
302
301
  // `HTTPMethodRange` will be conditionally removed later if it ends up not being used.
303
302
  defaultImport: 'type { ConfigOptions, FetchResponse, HTTPMethodRange }',
304
- moduleSpecifier: 'api/dist/core',
303
+ moduleSpecifier: 'api.core',
305
304
  },
306
305
  { defaultImport: 'Oas', moduleSpecifier: 'oas' },
307
- { defaultImport: 'APICore', moduleSpecifier: 'api/dist/core' },
306
+ { defaultImport: 'APICore', moduleSpecifier: 'api.core' },
308
307
  { defaultImport: 'definition', moduleSpecifier: this.specPath },
309
308
  ]);
310
309
 
@@ -340,7 +339,7 @@ export default class TSGenerator extends CodeGeneratorLanguage {
340
339
  {
341
340
  tagName: 'param',
342
341
  text: wordWrap(
343
- 'config.timeout Override the default `fetch` request timeout of 30 seconds. This number should be represented in milliseconds.'
342
+ 'config.timeout Override the default `fetch` request timeout of 30 seconds. This number should be represented in milliseconds.',
344
343
  ),
345
344
  },
346
345
  ],
@@ -370,7 +369,7 @@ sdk.auth('username', 'password');
370
369
  sdk.auth('myBearerToken');
371
370
 
372
371
  @example <caption>API Keys</caption>
373
- sdk.auth('myApiKey');`)
372
+ sdk.auth('myApiKey');`),
374
373
  ),
375
374
  tags: [
376
375
  { tagName: 'see', text: '{@link https://spec.openapis.org/oas/v3.0.3#fixed-fields-22}' },
@@ -403,7 +402,7 @@ sdk.server('https://{region}.api.example.com/{basePath}', {
403
402
  });
404
403
 
405
404
  @example <caption>Fully qualified server URL</caption>
406
- sdk.server('https://eu.api.example.com/v14');`)
405
+ sdk.server('https://eu.api.example.com/v14');`),
407
406
  ),
408
407
  tags: [
409
408
  { tagName: 'param', text: 'url Server URL' },
@@ -536,7 +535,7 @@ sdk.server('https://eu.api.example.com/v14');`)
536
535
  operation: Operation,
537
536
  operationId: string,
538
537
  paramTypes?: OperationTypeHousing['types']['params'],
539
- responseTypes?: OperationTypeHousing['types']['responses']
538
+ responseTypes?: OperationTypeHousing['types']['responses'],
540
539
  ) {
541
540
  let docblock: OptionalKind<JSDocStructure> = {};
542
541
  const summary = operation.getSummary();
@@ -566,10 +565,10 @@ sdk.server('https://eu.api.example.com/v14');`)
566
565
 
567
566
  let hasOptionalBody = false;
568
567
  let hasOptionalMetadata = false;
569
- const parameters: {
570
- body?: OptionalKind<ParameterDeclarationStructure>;
571
- metadata?: OptionalKind<ParameterDeclarationStructure>;
572
- } = {};
568
+ const parameters = {} as {
569
+ body: OptionalKind<ParameterDeclarationStructure>;
570
+ metadata: OptionalKind<ParameterDeclarationStructure>;
571
+ };
573
572
 
574
573
  if (paramTypes) {
575
574
  // If an operation has a request body payload it will only ever have `body` or `formData`,
@@ -656,7 +655,7 @@ sdk.server('https://eu.api.example.com/v14');`)
656
655
  // we should only add a docblock to the first overload we create because IDE Intellisense will
657
656
  // always use that and adding a docblock to all three will bloat the SDK with unused and
658
657
  // unsurfaced method documentation.
659
- docs: shouldAddAltTypedOverloads ? null : Object.keys(docblock).length ? [docblock] : null,
658
+ docs: shouldAddAltTypedOverloads ? undefined : Object.keys(docblock).length ? [docblock] : undefined,
660
659
  statements: writer => {
661
660
  /**
662
661
  * @example return this.core.fetch('/pet/findByStatus', 'get', body, metadata);
@@ -676,7 +675,7 @@ sdk.server('https://eu.api.example.com/v14');`)
676
675
  }
677
676
 
678
677
  fetchStmt.write(arg.name);
679
- if (totalParams > 1 && i !== totalParams) {
678
+ if (i !== totalParams - 1) {
680
679
  fetchStmt.write(', ');
681
680
  }
682
681
  });
@@ -698,7 +697,7 @@ sdk.server('https://eu.api.example.com/v14');`)
698
697
  { ...parameters.metadata, hasQuestionToken: false },
699
698
  ],
700
699
  returnType,
701
- docs: Object.keys(docblock).length ? [docblock] : null,
700
+ docs: Object.keys(docblock).length ? [docblock] : undefined,
702
701
  });
703
702
 
704
703
  // Create an overload that just has a single `metadata` parameter.
@@ -711,7 +710,7 @@ sdk.server('https://eu.api.example.com/v14');`)
711
710
  // our `metadata` parameter is actually required for this operation this is the only way we're
712
711
  // able to have an optional `body` parameter be present before `metadata`.
713
712
  //
714
- // Thankfully our core fetch work in `api/dist/core` is able to do the proper determination to
713
+ // Thankfully our core fetch work in `api.core` is able to do the proper determination to
715
714
  // see if what the user is supplying is `metadata` or `body` content when they supply one or
716
715
  // both.
717
716
  operationIdAccessor.addParameters([
@@ -739,13 +738,13 @@ sdk.server('https://eu.api.example.com/v14');`)
739
738
  */
740
739
  loadOperationsAndMethods() {
741
740
  const operations: Record</* operationId */ string, OperationTypeHousing> = {};
742
- const methods = new Set();
741
+ const methods = new Set<HttpMethods>();
743
742
 
744
743
  // Prepare all of the schemas that we need to process for every operation within this API
745
744
  // definition.
746
745
  Object.entries(this.spec.getPaths()).forEach(([, ops]) => {
747
- Object.entries(ops).forEach(([method, operation]: [HttpMethods, Operation]) => {
748
- methods.add(method);
746
+ Object.entries(ops).forEach(([method, operation]: [string, Operation]) => {
747
+ methods.add(method as HttpMethods);
749
748
 
750
749
  const operationId = operation.getOperationId({
751
750
  // This `camelCase` option will clean up any weird characters that might be present in
@@ -786,7 +785,7 @@ sdk.server('https://eu.api.example.com/v14');`)
786
785
  transformer: (s: SchemaObject) => {
787
786
  // As our schemas are dereferenced in the `oas` library we don't want to pollute our
788
787
  // codegen'd schemas file with duplicate schemas.
789
- if ('x-readme-ref-name' in s) {
788
+ if ('x-readme-ref-name' in s && typeof s['x-readme-ref-name'] !== 'undefined') {
790
789
  const typeName = generateTypeName(s['x-readme-ref-name']);
791
790
  this.addSchemaToExport(s, typeName, typeName);
792
791
 
@@ -806,7 +805,7 @@ sdk.server('https://eu.api.example.com/v14');`)
806
805
  .reduce((prev, next) => Object.assign(prev, next));
807
806
 
808
807
  return Object.entries(res)
809
- .map(([paramType, schema]: [string, string | unknown]) => {
808
+ .map(([paramType, schema]: [string, string | SchemaObject]) => {
810
809
  let typeName;
811
810
 
812
811
  if (typeof schema === 'string' && schema.startsWith('::convert::')) {
@@ -815,7 +814,7 @@ sdk.server('https://eu.api.example.com/v14');`)
815
814
  typeName = schema.replace('::convert::', '');
816
815
  } else {
817
816
  typeName = generateTypeName(operationId, paramType, 'param');
818
- this.addSchemaToExport(schema, typeName, `${generateTypeName(operationId)}.${paramType}`);
817
+ this.addSchemaToExport(schema as SchemaObject, typeName, `${generateTypeName(operationId)}.${paramType}`);
819
818
  }
820
819
 
821
820
  return {
@@ -844,7 +843,7 @@ sdk.server('https://eu.api.example.com/v14');`)
844
843
  transformer: (s: SchemaObject) => {
845
844
  // As our schemas are dereferenced in the `oas` library we don't want to pollute our
846
845
  // codegen'd schemas file with duplicate schemas.
847
- if ('x-readme-ref-name' in s) {
846
+ if ('x-readme-ref-name' in s && typeof s['x-readme-ref-name'] !== 'undefined') {
848
847
  const typeName = generateTypeName(s['x-readme-ref-name']);
849
848
  this.addSchemaToExport(s, typeName, `${typeName}`);
850
849
 
@@ -900,7 +899,7 @@ sdk.server('https://eu.api.example.com/v14');`)
900
899
  * Add a given schema into our schema dataset that we'll be be exporting as types.
901
900
  *
902
901
  */
903
- addSchemaToExport(schema: any, typeName: string, pointer: string) {
902
+ addSchemaToExport(schema: SchemaObject, typeName: string, pointer: string) {
904
903
  if (this.types.has(typeName)) {
905
904
  return;
906
905
  }
@@ -5,8 +5,8 @@ import figures from 'figures';
5
5
  import Oas from 'oas';
6
6
  import ora from 'ora';
7
7
 
8
- import Fetcher from '../../fetcher';
9
8
  import codegen from '../codegen';
9
+ import Fetcher from '../fetcher';
10
10
  import promptTerminal from '../lib/prompt';
11
11
  import logger from '../logger';
12
12
  import Storage from '../storage';
@@ -24,7 +24,7 @@ cmd
24
24
  'js-cjs',
25
25
  'js-esm',
26
26
  'ts',
27
- ])
27
+ ]),
28
28
  )
29
29
  .addOption(new Option('-y, --yes', 'Automatically answer "yes" to any prompts printed'))
30
30
  .action(async (uri: string, options: { identifier?: string; lang: string; yes?: boolean }) => {
@@ -188,7 +188,7 @@ cmd
188
188
  Examples:
189
189
  $ api install @developers/v2.0#nysezql0wwo236
190
190
  $ api install https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore-simple.json
191
- $ api install ./petstore.json`
191
+ $ api install ./petstore.json`,
192
192
  );
193
193
 
194
194
  export default cmd;
package/src/fetcher.ts CHANGED
@@ -1,10 +1,9 @@
1
1
  import type { OASDocument } from 'oas/dist/rmoas.types';
2
2
 
3
- import fs from 'fs';
4
- import path from 'path';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
5
 
6
6
  import OpenAPIParser from '@readme/openapi-parser';
7
- import 'isomorphic-fetch';
8
7
  import yaml from 'js-yaml';
9
8
 
10
9
  export default class Fetcher {
@@ -14,7 +13,6 @@ export default class Fetcher {
14
13
  * @example @petstore/v1.0#n6kvf10vakpemvplx
15
14
  * @example @petstore#n6kvf10vakpemvplx
16
15
  */
17
- // eslint-disable-next-line unicorn/no-unsafe-regex
18
16
  static registryUUIDRegex = /^@(?<project>[a-zA-Z0-9-_]+)(\/?(?<version>.+))?#(?<uuid>[a-z0-9]+)$/;
19
17
 
20
18
  constructor(uri: string | OASDocument) {
@@ -53,13 +51,13 @@ export default class Fetcher {
53
51
  return undefined;
54
52
  }
55
53
 
56
- return matches.groups.project;
54
+ return matches.groups?.project;
57
55
  }
58
56
 
59
57
  async load() {
60
58
  if (typeof this.uri !== 'string') {
61
59
  throw new TypeError(
62
- "Something disastrous occurred and a non-string URI was supplied to the Fetcher library. This shouldn't have happened!"
60
+ "Something disastrous occurred and a non-string URI was supplied to the Fetcher library. This shouldn't have happened!",
63
61
  );
64
62
  }
65
63
 
@@ -103,7 +101,7 @@ export default class Fetcher {
103
101
 
104
102
  if (!fs.existsSync(file)) {
105
103
  throw new Error(
106
- `Sorry, we were unable to load an API definition from ${file}. Please either supply a URL or a path on your filesystem.`
104
+ `Sorry, we were unable to load an API definition from ${file}. Please either supply a URL or a path on your filesystem.`,
107
105
  );
108
106
  }
109
107
 
@@ -116,7 +114,7 @@ export default class Fetcher {
116
114
  });
117
115
  }
118
116
 
119
- static validate(json: any) {
117
+ static validate(json: OASDocument) {
120
118
  if (json.swagger) {
121
119
  throw new Error('Sorry, this module only supports OpenAPI definitions.');
122
120
  }
@@ -9,7 +9,7 @@ import prompts from 'prompts';
9
9
  */
10
10
  export default async function promptTerminal<T extends string = string>(
11
11
  question: prompts.PromptObject<T>,
12
- options?: prompts.Options
12
+ options?: prompts.Options,
13
13
  ) {
14
14
  const enableTerminalCursor = () => {
15
15
  process.stdout.write('\x1B[?25h');
@@ -1,3 +1,3 @@
1
1
  // This file is automatically updated by the build script.
2
2
  export const PACKAGE_NAME = 'api';
3
- export const PACKAGE_VERSION = '6.1.0';
3
+ export const PACKAGE_VERSION = '7.0.0-alpha.0';
@@ -1,14 +1,14 @@
1
1
  import type { OASDocument } from 'oas/dist/rmoas.types';
2
2
 
3
- import fs from 'fs';
4
- import path from 'path';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
5
 
6
6
  import makeDir from 'make-dir';
7
7
  import ssri from 'ssri';
8
8
  import validateNPMPackageName from 'validate-npm-package-name';
9
9
 
10
- import Fetcher from '../fetcher';
11
- import { PACKAGE_VERSION } from '../packageInfo';
10
+ import Fetcher from './fetcher';
11
+ import { PACKAGE_VERSION } from './packageInfo';
12
12
 
13
13
  export default class Storage {
14
14
  static dir: string;
@@ -21,7 +21,7 @@ export default class Storage {
21
21
  */
22
22
  source: string;
23
23
 
24
- identifier: string;
24
+ identifier!: string;
25
25
 
26
26
  fetcher: Fetcher;
27
27
 
@@ -31,7 +31,9 @@ export default class Storage {
31
31
  this.fetcher = new Fetcher(source);
32
32
 
33
33
  this.source = source;
34
- this.identifier = identifier;
34
+ if (identifier) {
35
+ this.identifier = identifier;
36
+ }
35
37
 
36
38
  // This should default to false so we have awareness if we've looked at the lockfile yet.
37
39
  Storage.lockfile = false;
@@ -116,7 +118,9 @@ export default class Storage {
116
118
  if (!isValidForNPM.validForNewPackages) {
117
119
  // `prompts` doesn't support surfacing multiple errors in a `validate` call so we can only
118
120
  // surface the first to the user.
119
- throw new Error(`Identifier cannot be used for an NPM package: ${isValidForNPM.errors[0]}`);
121
+ throw new Error(
122
+ `Identifier cannot be used for an NPM package: ${isValidForNPM?.errors?.[0] || '[error unavailable]'}`,
123
+ );
120
124
  }
121
125
 
122
126
  return true;
@@ -269,7 +273,7 @@ export default class Storage {
269
273
  }
270
274
  }
271
275
 
272
- export interface Lockfile {
276
+ interface Lockfile {
273
277
  apis: LockfileAPI[];
274
278
 
275
279
  /**
@@ -279,7 +283,7 @@ export interface Lockfile {
279
283
  version: '1.0';
280
284
  }
281
285
 
282
- export interface LockfileAPI {
286
+ interface LockfileAPI {
283
287
  /**
284
288
  * A unique identifier of the API. This'll be used to do requires on `@api/<identifier>` and also
285
289
  * where the SDK code will be located in `.api/apis/<identifier>`.