├── .editorconfig ├── .eslintignore ├── .eslintrc.json ├── .github └── workflows │ ├── merge-checks.yml │ └── npm-publish.yml ├── .gitignore ├── .npmignore ├── .prettierrc ├── .travis.yml ├── CHANGELOG.md ├── LICENSE ├── README.md ├── dependabot.yml ├── docs ├── development │ ├── clients.md │ ├── contributors-guide.md │ └── overview.md └── usage │ ├── api.md │ ├── clients.md │ └── generated-code.md ├── examples ├── .gitignore ├── clients │ ├── fetch.ts │ ├── live-data.ts │ └── observable.ts ├── generate │ ├── 01-single-spec.ts │ ├── 02-multiple-specs.ts │ └── 03-cleanup-before-generating.ts ├── package.json ├── tsconfig.json └── yarn.lock ├── nodemon.json ├── package.json ├── reviewpad.yml ├── src ├── index.ts ├── language │ └── typescript │ │ ├── 2.0 │ │ ├── index.ts │ │ └── serializers │ │ │ ├── __tests__ │ │ │ ├── responses-object.spec.ts │ │ │ └── schema-object.spec.ts │ │ │ ├── definitions-object.ts │ │ │ ├── items-object.ts │ │ │ ├── operation-object.ts │ │ │ ├── parameter-object.ts │ │ │ ├── parameters-definitions-object.ts │ │ │ ├── path-item-object.ts │ │ │ ├── paths-object.ts │ │ │ ├── response-object.ts │ │ │ ├── responses-definitions-object.ts │ │ │ ├── responses-object.ts │ │ │ ├── schema-object.ts │ │ │ └── swagger-object.ts │ │ ├── 3.0 │ │ ├── bundled │ │ │ └── openapi-3-utils.ts │ │ ├── index.ts │ │ └── serializers │ │ │ ├── __tests__ │ │ │ ├── operation-object.spec.ts │ │ │ └── schema-object.spec.ts │ │ │ ├── components-object.ts │ │ │ ├── document.ts │ │ │ ├── operation-object.ts │ │ │ ├── parameter-object.ts │ │ │ ├── path-item-object.ts │ │ │ ├── paths-object.ts │ │ │ ├── request-body-object.ts │ │ │ ├── response-maps.ts │ │ │ ├── response-object.ts │ │ │ ├── responses-object.ts │ │ │ └── schema-object.ts │ │ ├── asyncapi-2.0.0 │ │ ├── index.ts │ │ └── serializers │ │ │ ├── __tests__ │ │ │ └── channel-item-object.spec.ts │ │ │ ├── asyncapi-object.ts │ │ │ ├── channel-item-object.ts │ │ │ ├── channels-object.ts │ │ │ ├── components-object.ts │ │ │ ├── message-object.ts │ │ │ ├── operation-object.ts │ │ │ └── schema-object.ts │ │ ├── common │ │ ├── __tests__ │ │ │ └── utils.spec.ts │ │ ├── bundled │ │ │ ├── __tests__ │ │ │ │ └── client.spec.ts │ │ │ ├── client.ts │ │ │ └── utils.ts │ │ ├── data │ │ │ ├── __tests__ │ │ │ │ └── serialized-type.spec.ts │ │ │ ├── serialized-dependency.ts │ │ │ ├── serialized-fragment.ts │ │ │ ├── serialized-header-parameters.ts │ │ │ ├── serialized-parameter.ts │ │ │ ├── serialized-path-parameter.ts │ │ │ └── serialized-type.ts │ │ └── utils.ts │ │ └── sketch-121 │ │ ├── index.ts │ │ ├── serializers │ │ ├── document.ts │ │ ├── enums │ │ │ ├── blend-mode.ts │ │ │ ├── text-horizontal-alignment.ts │ │ │ ├── text-vertical-alignment.ts │ │ │ └── underline-style.ts │ │ ├── file-format.ts │ │ └── objects │ │ │ ├── asset-collection.ts │ │ │ ├── border.ts │ │ │ ├── color.ts │ │ │ ├── foreign-layer-style.ts │ │ │ ├── foreign-text-style.ts │ │ │ ├── gradient-stop.ts │ │ │ ├── gradient.ts │ │ │ ├── inner-shadow.ts │ │ │ ├── layer.ts │ │ │ ├── page.ts │ │ │ ├── shadow.ts │ │ │ ├── shared-style.ts │ │ │ ├── shared-styled-container.ts │ │ │ ├── shared-text-style-container.ts │ │ │ ├── style.ts │ │ │ └── text-style.ts │ │ └── utils.ts ├── parsers │ └── sketch-121.ts ├── schema │ ├── 2.0 │ │ ├── contact-object.ts │ │ ├── definitions-object.ts │ │ ├── example-object.ts │ │ ├── external-documentation-object.ts │ │ ├── header-object.ts │ │ ├── headers-object.ts │ │ ├── info-object.ts │ │ ├── items-object.ts │ │ ├── license-object.ts │ │ ├── operation-object.ts │ │ ├── parameter-object.ts │ │ ├── parameters-definitions-object.ts │ │ ├── path-item-object.ts │ │ ├── paths-object.ts │ │ ├── reference-object.ts │ │ ├── response-object.ts │ │ ├── responses-definitions-object.ts │ │ ├── responses-object.ts │ │ ├── schema-object.ts │ │ ├── scopes-object.ts │ │ ├── security-definitions-object.ts │ │ ├── security-requirement-object.ts │ │ ├── security-scheme-object │ │ │ ├── access-code-oauth2-security-scheme-object.ts │ │ │ ├── api-key-security-scheme-object.ts │ │ │ ├── application-oauth2-security-scheme-object.ts │ │ │ ├── base-security-scheme-object.ts │ │ │ ├── basic-security-scheme-object.ts │ │ │ ├── implicit-oauth2-security-scheme-object.ts │ │ │ ├── oauth2-security-scheme-object.ts │ │ │ ├── password-oauth2-security-scheme-object.ts │ │ │ └── security-scheme-object.ts │ │ ├── swagger-object.ts │ │ └── tag-object.ts │ ├── 3.0 │ │ ├── components-object.ts │ │ ├── media-type-object.ts │ │ ├── openapi-object.ts │ │ ├── operation-object.ts │ │ ├── parameter-object.ts │ │ ├── path-item-object.ts │ │ ├── paths-object.ts │ │ ├── reference-object.ts │ │ ├── request-body-object.ts │ │ ├── response-object.ts │ │ ├── responses-object.ts │ │ ├── schema-object.ts │ │ ├── server-object.ts │ │ └── server-variable-object.ts │ ├── asyncapi-2.0.0 │ │ ├── asyncapi-object.ts │ │ ├── channel-bindings-object.ts │ │ ├── channel-item-object.ts │ │ ├── channels-object.ts │ │ ├── components-object.ts │ │ ├── contact-object.ts │ │ ├── correlation-id-object.ts │ │ ├── external-documentation-object.ts │ │ ├── info-object.ts │ │ ├── license-object.ts │ │ ├── message-object.ts │ │ ├── message-trait-object.ts │ │ ├── operation-object.ts │ │ ├── operation-trait-object.ts │ │ ├── parameter-object.ts │ │ ├── parameters-object.ts │ │ ├── reference-object.ts │ │ ├── schema-object.ts │ │ ├── security-requirement-object.ts │ │ ├── security-scheme-object.ts │ │ ├── server-object.ts │ │ ├── server-variable-object.ts │ │ ├── servers-object.ts │ │ ├── tag-object.ts │ │ ├── tags-object.ts │ │ └── websockets-channel-binding-object.ts │ └── sketch-121 │ │ ├── abstract-document.ts │ │ ├── document.ts │ │ ├── enums │ │ ├── blend-mode.ts │ │ ├── border-position.ts │ │ ├── fill-type.ts │ │ ├── gradient-type.ts │ │ ├── layer-class.ts │ │ ├── text-horizontal-alignment.ts │ │ ├── text-transform.ts │ │ ├── text-vertical-alignment.ts │ │ └── underline-style.ts │ │ ├── file-format.ts │ │ ├── meta.ts │ │ ├── objects │ │ ├── asset-collection.ts │ │ ├── border-options.ts │ │ ├── border.ts │ │ ├── color-asset.ts │ │ ├── color-controls.ts │ │ ├── color.ts │ │ ├── fill.ts │ │ ├── font-descriptor.ts │ │ ├── foreign-layer-style.ts │ │ ├── foreign-symbol.ts │ │ ├── foreign-text-style.ts │ │ ├── gradient-asset.ts │ │ ├── gradient-stop.ts │ │ ├── gradient.ts │ │ ├── graphics-context-settings.ts │ │ ├── inner-shadow.ts │ │ ├── layer.ts │ │ ├── object-id.ts │ │ ├── override-value.ts │ │ ├── page-file-ref.ts │ │ ├── page.ts │ │ ├── paragraph-style.ts │ │ ├── shadow.ts │ │ ├── shared-style-container.ts │ │ ├── shared-style.ts │ │ ├── shared-text-style-container.ts │ │ ├── style.ts │ │ └── text-style.ts │ │ ├── user.ts │ │ └── utils │ │ ├── point-string.ts │ │ └── unit-interval.ts ├── tsconfig.json └── utils │ ├── __tests__ │ └── ref.spec.ts │ ├── array.ts │ ├── either.ts │ ├── fast-check.ts │ ├── fs.ts │ ├── function.ts │ ├── io-ts.ts │ ├── monoid.ts │ ├── nullable.ts │ ├── option.ts │ ├── ref.ts │ ├── string.ts │ └── types.ts ├── test ├── index.spec.ts ├── specs │ ├── 2.0 │ │ ├── json │ │ │ ├── common.json │ │ │ └── swagger.json │ │ └── yaml │ │ │ ├── common.yml │ │ │ ├── demo.yml │ │ │ └── swagger.yml │ ├── 3.0 │ │ ├── api-with-examples.yaml │ │ ├── arbitrary.yml │ │ ├── callback-example.yaml │ │ ├── demo.yml │ │ ├── file-and-text.yml │ │ ├── nested │ │ │ └── link-example.yaml │ │ ├── openapi-3.0.yaml │ │ ├── petstore-expanded.yaml │ │ ├── petstore.yaml │ │ └── uspto.yaml │ ├── arbitrary.yml │ ├── asyncapi-2.0.0 │ │ ├── channel-params.yml │ │ ├── echo.yml │ │ └── streetlights-api.yml │ └── sketch │ │ └── demo.sketch └── utils.ts ├── tsconfig.build.json ├── tsconfig.json ├── tsconfig.test.json └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | # Editor configuration, see http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | trim_trailing_whitespace = true 7 | insert_final_newline = true 8 | 9 | [*.{js,ts,jsx,tsx,html,css,scss,sass}] 10 | indent_style = tab 11 | indent_size = 4 12 | 13 | [*.{json,yaml}] 14 | indent_size = 2 15 | indent_style = space 16 | 17 | [*.md] 18 | max_line_length = off 19 | -------------------------------------------------------------------------------- /.eslintignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | dist/* 3 | test/out/* 4 | -------------------------------------------------------------------------------- /.eslintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "./node_modules/@devexperts/lint/.eslintrc.json", 3 | "parserOptions": { 4 | "createDefaultProgram": true 5 | }, 6 | "rules": { 7 | "@typescript-eslint/no-unused-vars": "error" 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /.github/workflows/merge-checks.yml: -------------------------------------------------------------------------------- 1 | # This workflow will do a clean installation of node dependencies, build the source code and run tests 2 | # For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs 3 | 4 | name: Merge Checks 5 | 6 | on: 7 | pull_request: 8 | branches: [ "master" ] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 14.x 18 | - run: yarn 19 | - run: yarn test 20 | - run: yarn build 21 | -------------------------------------------------------------------------------- /.github/workflows/npm-publish.yml: -------------------------------------------------------------------------------- 1 | # This workflow will run tests using node and then publish a package to GitHub Packages when a release is created 2 | # For more information see: https://docs.github.com/en/actions/publishing-packages/publishing-nodejs-packages 3 | 4 | name: Build and Publish 5 | 6 | on: 7 | release: 8 | types: [published] 9 | 10 | jobs: 11 | build: 12 | runs-on: ubuntu-latest 13 | steps: 14 | - uses: actions/checkout@v3 15 | - uses: actions/setup-node@v3 16 | with: 17 | node-version: 14.x 18 | - run: yarn 19 | - run: yarn version 20 | - run: yarn publish 21 | env: 22 | NODE_AUTH_TOKEN: ${{secrets.npm_token}} 23 | - run: git push 24 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /.idea 2 | node_modules 3 | /.vscode 4 | /test/out 5 | /specs 6 | /dist 7 | /test/specs/sketch/ignore 8 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | /src 2 | /specs 3 | /node_modules 4 | /out 5 | /.vscode 6 | /test 7 | /nodemon.json 8 | /tsconfig.json 9 | /.gitignore 10 | /.editorconfig 11 | /.prettierrc 12 | /package-lock.json 13 | /.idea 14 | /tslint.json 15 | /.eslintignore 16 | /.eslintrc.json 17 | /.travis.yml 18 | /tsconfig.build.json 19 | /tsconfig.test.json 20 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "bracketSpacing": true, 3 | "jsxBracketSameLine": true, 4 | "parser": "typescript", 5 | "printWidth": 120, 6 | "semi": true, 7 | "singleQuote": true, 8 | "tabWidth": 4, 9 | "trailingComma": "all", 10 | "useTabs": true 11 | } 12 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "10" 4 | script: 5 | - npm run test && npm run build 6 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Build Status](https://travis-ci.org/devexperts/swagger-codegen-ts.svg?branch=master)](https://travis-ci.org/devexperts/swagger-codegen-ts) 2 | 3 | # Typesafe OpenAPI generator for TypeScript 4 | 5 | ## Features 6 | * Generates client code from **OpenAPI 3.0, 2.0** (aka Swagger) and **AsyncAPI** specs 7 | * **Pluggable HTTP clients:** can use `fetch`, `Axios` or any other library 8 | * **Flexible response types:** works with Promises and reactive streams like RxJS 9 | * **Runtime type checks:** validates server responses against the spec 10 | * Written in **pure TypeScript** using [`fp-ts`](https://github.com/gcanti/fp-ts) and [`io-ts`](https://github.com/gcanti/io-ts) libraries 11 | 12 | ## Demo code 13 | 14 | > The examples below refer to the [Pet Store OpenAPI 3.0 schema](https://petstore3.swagger.io/). 15 | 16 | After running the codegen, interacting with a REST API may be as simple as this: 17 | 18 | ```typescript 19 | import { petController as createPetController } from "./src/generated/petstore.json/paths/PetController"; 20 | import { Pet } from "./src/generated/petstore.json/components/schemas/Pet"; 21 | 22 | // Creating a controller, see the "HTTP Clients" wiki page for more details 23 | const petController = createPetController({ httpClient: fetchHttpClient }); 24 | 25 | // The returned object is guaranteed to be a valid `Pet` 26 | const createdPet: Promise = petController.addPet({ 27 | body: { 28 | // The parameters are statically typed, IntelliSense works, too 29 | name: "Spotty", 30 | photoUrls: [], 31 | }, 32 | }); 33 | ``` 34 | 35 | More usage scenarios are supported - check the [usage page](./docs/usage/generated-code.md) for more detail. 36 | 37 | ## Installation 38 | 39 | 1. Make sure the peer dependencies are installed, then install the codegen itself: 40 | ``` 41 | yarn add typescript fp-ts io-ts io-ts-types 42 | yarn add -D @devexperts/swagger-codegen-ts 43 | ``` 44 | 45 | 2. Create a console script that would invoke the `generate` function, passing the options such as path to the schema file and the output directory. 46 | See the [Generators](docs/usage/api.md) page for the API reference, and [examples/generate](examples/generate) for sample scripts. 47 | 48 | 3. In most cases, you might want to include the code generation step into the build and local launch scripts. Example: 49 | ```diff 50 | /* package.json */ 51 | 52 | "scripts": { 53 | + "generate:api": "ts-node scripts/generate-api.ts", 54 | - "start": "react-scripts start", 55 | + "start": "yarn generate:api && react-scripts start", 56 | - "build": "react-scripts build" 57 | + "build": "yarn generate:api && react-scripts build" 58 | } 59 | ``` 60 | 61 | ## Contributing 62 | 63 | * Feel free to file bugs and feature requests in [GitHub issues](https://github.com/devexperts/swagger-codegen-ts/issues/new). 64 | * Pull requests are welcome - please use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0-beta.2/). 65 | 66 | Please read the [Contributors Guide](./docs/development/contributors-guide.md) for more information. 67 | -------------------------------------------------------------------------------- /dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: npm 4 | directory: / 5 | schedule: 6 | interval: daily 7 | commit-message: 8 | prefix: "build: " 9 | -------------------------------------------------------------------------------- /docs/development/clients.md: -------------------------------------------------------------------------------- 1 | # Creating HTTP Clients 2 | 3 | The code generated by OpenAPI and AsyncAPI generators requires the user to provide an `HTTPClient` or `WebSocketClient` instance respectively. 4 | 5 | The original intent is to create such instances in the consumer's application; however, some predefined clients may be added in the future. This guide describes basic steps to create one. 6 | 7 | ### Defining a return type 8 | 9 | In order to support the desired return type, the generated code must know how to perform some basic operations over that type, such as creating a "successful" or "failed" response object, or applying a given transform function to the response. These operations are abstracted via the [`MonadThrow`](https://gcanti.github.io/fp-ts/modules/MonadThrow.ts.html) interface from the `fp-ts` library. 10 | 11 | Some common types already have corresponding `Monad` implementations, while for others you might have to implement one from scratch. For an example of how this can be done and what functions are required, check how the `Monad` is implemented for RxJS's `Observable` in the [`fp-ts-rxjs`](https://github.com/gcanti/fp-ts-rxjs/blob/master/src/Observable.ts) package. 12 | 13 | ### Implementing the actual HTTP requests logic 14 | 15 | Once the `Monad` implementation is available, just two methods need to be added to form a working `HTTPClient`: `throwError` and `request`. As can be seen from their signatures, they create a "failed" response and make actual HTTP calls, respectively. 16 | 17 | Considering the above, an `HTTPClient` for RxJS could be defined as follows: 18 | 19 | ```typescript 20 | import { Monad } from "fp-ts-rxjs/lib/Observable"; 21 | import { throwError } from "rxjs"; 22 | 23 | const rxjsHttpClient: HTTPClient1<"Observable"> = { 24 | ...Monad, 25 | request: (req) => { 26 | return ajax({ 27 | url: req.url, 28 | method: req.method, 29 | // add the logic to handle `req.body` and other parameters 30 | }).pipe(); 31 | }, 32 | throwError, 33 | }; 34 | ``` 35 | -------------------------------------------------------------------------------- /docs/development/contributors-guide.md: -------------------------------------------------------------------------------- 1 | # Contributors Guide 2 | 3 | Thanks for your attention and efforts to improve the codegen! 4 | 5 | Here are some resources to help you getting familiar with the code base. 6 | 7 | * [Development: Overview](./overview.md) 8 | 9 | # Testing 10 | 11 | # Submitting changes 12 | 13 | # Code style and conventions 14 | -------------------------------------------------------------------------------- /docs/development/overview.md: -------------------------------------------------------------------------------- 1 | # Development: Overview 2 | 3 | TODO: describe the architecture and data flows 4 | 5 | ### FAQ 6 | 1. **Why don't spec codecs reuse common parts?** 7 | 8 | That's because different versions of specs refer to different versions of [JSON Schema](http://json-schema.org) and they are generally not the same. We would like to avoid maintaining JSON Schema composition in this project. (for now) 9 | 10 | ### Publish 11 | `npm version major|minor|patch` 12 | -------------------------------------------------------------------------------- /docs/usage/api.md: -------------------------------------------------------------------------------- 1 | # API 2 | 3 | The single entry point to the generator is the `generate` function: 4 | 5 | ```typescript 6 | import { generate } from "@devexperts/swagger-codegen-ts"; 7 | import { OpenapiObjectCodec } from "@devexperts/swagger-codegen-ts/dist/schema/3.0/openapi-object"; 8 | import { serialize } from "@devexperts/swagger-codegen-ts/dist/language/typescript/3.0"; 9 | 10 | generate({ 11 | spec: path.resolve(__dirname, "petstore.json"), 12 | out: path.resolve(__dirname, "src/generated"), 13 | language: serialize, 14 | decoder: OpenapiObjectCodec, 15 | }); 16 | ``` 17 | 18 | See the typedocs for more info about the options. 19 | 20 | # CLI 21 | 22 | Not implemented yet - PRs are highly welcome! 23 | -------------------------------------------------------------------------------- /docs/usage/clients.md: -------------------------------------------------------------------------------- 1 | # Clients Reference 2 | 3 | Different projects have slightly different requirements regarding the error handling, request and response processing and other logic. 4 | These requirements should be implemented as an `HTTPClient` instance, which in turn is provided to the generated controllers. 5 | 6 | Resources: 7 | - For developing a custom `HTTPClient`, please refer to [Developers Guide - HTTP clients](../development/clients.md); 8 | - The repository contains a few [examples](../../examples/clients) of HTTPClient implementation for common libraries; 9 | -------------------------------------------------------------------------------- /examples/.gitignore: -------------------------------------------------------------------------------- 1 | /out/ 2 | -------------------------------------------------------------------------------- /examples/clients/fetch.ts: -------------------------------------------------------------------------------- 1 | import { HTTPClient1 } from '../out/petstore.yaml/client/client'; 2 | import { MonadThrow1 } from 'fp-ts/MonadThrow'; 3 | import { pipe } from 'fp-ts/function'; 4 | import { record } from 'fp-ts'; 5 | 6 | export const URI = 'Promise' as const; 7 | export type URI = typeof URI; 8 | 9 | declare module 'fp-ts/HKT' { 10 | interface URItoKind { 11 | readonly [URI]: Promise; 12 | } 13 | } 14 | 15 | export const monadPromise: MonadThrow1 = { 16 | URI, 17 | of: Promise.resolve, 18 | throwError: Promise.reject, 19 | map: (fa, f) => fa.then(a => Promise.resolve(f(a))), 20 | ap: (fab, fa) => fab.then(fn => fa.then(a => fn(a))), 21 | chain: (fa, f) => fa.then(f), 22 | }; 23 | 24 | export const fetchClient: HTTPClient1 = { 25 | ...monadPromise, 26 | request: ({ body, headers, method, query, url }) => 27 | fetch(query ? `${url}?${query}` : url, { 28 | body: body && JSON.stringify(body), 29 | headers: 30 | headers && 31 | pipe( 32 | headers, 33 | record.map(val => { 34 | if (Array.isArray(val)) { 35 | return val.join(','); 36 | } else { 37 | return String(val); 38 | } 39 | }), 40 | ), 41 | method, 42 | }), 43 | }; 44 | -------------------------------------------------------------------------------- /examples/clients/live-data.ts: -------------------------------------------------------------------------------- 1 | import { HTTPClient2 } from '../out/petstore.yaml/client/client'; 2 | import { Monad } from 'fp-ts-rxjs/Observable'; 3 | import { Observable, of } from 'rxjs'; 4 | import { ajax } from 'rxjs/ajax'; 5 | import { catchError, map, startWith, switchMap, take } from 'rxjs/operators'; 6 | import { failure, pending, RemoteData, success } from '@devexperts/remote-data-ts'; 7 | import { getRemoteDataM } from '@devexperts/remote-data-ts/dist/remote-data-t'; 8 | import { MonadThrow2 } from 'fp-ts/MonadThrow'; 9 | 10 | export const URI = 'LiveData' as const; 11 | export type URI = typeof URI; 12 | export type LiveData = Observable>; 13 | 14 | declare module 'fp-ts/HKT' { 15 | interface URItoKind2 { 16 | readonly [URI]: LiveData; 17 | } 18 | } 19 | 20 | const remoteDataMonad: MonadThrow2 = { 21 | ...getRemoteDataM(Monad), 22 | URI, 23 | throwError: e => of(failure(e)), 24 | }; 25 | 26 | export const liveDataClient: HTTPClient2 = { 27 | ...remoteDataMonad, 28 | request: ({ body, headers, method, query, url }) => 29 | ajax({ 30 | body: body && JSON.stringify(body), 31 | url: query ? `${url}?${query}` : url, 32 | headers, 33 | method, 34 | }).pipe( 35 | map(response => success(response.response)), 36 | catchError(remoteDataMonad.throwError), 37 | startWith(pending), 38 | ), 39 | }; 40 | 41 | export const liveDataClientWithAuth = (token$: Observable): HTTPClient2 => ({ 42 | ...liveDataClient, 43 | request: req => 44 | token$.pipe( 45 | take(1), 46 | switchMap(token => 47 | liveDataClient.request({ 48 | ...req, 49 | headers: { 50 | ...req.headers, 51 | Authorization: `Bearer ${token}`, 52 | }, 53 | }), 54 | ), 55 | ), 56 | }); 57 | -------------------------------------------------------------------------------- /examples/clients/observable.ts: -------------------------------------------------------------------------------- 1 | import { HTTPClient1 } from '../out/petstore.yaml/client/client'; 2 | import { URI, Monad } from 'fp-ts-rxjs/Observable'; 3 | import { throwError } from 'rxjs'; 4 | import { ajax } from 'rxjs/ajax'; 5 | import { map } from 'rxjs/operators'; 6 | 7 | export const rxjsClient: HTTPClient1 = { 8 | ...Monad, 9 | throwError, 10 | request: ({ body, headers, method, query, url }) => 11 | ajax({ 12 | body: body && JSON.stringify(body), 13 | url: query ? `${url}?${query}` : url, 14 | headers, 15 | method, 16 | }).pipe(map(response => response.response)), 17 | }; 18 | -------------------------------------------------------------------------------- /examples/generate/01-single-spec.ts: -------------------------------------------------------------------------------- 1 | import { generate } from '@devexperts/swagger-codegen-ts'; 2 | import * as path from 'path'; 3 | import { serialize as serializeOpenAPI3 } from '@devexperts/swagger-codegen-ts/dist/language/typescript/3.0'; 4 | import { OpenapiObjectCodec } from '@devexperts/swagger-codegen-ts/dist/schema/3.0/openapi-object'; 5 | import { either } from 'fp-ts'; 6 | 7 | const cwd = path.resolve(__dirname, '../../test/specs/3.0'); 8 | 9 | // Note that the `generate` function does not generate immediately but returns a `TaskEither` 10 | // see: https://dev.to/ryanleecode/practical-guide-to-fp-ts-p3-task-either-taskeither-2hpl 11 | const codegenTask = generate({ 12 | cwd, 13 | spec: path.resolve(cwd, 'petstore.yaml'), 14 | out: path.resolve(__dirname, '../out'), 15 | language: serializeOpenAPI3, 16 | decoder: OpenapiObjectCodec, 17 | }); 18 | 19 | // The result of a `TaskEither` invocation is a promise that is always resolved to an `Either` 20 | // Make sure that Either's left side is handled, otherwise the errors would be silently ignored. 21 | codegenTask().then( 22 | either.fold( 23 | error => { 24 | console.error('Code generation failed', error); 25 | process.exit(1); 26 | }, 27 | () => { 28 | console.log('Generated successfully'); 29 | }, 30 | ), 31 | ); 32 | -------------------------------------------------------------------------------- /examples/generate/02-multiple-specs.ts: -------------------------------------------------------------------------------- 1 | import { generate } from '@devexperts/swagger-codegen-ts'; 2 | import * as path from 'path'; 3 | import { serialize as serializeOpenAPI3 } from '@devexperts/swagger-codegen-ts/dist/language/typescript/3.0'; 4 | import { OpenapiObjectCodec } from '@devexperts/swagger-codegen-ts/dist/schema/3.0/openapi-object'; 5 | import { array, either, taskEither } from 'fp-ts'; 6 | import { pipe } from 'fp-ts/function'; 7 | 8 | const cwd = path.resolve(__dirname, '../../test/specs/3.0'); 9 | const specs = ['nested/link-example.yaml', 'demo.yml']; 10 | 11 | // Create a task for each input spec file 12 | const tasks = pipe( 13 | specs, 14 | array.map(spec => 15 | generate({ 16 | cwd, 17 | spec: path.resolve(cwd, spec), 18 | out: path.resolve(__dirname, '../out'), 19 | language: serializeOpenAPI3, 20 | decoder: OpenapiObjectCodec, 21 | }), 22 | ), 23 | // Notice how the sequence operation is used to run multiple tasks in parallel 24 | taskEither.sequenceArray, 25 | ); 26 | 27 | tasks().then( 28 | either.fold( 29 | error => { 30 | console.error(error); 31 | process.exit(1); 32 | }, 33 | () => { 34 | console.log('Generated successfully'); 35 | }, 36 | ), 37 | ); 38 | -------------------------------------------------------------------------------- /examples/generate/03-cleanup-before-generating.ts: -------------------------------------------------------------------------------- 1 | import { generate } from '@devexperts/swagger-codegen-ts'; 2 | import * as path from 'path'; 3 | import { serialize as serializeOpenAPI3 } from '@devexperts/swagger-codegen-ts/dist/language/typescript/3.0'; 4 | import { OpenapiObjectCodec } from '@devexperts/swagger-codegen-ts/dist/schema/3.0/openapi-object'; 5 | import { taskEither } from 'fp-ts'; 6 | import { pipe } from 'fp-ts/function'; 7 | import { remove } from 'fs-extra'; 8 | import { identity } from 'io-ts'; 9 | 10 | const cwd = path.resolve(__dirname, '../../test/specs/3.0'); 11 | const out = path.resolve(__dirname, '../out'); 12 | 13 | const cleanTask = taskEither.tryCatch(() => remove(out), identity); 14 | 15 | const generateTask = generate({ 16 | cwd, 17 | spec: 'file-and-text.yml', 18 | out, 19 | language: serializeOpenAPI3, 20 | decoder: OpenapiObjectCodec, 21 | }); 22 | 23 | pipe( 24 | [cleanTask, generateTask], 25 | taskEither.sequenceSeqArray, 26 | taskEither.match( 27 | error => { 28 | console.error(error); 29 | process.exit(1); 30 | }, 31 | () => { 32 | console.log('Generated successfully'); 33 | }, 34 | ), 35 | )(); 36 | -------------------------------------------------------------------------------- /examples/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@devexperts/swagger-codegen-ts-examples", 3 | "version": "0.0.1", 4 | "description": "TS generator for swagger spec - examples", 5 | "author": "devexperts", 6 | "license": "MPL-2.0", 7 | "private": true, 8 | "dependencies": { 9 | "@devexperts/remote-data-ts": "^2.0.5", 10 | "fp-ts": "^2.10.5", 11 | "fp-ts-rxjs": "^0.6.15", 12 | "io-ts": "^2.2.16", 13 | "io-ts-types": "^0.5.16", 14 | "rxjs": "^6.6.7", 15 | "typescript": "^4.2.4" 16 | }, 17 | "devDependencies": { 18 | "@devexperts/swagger-codegen-ts": "^2.0.0-alpha.24", 19 | "fs-extra": "^10.0.0", 20 | "ts-node": "^9.1.1" 21 | }, 22 | "scripts": { 23 | "generate": "ts-node generate/01-single-spec.ts" 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /examples/tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "strict": true, 4 | "lib": ["ES6", "DOM"] 5 | } 6 | } 7 | -------------------------------------------------------------------------------- /nodemon.json: -------------------------------------------------------------------------------- 1 | { 2 | "watch": [ 3 | "./test", 4 | "./src" 5 | ], 6 | "ignore": [ 7 | "node_modules", 8 | "dist", 9 | "./test/out" 10 | ], 11 | "ext": "ts,json,yml,yaml", 12 | "optOut": true 13 | } 14 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@devexperts/swagger-codegen-ts", 3 | "version": "2.0.0-alpha.29", 4 | "description": "TS generator for swagger spec", 5 | "main": "dist/index.js", 6 | "scripts": { 7 | "ts-node": "ts-node", 8 | "test:lint": "eslint \"./src/**/*.ts\" \"./test/**/*.ts\" --fix", 9 | "test:build": "tsc -p tsconfig.test.json", 10 | "test:jest": "jest", 11 | "test": "yarn test:lint && yarn prettier && yarn test:jest && yarn test:build", 12 | "prettier": "prettier --list-different \"./src/**/*.ts\" \"./test/**/*.ts\"", 13 | "prettier:fix": "prettier --write \"./src/**/*.ts\" \"./test/**/*.ts\"", 14 | "prepublishOnly": "yarn test && yarn build", 15 | "start": "nodemon --exec \"yarn test:run\"", 16 | "build": "tsc -p tsconfig.build.json", 17 | "changelog": "conventional-changelog -p angular -i CHANGELOG.md -s -r 0", 18 | "version": "yarn changelog && git add CHANGELOG.md" 19 | }, 20 | "author": "devexperts", 21 | "license": "MPL-2.0", 22 | "repository": { 23 | "type": "git", 24 | "url": "git+https://github.com/devexperts/swagger-codegen-ts.git" 25 | }, 26 | "bugs": { 27 | "url": "git+https://github.com/devexperts/swagger-codegen-ts/issues" 28 | }, 29 | "homepage": "https://github.com/devexperts/swagger-codegen-ts#readme", 30 | "publishConfig": { 31 | "access": "public" 32 | }, 33 | "dependencies": { 34 | "@devexperts/utils": "^1.0.0-alpha.10", 35 | "@types/adm-zip": "^0.4.32", 36 | "@types/color": "^3.0.0", 37 | "@types/fs-extra": "^8.0.0", 38 | "@types/prettier": "^1.13.2", 39 | "adm-zip": "^0.4.13", 40 | "color": "^3.1.2", 41 | "eslint-plugin-prettier": "^3.1.1", 42 | "fs-extra": "^8.1.0", 43 | "json-schema-ref-parser": "^7.1.1", 44 | "prettier": "^1.19.1" 45 | }, 46 | "devDependencies": { 47 | "@devexperts/lint": "^1.0.0-alpha.10", 48 | "@types/del": "^4.0.0", 49 | "@types/jest": "^24.0.18", 50 | "conventional-changelog-cli": "^2.1.1", 51 | "del": "^5.1.0", 52 | "eslint": "^6.7.2", 53 | "fast-check": "^1.17.0", 54 | "fp-ts": "^2.1.0", 55 | "io-ts": "^2.0.5", 56 | "io-ts-types": "^0.5.1", 57 | "jest": "^24.9.0", 58 | "nodemon": "^2.0.12", 59 | "ts-jest": "^24.1.0", 60 | "ts-node": "^8.4.1", 61 | "typescript": "^3.6.3" 62 | }, 63 | "peerDependencies": { 64 | "fp-ts": "^2.1.0", 65 | "io-ts": "^2.0.5", 66 | "io-ts-types": "^0.5.1" 67 | }, 68 | "jest": { 69 | "preset": "ts-jest", 70 | "testEnvironment": "node", 71 | "timers": "fake" 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/index.ts: -------------------------------------------------------------------------------- 1 | import { SwaggerObject } from '../../../schema/2.0/swagger-object'; 2 | import { defaultPrettierConfig, SerializeOptions } from '../common/utils'; 3 | import { fragment, FSEntity, map } from '../../../utils/fs'; 4 | import { Dictionary } from '../../../utils/types'; 5 | import { either, record } from 'fp-ts'; 6 | import { pipe } from 'fp-ts/lib/pipeable'; 7 | import { serializeSwaggerObject } from './serializers/swagger-object'; 8 | import { format } from 'prettier'; 9 | import { Either } from 'fp-ts/lib/Either'; 10 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 11 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 12 | 13 | export const serialize = combineReader( 14 | serializeSwaggerObject, 15 | serializeSwaggerObject => ( 16 | documents: Dictionary, 17 | options: SerializeOptions = {}, 18 | ): Either => 19 | pipe( 20 | documents, 21 | record.collect(serializeSwaggerObject), 22 | sequenceEither, 23 | either.map(serialized => 24 | map(fragment(serialized), content => format(content, options.prettierConfig || defaultPrettierConfig)), 25 | ), 26 | ), 27 | ); 28 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/__tests__/responses-object.spec.ts: -------------------------------------------------------------------------------- 1 | import { serializeOperationResponses } from '../responses-object'; 2 | import { constant } from 'fp-ts/lib/function'; 3 | import { fromString } from '../../../../../utils/ref'; 4 | import { pipe } from 'fp-ts/lib/pipeable'; 5 | import { either } from 'fp-ts'; 6 | import { sequenceTEither } from '@devexperts/utils/dist/adt/either.utils'; 7 | import { ResponsesObject } from '../../../../../schema/2.0/responses-object'; 8 | 9 | describe('ResponsesObject', () => { 10 | describe('serializeResponsesObject', () => { 11 | it('should serialize void response if it is the only response type', () => { 12 | const responses = pipe( 13 | ResponsesObject.decode({ 14 | 200: { 15 | description: 'Success (void)', 16 | }, 17 | }), 18 | either.mapLeft(constant(new Error())), 19 | ); 20 | 21 | const result = pipe( 22 | sequenceTEither(fromString('#/test'), responses), 23 | either.chain(([ref, responses]) => serializeOperationResponses(ref, responses)), 24 | ); 25 | 26 | pipe( 27 | result, 28 | either.fold(fail, result => { 29 | expect(result.type).toEqual('void'); 30 | expect(result.io).toEqual('tvoid'); 31 | }), 32 | ); 33 | }); 34 | 35 | it('should include void response into the union if needed', () => { 36 | const responses = pipe( 37 | ResponsesObject.decode({ 38 | 200: { 39 | description: 'Success (void)', 40 | }, 41 | 400: { 42 | description: 'Error', 43 | schema: { 44 | type: 'object', 45 | required: ['code'], 46 | properties: { 47 | code: { 48 | type: 'number', 49 | }, 50 | }, 51 | }, 52 | }, 53 | }), 54 | either.mapLeft(constant(new Error())), 55 | ); 56 | 57 | const result = pipe( 58 | sequenceTEither(fromString('#/test'), responses), 59 | either.chain(([ref, responses]) => serializeOperationResponses(ref, responses)), 60 | ); 61 | 62 | pipe( 63 | result, 64 | either.fold(fail, result => { 65 | expect(result.type).toEqual('void|{ code: number }'); 66 | expect(result.io).toEqual("union([tvoid,type({ code: number }, 'test')])"); 67 | }), 68 | ); 69 | }); 70 | }); 71 | }); 72 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/definitions-object.ts: -------------------------------------------------------------------------------- 1 | import { SchemaObject } from '../../../../schema/2.0/schema-object'; 2 | import { directory, Directory, file, File } from '../../../../utils/fs'; 3 | import { serializeSchemaObject } from './schema-object'; 4 | import { serializeDependencies } from '../../common/data/serialized-dependency'; 5 | import { DefinitionsObject } from '../../../../schema/2.0/definitions-object'; 6 | import { DEFINITIONS_DIRECTORY, getIOName } from '../../common/utils'; 7 | import { pipe } from 'fp-ts/lib/pipeable'; 8 | import { either, record } from 'fp-ts'; 9 | import { Either } from 'fp-ts/lib/Either'; 10 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 11 | import { addPathParts, Ref } from '../../../../utils/ref'; 12 | 13 | export const serializeDefinitions = (from: Ref, definitions: DefinitionsObject): Either => 14 | pipe( 15 | definitions, 16 | record.collect((name, definition) => 17 | pipe( 18 | from, 19 | addPathParts(name), 20 | either.chain(from => serializeDefinition(from, name, definition)), 21 | ), 22 | ), 23 | sequenceEither, 24 | either.map(serialized => directory(DEFINITIONS_DIRECTORY, serialized)), 25 | ); 26 | 27 | const serializeDefinition = (from: Ref, name: string, definition: SchemaObject): Either => 28 | pipe( 29 | serializeSchemaObject(from, definition), 30 | either.map(serialized => { 31 | const dependencies = serializeDependencies(serialized.dependencies); 32 | return file( 33 | `${name}.ts`, 34 | ` 35 | ${dependencies} 36 | 37 | export type ${name} = ${serialized.type}; 38 | export const ${getIOName(name)} = ${serialized.io}; 39 | `, 40 | ); 41 | }), 42 | ); 43 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/items-object.ts: -------------------------------------------------------------------------------- 1 | import { ItemsObject } from '../../../../schema/2.0/items-object'; 2 | import { 3 | getSerializedArrayType, 4 | getSerializedStringType, 5 | SERIALIZED_BOOLEAN_TYPE, 6 | SERIALIZED_INTEGER_TYPE, 7 | SERIALIZED_NUMBER_TYPE, 8 | SerializedType, 9 | } from '../../common/data/serialized-type'; 10 | import { Ref } from '../../../../utils/ref'; 11 | import { pipe } from 'fp-ts/lib/pipeable'; 12 | import { either } from 'fp-ts'; 13 | import { Either, right } from 'fp-ts/lib/Either'; 14 | import { none } from 'fp-ts/lib/Option'; 15 | 16 | export const serializeItemsObject = (from: Ref, itemsObject: ItemsObject): Either => { 17 | switch (itemsObject.type) { 18 | case 'array': { 19 | return pipe(serializeItemsObject(from, itemsObject.items), either.map(getSerializedArrayType(none))); 20 | } 21 | case 'string': { 22 | return getSerializedStringType(from, itemsObject.format); 23 | } 24 | case 'number': { 25 | return right(SERIALIZED_NUMBER_TYPE); 26 | } 27 | case 'integer': { 28 | return right(SERIALIZED_INTEGER_TYPE); 29 | } 30 | case 'boolean': { 31 | return right(SERIALIZED_BOOLEAN_TYPE); 32 | } 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/parameter-object.ts: -------------------------------------------------------------------------------- 1 | import { Ref } from '../../../../utils/ref'; 2 | import { ParameterObject } from '../../../../schema/2.0/parameter-object'; 3 | import { 4 | getSerializedArrayType, 5 | getSerializedStringType, 6 | SERIALIZED_BOOLEAN_TYPE, 7 | SERIALIZED_INTEGER_TYPE, 8 | SERIALIZED_NUMBER_TYPE, 9 | SERIALIZED_UNKNOWN_TYPE, 10 | } from '../../common/data/serialized-type'; 11 | import { serializeItemsObject } from './items-object'; 12 | import { serializeSchemaObject } from './schema-object'; 13 | import { Either, right } from 'fp-ts/lib/Either'; 14 | import { fromSerializedType, SerializedParameter } from '../../common/data/serialized-parameter'; 15 | import { pipe } from 'fp-ts/lib/pipeable'; 16 | import { either, option } from 'fp-ts'; 17 | import { constFalse } from 'fp-ts/lib/function'; 18 | import { none } from 'fp-ts/lib/Option'; 19 | 20 | export const serializeParameterObject = ( 21 | from: Ref, 22 | parameterObject: ParameterObject, 23 | ): Either => { 24 | const toSerializedParameter = fromSerializedType(isRequired(parameterObject)); 25 | switch (parameterObject.in) { 26 | case 'path': 27 | case 'query': 28 | case 'header': 29 | case 'formData': { 30 | switch (parameterObject.type) { 31 | case 'string': { 32 | return pipe( 33 | getSerializedStringType(from, parameterObject.format), 34 | either.map(toSerializedParameter), 35 | ); 36 | } 37 | case 'number': { 38 | return right(toSerializedParameter(SERIALIZED_NUMBER_TYPE)); 39 | } 40 | case 'integer': { 41 | return right(toSerializedParameter(SERIALIZED_INTEGER_TYPE)); 42 | } 43 | case 'boolean': { 44 | return right(toSerializedParameter(SERIALIZED_BOOLEAN_TYPE)); 45 | } 46 | case 'array': { 47 | return pipe( 48 | serializeItemsObject(from, parameterObject.items), 49 | either.map(getSerializedArrayType(none)), 50 | either.map(toSerializedParameter), 51 | ); 52 | } 53 | case 'file': 54 | return right(toSerializedParameter(SERIALIZED_UNKNOWN_TYPE)); 55 | } 56 | } 57 | case 'body': { 58 | return pipe(serializeSchemaObject(from, parameterObject.schema), either.map(toSerializedParameter)); 59 | } 60 | } 61 | }; 62 | 63 | export const isRequired = (parameterObject: ParameterObject): boolean => 64 | parameterObject.in === 'path' 65 | ? parameterObject.required 66 | : pipe(parameterObject.required, option.getOrElse(constFalse)); 67 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/parameters-definitions-object.ts: -------------------------------------------------------------------------------- 1 | import { ParametersDefinitionsObject } from '../../../../schema/2.0/parameters-definitions-object'; 2 | import { Either } from 'fp-ts/lib/Either'; 3 | import { directory, file, FSEntity } from '../../../../utils/fs'; 4 | import { pipe } from 'fp-ts/lib/pipeable'; 5 | import { either, record } from 'fp-ts'; 6 | import { ParameterObject } from '../../../../schema/2.0/parameter-object'; 7 | import { addPathParts, Ref } from '../../../../utils/ref'; 8 | import { serializeDependencies } from '../../common/data/serialized-dependency'; 9 | import { getIOName, getTypeName } from '../../common/utils'; 10 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 11 | import { serializeParameterObject } from './parameter-object'; 12 | 13 | export const serializeParametersDefinitionsObject = ( 14 | from: Ref, 15 | parametersDefinitionsObject: ParametersDefinitionsObject, 16 | ): Either => 17 | pipe( 18 | parametersDefinitionsObject, 19 | record.collect((name, parameterObject) => 20 | pipe( 21 | from, 22 | addPathParts(name), 23 | either.chain(from => serializeParameter(from, parameterObject)), 24 | ), 25 | ), 26 | sequenceEither, 27 | either.map(content => directory('parameters', content)), 28 | ); 29 | 30 | const serializeParameter = (from: Ref, parameterObject: ParameterObject): Either => 31 | pipe( 32 | serializeParameterObject(from, parameterObject), 33 | either.map(serialized => { 34 | const dependencies = serializeDependencies(serialized.dependencies); 35 | return file( 36 | `${from.name}.ts`, 37 | ` 38 | ${dependencies} 39 | 40 | export type ${getTypeName(from.name)} = ${serialized.type}; 41 | export const ${getIOName(from.name)} = ${serialized.io}; 42 | `, 43 | ); 44 | }), 45 | ); 46 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/response-object.ts: -------------------------------------------------------------------------------- 1 | import { ResponseObject } from '../../../../schema/2.0/response-object'; 2 | import { SerializedType, SERIALIZED_VOID_TYPE } from '../../common/data/serialized-type'; 3 | import { pipe } from 'fp-ts/lib/pipeable'; 4 | import { serializeSchemaObject } from './schema-object'; 5 | import { Either, right } from 'fp-ts/lib/Either'; 6 | import { Ref } from '../../../../utils/ref'; 7 | import { option } from 'fp-ts'; 8 | 9 | export const serializeResponseObject = (from: Ref, response: ResponseObject): Either => 10 | pipe( 11 | response.schema, 12 | option.fold( 13 | () => right(SERIALIZED_VOID_TYPE), 14 | schema => serializeSchemaObject(from, schema), 15 | ), 16 | ); 17 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/responses-definitions-object.ts: -------------------------------------------------------------------------------- 1 | import { getIOName, getTypeName } from '../../common/utils'; 2 | import { addPathParts, Ref } from '../../../../utils/ref'; 3 | import { ResponsesDefinitionsObject } from '../../../../schema/2.0/responses-definitions-object'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | import { directory, file, FSEntity } from '../../../../utils/fs'; 6 | import { pipe } from 'fp-ts/lib/pipeable'; 7 | import { either, record } from 'fp-ts'; 8 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 9 | import { ResponseObject } from '../../../../schema/2.0/response-object'; 10 | import { serializeResponseObject } from './response-object'; 11 | import { serializeDependencies } from '../../common/data/serialized-dependency'; 12 | 13 | export const serializeResponsesDefinitionsObject = ( 14 | from: Ref, 15 | responsesDefinitionsObject: ResponsesDefinitionsObject, 16 | ): Either => 17 | pipe( 18 | responsesDefinitionsObject, 19 | record.collect((name, parameterObject) => 20 | pipe( 21 | from, 22 | addPathParts(name), 23 | either.chain(from => serializeResponse(from, parameterObject)), 24 | ), 25 | ), 26 | sequenceEither, 27 | either.map(content => directory('responses', content)), 28 | ); 29 | 30 | const serializeResponse = (from: Ref, responseObject: ResponseObject): Either => 31 | pipe( 32 | serializeResponseObject(from, responseObject), 33 | either.map(serialized => { 34 | const dependencies = serializeDependencies(serialized.dependencies); 35 | return file( 36 | `${from.name}.ts`, 37 | ` 38 | ${dependencies} 39 | 40 | export type ${getTypeName(from.name)} = ${serialized.type}; 41 | export const ${getIOName(from.name)} = ${serialized.io}; 42 | `, 43 | ); 44 | }), 45 | ); 46 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/responses-object.ts: -------------------------------------------------------------------------------- 1 | import { ResponsesObject } from '../../../../schema/2.0/responses-object'; 2 | import { 3 | getSerializedRefType, 4 | intercalateSerializedTypes, 5 | SERIALIZED_VOID_TYPE, 6 | serializedType, 7 | SerializedType, 8 | uniqSerializedTypesByTypeAndIO, 9 | } from '../../common/data/serialized-type'; 10 | import { pipe } from 'fp-ts/lib/pipeable'; 11 | import { serializeResponseObject } from './response-object'; 12 | import { serializedDependency } from '../../common/data/serialized-dependency'; 13 | import { concatIfL } from '../../../../utils/array'; 14 | import { either, record } from 'fp-ts'; 15 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 16 | import { Either } from 'fp-ts/lib/Either'; 17 | import { fromString, Ref } from '../../../../utils/ref'; 18 | import { ReferenceObjectCodec } from '../../../../schema/3.0/reference-object'; 19 | 20 | export const serializeOperationResponses = (from: Ref, responses: ResponsesObject): Either => 21 | pipe( 22 | responses, 23 | record.collect((code, response) => { 24 | if (ReferenceObjectCodec.is(response)) { 25 | return pipe(fromString(response.$ref), either.map(getSerializedRefType(from))); 26 | } else { 27 | return serializeResponseObject(from, response); 28 | } 29 | }), 30 | sequenceEither, 31 | either.map(responses => { 32 | const serializedResponses = uniqSerializedTypesByTypeAndIO(responses); 33 | if (serializedResponses.length === 0) { 34 | return SERIALIZED_VOID_TYPE; 35 | } 36 | const combined = intercalateSerializedTypes(serializedType('|', ',', [], []), serializedResponses); 37 | 38 | const isUnion = serializedResponses.length > 1; 39 | 40 | return serializedType( 41 | combined.type, 42 | isUnion ? `union([${combined.io}])` : combined.io, 43 | concatIfL(isUnion, combined.dependencies, () => [serializedDependency('union', 'io-ts')]), 44 | [], 45 | ); 46 | }), 47 | ); 48 | -------------------------------------------------------------------------------- /src/language/typescript/2.0/serializers/swagger-object.ts: -------------------------------------------------------------------------------- 1 | import { directory, Directory } from '../../../../utils/fs'; 2 | import { pipe } from 'fp-ts/lib/pipeable'; 3 | import { serializeDefinitions } from './definitions-object'; 4 | import { serializePaths } from './paths-object'; 5 | import { pathsRef } from '../../common/utils'; 6 | import { Either } from 'fp-ts/lib/Either'; 7 | import { array, either, option } from 'fp-ts'; 8 | import { combineEither, sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 9 | import { SwaggerObject } from '../../../../schema/2.0/swagger-object'; 10 | import { fromString } from '../../../../utils/ref'; 11 | import { clientFile } from '../../common/bundled/client'; 12 | import { serializeParametersDefinitionsObject } from './parameters-definitions-object'; 13 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 14 | import { serializeResponsesDefinitionsObject } from './responses-definitions-object'; 15 | import { utilsFile } from '../../common/bundled/utils'; 16 | 17 | const definitionsRef = fromString('#/definitions'); 18 | const parametersRef = fromString('#/parameters'); 19 | const responsesRef = fromString('#/responses'); 20 | 21 | export const serializeSwaggerObject = combineReader( 22 | serializePaths, 23 | serializePaths => (name: string, swaggerObject: SwaggerObject): Either => { 24 | const definitions = pipe( 25 | swaggerObject.definitions, 26 | option.map(definitions => 27 | pipe( 28 | definitionsRef, 29 | either.chain(from => serializeDefinitions(from, definitions)), 30 | ), 31 | ), 32 | ); 33 | const parameters = pipe( 34 | swaggerObject.parameters, 35 | option.map(parameters => 36 | pipe( 37 | parametersRef, 38 | either.chain(ref => serializeParametersDefinitionsObject(ref, parameters)), 39 | ), 40 | ), 41 | ); 42 | const responses = pipe( 43 | swaggerObject.responses, 44 | option.map(responses => 45 | pipe( 46 | responsesRef, 47 | either.chain(ref => serializeResponsesDefinitionsObject(ref, responses)), 48 | ), 49 | ), 50 | ); 51 | const additional = pipe([definitions, parameters, responses], array.compact, sequenceEither); 52 | const paths = pipe( 53 | pathsRef, 54 | either.chain(from => serializePaths(from, swaggerObject.paths)), 55 | ); 56 | return combineEither(additional, paths, clientFile, utilsFile, (additional, paths, clientFile, utilsFile) => 57 | directory(name, [clientFile, ...additional, utilsFile, paths]), 58 | ); 59 | }, 60 | ); 61 | -------------------------------------------------------------------------------- /src/language/typescript/3.0/index.ts: -------------------------------------------------------------------------------- 1 | import { serializeDocument } from './serializers/document'; 2 | import { format } from 'prettier'; 3 | import { fragment, FSEntity, map as mapFS } from '../../../utils/fs'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | import { pipe } from 'fp-ts/lib/pipeable'; 6 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 7 | import { either, record } from 'fp-ts'; 8 | import { Dictionary } from '../../../utils/types'; 9 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 10 | import { OpenapiObject } from '../../../schema/3.0/openapi-object'; 11 | import { defaultPrettierConfig, SerializeOptions } from '../common/utils'; 12 | 13 | export { serializeDocument } from './serializers/document'; 14 | 15 | export const serialize = combineReader( 16 | serializeDocument, 17 | serializeDocument => ( 18 | documents: Dictionary, 19 | options: SerializeOptions = {}, 20 | ): Either => 21 | pipe( 22 | documents, 23 | record.collect(serializeDocument), 24 | sequenceEither, 25 | either.map(e => 26 | mapFS(fragment(e), content => format(content, options.prettierConfig || defaultPrettierConfig)), 27 | ), 28 | ), 29 | ); 30 | -------------------------------------------------------------------------------- /src/language/typescript/3.0/serializers/__tests__/operation-object.spec.ts: -------------------------------------------------------------------------------- 1 | import { getParameters as createGetParameters } from '../operation-object'; 2 | import { constant } from 'fp-ts/lib/function'; 3 | import { left } from 'fp-ts/lib/Either'; 4 | import { fromString } from '../../../../../utils/ref'; 5 | import { PathItemObjectCodec } from '../../../../../schema/3.0/path-item-object'; 6 | import { pipe } from 'fp-ts/lib/pipeable'; 7 | import { either, option } from 'fp-ts'; 8 | import { OperationObjectCodec } from '../../../../../schema/3.0/operation-object'; 9 | import { sequenceTEither } from '@devexperts/utils/dist/adt/either.utils'; 10 | import { normalizeCodeSnippet } from '../../../../../../test/utils'; 11 | 12 | describe('OperationObject', () => { 13 | describe('getParameters', () => { 14 | const getParameters = createGetParameters({ 15 | resolveRef: constant(left(new Error('Refs not supported'))), 16 | }); 17 | 18 | it('should correctly handle primitive query parameters', () => { 19 | const operation = pipe( 20 | OperationObjectCodec.decode({ 21 | responses: {}, 22 | parameters: [ 23 | { 24 | in: 'query', 25 | name: 'offset', 26 | required: false, 27 | schema: { 28 | type: 'number', 29 | }, 30 | }, 31 | { 32 | in: 'query', 33 | name: 'limit', 34 | required: true, 35 | schema: { 36 | type: 'number', 37 | }, 38 | }, 39 | ], 40 | }), 41 | either.mapLeft(constant(new Error())), 42 | ); 43 | 44 | const pathItem = pipe(PathItemObjectCodec.decode({}), either.mapLeft(constant(new Error()))); 45 | 46 | const result = pipe( 47 | sequenceTEither(fromString('#/test'), operation, pathItem), 48 | either.chain(([ref, operation, pathItem]) => getParameters(ref, operation, pathItem)), 49 | ); 50 | 51 | const generated = pipe( 52 | result, 53 | option.fromEither, 54 | option.chain(result => result.serializedQueryString), 55 | option.fold(constant(''), fragment => normalizeCodeSnippet(fragment.value)), 56 | ); 57 | 58 | expect(generated).toEqual( 59 | normalizeCodeSnippet(` 60 | compact([ 61 | pipe( 62 | optionFromNullable(number).encode(parameters.query['offset']), 63 | option.fromNullable, 64 | option.chain(value => fromEither(serializePrimitiveParameter('form', 'offset', value))), 65 | ), 66 | pipe( 67 | number.encode(parameters.query['limit']), 68 | value => fromEither(serializePrimitiveParameter('form', 'limit', value)), 69 | ) 70 | ]).join('&') 71 | `), 72 | ); 73 | }); 74 | }); 75 | }); 76 | -------------------------------------------------------------------------------- /src/language/typescript/3.0/serializers/document.ts: -------------------------------------------------------------------------------- 1 | import { directory, Directory } from '../../../../utils/fs'; 2 | import { serializePathsObject } from './paths-object'; 3 | import { pipe } from 'fp-ts/lib/pipeable'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 6 | import { serializeComponentsObject } from './components-object'; 7 | import { combineEither, sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 8 | import { fromString } from '../../../../utils/ref'; 9 | import { array, either, option } from 'fp-ts'; 10 | import { applyTo } from '../../../../utils/function'; 11 | import { OpenapiObject } from '../../../../schema/3.0/openapi-object'; 12 | import { pathsRef } from '../../common/utils'; 13 | import { clientFile } from '../../common/bundled/client'; 14 | import { openapi3utilsFile } from '../bundled/openapi-3-utils'; 15 | import { utilsFile } from '../../common/bundled/utils'; 16 | 17 | export const serializeDocument = combineReader( 18 | serializeComponentsObject, 19 | serializePathsObject, 20 | (serializeComponentsObject, serializePathsObject) => ( 21 | name: string, 22 | document: OpenapiObject, 23 | ): Either => { 24 | const componentsRef = fromString('#/components'); 25 | 26 | const paths = pipe(pathsRef, either.map(serializePathsObject), either.chain(applyTo(document.paths))); 27 | 28 | const components = pipe( 29 | document.components, 30 | option.map(components => 31 | pipe(componentsRef, either.map(serializeComponentsObject), either.chain(applyTo(components))), 32 | ), 33 | ); 34 | 35 | const additional = pipe(array.compact([components]), sequenceEither); 36 | return combineEither( 37 | paths, 38 | additional, 39 | clientFile, 40 | utilsFile, 41 | openapi3utilsFile, 42 | (paths, additional, clientFile, utilsFile, openapi3utilsFile) => 43 | directory(name, [paths, ...additional, clientFile, utilsFile, openapi3utilsFile]), 44 | ); 45 | }, 46 | ); 47 | -------------------------------------------------------------------------------- /src/language/typescript/3.0/serializers/path-item-object.ts: -------------------------------------------------------------------------------- 1 | import { flatten } from 'fp-ts/lib/Array'; 2 | import { uniqString } from '../../../../utils/array'; 3 | import { foldSerializedTypes, SerializedType } from '../../common/data/serialized-type'; 4 | import { serializeOperationObject } from './operation-object'; 5 | import { pipe } from 'fp-ts/lib/pipeable'; 6 | import { Either } from 'fp-ts/lib/Either'; 7 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 8 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 9 | import { array, either, nonEmptyArray, option } from 'fp-ts'; 10 | import { Ref } from '../../../../utils/ref'; 11 | import { PathItemObject } from '../../../../schema/3.0/path-item-object'; 12 | import { Option } from 'fp-ts/lib/Option'; 13 | import { Kind } from '../../../../utils/types'; 14 | 15 | export const serializePathItemObject = combineReader( 16 | serializeOperationObject, 17 | serializeOperationObject => ( 18 | pattern: string, 19 | item: PathItemObject, 20 | from: Ref, 21 | kind: Kind, 22 | ): Either => { 23 | const get = pipe( 24 | item.get, 25 | option.map(operation => serializeOperationObject(pattern, 'GET', from, kind, operation, item)), 26 | ); 27 | const post = pipe( 28 | item.post, 29 | option.map(operation => serializeOperationObject(pattern, 'POST', from, kind, operation, item)), 30 | ); 31 | const put = pipe( 32 | item.put, 33 | option.map(operation => serializeOperationObject(pattern, 'PUT', from, kind, operation, item)), 34 | ); 35 | const remove = pipe( 36 | item.delete, 37 | option.map(operation => serializeOperationObject(pattern, 'DELETE', from, kind, operation, item)), 38 | ); 39 | const patch = pipe( 40 | item.patch, 41 | option.map(operation => serializeOperationObject(pattern, 'PATCH', from, kind, operation, item)), 42 | ); 43 | const head = pipe( 44 | item.head, 45 | option.map(operation => serializeOperationObject(pattern, 'HEAD', from, kind, operation, item)), 46 | ); 47 | const options = pipe( 48 | item.options, 49 | option.map(operation => serializeOperationObject(pattern, 'OPTIONS', from, kind, operation, item)), 50 | ); 51 | return pipe( 52 | array.compact([get, post, put, remove, patch, head, options]), 53 | sequenceEither, 54 | either.map(foldSerializedTypes), 55 | ); 56 | }, 57 | ); 58 | 59 | export const serializePathItemObjectTags = (pathItemObject: PathItemObject): Option => { 60 | const operations = [ 61 | pathItemObject.get, 62 | pathItemObject.post, 63 | pathItemObject.put, 64 | pathItemObject.delete, 65 | pathItemObject.options, 66 | pathItemObject.head, 67 | pathItemObject.patch, 68 | pathItemObject.trace, 69 | ]; 70 | return pipe( 71 | nonEmptyArray.fromArray(array.compact(operations)), 72 | option.map(operations => uniqString(flatten(array.compact(operations.map(operation => operation.tags))))), 73 | option.chain(nonEmptyArray.fromArray), 74 | option.map(tags => tags.join('').replace(/\s/g, '')), 75 | ); 76 | }; 77 | -------------------------------------------------------------------------------- /src/language/typescript/3.0/serializers/request-body-object.ts: -------------------------------------------------------------------------------- 1 | import { serializeSchemaObject } from './schema-object'; 2 | import { 3 | getSerializedBlobType, 4 | getSerializedRefType, 5 | SerializedType, 6 | SERIALIZED_STRING_TYPE, 7 | } from '../../common/data/serialized-type'; 8 | import { Either, mapLeft } from 'fp-ts/lib/Either'; 9 | import { pipe } from 'fp-ts/lib/pipeable'; 10 | import { either, option } from 'fp-ts'; 11 | import { fromString, Ref } from '../../../../utils/ref'; 12 | import { RequestBodyObject } from '../../../../schema/3.0/request-body-object'; 13 | import { ReferenceObjectCodec, ReferenceObject } from '../../../../schema/3.0/reference-object'; 14 | import { SchemaObject } from '../../../../schema/3.0/schema-object'; 15 | import { getKeyMatchValue, getResponseTypeFromMediaType, XHRResponseType } from '../../common/utils'; 16 | import { MediaTypeObject } from '../../../../schema/3.0/media-type-object'; 17 | 18 | const requestMediaRegexp = /^(video|audio|image|application|text|multipart|\*)\/(\w+|\*)/; 19 | export const getRequestMedia = (content: Record) => 20 | getKeyMatchValue(content, requestMediaRegexp); 21 | 22 | export const serializeRequestBodyObject = (from: Ref, body: RequestBodyObject): Either => 23 | pipe( 24 | getRequestMedia(body.content), 25 | option.chain(({ key: mediaType, value: { schema } }) => 26 | pipe( 27 | schema, 28 | option.map(schema => ({ mediaType, schema })), 29 | ), 30 | ), 31 | either.fromOption(() => new Error('No schema found for ReqeustBodyObject')), 32 | either.chain(({ mediaType, schema }) => { 33 | const resType = getResponseTypeFromMediaType(mediaType); 34 | return serializeRequestSchema(resType, schema, from); 35 | }), 36 | ); 37 | 38 | const serializeRequestSchema = ( 39 | responseType: XHRResponseType, 40 | schema: ReferenceObject | SchemaObject, 41 | from: Ref, 42 | ): Either => { 43 | switch (responseType) { 44 | case 'json': 45 | return ReferenceObjectCodec.is(schema) 46 | ? pipe( 47 | fromString(schema.$ref), 48 | mapLeft( 49 | () => new Error(`Invalid MediaObject.content.$ref "${schema.$ref}" for RequestBodyObject`), 50 | ), 51 | either.map(getSerializedRefType(from)), 52 | ) 53 | : serializeSchemaObject(from)(schema); 54 | case 'text': 55 | return either.right(SERIALIZED_STRING_TYPE); 56 | case 'blob': 57 | return getSerializedBlobType(from); 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /src/language/typescript/3.0/serializers/response-maps.ts: -------------------------------------------------------------------------------- 1 | import { array, either, option } from 'fp-ts'; 2 | import { pipe } from 'fp-ts/lib/pipeable'; 3 | import { flow } from 'fp-ts/lib/function'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | import { Option } from 'fp-ts/lib/Option'; 6 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 7 | import { getOperationName } from './operation-object'; 8 | import { serializeResponsesObject } from './responses-object'; 9 | import { HTTPMethod } from '../../common/utils'; 10 | import { foldSerializedTypes, serializedType, SerializedType } from '../../common/data/serialized-type'; 11 | import { Ref } from '../../../../utils/ref'; 12 | import { PathItemObject } from '../../../../schema/3.0/path-item-object'; 13 | import { OperationObject } from '../../../../schema/3.0/operation-object'; 14 | 15 | const serializeResponseMap = ( 16 | pattern: string, 17 | method: HTTPMethod, 18 | from: Ref, 19 | operation: OperationObject, 20 | ): Either => { 21 | const operationName = getOperationName(pattern, operation, method); 22 | const serializedResponses = serializeResponsesObject(from)(operation.responses); 23 | return pipe( 24 | serializedResponses, 25 | either.map( 26 | flow( 27 | either.fold( 28 | () => serializedType('', '', [], []), 29 | sr => { 30 | const rows = sr.map(s => `'${s.mediaType}': ${s.schema.type};`); 31 | const type = `type MapToResponse${operationName} = {${rows.join('')}};`; 32 | return serializedType(type, '', [], []); // dependecies in serializeOperationObject serializedResponses 33 | }, 34 | ), 35 | ), 36 | ), 37 | ); 38 | }; 39 | 40 | export const serializeResponseMaps = ( 41 | pattern: string, 42 | item: PathItemObject, 43 | from: Ref, 44 | ): Either => { 45 | const methods: [HTTPMethod, Option][] = [ 46 | ['GET', item.get], 47 | ['POST', item.post], 48 | ['PUT', item.put], 49 | ['DELETE', item.delete], 50 | ['PATCH', item.patch], 51 | ['HEAD', item.head], 52 | ['OPTIONS', item.options], 53 | ]; 54 | 55 | return pipe( 56 | methods, 57 | array.map(([method, opObject]) => 58 | pipe( 59 | opObject, 60 | option.map(operation => serializeResponseMap(pattern, method, from, operation)), 61 | ), 62 | ), 63 | array.compact, 64 | sequenceEither, 65 | either.map(foldSerializedTypes), 66 | ); 67 | }; 68 | -------------------------------------------------------------------------------- /src/language/typescript/asyncapi-2.0.0/index.ts: -------------------------------------------------------------------------------- 1 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 2 | import { AsyncAPIObject } from '../../../schema/asyncapi-2.0.0/asyncapi-object'; 3 | import { defaultPrettierConfig, SerializeOptions } from '../common/utils'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | import { fragment, FSEntity, map as mapFS } from '../../../utils/fs'; 6 | import { pipe } from 'fp-ts/lib/pipeable'; 7 | import { either, record } from 'fp-ts'; 8 | import { format } from 'prettier'; 9 | import { serializeAsyncAPIObject } from './serializers/asyncapi-object'; 10 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 11 | 12 | export const serialize = combineReader( 13 | serializeAsyncAPIObject, 14 | serializeAsyncAPIObject => ( 15 | documents: Record, 16 | options: SerializeOptions = {}, 17 | ): Either => 18 | pipe( 19 | documents, 20 | record.collect(serializeAsyncAPIObject), 21 | sequenceEither, 22 | either.map(e => 23 | mapFS(fragment(e), content => format(content, options.prettierConfig || defaultPrettierConfig)), 24 | ), 25 | ), 26 | ); 27 | -------------------------------------------------------------------------------- /src/language/typescript/asyncapi-2.0.0/serializers/asyncapi-object.ts: -------------------------------------------------------------------------------- 1 | import { AsyncAPIObject } from '../../../../schema/asyncapi-2.0.0/asyncapi-object'; 2 | import { Either } from 'fp-ts/lib/Either'; 3 | import { directory, FSEntity } from '../../../../utils/fs'; 4 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 5 | import { serializeComponentsObject } from './components-object'; 6 | import { fromString } from '../../../../utils/ref'; 7 | import { pipe } from 'fp-ts/lib/pipeable'; 8 | import { array, either, option } from 'fp-ts'; 9 | import { combineEither, sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 10 | import { serializeChannelsObject } from './channels-object'; 11 | import { clientFile } from '../../common/bundled/client'; 12 | import { utilsFile } from '../../common/bundled/utils'; 13 | 14 | export const serializeAsyncAPIObject = combineReader( 15 | serializeComponentsObject, 16 | serializeChannelsObject, 17 | (serializeComponentsObject, serializeChannelsObject) => ( 18 | name: string, 19 | asyncAPIObject: AsyncAPIObject, 20 | ): Either => { 21 | const components = pipe( 22 | asyncAPIObject.components, 23 | option.map(components => 24 | pipe( 25 | fromString('#/components'), 26 | either.chain(from => serializeComponentsObject(from, components)), 27 | either.map(content => directory('components', [content])), 28 | ), 29 | ), 30 | ); 31 | const additional = pipe(array.compact([components]), sequenceEither); 32 | const channels = pipe( 33 | fromString('#/channels'), 34 | either.chain(from => serializeChannelsObject(from, asyncAPIObject.channels)), 35 | either.map(content => directory('channels', [content])), 36 | ); 37 | return combineEither( 38 | channels, 39 | additional, 40 | clientFile, 41 | utilsFile, 42 | (channels, additional, clientFile, utilsFile) => 43 | directory(name, [channels, clientFile, ...additional, utilsFile]), 44 | ); 45 | }, 46 | ); 47 | -------------------------------------------------------------------------------- /src/language/typescript/asyncapi-2.0.0/serializers/message-object.ts: -------------------------------------------------------------------------------- 1 | import { fromString, Ref } from '../../../../utils/ref'; 2 | import { MessageObject } from '../../../../schema/asyncapi-2.0.0/message-object'; 3 | import { Either } from 'fp-ts/lib/Either'; 4 | import { getSerializedRefType, SerializedType } from '../../common/data/serialized-type'; 5 | import { pipe } from 'fp-ts/lib/pipeable'; 6 | import { either } from 'fp-ts'; 7 | import { ReferenceObjectCodec } from '../../../../schema/asyncapi-2.0.0/reference-object'; 8 | import { serializeSchemaObject } from './schema-object'; 9 | 10 | export const serializeMessageObject = (from: Ref, messageObject: MessageObject): Either => 11 | ReferenceObjectCodec.is(messageObject.payload) 12 | ? pipe(fromString(messageObject.payload.$ref), either.map(getSerializedRefType(from))) 13 | : serializeSchemaObject(from, messageObject.payload); 14 | -------------------------------------------------------------------------------- /src/language/typescript/common/__tests__/utils.spec.ts: -------------------------------------------------------------------------------- 1 | import { getIOName, getTypeName } from '../utils'; 2 | 3 | describe('typescript/common/utils', () => { 4 | it('getTypeName', () => { 5 | expect(getTypeName('37sds afd,asd.324sfa as2_+=')).toBe('_37sds_afd_asd_324sfa_as2___'); 6 | }); 7 | it('getIOName', () => { 8 | expect(getIOName('37sds afd,asd.324sfa as2_+=')).toBe('_37sds_afd_asd_324sfa_as2___IO'); 9 | }); 10 | }); 11 | -------------------------------------------------------------------------------- /src/language/typescript/common/bundled/__tests__/client.spec.ts: -------------------------------------------------------------------------------- 1 | import * as typescript from 'typescript'; 2 | import { client } from '../client'; 3 | 4 | describe('client', () => { 5 | describe('ResponseValidationError class', () => { 6 | it('should produce uniquely identifiable instance of itself', () => { 7 | const exports = {} as any; 8 | 9 | const clientCodeTranspiled = typescript.transpile(client, { 10 | target: typescript.ScriptTarget.ESNext, 11 | module: typescript.ModuleKind.None, 12 | }); 13 | 14 | // eslint-disable-next-line no-eval 15 | eval(clientCodeTranspiled); 16 | 17 | expect(exports.ResponseValidationError.create([])).toBeInstanceOf(exports.ResponseValidationError); 18 | expect(exports.ResponseValidationError.create([])).toBeInstanceOf(Error); 19 | }); 20 | it('should produce instance that not crashing when its casted to string', () => { 21 | const exports = {} as any; 22 | const clientCodeTranspiled = typescript.transpile(client, { 23 | target: typescript.ScriptTarget.ESNext, 24 | module: typescript.ModuleKind.None, 25 | }); 26 | 27 | // eslint-disable-next-line no-eval 28 | eval(clientCodeTranspiled); 29 | 30 | expect(() => String(exports.ResponseValidationError.create([]))).not.toThrow(); 31 | }); 32 | }); 33 | }); 34 | -------------------------------------------------------------------------------- /src/language/typescript/common/bundled/utils.ts: -------------------------------------------------------------------------------- 1 | import { fromString } from '../../../../utils/ref'; 2 | import { pipe } from 'fp-ts/lib/pipeable'; 3 | import { either } from 'fp-ts'; 4 | import { fromRef } from '../../../../utils/fs'; 5 | 6 | export const utilsRef = fromString('#/utils/utils'); 7 | 8 | const utils = ` 9 | import { either, left, right } from 'fp-ts/lib/Either'; 10 | import { 11 | Type, 12 | type, 13 | TypeOf, 14 | failure, 15 | success, 16 | string as tstring, 17 | literal, 18 | Validate, 19 | Context, 20 | getValidationError, 21 | } from 'io-ts'; 22 | 23 | export const DateFromISODateStringIO = new Type( 24 | 'DateFromISODateString', 25 | (u): u is Date => u instanceof Date, 26 | (u, c) => 27 | either.chain(tstring.validate(u, c), dateString => { 28 | const [year, calendarMonth, day] = dateString.split('-'); 29 | const d = new Date(+year, +calendarMonth - 1, +day); 30 | return isNaN(d.getTime()) ? failure(u, c) : success(d); 31 | }), 32 | a => 33 | \`\${a.getFullYear().toString().padStart(4, '0')}-\${(a.getMonth() + 1).toString().padStart(2, '0')}-\${a 34 | .getDate() 35 | .toString() 36 | .padStart(2, '0')}\`, 37 | ); 38 | 39 | export type Base64 = TypeOf; 40 | 41 | export const Base64IO = type({ 42 | string: tstring, 43 | format: literal('base64'), 44 | }); 45 | 46 | export const Base64FromStringIO = new Type( 47 | 'Base64FromString', 48 | (u): u is Base64 => Base64IO.is(u), 49 | (u, c) => either.chain(tstring.validate(u, c), string => success({ string, format: 'base64' })), 50 | a => a.string, 51 | ); 52 | 53 | export type Binary = TypeOf; 54 | 55 | export const BinaryIO = type({ 56 | string: tstring, 57 | format: literal('binary'), 58 | }); 59 | 60 | export const BinaryFromStringIO = new Type( 61 | 'BinaryFromString', 62 | (u): u is Binary => BinaryIO.is(u), 63 | (u, c) => either.chain(tstring.validate(u, c), string => success({ string, format: 'binary' })), 64 | a => a.string, 65 | ); 66 | 67 | const validateBlob: Validate = (u: unknown, c: Context) => 68 | u instanceof Blob ? right(u) : left([getValidationError(u, c)]); 69 | 70 | export const BlobToBlobIO = new Type( 71 | 'Base64FromString', 72 | (u): u is Blob => u instanceof Blob, 73 | validateBlob, 74 | a => a, 75 | ); 76 | 77 | const blobMediaRegexp = /^(video|audio|image|application)/; 78 | const textMediaRegexp = /^text/; 79 | export const getResponseTypeFromMediaType = (mediaType: string) => { 80 | if (mediaType === 'application/json') { 81 | return 'json'; 82 | } 83 | if (blobMediaRegexp.test(mediaType)) { 84 | return 'blob'; 85 | } 86 | if (textMediaRegexp.test(mediaType)) { 87 | return 'text'; 88 | } 89 | return 'json'; 90 | }; 91 | 92 | `; 93 | 94 | export const utilsFile = pipe( 95 | utilsRef, 96 | either.map(ref => fromRef(ref, '.ts', utils)), 97 | ); 98 | -------------------------------------------------------------------------------- /src/language/typescript/common/data/serialized-dependency.ts: -------------------------------------------------------------------------------- 1 | import { pipe } from 'fp-ts/lib/pipeable'; 2 | import { groupBy, head } from 'fp-ts/lib/NonEmptyArray'; 3 | import { collect } from 'fp-ts/lib/Record'; 4 | import { join, uniqString } from '../../../../utils/array'; 5 | import { getMonoid as getArrayMonoid, uniq } from 'fp-ts/lib/Array'; 6 | import { Kind } from '../../../../utils/types'; 7 | import { Eq, eqString, getStructEq } from 'fp-ts/lib/Eq'; 8 | import { ord } from 'fp-ts'; 9 | import { ordString } from 'fp-ts/lib/Ord'; 10 | 11 | export interface SerializedDependency { 12 | readonly name: string; 13 | readonly path: string; 14 | } 15 | 16 | export const serializedDependency = (name: string, path: string): SerializedDependency => ({ 17 | name, 18 | path, 19 | }); 20 | 21 | export const serializeDependencies = (dependencies: SerializedDependency[]): string => 22 | pipe( 23 | dependencies, 24 | groupBy(dependency => dependency.path), 25 | collect((key, dependencies) => { 26 | const names = pipe(uniqString(dependencies.map(dependency => dependency.name)), join(',')); 27 | return `import { ${names} } from '${head(dependencies).path}';`; 28 | }), 29 | join(''), 30 | ); 31 | 32 | export const ordDependencyByPath = ord.contramap((dep: SerializedDependency) => dep.path)(ordString); 33 | export const ordDependencyByName = ord.contramap((dep: SerializedDependency) => dep.name)(ordString); 34 | 35 | export const monoidDependencies = getArrayMonoid(); 36 | const dependencyOption = serializedDependency('Option', 'fp-ts/lib/Option'); 37 | const dependencyOptionFromNullable = serializedDependency('optionFromNullable', 'io-ts-types/lib/optionFromNullable'); 38 | export const OPTION_DEPENDENCIES: SerializedDependency[] = [dependencyOption, dependencyOptionFromNullable]; 39 | export const LITERAL_DEPENDENCY = serializedDependency('literal', 'io-ts'); 40 | 41 | export const eqSerializedDependency: Eq = getStructEq({ 42 | name: eqString, 43 | path: eqString, 44 | }); 45 | export const uniqSerializedDependencies = uniq(eqSerializedDependency); 46 | 47 | export const getSerializedKindDependency = (kind: Kind): SerializedDependency => { 48 | switch (kind) { 49 | case 'HKT': { 50 | return serializedDependency('HKT', 'fp-ts/lib/HKT'); 51 | } 52 | case '*': { 53 | return serializedDependency('Kind', 'fp-ts/lib/HKT'); 54 | } 55 | case '* -> *': { 56 | return serializedDependency('Kind2', 'fp-ts/lib/HKT'); 57 | } 58 | } 59 | }; 60 | -------------------------------------------------------------------------------- /src/language/typescript/common/data/serialized-header-parameters.ts: -------------------------------------------------------------------------------- 1 | import { Ref, uniqRefs } from '../../../../utils/ref'; 2 | import { UNSAFE_PROPERTY_PATTERN } from '../utils'; 3 | import { serializedDependency, SerializedDependency, uniqSerializedDependencies } from './serialized-dependency'; 4 | import { SerializedParameter } from './serialized-parameter'; 5 | 6 | export interface SerializedHeaderParameter extends SerializedParameter { 7 | readonly name: string; 8 | } 9 | 10 | export const serializedHeaderParameter = ( 11 | name: string, 12 | type: string, 13 | io: string, 14 | isRequired: boolean, 15 | dependencies: SerializedDependency[], 16 | refs: Ref[], 17 | ): SerializedHeaderParameter => ({ 18 | name, 19 | type, 20 | io, 21 | isRequired, 22 | dependencies: uniqSerializedDependencies(dependencies), 23 | refs: uniqRefs(refs), 24 | }); 25 | 26 | export const fromSerializedHeaderParameter = (name: string) => ( 27 | serialized: SerializedParameter, 28 | ): SerializedHeaderParameter => ({ 29 | ...serialized, 30 | name, 31 | }); 32 | 33 | export const getSerializedHeaderParameterType = (serialized: SerializedHeaderParameter): SerializedHeaderParameter => { 34 | const name = UNSAFE_PROPERTY_PATTERN.test(serialized.name) ? `['${serialized.name}']` : serialized.name; 35 | return serializedHeaderParameter( 36 | name, 37 | `${name}: ${serialized.isRequired ? serialized.type : `option.Option<${serialized.type}>`}`, 38 | `${name}: ${serialized.isRequired ? serialized.io : `optionFromNullable(${serialized.io})`}`, 39 | serialized.isRequired, 40 | serialized.dependencies.concat( 41 | serialized.isRequired 42 | ? [] 43 | : [ 44 | serializedDependency('optionFromNullable', 'io-ts-types/lib/optionFromNullable'), 45 | serializedDependency('option', 'fp-ts'), 46 | ], 47 | ), 48 | serialized.refs, 49 | ); 50 | }; 51 | -------------------------------------------------------------------------------- /src/language/typescript/common/data/serialized-parameter.ts: -------------------------------------------------------------------------------- 1 | import { SerializedType } from './serialized-type'; 2 | import { monoidDependencies, SerializedDependency, uniqSerializedDependencies } from './serialized-dependency'; 3 | import { getStructMonoid, Monoid, monoidAny, monoidString } from 'fp-ts/lib/Monoid'; 4 | import { intercalate } from 'fp-ts/lib/Foldable'; 5 | import { array, getMonoid } from 'fp-ts/lib/Array'; 6 | import { Ref, uniqRefs } from '../../../../utils/ref'; 7 | 8 | export interface SerializedParameter extends SerializedType { 9 | readonly isRequired: boolean; 10 | } 11 | 12 | export const serializedParameter = ( 13 | type: string, 14 | io: string, 15 | isRequired: boolean, 16 | dependencies: SerializedDependency[], 17 | refs: Ref[], 18 | ): SerializedParameter => ({ 19 | type, 20 | io, 21 | isRequired, 22 | dependencies: uniqSerializedDependencies(dependencies), 23 | refs: uniqRefs(refs), 24 | }); 25 | 26 | export const fromSerializedType = (isRequired: boolean) => (serializedType: SerializedType): SerializedParameter => ({ 27 | ...serializedType, 28 | isRequired, 29 | }); 30 | 31 | export const monoidSerializedParameter: Monoid = getStructMonoid({ 32 | type: monoidString, 33 | io: monoidString, 34 | dependencies: monoidDependencies, 35 | isRequired: monoidAny, 36 | refs: getMonoid(), 37 | }); 38 | export const intercalateSerializedParameters = intercalate(monoidSerializedParameter, array); 39 | -------------------------------------------------------------------------------- /src/language/typescript/common/data/serialized-path-parameter.ts: -------------------------------------------------------------------------------- 1 | import { SerializedDependency, uniqSerializedDependencies } from './serialized-dependency'; 2 | import { SerializedParameter } from './serialized-parameter'; 3 | import { Ref, uniqRefs } from '../../../../utils/ref'; 4 | import { getTypeName } from '../utils'; 5 | 6 | export interface SerializedPathParameter extends SerializedParameter { 7 | readonly name: string; 8 | } 9 | 10 | export const serializedPathParameter = ( 11 | name: string, 12 | type: string, 13 | io: string, 14 | isRequired: boolean, 15 | dependencies: SerializedDependency[], 16 | refs: Ref[], 17 | ): SerializedPathParameter => ({ 18 | name, 19 | type, 20 | io, 21 | isRequired, 22 | dependencies: uniqSerializedDependencies(dependencies), 23 | refs: uniqRefs(refs), 24 | }); 25 | 26 | export const fromSerializedParameter = (name: string) => ( 27 | serialized: SerializedParameter, 28 | ): SerializedPathParameter => ({ 29 | ...serialized, 30 | name, 31 | }); 32 | 33 | export const getSerializedPathParameterType = (serialized: SerializedPathParameter): SerializedPathParameter => { 34 | const name = getTypeName(serialized.name); 35 | return serializedPathParameter( 36 | name, 37 | `${name}: ${serialized.type}`, 38 | `${serialized.io}.encode(${name})`, 39 | serialized.isRequired, 40 | serialized.dependencies, 41 | serialized.refs, 42 | ); 43 | }; 44 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/index.ts: -------------------------------------------------------------------------------- 1 | import { defaultPrettierConfig, SerializeOptions } from '../common/utils'; 2 | import { directory, fragment, FSEntity, map as mapFS } from '../../../utils/fs'; 3 | import { Either } from 'fp-ts/lib/Either'; 4 | import { pipe } from 'fp-ts/lib/pipeable'; 5 | import { array, either, option, record } from 'fp-ts'; 6 | import { format } from 'prettier'; 7 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 8 | import { sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 9 | import { FileFormat } from '../../../schema/sketch-121/file-format'; 10 | import { serializeFileFormat } from './serializers/file-format'; 11 | 12 | export const serialize = combineReader( 13 | serializeFileFormat, 14 | serializeFileFormat => ( 15 | files: Record, 16 | options: SerializeOptions = {}, 17 | ): Either => 18 | pipe( 19 | files, 20 | record.collect((name, file) => 21 | pipe(serializeFileFormat(file), either.map(option.map(content => directory(name, [content])))), 22 | ), 23 | sequenceEither, 24 | either.map(serialized => 25 | mapFS(fragment(array.compact(serialized)), content => 26 | format(content, options.prettierConfig || defaultPrettierConfig), 27 | ), 28 | ), 29 | ), 30 | ); 31 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/enums/text-horizontal-alignment.ts: -------------------------------------------------------------------------------- 1 | import { TextHorizontalAlignment } from '../../../../../schema/sketch-121/enums/text-horizontal-alignment'; 2 | import { Either, left, right } from 'fp-ts/lib/Either'; 3 | 4 | export const serializeTextHorizontalAlignment = (alignment: TextHorizontalAlignment): Either => { 5 | switch (alignment) { 6 | case 'Centered': { 7 | return right('center'); 8 | } 9 | case 'Justified': { 10 | return right('justify'); 11 | } 12 | case 'Left': { 13 | return right('left'); 14 | } 15 | case 'Right': { 16 | return right('right'); 17 | } 18 | case 'Natural': { 19 | return left(new Error('TextHorizontalAlignment.Natural is not supported')); 20 | } 21 | } 22 | }; 23 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/enums/text-vertical-alignment.ts: -------------------------------------------------------------------------------- 1 | import { TextVerticalAlignment } from '../../../../../schema/sketch-121/enums/text-vertical-alignment'; 2 | 3 | export const serializeTextVerticalAlignment = (alignment: TextVerticalAlignment): string => { 4 | switch (alignment) { 5 | case 'Top': { 6 | return 'top'; 7 | } 8 | case 'Middle': { 9 | return 'middle'; 10 | } 11 | case 'Bottom': { 12 | return 'bottom'; 13 | } 14 | } 15 | }; 16 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/enums/underline-style.ts: -------------------------------------------------------------------------------- 1 | import { UnderlineStyle } from '../../../../../schema/sketch-121/enums/underline-style'; 2 | 3 | export const serializeUnderlineStyle = (style: UnderlineStyle): string => { 4 | switch (style) { 5 | case 'None': { 6 | return 'normal'; 7 | } 8 | case 'Underlined': { 9 | return 'underline'; 10 | } 11 | } 12 | }; 13 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/file-format.ts: -------------------------------------------------------------------------------- 1 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 2 | import { serializeDocument } from './document'; 3 | import { FileFormat } from '../../../../schema/sketch-121/file-format'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | import { fragment, FSEntity } from '../../../../utils/fs'; 6 | import { pipe } from 'fp-ts/lib/pipeable'; 7 | import { array, nonEmptyArray, option } from 'fp-ts'; 8 | import { combineEither } from '@devexperts/utils/dist/adt/either.utils'; 9 | import { Option } from 'fp-ts/lib/Option'; 10 | 11 | export const serializeFileFormat = combineReader( 12 | serializeDocument, 13 | serializeDocument => (fileFormat: FileFormat): Either> => { 14 | const document = serializeDocument(fileFormat.document); 15 | 16 | return combineEither(document, document => 17 | pipe(nonEmptyArray.fromArray(array.compact([document])), option.map(fragment)), 18 | ); 19 | }, 20 | ); 21 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/border.ts: -------------------------------------------------------------------------------- 1 | import { Border } from '../../../../../schema/sketch-121/objects/border'; 2 | import { Either, left, right } from 'fp-ts/lib/Either'; 3 | import { serializeColor } from './color'; 4 | import { BorderOptions } from '../../../../../schema/sketch-121/objects/border-options'; 5 | import { serializeGradient } from './gradient'; 6 | import { pipe } from 'fp-ts/lib/pipeable'; 7 | import { either } from 'fp-ts'; 8 | 9 | export const serializeBorder = (border: Border, borderOptions: BorderOptions): Either => { 10 | const width = `${border.thickness}px`; 11 | const style = borderOptions.isEnabled && borderOptions.dashPattern.length > 0 ? 'dashed' : 'solid'; 12 | 13 | switch (border.fillType) { 14 | case 'Color': 15 | const color = serializeColor(border.color); 16 | return right(`border: '${style} ${width} ${color}'`); 17 | case 'Gradient': 18 | const gradient = serializeGradient(border.gradient); 19 | return pipe( 20 | gradient, 21 | either.map( 22 | gradient => ` 23 | borderStyle: '${style}', 24 | borderWidth: '${width}', 25 | borderImageSource: '${gradient}', 26 | borderImageSlice: '1' 27 | `, 28 | ), 29 | ); 30 | case 'Pattern': { 31 | return left(new Error(`Border.fillType "Pattern" is not supported`)); 32 | } 33 | } 34 | }; 35 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/color.ts: -------------------------------------------------------------------------------- 1 | import { Color } from '../../../../../schema/sketch-121/objects/color'; 2 | import * as c from 'color'; 3 | import { UnitInterval } from '../../../../../schema/sketch-121/utils/unit-interval'; 4 | 5 | const toValue = (unit: UnitInterval): number => Math.round(255 * unit); 6 | export const serializeColor = (color: Color): string => 7 | c({ 8 | alpha: color.alpha, 9 | r: toValue(color.red), 10 | g: toValue(color.green), 11 | b: toValue(color.blue), 12 | }).string(); 13 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/foreign-layer-style.ts: -------------------------------------------------------------------------------- 1 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 2 | import { serializeSharedStyle } from './shared-style'; 3 | import { ForeignLayerStyle } from '../../../../../schema/sketch-121/objects/foreign-layer-style'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | 6 | export const serializeForeignLayerStyle = combineReader( 7 | serializeSharedStyle, 8 | serializeSharedStyle => (style: ForeignLayerStyle): Either => 9 | serializeSharedStyle(style.localSharedStyle, [style.sourceLibraryName]), 10 | ); 11 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/foreign-text-style.ts: -------------------------------------------------------------------------------- 1 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 2 | import { serializeSharedStyle } from './shared-style'; 3 | import { Either } from 'fp-ts/lib/Either'; 4 | import { ForeignTextStyle } from '../../../../../schema/sketch-121/objects/foreign-text-style'; 5 | 6 | export const serializeForeignTextStyle = combineReader( 7 | serializeSharedStyle, 8 | serializeSharedStyle => (style: ForeignTextStyle): Either => 9 | serializeSharedStyle(style.localSharedStyle, [style.sourceLibraryName]), 10 | ); 11 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/gradient-stop.ts: -------------------------------------------------------------------------------- 1 | import { GradientStop } from '../../../../../schema/sketch-121/objects/gradient-stop'; 2 | import { serializeColor } from './color'; 3 | import { percentageFromFraction } from '../../../../../utils/io-ts'; 4 | import { Either } from 'fp-ts/lib/Either'; 5 | import { combineEither } from '@devexperts/utils/dist/adt/either.utils'; 6 | 7 | export const serializeGradientStop = (stop: GradientStop): Either => { 8 | const color = serializeColor(stop.color); 9 | const positionInPercents = percentageFromFraction(stop.position); 10 | return combineEither(positionInPercents, position => `${color} ${position}%`); 11 | }; 12 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/gradient.ts: -------------------------------------------------------------------------------- 1 | import { Gradient } from '../../../../../schema/sketch-121/objects/gradient'; 2 | import { PointString } from '../../../../../schema/sketch-121/utils/point-string'; 3 | import { Either } from 'fp-ts/lib/Either'; 4 | import { serializeGradientStop } from './gradient-stop'; 5 | import { combineEither, sequenceEither } from '@devexperts/utils/dist/adt/either.utils'; 6 | import { pipe } from 'fp-ts/lib/pipeable'; 7 | import { either } from 'fp-ts'; 8 | import { GradientStop } from '../../../../../schema/sketch-121/objects/gradient-stop'; 9 | 10 | const serializeGradientStops = (stops: GradientStop[]): Either => 11 | pipe( 12 | stops.map(serializeGradientStop), 13 | sequenceEither, 14 | either.map(stops => stops.join(', ')), 15 | ); 16 | 17 | const serializeLinearGradient = (gradient: Gradient): Either => { 18 | const angle = getAngle(gradient.from, gradient.to); 19 | const stops = serializeGradientStops(gradient.stops); 20 | return combineEither(stops, stops => `linear-gradient(${angle}deg, ${stops})`); 21 | }; 22 | 23 | const serializeRadialGradient = (gradient: Gradient): Either => { 24 | const stops = serializeGradientStops(gradient.stops); 25 | return combineEither(stops, stops => `radial-gradient(${stops})`); 26 | }; 27 | 28 | const serializeConicGradient = (gradient: Gradient): Either => { 29 | const stops = serializeGradientStops(gradient.stops); 30 | return combineEither(stops, stops => `conic-gradient(${stops})`); 31 | }; 32 | 33 | export const serializeGradient = (gradient: Gradient): Either => { 34 | switch (gradient.gradientType) { 35 | case 0: { 36 | return serializeLinearGradient(gradient); 37 | } 38 | case 1: { 39 | return serializeRadialGradient(gradient); 40 | } 41 | case 2: { 42 | return serializeConicGradient(gradient); 43 | } 44 | } 45 | }; 46 | 47 | const getAngle = (start: PointString, end: PointString): number => 48 | 90 - (Math.atan2(end.y - start.y, end.x - start.x) * 180) / Math.PI; 49 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/inner-shadow.ts: -------------------------------------------------------------------------------- 1 | import { InnerShadow } from '../../../../../schema/sketch-121/objects/inner-shadow'; 2 | import { serializeColor } from './color'; 3 | 4 | export const serializeInnerShadow = (shadow: InnerShadow): string => { 5 | const color = serializeColor(shadow.color); 6 | return `inset ${shadow.offsetX}px ${shadow.offsetY}px ${shadow.blurRadius}px ${shadow.spread}px ${color}`; 7 | }; 8 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/layer.ts: -------------------------------------------------------------------------------- 1 | import { Layer } from '../../../../../schema/sketch-121/objects/layer'; 2 | import { Either } from 'fp-ts/lib/Either'; 3 | import { getJSDoc, escapeCommpent } from '../../../common/utils'; 4 | import { serializeStyle } from './style'; 5 | import { combineEither } from '@devexperts/utils/dist/adt/either.utils'; 6 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 7 | import { context } from '../../utils'; 8 | import { option, either } from 'fp-ts'; 9 | import { pipe } from 'fp-ts/lib/pipeable'; 10 | import { traverseArrayEither, traverseOptionEither } from '../../../../../utils/either'; 11 | import { identity, constant } from 'fp-ts/lib/function'; 12 | 13 | export const serializeLayer = combineReader(context, context => (layer: Layer, jsdoc?: string[]): Either< 14 | Error, 15 | string 16 | > => { 17 | const layerNameWithPrefix = `layer_${layer.name}`; 18 | const safeName = context.nameStorage.getSafeName(layer.do_objectID, layerNameWithPrefix); 19 | const layerStyle = serializeStyle(layer.style); 20 | 21 | const nestedLayersStyles = traverseOptionEither(layer.layers, layers => 22 | pipe( 23 | traverseArrayEither(layers, serializeLayer(context)), 24 | either.map(styles => styles.join('')), 25 | ), 26 | ); 27 | 28 | return combineEither( 29 | layerStyle, 30 | nestedLayersStyles, 31 | (pageStyle, nestedPagesStyles) => ` 32 | ${getJSDoc([...(jsdoc || []), escapeCommpent(layer.name), layer.do_objectID])} 33 | export const ${safeName}: { name: string; styles: Partial } = { 34 | name: '${layer.name}', 35 | styles: { 36 | ${pageStyle} 37 | }, 38 | }; 39 | ${option.fold(constant(''), identity)(nestedPagesStyles)} 40 | `, 41 | ); 42 | }); 43 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/page.ts: -------------------------------------------------------------------------------- 1 | import { Page } from '../../../../../schema/sketch-121/objects/page'; 2 | import { either } from 'fp-ts'; 3 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 4 | import { pipe } from 'fp-ts/lib/pipeable'; 5 | import { serializeLayer } from './layer'; 6 | import { traverseArrayEither } from '../../../../../utils/either'; 7 | import { Either } from 'fp-ts/lib/Either'; 8 | 9 | export const serializePage = combineReader(serializeLayer, serializeLayer => (page: Page): Either => 10 | pipe( 11 | traverseArrayEither(page.layers, serializeLayer), 12 | either.map(styles => styles.join('')), 13 | ), 14 | ); 15 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/shadow.ts: -------------------------------------------------------------------------------- 1 | import { serializeColor } from './color'; 2 | import { Shadow } from '../../../../../schema/sketch-121/objects/shadow'; 3 | 4 | export const serializeShadow = (shadow: Shadow): string => { 5 | const color = serializeColor(shadow.color); 6 | return `${shadow.offsetX}px ${shadow.offsetY}px ${shadow.blurRadius}px ${shadow.spread}px ${color}`; 7 | }; 8 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/shared-style.ts: -------------------------------------------------------------------------------- 1 | import { SharedStyle } from '../../../../../schema/sketch-121/objects/shared-style'; 2 | import { Either } from 'fp-ts/lib/Either'; 3 | import { getJSDoc } from '../../../common/utils'; 4 | import { serializeStyle } from './style'; 5 | import { combineEither } from '@devexperts/utils/dist/adt/either.utils'; 6 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 7 | import { context } from '../../utils'; 8 | 9 | export const serializeSharedStyle = combineReader( 10 | context, 11 | context => (sharedStyle: SharedStyle, jsdoc?: string[]): Either => { 12 | const style = serializeStyle(sharedStyle.value); 13 | const safeName = context.nameStorage.getSafeName(sharedStyle.do_objectID, sharedStyle.name); 14 | return combineEither( 15 | style, 16 | style => ` 17 | ${getJSDoc([...(jsdoc || []), sharedStyle.name, sharedStyle.do_objectID])} 18 | export const ${safeName}: Partial = { 19 | ${style} 20 | }; 21 | `, 22 | ); 23 | }, 24 | ); 25 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/shared-styled-container.ts: -------------------------------------------------------------------------------- 1 | import { SharedStyleContainer } from '../../../../../schema/sketch-121/objects/shared-style-container'; 2 | import { Either } from 'fp-ts/lib/Either'; 3 | import { pipe } from 'fp-ts/lib/pipeable'; 4 | import { serializeSharedStyle } from './shared-style'; 5 | import { either, nonEmptyArray, option } from 'fp-ts'; 6 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 7 | import { traverseNEAEither } from '../../../../../utils/either'; 8 | import { Option } from 'fp-ts/lib/Option'; 9 | import { sequenceOptionEither } from '../../../../../utils/option'; 10 | 11 | export const serializeSharedStyleContainer = combineReader( 12 | serializeSharedStyle, 13 | serializeSharedStyle => (sharedStyleContainer: SharedStyleContainer): Either> => 14 | pipe( 15 | nonEmptyArray.fromArray(sharedStyleContainer.objects), 16 | option.map(objects => 17 | pipe( 18 | traverseNEAEither(objects, serializeSharedStyle), 19 | either.map(styles => styles.join('')), 20 | ), 21 | ), 22 | sequenceOptionEither, 23 | ), 24 | ); 25 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/shared-text-style-container.ts: -------------------------------------------------------------------------------- 1 | import { Either } from 'fp-ts/lib/Either'; 2 | import { pipe } from 'fp-ts/lib/pipeable'; 3 | import { serializeSharedStyle } from './shared-style'; 4 | import { either, nonEmptyArray, option } from 'fp-ts'; 5 | import { combineReader } from '@devexperts/utils/dist/adt/reader.utils'; 6 | import { SharedTextStyleContainer } from '../../../../../schema/sketch-121/objects/shared-text-style-container'; 7 | import { Option } from 'fp-ts/lib/Option'; 8 | import { traverseNEAEither } from '../../../../../utils/either'; 9 | import { sequenceOptionEither } from '../../../../../utils/option'; 10 | 11 | export const serializeSharedTextStyleContainer = combineReader( 12 | serializeSharedStyle, 13 | serializeSharedStyle => (sharedTextStyleContainer: SharedTextStyleContainer): Either> => 14 | pipe( 15 | nonEmptyArray.fromArray(sharedTextStyleContainer.objects), 16 | option.map(objects => 17 | pipe( 18 | traverseNEAEither(objects, serializeSharedStyle), 19 | either.map(values => values.join('')), 20 | ), 21 | ), 22 | sequenceOptionEither, 23 | ), 24 | ); 25 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/serializers/objects/text-style.ts: -------------------------------------------------------------------------------- 1 | import { TextStyle } from '../../../../../schema/sketch-121/objects/text-style'; 2 | import { pipe } from 'fp-ts/lib/pipeable'; 3 | import { array, option } from 'fp-ts'; 4 | import { serializeColor } from './color'; 5 | import { serializeTextVerticalAlignment } from '../enums/text-vertical-alignment'; 6 | import { serializeTextHorizontalAlignment } from '../enums/text-horizontal-alignment'; 7 | import { serializeUnderlineStyle } from '../enums/underline-style'; 8 | 9 | export const serializeTextStyle = (textStyle: TextStyle): string => { 10 | const textAlign = pipe( 11 | textStyle.encodedAttributes.paragraphStyle, 12 | option.chain(style => style.alignment), 13 | option.chain(alignment => option.fromEither(serializeTextHorizontalAlignment(alignment))), 14 | option.map(alignment => `textAlign: ${JSON.stringify(alignment)}`), 15 | ); 16 | 17 | const lineHeight = pipe( 18 | textStyle.encodedAttributes.paragraphStyle, 19 | option.chain(style => style.maximumLineHeight), 20 | option.alt(() => 21 | pipe( 22 | textStyle.encodedAttributes.paragraphStyle, 23 | option.chain(style => style.minimumLineHeight), 24 | ), 25 | ), 26 | option.map(lineHeight => `lineHeight: '${lineHeight}px'`), 27 | ); 28 | 29 | const textDecoration = pipe( 30 | textStyle.encodedAttributes.underlineStyle, 31 | option.map(style => `textDecoration: ${JSON.stringify(serializeUnderlineStyle(style))}`), 32 | ); 33 | 34 | const letterSpacing = pipe( 35 | textStyle.encodedAttributes.kerning, 36 | option.map(kerning => `letterSpacing: '${kerning}px'`), 37 | ); 38 | 39 | const color = pipe( 40 | textStyle.encodedAttributes.MSAttributedStringColorAttribute, 41 | option.map(color => `color: ${JSON.stringify(serializeColor(color))}`), 42 | ); 43 | 44 | const verticalAlign = `verticalAlign: ${JSON.stringify( 45 | serializeTextVerticalAlignment(textStyle.verticalAlignment), 46 | )}`; 47 | 48 | const fontFamily = `fontFamily: ${JSON.stringify( 49 | textStyle.encodedAttributes.MSAttributedStringFontAttribute.attributes.name, 50 | )}`; 51 | 52 | const fontSize = `fontSize: '${textStyle.encodedAttributes.MSAttributedStringFontAttribute.attributes.size}px'`; 53 | 54 | return [ 55 | fontFamily, 56 | fontSize, 57 | verticalAlign, 58 | ...array.compact([color, textAlign, lineHeight, textDecoration, letterSpacing]), 59 | ].join(', '); 60 | }; 61 | -------------------------------------------------------------------------------- /src/language/typescript/sketch-121/utils.ts: -------------------------------------------------------------------------------- 1 | import { ask } from 'fp-ts/lib/Reader'; 2 | import { getSafePropertyName } from '../common/utils'; 3 | 4 | export interface NameStorage { 5 | readonly getSafeName: (uuid: string, name: string) => string; 6 | } 7 | 8 | export const createNameStorage = () => { 9 | const nameToUuid = new Map(); 10 | const uuidToName = new Map(); 11 | const nameToCounter = new Map(); 12 | 13 | const getSafeNameWithCounter = (safeName: string): string => { 14 | const counter = nameToCounter.get(safeName) || 1; 15 | const nameWithCounter = safeName + counter; 16 | nameToCounter.set(safeName, counter + 1); 17 | return !nameToUuid.has(nameWithCounter) ? nameWithCounter : getSafeNameWithCounter(safeName); 18 | }; 19 | 20 | const getSafeName = (uuid: string, name: string): string => { 21 | const safeName = getSafePropertyName(name); 22 | // check if we have a name for such uuid 23 | const storedName = uuidToName.get(uuid); 24 | if (storedName !== undefined) { 25 | return storedName; 26 | } 27 | // no name - generate one 28 | // check if we have such name 29 | if (!nameToUuid.has(safeName)) { 30 | // no collisions 31 | nameToUuid.set(safeName, uuid); 32 | uuidToName.set(uuid, safeName); 33 | nameToCounter.set(safeName, 0); 34 | return safeName; 35 | } 36 | // we already have such safeName stored - increase counter and store under uuid 37 | const nameWithCounter = getSafeNameWithCounter(safeName); 38 | nameToUuid.set(nameWithCounter, uuid); 39 | uuidToName.set(uuid, nameWithCounter); 40 | return nameWithCounter; 41 | }; 42 | 43 | return { 44 | getSafeName, 45 | }; 46 | }; 47 | 48 | export interface Context { 49 | readonly nameStorage: NameStorage; 50 | } 51 | export const context = ask(); 52 | -------------------------------------------------------------------------------- /src/parsers/sketch-121.ts: -------------------------------------------------------------------------------- 1 | import { FileInfo } from 'json-schema-ref-parser'; 2 | import * as AdmZip from 'adm-zip'; 3 | import { array, string, type } from 'io-ts'; 4 | import { isLeft } from 'fp-ts/lib/Either'; 5 | 6 | const log = (...args: unknown[]): void => console.log('[SKETCH-PARSER]:', ...args); 7 | 8 | export const sketchParser121 = { 9 | order: 90, 10 | allowEmpty: false, 11 | canParse: (file: FileInfo): boolean => file.extension === 'sketch', 12 | parse: async (file: FileInfo): Promise => { 13 | log('Unzipping', file.url); 14 | const zip = new AdmZip(file.data); 15 | log('Parsing document.json'); 16 | const document = toJSON(zip.getEntry('document.json').getData()); 17 | log('Parsing meta.json'); 18 | const meta = toJSON(zip.getEntry('meta.json').getData()); 19 | log('Parsing user.json'); 20 | const user = toJSON(zip.getEntry('user.json').getData()); 21 | 22 | const decodedDocument = documentCodec.decode(document); 23 | if (isLeft(decodedDocument)) { 24 | throw decodedDocument.left; 25 | } 26 | const pages = decodedDocument.right.pages.map(page => { 27 | const entry = `${page._ref}.json`; 28 | log('Parsing', entry); 29 | return toJSON(zip.getEntry(entry).getData()); 30 | }); 31 | 32 | log('Done'); 33 | return { 34 | document: { 35 | ...document, 36 | pages, 37 | }, 38 | meta, 39 | user, 40 | }; 41 | }, 42 | }; 43 | 44 | const documentCodec = type({ 45 | pages: array( 46 | type({ 47 | _ref: string, 48 | }), 49 | ), 50 | }); 51 | 52 | const toJSON = (buffer: Buffer): unknown => JSON.parse(buffer.toString('utf-8')); 53 | -------------------------------------------------------------------------------- /src/schema/2.0/contact-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { stringOption } from '../../utils/io-ts'; 3 | import { type } from 'io-ts'; 4 | 5 | export interface ContactObject { 6 | readonly name: Option; 7 | readonly url: Option; 8 | readonly email: Option; 9 | } 10 | 11 | export const ContactObject = type( 12 | { 13 | name: stringOption, 14 | url: stringOption, 15 | email: stringOption, 16 | }, 17 | 'ContactObject', 18 | ); 19 | -------------------------------------------------------------------------------- /src/schema/2.0/definitions-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { SchemaObject, SchemaObjectCodec } from './schema-object'; 3 | import { dictionary } from '../../utils/io-ts'; 4 | 5 | export interface DefinitionsObject extends Dictionary {} 6 | 7 | export const DefinitionsObject = dictionary(SchemaObjectCodec, 'DefinitionsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/example-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { dictionary } from '../../utils/io-ts'; 3 | import { string } from 'io-ts'; 4 | 5 | export interface ExampleObject extends Dictionary {} 6 | 7 | export const ExampleObject = dictionary(string, 'ExampleObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/external-documentation-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { stringOption } from '../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | 5 | export interface ExternalDocumentationObject { 6 | readonly description: Option; 7 | readonly url: string; 8 | } 9 | 10 | export const ExternalDocumentationObject = type( 11 | { 12 | description: stringOption, 13 | url: string, 14 | }, 15 | 'ExternalDocumentationObject', 16 | ); 17 | -------------------------------------------------------------------------------- /src/schema/2.0/header-object.ts: -------------------------------------------------------------------------------- 1 | import { ItemsObject, ItemsObjectCodec } from './items-object'; 2 | import { Option } from 'fp-ts/lib/Option'; 3 | import { stringOption } from '../../utils/io-ts'; 4 | import { intersection, type } from 'io-ts'; 5 | 6 | export type HeaderObject = ItemsObject & { 7 | readonly description: Option; 8 | }; 9 | export const HeaderObject = intersection( 10 | [ 11 | ItemsObjectCodec, 12 | type({ 13 | description: stringOption, 14 | }), 15 | ], 16 | 'HeaderObject', 17 | ); 18 | -------------------------------------------------------------------------------- /src/schema/2.0/headers-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { HeaderObject } from './header-object'; 3 | import { dictionary } from '../../utils/io-ts'; 4 | 5 | export interface HeadersObject extends Dictionary {} 6 | 7 | export const HeadersObject = dictionary(HeaderObject, 'HeadersObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/info-object.ts: -------------------------------------------------------------------------------- 1 | import { stringOption } from '../../utils/io-ts'; 2 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 3 | import { ContactObject } from './contact-object'; 4 | import { LicenseObject } from './license-object'; 5 | import { Option } from 'fp-ts/lib/Option'; 6 | import { string, type } from 'io-ts'; 7 | 8 | export interface InfoObject { 9 | readonly title: string; 10 | readonly description: Option; 11 | readonly termsOfService: Option; 12 | readonly contact: Option; 13 | readonly license: Option; 14 | readonly version: string; 15 | } 16 | 17 | export const InfoObject = type( 18 | { 19 | title: string, 20 | description: stringOption, 21 | termsOfService: stringOption, 22 | contact: optionFromNullable(ContactObject), 23 | license: optionFromNullable(LicenseObject), 24 | version: string, 25 | }, 26 | 'InfoObject', 27 | ); 28 | -------------------------------------------------------------------------------- /src/schema/2.0/items-object.ts: -------------------------------------------------------------------------------- 1 | import { booleanOption, Codec, numberOption, primitiveArrayOption, stringOption } from '../../utils/io-ts'; 2 | import { literal, recursion, type, union } from 'io-ts'; 3 | import { Option } from 'fp-ts/lib/Option'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | 6 | export interface BaseItemsObject { 7 | readonly format: Option; 8 | readonly collectionFormat: Option<'csv' | 'ssv' | 'tsv' | 'pipes'>; 9 | readonly maximum: Option; 10 | readonly exclusiveMaximum: Option; 11 | readonly minimum: Option; 12 | readonly exclusiveMinimum: Option; 13 | readonly maxLength: Option; 14 | readonly minLength: Option; 15 | readonly pattern: Option; 16 | readonly maxItems: Option; 17 | readonly minItems: Option; 18 | readonly uniqueItems: Option; 19 | readonly enum: Option>; 20 | readonly multipleOf: Option; 21 | } 22 | 23 | const BaseItemsObjectProps = { 24 | format: stringOption, 25 | collectionFormat: optionFromNullable(union([literal('csv'), literal('ssv'), literal('tsv'), literal('pipes')])), 26 | maximum: numberOption, 27 | exclusiveMaximum: booleanOption, 28 | minimum: numberOption, 29 | exclusiveMinimum: booleanOption, 30 | maxLength: numberOption, 31 | minLength: numberOption, 32 | pattern: stringOption, 33 | maxItems: numberOption, 34 | minItems: numberOption, 35 | uniqueItems: booleanOption, 36 | enum: primitiveArrayOption, 37 | multipleOf: numberOption, 38 | }; 39 | 40 | export type ArrayItemsObjectCollectionFormat = 'csv' | 'ssv' | 'tsv' | 'pipes'; 41 | export interface ArrayItemsObject extends BaseItemsObject { 42 | readonly type: 'array'; 43 | readonly items: ItemsObject; 44 | readonly collectionFormat: Option; 45 | } 46 | 47 | const ArrayItemsObjectCodec: Codec = recursion('ArrayItemsObject', () => 48 | type({ 49 | ...BaseItemsObjectProps, 50 | type: literal('array'), 51 | items: ItemsObjectCodec, 52 | collectionFormat: optionFromNullable(union([literal('csv'), literal('ssv'), literal('tsv'), literal('pipes')])), 53 | }), 54 | ); 55 | 56 | export interface NonArrayItemsObject extends BaseItemsObject { 57 | readonly type: 'string' | 'number' | 'integer' | 'boolean'; 58 | } 59 | 60 | const NonArrayItemsObjectCodec: Codec = type({ 61 | ...BaseItemsObjectProps, 62 | type: union([literal('string'), literal('number'), literal('integer'), literal('boolean')]), 63 | }); 64 | 65 | export type ItemsObject = ArrayItemsObject | NonArrayItemsObject; 66 | 67 | export const ItemsObjectCodec: Codec = recursion('ItemsObject', () => 68 | union([ArrayItemsObjectCodec, NonArrayItemsObjectCodec]), 69 | ); 70 | -------------------------------------------------------------------------------- /src/schema/2.0/license-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { stringOption } from '../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | 5 | export interface LicenseObject { 6 | readonly name: string; 7 | readonly url: Option; 8 | } 9 | 10 | export const LicenseObject = type( 11 | { 12 | name: string, 13 | url: stringOption, 14 | }, 15 | 'LicenseObject', 16 | ); 17 | -------------------------------------------------------------------------------- /src/schema/2.0/operation-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ExternalDocumentationObject } from './external-documentation-object'; 3 | import { ParameterObject, ParameterObjectCodec } from './parameter-object'; 4 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 5 | import { ResponsesObject } from './responses-object'; 6 | import { SecurityRequirementObject } from './security-requirement-object'; 7 | import { booleanOption, stringArrayOption, stringOption } from '../../utils/io-ts'; 8 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 9 | import { array, type, union } from 'io-ts'; 10 | 11 | export interface OperationObject { 12 | readonly tags: Option; 13 | readonly summary: Option; 14 | readonly description: Option; 15 | readonly externalDocs: Option; 16 | readonly operationId: Option; 17 | readonly consumes: Option; 18 | readonly produces: Option; 19 | readonly parameters: Option>; 20 | readonly responses: ResponsesObject; 21 | readonly schemes: Option; 22 | readonly deprecated: Option; 23 | readonly security: Option; 24 | } 25 | 26 | export const OperationObject = type( 27 | { 28 | tags: stringArrayOption, 29 | summary: stringOption, 30 | description: stringOption, 31 | externalDocs: optionFromNullable(ExternalDocumentationObject), 32 | operationId: stringOption, 33 | consumes: stringArrayOption, 34 | produces: stringArrayOption, 35 | parameters: optionFromNullable(array(union([ReferenceObjectCodec, ParameterObjectCodec]))), 36 | responses: ResponsesObject, 37 | schemes: stringArrayOption, 38 | deprecated: booleanOption, 39 | security: optionFromNullable(array(SecurityRequirementObject)), 40 | }, 41 | 'OperationObject', 42 | ); 43 | -------------------------------------------------------------------------------- /src/schema/2.0/parameters-definitions-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { ParameterObject, ParameterObjectCodec } from './parameter-object'; 3 | import { dictionary } from '../../utils/io-ts'; 4 | 5 | export interface ParametersDefinitionsObject extends Dictionary {} 6 | 7 | export const ParametersDefinitionsObject = dictionary(ParameterObjectCodec, 'ParametersDefinitionsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/path-item-object.ts: -------------------------------------------------------------------------------- 1 | import { stringOption } from '../../utils/io-ts'; 2 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 3 | import { OperationObject } from './operation-object'; 4 | import { ParameterObject, ParameterObjectCodec } from './parameter-object'; 5 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 6 | import { Option } from 'fp-ts/lib/Option'; 7 | import { array, type, union } from 'io-ts'; 8 | 9 | export interface PathItemObject { 10 | readonly $ref: Option; 11 | readonly get: Option; 12 | readonly put: Option; 13 | readonly post: Option; 14 | readonly delete: Option; 15 | readonly options: Option; 16 | readonly head: Option; 17 | readonly patch: Option; 18 | readonly parameters: Option>; 19 | } 20 | 21 | export const PathItemObjectCodec = type( 22 | { 23 | $ref: stringOption, 24 | get: optionFromNullable(OperationObject), 25 | put: optionFromNullable(OperationObject), 26 | post: optionFromNullable(OperationObject), 27 | delete: optionFromNullable(OperationObject), 28 | options: optionFromNullable(OperationObject), 29 | head: optionFromNullable(OperationObject), 30 | patch: optionFromNullable(OperationObject), 31 | parameters: optionFromNullable(array(union([ReferenceObjectCodec, ParameterObjectCodec]))), 32 | }, 33 | 'PathItemObject', 34 | ); 35 | -------------------------------------------------------------------------------- /src/schema/2.0/paths-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { PathItemObject, PathItemObjectCodec } from './path-item-object'; 3 | import { dictionary } from '../../utils/io-ts'; 4 | 5 | export interface PathsObject extends Dictionary {} 6 | 7 | export const PathsObject = dictionary(PathItemObjectCodec, 'PathsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/reference-object.ts: -------------------------------------------------------------------------------- 1 | import { string, type } from 'io-ts'; 2 | import { Codec } from '../../utils/io-ts'; 3 | 4 | export interface ReferenceObject { 5 | readonly $ref: string; 6 | } 7 | 8 | export const ReferenceObjectCodec: Codec = type( 9 | { 10 | $ref: string, 11 | }, 12 | 'ReferenceObject', 13 | ); 14 | -------------------------------------------------------------------------------- /src/schema/2.0/response-object.ts: -------------------------------------------------------------------------------- 1 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 2 | import { Option } from 'fp-ts/lib/Option'; 3 | import { ExampleObject } from './example-object'; 4 | import { HeadersObject } from './headers-object'; 5 | import { SchemaObject, SchemaObjectCodec } from './schema-object'; 6 | import { string, type } from 'io-ts'; 7 | 8 | export interface ResponseObject { 9 | readonly description: string; 10 | readonly schema: Option; 11 | readonly headers: Option; 12 | readonly examples: Option; 13 | } 14 | 15 | export const ResponseObject = type( 16 | { 17 | description: string, 18 | schema: optionFromNullable(SchemaObjectCodec), 19 | headers: optionFromNullable(HeadersObject), 20 | examples: optionFromNullable(ExampleObject), 21 | }, 22 | 'ResponseObject', 23 | ); 24 | -------------------------------------------------------------------------------- /src/schema/2.0/responses-definitions-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { ResponseObject } from './response-object'; 3 | import { dictionary } from '../../utils/io-ts'; 4 | 5 | export interface ResponsesDefinitionsObject extends Dictionary {} 6 | 7 | export const ResponsesDefinitionsObject = dictionary(ResponseObject, 'ResponsesDefinitionsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/responses-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { ResponseObject } from './response-object'; 3 | import { Codec, dictionary } from '../../utils/io-ts'; 4 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 5 | import { union } from 'io-ts'; 6 | 7 | export interface ResponsesObject extends Dictionary {} 8 | 9 | export const ResponsesObject: Codec = dictionary( 10 | union([ReferenceObjectCodec, ResponseObject]), 11 | 'ResponsesObject', 12 | ); 13 | -------------------------------------------------------------------------------- /src/schema/2.0/scopes-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { dictionary } from '../../utils/io-ts'; 3 | import { string } from 'io-ts'; 4 | 5 | export interface ScopesObject extends Dictionary {} 6 | 7 | export const ScopesObject = dictionary(string, 'ScopesObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/security-definitions-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { SecuritySchemeObject } from './security-scheme-object/security-scheme-object'; 3 | import { dictionary } from '../../utils/io-ts'; 4 | 5 | export interface SecurityDefinitionsObject extends Dictionary {} 6 | 7 | export const SecurityDefinitionsObject = dictionary(SecuritySchemeObject, 'SecurityDefinitionsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/security-requirement-object.ts: -------------------------------------------------------------------------------- 1 | import { Dictionary } from '../../utils/types'; 2 | import { dictionary } from '../../utils/io-ts'; 3 | import { array, string } from 'io-ts'; 4 | 5 | export interface SecurityRequirementObject extends Dictionary {} 6 | 7 | export const SecurityRequirementObject = dictionary(array(string), 'SecurityRequirementObject'); 8 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/access-code-oauth2-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { BaseSecuritySchemeObjectProps } from './base-security-scheme-object'; 2 | import { ScopesObject } from '../scopes-object'; 3 | import { literal, string, type } from 'io-ts'; 4 | export interface AccessCodeOAuth2SecuritySchemeObject extends BaseSecuritySchemeObjectProps { 5 | readonly type: 'oauth2'; 6 | readonly flow: 'accessCode'; 7 | readonly tokenUrl: string; 8 | readonly scopes: ScopesObject; 9 | } 10 | 11 | export const AccessCodeOAuth2SecuritySchemeObject = type( 12 | { 13 | ...BaseSecuritySchemeObjectProps, 14 | type: literal('oauth2'), 15 | flow: literal('accessCode'), 16 | tokenUrl: string, 17 | scopes: ScopesObject, 18 | }, 19 | 'AccessCodeOAuth2SecuritySchemeObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/api-key-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { BaseSecuritySchemeObjectProps } from './base-security-scheme-object'; 2 | import { literal, string, type, union } from 'io-ts'; 3 | 4 | export interface ApiKeySecuritySchemeObject extends BaseSecuritySchemeObjectProps { 5 | readonly type: 'apiKey'; 6 | readonly in: 'query' | 'header'; 7 | readonly name: string; 8 | } 9 | 10 | export const ApiKeySecuritySchemeObject = type( 11 | { 12 | ...BaseSecuritySchemeObjectProps, 13 | type: literal('apiKey'), 14 | in: union([literal('query'), literal('header')]), 15 | name: string, 16 | }, 17 | 'ApiKeySecuritySchemeObject', 18 | ); 19 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/application-oauth2-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { BaseSecuritySchemeObjectProps } from './base-security-scheme-object'; 2 | import { ScopesObject } from '../scopes-object'; 3 | import { literal, string, type } from 'io-ts'; 4 | export interface ApplicationOAuth2SecuritySchemeObject extends BaseSecuritySchemeObjectProps { 5 | readonly type: 'oauth2'; 6 | readonly flow: 'application'; 7 | readonly tokenUrl: string; 8 | readonly scopes: ScopesObject; 9 | } 10 | 11 | export const ApplicationOAuth2SecuritySchemeObject = type( 12 | { 13 | ...BaseSecuritySchemeObjectProps, 14 | type: literal('oauth2'), 15 | flow: literal('application'), 16 | tokenUrl: string, 17 | scopes: ScopesObject, 18 | }, 19 | 'ApplicationOAuth2SecuritySchemeObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/base-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { stringOption } from '../../../utils/io-ts'; 2 | import { Option } from 'fp-ts/lib/Option'; 3 | 4 | export interface BaseSecuritySchemeObjectProps { 5 | readonly description: Option; 6 | } 7 | 8 | export const BaseSecuritySchemeObjectProps = { 9 | description: stringOption, 10 | }; 11 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/basic-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { BaseSecuritySchemeObjectProps } from './base-security-scheme-object'; 2 | import { literal, type } from 'io-ts'; 3 | 4 | export interface BasicSecuritySchemeObject extends BaseSecuritySchemeObjectProps { 5 | readonly type: 'basic'; 6 | } 7 | 8 | export const BasicSecuritySchemeObject = type( 9 | { 10 | ...BaseSecuritySchemeObjectProps, 11 | type: literal('basic'), 12 | }, 13 | 'BasicSecuritySchemeObject', 14 | ); 15 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/implicit-oauth2-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { BaseSecuritySchemeObjectProps } from './base-security-scheme-object'; 2 | import { ScopesObject } from '../scopes-object'; 3 | import { literal, string, type } from 'io-ts'; 4 | 5 | export interface ImplicitOAuth2SecuritySchemeObject extends BaseSecuritySchemeObjectProps { 6 | readonly type: 'oauth2'; 7 | readonly flow: 'implicit'; 8 | readonly authorizationUrl: string; 9 | readonly scopes: ScopesObject; 10 | } 11 | 12 | export const ImplicitOAuth2SecuritySchemeObject = type( 13 | { 14 | ...BaseSecuritySchemeObjectProps, 15 | type: literal('oauth2'), 16 | flow: literal('implicit'), 17 | authorizationUrl: string, 18 | scopes: ScopesObject, 19 | }, 20 | 'ImplicitOAuth2SecuritySchemeObject', 21 | ); 22 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/oauth2-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { ImplicitOAuth2SecuritySchemeObject } from './implicit-oauth2-security-scheme-object'; 2 | import { PasswordOAuth2SecuritySchemeObject } from './password-oauth2-security-scheme-object'; 3 | import { ApplicationOAuth2SecuritySchemeObject } from './application-oauth2-security-scheme-object'; 4 | import { AccessCodeOAuth2SecuritySchemeObject } from './access-code-oauth2-security-scheme-object'; 5 | import { union } from 'io-ts'; 6 | 7 | export type OAuth2SecuritySchemeObject = 8 | | ImplicitOAuth2SecuritySchemeObject 9 | | PasswordOAuth2SecuritySchemeObject 10 | | ApplicationOAuth2SecuritySchemeObject 11 | | AccessCodeOAuth2SecuritySchemeObject; 12 | 13 | export const OAuth2SecuritySchemeObject = union( 14 | [ 15 | ImplicitOAuth2SecuritySchemeObject, 16 | PasswordOAuth2SecuritySchemeObject, 17 | ApplicationOAuth2SecuritySchemeObject, 18 | AccessCodeOAuth2SecuritySchemeObject, 19 | ], 20 | 'OAuth2SecuritySchemeObject', 21 | ); 22 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/password-oauth2-security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { BaseSecuritySchemeObjectProps } from './base-security-scheme-object'; 2 | import { ScopesObject } from '../scopes-object'; 3 | import { literal, string, type } from 'io-ts'; 4 | export interface PasswordOAuth2SecuritySchemeObject extends BaseSecuritySchemeObjectProps { 5 | readonly type: 'oauth2'; 6 | readonly flow: 'password'; 7 | readonly tokenUrl: string; 8 | readonly scopes: ScopesObject; 9 | } 10 | 11 | export const PasswordOAuth2SecuritySchemeObject = type( 12 | { 13 | ...BaseSecuritySchemeObjectProps, 14 | type: literal('oauth2'), 15 | flow: literal('password'), 16 | tokenUrl: string, 17 | scopes: ScopesObject, 18 | }, 19 | 'PasswordOAuth2SecuritySchemeObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/2.0/security-scheme-object/security-scheme-object.ts: -------------------------------------------------------------------------------- 1 | import { BasicSecuritySchemeObject } from './basic-security-scheme-object'; 2 | import { ApiKeySecuritySchemeObject } from './api-key-security-scheme-object'; 3 | import { OAuth2SecuritySchemeObject } from './oauth2-security-scheme-object'; 4 | import { union } from 'io-ts'; 5 | 6 | export type SecuritySchemeObject = BasicSecuritySchemeObject | ApiKeySecuritySchemeObject | OAuth2SecuritySchemeObject; 7 | export const SecuritySchemeObject = union( 8 | [BasicSecuritySchemeObject, ApiKeySecuritySchemeObject, OAuth2SecuritySchemeObject], 9 | 'SecuritySchemeObject', 10 | ); 11 | -------------------------------------------------------------------------------- /src/schema/2.0/swagger-object.ts: -------------------------------------------------------------------------------- 1 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 2 | import { Option } from 'fp-ts/lib/Option'; 3 | import { stringArrayOption, stringOption } from '../../utils/io-ts'; 4 | import { InfoObject } from './info-object'; 5 | import { ExternalDocumentationObject } from './external-documentation-object'; 6 | import { SecurityRequirementObject } from './security-requirement-object'; 7 | import { TagObject } from './tag-object'; 8 | import { ResponsesDefinitionsObject } from './responses-definitions-object'; 9 | import { SecurityDefinitionsObject } from './security-definitions-object'; 10 | import { DefinitionsObject } from './definitions-object'; 11 | import { PathsObject } from './paths-object'; 12 | import { ParametersDefinitionsObject } from './parameters-definitions-object'; 13 | import { array, string, type } from 'io-ts'; 14 | 15 | export interface SwaggerObject { 16 | readonly basePath: Option; 17 | readonly consumes: Option; 18 | readonly definitions: Option; 19 | readonly externalDocs: Option; 20 | readonly host: Option; 21 | readonly info: InfoObject; 22 | readonly parameters: Option; 23 | readonly paths: PathsObject; 24 | readonly produces: Option; 25 | readonly responses: Option; 26 | readonly schemes: Option; 27 | readonly security: Option; 28 | readonly securityDefinitions: Option; 29 | readonly swagger: string; 30 | readonly tags: Option; 31 | } 32 | 33 | export const SwaggerObject = type( 34 | { 35 | basePath: stringOption, 36 | consumes: stringArrayOption, 37 | definitions: optionFromNullable(DefinitionsObject), 38 | externalDocs: optionFromNullable(ExternalDocumentationObject), 39 | host: stringOption, 40 | info: InfoObject, 41 | parameters: optionFromNullable(ParametersDefinitionsObject), 42 | paths: PathsObject, 43 | produces: stringArrayOption, 44 | responses: optionFromNullable(ResponsesDefinitionsObject), 45 | schemes: stringArrayOption, 46 | security: optionFromNullable(array(SecurityRequirementObject)), 47 | securityDefinitions: optionFromNullable(SecurityDefinitionsObject), 48 | swagger: string, 49 | tags: optionFromNullable(array(TagObject)), 50 | }, 51 | 'SwaggerObject', 52 | ); 53 | -------------------------------------------------------------------------------- /src/schema/2.0/tag-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ExternalDocumentationObject } from './external-documentation-object'; 3 | import { stringOption } from '../../utils/io-ts'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | import { string, type } from 'io-ts'; 6 | 7 | export interface TagObject { 8 | readonly name: string; 9 | readonly description: Option; 10 | readonly externalDocs: Option; 11 | } 12 | 13 | export const TagObject = type( 14 | { 15 | name: string, 16 | description: stringOption, 17 | externalDocs: optionFromNullable(ExternalDocumentationObject), 18 | }, 19 | 'TagObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/3.0/components-object.ts: -------------------------------------------------------------------------------- 1 | import { record, string, type, union } from 'io-ts'; 2 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 3 | import { SchemaObject, SchemaObjectCodec } from './schema-object'; 4 | import { Option } from 'fp-ts/lib/Option'; 5 | import { Codec } from '../../utils/io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | import { ParameterObject, ParameterObjectCodec } from './parameter-object'; 8 | import { ResponseObject, ResponseObjectCodec } from './response-object'; 9 | import { RequestBodyObject, RequestBodyObjectCodec } from './request-body-object'; 10 | 11 | export interface ComponentsObject { 12 | readonly schemas: Option>; 13 | readonly parameters: Option>; 14 | readonly responses: Option>; 15 | readonly requestBodies: Option>; 16 | } 17 | 18 | export const ComponentsObjectCodec: Codec = type( 19 | { 20 | schemas: optionFromNullable(record(string, union([ReferenceObjectCodec, SchemaObjectCodec]))), 21 | parameters: optionFromNullable(record(string, union([ReferenceObjectCodec, ParameterObjectCodec]))), 22 | responses: optionFromNullable(record(string, union([ReferenceObjectCodec, ResponseObjectCodec]))), 23 | requestBodies: optionFromNullable(record(string, union([ReferenceObjectCodec, RequestBodyObjectCodec]))), 24 | }, 25 | 'ComponentsObject', 26 | ); 27 | -------------------------------------------------------------------------------- /src/schema/3.0/media-type-object.ts: -------------------------------------------------------------------------------- 1 | import { type, union } from 'io-ts'; 2 | import { SchemaObject, SchemaObjectCodec } from './schema-object'; 3 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 4 | import { Option } from 'fp-ts/lib/Option'; 5 | import { Codec } from '../../utils/io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | 8 | export interface MediaTypeObject { 9 | readonly schema: Option; 10 | } 11 | 12 | export const MediaTypeObjectCodec: Codec = type( 13 | { 14 | schema: optionFromNullable(union([ReferenceObjectCodec, SchemaObjectCodec])), 15 | }, 16 | 'MediaTypeObject', 17 | ); 18 | -------------------------------------------------------------------------------- /src/schema/3.0/openapi-object.ts: -------------------------------------------------------------------------------- 1 | import { literal, Type, type, union } from 'io-ts'; 2 | import { PathsObject, PathsObjectCodec } from './paths-object'; 3 | import { ComponentsObject, ComponentsObjectCodec } from './components-object'; 4 | import { Option } from 'fp-ts/lib/Option'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | 7 | export interface OpenapiObject { 8 | readonly openapi: '3.0.0' | '3.0.1' | '3.0.2'; 9 | readonly paths: PathsObject; 10 | readonly components: Option; 11 | } 12 | 13 | export const OpenapiObjectCodec: Type = type( 14 | { 15 | openapi: union([literal('3.0.0'), literal('3.0.1'), literal('3.0.2')], 'OpenapiObject'), 16 | paths: PathsObjectCodec, 17 | components: optionFromNullable(ComponentsObjectCodec), 18 | }, 19 | 'OpenapiObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/3.0/operation-object.ts: -------------------------------------------------------------------------------- 1 | import { array, boolean, string, type, union } from 'io-ts'; 2 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 3 | import { ParameterObject, ParameterObjectCodec } from './parameter-object'; 4 | import { RequestBodyObject, RequestBodyObjectCodec } from './request-body-object'; 5 | import { ResponsesObject, ResponsesObjectCodec } from './responses-object'; 6 | import { Option } from 'fp-ts/lib/Option'; 7 | import { Codec } from '../../utils/io-ts'; 8 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 9 | 10 | export interface OperationObject { 11 | readonly tags: Option; 12 | readonly summary: Option; 13 | readonly description: Option; 14 | readonly operationId: Option; 15 | readonly parameters: Option>; 16 | readonly requestBody: Option; 17 | readonly responses: ResponsesObject; 18 | readonly deprecated: Option; 19 | } 20 | 21 | export const OperationObjectCodec: Codec = type( 22 | { 23 | tags: optionFromNullable(array(string)), 24 | summary: optionFromNullable(string), 25 | description: optionFromNullable(string), 26 | operationId: optionFromNullable(string), 27 | parameters: optionFromNullable(array(union([ReferenceObjectCodec, ParameterObjectCodec]))), 28 | requestBody: optionFromNullable(union([ReferenceObjectCodec, RequestBodyObjectCodec])), 29 | responses: ResponsesObjectCodec, 30 | deprecated: optionFromNullable(boolean), 31 | }, 32 | 'OperationObject', 33 | ); 34 | -------------------------------------------------------------------------------- /src/schema/3.0/path-item-object.ts: -------------------------------------------------------------------------------- 1 | import { array, string, type, union } from 'io-ts'; 2 | import { OperationObject, OperationObjectCodec } from './operation-object'; 3 | import { ServerObject, ServerObjectCodec } from './server-object'; 4 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 5 | import { ParameterObject, ParameterObjectCodec } from './parameter-object'; 6 | import { Option } from 'fp-ts/lib/Option'; 7 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 8 | import { Codec } from '../../utils/io-ts'; 9 | 10 | export interface PathItemObject { 11 | readonly $ref: Option; 12 | readonly summary: Option; 13 | readonly description: Option; 14 | readonly get: Option; 15 | readonly put: Option; 16 | readonly post: Option; 17 | readonly delete: Option; 18 | readonly options: Option; 19 | readonly head: Option; 20 | readonly patch: Option; 21 | readonly trace: Option; 22 | readonly servers: Option; 23 | readonly parameters: Option>; 24 | } 25 | 26 | export const PathItemObjectCodec: Codec = type( 27 | { 28 | $ref: optionFromNullable(string), 29 | summary: optionFromNullable(string), 30 | description: optionFromNullable(string), 31 | get: optionFromNullable(OperationObjectCodec), 32 | put: optionFromNullable(OperationObjectCodec), 33 | post: optionFromNullable(OperationObjectCodec), 34 | delete: optionFromNullable(OperationObjectCodec), 35 | options: optionFromNullable(OperationObjectCodec), 36 | head: optionFromNullable(OperationObjectCodec), 37 | patch: optionFromNullable(OperationObjectCodec), 38 | trace: optionFromNullable(OperationObjectCodec), 39 | servers: optionFromNullable(array(ServerObjectCodec)), 40 | parameters: optionFromNullable(array(union([ReferenceObjectCodec, ParameterObjectCodec]))), 41 | }, 42 | 'PathItemObject', 43 | ); 44 | -------------------------------------------------------------------------------- /src/schema/3.0/paths-object.ts: -------------------------------------------------------------------------------- 1 | import { record, string } from 'io-ts'; 2 | import { PathItemObject, PathItemObjectCodec } from './path-item-object'; 3 | import { Codec } from '../../utils/io-ts'; 4 | 5 | export interface PathsObject extends Record {} 6 | 7 | export const PathsObjectCodec: Codec = record(string, PathItemObjectCodec, 'PathsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/3.0/reference-object.ts: -------------------------------------------------------------------------------- 1 | import { string, type } from 'io-ts'; 2 | import { Codec } from '../../utils/io-ts'; 3 | 4 | export interface ReferenceObject { 5 | readonly $ref: string; 6 | } 7 | 8 | export const ReferenceObjectCodec: Codec = type( 9 | { 10 | $ref: string, 11 | }, 12 | 'ReferenceObject', 13 | ); 14 | -------------------------------------------------------------------------------- /src/schema/3.0/request-body-object.ts: -------------------------------------------------------------------------------- 1 | import { boolean, record, string, type } from 'io-ts'; 2 | import { MediaTypeObject, MediaTypeObjectCodec } from './media-type-object'; 3 | import { Option } from 'fp-ts/lib/Option'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | 7 | export interface RequestBodyObject { 8 | readonly description: Option; 9 | readonly content: Record; 10 | readonly required: Option; 11 | } 12 | 13 | export const RequestBodyObjectCodec: Codec = type( 14 | { 15 | content: record(string, MediaTypeObjectCodec), 16 | description: optionFromNullable(string), 17 | required: optionFromNullable(boolean), 18 | }, 19 | 'RequestBodyObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/3.0/response-object.ts: -------------------------------------------------------------------------------- 1 | import { record, string, type } from 'io-ts'; 2 | import { MediaTypeObject, MediaTypeObjectCodec } from './media-type-object'; 3 | import { Option } from 'fp-ts/lib/Option'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | 7 | export interface ResponseObject { 8 | readonly description: string; 9 | readonly content: Option>; 10 | } 11 | 12 | export const ResponseObjectCodec: Codec = type( 13 | { 14 | description: string, 15 | content: optionFromNullable(record(string, MediaTypeObjectCodec)), 16 | }, 17 | 'ResponseObject', 18 | ); 19 | -------------------------------------------------------------------------------- /src/schema/3.0/responses-object.ts: -------------------------------------------------------------------------------- 1 | import { record, string, union } from 'io-ts'; 2 | import { ResponseObject, ResponseObjectCodec } from './response-object'; 3 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 4 | import { Codec } from '../../utils/io-ts'; 5 | 6 | export interface ResponsesObject extends Record {} 7 | 8 | export const ResponsesObjectCodec: Codec = record( 9 | string, 10 | union([ReferenceObjectCodec, ResponseObjectCodec]), 11 | 'ResponsesObject', 12 | ); 13 | -------------------------------------------------------------------------------- /src/schema/3.0/server-object.ts: -------------------------------------------------------------------------------- 1 | import { ServerVariableObject, ServerVariableObjectCodec } from './server-variable-object'; 2 | import { record, string, type } from 'io-ts'; 3 | import { Option } from 'fp-ts/lib/Option'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | import { Codec } from '../../utils/io-ts'; 6 | 7 | export interface ServerObject { 8 | readonly url: string; 9 | readonly description: Option; 10 | readonly variables: Option>; 11 | } 12 | 13 | export const ServerObjectCodec: Codec = type( 14 | { 15 | url: string, 16 | description: optionFromNullable(string), 17 | variables: optionFromNullable(record(string, ServerVariableObjectCodec)), 18 | }, 19 | 'ServerObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/3.0/server-variable-object.ts: -------------------------------------------------------------------------------- 1 | import { array, string, type } from 'io-ts'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { Option } from 'fp-ts/lib/Option'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | 6 | export interface ServerVariableObject { 7 | readonly enum: Option; 8 | readonly default: string; 9 | readonly description: Option; 10 | } 11 | 12 | export const ServerVariableObjectCodec: Codec = type( 13 | { 14 | default: string, 15 | enum: optionFromNullable(array(string)), 16 | description: optionFromNullable(string), 17 | }, 18 | 'ServerVariableObject', 19 | ); 20 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/asyncapi-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { InfoObject, InfoObjectCodec } from './info-object'; 3 | import { ServersObject, ServersObjectCodec } from './servers-object'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { literal, type } from 'io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | import { ChannelsObject, ChannelsObjectCodec } from './channels-object'; 8 | import { ComponentsObject, ComponentsObjectCodec } from './components-object'; 9 | import { TagsObject, TagsObjectCodec } from './tags-object'; 10 | import { ExternalDocumentationObject, ExternalDocumentationObjectCodec } from './external-documentation-object'; 11 | 12 | export interface AsyncAPIObject { 13 | readonly asyncapi: '2.0.0'; 14 | readonly info: InfoObject; 15 | readonly servers: Option; 16 | readonly channels: ChannelsObject; 17 | readonly components: Option; 18 | readonly tags: Option; 19 | readonly externalDocs: Option; 20 | } 21 | 22 | export const AsyncAPIObjectCodec: Codec = type( 23 | { 24 | asyncapi: literal('2.0.0'), 25 | info: InfoObjectCodec, 26 | servers: optionFromNullable(ServersObjectCodec), 27 | channels: ChannelsObjectCodec, 28 | components: optionFromNullable(ComponentsObjectCodec), 29 | tags: optionFromNullable(TagsObjectCodec), 30 | externalDocs: optionFromNullable(ExternalDocumentationObjectCodec), 31 | }, 32 | 'AsyncAPIObject', 33 | ); 34 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/channel-bindings-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { 3 | WebsocketsChannelBindingObject, 4 | WebsocketsChannelBindingObjectCodec, 5 | } from './websockets-channel-binding-object'; 6 | import { Codec } from '../../utils/io-ts'; 7 | import { type } from 'io-ts'; 8 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 9 | 10 | export interface ChannelBindingsObject { 11 | readonly ws: Option; 12 | } 13 | 14 | export const ChannelBindingsObjectCodec: Codec = type( 15 | { 16 | ws: optionFromNullable(WebsocketsChannelBindingObjectCodec), 17 | }, 18 | 'ChannelBindingsObject', 19 | ); 20 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/channel-item-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { OperationObject, OperationObjectCodec } from './operation-object'; 3 | import { ParametersObject, ParametersObjectCodec } from './parameters-object'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { string, type } from 'io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | import { ChannelBindingsObject, ChannelBindingsObjectCodec } from './channel-bindings-object'; 8 | 9 | export interface ChannelItemObject { 10 | readonly $ref: Option; 11 | readonly description: Option; 12 | readonly subscribe: Option; 13 | readonly publish: Option; 14 | readonly parameters: Option; 15 | readonly bindings: Option; 16 | } 17 | 18 | export const ChannelItemObjectCodec: Codec = type( 19 | { 20 | $ref: optionFromNullable(string), 21 | description: optionFromNullable(string), 22 | subscribe: optionFromNullable(OperationObjectCodec), 23 | publish: optionFromNullable(OperationObjectCodec), 24 | parameters: optionFromNullable(ParametersObjectCodec), 25 | bindings: optionFromNullable(ChannelBindingsObjectCodec), 26 | }, 27 | 'ChannelItemObject', 28 | ); 29 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/channels-object.ts: -------------------------------------------------------------------------------- 1 | import { ChannelItemObject, ChannelItemObjectCodec } from './channel-item-object'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { record, string } from 'io-ts'; 4 | 5 | export interface ChannelsObject extends Record {} 6 | 7 | export const ChannelsObjectCodec: Codec = record(string, ChannelItemObjectCodec, 'ChannelsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/contact-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | 6 | export interface ContactObject { 7 | readonly name: Option; 8 | readonly url: Option; 9 | readonly email: Option; 10 | } 11 | 12 | export const ContactObjectCodec: Codec = type( 13 | { 14 | name: optionFromNullable(string), 15 | url: optionFromNullable(string), 16 | email: optionFromNullable(string), 17 | }, 18 | 'ContactObject', 19 | ); 20 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/correlation-id-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | 6 | export interface CorrelationIdObject { 7 | readonly description: Option; 8 | readonly location: string; 9 | } 10 | 11 | export const CorrelationIdObjectCodec: Codec = type( 12 | { 13 | description: optionFromNullable(string), 14 | location: string, 15 | }, 16 | 'CorrelationIdObject', 17 | ); 18 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/external-documentation-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | 6 | export interface ExternalDocumentationObject { 7 | readonly description: Option; 8 | readonly url: string; 9 | } 10 | 11 | export const ExternalDocumentationObjectCodec: Codec = type( 12 | { 13 | description: optionFromNullable(string), 14 | url: string, 15 | }, 16 | 'ExternalDocumentationObject', 17 | ); 18 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/info-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ContactObject, ContactObjectCodec } from './contact-object'; 3 | import { LicenseObject, LicenseObjectCodec } from './license-object'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { string, type } from 'io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | 8 | export interface InfoObject { 9 | readonly title: string; 10 | readonly version: string; 11 | readonly description: Option; 12 | readonly termsOfService: Option; 13 | readonly contact: Option; 14 | readonly license: Option; 15 | } 16 | 17 | export const InfoObjectCodec: Codec = type( 18 | { 19 | title: string, 20 | version: string, 21 | description: optionFromNullable(string), 22 | termsOfService: optionFromNullable(string), 23 | contact: optionFromNullable(ContactObjectCodec), 24 | license: optionFromNullable(LicenseObjectCodec), 25 | }, 26 | 'InfoObject', 27 | ); 28 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/license-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | 6 | export interface LicenseObject { 7 | readonly name: string; 8 | readonly url: Option; 9 | } 10 | 11 | export const LicenseObjectCodec: Codec = type( 12 | { 13 | name: string, 14 | url: optionFromNullable(string), 15 | }, 16 | 'LicenseObject', 17 | ); 18 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/message-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 3 | import { CorrelationIdObject, CorrelationIdObjectCodec } from './correlation-id-object'; 4 | import { TagsObject, TagsObjectCodec } from './tags-object'; 5 | import { ExternalDocumentationObject, ExternalDocumentationObjectCodec } from './external-documentation-object'; 6 | import { MessageTraitObject, MessageTraitObjectCodec } from './message-trait-object'; 7 | import { ObjectSchemaObject, ObjectSchemaObjectCodec, SchemaObject, SchemaObjectCodec } from './schema-object'; 8 | import { Codec } from '../../utils/io-ts'; 9 | import { array, record, string, type, union, unknown } from 'io-ts'; 10 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 11 | 12 | export interface MessageObject { 13 | readonly headers: Option; 14 | // inaccurate to the spec https://www.asyncapi.com/docs/specifications/2.0.0/#a-name-messageobject-a-message-object 15 | readonly payload: ReferenceObject | SchemaObject; 16 | readonly correlationId: Option; 17 | readonly schemaFormat: Option; 18 | readonly contentType: Option; 19 | readonly name: Option; 20 | readonly title: Option; 21 | readonly summary: Option; 22 | readonly description: Option; 23 | readonly tags: Option; 24 | readonly externalDocs: Option; 25 | readonly examples: Option[]>; 26 | readonly traits: Option; 27 | } 28 | 29 | export const MessageObjectCodec: Codec = type( 30 | { 31 | headers: optionFromNullable(ObjectSchemaObjectCodec), 32 | payload: union([ReferenceObjectCodec, SchemaObjectCodec]), 33 | correlationId: optionFromNullable(union([ReferenceObjectCodec, CorrelationIdObjectCodec])), 34 | schemaFormat: optionFromNullable(string), 35 | contentType: optionFromNullable(string), 36 | name: optionFromNullable(string), 37 | title: optionFromNullable(string), 38 | summary: optionFromNullable(string), 39 | description: optionFromNullable(string), 40 | tags: optionFromNullable(TagsObjectCodec), 41 | externalDocs: optionFromNullable(ExternalDocumentationObjectCodec), 42 | examples: optionFromNullable(array(record(string, unknown))), 43 | traits: optionFromNullable(array(MessageTraitObjectCodec)), 44 | }, 45 | 'MessageObject', 46 | ); 47 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/message-trait-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 3 | import { CorrelationIdObject, CorrelationIdObjectCodec } from './correlation-id-object'; 4 | import { TagsObject, TagsObjectCodec } from './tags-object'; 5 | import { ExternalDocumentationObject, ExternalDocumentationObjectCodec } from './external-documentation-object'; 6 | import { Codec } from '../../utils/io-ts'; 7 | import { record, string, type, union, unknown } from 'io-ts'; 8 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 9 | import { ObjectSchemaObject, ObjectSchemaObjectCodec } from './schema-object'; 10 | 11 | export interface MessageTraitObject { 12 | readonly headers: Option; 13 | readonly correlationId: Option; 14 | readonly schemaFormat: Option; 15 | readonly contentType: Option; 16 | readonly name: Option; 17 | readonly title: Option; 18 | readonly summary: Option; 19 | readonly description: Option; 20 | readonly tags: Option; 21 | readonly externalDocs: Option; 22 | readonly examples: Option>; 23 | } 24 | 25 | export const MessageTraitObjectCodec: Codec = type( 26 | { 27 | headers: optionFromNullable(union([ReferenceObjectCodec, ObjectSchemaObjectCodec])), 28 | correlationId: optionFromNullable(union([ReferenceObjectCodec, CorrelationIdObjectCodec])), 29 | schemaFormat: optionFromNullable(string), 30 | contentType: optionFromNullable(string), 31 | name: optionFromNullable(string), 32 | title: optionFromNullable(string), 33 | summary: optionFromNullable(string), 34 | description: optionFromNullable(string), 35 | tags: optionFromNullable(TagsObjectCodec), 36 | externalDocs: optionFromNullable(ExternalDocumentationObjectCodec), 37 | examples: optionFromNullable(record(string, unknown)), 38 | }, 39 | 'MessageTraitObject', 40 | ); 41 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/operation-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { TagsObject, TagsObjectCodec } from './tags-object'; 3 | import { ExternalDocumentationObject, ExternalDocumentationObjectCodec } from './external-documentation-object'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { array, string, type, union } from 'io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | import { OperationTraitObject, OperationTraitObjectCodec } from './operation-trait-object'; 8 | import { MessageObject, MessageObjectCodec } from './message-object'; 9 | import { NonEmptyArray } from 'fp-ts/lib/NonEmptyArray'; 10 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 11 | import { nonEmptyArray } from 'io-ts-types/lib/nonEmptyArray'; 12 | 13 | export interface OperationObjectOneOfMessage { 14 | readonly oneOf: NonEmptyArray; 15 | } 16 | export const OperationObjectOneOfMessageCodec: Codec = type( 17 | { 18 | oneOf: nonEmptyArray(union([ReferenceObjectCodec, MessageObjectCodec])), 19 | }, 20 | 'OperationObjectOneOfMessage', 21 | ); 22 | 23 | export interface OperationObject { 24 | readonly operationId: Option; 25 | readonly summary: Option; 26 | readonly description: Option; 27 | readonly tags: Option; 28 | readonly externalDocs: Option; 29 | readonly traits: Option; 30 | // inaccurate to https://www.asyncapi.com/docs/specifications/2.0.0/#a-name-operationobject-a-operation-object 31 | readonly message: ReferenceObject | MessageObject | OperationObjectOneOfMessage; 32 | } 33 | 34 | export const OperationObjectCodec: Codec = type( 35 | { 36 | operationId: optionFromNullable(string), 37 | summary: optionFromNullable(string), 38 | description: optionFromNullable(string), 39 | tags: optionFromNullable(TagsObjectCodec), 40 | externalDocs: optionFromNullable(ExternalDocumentationObjectCodec), 41 | traits: optionFromNullable(array(OperationTraitObjectCodec)), 42 | message: union([ReferenceObjectCodec, MessageObjectCodec, OperationObjectOneOfMessageCodec]), 43 | }, 44 | 'OperationObject', 45 | ); 46 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/operation-trait-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { TagsObject, TagsObjectCodec } from './tags-object'; 3 | import { ExternalDocumentationObject, ExternalDocumentationObjectCodec } from './external-documentation-object'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { string, type } from 'io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | 8 | export interface OperationTraitObject { 9 | readonly operationId: Option; 10 | readonly summary: Option; 11 | readonly description: Option; 12 | readonly tags: Option; 13 | readonly externalDocs: Option; 14 | } 15 | 16 | export const OperationTraitObjectCodec: Codec = type( 17 | { 18 | operationId: optionFromNullable(string), 19 | summary: optionFromNullable(string), 20 | description: optionFromNullable(string), 21 | tags: optionFromNullable(TagsObjectCodec), 22 | externalDocs: optionFromNullable(ExternalDocumentationObjectCodec), 23 | }, 24 | 'OperationTraitObject', 25 | ); 26 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/parameter-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { SchemaObject, SchemaObjectCodec } from './schema-object'; 3 | import { Codec } from '../../utils/io-ts'; 4 | import { string, type } from 'io-ts'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | 7 | export interface ParameterObject { 8 | readonly description: Option; 9 | readonly schema: Option; 10 | readonly location: Option; 11 | } 12 | 13 | export const ParameterObjectCodec: Codec = type( 14 | { 15 | description: optionFromNullable(string), 16 | schema: optionFromNullable(SchemaObjectCodec), 17 | location: optionFromNullable(string), 18 | }, 19 | 'ParameterObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/parameters-object.ts: -------------------------------------------------------------------------------- 1 | import { brand, Branded, record, string, union } from 'io-ts'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { ReferenceObject, ReferenceObjectCodec } from './reference-object'; 4 | import { ParameterObject, ParameterObjectCodec } from './parameter-object'; 5 | 6 | export interface ParametersObjectFieldPatternBrand { 7 | readonly ParametersObjectFieldPattern: unique symbol; 8 | } 9 | export type ParametersObjectPattern = Branded; 10 | 11 | const pattern = /^[A-Za-z0-9_\-]+$/; 12 | const ParametersObjectFieldPatternCodec = brand( 13 | string, 14 | (v): v is ParametersObjectPattern => pattern.test(v), 15 | 'ParametersObjectFieldPattern', 16 | ); 17 | 18 | export interface ParametersObject extends Record {} 19 | 20 | export const ParametersObjectCodec: Codec = record( 21 | ParametersObjectFieldPatternCodec, 22 | union([ReferenceObjectCodec, ParameterObjectCodec]), 23 | 'ParametersObject', 24 | ); 25 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/reference-object.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../utils/io-ts'; 2 | import { string, type } from 'io-ts'; 3 | 4 | export interface ReferenceObject { 5 | readonly $ref: string; 6 | } 7 | 8 | export const ReferenceObjectCodec: Codec = type( 9 | { 10 | $ref: string, 11 | }, 12 | 'ReferenceObject', 13 | ); 14 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/security-requirement-object.ts: -------------------------------------------------------------------------------- 1 | import { record, string } from 'io-ts'; 2 | import { Codec } from '../../utils/io-ts'; 3 | 4 | export interface SecurityRequirementObject extends Record {} 5 | 6 | export const SecurityRequirementObjectCodec: Codec = record( 7 | string, 8 | string, 9 | 'SecurityRequirementObject', 10 | ); 11 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/server-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ServerVariableObject, ServerVariableObjectCodec } from './server-variable-object'; 3 | import { SecurityRequirementObject, SecurityRequirementObjectCodec } from './security-requirement-object'; 4 | import { Codec } from '../../utils/io-ts'; 5 | import { array, record, string, type } from 'io-ts'; 6 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 7 | 8 | export interface ServerObject { 9 | readonly url: string; 10 | readonly protocol: string; 11 | readonly protocolVersion: Option; 12 | readonly description: Option; 13 | readonly variables: Option>; 14 | readonly security: Option; 15 | } 16 | 17 | export const ServerObjectCodec: Codec = type( 18 | { 19 | url: string, 20 | protocol: string, 21 | protocolVersion: optionFromNullable(string), 22 | description: optionFromNullable(string), 23 | variables: optionFromNullable(record(string, ServerVariableObjectCodec)), 24 | security: optionFromNullable(array(SecurityRequirementObjectCodec)), 25 | }, 26 | 'ServerObject', 27 | ); 28 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/server-variable-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { array, string, type } from 'io-ts'; 4 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 5 | 6 | export interface ServerVariableObject { 7 | readonly enum: Option; 8 | readonly default: Option; 9 | readonly description: Option; 10 | readonly examples: Option; 11 | } 12 | 13 | export const ServerVariableObjectCodec: Codec = type( 14 | { 15 | enum: optionFromNullable(array(string)), 16 | default: optionFromNullable(string), 17 | description: optionFromNullable(string), 18 | examples: optionFromNullable(array(string)), 19 | }, 20 | 'ServerVariableObject', 21 | ); 22 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/servers-object.ts: -------------------------------------------------------------------------------- 1 | import { brand, Branded, record, string } from 'io-ts'; 2 | import { ServerObject, ServerObjectCodec } from './server-object'; 3 | import { Codec } from '../../utils/io-ts'; 4 | 5 | export interface ServersObjectFieldPatternBrand { 6 | readonly ServersObjectFieldPattern: unique symbol; 7 | } 8 | export type ServersObjectPattern = Branded; 9 | 10 | const pattern = /^[A-Za-z0-9_\-]+$/; 11 | const ServersObjectFieldPatternCodec = brand( 12 | string, 13 | (v): v is ServersObjectPattern => pattern.test(v), 14 | 'ServersObjectFieldPattern', 15 | ); 16 | 17 | export interface ServersObject extends Record {} 18 | 19 | export const ServersObjectCodec: Codec = record( 20 | ServersObjectFieldPatternCodec, 21 | ServerObjectCodec, 22 | 'ServersObject', 23 | ); 24 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/tag-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ExternalDocumentationObject, ExternalDocumentationObjectCodec } from './external-documentation-object'; 3 | import { Codec } from '../../utils/io-ts'; 4 | import { string, type } from 'io-ts'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | 7 | export interface TagObject { 8 | readonly name: string; 9 | readonly description: Option; 10 | readonly externalDocs: Option; 11 | } 12 | 13 | export const TagObjectCodec: Codec = type( 14 | { 15 | name: string, 16 | description: optionFromNullable(string), 17 | externalDocs: optionFromNullable(ExternalDocumentationObjectCodec), 18 | }, 19 | 'TagObject', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/tags-object.ts: -------------------------------------------------------------------------------- 1 | import { TagObject, TagObjectCodec } from './tag-object'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { array } from 'io-ts'; 4 | 5 | export interface TagsObject extends Array {} 6 | 7 | export const TagsObjectCodec: Codec = array(TagObjectCodec, 'TagsObject'); 8 | -------------------------------------------------------------------------------- /src/schema/asyncapi-2.0.0/websockets-channel-binding-object.ts: -------------------------------------------------------------------------------- 1 | import { Option } from 'fp-ts/lib/Option'; 2 | import { ObjectSchemaObject, ObjectSchemaObjectCodec } from './schema-object'; 3 | import { Codec } from '../../utils/io-ts'; 4 | import { literal, string, type, union } from 'io-ts'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | 7 | export interface WebsocketsChannelBindingObject { 8 | readonly method: Option<'GET' | 'POST'>; 9 | readonly query: Option; 10 | readonly headers: Option; 11 | readonly bindingVersion: Option; 12 | } 13 | 14 | export const WebsocketsChannelBindingObjectCodec: Codec = type( 15 | { 16 | method: optionFromNullable(union([literal('GET'), literal('POST')])), 17 | query: optionFromNullable(ObjectSchemaObjectCodec), 18 | headers: optionFromNullable(ObjectSchemaObjectCodec), 19 | bindingVersion: optionFromNullable(string), 20 | }, 21 | 'WebsocketsChannelBindingObject', 22 | ); 23 | -------------------------------------------------------------------------------- /src/schema/sketch-121/abstract-document.ts: -------------------------------------------------------------------------------- 1 | import { SharedStyleContainer, SharedStyleContainerCodec } from './objects/shared-style-container'; 2 | import { Codec } from '../../utils/io-ts'; 3 | import { array, type } from 'io-ts'; 4 | import { SharedTextStyleContainer, SharedTextStyleContainerCodec } from './objects/shared-text-style-container'; 5 | import { ForeignLayerStyle, ForeignLayerStyleCodec } from './objects/foreign-layer-style'; 6 | import { ForeignTextStyle, ForeignTextStyleCodec } from './objects/foreign-text-style'; 7 | import { AssetCollection, AssetCollectionCodec } from './objects/asset-collection'; 8 | import { ObjectID, ObjectIDCodec } from './objects/object-id'; 9 | import { ForeignSymbol, ForeignSymbolCodec } from './objects/foreign-symbol'; 10 | 11 | export interface AbstractDocument { 12 | readonly do_objectID: ObjectID; 13 | readonly assets: AssetCollection; 14 | readonly foreignLayerStyles: ForeignLayerStyle[]; 15 | readonly foreignTextStyles: ForeignTextStyle[]; 16 | readonly foreignSymbols: ForeignSymbol[]; 17 | readonly layerTextStyles: SharedTextStyleContainer; 18 | readonly layerStyles: SharedStyleContainer; 19 | } 20 | 21 | export const AbstractDocumentCodec: Codec = type({ 22 | do_objectID: ObjectIDCodec, 23 | assets: AssetCollectionCodec, 24 | foreignLayerStyles: array(ForeignLayerStyleCodec), 25 | foreignTextStyles: array(ForeignTextStyleCodec), 26 | foreignSymbols: array(ForeignSymbolCodec), 27 | layerTextStyles: SharedTextStyleContainerCodec, 28 | layerStyles: SharedStyleContainerCodec, 29 | }); 30 | -------------------------------------------------------------------------------- /src/schema/sketch-121/document.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../utils/io-ts'; 2 | import { array, intersection, type } from 'io-ts'; 3 | import { AbstractDocument, AbstractDocumentCodec } from './abstract-document'; 4 | import { Page, PageCodec } from './objects/page'; 5 | 6 | export interface Document extends AbstractDocument { 7 | readonly pages: Page[]; 8 | } 9 | 10 | export const DocumentCodec: Codec = intersection( 11 | [ 12 | AbstractDocumentCodec, 13 | type({ 14 | pages: array(PageCodec), 15 | }), 16 | ], 17 | 'Document', 18 | ); 19 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/blend-mode.ts: -------------------------------------------------------------------------------- 1 | import { Codec, mapper } from '../../../utils/io-ts'; 2 | import { union } from 'io-ts'; 3 | 4 | export type BlendMode = 5 | | 'Normal' 6 | | 'Darken' 7 | | 'Multiply' 8 | | 'Color burn' 9 | | 'Lighten' 10 | | 'Screen' 11 | | 'Color dodge' 12 | | 'Overlay' 13 | | 'Soft light' 14 | | 'Hard light' 15 | | 'Difference' 16 | | 'Exclusion' 17 | | 'Hue' 18 | | 'Saturation' 19 | | 'Color' 20 | | 'Luminosity' 21 | | 'Plus darker' 22 | | 'Plus lighter'; 23 | 24 | export const BlendModeCodec: Codec = union( 25 | [ 26 | mapper('Normal', 0), 27 | mapper('Darken', 1), 28 | mapper('Multiply', 2), 29 | mapper('Color burn', 3), 30 | mapper('Lighten', 4), 31 | mapper('Screen', 5), 32 | mapper('Color dodge', 6), 33 | mapper('Overlay', 7), 34 | mapper('Soft light', 8), 35 | mapper('Hard light', 9), 36 | mapper('Difference', 10), 37 | mapper('Exclusion', 11), 38 | mapper('Hue', 12), 39 | mapper('Saturation', 13), 40 | mapper('Color', 14), 41 | mapper('Luminosity', 15), 42 | mapper('Plus darker', 16), 43 | mapper('Plus lighter', 17), 44 | ], 45 | 'BlendMode', 46 | ); 47 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/border-position.ts: -------------------------------------------------------------------------------- 1 | import { Codec, mapper } from '../../../utils/io-ts'; 2 | import { union } from 'io-ts'; 3 | 4 | export type BorderPosition = 'Center' | 'Inside' | 'Outside'; 5 | 6 | export const BorderPositionCodec: Codec = union( 7 | [mapper('Center', 0), mapper('Inside', 1), mapper('Outside', 2)], 8 | 'BorderPosition', 9 | ); 10 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/fill-type.ts: -------------------------------------------------------------------------------- 1 | import { Codec, mapper } from '../../../utils/io-ts'; 2 | import { union } from 'io-ts'; 3 | 4 | export type FillType = 'Color' | 'Gradient' | 'Pattern'; 5 | 6 | export const FillTypeCodec: Codec = union( 7 | [mapper('Color', 0), mapper('Gradient', 1), mapper('Pattern', 2)], 8 | 'FillType', 9 | ); 10 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/gradient-type.ts: -------------------------------------------------------------------------------- 1 | import { literal, union } from 'io-ts'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | 4 | export type GradientType = 0 | 1 | 2; 5 | 6 | export const GradientTypeCodec: Codec = union( 7 | [literal(0, 'Linear'), literal(1, 'Radial'), literal(2, 'Angular')], 8 | 'GradientType', 9 | ); 10 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/layer-class.ts: -------------------------------------------------------------------------------- 1 | import { literal, union } from 'io-ts'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | 4 | export type LayerClass = 5 | | 'symbolInstance' 6 | | 'symbolMaster' 7 | | 'group' 8 | | 'oval' 9 | | 'text' 10 | | 'rectangle' 11 | | 'shapePath' 12 | | 'shapeGroup' 13 | | 'artboard'; 14 | 15 | export const LayerClassCodec: Codec = union( 16 | [ 17 | literal('symbolInstance'), 18 | literal('symbolMaster'), 19 | literal('group'), 20 | literal('oval'), 21 | literal('text'), 22 | literal('rectangle'), 23 | literal('shapePath'), 24 | literal('shapeGroup'), 25 | literal('artboard'), 26 | ], 27 | 'LayerClass', 28 | ); 29 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/text-horizontal-alignment.ts: -------------------------------------------------------------------------------- 1 | import { Codec, mapper } from '../../../utils/io-ts'; 2 | import { union } from 'io-ts'; 3 | 4 | export type TextHorizontalAlignment = 'Left' | 'Right' | 'Centered' | 'Justified' | 'Natural'; 5 | 6 | export const TextHorizontalAlignmentCodec: Codec = union( 7 | [mapper('Left', 0), mapper('Right', 1), mapper('Centered', 2), mapper('Justified', 3), mapper('Natural', 4)], 8 | 'TextHorizontalAlignment', 9 | ); 10 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/text-transform.ts: -------------------------------------------------------------------------------- 1 | import { Codec, mapper } from '../../../utils/io-ts'; 2 | import { union } from 'io-ts'; 3 | 4 | export type TextTransform = 'None' | 'Uppercase' | 'Lowercase'; 5 | 6 | export const TextTransformCodec: Codec = union( 7 | [mapper('None', 0), mapper('Uppercase', 1), mapper('Lowercase', 2)], 8 | 'TextTransform', 9 | ); 10 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/text-vertical-alignment.ts: -------------------------------------------------------------------------------- 1 | import { Codec, mapper } from '../../../utils/io-ts'; 2 | import { union } from 'io-ts'; 3 | 4 | export type TextVerticalAlignment = 'Top' | 'Middle' | 'Bottom'; 5 | 6 | export const TextVerticalAlignmentCodec: Codec = union( 7 | [mapper('Top', 0), mapper('Middle', 1), mapper('Bottom', 2)], 8 | 'TextVerticalAlignment', 9 | ); 10 | -------------------------------------------------------------------------------- /src/schema/sketch-121/enums/underline-style.ts: -------------------------------------------------------------------------------- 1 | import { Codec, mapper } from '../../../utils/io-ts'; 2 | import { union } from 'io-ts'; 3 | 4 | export type UnderlineStyle = 'None' | 'Underlined'; 5 | 6 | export const UnderlineStyleCodec: Codec = union( 7 | [mapper('None', 0), mapper('Underlined', 1)], 8 | 'UnderlineStyle', 9 | ); 10 | -------------------------------------------------------------------------------- /src/schema/sketch-121/file-format.ts: -------------------------------------------------------------------------------- 1 | import { Meta, MetaCodec } from './meta'; 2 | import { User, UserCodec } from './user'; 3 | import { Codec } from '../../utils/io-ts'; 4 | import { type } from 'io-ts'; 5 | import { Document, DocumentCodec } from './document'; 6 | 7 | export interface FileFormat { 8 | readonly document: Document; 9 | readonly meta: Meta; 10 | readonly user: User; 11 | } 12 | 13 | export const FileFormatCodec: Codec = type({ 14 | document: DocumentCodec, 15 | meta: MetaCodec, 16 | user: UserCodec, 17 | }); 18 | -------------------------------------------------------------------------------- /src/schema/sketch-121/meta.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../utils/io-ts'; 2 | import { literal, type, union } from 'io-ts'; 3 | 4 | export interface Meta { 5 | readonly version: 121 | 122 | 123; 6 | } 7 | 8 | export const MetaCodec: Codec = type( 9 | { 10 | version: union([literal(121), literal(122), literal(123)]), 11 | }, 12 | 'Meta', 13 | ); 14 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/asset-collection.ts: -------------------------------------------------------------------------------- 1 | import { ColorAsset, ColorAssetCodec } from './color-asset'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { array, type } from 'io-ts'; 4 | import { Color, ColorCodec } from './color'; 5 | import { Gradient, GradientCodec } from './gradient'; 6 | import { GradientAsset, GradientAssetCodec } from './gradient-asset'; 7 | import { ObjectID, ObjectIDCodec } from './object-id'; 8 | 9 | export interface AssetCollection { 10 | readonly do_objectID: ObjectID; 11 | readonly colorAssets: ColorAsset[]; 12 | readonly gradientAssets: GradientAsset[]; 13 | readonly colors: Color[]; 14 | readonly gradients: Gradient[]; 15 | } 16 | 17 | export const AssetCollectionCodec: Codec = type({ 18 | do_objectID: ObjectIDCodec, 19 | colorAssets: array(ColorAssetCodec), 20 | gradientAssets: array(GradientAssetCodec), 21 | colors: array(ColorCodec), 22 | gradients: array(GradientCodec), 23 | }); 24 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/border-options.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { array, boolean, number, type } from 'io-ts'; 3 | 4 | export interface BorderOptions { 5 | readonly isEnabled: boolean; 6 | readonly dashPattern: number[]; 7 | } 8 | 9 | export const BorderOptionsCodec: Codec = type({ 10 | isEnabled: boolean, 11 | dashPattern: array(number), 12 | }); 13 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/border.ts: -------------------------------------------------------------------------------- 1 | import { Codec, nonNegative, NonNegative } from '../../../utils/io-ts'; 2 | import { boolean, type } from 'io-ts'; 3 | import { Color, ColorCodec } from './color'; 4 | import { FillType, FillTypeCodec } from '../enums/fill-type'; 5 | import { BorderPosition, BorderPositionCodec } from '../enums/border-position'; 6 | import { GraphicsContextSettings, GraphicsContextSettingsCodec } from './graphics-context-settings'; 7 | import { Gradient, GradientCodec } from './gradient'; 8 | 9 | export interface Border { 10 | readonly isEnabled: boolean; 11 | readonly color: Color; 12 | readonly fillType: FillType; 13 | readonly position: BorderPosition; 14 | readonly thickness: NonNegative; 15 | readonly contextSettings: GraphicsContextSettings; 16 | readonly gradient: Gradient; 17 | } 18 | 19 | export const BorderCodec: Codec = type( 20 | { 21 | isEnabled: boolean, 22 | color: ColorCodec, 23 | fillType: FillTypeCodec, 24 | position: BorderPositionCodec, 25 | thickness: nonNegative, 26 | contextSettings: GraphicsContextSettingsCodec, 27 | gradient: GradientCodec, 28 | }, 29 | 'Border', 30 | ); 31 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/color-asset.ts: -------------------------------------------------------------------------------- 1 | import { Color, ColorCodec } from './color'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | import { ObjectID, ObjectIDCodec } from './object-id'; 5 | 6 | export interface ColorAsset { 7 | readonly do_objectID: ObjectID; 8 | readonly name: string; 9 | readonly color: Color; 10 | } 11 | 12 | export const ColorAssetCodec: Codec = type( 13 | { 14 | do_objectID: ObjectIDCodec, 15 | name: string, 16 | color: ColorCodec, 17 | }, 18 | 'ColorAsset', 19 | ); 20 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/color-controls.ts: -------------------------------------------------------------------------------- 1 | import { UnitInterval, UnitIntervalCodec } from '../utils/unit-interval'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { boolean, type } from 'io-ts'; 4 | 5 | export interface ColorControls { 6 | readonly isEnabled: boolean; 7 | readonly brightness: UnitInterval; 8 | readonly contrast: UnitInterval; 9 | readonly hue: UnitInterval; 10 | readonly saturation: UnitInterval; 11 | } 12 | 13 | export const ColorControlsCodec: Codec = type( 14 | { 15 | isEnabled: boolean, 16 | brightness: UnitIntervalCodec, 17 | contrast: UnitIntervalCodec, 18 | hue: UnitIntervalCodec, 19 | saturation: UnitIntervalCodec, 20 | }, 21 | 'ColorControls', 22 | ); 23 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/color.ts: -------------------------------------------------------------------------------- 1 | import { UnitInterval, UnitIntervalCodec } from '../utils/unit-interval'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { type } from 'io-ts'; 4 | 5 | export interface Color { 6 | readonly alpha: UnitInterval; 7 | readonly red: UnitInterval; 8 | readonly green: UnitInterval; 9 | readonly blue: UnitInterval; 10 | } 11 | 12 | export const ColorCodec: Codec = type( 13 | { 14 | alpha: UnitIntervalCodec, 15 | red: UnitIntervalCodec, 16 | green: UnitIntervalCodec, 17 | blue: UnitIntervalCodec, 18 | }, 19 | 'Color', 20 | ); 21 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/fill.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { boolean, type } from 'io-ts'; 3 | import { Color, ColorCodec } from './color'; 4 | import { Gradient, GradientCodec } from './gradient'; 5 | import { FillType, FillTypeCodec } from '../enums/fill-type'; 6 | import { GraphicsContextSettings, GraphicsContextSettingsCodec } from './graphics-context-settings'; 7 | 8 | export interface Fill { 9 | readonly isEnabled: boolean; 10 | readonly color: Color; 11 | readonly fillType: FillType; 12 | readonly contextSettings: GraphicsContextSettings; 13 | readonly gradient: Gradient; 14 | } 15 | 16 | export const FillCodec: Codec = type( 17 | { 18 | isEnabled: boolean, 19 | color: ColorCodec, 20 | fillType: FillTypeCodec, 21 | contextSettings: GraphicsContextSettingsCodec, 22 | gradient: GradientCodec, 23 | }, 24 | 'Fill', 25 | ); 26 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/font-descriptor.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { number, string, type } from 'io-ts'; 3 | 4 | export interface FontDescriptor { 5 | readonly attributes: { 6 | readonly name: string; 7 | readonly size: number; 8 | }; 9 | } 10 | 11 | export const FontDescriptorCodec: Codec = type({ 12 | attributes: type({ 13 | name: string, 14 | size: number, 15 | }), 16 | }); 17 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/foreign-layer-style.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { string, type } from 'io-ts'; 3 | import { SharedStyle, SharedStyleCodec } from './shared-style'; 4 | 5 | export interface ForeignLayerStyle { 6 | readonly sourceLibraryName: string; 7 | readonly localSharedStyle: SharedStyle; 8 | } 9 | 10 | export const ForeignLayerStyleCodec: Codec = type( 11 | { 12 | sourceLibraryName: string, 13 | localSharedStyle: SharedStyleCodec, 14 | }, 15 | 'ForeignLayerStyle', 16 | ); 17 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/foreign-symbol.ts: -------------------------------------------------------------------------------- 1 | import { type } from 'io-ts'; 2 | import { Layer, LayerCodec } from './layer'; 3 | import { ObjectID, ObjectIDCodec } from './object-id'; 4 | import { Codec } from '../../../utils/io-ts'; 5 | 6 | export interface ForeignSymbol { 7 | do_objectID: ObjectID; 8 | originalMaster: Layer; 9 | symbolMaster: Layer; 10 | } 11 | 12 | export const ForeignSymbolCodec: Codec = type( 13 | { 14 | do_objectID: ObjectIDCodec, 15 | originalMaster: LayerCodec, 16 | symbolMaster: LayerCodec, 17 | }, 18 | 'ForeignSymbol', 19 | ); 20 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/foreign-text-style.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { string, type } from 'io-ts'; 3 | import { SharedStyle, SharedStyleCodec } from './shared-style'; 4 | 5 | export interface ForeignTextStyle { 6 | readonly sourceLibraryName: string; 7 | readonly localSharedStyle: SharedStyle; 8 | } 9 | 10 | export const ForeignTextStyleCodec: Codec = type( 11 | { 12 | sourceLibraryName: string, 13 | localSharedStyle: SharedStyleCodec, 14 | }, 15 | 'ForeignTextStyle', 16 | ); 17 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/gradient-asset.ts: -------------------------------------------------------------------------------- 1 | import { Gradient, GradientCodec } from './gradient'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { string, type } from 'io-ts'; 4 | import { ObjectID, ObjectIDCodec } from './object-id'; 5 | 6 | export interface GradientAsset { 7 | readonly do_objectID: ObjectID; 8 | readonly name: string; 9 | readonly gradient: Gradient; 10 | } 11 | 12 | export const GradientAssetCodec: Codec = type({ 13 | do_objectID: ObjectIDCodec, 14 | name: string, 15 | gradient: GradientCodec, 16 | }); 17 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/gradient-stop.ts: -------------------------------------------------------------------------------- 1 | import { Color, ColorCodec } from './color'; 2 | import { UnitInterval, UnitIntervalCodec } from '../utils/unit-interval'; 3 | import { Codec } from '../../../utils/io-ts'; 4 | import { type } from 'io-ts'; 5 | 6 | export interface GradientStop { 7 | readonly color: Color; 8 | readonly position: UnitInterval; 9 | } 10 | 11 | export const GradientStopCodec: Codec = type( 12 | { 13 | color: ColorCodec, 14 | position: UnitIntervalCodec, 15 | }, 16 | 'GradientStopCodec', 17 | ); 18 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/gradient.ts: -------------------------------------------------------------------------------- 1 | import { GradientType, GradientTypeCodec } from '../enums/gradient-type'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { array, type } from 'io-ts'; 4 | import { PointString, PointStringCodec } from '../utils/point-string'; 5 | import { GradientStop, GradientStopCodec } from './gradient-stop'; 6 | 7 | export interface Gradient { 8 | readonly gradientType: GradientType; 9 | readonly from: PointString; 10 | readonly to: PointString; 11 | readonly stops: GradientStop[]; 12 | } 13 | 14 | export const GradientCodec: Codec = type( 15 | { 16 | gradientType: GradientTypeCodec, 17 | from: PointStringCodec, 18 | to: PointStringCodec, 19 | stops: array(GradientStopCodec), 20 | }, 21 | 'Gradient', 22 | ); 23 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/graphics-context-settings.ts: -------------------------------------------------------------------------------- 1 | import { BlendMode, BlendModeCodec } from '../enums/blend-mode'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { number, type } from 'io-ts'; 4 | 5 | export interface GraphicsContextSettings { 6 | readonly blendMode: BlendMode; 7 | readonly opacity: number; 8 | } 9 | 10 | export const GraphicsContextSettingsCodec: Codec = type( 11 | { 12 | blendMode: BlendModeCodec, 13 | opacity: number, 14 | }, 15 | 'GraphicsContextSettings', 16 | ); 17 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/inner-shadow.ts: -------------------------------------------------------------------------------- 1 | import { Color, ColorCodec } from './color'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | import { boolean, number, type } from 'io-ts'; 4 | 5 | export interface InnerShadow { 6 | readonly isEnabled: boolean; 7 | readonly blurRadius: number; 8 | readonly color: Color; 9 | readonly offsetX: number; 10 | readonly offsetY: number; 11 | readonly spread: number; 12 | } 13 | 14 | export const InnerShadowCodec: Codec = type( 15 | { 16 | isEnabled: boolean, 17 | blurRadius: number, 18 | color: ColorCodec, 19 | offsetX: number, 20 | offsetY: number, 21 | spread: number, 22 | }, 23 | 'InnerShadow', 24 | ); 25 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/layer.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { Style, StyleCodec } from './style'; 3 | import { ObjectID, ObjectIDCodec } from './object-id'; 4 | import { string, type, array, recursion, boolean } from 'io-ts'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | import { Option } from 'fp-ts/lib/Option'; 7 | import { OverrideValue, OverrideValueCodec } from './override-value'; 8 | import { LayerClass, LayerClassCodec } from '../enums/layer-class'; 9 | 10 | export interface Layer { 11 | readonly _class: LayerClass; 12 | readonly do_objectID: ObjectID; 13 | readonly name: string; 14 | readonly style: Style; 15 | readonly layers: Option; 16 | readonly isVisible: boolean; 17 | readonly overrideValues: Option; 18 | readonly sharedStyleID: Option; 19 | readonly symbolID: Option; 20 | } 21 | 22 | export const LayerCodec: Codec = recursion('Layer', () => 23 | type( 24 | { 25 | _class: LayerClassCodec, 26 | do_objectID: ObjectIDCodec, 27 | name: string, 28 | style: StyleCodec, 29 | isVisible: boolean, 30 | layers: optionFromNullable(array(LayerCodec)), 31 | overrideValues: optionFromNullable(array(OverrideValueCodec)), 32 | sharedStyleID: optionFromNullable(ObjectIDCodec), 33 | symbolID: optionFromNullable(ObjectIDCodec), 34 | }, 35 | 'Layer', 36 | ), 37 | ); 38 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/object-id.ts: -------------------------------------------------------------------------------- 1 | import { brand, Branded, string } from 'io-ts'; 2 | 3 | const UUIDReg = /[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}/; 4 | const ObjectIDReg = new RegExp(`${UUIDReg.source}(\\[${UUIDReg.source}\\])?`, 'i'); 5 | 6 | interface ObjectIDBrand { 7 | readonly ObjectID: unique symbol; 8 | } 9 | export type ObjectID = Branded; 10 | 11 | export const ObjectIDCodec = brand(string, (n): n is ObjectID => ObjectIDReg.test(n), 'ObjectID'); 12 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/override-value.ts: -------------------------------------------------------------------------------- 1 | import { string, type } from 'io-ts'; 2 | import { Codec } from '../../../utils/io-ts'; 3 | 4 | export interface OverrideValue { 5 | readonly _class: string; 6 | readonly overrideName: string; 7 | readonly value: string; 8 | } 9 | 10 | export const OverrideValueCodec: Codec = type( 11 | { 12 | _class: string, 13 | value: string, 14 | overrideName: string, 15 | }, 16 | 'OverrideValue', 17 | ); 18 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/page-file-ref.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { string, type } from 'io-ts'; 3 | 4 | export interface PageFileRef { 5 | readonly _ref: string; 6 | } 7 | 8 | export const PageFileRefCodec: Codec = type({ 9 | _ref: string, 10 | }); 11 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/page.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { Style, StyleCodec } from './style'; 3 | import { ObjectID, ObjectIDCodec } from './object-id'; 4 | import { string, type, array } from 'io-ts'; 5 | import { Layer, LayerCodec } from './layer'; 6 | 7 | export interface Page { 8 | do_objectID: ObjectID; 9 | name: string; 10 | style: Style; 11 | layers: Layer[]; 12 | } 13 | 14 | export const PageCodec: Codec = type( 15 | { 16 | do_objectID: ObjectIDCodec, 17 | name: string, 18 | style: StyleCodec, 19 | layers: array(LayerCodec), 20 | }, 21 | 'Page', 22 | ); 23 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/paragraph-style.ts: -------------------------------------------------------------------------------- 1 | import { TextHorizontalAlignment, TextHorizontalAlignmentCodec } from '../enums/text-horizontal-alignment'; 2 | import { Option } from 'fp-ts/lib/Option'; 3 | import { Codec } from '../../../utils/io-ts'; 4 | import { number, type } from 'io-ts'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | 7 | export interface ParagraphStyle { 8 | readonly alignment: Option; 9 | readonly maximumLineHeight: Option; 10 | readonly minimumLineHeight: Option; 11 | } 12 | 13 | export const ParagraphStyleCodec: Codec = type({ 14 | alignment: optionFromNullable(TextHorizontalAlignmentCodec), 15 | maximumLineHeight: optionFromNullable(number), 16 | minimumLineHeight: optionFromNullable(number), 17 | }); 18 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/shadow.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { boolean, number, type } from 'io-ts'; 3 | import { Color, ColorCodec } from './color'; 4 | 5 | export interface Shadow { 6 | readonly isEnabled: boolean; 7 | readonly blurRadius: number; 8 | readonly color: Color; 9 | readonly offsetX: number; 10 | readonly offsetY: number; 11 | readonly spread: number; 12 | } 13 | 14 | export const ShadowCodec: Codec = type( 15 | { 16 | isEnabled: boolean, 17 | blurRadius: number, 18 | color: ColorCodec, 19 | offsetX: number, 20 | offsetY: number, 21 | spread: number, 22 | }, 23 | 'Shadow', 24 | ); 25 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/shared-style-container.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { array, type } from 'io-ts'; 3 | import { SharedStyle, SharedStyleCodec } from './shared-style'; 4 | 5 | export interface SharedStyleContainer { 6 | readonly objects: SharedStyle[]; 7 | } 8 | 9 | export const SharedStyleContainerCodec: Codec = type( 10 | { 11 | objects: array(SharedStyleCodec), 12 | }, 13 | 'SharedStyleContainer', 14 | ); 15 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/shared-style.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { string, type } from 'io-ts'; 3 | import { Style, StyleCodec } from './style'; 4 | import { ObjectID, ObjectIDCodec } from './object-id'; 5 | 6 | export interface SharedStyle { 7 | readonly do_objectID: ObjectID; 8 | readonly name: string; 9 | readonly value: Style; 10 | } 11 | 12 | export const SharedStyleCodec: Codec = type( 13 | { 14 | name: string, 15 | do_objectID: ObjectIDCodec, 16 | value: StyleCodec, 17 | }, 18 | 'SharedStyle', 19 | ); 20 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/shared-text-style-container.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { array, type } from 'io-ts'; 3 | import { SharedStyle, SharedStyleCodec } from './shared-style'; 4 | 5 | export interface SharedTextStyleContainer { 6 | readonly objects: SharedStyle[]; 7 | } 8 | 9 | export const SharedTextStyleContainerCodec: Codec = type( 10 | { 11 | objects: array(SharedStyleCodec), 12 | }, 13 | 'SharedTextStyleContainer', 14 | ); 15 | -------------------------------------------------------------------------------- /src/schema/sketch-121/objects/style.ts: -------------------------------------------------------------------------------- 1 | import { Codec } from '../../../utils/io-ts'; 2 | import { array, type } from 'io-ts'; 3 | import { Option } from 'fp-ts/lib/Option'; 4 | import { Fill, FillCodec } from './fill'; 5 | import { optionFromNullable } from 'io-ts-types/lib/optionFromNullable'; 6 | import { GraphicsContextSettings, GraphicsContextSettingsCodec } from './graphics-context-settings'; 7 | import { Border, BorderCodec } from './border'; 8 | import { BorderOptions, BorderOptionsCodec } from './border-options'; 9 | import { InnerShadow, InnerShadowCodec } from './inner-shadow'; 10 | import { Shadow, ShadowCodec } from './shadow'; 11 | import { TextStyle, TextStyleCodec } from './text-style'; 12 | import { ObjectID, ObjectIDCodec } from './object-id'; 13 | 14 | export interface Style { 15 | readonly do_objectID: ObjectID; 16 | readonly borders: Option; 17 | readonly borderOptions: BorderOptions; 18 | readonly fills: Option; 19 | readonly textStyle: Option; 20 | readonly shadows: Option; 21 | readonly innerShadows: InnerShadow[]; 22 | readonly contextSettings: Option; 23 | } 24 | 25 | export const StyleCodec: Codec