UNPKG

api

Version:

Magical SDK generation from an OpenAPI definition 🪄

112 lines • 5.14 kB
import { findLicense } from 'license'; import { PACKAGE_NAME, PACKAGE_VERSION } from '../packageInfo.js'; export default class CodeGenerator { /** The associated API definition */ spec; /** * 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; /** * 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; /** The user agent which is set for all outgoing fetch requests */ userAgent; /** * The license associated with the SDK. * This is extrapolated from the API definition file. */ spdxLicense; /** * Contact info for the API and/or SDK author in case users need support. * This is extrapolated from the API definition file. */ apiContact = {}; /** * An object containing any downstream packages that are required * for building/executing the SDK. */ requiredPackages; /** * An example code snippet that a user can run to get started with the SDK. */ exampleCodeSnippet; constructor(spec, specPath, identifier) { this.spec = spec; this.specPath = specPath; this.identifier = identifier; // User agents should be contextual to the spec in question and the version of `api` that was // used to generate the SDK. For example, this'll look like `petstore/1.0.0 (api/4.2.0)` for // a `petstore` spec installed on api@4.2.0. const info = spec.getDefinition().info; this.userAgent = `${identifier}/${info.version} (${PACKAGE_NAME}/${PACKAGE_VERSION})`; /** * This check is barbaric but there are a number of issues with how the `transformer` work we * have in `oas` and in `.getParametersAsJSONSchema()` and `.getResponseAsJSONSchema()` that * are fully crashing when attempting to codegen an SDK for an API definition that has a * circular reference. * * In order to get v5 out the door we're not going to support this case initialy. * * @see {@link https://github.com/readmeio/api/issues/549} */ if (JSON.stringify(spec.api).includes('"$ref":"#/')) { throw new Error('Sorry, this library does not yet support generating an SDK for an OpenAPI definition that contains circular references.'); } const infoObject = this.spec.api.info; if (infoObject?.license?.name || infoObject?.license?.identifier) { let spdxLicense; if (infoObject?.license?.identifier) { spdxLicense = infoObject?.license?.identifier; } else { // Though `name` is required by the OpenAPI specification but most people seem to use `name` // instead `identifier` for their licensing identifier so if they've done this we should // try to make the license name recognizable by the `license` package. For example this'll // change "Apache 2.0" to the SPDX-recognized "Apache-2.0". spdxLicense = infoObject?.license?.name.replace(/ /g, '-'); } // If the license they've got has too many matches we shouldn't try to pick a license because // we'll run the risk of licensing it under a license they didn't intend. if (findLicense(spdxLicense).length === 1) { this.spdxLicense = spdxLicense; } } if (infoObject?.contact) { if (infoObject.contact?.name || infoObject.contact?.email) { if (infoObject.contact?.name && infoObject.contact?.email) { this.apiContact.name = `${infoObject.contact.name} <${infoObject.contact.email}>`; } else { this.apiContact.name = infoObject.contact.email ? `<${infoObject.contact.email}>` : (infoObject.contact.name ?? undefined); } } if (infoObject.contact?.url) { this.apiContact.url = infoObject.contact.url; } } } /** * It would be better if this were an abstract function but TS/JS doesn't have support for that so * we instead have to rely on throwing a `TypeError` if it's not been implemented instead of a * build-time error. * * @see {@link https://github.com/microsoft/TypeScript/issues/34516} */ // oxlint-disable-next-line no-unused-vars -- This is an abstract class. static async uninstall(storage, opts) { throw new TypeError('The uninstallation step for this language has not been implemented'); } hasRequiredPackages() { return Boolean(Object.keys(this.requiredPackages)); } } //# sourceMappingURL=codegenerator.js.map