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.
Files changed (37) hide show
  1. package/dist/bin.js +6 -1
  2. package/dist/bin.js.map +1 -1
  3. package/dist/codegen/codegenerator.d.ts +35 -0
  4. package/dist/codegen/codegenerator.d.ts.map +1 -1
  5. package/dist/codegen/codegenerator.js +66 -0
  6. package/dist/codegen/codegenerator.js.map +1 -1
  7. package/dist/codegen/languages/typescript/index.d.ts +26 -4
  8. package/dist/codegen/languages/typescript/index.d.ts.map +1 -1
  9. package/dist/codegen/languages/typescript/index.js +181 -54
  10. package/dist/codegen/languages/typescript/index.js.map +1 -1
  11. package/dist/commands/install.d.ts.map +1 -1
  12. package/dist/commands/install.js +66 -54
  13. package/dist/commands/install.js.map +1 -1
  14. package/dist/commands/uninstall.d.ts.map +1 -1
  15. package/dist/commands/uninstall.js +7 -10
  16. package/dist/commands/uninstall.js.map +1 -1
  17. package/dist/fetcher.d.ts +1 -1
  18. package/dist/fetcher.d.ts.map +1 -1
  19. package/dist/lib/suggestedOperations.d.ts +31 -0
  20. package/dist/lib/suggestedOperations.d.ts.map +1 -0
  21. package/dist/lib/suggestedOperations.js +108 -0
  22. package/dist/lib/suggestedOperations.js.map +1 -0
  23. package/dist/lockfileSchema.d.ts +1 -1
  24. package/dist/lockfileSchema.d.ts.map +1 -1
  25. package/dist/logger.d.ts +2 -0
  26. package/dist/logger.d.ts.map +1 -1
  27. package/dist/logger.js +5 -1
  28. package/dist/logger.js.map +1 -1
  29. package/dist/packageInfo.d.ts +1 -1
  30. package/dist/packageInfo.js +1 -1
  31. package/dist/storage.d.ts +3 -1
  32. package/dist/storage.d.ts.map +1 -1
  33. package/dist/storage.js +11 -3
  34. package/dist/storage.js.map +1 -1
  35. package/legacy-require-handler.cjs +29 -0
  36. package/legacy-require-handler.d.cts +2 -0
  37. 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;AACzC,CAAC,CAAC,EAAE,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;AAI3B,MAAM,CAAC,OAAO,CAAC,QAAQ,OAAO,aAAa;IACzC,IAAI,EAAE,GAAG,CAAC;IAEV,QAAQ,EAAE,MAAM,CAAC;IAEjB,UAAU,EAAE,MAAM,CAAC;IAEnB,SAAS,EAAE,MAAM,CAAC;IAElB,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;gBAEU,IAAI,EAAE,GAAG,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM;IA4B3D,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,mBAAmB;CAGpB"}
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":"AAIA,OAAO,EAAE,YAAY,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAElE,MAAM,CAAC,OAAO,OAAgB,aAAa;IACzC,IAAI,CAAM;IAEV,QAAQ,CAAS;IAEjB,UAAU,CAAS;IAEnB,SAAS,CAAS;IAElB,gBAAgB,CAQd;IAEF,YAAY,IAAS,EAAE,QAAgB,EAAE,UAAkB;QACzD,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,UAAU,GAAG,UAAU,CAAC;QAE7B,6FAA6F;QAC7F,4FAA4F;QAC5F,4CAA4C;QAC5C,MAAM,IAAI,GAAG,IAAI,CAAC,aAAa,EAAE,CAAC,IAAI,CAAC;QACvC,IAAI,CAAC,SAAS,GAAG,GAAG,UAAU,IAAI,IAAI,CAAC,OAAO,KAAK,YAAY,IAAI,eAAe,GAAG,CAAC;QAEtF;;;;;;;;;WASG;QACH,IAAI,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE;YACnD,MAAM,IAAI,KAAK,CACb,yHAAyH,CAC1H,CAAC;SACH;IACH,CAAC;IAMD;;;;;;OAMG;IACH,6DAA6D;IAC7D,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,OAAgB,EAAE,IAAuB;QAC9D,MAAM,IAAI,SAAS,CAAC,oEAAoE,CAAC,CAAC;IAC5F,CAAC;IAID,mBAAmB;QACjB,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC;IACrD,CAAC;CACF"}
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(): import("ts-morph").SourceFile;
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(): import("ts-morph").SourceFile;
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(): import("ts-morph").SourceFile;
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;AACzD,OAAO,KAAK,GAAG,MAAM,KAAK,CAAC;AAI3B,OAAO,KAAK,EACV,gBAAgB,EAMjB,MAAM,UAAU,CAAC;AAUlB,OAAO,EAAmB,OAAO,EAAoD,MAAM,UAAU,CAAC;AAItG,OAAO,OAAO,MAAM,qBAAqB,CAAC;AAC1C,OAAO,aAAa,MAAM,wBAAwB,CAAC;AAiCnD,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;WAoC9D,SAAS,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBpF;;;OAGG;IAEG,OAAO,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,GAAE,gBAAqB,GAAG,OAAO,CAAC,IAAI,CAAC;IAsB3E;;;OAGG;IACG,QAAQ;;;IAqDd;;;OAGG;IACH,OAAO,CAAC,eAAe;IAuJvB;;;OAGG;IACH,cAAc;IAgBd;;;OAGG;IACH,iBAAiB;IAwEjB;;;OAGG;IACH,YAAY;IAyBZ;;;;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
+ {"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
- if (opts.dryRun) {
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
- if (opts.dryRun) {
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('npx', ['tsup'], {
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
- if (opts.dryRun) {
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
- // Export our SDK into the source file.
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
- module: 'NodeNext',
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
- main: './dist/index.js',
388
- types: './dist/index.d.ts',
389
- module: './dist/index.mts',
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.mjs',
393
- require: './dist/index.js',
503
+ import: './dist/index.js',
504
+ require: './dist/index.cjs',
394
505
  },
395
506
  ...(hasTypes
396
507
  ? {
397
508
  './types': {
398
- import: './dist/types.d.mts',
399
- require: './dist/types.d.ts',
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
- prepare: 'tsup',
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
- Add SDK setup information and usage examples here so your users get started in a jiffy! 🚀
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/lib' },
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 });