Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions packages/api/src/codegen/codegenerator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,43 @@ import { findLicense } from 'license';
import { PACKAGE_NAME, PACKAGE_VERSION } from '../packageInfo.js';

export default abstract class CodeGenerator {
/** The associated API definition */
spec: Oas;

/**
* The path to the API definion (might be a local path, a URL, or an API registry identifier)
* @example https://raw.githubusercontent.com/readmeio/oas-examples/main/3.0/json/petstore-simple.json
* @example @petstore/v1.0#n6kvf10vakpemvplx
* @example ./petstore.json
*/
specPath: string;

/**
* The user-specified identifier for the SDK,
* used as the directory name in the `.api/apis` directory
* where the SDK source code is located.
*/
identifier: string;

/** The user agent which is set for all outgoing fetch requests */
userAgent: string;

/**
* The license associated with the SDK.
* This is extrapolated from the API definition file.
*/
spdxLicense?: string;

/**
* Contact info for the API and/or SDK author in case users need support.
* This is extrapolated from the API definition file.
*/
apiContact: { name?: string; url?: string } = {};

/**
* An object containing any downstream packages that are required
* for building/executing the SDK.
*/
requiredPackages!: Record<
string,
{
Expand All @@ -30,6 +55,11 @@ export default abstract class CodeGenerator {
}
>;

/**
* An example code snippet that a user can run to get started with the SDK.
*/
exampleCodeSnippet?: string | false;

constructor(spec: Oas, specPath: string, identifier: string) {
this.spec = spec;
this.specPath = specPath;
Expand Down Expand Up @@ -112,6 +142,8 @@ export default abstract class CodeGenerator {

abstract compile(storage: Storage, opts?: InstallerOptions): Promise<void>;

abstract getExampleCodeSnippet(): Promise<string | false>;

hasRequiredPackages() {
return Boolean(Object.keys(this.requiredPackages));
}
Expand Down
37 changes: 34 additions & 3 deletions packages/api/src/codegen/languages/typescript/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import setWith from 'lodash.setwith';
import semver from 'semver';
import { IndentationText, Project, QuoteKind, ScriptTarget, VariableDeclarationKind } from 'ts-morph';

import { buildCodeSnippetForOperation, getSuggestedOperation } from '../../../lib/suggestedOperations.js';
import logger from '../../../logger.js';
import { PACKAGE_VERSION } from '../../../packageInfo.js';
import Storage from '../../../storage.js';
Expand Down Expand Up @@ -213,7 +214,7 @@ export default class TSGenerator extends CodeGenerator {
this.createGitIgnore();
this.createPackageJSON();
this.createTSConfig();
this.createREADME();
await this.createREADME();

if (Object.keys(this.schemas).length) {
this.createSchemasFile(srcDirectory);
Expand Down Expand Up @@ -260,6 +261,23 @@ export default class TSGenerator extends CodeGenerator {
].reduce((prev, next) => Object.assign(prev, next));
}

async getExampleCodeSnippet() {
// if we've already built the code snippet, return it instead of re-building it!
if (typeof this.exampleCodeSnippet !== 'undefined') {
return this.exampleCodeSnippet;
}

const operation = getSuggestedOperation(this.spec);
if (!operation) {
this.exampleCodeSnippet = false;
return false;
}

const snippet = await buildCodeSnippetForOperation(this.spec, operation, { identifier: this.identifier });
this.exampleCodeSnippet = snippet;
return snippet;
}

/**
* Create our main SDK source file.
*
Expand Down Expand Up @@ -641,15 +659,28 @@ dist/
* Create a placeholder `README.md` file in the repository, with information on how to use/administer the SDK.
*
*/
createREADME() {
async createREADME() {
let createdAt = new Date().toISOString();
const currentAPI = Storage.getLockfile().apis.find(api => api.identifier === this.identifier);
if (currentAPI) createdAt = currentAPI.createdAt;

let exampleUsage = 'Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌';
const exampleSnippet = await this.getExampleCodeSnippet();
if (exampleSnippet) {
exampleUsage = `
## Example Usage 馃殌

\`\`\`js
${exampleSnippet}
\`\`\`
`.trim();
}

const file = `# \`@api/${this.identifier}\`

This SDK was autogenerated by the [\`api\` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 馃

Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌
${exampleUsage}

<!---

Expand Down
12 changes: 1 addition & 11 deletions packages/api/src/commands/install.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,6 @@ import uslug from 'uslug';
import { SupportedLanguages, codegenFactory } from '../codegen/factory.js';
import Fetcher from '../fetcher.js';
import promptTerminal from '../lib/prompt.js';
import { buildCodeSnippetForOperation, getSuggestedOperation } from '../lib/suggestedOperations.js';
import logger, { oraOptions } from '../logger.js';
import Storage from '../storage.js';

Expand Down Expand Up @@ -71,15 +70,6 @@ async function getIdentifier(oas: Oas, uri: string, options: Options) {
return identifier;
}

async function getExampleCodeSnippet(oas: Oas, identifier: string) {
const operation = getSuggestedOperation(oas);
if (!operation) {
return false;
}

return buildCodeSnippetForOperation(oas, operation, { identifier });
}

// @todo log logs to `.api/.logs` and have `.logs` ignored
const cmd = new Command();
cmd
Expand Down Expand Up @@ -213,7 +203,7 @@ cmd
)} package.`,
);

const exampleSnippet = await getExampleCodeSnippet(oas, identifier);
const exampleSnippet = await generator.getExampleCodeSnippet();
if (exampleSnippet) {
logger('');
logger(chalk.bold("馃憞 Here's an example code snippet you can try out 馃憞"));
Expand Down
11 changes: 10 additions & 1 deletion packages/test-utils/sdks/alby/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

This SDK was autogenerated by the [`api` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 馃

Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌
## Example Usage 馃殌

```js
import alby from '@api/alby';

alby.auth('token');
alby.getMe()
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
```

<!---

Expand Down
10 changes: 9 additions & 1 deletion packages/test-utils/sdks/metrotransit/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

This SDK was autogenerated by the [`api` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 馃

Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌
## Example Usage 馃殌

```js
import metrotransit from '@api/metrotransit';

metrotransit.getNextripAgencies()
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
```

<!---

Expand Down
10 changes: 9 additions & 1 deletion packages/test-utils/sdks/operationid-quirks/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

This SDK was autogenerated by the [`api` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 馃

Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌
## Example Usage 馃殌

```js
import operationidQuirks from '@api/operationid-quirks';

operationidQuirks.quirky_OperationId_string()
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
```

<!---

Expand Down
11 changes: 10 additions & 1 deletion packages/test-utils/sdks/petstore/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

This SDK was autogenerated by the [`api` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 馃

Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌
## Example Usage 馃殌

```js
import petstore from '@api/petstore';

petstore.auth('token');
petstore.getInventory()
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
```

<!---

Expand Down
11 changes: 10 additions & 1 deletion packages/test-utils/sdks/readme/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,16 @@

This SDK was autogenerated by the [`api` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 馃

Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌
## Example Usage 馃殌

```js
import readme from '@api/readme';

readme.auth('username', 'password');
readme.getAPISpecification()
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
```

<!---

Expand Down
10 changes: 9 additions & 1 deletion packages/test-utils/sdks/star-trek/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,15 @@

This SDK was autogenerated by the [`api` SDK generator](https://api.readme.dev), powered by [ReadMe](https://readme.com) 馃

Add SDK setup information and usage examples here so your users get started in a jiffy! 馃殌
## Example Usage 馃殌

```js
import starTrek from '@api/star-trek';

starTrek.getAnimalSearch()
.then(({ data }) => console.log(data))
.catch(err => console.error(err));
```

<!---

Expand Down