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

refactor: migrate oas libraries of ours into this new monorepo #811

Merged
merged 10 commits into from
Oct 5, 2023
Merged
1 change: 1 addition & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,5 @@ jobs:
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
- run: npm run lint
14,509 changes: 8,489 additions & 6,020 deletions package-lock.json

Large diffs are not rendered by default.

3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@
"lint": "npm run lint:types && npm run lint:js && npm run prettier",
"lint:js": "npm run lint:js --if-present --workspaces",
"lint:types": "npm run lint:types --if-present --workspaces",
"prelint": "npm run prelint --if-present --workspaces",
"prepare": "husky install",
"prettier": "prettier --check .",
"prettier:write": "prettier --check --write .",
Expand All @@ -28,7 +27,7 @@
"devDependencies": {
"@commitlint/cli": "^17.7.2",
"@commitlint/config-conventional": "^17.7.0",
"@readme/eslint-config": "^12.2.1",
"@readme/eslint-config": "^13.1.0",
"alex": "^11.0.1",
"eslint": "^8.48.0",
"husky": "^8.0.3",
Expand Down
2 changes: 2 additions & 0 deletions packages/oas-extensions/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
coverage/
dist/
8 changes: 8 additions & 0 deletions packages/oas-extensions/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"extends": ["@readme/eslint-config", "@readme/eslint-config/typescript"],
"root": true,
"rules": {
"@typescript-eslint/consistent-type-imports": "error",
"@typescript-eslint/explicit-module-boundary-types": "off"
}
}
3 changes: 3 additions & 0 deletions packages/oas-extensions/.npmignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
coverage/
test/
.eslint*
13 changes: 13 additions & 0 deletions packages/oas-extensions/LICENSE
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Copyright © 2023 ReadMe

Permission to use, copy, modify, and/or distribute this software for any purpose
with or without fee is hereby granted, provided that the above copyright notice
and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND
FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS
OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER
TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
15 changes: 15 additions & 0 deletions packages/oas-extensions/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# @readme/oas-extensions

A list of extensions that ReadMe has added to extend the OpenAPI Specification.

https://docs.readme.com/docs/openapi-extensions

[![Build](https://github.com/readmeio/oas/workflows/CI/badge.svg)](https://github.com/readmeio/oas/tree/main/packages/oas-extensions)

[![](https://raw.githubusercontent.com/readmeio/.github/main/oss-header.png)](https://readme.io)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ohhh thank you for this

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah i was sick of seeing that cloudfront.net link

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have an open design request to update this and i was literally thinking of doing this so we can just update the graphic in one fell swoop


## Installation

```
npm install --save @readme/oas-extensions
```
53 changes: 53 additions & 0 deletions packages/oas-extensions/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
{
"name": "@readme/oas-extensions",
"description": "A list of extensions that ReadMe has added to extend the OpenAPI Specification",
"version": "20.0.1",
"author": "Jon Ursenbach <jon@readme.io>",
"license": "ISC",
"sideEffects": false,
"type": "module",
"exports": {
".": {
"require": "./dist/index.cjs",
"import": "./dist/index.js"
}
},
"main": "dist/index.cjs",
"module": "dist/index.js",
"types": "dist/index.d.cts",
"engines": {
"node": ">=18"
},
"files": [
"dist"
],
"repository": {
"type": "git",
"url": "git://github.com/readmeio/oas.git",
"directory": "packages/oas-extensions"
},
"bugs": {
"url": "https://github.com/readmeio/oas/issues"
},
"scripts": {
"build": "tsup",
"lint": "npm run lint:types && npm run lint:js",
"lint:js": "eslint . --ext .js,.ts",
"lint:types": "tsc --noEmit",
"prebuild": "rm -rf dist/",
"prepack": "npm run build",
"test": "vitest run --coverage"
},
"peerDependencies": {
"oas": "file:../oas"
},
"devDependencies": {
"@readme/oas-examples": "^5.12.0",
"@vitest/coverage-v8": "^0.34.3",
"eslint": "^8.48.0",
"tsup": "^7.2.0",
"typescript": "^5.2.2",
"vitest": "^0.34.3"
},
"prettier": "@readme/eslint-config/prettier"
}
134 changes: 134 additions & 0 deletions packages/oas-extensions/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
import type Oas from 'oas';
import type Operation from 'oas/operation';

export const CODE_SAMPLES = 'code-samples';
export const EXPLORER_ENABLED = 'explorer-enabled';
export const HEADERS = 'headers';
export const METRICS_ENABLED = 'metrics-enabled';
export const PROXY_ENABLED = 'proxy-enabled';
export const SAMPLES_ENABLED = 'samples-enabled';
export const SAMPLES_LANGUAGES = 'samples-languages';
export const SEND_DEFAULTS = 'send-defaults';
export const SIMPLE_MODE = 'simple-mode';

// Make sure you document any changes on here:
// https://docs.readme.com/docs/openapi-extensions
export interface Extensions {
[CODE_SAMPLES]: {
code: string;
install?: string;
language: string;
name?: string;
};
[EXPLORER_ENABLED]: boolean;
[HEADERS]: Record<string, string | number>[];
[METRICS_ENABLED]: boolean;
[PROXY_ENABLED]: boolean;
[SAMPLES_ENABLED]: boolean; // @deprecated
[SAMPLES_LANGUAGES]: string[];
[SEND_DEFAULTS]: boolean; // @deprecated
[SIMPLE_MODE]: boolean;
}

export const defaults: Extensions = {
[CODE_SAMPLES]: undefined,
[EXPLORER_ENABLED]: true,
[HEADERS]: undefined,
[METRICS_ENABLED]: true,
[PROXY_ENABLED]: true,
[SAMPLES_ENABLED]: true,
[SAMPLES_LANGUAGES]: ['shell', 'node', 'ruby', 'php', 'python', 'java', 'csharp'],
[SEND_DEFAULTS]: false,
[SIMPLE_MODE]: true,
};

/**
* With one of our custom OpenAPI extensions, look for it in either an instance of `oas` or an
* instance of the `Operation` class in `oas`.
*
* Our custom extensions can either be nestled inside of an `x-readme` object or at the root level
* with an `x-` prefix.
*
* @see {@link https://npm.im/oas}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions}
* @param extension Specification extension to lookup.
* @param oas An instance of the `oas` library class.
* @param operation An instsance of the `Operation` class from the `oas` library.
* @returns Contents of the extension if found, otherwise the extensions default value.
*/
export function getExtension(extension: keyof Extensions, oas: Oas, operation?: Operation) {
if (operation) {
if (operation.hasExtension('x-readme')) {
const data = operation.getExtension('x-readme') as Extensions;
if (data && typeof data === 'object' && extension in data) {
return data[extension];
}
}

if (operation.hasExtension(`x-${extension}`)) {
return operation.getExtension(`x-${extension}`);
}
}

// Because our `code-samples` extension is intended for operation-level use, if it's instead
// placed at the OAS-level we should ignore it.
if (extension === CODE_SAMPLES) {
return defaults[extension];
}

if (oas.hasExtension('x-readme')) {
const data = oas.getExtension('x-readme') as Extensions;
if (data && typeof data === 'object' && extension in data) {
return data[extension];
}
}

if (oas.hasExtension(`x-${extension}`)) {
return oas.getExtension(`x-${extension}`);
}

return defaults[extension];
}

/**
* With one of our custom OpenAPI extensions, determine if it's valid on a given instance of `oas`.
*
* @todo add support for validating on operations.
*
* @see {@link https://npm.im/oas}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.0.3.md#specificationExtensions}
* @see {@link https://github.com/OAI/OpenAPI-Specification/blob/main/versions/3.1.0.md#specificationExtensions}
* @param extension Specification extension to lookup.
* @param oas An instance of the `oas` library class.
*/
export function validateExtension(extension: keyof Extensions, oas: Oas) {
if (oas.hasExtension('x-readme')) {
const data = oas.getExtension('x-readme') as Extensions;
if (typeof data !== 'object' || Array.isArray(data) || data === null) {
throw new TypeError('"x-readme" must be of type "Object"');
}

if (extension in data) {
if ([CODE_SAMPLES, HEADERS, SAMPLES_LANGUAGES].includes(extension)) {
if (!Array.isArray(data[extension])) {
throw new TypeError(`"x-readme.${extension}" must be of type "Array"`);
}
} else if (typeof data[extension] !== 'boolean') {
throw new TypeError(`"x-readme.${extension}" must be of type "Boolean"`);
}
}
}

// If the extension isn't grouped under `x-readme`, we need to look for them with `x-` prefixes.
if (oas.hasExtension(`x-${extension}`)) {
const data = oas.getExtension(`x-${extension}`);
if ([CODE_SAMPLES, HEADERS, SAMPLES_LANGUAGES].includes(extension)) {
if (!Array.isArray(data)) {
throw new TypeError(`"x-${extension}" must be of type "Array"`);
}
} else if (typeof data !== 'boolean') {
throw new TypeError(`"x-${extension}" must be of type "Boolean"`);
}
}
}
3 changes: 3 additions & 0 deletions packages/oas-extensions/test/.eslintrc
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"extends": "@readme/eslint-config/testing/vitest"
}
Loading