api 7.0.0-beta.2 → 7.0.0-beta.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/bin.js +6 -1
- package/dist/bin.js.map +1 -1
- package/dist/codegen/codegenerator.d.ts +35 -0
- package/dist/codegen/codegenerator.d.ts.map +1 -1
- package/dist/codegen/codegenerator.js +66 -0
- package/dist/codegen/codegenerator.js.map +1 -1
- package/dist/codegen/languages/typescript/index.d.ts +26 -4
- package/dist/codegen/languages/typescript/index.d.ts.map +1 -1
- package/dist/codegen/languages/typescript/index.js +181 -54
- package/dist/codegen/languages/typescript/index.js.map +1 -1
- package/dist/commands/install.d.ts.map +1 -1
- package/dist/commands/install.js +66 -54
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/uninstall.d.ts.map +1 -1
- package/dist/commands/uninstall.js +7 -10
- package/dist/commands/uninstall.js.map +1 -1
- package/dist/fetcher.d.ts +1 -1
- package/dist/fetcher.d.ts.map +1 -1
- package/dist/lib/suggestedOperations.d.ts +31 -0
- package/dist/lib/suggestedOperations.d.ts.map +1 -0
- package/dist/lib/suggestedOperations.js +108 -0
- package/dist/lib/suggestedOperations.js.map +1 -0
- package/dist/lockfileSchema.d.ts +1 -1
- package/dist/lockfileSchema.d.ts.map +1 -1
- package/dist/logger.d.ts +2 -0
- package/dist/logger.d.ts.map +1 -1
- package/dist/logger.js +5 -1
- package/dist/logger.js.map +1 -1
- package/dist/packageInfo.d.ts +1 -1
- package/dist/packageInfo.js +1 -1
- package/dist/storage.d.ts +3 -1
- package/dist/storage.d.ts.map +1 -1
- package/dist/storage.js +11 -3
- package/dist/storage.js.map +1 -1
- package/legacy-require-handler.cjs +29 -0
- package/legacy-require-handler.d.cts +2 -0
- package/package.json +17 -9
package/dist/bin.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { Command } from 'commander';
|
|
2
2
|
import commands from './commands/index.js';
|
|
3
|
+
import logger from './logger.js';
|
|
3
4
|
import * as pkg from './packageInfo.js';
|
|
4
5
|
(async () => {
|
|
5
6
|
const program = new Command();
|
|
@@ -13,6 +14,10 @@ import * as pkg from './packageInfo.js';
|
|
|
13
14
|
Object.entries(commands).forEach(([, cmd]) => {
|
|
14
15
|
program.addCommand(cmd);
|
|
15
16
|
});
|
|
16
|
-
await program.parseAsync(process.argv)
|
|
17
|
+
await program.parseAsync(process.argv).catch(err => {
|
|
18
|
+
if (err.message)
|
|
19
|
+
logger(err.message, true);
|
|
20
|
+
process.exit(1);
|
|
21
|
+
});
|
|
17
22
|
})();
|
|
18
23
|
//# sourceMappingURL=bin.js.map
|
package/dist/bin.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAExC,CAAC,KAAK,IAAI,EAAE;IACV,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC/B,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAErC;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAoB,EAAE,EAAE;QAC9D,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;
|
|
1
|
+
{"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAEpC,OAAO,QAAQ,MAAM,qBAAqB,CAAC;AAC3C,OAAO,MAAM,MAAM,aAAa,CAAC;AACjC,OAAO,KAAK,GAAG,MAAM,kBAAkB,CAAC;AAExC,CAAC,KAAK,IAAI,EAAE;IACV,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAC9B,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,YAAY,CAAC,CAAC;IAC/B,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IAErC;;;;OAIG;IACH,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,GAAG,CAAoB,EAAE,EAAE;QAC9D,OAAO,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC,CAAC,CAAC;IAEH,MAAM,OAAO,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE;QACjD,IAAI,GAAG,CAAC,OAAO;YAAE,MAAM,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,EAAE,CAAC"}
|
|
@@ -2,16 +2,50 @@ import type { InstallerOptions } from './factory.js';
|
|
|
2
2
|
import type Storage from '../storage.js';
|
|
3
3
|
import type Oas from 'oas';
|
|
4
4
|
export default abstract class CodeGenerator {
|
|
5
|
+
/** The associated API definition */
|
|
5
6
|
spec: Oas;
|
|
7
|
+
/**
|
|
8
|
+
* The path to the API definion (might be a local path, a URL, or an API registry identifier)
|
|
9
|
+
* @example https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore-simple.json
|
|
10
|
+
* @example @petstore/v1.0#n6kvf10vakpemvplx
|
|
11
|
+
* @example ./petstore.json
|
|
12
|
+
*/
|
|
6
13
|
specPath: string;
|
|
14
|
+
/**
|
|
15
|
+
* The user-specified identifier for the SDK,
|
|
16
|
+
* used as the directory name in the `.api/apis` directory
|
|
17
|
+
* where the SDK source code is located.
|
|
18
|
+
*/
|
|
7
19
|
identifier: string;
|
|
20
|
+
/** The user agent which is set for all outgoing fetch requests */
|
|
8
21
|
userAgent: string;
|
|
22
|
+
/**
|
|
23
|
+
* The license associated with the SDK.
|
|
24
|
+
* This is extrapolated from the API definition file.
|
|
25
|
+
*/
|
|
26
|
+
spdxLicense?: string;
|
|
27
|
+
/**
|
|
28
|
+
* Contact info for the API and/or SDK author in case users need support.
|
|
29
|
+
* This is extrapolated from the API definition file.
|
|
30
|
+
*/
|
|
31
|
+
apiContact: {
|
|
32
|
+
name?: string;
|
|
33
|
+
url?: string;
|
|
34
|
+
};
|
|
35
|
+
/**
|
|
36
|
+
* An object containing any downstream packages that are required
|
|
37
|
+
* for building/executing the SDK.
|
|
38
|
+
*/
|
|
9
39
|
requiredPackages: Record<string, {
|
|
10
40
|
dependencyType: 'production' | 'development';
|
|
11
41
|
reason: string;
|
|
12
42
|
url?: string;
|
|
13
43
|
version: string;
|
|
14
44
|
}>;
|
|
45
|
+
/**
|
|
46
|
+
* An example code snippet that a user can run to get started with the SDK.
|
|
47
|
+
*/
|
|
48
|
+
exampleCodeSnippet?: string | false;
|
|
15
49
|
constructor(spec: Oas, specPath: string, identifier: string);
|
|
16
50
|
abstract generate(): Promise<Record<string, string>>;
|
|
17
51
|
abstract install(storage: Storage, opts?: InstallerOptions): Promise<void>;
|
|
@@ -24,6 +58,7 @@ export default abstract class CodeGenerator {
|
|
|
24
58
|
*/
|
|
25
59
|
static uninstall(storage: Storage, opts?: InstallerOptions): Promise<void>;
|
|
26
60
|
abstract compile(storage: Storage, opts?: InstallerOptions): Promise<void>;
|
|
61
|
+
abstract getExampleCodeSnippet(): Promise<string | false>;
|
|
27
62
|
hasRequiredPackages(): boolean;
|
|
28
63
|
}
|
|
29
64
|
//# sourceMappingURL=codegenerator.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegenerator.d.ts","sourceRoot":"","sources":["../../src/codegen/codegenerator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,OAAO,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;
|
|
1
|
+
{"version":3,"file":"codegenerator.d.ts","sourceRoot":"","sources":["../../src/codegen/codegenerator.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,KAAK,OAAO,MAAM,eAAe,CAAC;AACzC,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAO3B,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa;IACzC,oCAAoC;IACpC,IAAI,EAAE,GAAG,CAAC;IAEV;;;;;OAKG;IACH,QAAQ,EAAE,MAAM,CAAC;IAEjB;;;;OAIG;IACH,UAAU,EAAE,MAAM,CAAC;IAEnB,kEAAkE;IAClE,SAAS,EAAE,MAAM,CAAC;IAElB;;;OAGG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC;IAErB;;;OAGG;IACH,UAAU,EAAE;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,GAAG,CAAC,EAAE,MAAM,CAAA;KAAE,CAAM;IAEjD;;;OAGG;IACH,gBAAgB,EAAG,MAAM,CACvB,MAAM,EACN;QACE,cAAc,EAAE,YAAY,GAAG,aAAa,CAAC;QAC7C,MAAM,EAAE,MAAM,CAAC;QACf,GAAG,CAAC,EAAE,MAAM,CAAC;QACb,OAAO,EAAE,MAAM,CAAC;KACjB,CACF,CAAC;IAEF;;OAEG;IACH,kBAAkB,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;gBAExB,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAgE3D,QAAQ,CAAC,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEpD,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1E;;;;;;OAMG;WAEU,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAIhF,QAAQ,CAAC,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAE1E,QAAQ,CAAC,qBAAqB,IAAI,OAAO,CAAC,MAAM,GAAG,KAAK,CAAC;IAEzD,mBAAmB;CAGpB"}
|
|
@@ -1,10 +1,42 @@
|
|
|
1
|
+
import { findLicense } from 'license';
|
|
1
2
|
import { PACKAGE_NAME, PACKAGE_VERSION } from '../packageInfo.js';
|
|
2
3
|
export default class CodeGenerator {
|
|
4
|
+
/** The associated API definition */
|
|
3
5
|
spec;
|
|
6
|
+
/**
|
|
7
|
+
* The path to the API definion (might be a local path, a URL, or an API registry identifier)
|
|
8
|
+
* @example https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore-simple.json
|
|
9
|
+
* @example @petstore/v1.0#n6kvf10vakpemvplx
|
|
10
|
+
* @example ./petstore.json
|
|
11
|
+
*/
|
|
4
12
|
specPath;
|
|
13
|
+
/**
|
|
14
|
+
* The user-specified identifier for the SDK,
|
|
15
|
+
* used as the directory name in the `.api/apis` directory
|
|
16
|
+
* where the SDK source code is located.
|
|
17
|
+
*/
|
|
5
18
|
identifier;
|
|
19
|
+
/** The user agent which is set for all outgoing fetch requests */
|
|
6
20
|
userAgent;
|
|
21
|
+
/**
|
|
22
|
+
* The license associated with the SDK.
|
|
23
|
+
* This is extrapolated from the API definition file.
|
|
24
|
+
*/
|
|
25
|
+
spdxLicense;
|
|
26
|
+
/**
|
|
27
|
+
* Contact info for the API and/or SDK author in case users need support.
|
|
28
|
+
* This is extrapolated from the API definition file.
|
|
29
|
+
*/
|
|
30
|
+
apiContact = {};
|
|
31
|
+
/**
|
|
32
|
+
* An object containing any downstream packages that are required
|
|
33
|
+
* for building/executing the SDK.
|
|
34
|
+
*/
|
|
7
35
|
requiredPackages;
|
|
36
|
+
/**
|
|
37
|
+
* An example code snippet that a user can run to get started with the SDK.
|
|
38
|
+
*/
|
|
39
|
+
exampleCodeSnippet;
|
|
8
40
|
constructor(spec, specPath, identifier) {
|
|
9
41
|
this.spec = spec;
|
|
10
42
|
this.specPath = specPath;
|
|
@@ -27,6 +59,40 @@ export default class CodeGenerator {
|
|
|
27
59
|
if (JSON.stringify(spec.api).includes('"$ref":"#/')) {
|
|
28
60
|
throw new Error('Sorry, this library does not yet support generating an SDK for an OpenAPI definition that contains circular references.');
|
|
29
61
|
}
|
|
62
|
+
const infoObject = this.spec.api.info;
|
|
63
|
+
if (infoObject?.license?.name || infoObject?.license?.identifier) {
|
|
64
|
+
let spdxLicense;
|
|
65
|
+
if (infoObject?.license?.identifier) {
|
|
66
|
+
spdxLicense = infoObject?.license?.identifier;
|
|
67
|
+
}
|
|
68
|
+
else {
|
|
69
|
+
// Though `name` is required by the OpenAPI specification but most people seem to use `name`
|
|
70
|
+
// instead `identifier` for their licensing identifier so if they've done this we should
|
|
71
|
+
// try to make the license name recognizable by the `license` package. For example this'll
|
|
72
|
+
// change "Apache 2.0" to the SPDX-recognized "Apache-2.0".
|
|
73
|
+
spdxLicense = infoObject?.license?.name.replace(/ /g, '-');
|
|
74
|
+
}
|
|
75
|
+
// If the license they've got has too many matches we shouldn't try to pick a license because
|
|
76
|
+
// we'll run the risk of licensing it under a license they didn't intend.
|
|
77
|
+
if (findLicense(spdxLicense).length === 1) {
|
|
78
|
+
this.spdxLicense = spdxLicense;
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
if (infoObject?.contact) {
|
|
82
|
+
if (infoObject.contact?.name || infoObject.contact?.email) {
|
|
83
|
+
if (infoObject.contact?.name && infoObject.contact?.email) {
|
|
84
|
+
this.apiContact.name = `${infoObject.contact.name} <${infoObject.contact.email}>`;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
this.apiContact.name = infoObject.contact.email
|
|
88
|
+
? `<${infoObject.contact.email}>`
|
|
89
|
+
: infoObject.contact.name ?? undefined;
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
if (infoObject.contact?.url) {
|
|
93
|
+
this.apiContact.url = infoObject.contact.url;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
30
96
|
}
|
|
31
97
|
/**
|
|
32
98
|
* It would be better if this were an abstract function but TS/JS doesn't have support for that so
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"codegenerator.js","sourceRoot":"","sources":["../../src/codegen/codegenerator.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"codegenerator.js","sourceRoot":"","sources":["../../src/codegen/codegenerator.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InstallerOptions } from '../../factory.js';
|
|
2
2
|
import type Oas from 'oas';
|
|
3
|
-
import type { ClassDeclaration } from 'ts-morph';
|
|
3
|
+
import type { ClassDeclaration, SourceFile } from 'ts-morph';
|
|
4
4
|
import { Project } from 'ts-morph';
|
|
5
5
|
import Storage from '../../../storage.js';
|
|
6
6
|
import CodeGenerator from '../../codegenerator.js';
|
|
@@ -30,26 +30,48 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
30
30
|
generate(): Promise<{
|
|
31
31
|
[x: string]: string;
|
|
32
32
|
}>;
|
|
33
|
+
getExampleCodeSnippet(): Promise<string | false>;
|
|
33
34
|
/**
|
|
34
35
|
* Create our main SDK source file.
|
|
35
36
|
*
|
|
36
37
|
*/
|
|
37
38
|
private createSDKSource;
|
|
39
|
+
/**
|
|
40
|
+
* Create an IIFE export of our SDK in the SDK source file so users can do
|
|
41
|
+
* `import sdk from '<package>'` and have a ready-to-go instance of their SDK -- eliminating them
|
|
42
|
+
* having to create an instance with `new SDK()`.
|
|
43
|
+
*
|
|
44
|
+
* This will also fill our a JSDoc heading on the IIFE we're creating based on various pieces of
|
|
45
|
+
* data that may be present in the OpenAPI definition `info` object.
|
|
46
|
+
*
|
|
47
|
+
* Additionally if a license in `info.license` is recognized by the SPDX we'll also create a
|
|
48
|
+
* `LICENSE` file in for their generated SDK. We're only supporting SPDX-recognized licenses for
|
|
49
|
+
* this because we otherwise have no idea what the license represents and we should be extremely
|
|
50
|
+
* cautious around assuming intent with software licensing.
|
|
51
|
+
*
|
|
52
|
+
* @see {@link https://spdx.org/licenses/}
|
|
53
|
+
*/
|
|
54
|
+
createSDKExport(sourceFile: SourceFile): SourceFile;
|
|
55
|
+
/**
|
|
56
|
+
* Creates a `.gitignore` file to prevent the `dist/` directory from being tracked.
|
|
57
|
+
*
|
|
58
|
+
*/
|
|
59
|
+
createGitIgnore(): SourceFile;
|
|
38
60
|
/**
|
|
39
61
|
* Create the `tsconfig.json` file that will allow this SDK to be compiled for use.
|
|
40
62
|
*
|
|
41
63
|
*/
|
|
42
|
-
createTSConfig():
|
|
64
|
+
createTSConfig(): SourceFile;
|
|
43
65
|
/**
|
|
44
66
|
* Create the `package.json` file that will ultimately make this SDK available to use.
|
|
45
67
|
*
|
|
46
68
|
*/
|
|
47
|
-
createPackageJSON():
|
|
69
|
+
createPackageJSON(): SourceFile;
|
|
48
70
|
/**
|
|
49
71
|
* Create a placeholder `README.md` file in the repository, with information on how to use/administer the SDK.
|
|
50
72
|
*
|
|
51
73
|
*/
|
|
52
|
-
createREADME():
|
|
74
|
+
createREADME(): Promise<SourceFile>;
|
|
53
75
|
/**
|
|
54
76
|
* Create our main schemas file. This is where all of the JSON Schema that our TypeScript typing
|
|
55
77
|
* infrastructure sources its data from. Without this there are no types.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/codegen/languages/typescript/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/codegen/languages/typescript/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAK3B,OAAO,KAAK,EACV,gBAAgB,EAMhB,UAAU,EACX,MAAM,UAAU,CAAC;AAWlB,OAAO,EAAmB,OAAO,EAAoD,MAAM,UAAU,CAAC;AAKtG,OAAO,OAAO,MAAM,qBAAqB,CAAC;AAC1C,OAAO,aAAa,MAAM,wBAAwB,CAAC;AAiDnD,MAAM,CAAC,OAAO,OAAO,WAAY,SAAQ,aAAa;;IACpD,OAAO,EAAE,OAAO,CAAC;IAEjB,KAAK,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAE3B,GAAG,EAAG,gBAAgB,CAAC;IAEvB,OAAO,EAAE,MAAM,CACb,MAAM,EAEJ;QACE,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,QAAQ,CAAC,EAAE,OAAO,CAAC;QACnB,QAAQ,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACpC,GAED,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAC1B,CAAC;IAEF,4BAA4B,UAAS;gBAEzB,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IAiDrD,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;WA0B9D,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IASpF;;;OAGG;IAEG,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAc3E;;;OAGG;IACG,QAAQ;;;IAsDR,qBAAqB;IAiB3B;;;OAGG;IACH,OAAO,CAAC,eAAe;IAgIvB;;;;;;;;;;;;;;OAcG;IACH,eAAe,CAAC,UAAU,EAAE,UAAU;IA4GtC;;;OAGG;IACH,eAAe;IAYf;;;OAGG;IACH,cAAc;IAmBd;;;OAGG;IACH,iBAAiB;IA+EjB;;;OAGG;IACG,YAAY;IAsClB;;;;OAIG;IACH,OAAO,CAAC,iBAAiB;IAgEzB;;;;;;OAMG;IACH,OAAO,CAAC,eAAe;IAevB;;;OAGG;IACH,OAAO,CAAC,uBAAuB;IAuM/B;;;;;OAKG;IACH,OAAO,CAAC,wBAAwB;IAoChC;;;;OAIG;IACH,OAAO,CAAC,iCAAiC;IAiDzC;;;OAGG;IACH,OAAO,CAAC,gCAAgC;IAiExC;;;OAGG;IACH,OAAO,CAAC,iBAAiB;CAsB1B"}
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
2
|
import corePkg from '@readme/api-core/package.json' assert { type: 'json' };
|
|
3
3
|
import { execa } from 'execa';
|
|
4
|
+
import { getLicense } from 'license';
|
|
4
5
|
import setWith from 'lodash.setwith';
|
|
5
6
|
import semver from 'semver';
|
|
6
7
|
import { IndentationText, Project, QuoteKind, ScriptTarget, VariableDeclarationKind } from 'ts-morph';
|
|
8
|
+
import { buildCodeSnippetForOperation, getSuggestedOperation } from '../../../lib/suggestedOperations.js';
|
|
7
9
|
import logger from '../../../logger.js';
|
|
8
10
|
import { PACKAGE_VERSION } from '../../../packageInfo.js';
|
|
9
11
|
import Storage from '../../../storage.js';
|
|
@@ -23,6 +25,19 @@ import { docblockEscape, generateTypeName, wordWrap } from './util.js';
|
|
|
23
25
|
*/
|
|
24
26
|
const REF_PLACEHOLDER = '::convert::';
|
|
25
27
|
const REF_PLACEHOLDER_REGEX = /"::convert::([a-zA-Z_$\\d]*)"/g;
|
|
28
|
+
function handleExecSuccess(res, opts = {}) {
|
|
29
|
+
if (opts.dryRun) {
|
|
30
|
+
(opts.logger ? opts.logger : logger)(res.command);
|
|
31
|
+
(opts.logger ? opts.logger : logger)(res.stdout);
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
function handleExecFailure(err, opts = {}) {
|
|
35
|
+
if (opts.dryRun) {
|
|
36
|
+
(opts.logger ? opts.logger : logger)(err.message);
|
|
37
|
+
return;
|
|
38
|
+
}
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
26
41
|
export default class TSGenerator extends CodeGenerator {
|
|
27
42
|
project;
|
|
28
43
|
types;
|
|
@@ -81,12 +96,7 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
81
96
|
// adding `@api/<sdk identifier>` as a dependency there so you can load it with
|
|
82
97
|
// `require('@api/<sdk identifier>)`.
|
|
83
98
|
return execa('npm', [...npmInstall, installDir].filter(Boolean))
|
|
84
|
-
.then(res =>
|
|
85
|
-
if (opts.dryRun) {
|
|
86
|
-
(opts.logger ? opts.logger : logger)(res.command);
|
|
87
|
-
(opts.logger ? opts.logger : logger)(res.stdout);
|
|
88
|
-
}
|
|
89
|
-
})
|
|
99
|
+
.then(res => handleExecSuccess(res, opts))
|
|
90
100
|
.catch(err => {
|
|
91
101
|
// If `npm install` throws this error it always happens **after** our dependencies have been
|
|
92
102
|
// installed and is an annoying quirk that sometimes occurs when installing a package within
|
|
@@ -96,26 +106,15 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
96
106
|
(opts.logger ? opts.logger : logger)("npm threw an error but we're ignoring it");
|
|
97
107
|
return;
|
|
98
108
|
}
|
|
99
|
-
|
|
100
|
-
(opts.logger ? opts.logger : logger)(err.message);
|
|
101
|
-
return;
|
|
102
|
-
}
|
|
103
|
-
throw err;
|
|
109
|
+
handleExecFailure(err, opts);
|
|
104
110
|
});
|
|
105
111
|
}
|
|
106
112
|
static async uninstall(storage, opts = {}) {
|
|
107
113
|
const pkgName = storage.getPackageName();
|
|
108
114
|
const args = ['uninstall', pkgName, opts.dryRun ? '--dry-run' : ''].filter(Boolean);
|
|
109
115
|
return execa('npm', args)
|
|
110
|
-
.then(res =>
|
|
111
|
-
|
|
112
|
-
(opts.logger ? opts.logger : logger)(res.command);
|
|
113
|
-
(opts.logger ? opts.logger : logger)(res.stdout);
|
|
114
|
-
}
|
|
115
|
-
})
|
|
116
|
-
.catch(err => {
|
|
117
|
-
throw err;
|
|
118
|
-
});
|
|
116
|
+
.then(res => handleExecSuccess(res, opts))
|
|
117
|
+
.catch(err => handleExecFailure(err, opts));
|
|
119
118
|
}
|
|
120
119
|
/**
|
|
121
120
|
* Compile the TS code we generated into JS for use in CJS and ESM environments.
|
|
@@ -124,22 +123,14 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
124
123
|
// eslint-disable-next-line class-methods-use-this
|
|
125
124
|
async compile(storage, opts = {}) {
|
|
126
125
|
const installDir = storage.getIdentifierStorageDir();
|
|
127
|
-
await execa('
|
|
126
|
+
await execa('npm', ['pkg', 'set', 'scripts.prepare=tsup'], { cwd: installDir })
|
|
127
|
+
.then(res => handleExecSuccess(res, opts))
|
|
128
|
+
.catch(err => handleExecFailure(err, opts));
|
|
129
|
+
await execa('npm', ['run', 'prepare'], {
|
|
128
130
|
cwd: installDir,
|
|
129
131
|
})
|
|
130
|
-
.then(res =>
|
|
131
|
-
|
|
132
|
-
(opts.logger ? opts.logger : logger)(res.command);
|
|
133
|
-
(opts.logger ? opts.logger : logger)(res.stdout);
|
|
134
|
-
}
|
|
135
|
-
})
|
|
136
|
-
.catch(err => {
|
|
137
|
-
if (opts.dryRun) {
|
|
138
|
-
(opts.logger ? opts.logger : logger)(err.message);
|
|
139
|
-
return;
|
|
140
|
-
}
|
|
141
|
-
throw err;
|
|
142
|
-
});
|
|
132
|
+
.then(res => handleExecSuccess(res, opts))
|
|
133
|
+
.catch(err => handleExecFailure(err, opts));
|
|
143
134
|
}
|
|
144
135
|
/**
|
|
145
136
|
* Generate the current OpenAPI definition into a TypeScript library.
|
|
@@ -148,9 +139,10 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
148
139
|
async generate() {
|
|
149
140
|
const srcDirectory = this.project.createDirectory('src');
|
|
150
141
|
const sdkSource = this.createSDKSource(srcDirectory);
|
|
142
|
+
this.createGitIgnore();
|
|
151
143
|
this.createPackageJSON();
|
|
152
144
|
this.createTSConfig();
|
|
153
|
-
this.createREADME();
|
|
145
|
+
await this.createREADME();
|
|
154
146
|
if (Object.keys(this.schemas).length) {
|
|
155
147
|
this.createSchemasFile(srcDirectory);
|
|
156
148
|
this.createTypesFile(srcDirectory);
|
|
@@ -159,7 +151,7 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
159
151
|
// If we don't have any schemas then we shouldn't import a `types` file that doesn't exist.
|
|
160
152
|
sdkSource
|
|
161
153
|
.getImportDeclarations()
|
|
162
|
-
.find(id => id.getText() === "import type * as types from './types';")
|
|
154
|
+
.find(id => id.getText() === "import type * as types from './types.js';")
|
|
163
155
|
?.remove();
|
|
164
156
|
}
|
|
165
157
|
// If this SDK doesn't use the `HTTPMethodRange` interface for handling `2XX` response status
|
|
@@ -193,6 +185,20 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
193
185
|
}),
|
|
194
186
|
].reduce((prev, next) => Object.assign(prev, next));
|
|
195
187
|
}
|
|
188
|
+
async getExampleCodeSnippet() {
|
|
189
|
+
// if we've already built the code snippet, return it instead of re-building it!
|
|
190
|
+
if (typeof this.exampleCodeSnippet !== 'undefined') {
|
|
191
|
+
return this.exampleCodeSnippet;
|
|
192
|
+
}
|
|
193
|
+
const operation = getSuggestedOperation(this.spec);
|
|
194
|
+
if (!operation) {
|
|
195
|
+
this.exampleCodeSnippet = false;
|
|
196
|
+
return false;
|
|
197
|
+
}
|
|
198
|
+
const snippet = await buildCodeSnippetForOperation(this.spec, operation, { identifier: this.identifier });
|
|
199
|
+
this.exampleCodeSnippet = snippet;
|
|
200
|
+
return snippet;
|
|
201
|
+
}
|
|
196
202
|
/**
|
|
197
203
|
* Create our main SDK source file.
|
|
198
204
|
*
|
|
@@ -202,7 +208,7 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
202
208
|
const sourceFile = sourceDirectory.createSourceFile('index.ts', '');
|
|
203
209
|
sourceFile.addImportDeclarations([
|
|
204
210
|
// This import will be automatically removed later if the SDK ends up not having any types.
|
|
205
|
-
{ defaultImport: 'type * as types', moduleSpecifier: './types' },
|
|
211
|
+
{ defaultImport: 'type * as types', moduleSpecifier: './types.js' },
|
|
206
212
|
{
|
|
207
213
|
// `HTTPMethodRange` will be conditionally removed later if it ends up not being used.
|
|
208
214
|
defaultImport: 'type { ConfigOptions, FetchResponse, HTTPMethodRange }',
|
|
@@ -211,7 +217,6 @@ export default class TSGenerator extends CodeGenerator {
|
|
|
211
217
|
{ defaultImport: 'APICore', moduleSpecifier: '@readme/api-core' },
|
|
212
218
|
{ defaultImport: 'definition', moduleSpecifier: this.specPath },
|
|
213
219
|
]);
|
|
214
|
-
// @todo add TOS, License, info.* to a docblock at the top of the SDK.
|
|
215
220
|
this.sdk = sourceFile.addClass({
|
|
216
221
|
name: 'SDK',
|
|
217
222
|
properties: [{ name: 'core', type: 'APICore' }],
|
|
@@ -305,9 +310,98 @@ sdk.server('https://eu.api.example.com/v14');`)),
|
|
|
305
310
|
Object.entries(operations).forEach(([operationId, data]) => {
|
|
306
311
|
this.createOperationAccessor(data.operation, operationId, data.types.params, data.types.responses);
|
|
307
312
|
});
|
|
308
|
-
|
|
313
|
+
this.createSDKExport(sourceFile);
|
|
314
|
+
return sourceFile;
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* Create an IIFE export of our SDK in the SDK source file so users can do
|
|
318
|
+
* `import sdk from '<package>'` and have a ready-to-go instance of their SDK -- eliminating them
|
|
319
|
+
* having to create an instance with `new SDK()`.
|
|
320
|
+
*
|
|
321
|
+
* This will also fill our a JSDoc heading on the IIFE we're creating based on various pieces of
|
|
322
|
+
* data that may be present in the OpenAPI definition `info` object.
|
|
323
|
+
*
|
|
324
|
+
* Additionally if a license in `info.license` is recognized by the SPDX we'll also create a
|
|
325
|
+
* `LICENSE` file in for their generated SDK. We're only supporting SPDX-recognized licenses for
|
|
326
|
+
* this because we otherwise have no idea what the license represents and we should be extremely
|
|
327
|
+
* cautious around assuming intent with software licensing.
|
|
328
|
+
*
|
|
329
|
+
* @see {@link https://spdx.org/licenses/}
|
|
330
|
+
*/
|
|
331
|
+
createSDKExport(sourceFile) {
|
|
332
|
+
let docblock = {};
|
|
333
|
+
// The OpenAPI 3.1 `info` object added some properties that aren't available in 3.0 but 3.1
|
|
334
|
+
// still contains everything that was available in 3.0 so to allow us to not have to do gross
|
|
335
|
+
// `as OpenAPIV3_1.InfoObject` typing everywhere we're just assuming that we have 3.1 object
|
|
336
|
+
// here.
|
|
337
|
+
const infoObject = this.spec.api.info;
|
|
338
|
+
if (infoObject?.title || infoObject?.description) {
|
|
339
|
+
docblock.description = writer => {
|
|
340
|
+
if (infoObject.title) {
|
|
341
|
+
writer.writeLine(docblockEscape(wordWrap(infoObject.title)));
|
|
342
|
+
}
|
|
343
|
+
if (infoObject.description) {
|
|
344
|
+
writer.conditionalNewLine(!!infoObject.title);
|
|
345
|
+
writer.writeLine(docblockEscape(wordWrap(infoObject.description)));
|
|
346
|
+
}
|
|
347
|
+
writer.newLineIfLastNot();
|
|
348
|
+
return writer;
|
|
349
|
+
};
|
|
350
|
+
}
|
|
351
|
+
if (this.apiContact.name) {
|
|
352
|
+
docblock = TSGenerator.#addTagToDocblock(docblock, {
|
|
353
|
+
tagName: 'author',
|
|
354
|
+
text: this.apiContact.name,
|
|
355
|
+
});
|
|
356
|
+
}
|
|
357
|
+
if (this.apiContact.url) {
|
|
358
|
+
docblock = TSGenerator.#addTagToDocblock(docblock, {
|
|
359
|
+
tagName: 'see',
|
|
360
|
+
text: `{@link ${this.apiContact.url}}`,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
if (infoObject?.termsOfService) {
|
|
364
|
+
docblock = TSGenerator.#addTagToDocblock(docblock, {
|
|
365
|
+
tagName: 'see',
|
|
366
|
+
text: `{@link ${infoObject.termsOfService} Terms of Service}`,
|
|
367
|
+
});
|
|
368
|
+
}
|
|
369
|
+
if (this.spdxLicense) {
|
|
370
|
+
docblock = TSGenerator.#addTagToDocblock(docblock, {
|
|
371
|
+
tagName: 'license',
|
|
372
|
+
text: this.spdxLicense,
|
|
373
|
+
});
|
|
374
|
+
// Some licenses like `Apache-2.0` have the year as `[yyyy]` but the `license` package only
|
|
375
|
+
// supports templating on `<templatekey>` so we need to fix this ourselves.
|
|
376
|
+
// https://github.com/Ovyerus/license/issues/12
|
|
377
|
+
const year = new Date().getFullYear().toString();
|
|
378
|
+
const license = getLicense(this.spdxLicense, {
|
|
379
|
+
year,
|
|
380
|
+
// `license` doesn't support empty strings so we need to fake it here
|
|
381
|
+
author: this.apiContact.name ?? ' ',
|
|
382
|
+
})
|
|
383
|
+
.replace(/<yyyy>/g, year)
|
|
384
|
+
.replace(/\[yyyy\]/g, year);
|
|
385
|
+
this.project.createSourceFile('LICENSE', license);
|
|
386
|
+
}
|
|
387
|
+
else if (infoObject?.license) {
|
|
388
|
+
// If they have a license but it's not recognized by the SPDX we should still surface it.
|
|
389
|
+
if (infoObject?.license?.name) {
|
|
390
|
+
docblock = TSGenerator.#addTagToDocblock(docblock, {
|
|
391
|
+
tagName: 'license',
|
|
392
|
+
text: infoObject.license.name,
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
if (infoObject.license?.url) {
|
|
396
|
+
docblock = TSGenerator.#addTagToDocblock(docblock, {
|
|
397
|
+
tagName: 'see',
|
|
398
|
+
text: `{@link ${infoObject.license.url}}`,
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
309
402
|
sourceFile.addVariableStatement({
|
|
310
403
|
declarationKind: VariableDeclarationKind.Const,
|
|
404
|
+
docs: Object.keys(docblock).length ? [docblock] : [],
|
|
311
405
|
declarations: [
|
|
312
406
|
{
|
|
313
407
|
name: 'createSDK',
|
|
@@ -329,6 +423,19 @@ sdk.server('https://eu.api.example.com/v14');`)),
|
|
|
329
423
|
});
|
|
330
424
|
return sourceFile;
|
|
331
425
|
}
|
|
426
|
+
/**
|
|
427
|
+
* Creates a `.gitignore` file to prevent the `dist/` directory from being tracked.
|
|
428
|
+
*
|
|
429
|
+
*/
|
|
430
|
+
createGitIgnore() {
|
|
431
|
+
const file = `# This file prevents the \`dist/\` directory from being tracked via git.
|
|
432
|
+
# This is recommended since the \`prepare\` npm script automatically
|
|
433
|
+
# regenerates the contents of the \`dist/\` directory as needed.
|
|
434
|
+
dist/
|
|
435
|
+
`;
|
|
436
|
+
const sourceFile = this.project.createSourceFile('.gitignore', file);
|
|
437
|
+
return sourceFile;
|
|
438
|
+
}
|
|
332
439
|
/**
|
|
333
440
|
* Create the `tsconfig.json` file that will allow this SDK to be compiled for use.
|
|
334
441
|
*
|
|
@@ -337,8 +444,11 @@ sdk.server('https://eu.api.example.com/v14');`)),
|
|
|
337
444
|
const sourceFile = this.project.createSourceFile('tsconfig.json', '');
|
|
338
445
|
const config = {
|
|
339
446
|
compilerOptions: {
|
|
340
|
-
|
|
447
|
+
esModuleInterop: true,
|
|
448
|
+
module: 'ESNext',
|
|
449
|
+
moduleResolution: 'Bundler',
|
|
341
450
|
resolveJsonModule: true,
|
|
451
|
+
strict: true,
|
|
342
452
|
},
|
|
343
453
|
include: ['./src/**/*'],
|
|
344
454
|
};
|
|
@@ -384,31 +494,37 @@ sdk.server('https://eu.api.example.com/v14');`)),
|
|
|
384
494
|
const pkg = {
|
|
385
495
|
name: `@api/${this.identifier}`,
|
|
386
496
|
version: pkgVersion.version,
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
497
|
+
type: 'module',
|
|
498
|
+
main: 'dist/index.cjs',
|
|
499
|
+
types: 'dist/index.d.cts',
|
|
500
|
+
module: 'dist/index.ts',
|
|
390
501
|
exports: {
|
|
391
502
|
'.': {
|
|
392
|
-
import: './dist/index.
|
|
393
|
-
require: './dist/index.
|
|
503
|
+
import: './dist/index.js',
|
|
504
|
+
require: './dist/index.cjs',
|
|
394
505
|
},
|
|
395
506
|
...(hasTypes
|
|
396
507
|
? {
|
|
397
508
|
'./types': {
|
|
398
|
-
import: './dist/types.
|
|
399
|
-
require: './dist/types.
|
|
509
|
+
import: './dist/types.js',
|
|
510
|
+
require: './dist/types.cjs',
|
|
400
511
|
},
|
|
401
512
|
}
|
|
402
513
|
: {}),
|
|
514
|
+
'./package.json': './package.json',
|
|
403
515
|
},
|
|
516
|
+
license: this.spdxLicense ?? '',
|
|
404
517
|
files: ['dist', 'openapi.json'],
|
|
405
518
|
scripts: {
|
|
406
|
-
|
|
519
|
+
lint: 'tsc --noEmit',
|
|
407
520
|
},
|
|
408
521
|
dependencies,
|
|
409
522
|
devDependencies,
|
|
410
523
|
tsup: tsupOptions,
|
|
411
524
|
};
|
|
525
|
+
if (!this.spdxLicense) {
|
|
526
|
+
delete pkg.license;
|
|
527
|
+
}
|
|
412
528
|
sourceFile.addStatements(JSON.stringify(pkg, null, 2));
|
|
413
529
|
return sourceFile;
|
|
414
530
|
}
|
|
@@ -416,16 +532,27 @@ sdk.server('https://eu.api.example.com/v14');`)),
|
|
|
416
532
|
* Create a placeholder `README.md` file in the repository, with information on how to use/administer the SDK.
|
|
417
533
|
*
|
|
418
534
|
*/
|
|
419
|
-
createREADME() {
|
|
535
|
+
async createREADME() {
|
|
420
536
|
let createdAt = new Date().toISOString();
|
|
421
537
|
const currentAPI = Storage.getLockfile().apis.find(api => api.identifier === this.identifier);
|
|
422
538
|
if (currentAPI)
|
|
423
539
|
createdAt = currentAPI.createdAt;
|
|
540
|
+
let exampleUsage = 'Add SDK setup information and usage examples here so your users get started in a jiffy! 🚀';
|
|
541
|
+
const exampleSnippet = await this.getExampleCodeSnippet();
|
|
542
|
+
if (exampleSnippet) {
|
|
543
|
+
exampleUsage = `
|
|
544
|
+
## Example Usage 🚀
|
|
545
|
+
|
|
546
|
+
\`\`\`js
|
|
547
|
+
${exampleSnippet}
|
|
548
|
+
\`\`\`
|
|
549
|
+
`.trim();
|
|
550
|
+
}
|
|
424
551
|
const file = `# \`@api/${this.identifier}\`
|
|
425
552
|
|
|
426
553
|
This SDK was autogenerated by the [\`api\` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 🦉
|
|
427
554
|
|
|
428
|
-
|
|
555
|
+
${exampleUsage}
|
|
429
556
|
|
|
430
557
|
<!---
|
|
431
558
|
|
|
@@ -454,7 +581,7 @@ Generated at ${createdAt}
|
|
|
454
581
|
// for these schemas into our main `schemas.ts` file.`
|
|
455
582
|
sourceFile.addImportDeclaration({
|
|
456
583
|
defaultImport: schemaName,
|
|
457
|
-
moduleSpecifier: `./schemas/${schemaName}`,
|
|
584
|
+
moduleSpecifier: `./schemas/${schemaName}.js`,
|
|
458
585
|
});
|
|
459
586
|
// Though we aren't using Prettier to make these generated SDKs look amazing we should at
|
|
460
587
|
// least make the schema files we generate not look like completely unreadable garbage.
|
|
@@ -470,7 +597,7 @@ Generated at ${createdAt}
|
|
|
470
597
|
// declaration for it.
|
|
471
598
|
schemaFile.addImportDeclaration({
|
|
472
599
|
defaultImport: ref,
|
|
473
|
-
moduleSpecifier: `./${ref}`,
|
|
600
|
+
moduleSpecifier: `./${ref}.js`,
|
|
474
601
|
});
|
|
475
602
|
});
|
|
476
603
|
}
|
|
@@ -506,8 +633,8 @@ Generated at ${createdAt}
|
|
|
506
633
|
createTypesFile(sourceDirectory) {
|
|
507
634
|
const sourceFile = sourceDirectory.createSourceFile('types.ts', '');
|
|
508
635
|
sourceFile.addImportDeclarations([
|
|
509
|
-
{ defaultImport: 'type { FromSchema }', moduleSpecifier: '@readme/api-core/
|
|
510
|
-
{ defaultImport: '* as schemas', moduleSpecifier: './schemas' },
|
|
636
|
+
{ defaultImport: 'type { FromSchema }', moduleSpecifier: '@readme/api-core/types' },
|
|
637
|
+
{ defaultImport: '* as schemas', moduleSpecifier: './schemas.js' },
|
|
511
638
|
]);
|
|
512
639
|
Array.from(new Map(Array.from(this.types.entries()).sort())).forEach(([typeName, typeExpression]) => {
|
|
513
640
|
sourceFile.addTypeAlias({ isExported: true, name: typeName, type: typeExpression });
|