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.
- package/LICENSE +1 -1
- package/README.md +0 -12
- package/package.json +18 -38
- package/src/bin.ts +1 -1
- package/src/{cli/codegen → codegen}/index.ts +1 -1
- package/src/{cli/codegen → codegen}/language.ts +4 -3
- package/src/{cli/codegen → codegen}/languages/typescript/util.ts +1 -10
- package/src/{cli/codegen → codegen}/languages/typescript.ts +40 -41
- package/src/{cli/commands → commands}/install.ts +3 -3
- package/src/fetcher.ts +6 -8
- package/src/{cli/lib → lib}/prompt.ts +1 -1
- package/src/packageInfo.ts +1 -1
- package/src/{cli/storage.ts → storage.ts} +13 -9
- package/tsconfig.json +3 -13
- package/dist/bin.d.ts +0 -1
- package/dist/bin.js +0 -91
- package/dist/cache.d.ts +0 -68
- package/dist/cache.js +0 -198
- package/dist/cli/codegen/index.d.ts +0 -4
- package/dist/cli/codegen/index.js +0 -23
- package/dist/cli/codegen/language.d.ts +0 -27
- package/dist/cli/codegen/language.js +0 -32
- package/dist/cli/codegen/languages/typescript/util.d.ts +0 -21
- package/dist/cli/codegen/languages/typescript/util.js +0 -185
- package/dist/cli/codegen/languages/typescript.d.ts +0 -111
- package/dist/cli/codegen/languages/typescript.js +0 -821
- package/dist/cli/commands/index.d.ts +0 -4
- package/dist/cli/commands/index.js +0 -9
- package/dist/cli/commands/install.d.ts +0 -3
- package/dist/cli/commands/install.js +0 -236
- package/dist/cli/lib/prompt.d.ts +0 -9
- package/dist/cli/lib/prompt.js +0 -81
- package/dist/cli/logger.d.ts +0 -1
- package/dist/cli/logger.js +0 -16
- package/dist/cli/storage.d.ts +0 -105
- package/dist/cli/storage.js +0 -277
- package/dist/core/errors/fetchError.d.ts +0 -12
- package/dist/core/errors/fetchError.js +0 -36
- package/dist/core/getJSONSchemaDefaults.d.ts +0 -14
- package/dist/core/getJSONSchemaDefaults.js +0 -61
- package/dist/core/index.d.ts +0 -40
- package/dist/core/index.js +0 -168
- package/dist/core/parseResponse.d.ts +0 -6
- package/dist/core/parseResponse.js +0 -71
- package/dist/core/prepareAuth.d.ts +0 -5
- package/dist/core/prepareAuth.js +0 -84
- package/dist/core/prepareParams.d.ts +0 -21
- package/dist/core/prepareParams.js +0 -422
- package/dist/core/prepareServer.d.ts +0 -10
- package/dist/core/prepareServer.js +0 -47
- package/dist/fetcher.d.ts +0 -54
- package/dist/fetcher.js +0 -165
- package/dist/index.d.ts +0 -6
- package/dist/index.js +0 -259
- package/dist/packageInfo.d.ts +0 -2
- package/dist/packageInfo.js +0 -6
- package/src/.sink.d.ts +0 -1
- package/src/cache.ts +0 -193
- package/src/core/errors/fetchError.ts +0 -31
- package/src/core/getJSONSchemaDefaults.ts +0 -74
- package/src/core/index.ts +0 -148
- package/src/core/parseResponse.ts +0 -26
- package/src/core/prepareAuth.ts +0 -109
- package/src/core/prepareParams.ts +0 -410
- package/src/core/prepareServer.ts +0 -48
- package/src/index.ts +0 -203
- package/src/typings.d.ts +0 -2
- /package/src/{cli/commands → commands}/index.ts +0 -0
- /package/src/{cli/logger.ts → logger.ts} +0 -0
package/LICENSE
CHANGED
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": "
|
|
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": "
|
|
16
|
-
"test:smoke": "
|
|
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": ">=
|
|
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": "^
|
|
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.
|
|
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
|
-
"@
|
|
76
|
-
"@
|
|
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/
|
|
86
|
-
"@types/
|
|
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
|
-
"
|
|
95
|
-
"
|
|
96
|
-
"
|
|
97
|
-
"
|
|
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,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 '
|
|
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
|
|
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
|
-
|
|
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,
|
|
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
|
-
|
|
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?:
|
|
65
|
-
metadata?:
|
|
66
|
-
response?: Record<string,
|
|
63
|
+
body?: unknown;
|
|
64
|
+
metadata?: unknown;
|
|
65
|
+
response?: Record<string, unknown>;
|
|
67
66
|
}
|
|
68
67
|
// Wholesale collection of `$ref` pointer types
|
|
69
|
-
| Record<string,
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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 =
|
|
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()]:
|
|
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)]:
|
|
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
|
|
303
|
+
moduleSpecifier: 'api.core',
|
|
305
304
|
},
|
|
306
305
|
{ defaultImport: 'Oas', moduleSpecifier: 'oas' },
|
|
307
|
-
{ defaultImport: 'APICore', moduleSpecifier: 'api
|
|
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
|
|
571
|
-
metadata
|
|
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 ?
|
|
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 (
|
|
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] :
|
|
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
|
|
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]: [
|
|
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 |
|
|
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:
|
|
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
|
|
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:
|
|
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');
|
package/src/packageInfo.ts
CHANGED
|
@@ -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 '
|
|
11
|
-
import { PACKAGE_VERSION } from '
|
|
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
|
|
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
|
-
|
|
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(
|
|
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
|
-
|
|
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
|
-
|
|
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>`.
|