Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: add example code snippet to README #809

Merged
merged 7 commits into from
Nov 2, 2023
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