From baf381470127baab8130e0ba25a9f8760a998aba Mon Sep 17 00:00:00 2001 From: "Sergey S. Volkov" Date: Sat, 13 Feb 2021 02:39:25 +0300 Subject: [PATCH] Release 5.0.0 (#149) * BREAKING_CHANGE: fully refactored http-client.eta template; feat: image content kind; feat: request content type auto substitution * chore: update funding * feat: RequestHeaders, RequestParams types (issue #150, thanks @Fabiencdp); chore: removed apiConfig.generic usage in templates * internal: rename test scripts; docs: update CHANGELOG * fix: try to fix pseudo duplicated operationIds (issue #152, thanks @RoXuS for report) * feat: --default-response option; BREAKING_CHANGE: changed the default response body type ('any' -> 'void') * fix: remove hard coded request content type (issue #153, thanks @po5i); BREAKING_CHANGE: changed request body transformation * feat: request cancellation support (issue #96, thanks @ApacheEx) * bump: up project version to 5.0.0 * fix: critical bug with `:paramName` path params (issue #149) --- .github/FUNDING.yml | 12 +- CHANGELOG.md | 32 + README.md | 1 + index.d.ts | 6 +- index.js | 4 + package-lock.json | 2356 +---------- package.json | 25 +- src/apiConfig.js | 11 +- src/config.js | 1 + src/constants.js | 1 + src/index.js | 8 +- src/routes.js | 212 +- templates/default/api.eta | 28 +- templates/default/http-client.eta | 203 +- templates/default/procedure-call.eta | 48 +- templates/default/route-type.eta | 18 +- templates/modular/api.eta | 4 +- templates/modular/http-client.eta | 214 +- templates/modular/procedure-call.eta | 48 +- templates/modular/route-type.eta | 23 +- tests/README.md | 2 +- tests/generated/v2.0/adafruit.ts | 1215 +++--- tests/generated/v2.0/another-example.ts | 427 +- tests/generated/v2.0/api-with-examples.ts | 201 +- tests/generated/v2.0/authentiq.ts | 358 +- tests/generated/v2.0/example1.ts | 204 +- tests/generated/v2.0/file-formdata-example.ts | 195 +- tests/generated/v2.0/furkot-example.ts | 204 +- tests/generated/v2.0/giphy.ts | 357 +- tests/generated/v2.0/github-swagger.ts | 2490 +++++++++--- tests/generated/v2.0/path-args.ts | 196 +- tests/generated/v2.0/petstore-expanded.ts | 221 +- tests/generated/v2.0/petstore-minimal.ts | 193 +- tests/generated/v2.0/petstore-simple.ts | 221 +- tests/generated/v2.0/petstore-swagger-io.ts | 397 +- .../v2.0/petstore-with-external-docs.ts | 221 +- tests/generated/v2.0/petstore.ts | 210 +- tests/generated/v2.0/query-path-param.ts | 195 +- tests/generated/v2.0/uber.ts | 243 +- tests/generated/v3.0/additional-properties.ts | 185 +- .../generated/v3.0/additional-properties2.ts | 187 +- tests/generated/v3.0/allof-example.ts | 195 +- tests/generated/v3.0/anyof-example.ts | 195 +- tests/generated/v3.0/api-with-examples.ts | 201 +- tests/generated/v3.0/callback-example.ts | 195 +- tests/generated/v3.0/components-responses.ts | 192 +- tests/generated/v3.0/explode-param-3.0.1.ts | 194 +- tests/generated/v3.0/link-example.ts | 243 +- tests/generated/v3.0/no-definitions-schema.ts | 185 +- tests/generated/v3.0/nullable-refs.ts | 185 +- tests/generated/v3.0/oneof-example.ts | 195 +- tests/generated/v3.0/personal-api-example.ts | 302 +- tests/generated/v3.0/petstore-expanded.ts | 221 +- tests/generated/v3.0/petstore.ts | 210 +- tests/generated/v3.0/responses.ts | 193 +- tests/generated/v3.0/swaggerhub-template.ts | 202 +- tests/generated/v3.0/tsoa-odd-types-3.0.2.ts | 336 +- tests/generated/v3.0/up-banking.ts | 1083 ++++++ tests/generated/v3.0/uspto.ts | 219 +- tests/generated/v3.0/wrong-enum-subtypes.ts | 185 +- tests/schemas/v2.0/authentiq.json | 32 + tests/schemas/v3.0/up-banking.json | 2764 +++++++++++++ tests/spec/defaultAsSuccess/schema.ts | 322 +- tests/spec/defaultResponse/schema.json | 57 + tests/spec/defaultResponse/schema.ts | 224 ++ tests/spec/defaultResponse/test.js | 25 + tests/spec/enumNamesAsValues/schema.ts | 302 +- tests/spec/extractRequestParams/schema.ts | 322 +- tests/spec/js/schema.d.ts | 579 +-- tests/spec/js/schema.js | 2255 +++++++++-- tests/spec/modular/Key.ts | 62 +- tests/spec/modular/Login.ts | 25 +- tests/spec/modular/Scope.ts | 60 +- tests/spec/modular/http-client.ts | 183 +- tests/spec/modular/schema.json | 35 + tests/spec/moduleNameIndex/schema.ts | 424 +- tests/spec/responses/schema.ts | 330 +- tests/spec/routeTypes/schema.json | 400 +- tests/spec/routeTypes/schema.ts | 3451 +++-------------- tests/spec/routeTypes/test.js | 29 +- tests/spec/specProperty/schema.ts | 235 +- tests/spec/unionEnums/schema.ts | 187 +- 82 files changed, 17479 insertions(+), 11132 deletions(-) create mode 100644 tests/generated/v3.0/up-banking.ts create mode 100644 tests/schemas/v3.0/up-banking.json create mode 100644 tests/spec/defaultResponse/schema.json create mode 100644 tests/spec/defaultResponse/schema.ts create mode 100644 tests/spec/defaultResponse/test.js diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml index 387638d1..1456f8c9 100644 --- a/.github/FUNDING.yml +++ b/.github/FUNDING.yml @@ -1,12 +1,2 @@ -# These are supported funding model platforms - -github: [js2me] -patreon: js2me -open_collective: # Replace with a single Open Collective username ko_fi: js2me -tidelift: # Replace with a single Tidelift platform-name/package-name e.g., npm/babel -community_bridge: # Replace with a single Community Bridge project-name e.g., cloud-foundry -liberapay: # Replace with a single Liberapay username -issuehunt: # Replace with a single IssueHunt username -otechie: # Replace with a single Otechie username -custom: ['https://paypal.me/acacode'] # Replace with up to 4 custom sponsorship URLs e.g., ['link1', 'link2'] +custom: ["https://paypal.me/acacode"] diff --git a/CHANGELOG.md b/CHANGELOG.md index 0894d7b5..c4f800e4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # next release +# 5.0.0 + +Fixes: +- Request content types auto substitution + i.e. if request body is form data, then request body content type will be `multipart/form-data` +- Strange method name (issue #152, thanks @RoXuS) +- Hardcoded Content-Type causes issues with some endpoints (issue #153, thanks @po5i) +- Critical bug with `:paramName` path params (issue #154) + +Features: +- Ability to provide custom formatting `fetch` response +- `"IMAGE"` content kind for response\request data objects +- `RequestParams` `RequestHeaders` types for `--route-types` (`routeTypes: true`) option (issue #150, thanks @Fabiencdp ) +- `--default-response` option. Allows to set default type for empty response schema (default: `void`) (based on issue #14) +- Request cancellation support (issue #96, thanks @ApacheEx) + `RequestParams` type now have the `cancelToken` field + `HttpClient` instance now have the `abortRequest(cancelToken)` method + +BREAKING_CHANGES: +- Fully refactored `http-client.eta` template, make it more flexible and simpler. + `HttpClient["request"]` takes one argument with type `FullRequestParams` + (previously it takes many count of arguments which was not flexible) +- Changed the default response body type from `any` to `void` (issue #14) + +Internal: +- Changed templates: + - `http-client.eta` + - `procedure-call.eta` + - `api.eta` + +This version works with previous templates. + # 4.4.0 Fixes: diff --git a/README.md b/README.md index 91815838..60bf6683 100644 --- a/README.md +++ b/README.md @@ -58,6 +58,7 @@ Options: --modular generate separated files for http client, data contracts, and routes (default: false) --disableStrictSSL disabled strict SSL (default: false) --clean-output clean output folder before generate api. WARNING: May cause data loss (default: false) + --default-response default type for empty response schema (default: "void") -h, --help display help for command ``` diff --git a/index.d.ts b/index.d.ts index 8aa837c5..cefcbada 100644 --- a/index.d.ts +++ b/index.d.ts @@ -77,6 +77,10 @@ interface GenerateApiParams { * prettier configuration */ prettier?: object; + /** + * default type for empty response schema (default: "void") + */ + defaultResponseType?: boolean; cleanOutput?: boolean; enumNamesAsValues?: boolean; @@ -215,7 +219,7 @@ export interface GenerateApiConfiguration { componentsMap: Record; convertedFromSwagger2: boolean; moduleNameIndex: number; - disableStrictSSSL: boolean; + disableStrictSSL: boolean; extractRequestParams: boolean; fileNames: { dataContracts: string; diff --git a/index.js b/index.js index a5a89bd6..33119352 100755 --- a/index.js +++ b/index.js @@ -10,6 +10,7 @@ const { Command } = require("commander"); const { resolve } = require("path"); const { generateApi } = require("./src"); const { version, name: packageName } = require("./package.json"); +const { TS_KEYWORDS } = require("./src/constants"); const program = new Command(packageName); @@ -61,6 +62,7 @@ program 0, ) .option("--disableStrictSSL", "disabled strict SSL", false) + .option("--default-response ", "default type for empty response schema", TS_KEYWORDS.VOID) .option( "--clean-output", "clean output folder before generate api. WARNING: May cause data loss", @@ -86,6 +88,7 @@ const { enumNamesAsValues, disableStrictSSL, cleanOutput, + defaultResponse, } = program; generateApi({ @@ -94,6 +97,7 @@ generateApi({ generateRouteTypes: routeTypes, generateClient: client, defaultResponseAsSuccess: defaultAsSuccess, + defaultResponseType: defaultResponse, generateUnionEnums: unionEnums, generateResponses: responses, extractRequestParams: extractRequestParams, diff --git a/package-lock.json b/package-lock.json index 08af59dc..89c36774 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,2360 +1,8 @@ { "name": "swagger-typescript-api", - "version": "4.4.0", - "lockfileVersion": 2, + "version": "5.0.0", + "lockfileVersion": 1, "requires": true, - "packages": { - "": { - "version": "4.4.0", - "license": "MIT", - "dependencies": { - "@types/swagger-schema-official": "2.0.21", - "axios": "^0.21.1", - "commander": "^6.2.1", - "eta": "^1.12.1", - "js-yaml": "^4.0.0", - "lodash": "^4.17.20", - "make-dir": "^3.1.0", - "nanoid": "^3.1.20", - "prettier": "^2.2.1", - "swagger-schema-official": "2.0.0-bab6bed", - "swagger2openapi": "^7.0.5", - "typescript": "^4.1.3" - }, - "bin": { - "sta": "index.js", - "swagger-typescript-api": "index.js" - }, - "devDependencies": { - "@types/lodash": "^4.14.166", - "@types/prettier": "^2.1.6", - "all-contributors-cli": "^6.19.0", - "husky": "^4.3.6", - "npm-run-all": "^4.1.5", - "pretty-quick": "^3.1.0" - } - }, - "node_modules/@babel/code-frame": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.12.11.tgz", - "integrity": "sha512-Zt1yodBx1UcyiePMSkWnU4hPqhwq7hGi2nFL1LeA3EUl+q2LQx16MISgJ0+z7dnmgvP9QtIleuETGOiOH1RcIw==", - "dev": true, - "dependencies": { - "@babel/highlight": "^7.10.4" - } - }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.12.11", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.12.11.tgz", - "integrity": "sha512-np/lG3uARFybkoHokJUmf1QfEvRVCPbmQeUQpKow5cQ3xWrV9i3rUHodKDJPQfTVX61qKi+UdYk8kik84n7XOw==", - "dev": true - }, - "node_modules/@babel/highlight": { - "version": "7.10.4", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.10.4.tgz", - "integrity": "sha512-i6rgnR/YgPEQzZZnbTHHuZdlE8qyoBNalD6F+q4vAFlcMEcqmkoG+mPqJYJCo63qPf74+Y1UZsl3l6f7/RIkmA==", - "dev": true, - "dependencies": { - "@babel/helper-validator-identifier": "^7.10.4", - "chalk": "^2.0.0", - "js-tokens": "^4.0.0" - } - }, - "node_modules/@babel/runtime": { - "version": "7.12.5", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.12.5.tgz", - "integrity": "sha512-plcc+hbExy3McchJCEQG3knOsuh3HH+Prx1P6cLIkET/0dLuQDEnrT+s27Axgc9bqfsmNUNHfscgMUdBpC9xfg==", - "dev": true, - "dependencies": { - "regenerator-runtime": "^0.13.4" - } - }, - "node_modules/@exodus/schemasafe": { - "version": "1.0.0-rc.3", - "resolved": "https://registry.npmjs.org/@exodus/schemasafe/-/schemasafe-1.0.0-rc.3.tgz", - "integrity": "sha512-GoXw0U2Qaa33m3eUcxuHnHpNvHjNlLo0gtV091XBpaRINaB4X6FGCG5XKxSFNFiPpugUDqNruHzaqpTdDm4AOg==" - }, - "node_modules/@types/lodash": { - "version": "4.14.166", - "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.14.166.tgz", - "integrity": "sha512-A3YT/c1oTlyvvW/GQqG86EyqWNrT/tisOIh2mW3YCgcx71TNjiTZA3zYZWA5BCmtsOTXjhliy4c4yEkErw6njA==", - "dev": true - }, - "node_modules/@types/minimatch": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.3.tgz", - "integrity": "sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==", - "dev": true - }, - "node_modules/@types/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/@types/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha512-//oorEZjL6sbPcKUaCdIGlIUeH26mgzimjBB77G6XRgnDl/L5wOnpyBGRe/Mmf5CVW3PwEBE1NjiMZ/ssFh4wA==", - "dev": true - }, - "node_modules/@types/prettier": { - "version": "2.1.6", - "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.1.6.tgz", - "integrity": "sha512-6gOkRe7OIioWAXfnO/2lFiv+SJichKVSys1mSsgyrYHSEjk8Ctv4tSR/Odvnu+HWlH2C8j53dahU03XmQdd5fA==", - "dev": true - }, - "node_modules/@types/swagger-schema-official": { - "version": "2.0.21", - "resolved": "https://registry.npmjs.org/@types/swagger-schema-official/-/swagger-schema-official-2.0.21.tgz", - "integrity": "sha512-n9BbLOjR4Hre7B4TSGGMPohOgOg8tcp00uxqsIE00uuWQC0QuX57G1bqC1csLsk2DpTGtHkd0dEb3ipsCZ9dAA==" - }, - "node_modules/all-contributors-cli": { - "version": "6.19.0", - "resolved": "https://registry.npmjs.org/all-contributors-cli/-/all-contributors-cli-6.19.0.tgz", - "integrity": "sha512-QJN4iLeTeYpTZJES8XFTzQ+itA1qSyBbxLapJLtwrnY+kipyRhCX49fS/s/qftQQym9XLATMZUpUeEeJSox1sw==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.7.6", - "async": "^3.0.1", - "chalk": "^4.0.0", - "didyoumean": "^1.2.1", - "inquirer": "^7.0.4", - "json-fixer": "^1.5.1", - "lodash": "^4.11.2", - "node-fetch": "^2.6.0", - "pify": "^5.0.0", - "yargs": "^15.0.1" - }, - "bin": { - "all-contributors": "dist/cli.js" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/all-contributors-cli/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/all-contributors-cli/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/all-contributors-cli/node_modules/cliui": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", - "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", - "dev": true, - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^6.2.0" - } - }, - "node_modules/all-contributors-cli/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/all-contributors-cli/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/all-contributors-cli/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/all-contributors-cli/node_modules/pify": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-5.0.0.tgz", - "integrity": "sha512-eW/gHNMlxdSP6dmG6uJip6FXN0EQBwm2clYYd8Wul42Cwu/DK8HEftzsapcNdYe2MfLiIwZqsDk2RDEsTE79hA==", - "dev": true, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/all-contributors-cli/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/all-contributors-cli/node_modules/wrap-ansi": { - "version": "6.2.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", - "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/all-contributors-cli/node_modules/y18n": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", - "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==", - "dev": true - }, - "node_modules/all-contributors-cli/node_modules/yargs": { - "version": "15.4.1", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", - "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", - "dev": true, - "dependencies": { - "cliui": "^6.0.0", - "decamelize": "^1.2.0", - "find-up": "^4.1.0", - "get-caller-file": "^2.0.1", - "require-directory": "^2.1.1", - "require-main-filename": "^2.0.0", - "set-blocking": "^2.0.0", - "string-width": "^4.2.0", - "which-module": "^2.0.0", - "y18n": "^4.0.0", - "yargs-parser": "^18.1.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/all-contributors-cli/node_modules/yargs-parser": { - "version": "18.1.3", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", - "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", - "dev": true, - "dependencies": { - "camelcase": "^5.0.0", - "decamelize": "^1.2.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/ansi-escapes": { - "version": "4.3.1", - "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.1.tgz", - "integrity": "sha512-JWF7ocqNrp8u9oqpgV+wH5ftbt+cfvv+PTjOvKLT3AdYly/LmORARfEVT1iyjwN+4MqE5UmVKoAdIBqeoCHgLA==", - "dev": true, - "dependencies": { - "type-fest": "^0.11.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/ansi-regex": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.0.tgz", - "integrity": "sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "dependencies": { - "color-convert": "^1.9.0" - } - }, - "node_modules/argparse": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", - "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" - }, - "node_modules/array-differ": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-3.0.0.tgz", - "integrity": "sha512-THtfYS6KtME/yIAhKjZ2ul7XI96lQGHRputJQHO80LAWQnuGP4iCIN8vdMRboGbIEYBwU33q8Tch1os2+X0kMg==", - "dev": true - }, - "node_modules/array-union": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", - "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", - "dev": true - }, - "node_modules/arrify": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz", - "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==", - "dev": true - }, - "node_modules/async": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/async/-/async-3.2.0.tgz", - "integrity": "sha512-TR2mEZFVOj2pLStYxLht7TyfuRzaydfpxr3k9RpHIzMgw7A64dzsdqCxH1WJyQdoe8T10nDXd9wnEigmiuHIZw==", - "dev": true - }, - "node_modules/axios": { - "version": "0.21.1", - "resolved": "https://registry.npmjs.org/axios/-/axios-0.21.1.tgz", - "integrity": "sha512-dKQiRHxGD9PPRIUNIWvZhPTPpl1rf/OxTYKsqKUDjBwYylTvV7SjSHJb9ratfyzM6wCdLCOYLzs73qpg5c4iGA==", - "dependencies": { - "follow-redirects": "^1.10.0" - } - }, - "node_modules/balanced-match": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", - "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", - "dev": true - }, - "node_modules/brace-expansion": { - "version": "1.1.11", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", - "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", - "dev": true, - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "node_modules/call-me-maybe": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/call-me-maybe/-/call-me-maybe-1.0.1.tgz", - "integrity": "sha1-JtII6onje1y95gJQoV8DHBak1ms=" - }, - "node_modules/callsites": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", - "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" - } - }, - "node_modules/chardet": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", - "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==", - "dev": true - }, - "node_modules/ci-info": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-2.0.0.tgz", - "integrity": "sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ==", - "dev": true - }, - "node_modules/cli-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", - "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", - "dev": true, - "dependencies": { - "restore-cursor": "^3.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/cli-width": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-3.0.0.tgz", - "integrity": "sha512-FxqpkPPwu1HjuN93Omfm4h8uIanXofW0RxVEW3k5RKx+mJJYSthzNhp32Kzxxy3YAEZ/Dc/EWN1vZRY0+kOhbw==", - "dev": true, - "engines": { - "node": ">= 10" - } - }, - "node_modules/cliui": { - "version": "7.0.4", - "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", - "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", - "dependencies": { - "string-width": "^4.2.0", - "strip-ansi": "^6.0.0", - "wrap-ansi": "^7.0.0" - } - }, - "node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", - "dev": true - }, - "node_modules/commander": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", - "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/compare-versions": { - "version": "3.6.0", - "resolved": "https://registry.npmjs.org/compare-versions/-/compare-versions-3.6.0.tgz", - "integrity": "sha512-W6Af2Iw1z4CB7q4uU4hv646dW9GQuBM+YpC0UvUCWSD8w90SJjp+ujJuXaEMtAXBtSqGfMPuFOVn4/+FlaqfBA==", - "dev": true - }, - "node_modules/concat-map": { - "version": "0.0.1", - "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", - "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", - "dev": true - }, - "node_modules/cosmiconfig": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.0.0.tgz", - "integrity": "sha512-pondGvTuVYDk++upghXJabWzL6Kxu6f26ljFw64Swq9v6sQPUL3EUlVDV56diOjpCayKihL6hVe8exIACU4XcA==", - "dev": true, - "dependencies": { - "@types/parse-json": "^4.0.0", - "import-fresh": "^3.2.1", - "parse-json": "^5.0.0", - "path-type": "^4.0.0", - "yaml": "^1.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/cosmiconfig/node_modules/parse-json": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.1.0.tgz", - "integrity": "sha512-+mi/lmVVNKFNVyLXV31ERiy2CY5E1/F6QtJFEzoChPRwwngMNXRDQ9GJ5WdE2Z2P4AujsOi0/+2qHID68KwfIQ==", - "dev": true, - "dependencies": { - "@babel/code-frame": "^7.0.0", - "error-ex": "^1.3.1", - "json-parse-even-better-errors": "^2.3.0", - "lines-and-columns": "^1.1.6" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/cosmiconfig/node_modules/path-type": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", - "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/cross-spawn": { - "version": "6.0.5", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-6.0.5.tgz", - "integrity": "sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ==", - "dev": true, - "dependencies": { - "nice-try": "^1.0.4", - "path-key": "^2.0.1", - "semver": "^5.5.0", - "shebang-command": "^1.2.0", - "which": "^1.2.9" - } - }, - "node_modules/decamelize": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", - "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/define-properties": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", - "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", - "dev": true, - "dependencies": { - "object-keys": "^1.0.12" - } - }, - "node_modules/didyoumean": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/didyoumean/-/didyoumean-1.2.1.tgz", - "integrity": "sha1-6S7f2tplN9SE1zwBcv0eugxJdv8=", - "dev": true - }, - "node_modules/emoji-regex": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", - "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" - }, - "node_modules/end-of-stream": { - "version": "1.4.4", - "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", - "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", - "dev": true, - "dependencies": { - "once": "^1.4.0" - } - }, - "node_modules/error-ex": { - "version": "1.3.2", - "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", - "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", - "dev": true, - "dependencies": { - "is-arrayish": "^0.2.1" - } - }, - "node_modules/es-abstract": { - "version": "1.17.4", - "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.17.4.tgz", - "integrity": "sha512-Ae3um/gb8F0mui/jPL+QiqmglkUsaQf7FwBEHYIFkztkneosu9imhqHpBzQ3h1vit8t5iQ74t6PEVvphBZiuiQ==", - "dev": true, - "dependencies": { - "es-to-primitive": "^1.2.1", - "function-bind": "^1.1.1", - "has": "^1.0.3", - "has-symbols": "^1.0.1", - "is-callable": "^1.1.5", - "is-regex": "^1.0.5", - "object-inspect": "^1.7.0", - "object-keys": "^1.1.1", - "object.assign": "^4.1.0", - "string.prototype.trimleft": "^2.1.1", - "string.prototype.trimright": "^2.1.1" - } - }, - "node_modules/es-to-primitive": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", - "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", - "dev": true, - "dependencies": { - "is-callable": "^1.1.4", - "is-date-object": "^1.0.1", - "is-symbol": "^1.0.2" - } - }, - "node_modules/es6-promise": { - "version": "3.3.1", - "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-3.3.1.tgz", - "integrity": "sha1-oIzd6EzNvzTQJ6FFG8kdS80ophM=" - }, - "node_modules/escalade": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", - "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", - "engines": { - "node": ">=6" - } - }, - "node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", - "dev": true - }, - "node_modules/eta": { - "version": "1.12.1", - "resolved": "https://registry.npmjs.org/eta/-/eta-1.12.1.tgz", - "integrity": "sha512-H8npoci2J/7XiPnVcCVulBSPsTNGvGaINyMjQDU8AFqp9LGsEYS88g2CiU+d01Sg44WtX7o4nb8wUJ9vnI+tiA==", - "license": "MIT", - "engines": { - "node": ">=6.0.0" - }, - "funding": { - "url": "https://github.com/eta-dev/eta?sponsor=1" - } - }, - "node_modules/execa": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", - "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", - "dev": true, - "dependencies": { - "cross-spawn": "^7.0.0", - "get-stream": "^5.0.0", - "human-signals": "^1.1.1", - "is-stream": "^2.0.0", - "merge-stream": "^2.0.0", - "npm-run-path": "^4.0.0", - "onetime": "^5.1.0", - "signal-exit": "^3.0.2", - "strip-final-newline": "^2.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/execa?sponsor=1" - } - }, - "node_modules/execa/node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, - "dependencies": { - "path-key": "^3.1.0", - "shebang-command": "^2.0.0", - "which": "^2.0.1" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/execa/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/execa/node_modules/shebang-command": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", - "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, - "dependencies": { - "shebang-regex": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/execa/node_modules/shebang-regex": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", - "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/execa/node_modules/which": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", - "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - }, - "bin": { - "node-which": "bin/node-which" - }, - "engines": { - "node": ">= 8" - } - }, - "node_modules/external-editor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", - "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", - "dev": true, - "dependencies": { - "chardet": "^0.7.0", - "iconv-lite": "^0.4.24", - "tmp": "^0.0.33" - }, - "engines": { - "node": ">=4" - } - }, - "node_modules/fast-safe-stringify": { - "version": "2.0.7", - "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", - "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" - }, - "node_modules/figures": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", - "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", - "dev": true, - "dependencies": { - "escape-string-regexp": "^1.0.5" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/find-versions": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/find-versions/-/find-versions-3.2.0.tgz", - "integrity": "sha512-P8WRou2S+oe222TOCHitLy8zj+SIsVJh52VP4lvXkaFVnOFFdoWv1H1Jjvel1aI6NCFOAaeAVm8qrI0odiLcww==", - "dev": true, - "dependencies": { - "semver-regex": "^2.0.0" - } - }, - "node_modules/follow-redirects": { - "version": "1.13.1", - "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.13.1.tgz", - "integrity": "sha512-SSG5xmZh1mkPGyKzjZP8zLjltIfpW32Y5QpdNJyjcfGxK3qo3NDDkZOZSFiGn1A6SclQxY9GzEwAHQ3dmYRWpg==", - "funding": [ - { - "type": "individual", - "url": "https://github.com/sponsors/RubenVerborgh" - } - ], - "engines": { - "node": ">=4.0" - }, - "peerDependenciesMeta": { - "debug": { - "optional": true - } - } - }, - "node_modules/function-bind": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", - "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", - "dev": true - }, - "node_modules/get-caller-file": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", - "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", - "engines": { - "node": "6.* || 8.* || >= 10.*" - } - }, - "node_modules/get-stream": { - "version": "5.2.0", - "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", - "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", - "dev": true, - "dependencies": { - "pump": "^3.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/graceful-fs": { - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.3.tgz", - "integrity": "sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==", - "dev": true - }, - "node_modules/has": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", - "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", - "dev": true, - "dependencies": { - "function-bind": "^1.1.1" - } - }, - "node_modules/has-flag": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", - "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", - "dev": true - }, - "node_modules/has-symbols": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.1.tgz", - "integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==", - "dev": true - }, - "node_modules/hosted-git-info": { - "version": "2.8.5", - "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.5.tgz", - "integrity": "sha512-kssjab8CvdXfcXMXVcvsXum4Hwdq9XGtRD3TteMEvEbq0LXyiNQr6AprqKqfeaDXze7SxWvRxdpwE6ku7ikLkg==", - "dev": true - }, - "node_modules/http2-client": { - "version": "1.3.3", - "resolved": "https://registry.npmjs.org/http2-client/-/http2-client-1.3.3.tgz", - "integrity": "sha512-nUxLymWQ9pzkzTmir24p2RtsgruLmhje7lH3hLX1IpwvyTg77fW+1brenPPP3USAR+rQ36p5sTA/x7sjCJVkAA==" - }, - "node_modules/human-signals": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", - "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", - "dev": true, - "engines": { - "node": ">=8.12.0" - } - }, - "node_modules/husky": { - "version": "4.3.6", - "resolved": "https://registry.npmjs.org/husky/-/husky-4.3.6.tgz", - "integrity": "sha512-o6UjVI8xtlWRL5395iWq9LKDyp/9TE7XMOTvIpEVzW638UcGxTmV5cfel6fsk/jbZSTlvfGVJf2svFtybcIZag==", - "dev": true, - "hasInstallScript": true, - "dependencies": { - "chalk": "^4.0.0", - "ci-info": "^2.0.0", - "compare-versions": "^3.6.0", - "cosmiconfig": "^7.0.0", - "find-versions": "^3.2.0", - "opencollective-postinstall": "^2.0.2", - "pkg-dir": "^4.2.0", - "please-upgrade-node": "^3.2.0", - "slash": "^3.0.0", - "which-pm-runs": "^1.0.0" - }, - "bin": { - "husky-run": "bin/run.js", - "husky-upgrade": "lib/upgrader/bin.js" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/husky" - } - }, - "node_modules/husky/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/husky/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/husky/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/husky/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/husky/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/husky/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/iconv-lite": { - "version": "0.4.24", - "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", - "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", - "dev": true, - "dependencies": { - "safer-buffer": ">= 2.1.2 < 3" - }, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/ignore": { - "version": "5.1.4", - "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.1.4.tgz", - "integrity": "sha512-MzbUSahkTW1u7JpKKjY7LCARd1fU5W2rLdxlM4kdkayuCwZImjkpluF9CM1aLewYJguPDqewLam18Y6AU69A8A==", - "dev": true - }, - "node_modules/import-fresh": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", - "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", - "dev": true, - "dependencies": { - "parent-module": "^1.0.0", - "resolve-from": "^4.0.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/inquirer": { - "version": "7.3.3", - "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-7.3.3.tgz", - "integrity": "sha512-JG3eIAj5V9CwcGvuOmoo6LB9kbAYT8HXffUl6memuszlwDC/qvFAJw49XJ5NROSFNPxp3iQg1GqkFhaY/CR0IA==", - "dev": true, - "dependencies": { - "ansi-escapes": "^4.2.1", - "chalk": "^4.1.0", - "cli-cursor": "^3.1.0", - "cli-width": "^3.0.0", - "external-editor": "^3.0.3", - "figures": "^3.0.0", - "lodash": "^4.17.19", - "mute-stream": "0.0.8", - "run-async": "^2.4.0", - "rxjs": "^6.6.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0", - "through": "^2.3.6" - }, - "engines": { - "node": ">=8.0.0" - } - }, - "node_modules/inquirer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/inquirer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/inquirer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/inquirer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/inquirer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-arrayish": { - "version": "0.2.1", - "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", - "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", - "dev": true - }, - "node_modules/is-callable": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.1.5.tgz", - "integrity": "sha512-ESKv5sMCJB2jnHTWZ3O5itG+O128Hsus4K4Qh1h2/cgn2vbgnLSVqfV46AeJA9D5EeeLa9w81KUXMtn34zhX+Q==", - "dev": true - }, - "node_modules/is-date-object": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.2.tgz", - "integrity": "sha512-USlDT524woQ08aoZFzh3/Z6ch9Y/EWXEHQ/AaRN0SkKq4t2Jw2R2339tSXmwuVoY7LLlBCbOIlx2myP/L5zk0g==", - "dev": true - }, - "node_modules/is-fullwidth-code-point": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", - "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", - "engines": { - "node": ">=8" - } - }, - "node_modules/is-regex": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.0.5.tgz", - "integrity": "sha512-vlKW17SNq44owv5AQR3Cq0bQPEb8+kF3UKZ2fiZNOWtztYE5i0CzCZxFDwO58qAOWtxdBRVO/V5Qin1wjCqFYQ==", - "dev": true, - "dependencies": { - "has": "^1.0.3" - } - }, - "node_modules/is-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.0.tgz", - "integrity": "sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/is-symbol": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", - "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", - "dev": true, - "dependencies": { - "has-symbols": "^1.0.1" - } - }, - "node_modules/isexe": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", - "dev": true - }, - "node_modules/js-tokens": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", - "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", - "dev": true - }, - "node_modules/js-yaml": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.0.0.tgz", - "integrity": "sha512-pqon0s+4ScYUvX30wxQi3PogGFAlUyH0awepWvwkj4jD4v+ova3RiYw8bmA6x2rDrEaj8i/oWKoRxpVNW+Re8Q==", - "dependencies": { - "argparse": "^2.0.1" - }, - "bin": { - "js-yaml": "bin/js-yaml.js" - } - }, - "node_modules/json-fixer": { - "version": "1.6.8", - "resolved": "https://registry.npmjs.org/json-fixer/-/json-fixer-1.6.8.tgz", - "integrity": "sha512-VUI3GPVLpM/nYmM1tSuvd3kh36eWvoNO1SFveVQf5k9QJI3kfaoOPVbN7WbpRfvZqa2BFySyVuqSs57laYfIDQ==", - "dev": true, - "dependencies": { - "@babel/runtime": "^7.12.5", - "chalk": "^4.1.0", - "pegjs": "^0.10.0" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/json-fixer/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/json-fixer/node_modules/chalk": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", - "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/chalk?sponsor=1" - } - }, - "node_modules/json-fixer/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/json-fixer/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/json-fixer/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/json-fixer/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/json-parse-better-errors": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", - "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", - "dev": true - }, - "node_modules/json-parse-even-better-errors": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", - "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", - "dev": true - }, - "node_modules/lines-and-columns": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.1.6.tgz", - "integrity": "sha1-HADHQ7QzzQpOgHWPe2SldEDZ/wA=", - "dev": true - }, - "node_modules/load-json-file": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-4.0.0.tgz", - "integrity": "sha1-L19Fq5HjMhYjT9U62rZo607AmTs=", - "dev": true, - "dependencies": { - "graceful-fs": "^4.1.2", - "parse-json": "^4.0.0", - "pify": "^3.0.0", - "strip-bom": "^3.0.0" - } - }, - "node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "dependencies": { - "p-locate": "^4.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/lodash": { - "version": "4.17.20", - "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.20.tgz", - "integrity": "sha512-PlhdFcillOINfeV7Ni6oF1TAEayyZBoZ8bcshTHqOYJYlrqzRK5hagpagky5o4HfCzzd1TRkXPMFq6cKk9rGmA==" - }, - "node_modules/make-dir": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", - "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", - "dependencies": { - "semver": "^6.0.0" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/make-dir/node_modules/semver": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz", - "integrity": "sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw==", - "bin": { - "semver": "bin/semver.js" - } - }, - "node_modules/memorystream": { - "version": "0.3.1", - "resolved": "https://registry.npmjs.org/memorystream/-/memorystream-0.3.1.tgz", - "integrity": "sha1-htcJCzDORV1j+64S3aUaR93K+bI=", - "dev": true - }, - "node_modules/merge-stream": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", - "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", - "dev": true - }, - "node_modules/mimic-fn": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", - "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/minimatch": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", - "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", - "dev": true, - "dependencies": { - "brace-expansion": "^1.1.7" - } - }, - "node_modules/mri": { - "version": "1.1.6", - "resolved": "https://registry.npmjs.org/mri/-/mri-1.1.6.tgz", - "integrity": "sha512-oi1b3MfbyGa7FJMP9GmLTttni5JoICpYBRlq+x5V16fZbLsnL9N3wFqqIm/nIG43FjUFkFh9Epzp/kzUGUnJxQ==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/multimatch": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/multimatch/-/multimatch-4.0.0.tgz", - "integrity": "sha512-lDmx79y1z6i7RNx0ZGCPq1bzJ6ZoDDKbvh7jxr9SJcWLkShMzXrHbYVpTdnhNM5MXpDUxCQ4DgqVttVXlBgiBQ==", - "dev": true, - "dependencies": { - "@types/minimatch": "^3.0.3", - "array-differ": "^3.0.0", - "array-union": "^2.1.0", - "arrify": "^2.0.1", - "minimatch": "^3.0.4" - } - }, - "node_modules/mute-stream": { - "version": "0.0.8", - "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-0.0.8.tgz", - "integrity": "sha512-nnbWWOkoWyUsTjKrhgD0dcz22mdkSnpYqbEjIm2nhwhuxlSkpywJmBo8h0ZqJdkp73mb90SssHkN4rsRaBAfAA==", - "dev": true - }, - "node_modules/nanoid": { - "version": "3.1.20", - "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.1.20.tgz", - "integrity": "sha512-a1cQNyczgKbLX9jwbS/+d7W8fX/RfgYR7lVWwWOGIPNgK2m0MWvrGF6/m4kk6U3QcFMnZf3RIhL0v2Jgh/0Uxw==", - "bin": { - "nanoid": "bin/nanoid.cjs" - }, - "engines": { - "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" - } - }, - "node_modules/nice-try": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/nice-try/-/nice-try-1.0.5.tgz", - "integrity": "sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ==", - "dev": true - }, - "node_modules/node-fetch": { - "version": "2.6.1", - "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz", - "integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw==", - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/node-fetch-h2": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/node-fetch-h2/-/node-fetch-h2-2.3.0.tgz", - "integrity": "sha512-ofRW94Ab0T4AOh5Fk8t0h8OBWrmjb0SSB20xh1H8YnPV9EJ+f5AMoYSUQ2zgJ4Iq2HAK0I2l5/Nequ8YzFS3Hg==", - "dependencies": { - "http2-client": "^1.2.5" - }, - "engines": { - "node": "4.x || >=6.0.0" - } - }, - "node_modules/node-readfiles": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/node-readfiles/-/node-readfiles-0.2.0.tgz", - "integrity": "sha1-271K8SE04uY1wkXvk//Pb2BnOl0=", - "dependencies": { - "es6-promise": "^3.2.1" - } - }, - "node_modules/normalize-package-data": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz", - "integrity": "sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==", - "dev": true, - "dependencies": { - "hosted-git-info": "^2.1.4", - "resolve": "^1.10.0", - "semver": "2 || 3 || 4 || 5", - "validate-npm-package-license": "^3.0.1" - } - }, - "node_modules/npm-run-all": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/npm-run-all/-/npm-run-all-4.1.5.tgz", - "integrity": "sha512-Oo82gJDAVcaMdi3nuoKFavkIHBRVqQ1qvMb+9LHk/cF4P6B2m8aP04hGf7oL6wZ9BuGwX1onlLhpuoofSyoQDQ==", - "dev": true, - "dependencies": { - "ansi-styles": "^3.2.1", - "chalk": "^2.4.1", - "cross-spawn": "^6.0.5", - "memorystream": "^0.3.1", - "minimatch": "^3.0.4", - "pidtree": "^0.3.0", - "read-pkg": "^3.0.0", - "shell-quote": "^1.6.1", - "string.prototype.padend": "^3.0.0" - } - }, - "node_modules/npm-run-path": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", - "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", - "dev": true, - "dependencies": { - "path-key": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/npm-run-path/node_modules/path-key": { - "version": "3.1.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", - "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/oas-kit-common": { - "version": "1.0.8", - "resolved": "https://registry.npmjs.org/oas-kit-common/-/oas-kit-common-1.0.8.tgz", - "integrity": "sha512-pJTS2+T0oGIwgjGpw7sIRU8RQMcUoKCDWFLdBqKB2BNmGpbBMH2sdqAaOXUg8OzonZHU0L7vfJu1mJFEiYDWOQ==", - "dependencies": { - "fast-safe-stringify": "^2.0.7" - } - }, - "node_modules/oas-linter": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/oas-linter/-/oas-linter-3.2.1.tgz", - "integrity": "sha512-e5G6bbq3Nrfxm+SDPR5AiZ6n2smVUmhLA1OgI2/Bl8e2ywfWsKw/yuqrwiXXiNHb1wdM/GyPMX6QjCGJODlaaA==", - "dependencies": { - "@exodus/schemasafe": "^1.0.0-rc.2", - "should": "^13.2.1", - "yaml": "^1.10.0" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-resolver": { - "version": "2.5.4", - "resolved": "https://registry.npmjs.org/oas-resolver/-/oas-resolver-2.5.4.tgz", - "integrity": "sha512-1vIj5Wkjmi+kZj5sFamt95LkuXoalmoKUohtaUQoCQZjLfPFaY8uZ7nw6IZaWuE6eLON2b6xrXhxD4hiTdYl0g==", - "dependencies": { - "node-fetch-h2": "^2.3.0", - "oas-kit-common": "^1.0.8", - "reftools": "^1.1.8", - "yaml": "^1.10.0", - "yargs": "^16.1.1" - }, - "bin": { - "resolve": "resolve.js" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-schema-walker": { - "version": "1.1.5", - "resolved": "https://registry.npmjs.org/oas-schema-walker/-/oas-schema-walker-1.1.5.tgz", - "integrity": "sha512-2yucenq1a9YPmeNExoUa9Qwrt9RFkjqaMAA1X+U7sbb0AqBeTIdMHky9SQQ6iN94bO5NW0W4TRYXerG+BdAvAQ==", - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/oas-validator": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/oas-validator/-/oas-validator-5.0.5.tgz", - "integrity": "sha512-d10yy6xlhRTh6np44k2U0gm5M66pioYTllH8J1ZTj+WSY3cpTvU+Dt51iWOT85HJqyGHo0RZKXF3u/NGQWDFgg==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "oas-kit-common": "^1.0.8", - "oas-linter": "^3.2.1", - "oas-resolver": "^2.5.4", - "oas-schema-walker": "^1.1.5", - "reftools": "^1.1.8", - "should": "^13.2.1", - "yaml": "^1.10.0" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/object-inspect": { - "version": "1.7.0", - "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.7.0.tgz", - "integrity": "sha512-a7pEHdh1xKIAgTySUGgLMx/xwDZskN1Ud6egYYN3EdRW4ZMPNEDUTF+hwy2LUC+Bl+SyLXANnwz/jyh/qutKUw==", - "dev": true - }, - "node_modules/object-keys": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", - "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", - "dev": true - }, - "node_modules/object.assign": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", - "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.2", - "function-bind": "^1.1.1", - "has-symbols": "^1.0.0", - "object-keys": "^1.0.11" - } - }, - "node_modules/once": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", - "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", - "dev": true, - "dependencies": { - "wrappy": "1" - } - }, - "node_modules/onetime": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", - "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", - "dev": true, - "dependencies": { - "mimic-fn": "^2.1.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/opencollective-postinstall": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/opencollective-postinstall/-/opencollective-postinstall-2.0.2.tgz", - "integrity": "sha512-pVOEP16TrAO2/fjej1IdOyupJY8KDUM1CvsaScRbw6oddvpQoOfGk4ywha0HKKVAD6RkW4x6Q+tNBwhf3Bgpuw==", - "dev": true - }, - "node_modules/os-tmpdir": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", - "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", - "dev": true, - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/p-limit": { - "version": "2.2.2", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.2.tgz", - "integrity": "sha512-WGR+xHecKTr7EbUEhyLSh5Dube9JtdiG78ufaeLxTgpudf/20KqyMioIUZJAezlTIi6evxuoUs9YXc11cU+yzQ==", - "dev": true, - "dependencies": { - "p-try": "^2.0.0" - } - }, - "node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "dependencies": { - "p-limit": "^2.2.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/p-try": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", - "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", - "dev": true - }, - "node_modules/parent-module": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", - "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", - "dev": true, - "dependencies": { - "callsites": "^3.0.0" - }, - "engines": { - "node": ">=6" - } - }, - "node_modules/parse-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-4.0.0.tgz", - "integrity": "sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA=", - "dev": true, - "dependencies": { - "error-ex": "^1.3.1", - "json-parse-better-errors": "^1.0.1" - } - }, - "node_modules/path-exists": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", - "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/path-key": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/path-key/-/path-key-2.0.1.tgz", - "integrity": "sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=", - "dev": true - }, - "node_modules/path-parse": { - "version": "1.0.6", - "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", - "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", - "dev": true - }, - "node_modules/path-type": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/path-type/-/path-type-3.0.0.tgz", - "integrity": "sha512-T2ZUsdZFHgA3u4e5PfPbjd7HDDpxPnQb5jN0SrDsjNSuVXHJqtwTnWqG0B1jZrgmJ/7lj1EmVIByWt1gxGkWvg==", - "dev": true, - "dependencies": { - "pify": "^3.0.0" - } - }, - "node_modules/pegjs": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/pegjs/-/pegjs-0.10.0.tgz", - "integrity": "sha1-z4uvrm7d/0tafvsYUmnqr0YQ3b0=", - "dev": true, - "bin": { - "pegjs": "bin/pegjs" - }, - "engines": { - "node": ">=0.10" - } - }, - "node_modules/pidtree": { - "version": "0.3.0", - "resolved": "https://registry.npmjs.org/pidtree/-/pidtree-0.3.0.tgz", - "integrity": "sha512-9CT4NFlDcosssyg8KVFltgokyKZIFjoBxw8CTGy+5F38Y1eQWrt8tRayiUOXE+zVKQnYu5BR8JjCtvK3BcnBhg==", - "dev": true - }, - "node_modules/pify": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pify/-/pify-3.0.0.tgz", - "integrity": "sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY=", - "dev": true - }, - "node_modules/pkg-dir": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", - "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", - "dev": true, - "dependencies": { - "find-up": "^4.0.0" - } - }, - "node_modules/please-upgrade-node": { - "version": "3.2.0", - "resolved": "https://registry.npmjs.org/please-upgrade-node/-/please-upgrade-node-3.2.0.tgz", - "integrity": "sha512-gQR3WpIgNIKwBMVLkpMUeR3e1/E1y42bqDQZfql+kDeXd8COYfM8PQA4X6y7a8u9Ua9FHmsrrmirW2vHs45hWg==", - "dev": true, - "dependencies": { - "semver-compare": "^1.0.0" - } - }, - "node_modules/prettier": { - "version": "2.2.1", - "resolved": "https://registry.npmjs.org/prettier/-/prettier-2.2.1.tgz", - "integrity": "sha512-PqyhM2yCjg/oKkFPtTGUojv7gnZAoG80ttl45O6x2Ug/rMJw4wcc9k6aaf2hibP7BGVCCM33gZoGjyvt9mm16Q==", - "license": "MIT", - "bin": { - "prettier": "bin-prettier.js" - }, - "engines": { - "node": ">=10.13.0" - } - }, - "node_modules/pretty-quick": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/pretty-quick/-/pretty-quick-3.1.0.tgz", - "integrity": "sha512-DtxIxksaUWCgPFN7E1ZZk4+Aav3CCuRdhrDSFZENb404sYMtuo9Zka823F+Mgeyt8Zt3bUiCjFzzWYE9LYqkmQ==", - "dev": true, - "dependencies": { - "chalk": "^3.0.0", - "execa": "^4.0.0", - "find-up": "^4.1.0", - "ignore": "^5.1.4", - "mri": "^1.1.5", - "multimatch": "^4.0.0" - }, - "bin": { - "pretty-quick": "bin/pretty-quick.js" - }, - "engines": { - "node": ">=10.13" - }, - "peerDependencies": { - "prettier": ">=2.0.0" - } - }, - "node_modules/pretty-quick/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dev": true, - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/pretty-quick/node_modules/chalk": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-3.0.0.tgz", - "integrity": "sha512-4D3B6Wf41KOYRFdszmDqMCGq5VV/uMAB273JILmO+3jAlh8X4qDtdtgCR3fxtbLEMzSx22QdhnDcJvu2u1fVwg==", - "dev": true, - "dependencies": { - "ansi-styles": "^4.1.0", - "supports-color": "^7.1.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-quick/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dev": true, - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/pretty-quick/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", - "dev": true - }, - "node_modules/pretty-quick/node_modules/has-flag": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", - "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", - "dev": true, - "engines": { - "node": ">=8" - } - }, - "node_modules/pretty-quick/node_modules/supports-color": { - "version": "7.2.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", - "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", - "dev": true, - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/pump": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", - "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", - "dev": true, - "dependencies": { - "end-of-stream": "^1.1.0", - "once": "^1.3.1" - } - }, - "node_modules/read-pkg": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-3.0.0.tgz", - "integrity": "sha1-nLxoaXj+5l0WwA4rGcI3/Pbjg4k=", - "dev": true, - "dependencies": { - "load-json-file": "^4.0.0", - "normalize-package-data": "^2.3.2", - "path-type": "^3.0.0" - } - }, - "node_modules/reftools": { - "version": "1.1.8", - "resolved": "https://registry.npmjs.org/reftools/-/reftools-1.1.8.tgz", - "integrity": "sha512-Yvz9NH8uFHzD/AXX82Li1GdAP6FzDBxEZw+njerNBBQv/XHihqsWAjNfXtaq4QD2l4TEZVnp4UbktdYSegAM3g==", - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/regenerator-runtime": { - "version": "0.13.7", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz", - "integrity": "sha512-a54FxoJDIr27pgf7IgeQGxmqUNYrcV338lf/6gH456HZ/PhX+5BcwHXG9ajESmwe6WRO0tAzRUrRmNONWgkrew==", - "dev": true - }, - "node_modules/require-directory": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", - "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", - "engines": { - "node": ">=0.10.0" - } - }, - "node_modules/require-main-filename": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", - "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==", - "dev": true - }, - "node_modules/resolve": { - "version": "1.15.1", - "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.15.1.tgz", - "integrity": "sha512-84oo6ZTtoTUpjgNEr5SJyzQhzL72gaRodsSfyxC/AXRvwu0Yse9H8eF9IpGo7b8YetZhlI6v7ZQ6bKBFV/6S7w==", - "dev": true, - "dependencies": { - "path-parse": "^1.0.6" - } - }, - "node_modules/resolve-from": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", - "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", - "dev": true, - "engines": { - "node": ">=4" - } - }, - "node_modules/restore-cursor": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", - "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", - "dev": true, - "dependencies": { - "onetime": "^5.1.0", - "signal-exit": "^3.0.2" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/run-async": { - "version": "2.4.1", - "resolved": "https://registry.npmjs.org/run-async/-/run-async-2.4.1.tgz", - "integrity": "sha512-tvVnVv01b8c1RrA6Ep7JkStj85Guv/YrMcwqYQnwjsAS2cTmmPGBBjAjpCW7RrSodNSoE2/qg9O4bceNvUuDgQ==", - "dev": true, - "engines": { - "node": ">=0.12.0" - } - }, - "node_modules/rxjs": { - "version": "6.6.3", - "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.3.tgz", - "integrity": "sha512-trsQc+xYYXZ3urjOiJOuCOa5N3jAZ3eiSpQB5hIT8zGlL2QfnHLJ2r7GMkBGuIausdJN1OneaI6gQlsqNHHmZQ==", - "dev": true, - "dependencies": { - "tslib": "^1.9.0" - }, - "engines": { - "npm": ">=2.0.0" - } - }, - "node_modules/safer-buffer": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", - "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", - "dev": true - }, - "node_modules/semver": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz", - "integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==", - "dev": true - }, - "node_modules/semver-compare": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/semver-compare/-/semver-compare-1.0.0.tgz", - "integrity": "sha1-De4hahyUGrN+nvsXiPavxf9VN/w=", - "dev": true - }, - "node_modules/semver-regex": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/semver-regex/-/semver-regex-2.0.0.tgz", - "integrity": "sha512-mUdIBBvdn0PLOeP3TEkMH7HHeUP3GjsXCwKarjv/kGmUFOYg1VqEemKhoQpWMu6X2I8kHeuVdGibLGkVK+/5Qw==", - "dev": true - }, - "node_modules/set-blocking": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", - "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", - "dev": true - }, - "node_modules/shebang-command": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-1.2.0.tgz", - "integrity": "sha1-RKrGW2lbAzmJaMOfNj/uXer98eo=", - "dev": true, - "dependencies": { - "shebang-regex": "^1.0.0" - } - }, - "node_modules/shebang-regex": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-1.0.0.tgz", - "integrity": "sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM=", - "dev": true - }, - "node_modules/shell-quote": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.7.2.tgz", - "integrity": "sha512-mRz/m/JVscCrkMyPqHc/bczi3OQHkLTqXHEFu0zDhK/qfv3UcOA4SVmRCLmos4bhjr9ekVQubj/R7waKapmiQg==", - "dev": true - }, - "node_modules/should": { - "version": "13.2.3", - "resolved": "https://registry.npmjs.org/should/-/should-13.2.3.tgz", - "integrity": "sha512-ggLesLtu2xp+ZxI+ysJTmNjh2U0TsC+rQ/pfED9bUZZ4DKefP27D+7YJVVTvKsmjLpIi9jAa7itwDGkDDmt1GQ==", - "dependencies": { - "should-equal": "^2.0.0", - "should-format": "^3.0.3", - "should-type": "^1.4.0", - "should-type-adaptors": "^1.0.1", - "should-util": "^1.0.0" - } - }, - "node_modules/should-equal": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/should-equal/-/should-equal-2.0.0.tgz", - "integrity": "sha512-ZP36TMrK9euEuWQYBig9W55WPC7uo37qzAEmbjHz4gfyuXrEUgF8cUvQVO+w+d3OMfPvSRQJ22lSm8MQJ43LTA==", - "dependencies": { - "should-type": "^1.4.0" - } - }, - "node_modules/should-format": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/should-format/-/should-format-3.0.3.tgz", - "integrity": "sha1-m/yPdPo5IFxT04w01xcwPidxJPE=", - "dependencies": { - "should-type": "^1.3.0", - "should-type-adaptors": "^1.0.1" - } - }, - "node_modules/should-type": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/should-type/-/should-type-1.4.0.tgz", - "integrity": "sha1-B1bYzoRt/QmEOmlHcZ36DUz/XPM=" - }, - "node_modules/should-type-adaptors": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/should-type-adaptors/-/should-type-adaptors-1.1.0.tgz", - "integrity": "sha512-JA4hdoLnN+kebEp2Vs8eBe9g7uy0zbRo+RMcU0EsNy+R+k049Ki+N5tT5Jagst2g7EAja+euFuoXFCa8vIklfA==", - "dependencies": { - "should-type": "^1.3.0", - "should-util": "^1.0.0" - } - }, - "node_modules/should-util": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/should-util/-/should-util-1.0.1.tgz", - "integrity": "sha512-oXF8tfxx5cDk8r2kYqlkUJzZpDBqVY/II2WhvU0n9Y3XYvAYRmeaf1PvvIvTgPnv4KJ+ES5M0PyDq5Jp+Ygy2g==" - }, - "node_modules/signal-exit": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz", - "integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA==", - "dev": true - }, - "node_modules/slash": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", - "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", - "dev": true - }, - "node_modules/spdx-correct": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", - "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", - "dev": true, - "dependencies": { - "spdx-expression-parse": "^3.0.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-exceptions": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", - "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", - "dev": true - }, - "node_modules/spdx-expression-parse": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", - "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", - "dev": true, - "dependencies": { - "spdx-exceptions": "^2.1.0", - "spdx-license-ids": "^3.0.0" - } - }, - "node_modules/spdx-license-ids": { - "version": "3.0.5", - "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.5.tgz", - "integrity": "sha512-J+FWzZoynJEXGphVIS+XEh3kFSjZX/1i9gFBaWQcB+/tmpe2qUsSBABpcxqxnAxFdiUFEgAX1bjYGQvIZmoz9Q==", - "dev": true - }, - "node_modules/string-width": { - "version": "4.2.0", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.0.tgz", - "integrity": "sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg==", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/string.prototype.padend": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/string.prototype.padend/-/string.prototype.padend-3.1.0.tgz", - "integrity": "sha512-3aIv8Ffdp8EZj8iLwREGpQaUZiPyrWrpzMBHvkiSW/bK/EGve9np07Vwy7IJ5waydpGXzQZu/F8Oze2/IWkBaA==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "es-abstract": "^1.17.0-next.1" - } - }, - "node_modules/string.prototype.trimleft": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimleft/-/string.prototype.trimleft-2.1.1.tgz", - "integrity": "sha512-iu2AGd3PuP5Rp7x2kEZCrB2Nf41ehzh+goo8TV7z8/XDBbsvc6HQIlUl9RjkZ4oyrW1XM5UwlGl1oVEaDjg6Ag==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "node_modules/string.prototype.trimright": { - "version": "2.1.1", - "resolved": "https://registry.npmjs.org/string.prototype.trimright/-/string.prototype.trimright-2.1.1.tgz", - "integrity": "sha512-qFvWL3/+QIgZXVmJBfpHmxLB7xsUXz6HsUmP8+5dRaC3Q7oKUv9Vo6aMCRZC1smrtyECFsIT30PqBJ1gTjAs+g==", - "dev": true, - "dependencies": { - "define-properties": "^1.1.3", - "function-bind": "^1.1.1" - } - }, - "node_modules/strip-ansi": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz", - "integrity": "sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w==", - "dependencies": { - "ansi-regex": "^5.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "node_modules/strip-bom": { - "version": "3.0.0", - "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz", - "integrity": "sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM=", - "dev": true - }, - "node_modules/strip-final-newline": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", - "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", - "dev": true, - "engines": { - "node": ">=6" - } - }, - "node_modules/supports-color": { - "version": "5.5.0", - "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", - "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", - "dev": true, - "dependencies": { - "has-flag": "^3.0.0" - } - }, - "node_modules/swagger-schema-official": { - "version": "2.0.0-bab6bed", - "resolved": "https://registry.npmjs.org/swagger-schema-official/-/swagger-schema-official-2.0.0-bab6bed.tgz", - "integrity": "sha1-cAcEaNbSl3ylI3suUZyn0Gouo/0=" - }, - "node_modules/swagger2openapi": { - "version": "7.0.5", - "resolved": "https://registry.npmjs.org/swagger2openapi/-/swagger2openapi-7.0.5.tgz", - "integrity": "sha512-Hzxse+VTX0u8xBgYJ665EjO6BfvW2PN9Yv+yIjBDm6ga9jl83+4CEdCCpznH+ILr5MS8bIIXB+XcQUM3u25w4g==", - "dependencies": { - "call-me-maybe": "^1.0.1", - "node-fetch": "^2.6.1", - "node-fetch-h2": "^2.3.0", - "node-readfiles": "^0.2.0", - "oas-kit-common": "^1.0.8", - "oas-resolver": "^2.5.4", - "oas-schema-walker": "^1.1.5", - "oas-validator": "^5.0.5", - "reftools": "^1.1.8", - "yaml": "^1.10.0", - "yargs": "^16.1.1" - }, - "bin": { - "boast": "boast.js", - "oas-validate": "oas-validate.js", - "swagger2openapi": "swagger2openapi.js" - }, - "funding": { - "url": "https://github.com/Mermade/oas-kit?sponsor=1" - } - }, - "node_modules/through": { - "version": "2.3.8", - "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", - "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", - "dev": true - }, - "node_modules/tmp": { - "version": "0.0.33", - "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", - "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", - "dev": true, - "dependencies": { - "os-tmpdir": "~1.0.2" - }, - "engines": { - "node": ">=0.6.0" - } - }, - "node_modules/tslib": { - "version": "1.14.1", - "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", - "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", - "dev": true - }, - "node_modules/type-fest": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.11.0.tgz", - "integrity": "sha512-OdjXJxnCN1AvyLSzeKIgXTXxV+99ZuXl3Hpo9XpJAv9MBcHrrJOQ5kV7ypXOuQie+AmWG25hLbiKdwYTifzcfQ==", - "dev": true, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/typescript": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.1.3.tgz", - "integrity": "sha512-B3ZIOf1IKeH2ixgHhj6la6xdwR9QrLC5d1VKeCSY4tvkqhF2eqd9O7txNlS0PO3GrBAFIdr3L1ndNwteUbZLYg==", - "bin": { - "tsc": "bin/tsc", - "tsserver": "bin/tsserver" - }, - "engines": { - "node": ">=4.2.0" - } - }, - "node_modules/validate-npm-package-license": { - "version": "3.0.4", - "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", - "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", - "dev": true, - "dependencies": { - "spdx-correct": "^3.0.0", - "spdx-expression-parse": "^3.0.0" - } - }, - "node_modules/which": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", - "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", - "dev": true, - "dependencies": { - "isexe": "^2.0.0" - } - }, - "node_modules/which-module": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", - "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=", - "dev": true - }, - "node_modules/which-pm-runs": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz", - "integrity": "sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs=", - "dev": true - }, - "node_modules/wrap-ansi": { - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/ansi-styles": { - "version": "4.3.0", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", - "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", - "dependencies": { - "color-convert": "^2.0.1" - }, - "engines": { - "node": ">=8" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/wrap-ansi/node_modules/color-convert": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", - "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", - "dependencies": { - "color-name": "~1.1.4" - }, - "engines": { - "node": ">=7.0.0" - } - }, - "node_modules/wrap-ansi/node_modules/color-name": { - "version": "1.1.4", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", - "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" - }, - "node_modules/wrappy": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", - "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", - "dev": true - }, - "node_modules/y18n": { - "version": "5.0.5", - "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.5.tgz", - "integrity": "sha512-hsRUr4FFrvhhRH12wOdfs38Gy7k2FFzB9qgN9v3aLykRq0dRcdcpz5C9FxdS2NuhOrI/628b/KSTJ3rwHysYSg==", - "engines": { - "node": ">=10" - } - }, - "node_modules/yaml": { - "version": "1.10.0", - "resolved": "https://registry.npmjs.org/yaml/-/yaml-1.10.0.tgz", - "integrity": "sha512-yr2icI4glYaNG+KWONODapy2/jDdMSDnrONSjblABjD9B4Z5LgiircSt8m8sRZFNi08kG9Sm0uSHtEmP3zaEGg==", - "engines": { - "node": ">= 6" - } - }, - "node_modules/yargs": { - "version": "16.2.0", - "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", - "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", - "dependencies": { - "cliui": "^7.0.2", - "escalade": "^3.1.1", - "get-caller-file": "^2.0.5", - "require-directory": "^2.1.1", - "string-width": "^4.2.0", - "y18n": "^5.0.5", - "yargs-parser": "^20.2.2" - }, - "engines": { - "node": ">=10" - } - }, - "node_modules/yargs-parser": { - "version": "20.2.4", - "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.4.tgz", - "integrity": "sha512-WOkpgNhPTlE73h4VFAFsOnomJVaovO8VqLDzy5saChRBFQFBoMYirowyW+Q9HB4HFF4Z7VZTiG3iSzJJA29yRA==", - "engines": { - "node": ">=10" - } - } - }, "dependencies": { "@babel/code-frame": { "version": "7.12.11", diff --git a/package.json b/package.json index ba743e6a..413deafa 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "swagger-typescript-api", - "version": "4.4.0", + "version": "5.0.0", "description": "Create typescript api module from swagger schema", "scripts": { "cli:json": "node index.js -r -d -p ./swagger-test-cli.json -n swagger-test-cli.ts --extract-request-params --enum-names-as-values", @@ -16,18 +16,19 @@ "generate:debug": "node --nolazy tests/generate.js", "validate": "node tests/validate.js", "validate:debug": "node --nolazy tests/validate.js", - "test:routeTypes": "node tests/spec/routeTypes/test.js", - "test:noClient": "node tests/spec/noClient/test.js", - "test:defaultAsSuccess": "node tests/spec/defaultAsSuccess/test.js", - "test:templates": "node tests/spec/templates/test.js", - "test:unionEnums": "node tests/spec/unionEnums/test.js", - "test:responses": "node tests/spec/responses/test.js", + "test:--route-types": "node tests/spec/routeTypes/test.js", + "test:--no-client": "node tests/spec/noClient/test.js", + "test:--default-as-success": "node tests/spec/defaultAsSuccess/test.js", + "test:--templates": "node tests/spec/templates/test.js", + "test:--union-enums": "node tests/spec/unionEnums/test.js", + "test:--responses": "node tests/spec/responses/test.js", "test:specProperty": "node tests/spec/specProperty/test.js", - "test:moduleNameIndex": "node tests/spec/moduleNameIndex/test.js", - "test:modular": "node tests/spec/modular/test.js", - "test:extractRequestParams": "node tests/spec/extractRequestParams/test.js", - "test:enumNamesAsValues": "node tests/spec/enumNamesAsValues/test.js", - "test:js": "node tests/spec/js/test.js" + "test:--module-name-index": "node tests/spec/moduleNameIndex/test.js", + "test:--modular": "node tests/spec/modular/test.js", + "test:--extract-request-params": "node tests/spec/extractRequestParams/test.js", + "test:--enum-names-as-values": "node tests/spec/enumNamesAsValues/test.js", + "test:--default-response": "node tests/spec/defaultResponse/test.js", + "test:--js": "node tests/spec/js/test.js" }, "author": "acacode", "license": "MIT", diff --git a/src/apiConfig.js b/src/apiConfig.js index a534d4a6..b91fdb6a 100644 --- a/src/apiConfig.js +++ b/src/apiConfig.js @@ -2,7 +2,8 @@ const _ = require("lodash"); const { formatDescription } = require("./common"); const { TS_KEYWORDS } = require("./constants"); -const createApiConfig = ({ info, servers }) => { +const createApiConfig = (swaggerSchema) => { + const { info, servers, host, basePath } = swaggerSchema; const server = (servers && servers[0]) || { url: "" }; const { title = "No title", version, description: schemaDescription = "" } = info || {}; const { url: serverUrl } = server; @@ -15,13 +16,18 @@ const createApiConfig = ({ info, servers }) => { ]); const description = _.compact([ - `@title ${title || "Api"}`, + `@title ${title || "No title"}`, version && `@version ${version}`, serverUrl && `@baseUrl ${serverUrl}`, _.replace(formatDescription(schemaDescription), /\n/g, "\n * "), ]); return { + info: info || {}, + servers: servers || [], + basePath, + host, + // TODO: unused, remove! props: _.compact([ { name: "baseUrl", @@ -39,6 +45,7 @@ const createApiConfig = ({ info, servers }) => { type: "(securityData: SecurityDataType) => RequestParams", }, ]), + // TODO: unused in fresh templates, remove in future generic, baseUrl: serverUrl, title, diff --git a/src/config.js b/src/config.js index 9fb3ae3b..1aa08d7d 100644 --- a/src/config.js +++ b/src/config.js @@ -45,6 +45,7 @@ const config = { onPrepareConfig: (apiConfig) => apiConfig, onCreateRequestParams: (rawType) => {}, }, + defaultResponseType: constants.TS_KEYWORDS.VOID, }; /** needs to use data everywhere in project */ diff --git a/src/constants.js b/src/constants.js index f68e0375..8931cd61 100644 --- a/src/constants.js +++ b/src/constants.js @@ -3,6 +3,7 @@ const TS_KEYWORDS = { STRING: "string", BOOLEAN: "boolean", ANY: "any", + VOID: "void", UNKNOWN: "unknown", NULL: "null", UNDEFINED: "undefined", diff --git a/src/index.js b/src/index.js index 89f62bc0..218812c4 100644 --- a/src/index.js +++ b/src/index.js @@ -36,6 +36,7 @@ module.exports = { generateUnionEnums = config.generateUnionEnums, moduleNameIndex = config.moduleNameIndex, extractRequestParams = config.extractRequestParams, + defaultResponseType = config.defaultResponseType, prettier: prettierOptions = constants.PRETTIER_OPTIONS, hooks: rawHooks, extraTemplates, @@ -59,6 +60,7 @@ module.exports = { enumNamesAsValues, disableStrictSSL, cleanOutput, + defaultResponseType, }); (spec ? convertSwaggerObject(spec) : getSwaggerObject(input, url, disableStrictSSL)) .then(({ usageSchema, originalSchema }) => { @@ -74,7 +76,7 @@ module.exports = { templatesToRender, }); - const { info, paths, servers, components } = usageSchema; + const { components } = usageSchema; addToConfig(config.hooks.onInit(config) || config); @@ -91,9 +93,9 @@ module.exports = { const hasSecurityRoutes = routes.some((route) => route.security); const hasQueryRoutes = routes.some((route) => route.hasQuery); const hasFormDataRoutes = routes.some((route) => route.hasFormDataParams); - const apiConfig = createApiConfig({ info, servers }, hasSecurityRoutes); + const rawConfiguration = { - apiConfig, + apiConfig: createApiConfig(usageSchema, hasSecurityRoutes), config, modelTypes: _.map(filterComponentsMap(componentsMap, "schemas"), prepareModelType), hasFormDataRoutes, diff --git a/src/routes.js b/src/routes.js index d52b510f..6f66a1bf 100644 --- a/src/routes.js +++ b/src/routes.js @@ -1,5 +1,4 @@ const _ = require("lodash"); -const { collect } = require("./utils"); const { types, parseSchema, getRefType, getInlineParseContent } = require("./schema"); const { checkAndRenameModelName } = require("./modelNames"); const { @@ -35,7 +34,7 @@ const getSchemaFromRequestType = (requestInfo) => { return null; }; -const getTypeFromRequestInfo = (requestInfo, parsedSchemas, operationId) => { +const getTypeFromRequestInfo = ({ requestInfo, parsedSchemas, operationId, defaultType }) => { // TODO: make more flexible pick schema without content type const schema = getSchemaFromRequestType(requestInfo); const refTypeInfo = getRefType(requestInfo); @@ -76,19 +75,27 @@ const getTypeFromRequestInfo = (requestInfo, parsedSchemas, operationId) => { } } - return TS_KEYWORDS.ANY; + return defaultType || TS_KEYWORDS.ANY; }; -const getRequestInfoTypes = (requestInfos, parsedSchemas, operationId) => +const getRequestInfoTypes = ({ requestInfos, parsedSchemas, operationId, defaultType }) => _.reduce( requestInfos, (acc, requestInfo, status) => { + const contentTypes = getContentTypes([requestInfo]); + return [ ...acc, { ...(requestInfo || {}), - contentTypes: getContentTypes([requestInfo]), - type: getTypeFromRequestInfo(requestInfo, parsedSchemas, operationId), + contentTypes: contentTypes, + contentKind: getContentKind(contentTypes), + type: getTypeFromRequestInfo({ + requestInfo, + parsedSchemas, + operationId, + defaultType, + }), description: formatDescription(requestInfo.description || "", true), status: _.isNaN(+status) ? status : +status, isSuccess: isSuccessStatus(status), @@ -102,9 +109,58 @@ const isSuccessStatus = (status) => (config.defaultResponseAsSuccess && status === "default") || (+status >= SUCCESS_RESPONSE_STATUS_RANGE[0] && +status < SUCCESS_RESPONSE_STATUS_RANGE[1]); -const getRouteParams = (routeInfo, route) => { +const parseRoute = (route) => { + const pathParamMatches = (route || "").match( + /({(([a-zA-Z]-?_?){1,})([0-9]{1,})?})|(:(([a-zA-Z]-?_?){1,})([0-9]{1,})?:?)/g, + ); + + // used in case when path parameters is not declared in requestInfo.parameters ("in": "path") + const pathParams = _.reduce( + pathParamMatches, + (pathParams, match) => { + const paramName = _.replace(match, /\{|\}|\:/g, ""); + + if (!paramName) return pathParams; + + if (_.includes(paramName, "-")) { + console.warn("🔨 wrong path param name", paramName); + } + + return [ + ...pathParams, + { + $match: match, + name: paramName, + required: true, + type: "string", + description: "", + schema: { + type: "string", + }, + in: "path", + }, + ]; + }, + [], + ); + + const fixedRoute = _.reduce( + pathParams, + (fixedRoute, pathParam) => { + return _.replace(fixedRoute, pathParam.$match, `\${${pathParam.name}}`); + }, + route || "", + ); + + return { + route: fixedRoute, + pathParams, + }; +}; + +const getRouteParams = (routeInfo, pathParams) => { const { parameters } = routeInfo; - const pathParamMatches = (route || "").match(/{(([a-zA-Z]-?_?){1,})([0-9]{1,})?}/g); + const routeParams = { path: [], header: [], @@ -117,16 +173,17 @@ const getRouteParams = (routeInfo, route) => { _.each(parameters, (parameter) => { const refTypeInfo = getRefType(parameter); + let routeParam = null; if (refTypeInfo && refTypeInfo.rawTypeData.in && refTypeInfo.rawTypeData) { if (!routeParams[refTypeInfo.rawTypeData.in]) { routeParams[refTypeInfo.rawTypeData.in] = []; } - routeParams[refTypeInfo.rawTypeData.in].push({ + routeParam = { ...refTypeInfo.rawTypeData, ...(refTypeInfo.rawTypeData.schema || {}), - }); + }; } else { if (!parameter.in) return; @@ -134,29 +191,23 @@ const getRouteParams = (routeInfo, route) => { routeParams[parameter.in] = []; } - routeParams[parameter.in].push({ + routeParam = { ...parameter, ...(parameter.schema || {}), - }); + }; + } + + if (routeParam) { + routeParams[routeParam.in].push(routeParam); } }); // used in case when path parameters is not declared in requestInfo.parameters ("in": "path") - _.each(pathParamMatches, (match) => { - const paramName = _.replace(match, /\{|\}/g, ""); - - if (!paramName) return; - - const alreadyExist = _.some(routeParams.path, (parameter) => parameter.name === paramName); + _.each(pathParams, (pathParam) => { + const alreadyExist = _.some(routeParams.path, (parameter) => parameter.name === pathParam.name); if (!alreadyExist) { - routeParams.path.push({ - name: paramName, - required: true, - type: "string", - description: "", - in: "path", - }); + routeParams.path.push(pathParam); } }); @@ -280,6 +331,7 @@ const CONTENT_KIND = { JSON: "JSON", URL_ENCODED: "URL_ENCODED", FORM_DATA: "FORM_DATA", + IMAGE: "IMAGE", OTHER: "OTHER", }; @@ -296,6 +348,10 @@ const getContentKind = (contentTypes) => { return CONTENT_KIND.FORM_DATA; } + if (_.some(contentTypes, (contentType) => _.includes(contentType, "image/"))) { + return CONTENT_KIND.IMAGE; + } + return CONTENT_KIND.OTHER; }; @@ -319,7 +375,11 @@ const getRequestBodyInfo = (routeInfo, routeParams, parsedSchemas) => { type = getInlineParseContent(schema); } else if (requestBody) { schema = requestBody; - type = getTypeFromRequestInfo(requestBody, parsedSchemas, operationId); + type = getTypeFromRequestInfo({ + requestInfo: requestBody, + parsedSchemas, + operationId, + }); // TODO: Refactor that. // It needed for cases when swagger schema is not declared request body type as form data @@ -345,7 +405,12 @@ const getResponseBodyInfo = (routeInfo, routeParams, parsedSchemas) => { const contentTypes = getContentTypes(responses, [...(produces || []), routeInfo["x-accepts"]]); - const responseInfos = getRequestInfoTypes(responses, parsedSchemas, operationId); + const responseInfos = getRequestInfoTypes({ + requestInfos: responses, + parsedSchemas, + operationId, + defaultType: config.defaultResponseType || TS_KEYWORDS.VOID, + }); const successResponse = responseInfos.find((response) => response.isSuccess); const errorResponses = responseInfos.filter( @@ -373,8 +438,8 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque routeNameDuplicatesMap: new Map(), }); - return pathsEntries.reduce((routes, [route, routeInfoByMethodsMap]) => { - if (route.startsWith("x-")) return routes; + return pathsEntries.reduce((routes, [rawRoute, routeInfoByMethodsMap]) => { + if (rawRoute.startsWith("x-")) return routes; const routeInfosMap = createRequestsMap(routeInfoByMethodsMap); @@ -395,6 +460,7 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque consumes, ...otherInfo } = routeInfo; + const { route, pathParams } = parseRoute(rawRoute); const routeId = nanoid(12); const moduleName = _.camelCase(_.compact(_.split(route, "/"))[moduleNameIndex]); @@ -403,7 +469,7 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque (security && security.length) ); - const routeParams = getRouteParams(routeInfo, route); + const routeParams = getRouteParams(routeInfo, pathParams); const pathArgs = routeParams.path.map((pathArgSchema) => ({ name: pathArgSchema.name, @@ -416,11 +482,13 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque const responseBodyInfo = getResponseBodyInfo(routeInfo, routeParams, parsedSchemas); const queryObjectSchema = convertRouteParamsIntoObject(routeParams.query); + const pathObjectSchema = convertRouteParamsIntoObject(routeParams.path); + const headersObjectSchema = convertRouteParamsIntoObject(routeParams.header); const routeName = getRouteName({ operationId, method, - route, + route: rawRoute, moduleName, responsesTypes: responseBodyInfo.responses, description, @@ -440,6 +508,10 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque const queryType = routeParams.query.length ? getInlineParseContent(queryObjectSchema) : null; + const pathType = routeParams.path.length ? getInlineParseContent(pathObjectSchema) : null; + const headersType = routeParams.header.length + ? getInlineParseContent(headersObjectSchema) + : null; const specificArgs = { query: queryType @@ -464,7 +536,24 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque : "params", optional: true, type: "RequestParams", + defaultValue: "{}", }, + pathParams: pathType + ? { + name: pathArgs.some((pathArg) => pathArg.name === "path") ? "pathParams" : "path", + optional: parseSchema(pathObjectSchema, null).allFieldsAreOptional, + type: pathType, + } + : void 0, + headers: headersType + ? { + name: pathArgs.some((pathArg) => pathArg.name === "headers") + ? "headersParams" + : "headers", + optional: parseSchema(headersObjectSchema, null).allFieldsAreOptional, + type: headersType, + } + : void 0, }; let routeArgs = _.compact([...pathArgs, specificArgs.query, specificArgs.body]); @@ -492,25 +581,6 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque routeArgs.push(specificArgs.requestParams); - // TODO: get args for formData - // "name": "file", - // "in": "formData", - - // const responsesInfos = _.reduce(responses, (acc, response, status) => { - - // const type = getTypeFromRequestInfo(response, parsedSchemas, 'application/json'); - - // if (type) { - // acc.push(`@response`) - // acc.push(` status: ${status === 'default' ? 200 : status}`) - // acc.push(` type: ${type}`) - // if (response.description) { - // acc.push(` description: ${response.description}`) - // } - // } - // return acc; - // }, [' ']) - const routeData = { id: routeId, namespace: _.replace(moduleName, /^(\d)/, "v$1"), @@ -518,18 +588,27 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque routeParams, requestBodyInfo, responseBodyInfo, + specificArgs, + queryObjectSchema, + pathObjectSchema, + headersObjectSchema, + responseBodySchema: responseBodyInfo.success.schema, + requestBodySchema: requestBodyInfo.schema, request: { contentTypes: requestBodyInfo.contentTypes, parameters: pathArgs, - query: specificArgs.query, - path: route.replace(/{/g, "${"), + path: route, formData: requestBodyInfo.contentKind === CONTENT_KIND.FORM_DATA, isQueryBody: requestBodyInfo.contentKind === CONTENT_KIND.URL_ENCODED, security: hasSecurity, method: method, + requestParams: requestParamsSchema, + payload: specificArgs.body, params: specificArgs.requestParams, - requestParams: requestParamsSchema, + query: specificArgs.query, + pathParams: specificArgs.pathParams, + headers: specificArgs.headers, }, response: { contentTypes: responseBodyInfo.contentTypes, @@ -539,7 +618,7 @@ const parseRoutes = ({ usageSchema, parsedSchemas, moduleNameIndex, extractReque raw: { operationId, method, - route, + route: rawRoute, moduleName, responsesTypes: responseBodyInfo.responses, description, @@ -587,7 +666,30 @@ const groupRoutes = (routes) => { acc.combined.push({ moduleName, - routes: packRoutes, + routes: _.map(packRoutes, (route) => { + const { original: originalName, usage: usageName } = route.routeName; + + // TODO: https://github.com/acacode/swagger-typescript-api/issues/152 + // TODO: refactor + if ( + packRoutes.length > 1 && + usageName !== originalName && + !_.some( + packRoutes, + ({ routeName, id }) => id !== route.id && originalName === routeName.original, + ) + ) { + return { + ...route, + routeName: { + ...route.routeName, + usage: originalName, + }, + }; + } + + return route; + }), }); } return acc; diff --git a/templates/default/api.eta b/templates/default/api.eta index b0f0f792..5dfdc3c0 100644 --- a/templates/default/api.eta +++ b/templates/default/api.eta @@ -1,23 +1,27 @@ <% const { apiConfig, routes, utils, config } = it; -const { _, require } = utils; -const genericValues = apiConfig.generic.map(g => ({ - withDefault: `${g.name} = ${g.defaultValue}`, - name: g.name, -})); +const { info, servers } = apiConfig; +const { _, require, formatDescription } = utils; + +const server = (servers && servers[0]) || { url: "" }; + +const descriptionLines = _.compact([ + `@title ${info.title || "No title"}`, + info.version && `@version ${info.version}`, + server.url && `@baseUrl ${server.url}`, + info.description && _.replace(formatDescription(info.description), /\n/g, "\n * "), +]); + %> -<% if (apiConfig.hasDescription) { %> +<% if (descriptionLines.length) { %> /** -<% apiConfig.description.forEach((jsDocLine) => { %> -* <%~ jsDocLine %> +<% descriptionLines.forEach((descriptionLine) => { %> +* <%~ descriptionLine %> <% }) %> */ <% } %> -export class Api<<%~ _.map(genericValues, "withDefault").join(', ') %>> extends HttpClient<<%~ _.map(genericValues, "name").join(', ') %>>{ -<% -/* TODO: outOfModule, combined should be attributes of route, which will allow to avoid duplication of code */ -%> +export class Api extends HttpClient{ <% routes.outOfModule && routes.outOfModule.forEach((route) => { %> diff --git a/templates/default/http-client.eta b/templates/default/http-client.eta index 39e2285c..2a941b03 100644 --- a/templates/default/http-client.eta +++ b/templates/default/http-client.eta @@ -2,17 +2,35 @@ const { apiConfig, generateResponses } = it; %> -export type RequestParams = Omit & { - secure?: boolean; +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ + secure?: boolean; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; } -export type RequestQueryParamsType = Record; +export type RequestParams = Omit -interface ApiConfig<<%~ apiConfig.generic.map(g => g.name).join(', ') %>> { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } <% if (generateResponses) {%> @@ -28,27 +46,28 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } -export class HttpClient<<%~ apiConfig.generic.map(g => `${g.name} = unknown`).join(', ') %>> { +export class HttpClient { public baseUrl: string = "<%~ apiConfig.baseUrl %>"; private securityData: SecurityDataType = (null as any); - private securityWorker: null | ApiConfig<<%~ apiConfig.generic.map(g => g.name).join(', ') %>>["securityWorker"] = null; + private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: 'same-origin', - headers: { - 'Content-Type': 'application/json' - }, + headers: {}, redirect: 'follow', referrerPolicy: 'no-referrer', } - constructor(apiConfig: ApiConfig<<%~ apiConfig.generic.map(g => g.name).join(', ') %>> = {}) { + constructor(apiConfig: ApiConfig = {}) { Object.assign(this, apiConfig); } @@ -56,91 +75,133 @@ export class HttpClient<<%~ apiConfig.generic.map(g => `${g.name} = unknown`).jo this.securityData = data } - private addQueryParam(query: RequestQueryParamsType, key: string) { - return encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + + return ( + encodeURIComponent(key) + "=" + encodeURIComponent( + Array.isArray(value) ? value.join(",") : + typeof value === "number" ? value : + `${value}` + ) + ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input:any) => input !== null && typeof input === "object" ? JSON.stringify(input) : input, + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), } - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}) + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), + }, + }; + } + + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; } + return void 0; } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = null as unknown as T; - r.error = null as unknown as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); - } + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken) - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): <% if (generateResponses) { %>TPromise><% } else { %>Promise><% } %> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); } - - return fetch(requestUrl, requestOptions).then(async response => { - const data = await this.safeParseResponse(response); - if (!response.ok) throw data - return data - }) } + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): <% if (generateResponses) { %>TPromise><% } else { %>Promise><% } %> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch( + `${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, + { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + } + ).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } + + if (!response.ok) throw data; + return data; + }); + }; } diff --git a/templates/default/procedure-call.eta b/templates/default/procedure-call.eta index 49758d1b..bacf84fe 100644 --- a/templates/default/procedure-call.eta +++ b/templates/default/procedure-call.eta @@ -1,6 +1,6 @@ <% const { utils, route, config } = it; -const { requestBodyInfo } = route; +const { requestBodyInfo, responseBodyInfo } = route; const { _, getInlineParseContent, getParseContent, parseSchema, getComponentByRef, require } = utils; const { parameters, path, method, payload, params, query, formData, security, requestParams } = route.request; const { type, errorType, contentTypes } = route.response; @@ -8,7 +8,7 @@ const routeDocs = includeFile("./route-docs", { config, route, utils }); const queryName = (query && query.name) || "query"; const pathParams = _.values(parameters); -const argToTmpl = ({ name, optional, type }) => `${name}${optional ? '?' : ''}: ${type}`; +const argToTmpl = ({ name, optional, type, defaultValue }) => `${name}${!defaultValue && optional ? '?' : ''}: ${type}${defaultValue ? ` = ${defaultValue}` : ''}`; const rawWrapperArgs = config.extractRequestParams ? _.compact([ @@ -34,26 +34,25 @@ const wrapperArgs = _ .map(argToTmpl) .join(', ') +// RequestParams["type"] const requestContentKind = { - "JSON": "BodyType.Json", - "URL_ENCODED": "BodyType.UrlEncoded", - "FORM_DATA": "BodyType.FormData" + "JSON": "ContentType.Json", + "URL_ENCODED": "ContentType.UrlEncoded", + "FORM_DATA": "ContentType.FormData", +} +// RequestParams["format"] +const responseContentKind = { + "JSON": '"json"', + "IMAGE": '"blob"', + "FORM_DATA": '"formData"' } -const bodyModeTmpl = requestContentKind[requestBodyInfo.contentKind] || (security && requestContentKind.JSON) || null -const securityTmpl = security ? 'true' : null -const pathTmpl = query != null - ? `\`${path}\${this.addQueryParams(${queryName})}\`` - : `\`${path}\`` -const requestArgs = [pathTmpl, `'${_.upperCase(method)}'`, _.get(params, "name"), _.get(payload, "name"), bodyModeTmpl, securityTmpl] - .reverse() - .reduce((args, arg) => { - if (args.length === 0 && !arg) return args - args.push(arg ? arg : 'null') - return args - }, []) - .reverse() - .join(', ') +const bodyTmpl = _.get(payload, "name") || null; +const queryTmpl = (query != null && queryName) || null; +const bodyContentKindTmpl = requestContentKind[requestBodyInfo.contentKind] || null; +const responseFormatTmpl = responseContentKind[responseBodyInfo.success && responseBodyInfo.success.schema && responseBodyInfo.success.schema.contentKind] || null; +const securityTmpl = security ? 'true' : null; + %> /** <%~ routeDocs.description %> @@ -64,4 +63,13 @@ const requestArgs = [pathTmpl, `'${_.upperCase(method)}'`, _.get(params, "name") */ <%~ route.routeName.usage %><%~ route.namespace ? ': ' : ' = ' %>(<%~ wrapperArgs %>) => - this.request<<%~ type %>, <%~ errorType %>>(<%~ requestArgs %>)<%~ route.namespace ? ',' : '' %> \ No newline at end of file + this.request<<%~ type %>, <%~ errorType %>>({ + path: `<%~ path %>`, + method: '<%~ _.upperCase(method) %>', + <%~ queryTmpl ? `query: ${queryTmpl},` : '' %> + <%~ bodyTmpl ? `body: ${bodyTmpl},` : '' %> + <%~ securityTmpl ? `secure: ${securityTmpl},` : '' %> + <%~ bodyContentKindTmpl ? `type: ${bodyContentKindTmpl},` : '' %> + <%~ responseFormatTmpl ? `format: ${responseFormatTmpl},` : '' %> + ...<%~ _.get(params, "name") %>, + })<%~ route.namespace ? ',' : '' %> \ No newline at end of file diff --git a/templates/default/route-type.eta b/templates/default/route-type.eta index 5e20109e..20f45428 100644 --- a/templates/default/route-type.eta +++ b/templates/default/route-type.eta @@ -1,24 +1,22 @@ <% const { route, utils, config } = it; -const { _, classNameCase, require } = utils -const { query, payload } = route.request -const { type: responseType } = route.response +const { _, classNameCase, require } = utils; +const { query, payload, pathParams, headers } = route.request; const routeDocs = includeFile("./route-docs", { config, route, utils }); const routeNamespace = classNameCase(route.routeName.usage); -const queryType = (query && query.type) || '{}'; -const bodyType = (payload && payload.type) || 'never'; + %> /** <%~ routeDocs.description %> -* <% /* Here you can add some other JSDoc tags */ %> - <%~ routeDocs.lines %> */ export namespace <%~ routeNamespace %> { -export type RequestQuery = <%~ queryType %>; -export type RequestBody = <%~ bodyType %>; -export type ResponseBody = <%~ responseType %>; + export type RequestParams = <%~ (pathParams && pathParams.type) || '{}' %>; + export type RequestQuery = <%~ (query && query.type) || '{}' %>; + export type RequestBody = <%~ (payload && payload.type) || 'never' %>; + export type RequestHeaders = <%~ (headers && headers.type) || '{}' %>; + export type ResponseBody = <%~ route.response.type %>; } \ No newline at end of file diff --git a/templates/modular/api.eta b/templates/modular/api.eta index 46d6ea4a..90fce3ee 100644 --- a/templates/modular/api.eta +++ b/templates/modular/api.eta @@ -5,12 +5,12 @@ const apiClassName = classNameCase(route.moduleName); const routes = route.routes; const dataContracts = _.map(modelTypes, "name"); %> -import { HttpClient, RequestParams, BodyType } from "./<%~ config.fileNames.httpClient %>"; +import { HttpClient, RequestParams, ContentType } from "./<%~ config.fileNames.httpClient %>"; <% if (dataContracts.length) { %> import { <%~ dataContracts.join(", ") %> } from "./<%~ config.fileNames.dataContracts %>" <% } %> -export class <%= apiClassName %> extends HttpClient { +export class <%= apiClassName %> extends HttpClient { <% routes.forEach((route) => { %> <%~ includeFile('./procedure-call.eta', { route, utils, config }) %> <% }) %> diff --git a/templates/modular/http-client.eta b/templates/modular/http-client.eta index e5156a60..2623f0bd 100644 --- a/templates/modular/http-client.eta +++ b/templates/modular/http-client.eta @@ -1,51 +1,73 @@ - -export type RequestParams = Omit & { - secure?: boolean; +<% +const { apiConfig, generateResponses } = it; +%> + +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ + secure?: boolean; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; } -export type RequestQueryParamsType = Record; +export type RequestParams = Omit -interface ApiConfig<<%~ it.apiConfig.generic.map(g => g.name).join(', ') %>> { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; + baseApiParams?: Omit; securityWorker?: (securityData: SecurityDataType) => RequestParams; } -<% if (it.generateResponses) {%> +<% if (generateResponses) {%> /** Overrided Promise type. Needs for additional typings of `.catch` callback */ -export type TPromise = Omit, "then" | "catch"> & { +type TPromise = Omit, "then" | "catch"> & { then(onfulfilled?: ((value: ResolveType) => TResult1 | PromiseLike) | undefined | null, onrejected?: ((reason: RejectType) => TResult2 | PromiseLike) | undefined | null): TPromise; catch(onrejected?: ((reason: RejectType) => TResult | PromiseLike) | undefined | null): TPromise; } <% } %> -export interface HttpResponse extends Response { +interface HttpResponse extends Response { data: D; error: E; } -export enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } -export class HttpClient<<%~ it.apiConfig.generic.map(g => `${g.name} = unknown`).join(', ') %>> { - public baseUrl: string = "<%~ it.apiConfig.baseUrl %>"; +export class HttpClient { + public baseUrl: string = "<%~ apiConfig.baseUrl %>"; private securityData: SecurityDataType = (null as any); - private securityWorker: null | ApiConfig<<%~ it.apiConfig.generic.map(g => g.name).join(', ') %>>["securityWorker"] = null; + private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: 'same-origin', - headers: { - 'Content-Type': 'application/json' - }, + headers: {}, redirect: 'follow', referrerPolicy: 'no-referrer', } - constructor(apiConfig: ApiConfig<<%~ it.apiConfig.generic.map(g => g.name).join(', ') %>> = {}) { + constructor(apiConfig: ApiConfig = {}) { Object.assign(this, apiConfig); } @@ -53,91 +75,133 @@ export class HttpClient<<%~ it.apiConfig.generic.map(g => `${g.name} = unknown`) this.securityData = data } - private addQueryParam(query: RequestQueryParamsType, key: string) { - return encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + + return ( + encodeURIComponent(key) + "=" + encodeURIComponent( + Array.isArray(value) ? value.join(",") : + typeof value === "number" ? value : + `${value}` + ) + ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input:any) => input !== null && typeof input === "object" ? JSON.stringify(input) : input, + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), } - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}) + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), + }, + }; + } + + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; } + return void 0; } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = null as unknown as T; - r.error = null as unknown as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); - } + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken) - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): <% if (it.generateResponses) { %>TPromise><% } else { %>Promise><% } %> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); } - - return fetch(requestUrl, requestOptions).then(async response => { - const data = await this.safeParseResponse(response); - if (!response.ok) throw data - return data - }) } + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): <% if (generateResponses) { %>TPromise><% } else { %>Promise><% } %> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch( + `${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, + { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + } + ).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } + + if (!response.ok) throw data; + return data; + }); + }; } diff --git a/templates/modular/procedure-call.eta b/templates/modular/procedure-call.eta index 4b3b0e58..e8354000 100644 --- a/templates/modular/procedure-call.eta +++ b/templates/modular/procedure-call.eta @@ -1,6 +1,6 @@ <% const { utils, route, config } = it; -const { requestBodyInfo } = route; +const { requestBodyInfo, responseBodyInfo } = route; const { _, getInlineParseContent, getParseContent, parseSchema, getComponentByRef, require } = utils; const { parameters, path, method, payload, params, query, formData, security, requestParams } = route.request; const { type, errorType, contentTypes } = route.response; @@ -8,7 +8,7 @@ const routeDocs = includeFile("./route-docs", { config, route, utils }); const queryName = (query && query.name) || "query"; const pathParams = _.values(parameters); -const argToTmpl = ({ name, optional, type }) => `${name}${optional ? '?' : ''}: ${type}`; +const argToTmpl = ({ name, optional, type, defaultValue }) => `${name}${!defaultValue && optional ? '?' : ''}: ${type}${defaultValue ? ` = ${defaultValue}` : ''}`; const rawWrapperArgs = config.extractRequestParams ? _.compact([ @@ -30,30 +30,28 @@ const rawWrapperArgs = config.extractRequestParams ? const wrapperArgs = _ // Sort by optionality - .sortBy(rawWrapperArgs, [function(o) { return o.optional }]) + .sortBy(rawWrapperArgs, [o => o.optional]) .map(argToTmpl) .join(', ') +// RequestParams["type"] const requestContentKind = { - "JSON": "BodyType.Json", - "URL_ENCODED": "BodyType.UrlEncoded", - "FORM_DATA": "BodyType.FormData" + "JSON": "ContentType.Json", + "URL_ENCODED": "ContentType.UrlEncoded", + "FORM_DATA": "ContentType.FormData", +} +// RequestParams["format"] +const responseContentKind = { + "JSON": '"json"', + "IMAGE": '"blob"', + "FORM_DATA": '"formData"' } -const bodyModeTmpl = requestContentKind[requestBodyInfo.contentKind] || (security && requestContentKind.JSON) || null -const securityTmpl = security ? 'true' : null -const pathTmpl = query != null - ? '`' + path + '${this.addQueryParams(' + query.name + ')}' + '`' - : '`' + path + '`' -const requestArgs = [pathTmpl, `'${_.upperCase(method)}'`, _.get(params, "name"), _.get(payload, "name"), bodyModeTmpl, securityTmpl] - .reverse() - .reduce((args, arg) => { - if (args.length === 0 && !arg) return args - args.push(arg ? arg : 'null') - return args - }, []) - .reverse() - .join(', ') +const bodyTmpl = _.get(payload, "name") || null; +const queryTmpl = (query != null && queryName) || null; +const bodyContentKindTmpl = requestContentKind[requestBodyInfo.contentKind] || null; +const responseFormatTmpl = responseContentKind[responseBodyInfo.success && responseBodyInfo.success.schema && responseBodyInfo.success.schema.contentKind] || null; +const securityTmpl = security ? 'true' : null; %> /** <%~ routeDocs.description %> @@ -64,4 +62,12 @@ const requestArgs = [pathTmpl, `'${_.upperCase(method)}'`, _.get(params, "name") */ <%~ route.routeName.usage %> = (<%~ wrapperArgs %>) => - this.request<<%~ type %>, <%~ errorType %>>(<%~ requestArgs %>) \ No newline at end of file + this.request<<%~ type %>, <%~ errorType %>>({ + path: `<%~ path %>`, + method: '<%~ _.upperCase(method) %>', + <%~ queryTmpl ? `query: ${queryTmpl},` : '' %> + <%~ bodyTmpl ? `body: ${bodyTmpl},` : '' %> + <%~ securityTmpl ? `secure: ${securityTmpl},` : '' %> + <%~ bodyContentKindTmpl ? `type: ${bodyContentKindTmpl},` : '' %> + ...<%~ _.get(params, "name") %>, + }) \ No newline at end of file diff --git a/templates/modular/route-type.eta b/templates/modular/route-type.eta index 2399fb47..20f45428 100644 --- a/templates/modular/route-type.eta +++ b/templates/modular/route-type.eta @@ -1,25 +1,22 @@ <% -const { utils, route, config } = it; -const { _, fmtToJSDocLine, classNameCase, require } = utils; -const { name, jsDocDescription, routeName } = route; -const { query, payload } = route.request; -const { type: responseType } = route.response; +const { route, utils, config } = it; +const { _, classNameCase, require } = utils; +const { query, payload, pathParams, headers } = route.request; const routeDocs = includeFile("./route-docs", { config, route, utils }); -const routeNamespace = classNameCase(routeName.usage); -const queryType = (query && query.type) || '{}'; -const bodyType = (payload && payload.type) || 'never'; +const routeNamespace = classNameCase(route.routeName.usage); + %> /** <%~ routeDocs.description %> -* <% /* Here you can add some other JSDoc tags */ %> - <%~ routeDocs.lines %> */ export namespace <%~ routeNamespace %> { -export type RequestQuery = <%~ queryType %>; -export type RequestBody = <%~ bodyType %>; -export type ResponseBody = <%~ responseType %>; + export type RequestParams = <%~ (pathParams && pathParams.type) || '{}' %>; + export type RequestQuery = <%~ (query && query.type) || '{}' %>; + export type RequestBody = <%~ (payload && payload.type) || 'never' %>; + export type RequestHeaders = <%~ (headers && headers.type) || '{}' %>; + export type ResponseBody = <%~ route.response.type %>; } \ No newline at end of file diff --git a/tests/README.md b/tests/README.md index 4b991ebb..908a67e0 100644 --- a/tests/README.md +++ b/tests/README.md @@ -11,4 +11,4 @@ As you see above here is two folders: - [**`v3.0`**](./generated/v3.0) - generated api modules for OA 3.0 schemas from above folder -Most schemas taken from [apis.guru](https://apis.guru/openapi-directory/) and [swagger.io github repo](https://swagger.io/) \ No newline at end of file +Most schemas taken from [apis.guru](https://apis.guru/openapi-directory/), [swagger.io github repo](https://swagger.io/) and [up-banking](https://github.com/up-banking/api) \ No newline at end of file diff --git a/tests/generated/v2.0/adafruit.ts b/tests/generated/v2.0/adafruit.ts index dd6e31dd..c45e28b7 100644 --- a/tests/generated/v2.0/adafruit.ts +++ b/tests/generated/v2.0/adafruit.ts @@ -164,16 +164,34 @@ export interface User { username?: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -181,22 +199,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://io.adafruit.com/api/v2"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -209,92 +228,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -427,7 +480,7 @@ export class HttpClient { * We have client libraries to help you get started with your project: [Python](https://github.com/adafruit/io-client-python), [Ruby](https://github.com/adafruit/io-client-ruby), [Arduino C++](https://github.com/adafruit/Adafruit_IO_Arduino), [Javascript](https://github.com/adafruit/adafruit-io-node), and [Go](https://github.com/adafruit/io-client-go) are available. They're all open source, so if they don't already do what you want, you can fork and add any feature you'd like. * */ -export class Api extends HttpClient { +export class Api extends HttpClient { user = { /** * No description @@ -438,7 +491,14 @@ export class Api extends HttpClient { * @request GET:/user * @secure */ - currentUser: (params?: RequestParams) => this.request(`/user`, "GET", params, null, BodyType.Json, true), + currentUser: (params: RequestParams = {}) => + this.request({ + path: `/user`, + method: "GET", + secure: true, + format: "json", + ...params, + }), }; webhooks = { /** @@ -450,8 +510,16 @@ export class Api extends HttpClient { * @request POST:/webhooks/feed/:token * @secure */ - createWebhookFeedData: (payload: { value?: string }, params?: RequestParams) => - this.request(`/webhooks/feed/:token`, "POST", params, payload, BodyType.Json, true), + createWebhookFeedData: (token: string, payload: { value?: string }, params: RequestParams = {}) => + this.request({ + path: `/webhooks/feed/${token}`, + method: "POST", + body: payload, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description The raw data webhook receiver accepts POST requests and stores the raw request body on your feed. This is useful when you don't have control of the webhook sender. If feed history is turned on, payloads will be truncated at 1024 bytes. If feed history is turned off, payloads will be truncated at 100KB. @@ -462,8 +530,15 @@ export class Api extends HttpClient { * @request POST:/webhooks/feed/:token/raw * @secure */ - createRawWebhookFeedData: (params?: RequestParams) => - this.request(`/webhooks/feed/:token/raw`, "POST", params, null, BodyType.Json, true), + createRawWebhookFeedData: (token: string, params: RequestParams = {}) => + this.request({ + path: `/webhooks/feed/${token}/raw`, + method: "POST", + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), }; username = { /** @@ -475,8 +550,13 @@ export class Api extends HttpClient { * @request DELETE:/{username}/activities * @secure */ - destroyActivities: (username: string, params?: RequestParams) => - this.request(`/${username}/activities`, "DELETE", params, null, BodyType.Json, true), + destroyActivities: (username: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/activities`, + method: "DELETE", + secure: true, + ...params, + }), /** * @description The Activities endpoint returns information about the user's activities. @@ -490,16 +570,16 @@ export class Api extends HttpClient { allActivities: ( username: string, query?: { start_time?: string; end_time?: string; limit?: number }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/activities${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/activities`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description The Activities endpoint returns information about the user's activities. @@ -514,16 +594,16 @@ export class Api extends HttpClient { username: string, type: string, query?: { start_time?: string; end_time?: string; limit?: number }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/activities/${type}${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/activities/${type}`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description The Dashboards endpoint returns information about the user's dashboards. @@ -534,8 +614,14 @@ export class Api extends HttpClient { * @request GET:/{username}/dashboards * @secure */ - allDashboards: (username: string, params?: RequestParams) => - this.request(`/${username}/dashboards`, "GET", params, null, BodyType.Json, true), + allDashboards: (username: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -546,8 +632,16 @@ export class Api extends HttpClient { * @request POST:/{username}/dashboards * @secure */ - createDashboard: (username: string, dashboard: Dashboard, params?: RequestParams) => - this.request(`/${username}/dashboards`, "POST", params, dashboard, BodyType.Json, true), + createDashboard: (username: string, dashboard: Dashboard, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards`, + method: "POST", + body: dashboard, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description The Blocks endpoint returns information about the user's blocks. @@ -558,15 +652,14 @@ export class Api extends HttpClient { * @request GET:/{username}/dashboards/{dashboard_id}/blocks * @secure */ - allBlocks: (username: string, dashboard_id: string, params?: RequestParams) => - this.request( - `/${username}/dashboards/${dashboard_id}/blocks`, - "GET", - params, - null, - BodyType.Json, - true, - ), + allBlocks: (username: string, dashboard_id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards/${dashboard_id}/blocks`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -577,15 +670,16 @@ export class Api extends HttpClient { * @request POST:/{username}/dashboards/{dashboard_id}/blocks * @secure */ - createBlock: (username: string, dashboard_id: string, block: Block, params?: RequestParams) => - this.request( - `/${username}/dashboards/${dashboard_id}/blocks`, - "POST", - params, - block, - BodyType.Json, - true, - ), + createBlock: (username: string, dashboard_id: string, block: Block, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards/${dashboard_id}/blocks`, + method: "POST", + body: block, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -596,15 +690,14 @@ export class Api extends HttpClient { * @request DELETE:/{username}/dashboards/{dashboard_id}/blocks/{id} * @secure */ - destroyBlock: (username: string, dashboard_id: string, id: string, params?: RequestParams) => - this.request( - `/${username}/dashboards/${dashboard_id}/blocks/${id}`, - "DELETE", - params, - null, - BodyType.Json, - true, - ), + destroyBlock: (username: string, dashboard_id: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards/${dashboard_id}/blocks/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -615,15 +708,14 @@ export class Api extends HttpClient { * @request GET:/{username}/dashboards/{dashboard_id}/blocks/{id} * @secure */ - getBlock: (username: string, dashboard_id: string, id: string, params?: RequestParams) => - this.request( - `/${username}/dashboards/${dashboard_id}/blocks/${id}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + getBlock: (username: string, dashboard_id: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards/${dashboard_id}/blocks/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -651,16 +743,17 @@ export class Api extends HttpClient { size_y?: number; visual_type?: string; }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/dashboards/${dashboard_id}/blocks/${id}`, - "PATCH", - params, - block, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/dashboards/${dashboard_id}/blocks/${id}`, + method: "PATCH", + body: block, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -688,16 +781,17 @@ export class Api extends HttpClient { size_y?: number; visual_type?: string; }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/dashboards/${dashboard_id}/blocks/${id}`, - "PUT", - params, - block, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/dashboards/${dashboard_id}/blocks/${id}`, + method: "PUT", + body: block, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -708,8 +802,14 @@ export class Api extends HttpClient { * @request DELETE:/{username}/dashboards/{id} * @secure */ - destroyDashboard: (username: string, id: string, params?: RequestParams) => - this.request(`/${username}/dashboards/${id}`, "DELETE", params, null, BodyType.Json, true), + destroyDashboard: (username: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -720,8 +820,14 @@ export class Api extends HttpClient { * @request GET:/{username}/dashboards/{id} * @secure */ - getDashboard: (username: string, id: string, params?: RequestParams) => - this.request(`/${username}/dashboards/${id}`, "GET", params, null, BodyType.Json, true), + getDashboard: (username: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/dashboards/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -736,8 +842,17 @@ export class Api extends HttpClient { username: string, id: string, dashboard: { description?: string; key?: string; name?: string }, - params?: RequestParams, - ) => this.request(`/${username}/dashboards/${id}`, "PATCH", params, dashboard, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/dashboards/${id}`, + method: "PATCH", + body: dashboard, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -752,8 +867,17 @@ export class Api extends HttpClient { username: string, id: string, dashboard: { description?: string; key?: string; name?: string }, - params?: RequestParams, - ) => this.request(`/${username}/dashboards/${id}`, "PUT", params, dashboard, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/dashboards/${id}`, + method: "PUT", + body: dashboard, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description The Feeds endpoint returns information about the user's feeds. The response includes the latest value of each feed, and other metadata about each feed. @@ -764,8 +888,14 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds * @secure */ - allFeeds: (username: string, params?: RequestParams) => - this.request(`/${username}/feeds`, "GET", params, null, BodyType.Json, true), + allFeeds: (username: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -776,15 +906,17 @@ export class Api extends HttpClient { * @request POST:/{username}/feeds * @secure */ - createFeed: (username: string, feed: Feed, query?: { group_key?: string }, params?: RequestParams) => - this.request( - `/${username}/feeds${this.addQueryParams(query)}`, - "POST", - params, - feed, - BodyType.Json, - true, - ), + createFeed: (username: string, feed: Feed, query?: { group_key?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds`, + method: "POST", + query: query, + body: feed, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -795,8 +927,13 @@ export class Api extends HttpClient { * @request DELETE:/{username}/feeds/{feed_key} * @secure */ - destroyFeed: (username: string, feed_key: string, params?: RequestParams) => - this.request(`/${username}/feeds/${feed_key}`, "DELETE", params, null, BodyType.Json, true), + destroyFeed: (username: string, feed_key: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}`, + method: "DELETE", + secure: true, + ...params, + }), /** * @description Returns feed based on the feed key @@ -807,8 +944,14 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key} * @secure */ - getFeed: (username: string, feed_key: string, params?: RequestParams) => - this.request(`/${username}/feeds/${feed_key}`, "GET", params, null, BodyType.Json, true), + getFeed: (username: string, feed_key: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -823,8 +966,17 @@ export class Api extends HttpClient { username: string, feed_key: string, feed: { description?: string; key?: string; license?: string; name?: string }, - params?: RequestParams, - ) => this.request(`/${username}/feeds/${feed_key}`, "PATCH", params, feed, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/feeds/${feed_key}`, + method: "PATCH", + body: feed, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -839,8 +991,17 @@ export class Api extends HttpClient { username: string, feed_key: string, feed: { description?: string; key?: string; license?: string; name?: string }, - params?: RequestParams, - ) => this.request(`/${username}/feeds/${feed_key}`, "PUT", params, feed, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/feeds/${feed_key}`, + method: "PUT", + body: feed, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -855,16 +1016,16 @@ export class Api extends HttpClient { username: string, feed_key: string, query?: { start_time?: string; end_time?: string; limit?: number; include?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/feeds/${feed_key}/data${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/feeds/${feed_key}/data`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Create new data records on the given feed. **NOTE:** when feed history is on, data `value` size is limited to 1KB, when feed history is turned off data value size is limited to 100KB. @@ -879,8 +1040,17 @@ export class Api extends HttpClient { username: string, feed_key: string, datum: { created_at?: string; ele?: string; epoch?: number; lat?: string; lon?: string; value?: string }, - params?: RequestParams, - ) => this.request(`/${username}/feeds/${feed_key}/data`, "POST", params, datum, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/feeds/${feed_key}/data`, + method: "POST", + body: datum, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -891,15 +1061,16 @@ export class Api extends HttpClient { * @request POST:/{username}/feeds/{feed_key}/data/batch * @secure */ - batchCreateData: (username: string, feed_key: string, data: Data, params?: RequestParams) => - this.request( - `/${username}/feeds/${feed_key}/data/batch`, - "POST", - params, - data, - BodyType.Json, - true, - ), + batchCreateData: (username: string, feed_key: string, data: Data, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/batch`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description The Chart API is what we use on io.adafruit.com to populate charts over varying timespans with a consistent number of data points. The maximum number of points returned is 480. This API works by aggregating slices of time into a single value by averaging. All time-based parameters are optional, if none are given it will default to 1 hour at the finest-grained resolution possible. @@ -914,7 +1085,7 @@ export class Api extends HttpClient { username: string, feed_key: string, query?: { start_time?: string; end_time?: string; resolution?: number; hours?: number }, - params?: RequestParams, + params: RequestParams = {}, ) => this.request< { @@ -923,15 +1094,15 @@ export class Api extends HttpClient { feed?: { id?: number; key?: string; name?: string }; parameters?: object; }, - any - >( - `/${username}/feeds/${feed_key}/data/chart${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + void + >({ + path: `/${username}/feeds/${feed_key}/data/chart`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Get the oldest data point in the feed. This request sets the queue pointer to the beginning of the feed. @@ -942,15 +1113,16 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key}/data/first * @secure */ - firstData: (username: string, feed_key: string, query?: { include?: string }, params?: RequestParams) => - this.request( - `/${username}/feeds/${feed_key}/data/first${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + firstData: (username: string, feed_key: string, query?: { include?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/first`, + method: "GET", + query: query, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get the most recent data point in the feed. This request sets the queue pointer to the end of the feed. @@ -961,15 +1133,16 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key}/data/last * @secure */ - lastData: (username: string, feed_key: string, query?: { include?: string }, params?: RequestParams) => - this.request( - `/${username}/feeds/${feed_key}/data/last${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + lastData: (username: string, feed_key: string, query?: { include?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/last`, + method: "GET", + query: query, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get the next newest data point in the feed. If queue processing hasn't been started, the first data point in the feed will be returned. @@ -980,15 +1153,16 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key}/data/next * @secure */ - nextData: (username: string, feed_key: string, query?: { include?: string }, params?: RequestParams) => - this.request( - `/${username}/feeds/${feed_key}/data/next${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + nextData: (username: string, feed_key: string, query?: { include?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/next`, + method: "GET", + query: query, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get the previously processed data point in the feed. NOTE: this method doesn't move the processing queue pointer. @@ -999,15 +1173,16 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key}/data/previous * @secure */ - previousData: (username: string, feed_key: string, query?: { include?: string }, params?: RequestParams) => - this.request( - `/${username}/feeds/${feed_key}/data/previous${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + previousData: (username: string, feed_key: string, query?: { include?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/previous`, + method: "GET", + query: query, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get the most recent data point in the feed in an MQTT compatible CSV format: `value,lat,lon,ele` @@ -1018,8 +1193,14 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key}/data/retain * @secure */ - retainData: (username: string, feed_key: string, params?: RequestParams) => - this.request(`/${username}/feeds/${feed_key}/data/retain`, "GET", params, null, BodyType.Json, true), + retainData: (username: string, feed_key: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/retain`, + method: "GET", + secure: true, + type: ContentType.Json, + ...params, + }), /** * No description @@ -1030,15 +1211,14 @@ export class Api extends HttpClient { * @request DELETE:/{username}/feeds/{feed_key}/data/{id} * @secure */ - destroyData: (username: string, feed_key: string, id: string, params?: RequestParams) => - this.request( - `/${username}/feeds/${feed_key}/data/${id}`, - "DELETE", - params, - null, - BodyType.Json, - true, - ), + destroyData: (username: string, feed_key: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1049,15 +1229,21 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key}/data/{id} * @secure */ - getData: (username: string, feed_key: string, id: string, query?: { include?: string }, params?: RequestParams) => - this.request( - `/${username}/feeds/${feed_key}/data/${id}${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + getData: ( + username: string, + feed_key: string, + id: string, + query?: { include?: string }, + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/feeds/${feed_key}/data/${id}`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1073,16 +1259,17 @@ export class Api extends HttpClient { feed_key: string, id: string, datum: { created_at?: string; ele?: string; epoch?: number; lat?: string; lon?: string; value?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/feeds/${feed_key}/data/${id}`, - "PATCH", - params, - datum, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/feeds/${feed_key}/data/${id}`, + method: "PATCH", + body: datum, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1098,16 +1285,17 @@ export class Api extends HttpClient { feed_key: string, id: string, datum: { created_at?: string; ele?: string; epoch?: number; lat?: string; lon?: string; value?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/feeds/${feed_key}/data/${id}`, - "PUT", - params, - datum, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/feeds/${feed_key}/data/${id}`, + method: "PUT", + body: datum, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Returns more detailed feed record based on the feed key @@ -1118,8 +1306,14 @@ export class Api extends HttpClient { * @request GET:/{username}/feeds/{feed_key}/details * @secure */ - getFeedDetails: (username: string, feed_key: string, params?: RequestParams) => - this.request(`/${username}/feeds/${feed_key}/details`, "GET", params, null, BodyType.Json, true), + getFeedDetails: (username: string, feed_key: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/feeds/${feed_key}/details`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * @description The Groups endpoint returns information about the user's groups. The response includes the latest value of each feed in the group, and other metadata about the group. @@ -1130,8 +1324,14 @@ export class Api extends HttpClient { * @request GET:/{username}/groups * @secure */ - allGroups: (username: string, params?: RequestParams) => - this.request(`/${username}/groups`, "GET", params, null, BodyType.Json, true), + allGroups: (username: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/groups`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1142,8 +1342,16 @@ export class Api extends HttpClient { * @request POST:/{username}/groups * @secure */ - createGroup: (username: string, group: Group, params?: RequestParams) => - this.request(`/${username}/groups`, "POST", params, group, BodyType.Json, true), + createGroup: (username: string, group: Group, params: RequestParams = {}) => + this.request({ + path: `/${username}/groups`, + method: "POST", + body: group, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1154,8 +1362,14 @@ export class Api extends HttpClient { * @request DELETE:/{username}/groups/{group_key} * @secure */ - destroyGroup: (username: string, group_key: string, params?: RequestParams) => - this.request(`/${username}/groups/${group_key}`, "DELETE", params, null, BodyType.Json, true), + destroyGroup: (username: string, group_key: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/groups/${group_key}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1166,8 +1380,14 @@ export class Api extends HttpClient { * @request GET:/{username}/groups/{group_key} * @secure */ - getGroup: (username: string, group_key: string, params?: RequestParams) => - this.request(`/${username}/groups/${group_key}`, "GET", params, null, BodyType.Json, true), + getGroup: (username: string, group_key: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/groups/${group_key}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1182,8 +1402,17 @@ export class Api extends HttpClient { username: string, group_key: string, group: { description?: string; key?: string; name?: string }, - params?: RequestParams, - ) => this.request(`/${username}/groups/${group_key}`, "PATCH", params, group, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/groups/${group_key}`, + method: "PATCH", + body: group, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1198,8 +1427,17 @@ export class Api extends HttpClient { username: string, group_key: string, group: { description?: string; key?: string; name?: string }, - params?: RequestParams, - ) => this.request(`/${username}/groups/${group_key}`, "PUT", params, group, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/groups/${group_key}`, + method: "PUT", + body: group, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1210,15 +1448,15 @@ export class Api extends HttpClient { * @request POST:/{username}/groups/{group_key}/add * @secure */ - addFeedToGroup: (group_key: string, username: string, query?: { feed_key?: string }, params?: RequestParams) => - this.request( - `/${username}/groups/${group_key}/add${this.addQueryParams(query)}`, - "POST", - params, - null, - BodyType.Json, - true, - ), + addFeedToGroup: (group_key: string, username: string, query?: { feed_key?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/groups/${group_key}/add`, + method: "POST", + query: query, + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1237,16 +1475,17 @@ export class Api extends HttpClient { feeds: { key: string; value: string }[]; location: { ele?: number; lat: number; lon: number }; }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/groups/${group_key}/data`, - "POST", - params, - group_feed_data, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/groups/${group_key}/data`, + method: "POST", + body: group_feed_data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description The Group Feeds endpoint returns information about the user's feeds. The response includes the latest value of each feed, and other metadata about each feed, but only for feeds within the given group. @@ -1257,8 +1496,14 @@ export class Api extends HttpClient { * @request GET:/{username}/groups/{group_key}/feeds * @secure */ - allGroupFeeds: (group_key: string, username: string, params?: RequestParams) => - this.request(`/${username}/groups/${group_key}/feeds`, "GET", params, null, BodyType.Json, true), + allGroupFeeds: (group_key: string, username: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/groups/${group_key}/feeds`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1273,8 +1518,17 @@ export class Api extends HttpClient { username: string, group_key: string, feed: { description?: string; key?: string; license?: string; name?: string }, - params?: RequestParams, - ) => this.request(`/${username}/groups/${group_key}/feeds`, "POST", params, feed, BodyType.Json, true), + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/groups/${group_key}/feeds`, + method: "POST", + body: feed, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1290,16 +1544,16 @@ export class Api extends HttpClient { group_key: string, feed_key: string, query?: { start_time?: string; end_time?: string; limit?: number }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/groups/${group_key}/feeds/${feed_key}/data${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/groups/${group_key}/feeds/${feed_key}/data`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1315,16 +1569,17 @@ export class Api extends HttpClient { group_key: string, feed_key: string, datum: { created_at?: string; ele?: string; epoch?: number; lat?: string; lon?: string; value?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/groups/${group_key}/feeds/${feed_key}/data`, - "POST", - params, - datum, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/groups/${group_key}/feeds/${feed_key}/data`, + method: "POST", + body: datum, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1340,16 +1595,17 @@ export class Api extends HttpClient { group_key: string, feed_key: string, data: { created_at?: string; ele?: string; epoch?: number; lat?: string; lon?: string; value?: string }[], - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/groups/${group_key}/feeds/${feed_key}/data/batch`, - "POST", - params, - data, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/groups/${group_key}/feeds/${feed_key}/data/batch`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1360,15 +1616,20 @@ export class Api extends HttpClient { * @request POST:/{username}/groups/{group_key}/remove * @secure */ - removeFeedFromGroup: (group_key: string, username: string, query?: { feed_key?: string }, params?: RequestParams) => - this.request( - `/${username}/groups/${group_key}/remove${this.addQueryParams(query)}`, - "POST", - params, - null, - BodyType.Json, - true, - ), + removeFeedFromGroup: ( + group_key: string, + username: string, + query?: { feed_key?: string }, + params: RequestParams = {}, + ) => + this.request({ + path: `/${username}/groups/${group_key}/remove`, + method: "POST", + query: query, + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1379,15 +1640,14 @@ export class Api extends HttpClient { * @request GET:/{username}/throttle * @secure */ - getCurrentUserThrottle: (username: string, params?: RequestParams) => - this.request<{ active_data_rate?: number; data_rate_limit?: number }, any>( - `/${username}/throttle`, - "GET", - params, - null, - BodyType.Json, - true, - ), + getCurrentUserThrottle: (username: string, params: RequestParams = {}) => + this.request<{ active_data_rate?: number; data_rate_limit?: number }, void>({ + path: `/${username}/throttle`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * @description The Tokens endpoint returns information about the user's tokens. @@ -1398,8 +1658,14 @@ export class Api extends HttpClient { * @request GET:/{username}/tokens * @secure */ - allTokens: (username: string, params?: RequestParams) => - this.request(`/${username}/tokens`, "GET", params, null, BodyType.Json, true), + allTokens: (username: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/tokens`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1410,8 +1676,16 @@ export class Api extends HttpClient { * @request POST:/{username}/tokens * @secure */ - createToken: (username: string, token: Token, params?: RequestParams) => - this.request(`/${username}/tokens`, "POST", params, token, BodyType.Json, true), + createToken: (username: string, token: Token, params: RequestParams = {}) => + this.request({ + path: `/${username}/tokens`, + method: "POST", + body: token, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1422,8 +1696,14 @@ export class Api extends HttpClient { * @request DELETE:/{username}/tokens/{id} * @secure */ - destroyToken: (username: string, id: string, params?: RequestParams) => - this.request(`/${username}/tokens/${id}`, "DELETE", params, null, BodyType.Json, true), + destroyToken: (username: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/tokens/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1434,8 +1714,14 @@ export class Api extends HttpClient { * @request GET:/{username}/tokens/{id} * @secure */ - getToken: (username: string, id: string, params?: RequestParams) => - this.request(`/${username}/tokens/${id}`, "GET", params, null, BodyType.Json, true), + getToken: (username: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/tokens/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1446,8 +1732,16 @@ export class Api extends HttpClient { * @request PATCH:/{username}/tokens/{id} * @secure */ - updateToken: (username: string, id: string, token: { token?: string }, params?: RequestParams) => - this.request(`/${username}/tokens/${id}`, "PATCH", params, token, BodyType.Json, true), + updateToken: (username: string, id: string, token: { token?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/tokens/${id}`, + method: "PATCH", + body: token, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1458,8 +1752,16 @@ export class Api extends HttpClient { * @request PUT:/{username}/tokens/{id} * @secure */ - replaceToken: (username: string, id: string, token: { token?: string }, params?: RequestParams) => - this.request(`/${username}/tokens/${id}`, "PUT", params, token, BodyType.Json, true), + replaceToken: (username: string, id: string, token: { token?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/tokens/${id}`, + method: "PUT", + body: token, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description The Triggers endpoint returns information about the user's triggers. @@ -1470,8 +1772,14 @@ export class Api extends HttpClient { * @request GET:/{username}/triggers * @secure */ - allTriggers: (username: string, params?: RequestParams) => - this.request(`/${username}/triggers`, "GET", params, null, BodyType.Json, true), + allTriggers: (username: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/triggers`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1482,8 +1790,16 @@ export class Api extends HttpClient { * @request POST:/{username}/triggers * @secure */ - createTrigger: (username: string, trigger: Trigger, params?: RequestParams) => - this.request(`/${username}/triggers`, "POST", params, trigger, BodyType.Json, true), + createTrigger: (username: string, trigger: Trigger, params: RequestParams = {}) => + this.request({ + path: `/${username}/triggers`, + method: "POST", + body: trigger, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1494,8 +1810,14 @@ export class Api extends HttpClient { * @request DELETE:/{username}/triggers/{id} * @secure */ - destroyTrigger: (username: string, id: string, params?: RequestParams) => - this.request(`/${username}/triggers/${id}`, "DELETE", params, null, BodyType.Json, true), + destroyTrigger: (username: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/triggers/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1506,8 +1828,14 @@ export class Api extends HttpClient { * @request GET:/{username}/triggers/{id} * @secure */ - getTrigger: (username: string, id: string, params?: RequestParams) => - this.request(`/${username}/triggers/${id}`, "GET", params, null, BodyType.Json, true), + getTrigger: (username: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/triggers/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1518,8 +1846,16 @@ export class Api extends HttpClient { * @request PATCH:/{username}/triggers/{id} * @secure */ - updateTrigger: (username: string, id: string, trigger: { name?: string }, params?: RequestParams) => - this.request(`/${username}/triggers/${id}`, "PATCH", params, trigger, BodyType.Json, true), + updateTrigger: (username: string, id: string, trigger: { name?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/triggers/${id}`, + method: "PATCH", + body: trigger, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1530,8 +1866,16 @@ export class Api extends HttpClient { * @request PUT:/{username}/triggers/{id} * @secure */ - replaceTrigger: (username: string, id: string, trigger: { name?: string }, params?: RequestParams) => - this.request(`/${username}/triggers/${id}`, "PUT", params, trigger, BodyType.Json, true), + replaceTrigger: (username: string, id: string, trigger: { name?: string }, params: RequestParams = {}) => + this.request({ + path: `/${username}/triggers/${id}`, + method: "PUT", + body: trigger, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description The Permissions endpoint returns information about the user's permissions. @@ -1542,8 +1886,14 @@ export class Api extends HttpClient { * @request GET:/{username}/{type}/{type_id}/acl * @secure */ - allPermissions: (username: string, type: string, type_id: string, params?: RequestParams) => - this.request(`/${username}/${type}/${type_id}/acl`, "GET", params, null, BodyType.Json, true), + allPermissions: (username: string, type: string, type_id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/${type}/${type_id}/acl`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1559,16 +1909,17 @@ export class Api extends HttpClient { type: string, type_id: string, permission: Permission, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/${type}/${type_id}/acl`, - "POST", - params, - permission, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/${type}/${type_id}/acl`, + method: "POST", + body: permission, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1579,15 +1930,14 @@ export class Api extends HttpClient { * @request DELETE:/{username}/{type}/{type_id}/acl/{id} * @secure */ - destroyPermission: (username: string, type: string, type_id: string, id: string, params?: RequestParams) => - this.request( - `/${username}/${type}/${type_id}/acl/${id}`, - "DELETE", - params, - null, - BodyType.Json, - true, - ), + destroyPermission: (username: string, type: string, type_id: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/${type}/${type_id}/acl/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1598,15 +1948,14 @@ export class Api extends HttpClient { * @request GET:/{username}/{type}/{type_id}/acl/{id} * @secure */ - getPermission: (username: string, type: string, type_id: string, id: string, params?: RequestParams) => - this.request( - `/${username}/${type}/${type_id}/acl/${id}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + getPermission: (username: string, type: string, type_id: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/${username}/${type}/${type_id}/acl/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -1627,16 +1976,17 @@ export class Api extends HttpClient { scope?: "secret" | "public" | "user" | "organization"; scope_value?: string; }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/${type}/${type_id}/acl/${id}`, - "PATCH", - params, - permission, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/${type}/${type_id}/acl/${id}`, + method: "PATCH", + body: permission, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -1657,15 +2007,16 @@ export class Api extends HttpClient { scope?: "secret" | "public" | "user" | "organization"; scope_value?: string; }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/${username}/${type}/${type_id}/acl/${id}`, - "PUT", - params, - permission, - BodyType.Json, - true, - ), + this.request({ + path: `/${username}/${type}/${type_id}/acl/${id}`, + method: "PUT", + body: permission, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/another-example.ts b/tests/generated/v2.0/another-example.ts index de30c953..22710e70 100644 --- a/tests/generated/v2.0/another-example.ts +++ b/tests/generated/v2.0/another-example.ts @@ -140,16 +140,34 @@ export interface Amount { */ export type Currency = string; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -157,22 +175,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/v2"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -185,92 +204,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -283,7 +336,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/v2 * This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters. */ -export class Api extends HttpClient { +export class Api extends HttpClient { pet = { /** * No description @@ -294,8 +347,15 @@ export class Api extends HttpClient { * @request POST:/pet * @secure */ - addPet: (body: Pet, params?: RequestParams) => - this.request(`/pet`, "POST", params, body, BodyType.Json, true), + addPet: (body: Pet, params: RequestParams = {}) => + this.request({ + path: `/pet`, + method: "POST", + body: body, + secure: true, + type: ContentType.Json, + ...params, + }), /** * No description @@ -306,8 +366,15 @@ export class Api extends HttpClient { * @request PUT:/pet * @secure */ - updatePet: (body: Pet, params?: RequestParams) => - this.request(`/pet`, "PUT", params, body, BodyType.Json, true), + updatePet: (body: Pet, params: RequestParams = {}) => + this.request({ + path: `/pet`, + method: "PUT", + body: body, + secure: true, + type: ContentType.Json, + ...params, + }), /** * @description Multiple status values can be provided with comma separated strings @@ -318,15 +385,15 @@ export class Api extends HttpClient { * @request GET:/pet/findByStatus * @secure */ - findPetsByStatus: (query: { status: ("available" | "pending" | "sold")[] }, params?: RequestParams) => - this.request( - `/pet/findByStatus${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + findPetsByStatus: (query: { status: ("available" | "pending" | "sold")[] }, params: RequestParams = {}) => + this.request({ + path: `/pet/findByStatus`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * No description @@ -336,8 +403,14 @@ export class Api extends HttpClient { * @summary summary * @request POST:/pet/single-form-url-encoded */ - singleFormUrlEncodedRequest: (data: { param1: string; param2: string }, params?: RequestParams) => - this.request(`/pet/single-form-url-encoded`, "POST", params, data, BodyType.UrlEncoded), + singleFormUrlEncodedRequest: (data: { param1: string; param2: string }, params: RequestParams = {}) => + this.request({ + path: `/pet/single-form-url-encoded`, + method: "POST", + body: data, + type: ContentType.UrlEncoded, + ...params, + }), /** * No description @@ -347,8 +420,14 @@ export class Api extends HttpClient { * @summary summary * @request POST:/pet/form-url-encoded */ - formUrlEncodedRequest: (data: { param1: string; param2: string }, params?: RequestParams) => - this.request(`/pet/form-url-encoded`, "POST", params, data, BodyType.UrlEncoded), + formUrlEncodedRequest: (data: { param1: string; param2: string }, params: RequestParams = {}) => + this.request({ + path: `/pet/form-url-encoded`, + method: "POST", + body: data, + type: ContentType.UrlEncoded, + ...params, + }), /** * No description @@ -360,8 +439,14 @@ export class Api extends HttpClient { * @originalName formUrlEncodedRequest * @duplicate */ - formUrlEncodedRequest2: (data: { param1: string; param2: string }, params?: RequestParams) => - this.request(`/pet/end-form-url-encoded`, "POST", params, data, BodyType.UrlEncoded), + formUrlEncodedRequest2: (data: { param1: string; param2: string }, params: RequestParams = {}) => + this.request({ + path: `/pet/end-form-url-encoded`, + method: "POST", + body: data, + type: ContentType.UrlEncoded, + ...params, + }), /** * @description Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. @@ -372,15 +457,15 @@ export class Api extends HttpClient { * @request GET:/pet/findByTags * @secure */ - findPetsByTags: (query: { tags: string[] }, params?: RequestParams) => - this.request( - `/pet/findByTags${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + findPetsByTags: (query: { tags: string[] }, params: RequestParams = {}) => + this.request({ + path: `/pet/findByTags`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Returns a single pet @@ -391,8 +476,14 @@ export class Api extends HttpClient { * @request GET:/pet/{petId} * @secure */ - getPetById: (petId: number, params?: RequestParams) => - this.request(`/pet/${petId}`, "GET", params, null, BodyType.Json, true), + getPetById: (petId: number, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -403,8 +494,15 @@ export class Api extends HttpClient { * @request POST:/pet/{petId} * @secure */ - updatePetWithForm: (petId: number, data: { name?: string; status?: string }, params?: RequestParams) => - this.request(`/pet/${petId}`, "POST", params, data, BodyType.FormData, true), + updatePetWithForm: (petId: number, data: { name?: string; status?: string }, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}`, + method: "POST", + body: data, + secure: true, + type: ContentType.FormData, + ...params, + }), /** * No description @@ -415,8 +513,13 @@ export class Api extends HttpClient { * @request DELETE:/pet/{petId} * @secure */ - deletePet: (petId: number, params?: RequestParams) => - this.request(`/pet/${petId}`, "DELETE", params, null, BodyType.Json, true), + deletePet: (petId: number, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}`, + method: "DELETE", + secure: true, + ...params, + }), /** * No description @@ -427,8 +530,16 @@ export class Api extends HttpClient { * @request POST:/pet/{petId}/uploadImage * @secure */ - uploadFile: (petId: number, data: { additionalMetadata?: string; file?: File }, params?: RequestParams) => - this.request(`/pet/${petId}/uploadImage`, "POST", params, data, BodyType.FormData, true), + uploadFile: (petId: number, data: { additionalMetadata?: string; file?: File }, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}/uploadImage`, + method: "POST", + body: data, + secure: true, + type: ContentType.FormData, + format: "json", + ...params, + }), }; store = { /** @@ -440,8 +551,14 @@ export class Api extends HttpClient { * @request GET:/store/inventory * @secure */ - getInventory: (params?: RequestParams) => - this.request, any>(`/store/inventory`, "GET", params, null, BodyType.Json, true), + getInventory: (params: RequestParams = {}) => + this.request, any>({ + path: `/store/inventory`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -451,8 +568,15 @@ export class Api extends HttpClient { * @summary Place an order for a pet * @request POST:/store/order */ - placeOrder: (body: Order, params?: RequestParams) => - this.request(`/store/order`, "POST", params, body, BodyType.Json), + placeOrder: (body: Order, params: RequestParams = {}) => + this.request({ + path: `/store/order`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions @@ -462,8 +586,13 @@ export class Api extends HttpClient { * @summary Find purchase order by ID * @request GET:/store/order/{orderId} */ - getOrderById: (orderId: number, params?: RequestParams) => - this.request(`/store/order/${orderId}`, "GET", params), + getOrderById: (orderId: number, params: RequestParams = {}) => + this.request({ + path: `/store/order/${orderId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors @@ -473,8 +602,12 @@ export class Api extends HttpClient { * @summary Delete purchase order by ID * @request DELETE:/store/order/{orderId} */ - deleteOrder: (orderId: string, params?: RequestParams) => - this.request(`/store/order/${orderId}`, "DELETE", params), + deleteOrder: (orderId: string, params: RequestParams = {}) => + this.request({ + path: `/store/order/${orderId}`, + method: "DELETE", + ...params, + }), }; user = { /** @@ -485,8 +618,14 @@ export class Api extends HttpClient { * @summary Create user * @request POST:/user */ - createUser: (body: User, params?: RequestParams) => - this.request(`/user`, "POST", params, body, BodyType.Json), + createUser: (body: User, params: RequestParams = {}) => + this.request({ + path: `/user`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -496,8 +635,14 @@ export class Api extends HttpClient { * @summary Creates list of users with given input array * @request POST:/user/createWithArray */ - createUsersWithArrayInput: (body: User[], params?: RequestParams) => - this.request(`/user/createWithArray`, "POST", params, body, BodyType.Json), + createUsersWithArrayInput: (body: User[], params: RequestParams = {}) => + this.request({ + path: `/user/createWithArray`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -507,8 +652,14 @@ export class Api extends HttpClient { * @summary Creates list of users with given input array * @request POST:/user/createWithList */ - createUsersWithListInput: (body: User[], params?: RequestParams) => - this.request(`/user/createWithList`, "POST", params, body, BodyType.Json), + createUsersWithListInput: (body: User[], params: RequestParams = {}) => + this.request({ + path: `/user/createWithList`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -518,8 +669,14 @@ export class Api extends HttpClient { * @summary Logs user into the system * @request GET:/user/login */ - loginUser: (query: { username: string; password: string }, params?: RequestParams) => - this.request(`/user/login${this.addQueryParams(query)}`, "GET", params), + loginUser: (query: { username: string; password: string }, params: RequestParams = {}) => + this.request({ + path: `/user/login`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * No description @@ -529,7 +686,12 @@ export class Api extends HttpClient { * @summary Logs out current logged in user session * @request GET:/user/logout */ - logoutUser: (params?: RequestParams) => this.request(`/user/logout`, "GET", params), + logoutUser: (params: RequestParams = {}) => + this.request({ + path: `/user/logout`, + method: "GET", + ...params, + }), /** * No description @@ -539,8 +701,13 @@ export class Api extends HttpClient { * @summary Get user by user name * @request GET:/user/{username} */ - getUserByName: (username: string, params?: RequestParams) => - this.request(`/user/${username}`, "GET", params), + getUserByName: (username: string, params: RequestParams = {}) => + this.request({ + path: `/user/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description This can only be done by the logged in user. @@ -550,8 +717,14 @@ export class Api extends HttpClient { * @summary Updated user * @request PUT:/user/{username} */ - updateUser: (username: string, body: User, params?: RequestParams) => - this.request(`/user/${username}`, "PUT", params, body, BodyType.Json), + updateUser: (username: string, body: User, params: RequestParams = {}) => + this.request({ + path: `/user/${username}`, + method: "PUT", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description This can only be done by the logged in user. @@ -561,7 +734,11 @@ export class Api extends HttpClient { * @summary Delete user * @request DELETE:/user/{username} */ - deleteUser: (username: string, params?: RequestParams) => - this.request(`/user/${username}`, "DELETE", params), + deleteUser: (username: string, params: RequestParams = {}) => + this.request({ + path: `/user/${username}`, + method: "DELETE", + ...params, + }), }; } diff --git a/tests/generated/v2.0/api-with-examples.ts b/tests/generated/v2.0/api-with-examples.ts index 6d2cf11b..93e3c381 100644 --- a/tests/generated/v2.0/api-with-examples.ts +++ b/tests/generated/v2.0/api-with-examples.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -150,7 +203,7 @@ export class HttpClient { * @title Simple API overview * @version v2 */ -export class Api extends HttpClient { +export class Api extends HttpClient { /** * @description multiple line 1 multiple line 2 multiple line 3 * @@ -158,7 +211,13 @@ export class Api extends HttpClient { * @summary List API versions * @request GET:/ */ - listVersionsv2 = (params?: RequestParams) => this.request(`/`, "GET", params); + listVersionsv2 = (params: RequestParams = {}) => + this.request({ + path: `/`, + method: "GET", + format: "json", + ...params, + }); v2 = { /** @@ -168,6 +227,12 @@ export class Api extends HttpClient { * @summary Show API version details * @request GET:/v2 */ - getVersionDetailsv2: (params?: RequestParams) => this.request(`/v2`, "GET", params), + getVersionDetailsv2: (params: RequestParams = {}) => + this.request({ + path: `/v2`, + method: "GET", + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/authentiq.ts b/tests/generated/v2.0/authentiq.ts index 37635c70..70bf54b3 100644 --- a/tests/generated/v2.0/authentiq.ts +++ b/tests/generated/v2.0/authentiq.ts @@ -61,16 +61,34 @@ export interface PushToken { sub: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -78,22 +96,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://6-dot-authentiqio.appspot.com"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -106,92 +125,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -204,7 +257,43 @@ export class HttpClient { * @baseUrl https://6-dot-authentiqio.appspot.com * Strong authentication, without the passwords. */ -export class Api extends HttpClient { +export class Api extends HttpClient { + wrongPathParams1 = { + /** + * @description DDD + * + * @tags key, delete + * @name WrongPathParams1 + * @request DELETE:/wrong-path-params1/{pathParam1}/{path_param2}/{path_param3}/:pathParam4 + */ + wrongPathParams1: ( + pathParam1: string, + path_param2: string, + path_param3: string, + pathParam4: string, + params: RequestParams = {}, + ) => + this.request({ + path: `/wrong-path-params1/${pathParam1}/${path_param2}/${path_param3}/${pathParam4}`, + method: "DELETE", + ...params, + }), + }; + wrongPathParams2 = { + /** + * @description DDD + * + * @tags key, delete + * @name WrongPathParams2 + * @request DELETE:/wrong-path-params2 + */ + wrongPathParams2: (path_param1: string, params: RequestParams = {}) => + this.request({ + path: `/wrong-path-params2`, + method: "DELETE", + ...params, + }), + }; key = { /** * @description Revoke an Authentiq ID using email & phone. If called with `email` and `phone` only, a verification code will be sent by email. Do a second call adding `code` to complete the revocation. @@ -213,8 +302,14 @@ export class Api extends HttpClient { * @name KeyRevokeNosecret * @request DELETE:/key */ - keyRevokeNosecret: (query: { email: string; phone: string; code?: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key${this.addQueryParams(query)}`, "DELETE", params), + keyRevokeNosecret: (query: { email: string; phone: string; code?: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Register a new ID `JWT(sub, devtoken)` v5: `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -223,8 +318,14 @@ export class Api extends HttpClient { * @name KeyRegister * @request POST:/key */ - keyRegister: (body: AuthentiqID, params?: RequestParams) => - this.request<{ secret?: string; status?: string }, Error>(`/key`, "POST", params, body), + keyRegister: (body: AuthentiqID, params: RequestParams = {}) => + this.request<{ secret?: string; status?: string }, Error>({ + path: `/key`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Revoke an Identity (Key) with a revocation secret @@ -233,8 +334,14 @@ export class Api extends HttpClient { * @name KeyRevoke * @request DELETE:/key/{PK} */ - keyRevoke: (PK: string, query: { secret: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}${this.addQueryParams(query)}`, "DELETE", params), + keyRevoke: (PK: string, query: { secret: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Get public details of an Authentiq ID. @@ -243,8 +350,13 @@ export class Api extends HttpClient { * @name GetKey * @request GET:/key/{PK} */ - getKey: (PK: string, params?: RequestParams) => - this.request<{ since?: string; status?: string; sub?: string }, Error>(`/key/${PK}`, "GET", params), + getKey: (PK: string, params: RequestParams = {}) => + this.request<{ since?: string; status?: string; sub?: string }, Error>({ + path: `/key/${PK}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD info on Authentiq ID @@ -253,7 +365,12 @@ export class Api extends HttpClient { * @name HeadKey * @request HEAD:/key/{PK} */ - headKey: (PK: string, params?: RequestParams) => this.request(`/key/${PK}`, "HEAD", params), + headKey: (PK: string, params: RequestParams = {}) => + this.request({ + path: `/key/${PK}`, + method: "HEAD", + ...params, + }), /** * @description update properties of an Authentiq ID. (not operational in v4; use PUT for now) v5: POST issuer-signed email & phone scopes in a self-signed JWT See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -262,8 +379,14 @@ export class Api extends HttpClient { * @name KeyUpdate * @request POST:/key/{PK} */ - keyUpdate: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "POST", params, body), + keyUpdate: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Update Authentiq ID by replacing the object. v4: `JWT(sub,email,phone)` to bind email/phone hash; v5: POST issuer-signed email & phone scopes and PUT to update registration `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -272,8 +395,14 @@ export class Api extends HttpClient { * @name KeyBind * @request PUT:/key/{PK} */ - keyBind: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "PUT", params, body), + keyBind: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "PUT", + body: body, + format: "json", + ...params, + }), }; login = { /** @@ -283,8 +412,15 @@ export class Api extends HttpClient { * @name PushLoginRequest * @request POST:/login */ - pushLoginRequest: (query: { callback: string }, body: PushToken, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/login${this.addQueryParams(query)}`, "POST", params, body), + pushLoginRequest: (query: { callback: string }, body: PushToken, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/login`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), }; scope = { /** @@ -294,13 +430,15 @@ export class Api extends HttpClient { * @name SignRequest * @request POST:/scope */ - signRequest: (body: Claims, query?: { test?: number }, params?: RequestParams) => - this.request<{ job?: string; status?: string }, Error>( - `/scope${this.addQueryParams(query)}`, - "POST", - params, - body, - ), + signRequest: (body: Claims, query?: { test?: number }, params: RequestParams = {}) => + this.request<{ job?: string; status?: string }, Error>({ + path: `/scope`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), /** * @description delete a verification job @@ -309,8 +447,13 @@ export class Api extends HttpClient { * @name SignDelete * @request DELETE:/scope/{job} */ - signDelete: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "DELETE", params), + signDelete: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "DELETE", + format: "json", + ...params, + }), /** * @description get the status / current content of a verification job @@ -319,8 +462,13 @@ export class Api extends HttpClient { * @name SignRetrieve * @request GET:/scope/{job} */ - signRetrieve: (job: string, params?: RequestParams) => - this.request<{ exp?: number; field?: string; sub?: string }, Error>(`/scope/${job}`, "GET", params), + signRetrieve: (job: string, params: RequestParams = {}) => + this.request<{ exp?: number; field?: string; sub?: string }, Error>({ + path: `/scope/${job}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD to get the status of a verification job @@ -329,8 +477,12 @@ export class Api extends HttpClient { * @name SignRetrieveHead * @request HEAD:/scope/{job} */ - signRetrieveHead: (job: string, params?: RequestParams) => - this.request(`/scope/${job}`, "HEAD", params), + signRetrieveHead: (job: string, params: RequestParams = {}) => + this.request({ + path: `/scope/${job}`, + method: "HEAD", + ...params, + }), /** * @description this is a scope confirmation @@ -339,8 +491,14 @@ export class Api extends HttpClient { * @name SignConfirm * @request POST:/scope/{job} */ - signConfirm: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "POST", params, null, BodyType.Json), + signConfirm: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "POST", + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description authority updates a JWT with its signature See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -349,7 +507,11 @@ export class Api extends HttpClient { * @name SignUpdate * @request PUT:/scope/{job} */ - signUpdate: (job: string, params?: RequestParams) => - this.request<{ jwt?: string; status?: string }, Error>(`/scope/${job}`, "PUT", params), + signUpdate: (job: string, params: RequestParams = {}) => + this.request<{ jwt?: string; status?: string }, Error>({ + path: `/scope/${job}`, + method: "PUT", + ...params, + }), }; } diff --git a/tests/generated/v2.0/example1.ts b/tests/generated/v2.0/example1.ts index 7119a02b..7bcca6f0 100644 --- a/tests/generated/v2.0/example1.ts +++ b/tests/generated/v2.0/example1.ts @@ -36,16 +36,34 @@ export interface TdeCertificateProperties { privateBlob: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -53,22 +71,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://management.azure.com"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -81,92 +100,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -179,7 +232,7 @@ export class HttpClient { * @baseUrl https://management.azure.com * The Azure SQL Database management API provides a RESTful set of web APIs that interact with Azure SQL Database services to manage your databases. The API enables users to create, retrieve, update, and delete databases, servers, and other entities. */ -export class Api extends HttpClient { +export class Api extends HttpClient { subscriptions = { /** * @description Creates a TDE certificate for a given server. @@ -194,16 +247,15 @@ export class Api extends HttpClient { subscriptionId: string, query: { "api-version": string }, parameters: TdeCertificate, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Sql/managedInstances/${managedInstanceName}/tdeCertificates${this.addQueryParams( - query, - )}`, - "POST", - params, - parameters, - BodyType.Json, - ), + this.request({ + path: `/subscriptions/${subscriptionId}/resourceGroups/${resourceGroupName}/providers/Microsoft.Sql/managedInstances/${managedInstanceName}/tdeCertificates`, + method: "POST", + query: query, + body: parameters, + type: ContentType.Json, + ...params, + }), }; } diff --git a/tests/generated/v2.0/file-formdata-example.ts b/tests/generated/v2.0/file-formdata-example.ts index 4e9e331e..4274c428 100644 --- a/tests/generated/v2.0/file-formdata-example.ts +++ b/tests/generated/v2.0/file-formdata-example.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -150,7 +203,7 @@ export class HttpClient { * @title Title * @version v0.1 */ -export class Api extends HttpClient { +export class Api extends HttpClient { uploadFile = { /** * No description @@ -160,7 +213,13 @@ export class Api extends HttpClient { * @summary Upload file * @request POST:/upload-file */ - uploadFile: (data: { file?: File; someFlag?: boolean }, params?: RequestParams) => - this.request(`/upload-file`, "POST", params, data, BodyType.FormData), + uploadFile: (data: { file?: File; someFlag?: boolean }, params: RequestParams = {}) => + this.request({ + path: `/upload-file`, + method: "POST", + body: data, + type: ContentType.FormData, + ...params, + }), }; } diff --git a/tests/generated/v2.0/furkot-example.ts b/tests/generated/v2.0/furkot-example.ts index 24b48df1..c8e5b5c8 100644 --- a/tests/generated/v2.0/furkot-example.ts +++ b/tests/generated/v2.0/furkot-example.ts @@ -72,16 +72,34 @@ export interface Trip { name?: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -89,22 +107,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://trips.furkot.com/pub/api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -117,92 +136,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -217,7 +270,7 @@ export class HttpClient { * Using Furkot API an application can list user trips and display stops for a specific trip. * Furkot API uses OAuth2 protocol to authorize applications to access data on behalf of users. */ -export class Api extends HttpClient { +export class Api extends HttpClient { trip = { /** * @description list user's trips @@ -226,7 +279,14 @@ export class Api extends HttpClient { * @request GET:/trip * @secure */ - tripList: (params?: RequestParams) => this.request(`/trip`, "GET", params, null, BodyType.Json, true), + tripList: (params: RequestParams = {}) => + this.request({ + path: `/trip`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * @description list stops for a trip identified by {trip_id} @@ -235,7 +295,13 @@ export class Api extends HttpClient { * @request GET:/trip/{trip_id}/stop * @secure */ - stopDetail: (trip_id: string, params?: RequestParams) => - this.request(`/trip/${trip_id}/stop`, "GET", params, null, BodyType.Json, true), + stopDetail: (trip_id: string, params: RequestParams = {}) => + this.request({ + path: `/trip/${trip_id}/stop`, + method: "GET", + secure: true, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/giphy.ts b/tests/generated/v2.0/giphy.ts index 12d3a683..2bc00f02 100644 --- a/tests/generated/v2.0/giphy.ts +++ b/tests/generated/v2.0/giphy.ts @@ -291,16 +291,34 @@ export interface User { username?: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -308,22 +326,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://api.giphy.com/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -336,92 +355,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -434,7 +487,7 @@ export class HttpClient { * @baseUrl https://api.giphy.com/v1 * Giphy API */ -export class Api extends HttpClient { +export class Api extends HttpClient { gifs = { /** * @description A multiget version of the get GIF by ID endpoint. @@ -445,15 +498,15 @@ export class Api extends HttpClient { * @request GET:/gifs * @secure */ - getGifsById: (query?: { ids?: string }, params?: RequestParams) => - this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>( - `/gifs${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + getGifsById: (query?: { ids?: string }, params: RequestParams = {}) => + this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>({ + path: `/gifs`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Returns a random GIF, limited by tag. Excluding the tag parameter will return a random GIF from the GIPHY catalog. @@ -464,15 +517,15 @@ export class Api extends HttpClient { * @request GET:/gifs/random * @secure */ - randomGif: (query?: { tag?: string; rating?: string }, params?: RequestParams) => - this.request<{ data?: Gif; meta?: Meta }, any>( - `/gifs/random${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + randomGif: (query?: { tag?: string; rating?: string }, params: RequestParams = {}) => + this.request<{ data?: Gif; meta?: Meta }, any>({ + path: `/gifs/random`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Search all GIPHY GIFs for a word or phrase. Punctuation will be stripped and ignored. Use a plus or url encode for phrases. Example paul+rudd, ryan+gosling or american+psycho. @@ -485,16 +538,16 @@ export class Api extends HttpClient { */ searchGifs: ( query: { q: string; limit?: number; offset?: number; rating?: string; lang?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>( - `/gifs/search${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>({ + path: `/gifs/search`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description The translate API draws on search, but uses the GIPHY `special sauce` to handle translating from one vocabulary to another. In this case, words and phrases to GIF @@ -505,15 +558,15 @@ export class Api extends HttpClient { * @request GET:/gifs/translate * @secure */ - translateGif: (query: { s: string }, params?: RequestParams) => - this.request<{ data?: Gif; meta?: Meta }, any>( - `/gifs/translate${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + translateGif: (query: { s: string }, params: RequestParams = {}) => + this.request<{ data?: Gif; meta?: Meta }, any>({ + path: `/gifs/translate`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Fetch GIFs currently trending online. Hand curated by the GIPHY editorial team. The data returned mirrors the GIFs showcased on the GIPHY homepage. Returns 25 results by default. @@ -524,15 +577,15 @@ export class Api extends HttpClient { * @request GET:/gifs/trending * @secure */ - trendingGifs: (query?: { limit?: number; offset?: number; rating?: string }, params?: RequestParams) => - this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>( - `/gifs/trending${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + trendingGifs: (query?: { limit?: number; offset?: number; rating?: string }, params: RequestParams = {}) => + this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>({ + path: `/gifs/trending`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Returns a GIF given that GIF's unique ID @@ -543,8 +596,14 @@ export class Api extends HttpClient { * @request GET:/gifs/{gifId} * @secure */ - getGifById: (gifId: number, params?: RequestParams) => - this.request<{ data?: Gif; meta?: Meta }, any>(`/gifs/${gifId}`, "GET", params, null, BodyType.Json, true), + getGifById: (gifId: number, params: RequestParams = {}) => + this.request<{ data?: Gif; meta?: Meta }, any>({ + path: `/gifs/${gifId}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), }; stickers = { /** @@ -556,15 +615,15 @@ export class Api extends HttpClient { * @request GET:/stickers/random * @secure */ - randomSticker: (query?: { tag?: string; rating?: string }, params?: RequestParams) => - this.request<{ data?: Gif; meta?: Meta }, any>( - `/stickers/random${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + randomSticker: (query?: { tag?: string; rating?: string }, params: RequestParams = {}) => + this.request<{ data?: Gif; meta?: Meta }, any>({ + path: `/stickers/random`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Replicates the functionality and requirements of the classic GIPHY search, but returns animated stickers rather than GIFs. @@ -577,16 +636,16 @@ export class Api extends HttpClient { */ searchStickers: ( query: { q: string; limit?: number; offset?: number; rating?: string; lang?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>( - `/stickers/search${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>({ + path: `/stickers/search`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description The translate API draws on search, but uses the GIPHY `special sauce` to handle translating from one vocabulary to another. In this case, words and phrases to GIFs. @@ -597,15 +656,15 @@ export class Api extends HttpClient { * @request GET:/stickers/translate * @secure */ - translateSticker: (query: { s: string }, params?: RequestParams) => - this.request<{ data?: Gif; meta?: Meta }, any>( - `/stickers/translate${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + translateSticker: (query: { s: string }, params: RequestParams = {}) => + this.request<{ data?: Gif; meta?: Meta }, any>({ + path: `/stickers/translate`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Fetch Stickers currently trending online. Hand curated by the GIPHY editorial team. Returns 25 results by default. @@ -616,14 +675,14 @@ export class Api extends HttpClient { * @request GET:/stickers/trending * @secure */ - trendingStickers: (query?: { limit?: number; offset?: number; rating?: string }, params?: RequestParams) => - this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>( - `/stickers/trending${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + trendingStickers: (query?: { limit?: number; offset?: number; rating?: string }, params: RequestParams = {}) => + this.request<{ data?: Gif[]; meta?: Meta; pagination?: Pagination }, any>({ + path: `/stickers/trending`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/github-swagger.ts b/tests/generated/v2.0/github-swagger.ts index b406fbb8..9b6cab55 100644 --- a/tests/generated/v2.0/github-swagger.ts +++ b/tests/generated/v2.0/github-swagger.ts @@ -1434,16 +1434,34 @@ export interface UserUpdate { export type Users = User[]; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -1451,22 +1469,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://api.github.com"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -1479,92 +1498,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -1577,7 +1630,7 @@ export class HttpClient { * @baseUrl https://api.github.com * Powerful collaboration, code review, and code management for open source and private projects. */ -export class Api extends HttpClient { +export class Api extends HttpClient { emojis = { /** * @description Lists all the emojis available to use on GitHub. @@ -1585,7 +1638,13 @@ export class Api extends HttpClient { * @name EmojisList * @request GET:/emojis */ - emojisList: (params?: RequestParams) => this.request(`/emojis`, "GET", params), + emojisList: (params: RequestParams = {}) => + this.request({ + path: `/emojis`, + method: "GET", + format: "json", + ...params, + }), }; events = { /** @@ -1594,7 +1653,13 @@ export class Api extends HttpClient { * @name EventsList * @request GET:/events */ - eventsList: (params?: RequestParams) => this.request(`/events`, "GET", params), + eventsList: (params: RequestParams = {}) => + this.request({ + path: `/events`, + method: "GET", + format: "json", + ...params, + }), }; feeds = { /** @@ -1603,7 +1668,13 @@ export class Api extends HttpClient { * @name FeedsList * @request GET:/feeds */ - feedsList: (params?: RequestParams) => this.request(`/feeds`, "GET", params), + feedsList: (params: RequestParams = {}) => + this.request({ + path: `/feeds`, + method: "GET", + format: "json", + ...params, + }), }; gists = { /** @@ -1612,8 +1683,14 @@ export class Api extends HttpClient { * @name GistsList * @request GET:/gists */ - gistsList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/gists${this.addQueryParams(query)}`, "GET", params), + gistsList: (query?: { since?: string }, params: RequestParams = {}) => + this.request({ + path: `/gists`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a gist. @@ -1621,8 +1698,15 @@ export class Api extends HttpClient { * @name GistsCreate * @request POST:/gists */ - gistsCreate: (body: PostGist, params?: RequestParams) => - this.request(`/gists`, "POST", params, body, BodyType.Json), + gistsCreate: (body: PostGist, params: RequestParams = {}) => + this.request({ + path: `/gists`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List all public gists. @@ -1630,8 +1714,14 @@ export class Api extends HttpClient { * @name PublicList * @request GET:/gists/public */ - publicList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/gists/public${this.addQueryParams(query)}`, "GET", params), + publicList: (query?: { since?: string }, params: RequestParams = {}) => + this.request({ + path: `/gists/public`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List the authenticated user's starred gists. @@ -1639,8 +1729,14 @@ export class Api extends HttpClient { * @name StarredList * @request GET:/gists/starred */ - starredList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/gists/starred${this.addQueryParams(query)}`, "GET", params), + starredList: (query?: { since?: string }, params: RequestParams = {}) => + this.request({ + path: `/gists/starred`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Delete a gist. @@ -1648,7 +1744,12 @@ export class Api extends HttpClient { * @name GistsDelete * @request DELETE:/gists/{id} */ - gistsDelete: (id: number, params?: RequestParams) => this.request(`/gists/${id}`, "DELETE", params), + gistsDelete: (id: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}`, + method: "DELETE", + ...params, + }), /** * @description Get a single gist. @@ -1656,7 +1757,13 @@ export class Api extends HttpClient { * @name GistsDetail * @request GET:/gists/{id} */ - gistsDetail: (id: number, params?: RequestParams) => this.request(`/gists/${id}`, "GET", params), + gistsDetail: (id: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a gist. @@ -1664,8 +1771,15 @@ export class Api extends HttpClient { * @name GistsPartialUpdate * @request PATCH:/gists/{id} */ - gistsPartialUpdate: (id: number, body: PatchGist, params?: RequestParams) => - this.request(`/gists/${id}`, "PATCH", params, body, BodyType.Json), + gistsPartialUpdate: (id: number, body: PatchGist, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List comments on a gist. @@ -1673,8 +1787,13 @@ export class Api extends HttpClient { * @name CommentsDetail * @request GET:/gists/{id}/comments */ - commentsDetail: (id: number, params?: RequestParams) => - this.request(`/gists/${id}/comments`, "GET", params), + commentsDetail: (id: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a commen @@ -1682,8 +1801,14 @@ export class Api extends HttpClient { * @name CommentsCreate * @request POST:/gists/{id}/comments */ - commentsCreate: (id: number, body: CommentBody, params?: RequestParams) => - this.request(`/gists/${id}/comments`, "POST", params, body), + commentsCreate: (id: number, body: CommentBody, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/comments`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a comment. @@ -1691,8 +1816,12 @@ export class Api extends HttpClient { * @name CommentsDelete * @request DELETE:/gists/{id}/comments/{commentId} */ - commentsDelete: (id: number, commentId: number, params?: RequestParams) => - this.request(`/gists/${id}/comments/${commentId}`, "DELETE", params), + commentsDelete: (id: number, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single comment. @@ -1702,8 +1831,13 @@ export class Api extends HttpClient { * @originalName commentsDetail * @duplicate */ - commentsDetail2: (id: number, commentId: number, params?: RequestParams) => - this.request(`/gists/${id}/comments/${commentId}`, "GET", params), + commentsDetail2: (id: number, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a comment. @@ -1711,8 +1845,15 @@ export class Api extends HttpClient { * @name CommentsPartialUpdate * @request PATCH:/gists/{id}/comments/{commentId} */ - commentsPartialUpdate: (id: number, commentId: number, body: Comment, params?: RequestParams) => - this.request(`/gists/${id}/comments/${commentId}`, "PATCH", params, body, BodyType.Json), + commentsPartialUpdate: (id: number, commentId: number, body: Comment, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/comments/${commentId}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Fork a gist. @@ -1720,7 +1861,12 @@ export class Api extends HttpClient { * @name ForksCreate * @request POST:/gists/{id}/forks */ - forksCreate: (id: number, params?: RequestParams) => this.request(`/gists/${id}/forks`, "POST", params), + forksCreate: (id: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/forks`, + method: "POST", + ...params, + }), /** * @description Unstar a gist. @@ -1728,7 +1874,12 @@ export class Api extends HttpClient { * @name StarDelete * @request DELETE:/gists/{id}/star */ - starDelete: (id: number, params?: RequestParams) => this.request(`/gists/${id}/star`, "DELETE", params), + starDelete: (id: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/star`, + method: "DELETE", + ...params, + }), /** * @description Check if a gist is starred. @@ -1736,7 +1887,12 @@ export class Api extends HttpClient { * @name StarDetail * @request GET:/gists/{id}/star */ - starDetail: (id: number, params?: RequestParams) => this.request(`/gists/${id}/star`, "GET", params), + starDetail: (id: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/star`, + method: "GET", + ...params, + }), /** * @description Star a gist. @@ -1744,7 +1900,12 @@ export class Api extends HttpClient { * @name StarUpdate * @request PUT:/gists/{id}/star */ - starUpdate: (id: number, params?: RequestParams) => this.request(`/gists/${id}/star`, "PUT", params), + starUpdate: (id: number, params: RequestParams = {}) => + this.request({ + path: `/gists/${id}/star`, + method: "PUT", + ...params, + }), }; gitignore = { /** @@ -1753,7 +1914,13 @@ export class Api extends HttpClient { * @name TemplatesList * @request GET:/gitignore/templates */ - templatesList: (params?: RequestParams) => this.request(`/gitignore/templates`, "GET", params), + templatesList: (params: RequestParams = {}) => + this.request({ + path: `/gitignore/templates`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single template. @@ -1761,8 +1928,13 @@ export class Api extends HttpClient { * @name TemplatesDetail * @request GET:/gitignore/templates/{language} */ - templatesDetail: (language: string, params?: RequestParams) => - this.request(`/gitignore/templates/${language}`, "GET", params), + templatesDetail: (language: string, params: RequestParams = {}) => + this.request({ + path: `/gitignore/templates/${language}`, + method: "GET", + format: "json", + ...params, + }), }; issues = { /** @@ -1780,8 +1952,15 @@ export class Api extends HttpClient { direction: "asc" | "desc"; since?: string; }, - params?: RequestParams, - ) => this.request(`/issues${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; legacy = { /** @@ -1795,13 +1974,14 @@ export class Api extends HttpClient { state: "open" | "closed", owner: string, repository: string, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/legacy/issues/search/${owner}/${repository}/${state}/${keyword}`, - "GET", - params, - ), + this.request({ + path: `/legacy/issues/search/${owner}/${repository}/${state}/${keyword}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Find repositories by keyword. Note, this legacy method does not follow the v3 pagination pattern. This method returns up to 100 results per page and pages can be fetched using the start_page parameter. @@ -1812,13 +1992,15 @@ export class Api extends HttpClient { reposSearchDetail: ( keyword: string, query?: { order?: "desc" | "asc"; language?: string; start_page?: string; sort?: "updated" | "stars" | "forks" }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/legacy/repos/search/${keyword}${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/legacy/repos/search/${keyword}`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description This API call is added for compatibility reasons only. @@ -1826,8 +2008,13 @@ export class Api extends HttpClient { * @name UserEmailDetail * @request GET:/legacy/user/email/{email} */ - userEmailDetail: (email: string, params?: RequestParams) => - this.request(`/legacy/user/email/${email}`, "GET", params), + userEmailDetail: (email: string, params: RequestParams = {}) => + this.request({ + path: `/legacy/user/email/${email}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Find users by keyword. @@ -1838,13 +2025,15 @@ export class Api extends HttpClient { userSearchDetail: ( keyword: string, query?: { order?: "desc" | "asc"; start_page?: string; sort?: "updated" | "stars" | "forks" }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/legacy/user/search/${keyword}${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/legacy/user/search/${keyword}`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; markdown = { /** @@ -1853,8 +2042,14 @@ export class Api extends HttpClient { * @name MarkdownCreate * @request POST:/markdown */ - markdownCreate: (body: Markdown, params?: RequestParams) => - this.request(`/markdown`, "POST", params, body, BodyType.Json), + markdownCreate: (body: Markdown, params: RequestParams = {}) => + this.request({ + path: `/markdown`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description Render a Markdown document in raw mode @@ -1862,7 +2057,12 @@ export class Api extends HttpClient { * @name PostMarkdown * @request POST:/markdown/raw */ - postMarkdown: (params?: RequestParams) => this.request(`/markdown/raw`, "POST", params), + postMarkdown: (params: RequestParams = {}) => + this.request({ + path: `/markdown/raw`, + method: "POST", + ...params, + }), }; meta = { /** @@ -1871,7 +2071,13 @@ export class Api extends HttpClient { * @name MetaList * @request GET:/meta */ - metaList: (params?: RequestParams) => this.request(`/meta`, "GET", params), + metaList: (params: RequestParams = {}) => + this.request({ + path: `/meta`, + method: "GET", + format: "json", + ...params, + }), }; networks = { /** @@ -1880,8 +2086,13 @@ export class Api extends HttpClient { * @name EventsDetail * @request GET:/networks/{owner}/{repo}/events */ - eventsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/networks/${owner}/${repo}/events`, "GET", params), + eventsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/networks/${owner}/${repo}/events`, + method: "GET", + format: "json", + ...params, + }), }; notifications = { /** @@ -1890,8 +2101,17 @@ export class Api extends HttpClient { * @name NotificationsList * @request GET:/notifications */ - notificationsList: (query?: { all?: boolean; participating?: boolean; since?: string }, params?: RequestParams) => - this.request(`/notifications${this.addQueryParams(query)}`, "GET", params), + notificationsList: ( + query?: { all?: boolean; participating?: boolean; since?: string }, + params: RequestParams = {}, + ) => + this.request({ + path: `/notifications`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Mark as read. Marking a notification as "read" removes it from the default view on GitHub.com. @@ -1899,8 +2119,13 @@ export class Api extends HttpClient { * @name NotificationsUpdate * @request PUT:/notifications */ - notificationsUpdate: (body: NotificationMarkRead, params?: RequestParams) => - this.request(`/notifications`, "PUT", params, body), + notificationsUpdate: (body: NotificationMarkRead, params: RequestParams = {}) => + this.request({ + path: `/notifications`, + method: "PUT", + body: body, + ...params, + }), /** * @description View a single thread. @@ -1908,8 +2133,13 @@ export class Api extends HttpClient { * @name ThreadsDetail * @request GET:/notifications/threads/{id} */ - threadsDetail: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}`, "GET", params), + threadsDetail: (id: number, params: RequestParams = {}) => + this.request({ + path: `/notifications/threads/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Mark a thread as read @@ -1917,8 +2147,12 @@ export class Api extends HttpClient { * @name ThreadsPartialUpdate * @request PATCH:/notifications/threads/{id} */ - threadsPartialUpdate: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}`, "PATCH", params), + threadsPartialUpdate: (id: number, params: RequestParams = {}) => + this.request({ + path: `/notifications/threads/${id}`, + method: "PATCH", + ...params, + }), /** * @description Delete a Thread Subscription. @@ -1926,8 +2160,12 @@ export class Api extends HttpClient { * @name ThreadsSubscriptionDelete * @request DELETE:/notifications/threads/{id}/subscription */ - threadsSubscriptionDelete: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}/subscription`, "DELETE", params), + threadsSubscriptionDelete: (id: number, params: RequestParams = {}) => + this.request({ + path: `/notifications/threads/${id}/subscription`, + method: "DELETE", + ...params, + }), /** * @description Get a Thread Subscription. @@ -1935,8 +2173,13 @@ export class Api extends HttpClient { * @name ThreadsSubscriptionDetail * @request GET:/notifications/threads/{id}/subscription */ - threadsSubscriptionDetail: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}/subscription`, "GET", params), + threadsSubscriptionDetail: (id: number, params: RequestParams = {}) => + this.request({ + path: `/notifications/threads/${id}/subscription`, + method: "GET", + format: "json", + ...params, + }), /** * @description Set a Thread Subscription. This lets you subscribe to a thread, or ignore it. Subscribing to a thread is unnecessary if the user is already subscribed to the repository. Ignoring a thread will mute all future notifications (until you comment or get @mentioned). @@ -1944,8 +2187,15 @@ export class Api extends HttpClient { * @name ThreadsSubscriptionUpdate * @request PUT:/notifications/threads/{id}/subscription */ - threadsSubscriptionUpdate: (id: number, body: PutSubscription, params?: RequestParams) => - this.request(`/notifications/threads/${id}/subscription`, "PUT", params, body, BodyType.Json), + threadsSubscriptionUpdate: (id: number, body: PutSubscription, params: RequestParams = {}) => + this.request({ + path: `/notifications/threads/${id}/subscription`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), }; orgs = { /** @@ -1954,7 +2204,13 @@ export class Api extends HttpClient { * @name OrgsDetail * @request GET:/orgs/{org} */ - orgsDetail: (org: string, params?: RequestParams) => this.request(`/orgs/${org}`, "GET", params), + orgsDetail: (org: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit an Organization. @@ -1962,8 +2218,15 @@ export class Api extends HttpClient { * @name OrgsPartialUpdate * @request PATCH:/orgs/{org} */ - orgsPartialUpdate: (org: string, body: PatchOrg, params?: RequestParams) => - this.request(`/orgs/${org}`, "PATCH", params, body, BodyType.Json), + orgsPartialUpdate: (org: string, body: PatchOrg, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List public events for an organization. @@ -1971,8 +2234,13 @@ export class Api extends HttpClient { * @name EventsDetail * @request GET:/orgs/{org}/events */ - eventsDetail: (org: string, params?: RequestParams) => - this.request(`/orgs/${org}/events`, "GET", params), + eventsDetail: (org: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description List issues. List all issues for a given organization for the authenticated user. @@ -1990,8 +2258,15 @@ export class Api extends HttpClient { direction: "asc" | "desc"; since?: string; }, - params?: RequestParams, - ) => this.request(`/orgs/${org}/issues${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/orgs/${org}/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Members list. List all users who are members of an organization. A member is a user tha belongs to at least 1 team in the organization. If the authenticated user is also an owner of this organization then both concealed and public members will be returned. If the requester is not an owner of the organization the query will be redirected to the public members list. @@ -1999,8 +2274,13 @@ export class Api extends HttpClient { * @name MembersDetail * @request GET:/orgs/{org}/members */ - membersDetail: (org: string, params?: RequestParams) => - this.request(`/orgs/${org}/members`, "GET", params), + membersDetail: (org: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/members`, + method: "GET", + format: "json", + ...params, + }), /** * @description Remove a member. Removing a user from this list will remove them from all teams and they will no longer have any access to the organization's repositories. @@ -2008,8 +2288,12 @@ export class Api extends HttpClient { * @name MembersDelete * @request DELETE:/orgs/{org}/members/{username} */ - membersDelete: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/members/${username}`, "DELETE", params), + membersDelete: (org: string, username: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/members/${username}`, + method: "DELETE", + ...params, + }), /** * @description Check if a user is, publicly or privately, a member of the organization. @@ -2019,8 +2303,12 @@ export class Api extends HttpClient { * @originalName membersDetail * @duplicate */ - membersDetail2: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/members/${username}`, "GET", params), + membersDetail2: (org: string, username: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/members/${username}`, + method: "GET", + ...params, + }), /** * @description Public members list. Members of an organization can choose to have their membership publicized or not. @@ -2028,8 +2316,13 @@ export class Api extends HttpClient { * @name PublicMembersDetail * @request GET:/orgs/{org}/public_members */ - publicMembersDetail: (org: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members`, "GET", params), + publicMembersDetail: (org: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/public_members`, + method: "GET", + format: "json", + ...params, + }), /** * @description Conceal a user's membership. @@ -2037,8 +2330,12 @@ export class Api extends HttpClient { * @name PublicMembersDelete * @request DELETE:/orgs/{org}/public_members/{username} */ - publicMembersDelete: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members/${username}`, "DELETE", params), + publicMembersDelete: (org: string, username: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/public_members/${username}`, + method: "DELETE", + ...params, + }), /** * @description Check public membership. @@ -2048,8 +2345,12 @@ export class Api extends HttpClient { * @originalName publicMembersDetail * @duplicate */ - publicMembersDetail2: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members/${username}`, "GET", params), + publicMembersDetail2: (org: string, username: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/public_members/${username}`, + method: "GET", + ...params, + }), /** * @description Publicize a user's membership. @@ -2057,8 +2358,12 @@ export class Api extends HttpClient { * @name PublicMembersUpdate * @request PUT:/orgs/{org}/public_members/{username} */ - publicMembersUpdate: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members/${username}`, "PUT", params), + publicMembersUpdate: (org: string, username: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/public_members/${username}`, + method: "PUT", + ...params, + }), /** * @description List repositories for the specified org. @@ -2069,8 +2374,15 @@ export class Api extends HttpClient { reposDetail: ( org: string, query?: { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }, - params?: RequestParams, - ) => this.request(`/orgs/${org}/repos${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/orgs/${org}/repos`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. @@ -2078,8 +2390,14 @@ export class Api extends HttpClient { * @name ReposCreate * @request POST:/orgs/{org}/repos */ - reposCreate: (org: string, body: PostRepo, params?: RequestParams) => - this.request(`/orgs/${org}/repos`, "POST", params, body), + reposCreate: (org: string, body: PostRepo, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/repos`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List teams. @@ -2087,7 +2405,13 @@ export class Api extends HttpClient { * @name TeamsDetail * @request GET:/orgs/{org}/teams */ - teamsDetail: (org: string, params?: RequestParams) => this.request(`/orgs/${org}/teams`, "GET", params), + teamsDetail: (org: string, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/teams`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create team. In order to create a team, the authenticated user must be an owner of organization. @@ -2095,8 +2419,15 @@ export class Api extends HttpClient { * @name TeamsCreate * @request POST:/orgs/{org}/teams */ - teamsCreate: (org: string, body: OrgTeamsPost, params?: RequestParams) => - this.request(`/orgs/${org}/teams`, "POST", params, body, BodyType.Json), + teamsCreate: (org: string, body: OrgTeamsPost, params: RequestParams = {}) => + this.request({ + path: `/orgs/${org}/teams`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), }; rateLimit = { /** @@ -2105,7 +2436,13 @@ export class Api extends HttpClient { * @name RateLimitList * @request GET:/rate_limit */ - rateLimitList: (params?: RequestParams) => this.request(`/rate_limit`, "GET", params), + rateLimitList: (params: RequestParams = {}) => + this.request({ + path: `/rate_limit`, + method: "GET", + format: "json", + ...params, + }), }; repos = { /** @@ -2114,8 +2451,12 @@ export class Api extends HttpClient { * @name ReposDelete * @request DELETE:/repos/{owner}/{repo} */ - reposDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}`, "DELETE", params), + reposDelete: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Get repository. @@ -2123,8 +2464,13 @@ export class Api extends HttpClient { * @name ReposDetail * @request GET:/repos/{owner}/{repo} */ - reposDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}`, "GET", params), + reposDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit repository. @@ -2132,8 +2478,15 @@ export class Api extends HttpClient { * @name ReposPartialUpdate * @request PATCH:/repos/{owner}/{repo} */ - reposPartialUpdate: (owner: string, repo: string, body: RepoEdit, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}`, "PATCH", params, body, BodyType.Json), + reposPartialUpdate: (owner: string, repo: string, body: RepoEdit, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List assignees. This call lists all the available assignees (owner + collaborators) to which issues may be assigned. @@ -2141,8 +2494,13 @@ export class Api extends HttpClient { * @name AssigneesDetail * @request GET:/repos/{owner}/{repo}/assignees */ - assigneesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/assignees`, "GET", params), + assigneesDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/assignees`, + method: "GET", + format: "json", + ...params, + }), /** * @description Check assignee. You may also check to see if a particular user is an assignee for a repository. @@ -2152,8 +2510,12 @@ export class Api extends HttpClient { * @originalName assigneesDetail * @duplicate */ - assigneesDetail2: (owner: string, repo: string, assignee: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/assignees/${assignee}`, "GET", params), + assigneesDetail2: (owner: string, repo: string, assignee: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/assignees/${assignee}`, + method: "GET", + ...params, + }), /** * @description Get list of branches @@ -2161,8 +2523,13 @@ export class Api extends HttpClient { * @name BranchesDetail * @request GET:/repos/{owner}/{repo}/branches */ - branchesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/branches`, "GET", params), + branchesDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/branches`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get Branch @@ -2172,8 +2539,13 @@ export class Api extends HttpClient { * @originalName branchesDetail * @duplicate */ - branchesDetail2: (owner: string, repo: string, branch: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/branches/${branch}`, "GET", params), + branchesDetail2: (owner: string, repo: string, branch: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/branches/${branch}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List. When authenticating as an organization owner of an organization-owned repository, all organization owners are included in the list of collaborators. Otherwise, only users with access to the repository are returned in the collaborators list. @@ -2181,8 +2553,13 @@ export class Api extends HttpClient { * @name CollaboratorsDetail * @request GET:/repos/{owner}/{repo}/collaborators */ - collaboratorsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators`, "GET", params), + collaboratorsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators`, + method: "GET", + format: "json", + ...params, + }), /** * @description Remove collaborator. @@ -2190,8 +2567,12 @@ export class Api extends HttpClient { * @name CollaboratorsDelete * @request DELETE:/repos/{owner}/{repo}/collaborators/{user} */ - collaboratorsDelete: (owner: string, repo: string, user: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "DELETE", params), + collaboratorsDelete: (owner: string, repo: string, user: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators/${user}`, + method: "DELETE", + ...params, + }), /** * @description Check if user is a collaborator @@ -2201,8 +2582,12 @@ export class Api extends HttpClient { * @originalName collaboratorsDetail * @duplicate */ - collaboratorsDetail2: (owner: string, repo: string, user: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "GET", params), + collaboratorsDetail2: (owner: string, repo: string, user: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators/${user}`, + method: "GET", + ...params, + }), /** * @description Add collaborator. @@ -2210,8 +2595,12 @@ export class Api extends HttpClient { * @name CollaboratorsUpdate * @request PUT:/repos/{owner}/{repo}/collaborators/{user} */ - collaboratorsUpdate: (owner: string, repo: string, user: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "PUT", params), + collaboratorsUpdate: (owner: string, repo: string, user: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators/${user}`, + method: "PUT", + ...params, + }), /** * @description List commit comments for a repository. Comments are ordered by ascending ID. @@ -2219,8 +2608,13 @@ export class Api extends HttpClient { * @name CommentsDetail * @request GET:/repos/{owner}/{repo}/comments */ - commentsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/comments`, "GET", params), + commentsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Delete a commit comment @@ -2228,8 +2622,12 @@ export class Api extends HttpClient { * @name CommentsDelete * @request DELETE:/repos/{owner}/{repo}/comments/{commentId} */ - commentsDelete: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "DELETE", params), + commentsDelete: (owner: string, repo: string, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single commit comment. @@ -2239,8 +2637,13 @@ export class Api extends HttpClient { * @originalName commentsDetail * @duplicate */ - commentsDetail2: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "GET", params), + commentsDetail2: (owner: string, repo: string, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a commit comment. @@ -2253,8 +2656,15 @@ export class Api extends HttpClient { repo: string, commentId: number, body: CommentBody, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "PATCH", params, body), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/comments/${commentId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List commits on a repository. @@ -2266,8 +2676,15 @@ export class Api extends HttpClient { owner: string, repo: string, query?: { since?: string; sha?: string; path?: string; author?: string; until?: string }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/commits${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/commits`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Get the combined Status for a specific Ref The Combined status endpoint is currently available for developers to preview. During the preview period, the API may change without advance notice. Please see the blog post for full details. To access this endpoint during the preview period, you must provide a custom media type in the Accept header: application/vnd.github.she-hulk-preview+json @@ -2275,8 +2692,13 @@ export class Api extends HttpClient { * @name CommitsStatusDetail * @request GET:/repos/{owner}/{repo}/commits/{ref}/status */ - commitsStatusDetail: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/commits/${ref}/status`, "GET", params), + commitsStatusDetail: (owner: string, repo: string, ref: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits/${ref}/status`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single commit. @@ -2286,8 +2708,13 @@ export class Api extends HttpClient { * @originalName commitsDetail * @duplicate */ - commitsDetail2: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/commits/${shaCode}`, "GET", params), + commitsDetail2: (owner: string, repo: string, shaCode: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List comments for a single commitList comments for a single commit. @@ -2295,8 +2722,13 @@ export class Api extends HttpClient { * @name CommitsCommentsDetail * @request GET:/repos/{owner}/{repo}/commits/{shaCode}/comments */ - commitsCommentsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/commits/${shaCode}/comments`, "GET", params), + commitsCommentsDetail: (owner: string, repo: string, shaCode: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits/${shaCode}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a commit comment. @@ -2309,15 +2741,16 @@ export class Api extends HttpClient { repo: string, shaCode: string, body: CommitCommentBody, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/repos/${owner}/${repo}/commits/${shaCode}/comments`, - "POST", - params, - body, - BodyType.Json, - ), + this.request({ + path: `/repos/${owner}/${repo}/commits/${shaCode}/comments`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Compare two commits @@ -2325,8 +2758,13 @@ export class Api extends HttpClient { * @name CompareDetail * @request GET:/repos/{owner}/{repo}/compare/{baseId}...{headId} */ - compareDetail: (owner: string, repo: string, baseId: string, headId: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/compare/${baseId}...${headId}`, "GET", params), + compareDetail: (owner: string, repo: string, baseId: string, headId: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/compare/${baseId}...${headId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Delete a file. This method deletes a file in a repository. @@ -2334,8 +2772,15 @@ export class Api extends HttpClient { * @name ContentsDelete * @request DELETE:/repos/{owner}/{repo}/contents/{path} */ - contentsDelete: (owner: string, repo: string, path: string, body: DeleteFileBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/contents/${path}`, "DELETE", params, body, BodyType.Json), + contentsDelete: (owner: string, repo: string, path: string, body: DeleteFileBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/contents/${path}`, + method: "DELETE", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get contents. This method returns the contents of a file or directory in a repository. Files and symlinks support a custom media type for getting the raw content. Directories and submodules do not support custom media types. Note: This API supports files up to 1 megabyte in size. Here can be many outcomes. For details see "http://developer.github.com/v3/repos/contents/" @@ -2348,13 +2793,15 @@ export class Api extends HttpClient { repo: string, path: string, query?: { path?: string; ref?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/repos/${owner}/${repo}/contents/${path}${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/repos/${owner}/${repo}/contents/${path}`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a file. @@ -2362,8 +2809,15 @@ export class Api extends HttpClient { * @name ContentsUpdate * @request PUT:/repos/{owner}/{repo}/contents/{path} */ - contentsUpdate: (owner: string, repo: string, path: string, body: CreateFileBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/contents/${path}`, "PUT", params, body, BodyType.Json), + contentsUpdate: (owner: string, repo: string, path: string, body: CreateFileBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/contents/${path}`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get list of contributors. @@ -2371,8 +2825,14 @@ export class Api extends HttpClient { * @name ContributorsDetail * @request GET:/repos/{owner}/{repo}/contributors */ - contributorsDetail: (owner: string, repo: string, query: { anon: string }, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/contributors${this.addQueryParams(query)}`, "GET", params), + contributorsDetail: (owner: string, repo: string, query: { anon: string }, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/contributors`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Users with pull access can view deployments for a repository @@ -2380,8 +2840,13 @@ export class Api extends HttpClient { * @name DeploymentsDetail * @request GET:/repos/{owner}/{repo}/deployments */ - deploymentsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/deployments`, "GET", params), + deploymentsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/deployments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Users with push access can create a deployment for a given ref @@ -2389,8 +2854,15 @@ export class Api extends HttpClient { * @name DeploymentsCreate * @request POST:/repos/{owner}/{repo}/deployments */ - deploymentsCreate: (owner: string, repo: string, body: Deployment, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/deployments`, "POST", params, body, BodyType.Json), + deploymentsCreate: (owner: string, repo: string, body: Deployment, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/deployments`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Users with pull access can view deployment statuses for a deployment @@ -2398,8 +2870,13 @@ export class Api extends HttpClient { * @name DeploymentsStatusesDetail * @request GET:/repos/{owner}/{repo}/deployments/{id}/statuses */ - deploymentsStatusesDetail: (owner: string, repo: string, id: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/deployments/${id}/statuses`, "GET", params), + deploymentsStatusesDetail: (owner: string, repo: string, id: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/deployments/${id}/statuses`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Deployment Status Users with push access can create deployment statuses for a given deployment: @@ -2412,9 +2889,15 @@ export class Api extends HttpClient { repo: string, id: number, body: DeploymentStatusesCreate, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request(`/repos/${owner}/${repo}/deployments/${id}/statuses`, "POST", params, body, BodyType.Json), + this.request({ + path: `/repos/${owner}/${repo}/deployments/${id}/statuses`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description Deprecated. List downloads for a repository. @@ -2422,8 +2905,13 @@ export class Api extends HttpClient { * @name DownloadsDetail * @request GET:/repos/{owner}/{repo}/downloads */ - downloadsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/downloads`, "GET", params), + downloadsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/downloads`, + method: "GET", + format: "json", + ...params, + }), /** * @description Deprecated. Delete a download. @@ -2431,8 +2919,12 @@ export class Api extends HttpClient { * @name DownloadsDelete * @request DELETE:/repos/{owner}/{repo}/downloads/{downloadId} */ - downloadsDelete: (owner: string, repo: string, downloadId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/downloads/${downloadId}`, "DELETE", params), + downloadsDelete: (owner: string, repo: string, downloadId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/downloads/${downloadId}`, + method: "DELETE", + ...params, + }), /** * @description Deprecated. Get a single download. @@ -2442,8 +2934,13 @@ export class Api extends HttpClient { * @originalName downloadsDetail * @duplicate */ - downloadsDetail2: (owner: string, repo: string, downloadId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/downloads/${downloadId}`, "GET", params), + downloadsDetail2: (owner: string, repo: string, downloadId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/downloads/${downloadId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get list of repository events. @@ -2451,8 +2948,13 @@ export class Api extends HttpClient { * @name EventsDetail * @request GET:/repos/{owner}/{repo}/events */ - eventsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/events`, "GET", params), + eventsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description List forks. @@ -2464,8 +2966,15 @@ export class Api extends HttpClient { owner: string, repo: string, query?: { sort?: "newes" | "oldes" | "watchers" }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/forks${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/forks`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a fork. Forking a Repository happens asynchronously. Therefore, you may have to wai a short period before accessing the git objects. If this takes longer than 5 minutes, be sure to contact Support. @@ -2473,8 +2982,15 @@ export class Api extends HttpClient { * @name ForksCreate * @request POST:/repos/{owner}/{repo}/forks */ - forksCreate: (owner: string, repo: string, body: ForkBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/forks`, "POST", params, body, BodyType.Json), + forksCreate: (owner: string, repo: string, body: ForkBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/forks`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Create a Blob. @@ -2482,8 +2998,15 @@ export class Api extends HttpClient { * @name GitBlobsCreate * @request POST:/repos/{owner}/{repo}/git/blobs */ - gitBlobsCreate: (owner: string, repo: string, body: Blob, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/blobs`, "POST", params, body, BodyType.Json), + gitBlobsCreate: (owner: string, repo: string, body: Blob, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/blobs`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Blob. Since blobs can be any arbitrary binary data, the input and responses for the blob API takes an encoding parameter that can be either utf-8 or base64. If your data cannot be losslessly sent as a UTF-8 string, you can base64 encode it. @@ -2491,8 +3014,13 @@ export class Api extends HttpClient { * @name GitBlobsDetail * @request GET:/repos/{owner}/{repo}/git/blobs/{shaCode} */ - gitBlobsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/blobs/${shaCode}`, "GET", params), + gitBlobsDetail: (owner: string, repo: string, shaCode: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/blobs/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Commit. @@ -2500,8 +3028,15 @@ export class Api extends HttpClient { * @name GitCommitsCreate * @request POST:/repos/{owner}/{repo}/git/commits */ - gitCommitsCreate: (owner: string, repo: string, body: RepoCommitBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/commits`, "POST", params, body, BodyType.Json), + gitCommitsCreate: (owner: string, repo: string, body: RepoCommitBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/commits`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Commit. @@ -2509,8 +3044,13 @@ export class Api extends HttpClient { * @name GitCommitsDetail * @request GET:/repos/{owner}/{repo}/git/commits/{shaCode} */ - gitCommitsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/commits/${shaCode}`, "GET", params), + gitCommitsDetail: (owner: string, repo: string, shaCode: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/commits/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get all References @@ -2518,8 +3058,13 @@ export class Api extends HttpClient { * @name GitRefsDetail * @request GET:/repos/{owner}/{repo}/git/refs */ - gitRefsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs`, "GET", params), + gitRefsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Reference @@ -2527,8 +3072,15 @@ export class Api extends HttpClient { * @name GitRefsCreate * @request POST:/repos/{owner}/{repo}/git/refs */ - gitRefsCreate: (owner: string, repo: string, body: RefsBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs`, "POST", params, body, BodyType.Json), + gitRefsCreate: (owner: string, repo: string, body: RefsBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Delete a Reference Example: Deleting a branch: DELETE /repos/octocat/Hello-World/git/refs/heads/feature-a Example: Deleting a tag: DELETE /repos/octocat/Hello-World/git/refs/tags/v1.0 @@ -2536,8 +3088,12 @@ export class Api extends HttpClient { * @name GitRefsDelete * @request DELETE:/repos/{owner}/{repo}/git/refs/{ref} */ - gitRefsDelete: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "DELETE", params), + gitRefsDelete: (owner: string, repo: string, ref: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs/${ref}`, + method: "DELETE", + ...params, + }), /** * @description Get a Reference @@ -2547,8 +3103,13 @@ export class Api extends HttpClient { * @originalName gitRefsDetail * @duplicate */ - gitRefsDetail2: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "GET", params), + gitRefsDetail2: (owner: string, repo: string, ref: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs/${ref}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a Reference @@ -2556,8 +3117,15 @@ export class Api extends HttpClient { * @name GitRefsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/git/refs/{ref} */ - gitRefsPartialUpdate: (owner: string, repo: string, ref: string, body: GitRefPatch, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "PATCH", params, body, BodyType.Json), + gitRefsPartialUpdate: (owner: string, repo: string, ref: string, body: GitRefPatch, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs/${ref}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Create a Tag Object. Note that creating a tag object does not create the reference that makes a tag in Git. If you want to create an annotated tag in Git, you have to do this call to create the tag object, and then create the refs/tags/[tag] reference. If you want to create a lightweight tag, you only have to create the tag reference - this call would be unnecessary. @@ -2565,8 +3133,15 @@ export class Api extends HttpClient { * @name GitTagsCreate * @request POST:/repos/{owner}/{repo}/git/tags */ - gitTagsCreate: (owner: string, repo: string, body: TagBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/tags`, "POST", params, body, BodyType.Json), + gitTagsCreate: (owner: string, repo: string, body: TagBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/tags`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Tag. @@ -2574,8 +3149,13 @@ export class Api extends HttpClient { * @name GitTagsDetail * @request GET:/repos/{owner}/{repo}/git/tags/{shaCode} */ - gitTagsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/tags/${shaCode}`, "GET", params), + gitTagsDetail: (owner: string, repo: string, shaCode: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/tags/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Tree. The tree creation API will take nested entries as well. If both a tree and a nested path modifying that tree are specified, it will overwrite the contents of that tree with the new path contents and write a new tree out. @@ -2583,8 +3163,15 @@ export class Api extends HttpClient { * @name GitTreesCreate * @request POST:/repos/{owner}/{repo}/git/trees */ - gitTreesCreate: (owner: string, repo: string, body: Tree, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/trees`, "POST", params, body, BodyType.Json), + gitTreesCreate: (owner: string, repo: string, body: Tree, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/trees`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Tree. @@ -2597,13 +3184,15 @@ export class Api extends HttpClient { repo: string, shaCode: string, query?: { recursive?: number }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/repos/${owner}/${repo}/git/trees/${shaCode}${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/repos/${owner}/${repo}/git/trees/${shaCode}`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Get list of hooks. @@ -2611,8 +3200,13 @@ export class Api extends HttpClient { * @name HooksDetail * @request GET:/repos/{owner}/{repo}/hooks */ - hooksDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks`, "GET", params), + hooksDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a hook. @@ -2620,8 +3214,14 @@ export class Api extends HttpClient { * @name HooksCreate * @request POST:/repos/{owner}/{repo}/hooks */ - hooksCreate: (owner: string, repo: string, body: HookBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks`, "POST", params, body), + hooksCreate: (owner: string, repo: string, body: HookBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a hook. @@ -2629,8 +3229,12 @@ export class Api extends HttpClient { * @name HooksDelete * @request DELETE:/repos/{owner}/{repo}/hooks/{hookId} */ - hooksDelete: (owner: string, repo: string, hookId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "DELETE", params), + hooksDelete: (owner: string, repo: string, hookId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}`, + method: "DELETE", + ...params, + }), /** * @description Get single hook. @@ -2640,8 +3244,13 @@ export class Api extends HttpClient { * @originalName hooksDetail * @duplicate */ - hooksDetail2: (owner: string, repo: string, hookId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "GET", params), + hooksDetail2: (owner: string, repo: string, hookId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a hook. @@ -2649,8 +3258,14 @@ export class Api extends HttpClient { * @name HooksPartialUpdate * @request PATCH:/repos/{owner}/{repo}/hooks/{hookId} */ - hooksPartialUpdate: (owner: string, repo: string, hookId: number, body: HookBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "PATCH", params, body), + hooksPartialUpdate: (owner: string, repo: string, hookId: number, body: HookBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description Test a push hook. This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook is not subscribed to push events, the server will respond with 204 but no test POST will be generated. Note: Previously /repos/:owner/:repo/hooks/:id/tes @@ -2658,8 +3273,12 @@ export class Api extends HttpClient { * @name HooksTestsCreate * @request POST:/repos/{owner}/{repo}/hooks/{hookId}/tests */ - hooksTestsCreate: (owner: string, repo: string, hookId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}/tests`, "POST", params), + hooksTestsCreate: (owner: string, repo: string, hookId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}/tests`, + method: "POST", + ...params, + }), /** * @description List issues for a repository. @@ -2678,8 +3297,15 @@ export class Api extends HttpClient { direction: "asc" | "desc"; since?: string; }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/issues${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create an issue. Any user with pull access to a repository can create an issue. @@ -2687,8 +3313,14 @@ export class Api extends HttpClient { * @name IssuesCreate * @request POST:/repos/{owner}/{repo}/issues */ - issuesCreate: (owner: string, repo: string, body: Issue, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues`, "POST", params, body), + issuesCreate: (owner: string, repo: string, body: Issue, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List comments in a repository. @@ -2700,13 +3332,15 @@ export class Api extends HttpClient { owner: string, repo: string, query?: { direction?: string; sort?: "created" | "updated"; since?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/repos/${owner}/${repo}/issues/comments${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/repos/${owner}/${repo}/issues/comments`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Delete a comment. @@ -2714,8 +3348,12 @@ export class Api extends HttpClient { * @name IssuesCommentsDelete * @request DELETE:/repos/{owner}/{repo}/issues/comments/{commentId} */ - issuesCommentsDelete: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "DELETE", params), + issuesCommentsDelete: (owner: string, repo: string, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single comment. @@ -2725,8 +3363,13 @@ export class Api extends HttpClient { * @originalName issuesCommentsDetail * @duplicate */ - issuesCommentsDetail2: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "GET", params), + issuesCommentsDetail2: (owner: string, repo: string, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a comment. @@ -2739,9 +3382,15 @@ export class Api extends HttpClient { repo: string, commentId: number, body: CommentBody, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "PATCH", params, body), + this.request({ + path: `/repos/${owner}/${repo}/issues/comments/${commentId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List issue events for a repository. @@ -2749,8 +3398,13 @@ export class Api extends HttpClient { * @name IssuesEventsDetail * @request GET:/repos/{owner}/{repo}/issues/events */ - issuesEventsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/events`, "GET", params), + issuesEventsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single event. @@ -2760,8 +3414,13 @@ export class Api extends HttpClient { * @originalName issuesEventsDetail * @duplicate */ - issuesEventsDetail2: (owner: string, repo: string, eventId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/events/${eventId}`, "GET", params), + issuesEventsDetail2: (owner: string, repo: string, eventId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/events/${eventId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single issue @@ -2771,8 +3430,13 @@ export class Api extends HttpClient { * @originalName issuesDetail * @duplicate */ - issuesDetail2: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}`, "GET", params), + issuesDetail2: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit an issue. Issue owners and users with push access can edit an issue. @@ -2780,8 +3444,14 @@ export class Api extends HttpClient { * @name IssuesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/issues/{number} */ - issuesPartialUpdate: (owner: string, repo: string, number: number, body: Issue, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}`, "PATCH", params, body), + issuesPartialUpdate: (owner: string, repo: string, number: number, body: Issue, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List comments on an issue. @@ -2791,8 +3461,13 @@ export class Api extends HttpClient { * @originalName issuesCommentsDetail * @duplicate */ - issuesCommentsDetail3: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/comments`, "GET", params), + issuesCommentsDetail3: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a comment. @@ -2800,8 +3475,20 @@ export class Api extends HttpClient { * @name IssuesCommentsCreate * @request POST:/repos/{owner}/{repo}/issues/{number}/comments */ - issuesCommentsCreate: (owner: string, repo: string, number: number, body: CommentBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/comments`, "POST", params, body), + issuesCommentsCreate: ( + owner: string, + repo: string, + number: number, + body: CommentBody, + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/comments`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List events for an issue. @@ -2811,8 +3498,13 @@ export class Api extends HttpClient { * @originalName issuesEventsDetail * @duplicate */ - issuesEventsDetail3: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/events`, "GET", params), + issuesEventsDetail3: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description Remove all labels from an issue. @@ -2820,8 +3512,12 @@ export class Api extends HttpClient { * @name IssuesLabelsDelete * @request DELETE:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsDelete: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "DELETE", params), + issuesLabelsDelete: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "DELETE", + ...params, + }), /** * @description List labels on an issue. @@ -2829,8 +3525,13 @@ export class Api extends HttpClient { * @name IssuesLabelsDetail * @request GET:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "GET", params), + issuesLabelsDetail: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "GET", + format: "json", + ...params, + }), /** * @description Add labels to an issue. @@ -2838,8 +3539,14 @@ export class Api extends HttpClient { * @name IssuesLabelsCreate * @request POST:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsCreate: (owner: string, repo: string, number: number, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "POST", params, body), + issuesLabelsCreate: (owner: string, repo: string, number: number, body: EmailsPost, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Replace all labels for an issue. Sending an empty array ([]) will remove all Labels from the Issue. @@ -2847,8 +3554,14 @@ export class Api extends HttpClient { * @name IssuesLabelsUpdate * @request PUT:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsUpdate: (owner: string, repo: string, number: number, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "PUT", params, body), + issuesLabelsUpdate: (owner: string, repo: string, number: number, body: EmailsPost, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "PUT", + body: body, + format: "json", + ...params, + }), /** * @description Remove a label from an issue. @@ -2858,8 +3571,12 @@ export class Api extends HttpClient { * @originalName issuesLabelsDelete * @duplicate */ - issuesLabelsDelete2: (owner: string, repo: string, number: number, name: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels/${name}`, "DELETE", params), + issuesLabelsDelete2: (owner: string, repo: string, number: number, name: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels/${name}`, + method: "DELETE", + ...params, + }), /** * @description Get list of keys. @@ -2867,8 +3584,13 @@ export class Api extends HttpClient { * @name KeysDetail * @request GET:/repos/{owner}/{repo}/keys */ - keysDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys`, "GET", params), + keysDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a key. @@ -2876,8 +3598,14 @@ export class Api extends HttpClient { * @name KeysCreate * @request POST:/repos/{owner}/{repo}/keys */ - keysCreate: (owner: string, repo: string, body: UserKeysPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys`, "POST", params, body), + keysCreate: (owner: string, repo: string, body: UserKeysPost, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a key. @@ -2885,8 +3613,12 @@ export class Api extends HttpClient { * @name KeysDelete * @request DELETE:/repos/{owner}/{repo}/keys/{keyId} */ - keysDelete: (owner: string, repo: string, keyId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys/${keyId}`, "DELETE", params), + keysDelete: (owner: string, repo: string, keyId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys/${keyId}`, + method: "DELETE", + ...params, + }), /** * @description Get a key @@ -2896,8 +3628,13 @@ export class Api extends HttpClient { * @originalName keysDetail * @duplicate */ - keysDetail2: (owner: string, repo: string, keyId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys/${keyId}`, "GET", params), + keysDetail2: (owner: string, repo: string, keyId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys/${keyId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List all labels for this repository. @@ -2905,8 +3642,13 @@ export class Api extends HttpClient { * @name LabelsDetail * @request GET:/repos/{owner}/{repo}/labels */ - labelsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels`, "GET", params), + labelsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a label. @@ -2914,8 +3656,14 @@ export class Api extends HttpClient { * @name LabelsCreate * @request POST:/repos/{owner}/{repo}/labels */ - labelsCreate: (owner: string, repo: string, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels`, "POST", params, body), + labelsCreate: (owner: string, repo: string, body: EmailsPost, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a label. @@ -2923,8 +3671,12 @@ export class Api extends HttpClient { * @name LabelsDelete * @request DELETE:/repos/{owner}/{repo}/labels/{name} */ - labelsDelete: (owner: string, repo: string, name: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "DELETE", params), + labelsDelete: (owner: string, repo: string, name: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels/${name}`, + method: "DELETE", + ...params, + }), /** * @description Get a single label. @@ -2934,8 +3686,13 @@ export class Api extends HttpClient { * @originalName labelsDetail * @duplicate */ - labelsDetail2: (owner: string, repo: string, name: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "GET", params), + labelsDetail2: (owner: string, repo: string, name: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels/${name}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a label. @@ -2943,8 +3700,14 @@ export class Api extends HttpClient { * @name LabelsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/labels/{name} */ - labelsPartialUpdate: (owner: string, repo: string, name: string, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "PATCH", params, body), + labelsPartialUpdate: (owner: string, repo: string, name: string, body: EmailsPost, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels/${name}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List languages. List languages for the specified repository. The value on the right of a language is the number of bytes of code written in that language. @@ -2952,8 +3715,13 @@ export class Api extends HttpClient { * @name LanguagesDetail * @request GET:/repos/{owner}/{repo}/languages */ - languagesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/languages`, "GET", params), + languagesDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/languages`, + method: "GET", + format: "json", + ...params, + }), /** * @description Perform a merge. @@ -2961,14 +3729,15 @@ export class Api extends HttpClient { * @name MergesCreate * @request POST:/repos/{owner}/{repo}/merges */ - mergesCreate: (owner: string, repo: string, body: MergesBody, params?: RequestParams) => - this.request( - `/repos/${owner}/${repo}/merges`, - "POST", - params, - body, - BodyType.Json, - ), + mergesCreate: (owner: string, repo: string, body: MergesBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/merges`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List milestones for a repository. @@ -2980,8 +3749,15 @@ export class Api extends HttpClient { owner: string, repo: string, query?: { state?: "open" | "closed"; direction?: string; sort?: "due_date" | "completeness" }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/milestones${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/milestones`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a milestone. @@ -2989,8 +3765,14 @@ export class Api extends HttpClient { * @name MilestonesCreate * @request POST:/repos/{owner}/{repo}/milestones */ - milestonesCreate: (owner: string, repo: string, body: MilestoneUpdate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones`, "POST", params, body), + milestonesCreate: (owner: string, repo: string, body: MilestoneUpdate, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a milestone. @@ -2998,8 +3780,12 @@ export class Api extends HttpClient { * @name MilestonesDelete * @request DELETE:/repos/{owner}/{repo}/milestones/{number} */ - milestonesDelete: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones/${number}`, "DELETE", params), + milestonesDelete: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}`, + method: "DELETE", + ...params, + }), /** * @description Get a single milestone. @@ -3009,8 +3795,13 @@ export class Api extends HttpClient { * @originalName milestonesDetail * @duplicate */ - milestonesDetail2: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones/${number}`, "GET", params), + milestonesDetail2: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a milestone. @@ -3023,8 +3814,15 @@ export class Api extends HttpClient { repo: string, number: number, body: MilestoneUpdate, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/milestones/${number}`, "PATCH", params, body), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description Get labels for every issue in a milestone. @@ -3032,8 +3830,13 @@ export class Api extends HttpClient { * @name MilestonesLabelsDetail * @request GET:/repos/{owner}/{repo}/milestones/{number}/labels */ - milestonesLabelsDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones/${number}/labels`, "GET", params), + milestonesLabelsDetail: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}/labels`, + method: "GET", + format: "json", + ...params, + }), /** * @description List your notifications in a repository List all notifications for the current user. @@ -3045,13 +3848,15 @@ export class Api extends HttpClient { owner: string, repo: string, query?: { all?: boolean; participating?: boolean; since?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/repos/${owner}/${repo}/notifications${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/repos/${owner}/${repo}/notifications`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Mark notifications as read in a repository. Marking all notifications in a repository as "read" removes them from the default view on GitHub.com. @@ -3059,8 +3864,13 @@ export class Api extends HttpClient { * @name NotificationsUpdate * @request PUT:/repos/{owner}/{repo}/notifications */ - notificationsUpdate: (owner: string, repo: string, body: NotificationMarkRead, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/notifications`, "PUT", params, body), + notificationsUpdate: (owner: string, repo: string, body: NotificationMarkRead, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/notifications`, + method: "PUT", + body: body, + ...params, + }), /** * @description List pull requests. @@ -3072,8 +3882,15 @@ export class Api extends HttpClient { owner: string, repo: string, query?: { state?: "open" | "closed"; head?: string; base?: string }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/pulls${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/pulls`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a pull request. @@ -3081,8 +3898,15 @@ export class Api extends HttpClient { * @name PullsCreate * @request POST:/repos/{owner}/{repo}/pulls */ - pullsCreate: (owner: string, repo: string, body: PullsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls`, "POST", params, body, BodyType.Json), + pullsCreate: (owner: string, repo: string, body: PullsPost, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List comments in a repository. By default, Review Comments are ordered by ascending ID. @@ -3094,13 +3918,15 @@ export class Api extends HttpClient { owner: string, repo: string, query?: { direction?: string; sort?: "created" | "updated"; since?: string }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/repos/${owner}/${repo}/pulls/comments${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Delete a comment. @@ -3108,8 +3934,12 @@ export class Api extends HttpClient { * @name PullsCommentsDelete * @request DELETE:/repos/{owner}/{repo}/pulls/comments/{commentId} */ - pullsCommentsDelete: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "DELETE", params), + pullsCommentsDelete: (owner: string, repo: string, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single comment. @@ -3119,8 +3949,13 @@ export class Api extends HttpClient { * @originalName pullsCommentsDetail * @duplicate */ - pullsCommentsDetail2: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "GET", params), + pullsCommentsDetail2: (owner: string, repo: string, commentId: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a comment. @@ -3133,8 +3968,15 @@ export class Api extends HttpClient { repo: string, commentId: number, body: CommentBody, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "PATCH", params, body), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments/${commentId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description Get a single pull request. @@ -3144,8 +3986,13 @@ export class Api extends HttpClient { * @originalName pullsDetail * @duplicate */ - pullsDetail2: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}`, "GET", params), + pullsDetail2: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a pull request. @@ -3153,8 +4000,15 @@ export class Api extends HttpClient { * @name PullsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/pulls/{number} */ - pullsPartialUpdate: (owner: string, repo: string, number: number, body: PullUpdate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}`, "PATCH", params, body, BodyType.Json), + pullsPartialUpdate: (owner: string, repo: string, number: number, body: PullUpdate, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List comments on a pull request. @@ -3164,8 +4018,13 @@ export class Api extends HttpClient { * @originalName pullsCommentsDetail * @duplicate */ - pullsCommentsDetail3: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/comments`, "GET", params), + pullsCommentsDetail3: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a comment. #TODO Alternative input ( http://developer.github.com/v3/pulls/comments/ ) description: | Alternative Input. Instead of passing commit_id, path, and position you can reply to an existing Pull Request Comment like this: body Required string in_reply_to Required number - Comment id to reply to. @@ -3178,15 +4037,16 @@ export class Api extends HttpClient { repo: string, number: number, body: PullsCommentPost, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/repos/${owner}/${repo}/pulls/${number}/comments`, - "POST", - params, - body, - BodyType.Json, - ), + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/comments`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List commits on a pull request. @@ -3194,8 +4054,13 @@ export class Api extends HttpClient { * @name PullsCommitsDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/commits */ - pullsCommitsDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/commits`, "GET", params), + pullsCommitsDetail: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/commits`, + method: "GET", + format: "json", + ...params, + }), /** * @description List pull requests files. @@ -3203,8 +4068,13 @@ export class Api extends HttpClient { * @name PullsFilesDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/files */ - pullsFilesDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/files`, "GET", params), + pullsFilesDetail: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/files`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get if a pull request has been merged. @@ -3212,8 +4082,12 @@ export class Api extends HttpClient { * @name PullsMergeDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/merge */ - pullsMergeDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/merge`, "GET", params), + pullsMergeDetail: (owner: string, repo: string, number: number, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/merge`, + method: "GET", + ...params, + }), /** * @description Merge a pull request (Merge Button's) @@ -3221,8 +4095,15 @@ export class Api extends HttpClient { * @name PullsMergeUpdate * @request PUT:/repos/{owner}/{repo}/pulls/{number}/merge */ - pullsMergeUpdate: (owner: string, repo: string, number: number, body: MergePullBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/merge`, "PUT", params, body, BodyType.Json), + pullsMergeUpdate: (owner: string, repo: string, number: number, body: MergePullBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/merge`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get the README. This method returns the preferred README for a repository. @@ -3230,8 +4111,14 @@ export class Api extends HttpClient { * @name ReadmeDetail * @request GET:/repos/{owner}/{repo}/readme */ - readmeDetail: (owner: string, repo: string, query?: { ref?: string }, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/readme${this.addQueryParams(query)}`, "GET", params), + readmeDetail: (owner: string, repo: string, query?: { ref?: string }, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/readme`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Users with push access to the repository will receive all releases (i.e., published releases and draft releases). Users with pull access will receive published releases only @@ -3239,8 +4126,13 @@ export class Api extends HttpClient { * @name ReleasesDetail * @request GET:/repos/{owner}/{repo}/releases */ - releasesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases`, "GET", params), + releasesDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a release Users with push access to the repository can create a release. @@ -3248,8 +4140,14 @@ export class Api extends HttpClient { * @name ReleasesCreate * @request POST:/repos/{owner}/{repo}/releases */ - releasesCreate: (owner: string, repo: string, body: ReleaseCreate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases`, "POST", params, body), + releasesCreate: (owner: string, repo: string, body: ReleaseCreate, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a release asset @@ -3257,8 +4155,12 @@ export class Api extends HttpClient { * @name ReleasesAssetsDelete * @request DELETE:/repos/{owner}/{repo}/releases/assets/{id} */ - releasesAssetsDelete: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "DELETE", params), + releasesAssetsDelete: (owner: string, repo: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/assets/${id}`, + method: "DELETE", + ...params, + }), /** * @description Get a single release asset @@ -3266,8 +4168,13 @@ export class Api extends HttpClient { * @name ReleasesAssetsDetail * @request GET:/repos/{owner}/{repo}/releases/assets/{id} */ - releasesAssetsDetail: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "GET", params), + releasesAssetsDetail: (owner: string, repo: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/assets/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a release asset Users with push access to the repository can edit a release asset. @@ -3275,8 +4182,21 @@ export class Api extends HttpClient { * @name ReleasesAssetsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/releases/assets/{id} */ - releasesAssetsPartialUpdate: (owner: string, repo: string, id: string, body: AssetPatch, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "PATCH", params, body, BodyType.Json), + releasesAssetsPartialUpdate: ( + owner: string, + repo: string, + id: string, + body: AssetPatch, + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/releases/assets/${id}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Users with push access to the repository can delete a release. @@ -3284,8 +4204,12 @@ export class Api extends HttpClient { * @name ReleasesDelete * @request DELETE:/repos/{owner}/{repo}/releases/{id} */ - releasesDelete: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "DELETE", params), + releasesDelete: (owner: string, repo: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}`, + method: "DELETE", + ...params, + }), /** * @description Get a single release @@ -3295,8 +4219,13 @@ export class Api extends HttpClient { * @originalName releasesDetail * @duplicate */ - releasesDetail2: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "GET", params), + releasesDetail2: (owner: string, repo: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Users with push access to the repository can edit a release @@ -3304,8 +4233,14 @@ export class Api extends HttpClient { * @name ReleasesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/releases/{id} */ - releasesPartialUpdate: (owner: string, repo: string, id: string, body: ReleaseCreate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "PATCH", params, body), + releasesPartialUpdate: (owner: string, repo: string, id: string, body: ReleaseCreate, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List assets for a release @@ -3315,8 +4250,13 @@ export class Api extends HttpClient { * @originalName releasesAssetsDetail * @duplicate */ - releasesAssetsDetail2: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}/assets`, "GET", params), + releasesAssetsDetail2: (owner: string, repo: string, id: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}/assets`, + method: "GET", + format: "json", + ...params, + }), /** * @description List Stargazers. @@ -3324,8 +4264,13 @@ export class Api extends HttpClient { * @name StargazersDetail * @request GET:/repos/{owner}/{repo}/stargazers */ - stargazersDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stargazers`, "GET", params), + stargazersDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stargazers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the number of additions and deletions per week. Returns a weekly aggregate of the number of additions and deletions pushed to a repository. @@ -3333,8 +4278,13 @@ export class Api extends HttpClient { * @name StatsCodeFrequencyDetail * @request GET:/repos/{owner}/{repo}/stats/code_frequency */ - statsCodeFrequencyDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/code_frequency`, "GET", params), + statsCodeFrequencyDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/code_frequency`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the last year of commit activity data. Returns the last year of commit activity grouped by week. The days array is a group of commits per day, starting on Sunday. @@ -3342,8 +4292,13 @@ export class Api extends HttpClient { * @name StatsCommitActivityDetail * @request GET:/repos/{owner}/{repo}/stats/commit_activity */ - statsCommitActivityDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/commit_activity`, "GET", params), + statsCommitActivityDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/commit_activity`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get contributors list with additions, deletions, and commit counts. @@ -3351,8 +4306,13 @@ export class Api extends HttpClient { * @name StatsContributorsDetail * @request GET:/repos/{owner}/{repo}/stats/contributors */ - statsContributorsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/contributors`, "GET", params), + statsContributorsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/contributors`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the weekly commit count for the repo owner and everyone else. @@ -3360,8 +4320,13 @@ export class Api extends HttpClient { * @name StatsParticipationDetail * @request GET:/repos/{owner}/{repo}/stats/participation */ - statsParticipationDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/participation`, "GET", params), + statsParticipationDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/participation`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the number of commits per hour in each day. Each array contains the day number, hour number, and number of commits 0-6 Sunday - Saturday 0-23 Hour of day Number of commits For example, [2, 14, 25] indicates that there were 25 total commits, during the 2.00pm hour on Tuesdays. All times are based on the time zone of individual commits. @@ -3369,8 +4334,13 @@ export class Api extends HttpClient { * @name StatsPunchCardDetail * @request GET:/repos/{owner}/{repo}/stats/punch_card */ - statsPunchCardDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/punch_card`, "GET", params), + statsPunchCardDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/punch_card`, + method: "GET", + format: "json", + ...params, + }), /** * @description List Statuses for a specific Ref. @@ -3378,8 +4348,13 @@ export class Api extends HttpClient { * @name StatusesDetail * @request GET:/repos/{owner}/{repo}/statuses/{ref} */ - statusesDetail: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/statuses/${ref}`, "GET", params), + statusesDetail: (owner: string, repo: string, ref: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/statuses/${ref}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Status. @@ -3387,8 +4362,15 @@ export class Api extends HttpClient { * @name StatusesCreate * @request POST:/repos/{owner}/{repo}/statuses/{ref} */ - statusesCreate: (owner: string, repo: string, ref: string, body: HeadBranch, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/statuses/${ref}`, "POST", params, body, BodyType.Json), + statusesCreate: (owner: string, repo: string, ref: string, body: HeadBranch, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/statuses/${ref}`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List watchers. @@ -3396,8 +4378,13 @@ export class Api extends HttpClient { * @name SubscribersDetail * @request GET:/repos/{owner}/{repo}/subscribers */ - subscribersDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscribers`, "GET", params), + subscribersDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscribers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Delete a Repository Subscription. @@ -3405,8 +4392,12 @@ export class Api extends HttpClient { * @name SubscriptionDelete * @request DELETE:/repos/{owner}/{repo}/subscription */ - subscriptionDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscription`, "DELETE", params), + subscriptionDelete: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscription`, + method: "DELETE", + ...params, + }), /** * @description Get a Repository Subscription. @@ -3414,8 +4405,13 @@ export class Api extends HttpClient { * @name SubscriptionDetail * @request GET:/repos/{owner}/{repo}/subscription */ - subscriptionDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscription`, "GET", params), + subscriptionDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscription`, + method: "GET", + format: "json", + ...params, + }), /** * @description Set a Repository Subscription @@ -3423,8 +4419,15 @@ export class Api extends HttpClient { * @name SubscriptionUpdate * @request PUT:/repos/{owner}/{repo}/subscription */ - subscriptionUpdate: (owner: string, repo: string, body: SubscriptionBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscription`, "PUT", params, body, BodyType.Json), + subscriptionUpdate: (owner: string, repo: string, body: SubscriptionBody, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscription`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get list of tags. @@ -3432,8 +4435,13 @@ export class Api extends HttpClient { * @name TagsDetail * @request GET:/repos/{owner}/{repo}/tags */ - tagsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/tags`, "GET", params), + tagsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/tags`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get list of teams @@ -3441,8 +4449,13 @@ export class Api extends HttpClient { * @name TeamsDetail * @request GET:/repos/{owner}/{repo}/teams */ - teamsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/teams`, "GET", params), + teamsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/teams`, + method: "GET", + format: "json", + ...params, + }), /** * @description List Stargazers. New implementation. @@ -3450,8 +4463,13 @@ export class Api extends HttpClient { * @name WatchersDetail * @request GET:/repos/{owner}/{repo}/watchers */ - watchersDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/watchers`, "GET", params), + watchersDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/repos/${owner}/${repo}/watchers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get archive link. This method will return a 302 to a URL to download a tarball or zipball archive for a repository. Please make sure your HTTP framework is configured to follow redirects or you will need to use the Location header to make a second GET request. Note: For private repositories, these links are temporary and expire quickly. @@ -3466,8 +4484,13 @@ export class Api extends HttpClient { repo: string, archive_format: "tarball" | "zipball", path: string, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/${archive_format}/${path}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/repos/${owner}/${repo}/${archive_format}/${path}`, + method: "GET", + ...params, + }), }; repositories = { /** @@ -3476,8 +4499,14 @@ export class Api extends HttpClient { * @name RepositoriesList * @request GET:/repositories */ - repositoriesList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/repositories${this.addQueryParams(query)}`, "GET", params), + repositoriesList: (query?: { since?: string }, params: RequestParams = {}) => + this.request({ + path: `/repositories`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; search = { /** @@ -3486,8 +4515,14 @@ export class Api extends HttpClient { * @name CodeList * @request GET:/search/code */ - codeList: (query: { order?: "desc" | "asc"; q: string; sort?: "indexed" }, params?: RequestParams) => - this.request(`/search/code${this.addQueryParams(query)}`, "GET", params), + codeList: (query: { order?: "desc" | "asc"; q: string; sort?: "indexed" }, params: RequestParams = {}) => + this.request({ + path: `/search/code`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Find issues by state and keyword. (This method returns up to 100 results per page.) @@ -3497,8 +4532,15 @@ export class Api extends HttpClient { */ issuesList: ( query: { order?: "desc" | "asc"; q: string; sort?: "updated" | "created" | "comments" }, - params?: RequestParams, - ) => this.request(`/search/issues${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/search/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Search repositories. @@ -3508,8 +4550,15 @@ export class Api extends HttpClient { */ repositoriesList: ( query: { order?: "desc" | "asc"; q: string; sort?: "stars" | "forks" | "updated" }, - params?: RequestParams, - ) => this.request(`/search/repositories${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/search/repositories`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Search users. @@ -3519,8 +4568,15 @@ export class Api extends HttpClient { */ usersList: ( query: { order?: "desc" | "asc"; q: string; sort?: "followers" | "repositories" | "joined" }, - params?: RequestParams, - ) => this.request(`/search/users${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/search/users`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; teams = { /** @@ -3529,8 +4585,12 @@ export class Api extends HttpClient { * @name TeamsDelete * @request DELETE:/teams/{teamId} */ - teamsDelete: (teamId: number, params?: RequestParams) => - this.request(`/teams/${teamId}`, "DELETE", params), + teamsDelete: (teamId: number, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}`, + method: "DELETE", + ...params, + }), /** * @description Get team. @@ -3538,7 +4598,13 @@ export class Api extends HttpClient { * @name TeamsDetail * @request GET:/teams/{teamId} */ - teamsDetail: (teamId: number, params?: RequestParams) => this.request(`/teams/${teamId}`, "GET", params), + teamsDetail: (teamId: number, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit team. In order to edit a team, the authenticated user must be an owner of the org that the team is associated with. @@ -3546,8 +4612,15 @@ export class Api extends HttpClient { * @name TeamsPartialUpdate * @request PATCH:/teams/{teamId} */ - teamsPartialUpdate: (teamId: number, body: EditTeam, params?: RequestParams) => - this.request(`/teams/${teamId}`, "PATCH", params, body, BodyType.Json), + teamsPartialUpdate: (teamId: number, body: EditTeam, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List team members. In order to list members in a team, the authenticated user must be a member of the team. @@ -3555,8 +4628,13 @@ export class Api extends HttpClient { * @name MembersDetail * @request GET:/teams/{teamId}/members */ - membersDetail: (teamId: number, params?: RequestParams) => - this.request(`/teams/${teamId}/members`, "GET", params), + membersDetail: (teamId: number, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/members`, + method: "GET", + format: "json", + ...params, + }), /** * @description The "Remove team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Remove team membership API instead. It allows you to remove both active and pending memberships. Remove team member. In order to remove a user from a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. NOTE This does not delete the user, it just remove them from the team. @@ -3564,8 +4642,12 @@ export class Api extends HttpClient { * @name MembersDelete * @request DELETE:/teams/{teamId}/members/{username} */ - membersDelete: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/members/${username}`, "DELETE", params), + membersDelete: (teamId: number, username: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/members/${username}`, + method: "DELETE", + ...params, + }), /** * @description The "Get team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Get team membership API instead. It allows you to get both active and pending memberships. Get team member. In order to get if a user is a member of a team, the authenticated user mus be a member of the team. @@ -3575,8 +4657,12 @@ export class Api extends HttpClient { * @originalName membersDetail * @duplicate */ - membersDetail2: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/members/${username}`, "GET", params), + membersDetail2: (teamId: number, username: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/members/${username}`, + method: "GET", + ...params, + }), /** * @description The API (described below) is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Add team membership API instead. It allows you to invite new organization members to your teams. Add team member. In order to add a user to a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. @@ -3584,8 +4670,12 @@ export class Api extends HttpClient { * @name MembersUpdate * @request PUT:/teams/{teamId}/members/{username} */ - membersUpdate: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/members/${username}`, "PUT", params), + membersUpdate: (teamId: number, username: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/members/${username}`, + method: "PUT", + ...params, + }), /** * @description Remove team membership. In order to remove a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. NOTE: This does not delete the user, it just removes their membership from the team. @@ -3593,8 +4683,12 @@ export class Api extends HttpClient { * @name MembershipsDelete * @request DELETE:/teams/{teamId}/memberships/{username} */ - membershipsDelete: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/memberships/${username}`, "DELETE", params), + membershipsDelete: (teamId: number, username: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/memberships/${username}`, + method: "DELETE", + ...params, + }), /** * @description Get team membership. In order to get a user's membership with a team, the authenticated user must be a member of the team or an owner of the team's organization. @@ -3602,8 +4696,13 @@ export class Api extends HttpClient { * @name MembershipsDetail * @request GET:/teams/{teamId}/memberships/{username} */ - membershipsDetail: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/memberships/${username}`, "GET", params), + membershipsDetail: (teamId: number, username: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/memberships/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Add team membership. In order to add a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. If the user is already a part of the team's organization (meaning they're on at least one other team in the organization), this endpoint will add the user to the team. If the user is completely unaffiliated with the team's organization (meaning they're on none of the organization's teams), this endpoint will send an invitation to the user via email. This newly-created membership will be in the 'pending' state until the user accepts the invitation, at which point the membership will transition to the 'active' state and the user will be added as a member of the team. @@ -3611,8 +4710,13 @@ export class Api extends HttpClient { * @name MembershipsUpdate * @request PUT:/teams/{teamId}/memberships/{username} */ - membershipsUpdate: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/memberships/${username}`, "PUT", params), + membershipsUpdate: (teamId: number, username: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/memberships/${username}`, + method: "PUT", + format: "json", + ...params, + }), /** * @description List team repos @@ -3620,8 +4724,13 @@ export class Api extends HttpClient { * @name ReposDetail * @request GET:/teams/{teamId}/repos */ - reposDetail: (teamId: number, params?: RequestParams) => - this.request(`/teams/${teamId}/repos`, "GET", params), + reposDetail: (teamId: number, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/repos`, + method: "GET", + format: "json", + ...params, + }), /** * @description In order to remove a repository from a team, the authenticated user must be an owner of the org that the team is associated with. NOTE: This does not delete the repository, it just removes it from the team. @@ -3629,8 +4738,12 @@ export class Api extends HttpClient { * @name ReposDelete * @request DELETE:/teams/{teamId}/repos/{owner}/{repo} */ - reposDelete: (teamId: number, owner: string, repo: string, params?: RequestParams) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "DELETE", params), + reposDelete: (teamId: number, owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/repos/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Check if a team manages a repository @@ -3640,8 +4753,12 @@ export class Api extends HttpClient { * @originalName reposDetail * @duplicate */ - reposDetail2: (teamId: number, owner: string, repo: string, params?: RequestParams) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "GET", params), + reposDetail2: (teamId: number, owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/repos/${owner}/${repo}`, + method: "GET", + ...params, + }), /** * @description In order to add a repository to a team, the authenticated user must be an owner of the org that the team is associated with. Also, the repository must be owned by the organization, or a direct fork of a repository owned by the organization. @@ -3649,8 +4766,12 @@ export class Api extends HttpClient { * @name ReposUpdate * @request PUT:/teams/{teamId}/repos/{owner}/{repo} */ - reposUpdate: (teamId: number, owner: string, repo: string, params?: RequestParams) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "PUT", params), + reposUpdate: (teamId: number, owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/teams/${teamId}/repos/${owner}/${repo}`, + method: "PUT", + ...params, + }), }; user = { /** @@ -3659,7 +4780,13 @@ export class Api extends HttpClient { * @name UserList * @request GET:/user */ - userList: (params?: RequestParams) => this.request(`/user`, "GET", params), + userList: (params: RequestParams = {}) => + this.request({ + path: `/user`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update the authenticated user. @@ -3667,8 +4794,15 @@ export class Api extends HttpClient { * @name UserPartialUpdate * @request PATCH:/user */ - userPartialUpdate: (body: UserUpdate, params?: RequestParams) => - this.request(`/user`, "PATCH", params, body, BodyType.Json), + userPartialUpdate: (body: UserUpdate, params: RequestParams = {}) => + this.request({ + path: `/user`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Delete email address(es). You can include a single email address or an array of addresses. @@ -3676,8 +4810,14 @@ export class Api extends HttpClient { * @name EmailsDelete * @request DELETE:/user/emails */ - emailsDelete: (body: UserEmails, params?: RequestParams) => - this.request(`/user/emails`, "DELETE", params, body, BodyType.Json), + emailsDelete: (body: UserEmails, params: RequestParams = {}) => + this.request({ + path: `/user/emails`, + method: "DELETE", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description List email addresses for a user. In the final version of the API, this method will return an array of hashes with extended information for each email address indicating if the address has been verified and if it's primary email address for GitHub. Until API v3 is finalized, use the application/vnd.github.v3 media type to get other response format. @@ -3685,7 +4825,12 @@ export class Api extends HttpClient { * @name EmailsList * @request GET:/user/emails */ - emailsList: (params?: RequestParams) => this.request(`/user/emails`, "GET", params), + emailsList: (params: RequestParams = {}) => + this.request({ + path: `/user/emails`, + method: "GET", + ...params, + }), /** * @description Add email address(es). You can post a single email address or an array of addresses. @@ -3693,8 +4838,13 @@ export class Api extends HttpClient { * @name EmailsCreate * @request POST:/user/emails */ - emailsCreate: (body: EmailsPost, params?: RequestParams) => - this.request(`/user/emails`, "POST", params, body), + emailsCreate: (body: EmailsPost, params: RequestParams = {}) => + this.request({ + path: `/user/emails`, + method: "POST", + body: body, + ...params, + }), /** * @description List the authenticated user's followers @@ -3702,7 +4852,13 @@ export class Api extends HttpClient { * @name FollowersList * @request GET:/user/followers */ - followersList: (params?: RequestParams) => this.request(`/user/followers`, "GET", params), + followersList: (params: RequestParams = {}) => + this.request({ + path: `/user/followers`, + method: "GET", + format: "json", + ...params, + }), /** * @description List who the authenticated user is following. @@ -3710,7 +4866,13 @@ export class Api extends HttpClient { * @name FollowingList * @request GET:/user/following */ - followingList: (params?: RequestParams) => this.request(`/user/following`, "GET", params), + followingList: (params: RequestParams = {}) => + this.request({ + path: `/user/following`, + method: "GET", + format: "json", + ...params, + }), /** * @description Unfollow a user. Unfollowing a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. @@ -3718,8 +4880,12 @@ export class Api extends HttpClient { * @name FollowingDelete * @request DELETE:/user/following/{username} */ - followingDelete: (username: string, params?: RequestParams) => - this.request(`/user/following/${username}`, "DELETE", params), + followingDelete: (username: string, params: RequestParams = {}) => + this.request({ + path: `/user/following/${username}`, + method: "DELETE", + ...params, + }), /** * @description Check if you are following a user. @@ -3727,8 +4893,12 @@ export class Api extends HttpClient { * @name FollowingDetail * @request GET:/user/following/{username} */ - followingDetail: (username: string, params?: RequestParams) => - this.request(`/user/following/${username}`, "GET", params), + followingDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/user/following/${username}`, + method: "GET", + ...params, + }), /** * @description Follow a user. Following a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. @@ -3736,8 +4906,12 @@ export class Api extends HttpClient { * @name FollowingUpdate * @request PUT:/user/following/{username} */ - followingUpdate: (username: string, params?: RequestParams) => - this.request(`/user/following/${username}`, "PUT", params), + followingUpdate: (username: string, params: RequestParams = {}) => + this.request({ + path: `/user/following/${username}`, + method: "PUT", + ...params, + }), /** * @description List issues. List all issues across owned and member repositories for the authenticated user. @@ -3754,8 +4928,15 @@ export class Api extends HttpClient { direction: "asc" | "desc"; since?: string; }, - params?: RequestParams, - ) => this.request(`/user/issues${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/user/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List your public keys. Lists the current user's keys. Management of public keys via the API requires that you are authenticated through basic auth, or OAuth with the 'user', 'write:public_key' scopes. @@ -3763,7 +4944,13 @@ export class Api extends HttpClient { * @name KeysList * @request GET:/user/keys */ - keysList: (params?: RequestParams) => this.request(`/user/keys`, "GET", params), + keysList: (params: RequestParams = {}) => + this.request({ + path: `/user/keys`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a public key. @@ -3771,8 +4958,14 @@ export class Api extends HttpClient { * @name KeysCreate * @request POST:/user/keys */ - keysCreate: (body: UserKeysPost, params?: RequestParams) => - this.request(`/user/keys`, "POST", params, body), + keysCreate: (body: UserKeysPost, params: RequestParams = {}) => + this.request({ + path: `/user/keys`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a public key. Removes a public key. Requires that you are authenticated via Basic Auth or via OAuth with at least admin:public_key scope. @@ -3780,8 +4973,12 @@ export class Api extends HttpClient { * @name KeysDelete * @request DELETE:/user/keys/{keyId} */ - keysDelete: (keyId: number, params?: RequestParams) => - this.request(`/user/keys/${keyId}`, "DELETE", params), + keysDelete: (keyId: number, params: RequestParams = {}) => + this.request({ + path: `/user/keys/${keyId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single public key. @@ -3789,8 +4986,13 @@ export class Api extends HttpClient { * @name KeysDetail * @request GET:/user/keys/{keyId} */ - keysDetail: (keyId: number, params?: RequestParams) => - this.request(`/user/keys/${keyId}`, "GET", params), + keysDetail: (keyId: number, params: RequestParams = {}) => + this.request({ + path: `/user/keys/${keyId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List public and private organizations for the authenticated user. @@ -3798,7 +5000,13 @@ export class Api extends HttpClient { * @name OrgsList * @request GET:/user/orgs */ - orgsList: (params?: RequestParams) => this.request(`/user/orgs`, "GET", params), + orgsList: (params: RequestParams = {}) => + this.request({ + path: `/user/orgs`, + method: "GET", + format: "json", + ...params, + }), /** * @description List repositories for the authenticated user. Note that this does not include repositories owned by organizations which the user can access. You can lis user organizations and list organization repositories separately. @@ -3808,8 +5016,15 @@ export class Api extends HttpClient { */ reposList: ( query?: { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }, - params?: RequestParams, - ) => this.request(`/user/repos${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/user/repos`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. @@ -3817,8 +5032,14 @@ export class Api extends HttpClient { * @name ReposCreate * @request POST:/user/repos */ - reposCreate: (body: PostRepo, params?: RequestParams) => - this.request(`/user/repos`, "POST", params, body), + reposCreate: (body: PostRepo, params: RequestParams = {}) => + this.request({ + path: `/user/repos`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List repositories being starred by the authenticated user. @@ -3826,8 +5047,14 @@ export class Api extends HttpClient { * @name StarredList * @request GET:/user/starred */ - starredList: (query?: { direction?: string; sort?: "created" | "updated" }, params?: RequestParams) => - this.request(`/user/starred${this.addQueryParams(query)}`, "GET", params), + starredList: (query?: { direction?: string; sort?: "created" | "updated" }, params: RequestParams = {}) => + this.request({ + path: `/user/starred`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Unstar a repository @@ -3835,8 +5062,12 @@ export class Api extends HttpClient { * @name StarredDelete * @request DELETE:/user/starred/{owner}/{repo} */ - starredDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/starred/${owner}/${repo}`, "DELETE", params), + starredDelete: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/user/starred/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Check if you are starring a repository. @@ -3844,8 +5075,12 @@ export class Api extends HttpClient { * @name StarredDetail * @request GET:/user/starred/{owner}/{repo} */ - starredDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/starred/${owner}/${repo}`, "GET", params), + starredDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/user/starred/${owner}/${repo}`, + method: "GET", + ...params, + }), /** * @description Star a repository. @@ -3853,8 +5088,12 @@ export class Api extends HttpClient { * @name StarredUpdate * @request PUT:/user/starred/{owner}/{repo} */ - starredUpdate: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/starred/${owner}/${repo}`, "PUT", params), + starredUpdate: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/user/starred/${owner}/${repo}`, + method: "PUT", + ...params, + }), /** * @description List repositories being watched by the authenticated user. @@ -3862,7 +5101,13 @@ export class Api extends HttpClient { * @name SubscriptionsList * @request GET:/user/subscriptions */ - subscriptionsList: (params?: RequestParams) => this.request(`/user/subscriptions`, "GET", params), + subscriptionsList: (params: RequestParams = {}) => + this.request({ + path: `/user/subscriptions`, + method: "GET", + format: "json", + ...params, + }), /** * @description Stop watching a repository @@ -3870,8 +5115,12 @@ export class Api extends HttpClient { * @name SubscriptionsDelete * @request DELETE:/user/subscriptions/{owner}/{repo} */ - subscriptionsDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/subscriptions/${owner}/${repo}`, "DELETE", params), + subscriptionsDelete: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/user/subscriptions/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Check if you are watching a repository. @@ -3879,8 +5128,12 @@ export class Api extends HttpClient { * @name SubscriptionsDetail * @request GET:/user/subscriptions/{owner}/{repo} */ - subscriptionsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/subscriptions/${owner}/${repo}`, "GET", params), + subscriptionsDetail: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/user/subscriptions/${owner}/${repo}`, + method: "GET", + ...params, + }), /** * @description Watch a repository. @@ -3888,8 +5141,12 @@ export class Api extends HttpClient { * @name SubscriptionsUpdate * @request PUT:/user/subscriptions/{owner}/{repo} */ - subscriptionsUpdate: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/subscriptions/${owner}/${repo}`, "PUT", params), + subscriptionsUpdate: (owner: string, repo: string, params: RequestParams = {}) => + this.request({ + path: `/user/subscriptions/${owner}/${repo}`, + method: "PUT", + ...params, + }), /** * @description List all of the teams across all of the organizations to which the authenticated user belongs. This method requires user or repo scope when authenticating via OAuth. @@ -3897,7 +5154,13 @@ export class Api extends HttpClient { * @name TeamsList * @request GET:/user/teams */ - teamsList: (params?: RequestParams) => this.request(`/user/teams`, "GET", params), + teamsList: (params: RequestParams = {}) => + this.request({ + path: `/user/teams`, + method: "GET", + format: "json", + ...params, + }), }; users = { /** @@ -3906,8 +5169,14 @@ export class Api extends HttpClient { * @name UsersList * @request GET:/users */ - usersList: (query?: { since?: number }, params?: RequestParams) => - this.request(`/users${this.addQueryParams(query)}`, "GET", params), + usersList: (query?: { since?: number }, params: RequestParams = {}) => + this.request({ + path: `/users`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Get a single user. @@ -3915,8 +5184,13 @@ export class Api extends HttpClient { * @name UsersDetail * @request GET:/users/{username} */ - usersDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}`, "GET", params), + usersDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description If you are authenticated as the given user, you will see your private events. Otherwise, you'll only see public events. @@ -3924,8 +5198,12 @@ export class Api extends HttpClient { * @name EventsDetail * @request GET:/users/{username}/events */ - eventsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/events`, "GET", params), + eventsDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/events`, + method: "GET", + ...params, + }), /** * @description This is the user's organization dashboard. You must be authenticated as the user to view this. @@ -3933,8 +5211,12 @@ export class Api extends HttpClient { * @name EventsOrgsDetail * @request GET:/users/{username}/events/orgs/{org} */ - eventsOrgsDetail: (username: string, org: string, params?: RequestParams) => - this.request(`/users/${username}/events/orgs/${org}`, "GET", params), + eventsOrgsDetail: (username: string, org: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/events/orgs/${org}`, + method: "GET", + ...params, + }), /** * @description List a user's followers @@ -3942,8 +5224,13 @@ export class Api extends HttpClient { * @name FollowersDetail * @request GET:/users/{username}/followers */ - followersDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/followers`, "GET", params), + followersDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/followers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Check if one user follows another. @@ -3951,8 +5238,12 @@ export class Api extends HttpClient { * @name FollowingDetail * @request GET:/users/{username}/following/{targetUser} */ - followingDetail: (username: string, targetUser: string, params?: RequestParams) => - this.request(`/users/${username}/following/${targetUser}`, "GET", params), + followingDetail: (username: string, targetUser: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/following/${targetUser}`, + method: "GET", + ...params, + }), /** * @description List a users gists. @@ -3960,8 +5251,14 @@ export class Api extends HttpClient { * @name GistsDetail * @request GET:/users/{username}/gists */ - gistsDetail: (username: string, query?: { since?: string }, params?: RequestParams) => - this.request(`/users/${username}/gists${this.addQueryParams(query)}`, "GET", params), + gistsDetail: (username: string, query?: { since?: string }, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/gists`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List public keys for a user. Lists the verified public keys for a user. This is accessible by anyone. @@ -3969,8 +5266,13 @@ export class Api extends HttpClient { * @name KeysDetail * @request GET:/users/{username}/keys */ - keysDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/keys`, "GET", params), + keysDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/keys`, + method: "GET", + format: "json", + ...params, + }), /** * @description List all public organizations for a user. @@ -3978,8 +5280,13 @@ export class Api extends HttpClient { * @name OrgsDetail * @request GET:/users/{username}/orgs */ - orgsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/orgs`, "GET", params), + orgsDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/orgs`, + method: "GET", + format: "json", + ...params, + }), /** * @description These are events that you'll only see public events. @@ -3987,8 +5294,12 @@ export class Api extends HttpClient { * @name ReceivedEventsDetail * @request GET:/users/{username}/received_events */ - receivedEventsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/received_events`, "GET", params), + receivedEventsDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/received_events`, + method: "GET", + ...params, + }), /** * @description List public events that a user has received @@ -3996,8 +5307,12 @@ export class Api extends HttpClient { * @name ReceivedEventsPublicDetail * @request GET:/users/{username}/received_events/public */ - receivedEventsPublicDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/received_events/public`, "GET", params), + receivedEventsPublicDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/received_events/public`, + method: "GET", + ...params, + }), /** * @description List public repositories for the specified user. @@ -4008,8 +5323,15 @@ export class Api extends HttpClient { reposDetail: ( username: string, query?: { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }, - params?: RequestParams, - ) => this.request(`/users/${username}/repos${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/users/${username}/repos`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List repositories being starred by a user. @@ -4017,8 +5339,12 @@ export class Api extends HttpClient { * @name StarredDetail * @request GET:/users/{username}/starred */ - starredDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/starred`, "GET", params), + starredDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/starred`, + method: "GET", + ...params, + }), /** * @description List repositories being watched by a user. @@ -4026,7 +5352,11 @@ export class Api extends HttpClient { * @name SubscriptionsDetail * @request GET:/users/{username}/subscriptions */ - subscriptionsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/subscriptions`, "GET", params), + subscriptionsDetail: (username: string, params: RequestParams = {}) => + this.request({ + path: `/users/${username}/subscriptions`, + method: "GET", + ...params, + }), }; } diff --git a/tests/generated/v2.0/path-args.ts b/tests/generated/v2.0/path-args.ts index 1f5f0f36..e38d40d5 100644 --- a/tests/generated/v2.0/path-args.ts +++ b/tests/generated/v2.0/path-args.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://unknown.io/v666"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -151,7 +204,7 @@ export class HttpClient { * @version 1.0.0 * @baseUrl http://unknown.io/v666 */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * No description @@ -166,7 +219,14 @@ export class Api extends HttpClient { param1?: number, param2?: number, query?: { queryParam?: number }, - params?: RequestParams, - ) => this.request(`/pets/${param1}/${param2}/${param3}${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/pets/${param1}/${param2}/${param3}`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/petstore-expanded.ts b/tests/generated/v2.0/petstore-expanded.ts index 2fe1ad21..da3288cc 100644 --- a/tests/generated/v2.0/petstore-expanded.ts +++ b/tests/generated/v2.0/petstore-expanded.ts @@ -46,16 +46,34 @@ export interface PageTemplateResponseDto { totalPages?: number; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -63,22 +81,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -91,92 +110,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -189,7 +242,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/api * A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * @description Returns all pets from the system that the user has access to Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. @@ -197,8 +250,14 @@ export class Api extends HttpClient { * @name FindPets * @request GET:/pets */ - findPets: (query?: { tags?: string[]; limit?: number }, params?: RequestParams) => - this.request(`/pets${this.addQueryParams(query)}`, "GET", params), + findPets: (query?: { tags?: string[]; limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Creates a new pet in the store. Duplicates are allowed @@ -206,8 +265,15 @@ export class Api extends HttpClient { * @name AddPet * @request POST:/pets */ - addPet: (pet: NewPet, params?: RequestParams) => - this.request(`/pets`, "POST", params, pet, BodyType.Json), + addPet: (pet: NewPet, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "POST", + body: pet, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Returns a user based on a single ID, if the user does not have access to the pet @@ -215,7 +281,13 @@ export class Api extends HttpClient { * @name FindPetById * @request GET:/pets/{id} */ - findPetById: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "GET", params), + findPetById: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description deletes a single pet based on the ID supplied @@ -223,6 +295,11 @@ export class Api extends HttpClient { * @name DeletePet * @request DELETE:/pets/{id} */ - deletePet: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "DELETE", params), + deletePet: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "DELETE", + ...params, + }), }; } diff --git a/tests/generated/v2.0/petstore-minimal.ts b/tests/generated/v2.0/petstore-minimal.ts index 5fe192f6..37715517 100644 --- a/tests/generated/v2.0/petstore-minimal.ts +++ b/tests/generated/v2.0/petstore-minimal.ts @@ -17,16 +17,34 @@ export interface Pet { multiple?: string | number; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -34,22 +52,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -62,92 +81,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -160,7 +213,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/api * A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * @description Returns all pets from the system that the user has access to @@ -168,6 +221,12 @@ export class Api extends HttpClient { * @name PetsList * @request GET:/pets */ - petsList: (params?: RequestParams) => this.request(`/pets`, "GET", params), + petsList: (params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/petstore-simple.ts b/tests/generated/v2.0/petstore-simple.ts index d8a6e54c..8bda29ac 100644 --- a/tests/generated/v2.0/petstore-simple.ts +++ b/tests/generated/v2.0/petstore-simple.ts @@ -32,16 +32,34 @@ export interface ErrorModel { message: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -49,22 +67,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -77,92 +96,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -175,7 +228,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/api * A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * @description Returns all pets from the system that the user has access to @@ -183,8 +236,14 @@ export class Api extends HttpClient { * @name FindPets * @request GET:/pets */ - findPets: (query?: { tags?: string[]; limit?: number }, params?: RequestParams) => - this.request(`/pets${this.addQueryParams(query)}`, "GET", params), + findPets: (query?: { tags?: string[]; limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Creates a new pet in the store. Duplicates are allowed @@ -192,8 +251,15 @@ export class Api extends HttpClient { * @name AddPet * @request POST:/pets */ - addPet: (pet: NewPet, params?: RequestParams) => - this.request(`/pets`, "POST", params, pet, BodyType.Json), + addPet: (pet: NewPet, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "POST", + body: pet, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Returns a user based on a single ID, if the user does not have access to the pet @@ -201,7 +267,13 @@ export class Api extends HttpClient { * @name FindPetById * @request GET:/pets/{id} */ - findPetById: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "GET", params), + findPetById: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description deletes a single pet based on the ID supplied @@ -209,6 +281,11 @@ export class Api extends HttpClient { * @name DeletePet * @request DELETE:/pets/{id} */ - deletePet: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "DELETE", params), + deletePet: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "DELETE", + ...params, + }), }; } diff --git a/tests/generated/v2.0/petstore-swagger-io.ts b/tests/generated/v2.0/petstore-swagger-io.ts index 82567a20..f11d4a95 100644 --- a/tests/generated/v2.0/petstore-swagger-io.ts +++ b/tests/generated/v2.0/petstore-swagger-io.ts @@ -77,16 +77,34 @@ export interface User { userStatus?: number; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -94,22 +112,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://petstore.swagger.io/v2"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -122,92 +141,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -220,7 +273,7 @@ export class HttpClient { * @baseUrl https://petstore.swagger.io/v2 * This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters. */ -export class Api extends HttpClient { +export class Api extends HttpClient { pet = { /** * @description Returns a single pet @@ -231,8 +284,14 @@ export class Api extends HttpClient { * @request GET:/pet/{petId} * @secure */ - getPetById: (petId: number, params?: RequestParams) => - this.request(`/pet/${petId}`, "GET", params, null, BodyType.Json, true), + getPetById: (petId: number, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -243,8 +302,15 @@ export class Api extends HttpClient { * @request POST:/pet/{petId} * @secure */ - updatePetWithForm: (petId: number, data: { name?: string; status?: string }, params?: RequestParams) => - this.request(`/pet/${petId}`, "POST", params, data, BodyType.FormData, true), + updatePetWithForm: (petId: number, data: { name?: string; status?: string }, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}`, + method: "POST", + body: data, + secure: true, + type: ContentType.FormData, + ...params, + }), /** * No description @@ -255,8 +321,13 @@ export class Api extends HttpClient { * @request DELETE:/pet/{petId} * @secure */ - deletePet: (petId: number, params?: RequestParams) => - this.request(`/pet/${petId}`, "DELETE", params, null, BodyType.Json, true), + deletePet: (petId: number, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}`, + method: "DELETE", + secure: true, + ...params, + }), /** * No description @@ -267,8 +338,16 @@ export class Api extends HttpClient { * @request POST:/pet/{petId}/uploadImage * @secure */ - uploadFile: (petId: number, data: { additionalMetadata?: string; file?: File }, params?: RequestParams) => - this.request(`/pet/${petId}/uploadImage`, "POST", params, data, BodyType.FormData, true), + uploadFile: (petId: number, data: { additionalMetadata?: string; file?: File }, params: RequestParams = {}) => + this.request({ + path: `/pet/${petId}/uploadImage`, + method: "POST", + body: data, + secure: true, + type: ContentType.FormData, + format: "json", + ...params, + }), /** * No description @@ -279,8 +358,15 @@ export class Api extends HttpClient { * @request POST:/pet * @secure */ - addPet: (body: Pet, params?: RequestParams) => - this.request(`/pet`, "POST", params, body, BodyType.Json, true), + addPet: (body: Pet, params: RequestParams = {}) => + this.request({ + path: `/pet`, + method: "POST", + body: body, + secure: true, + type: ContentType.Json, + ...params, + }), /** * No description @@ -291,8 +377,15 @@ export class Api extends HttpClient { * @request PUT:/pet * @secure */ - updatePet: (body: Pet, params?: RequestParams) => - this.request(`/pet`, "PUT", params, body, BodyType.Json, true), + updatePet: (body: Pet, params: RequestParams = {}) => + this.request({ + path: `/pet`, + method: "PUT", + body: body, + secure: true, + type: ContentType.Json, + ...params, + }), /** * @description Multiple status values can be provided with comma separated strings @@ -303,15 +396,15 @@ export class Api extends HttpClient { * @request GET:/pet/findByStatus * @secure */ - findPetsByStatus: (query: { status: ("available" | "pending" | "sold")[] }, params?: RequestParams) => - this.request( - `/pet/findByStatus${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + findPetsByStatus: (query: { status: ("available" | "pending" | "sold")[] }, params: RequestParams = {}) => + this.request({ + path: `/pet/findByStatus`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. @@ -322,15 +415,15 @@ export class Api extends HttpClient { * @request GET:/pet/findByTags * @secure */ - findPetsByTags: (query: { tags: string[] }, params?: RequestParams) => - this.request( - `/pet/findByTags${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + findPetsByTags: (query: { tags: string[] }, params: RequestParams = {}) => + this.request({ + path: `/pet/findByTags`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), }; store = { /** @@ -342,8 +435,14 @@ export class Api extends HttpClient { * @request GET:/store/inventory * @secure */ - getInventory: (params?: RequestParams) => - this.request, any>(`/store/inventory`, "GET", params, null, BodyType.Json, true), + getInventory: (params: RequestParams = {}) => + this.request, any>({ + path: `/store/inventory`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * @description For valid response try integer IDs with value >= 1 and <= 10. Other values will generated exceptions @@ -353,8 +452,13 @@ export class Api extends HttpClient { * @summary Find purchase order by ID * @request GET:/store/order/{orderId} */ - getOrderById: (orderId: number, params?: RequestParams) => - this.request(`/store/order/${orderId}`, "GET", params), + getOrderById: (orderId: number, params: RequestParams = {}) => + this.request({ + path: `/store/order/${orderId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description For valid response try integer IDs with positive integer value. Negative or non-integer values will generate API errors @@ -364,8 +468,12 @@ export class Api extends HttpClient { * @summary Delete purchase order by ID * @request DELETE:/store/order/{orderId} */ - deleteOrder: (orderId: number, params?: RequestParams) => - this.request(`/store/order/${orderId}`, "DELETE", params), + deleteOrder: (orderId: number, params: RequestParams = {}) => + this.request({ + path: `/store/order/${orderId}`, + method: "DELETE", + ...params, + }), /** * No description @@ -375,8 +483,15 @@ export class Api extends HttpClient { * @summary Place an order for a pet * @request POST:/store/order */ - placeOrder: (body: Order, params?: RequestParams) => - this.request(`/store/order`, "POST", params, body, BodyType.Json), + placeOrder: (body: Order, params: RequestParams = {}) => + this.request({ + path: `/store/order`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), }; user = { /** @@ -387,8 +502,13 @@ export class Api extends HttpClient { * @summary Get user by user name * @request GET:/user/{username} */ - getUserByName: (username: string, params?: RequestParams) => - this.request(`/user/${username}`, "GET", params), + getUserByName: (username: string, params: RequestParams = {}) => + this.request({ + path: `/user/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description This can only be done by the logged in user. @@ -398,8 +518,14 @@ export class Api extends HttpClient { * @summary Updated user * @request PUT:/user/{username} */ - updateUser: (username: string, body: User, params?: RequestParams) => - this.request(`/user/${username}`, "PUT", params, body, BodyType.Json), + updateUser: (username: string, body: User, params: RequestParams = {}) => + this.request({ + path: `/user/${username}`, + method: "PUT", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description This can only be done by the logged in user. @@ -409,8 +535,12 @@ export class Api extends HttpClient { * @summary Delete user * @request DELETE:/user/{username} */ - deleteUser: (username: string, params?: RequestParams) => - this.request(`/user/${username}`, "DELETE", params), + deleteUser: (username: string, params: RequestParams = {}) => + this.request({ + path: `/user/${username}`, + method: "DELETE", + ...params, + }), /** * No description @@ -420,8 +550,14 @@ export class Api extends HttpClient { * @summary Logs user into the system * @request GET:/user/login */ - loginUser: (query: { username: string; password: string }, params?: RequestParams) => - this.request(`/user/login${this.addQueryParams(query)}`, "GET", params), + loginUser: (query: { username: string; password: string }, params: RequestParams = {}) => + this.request({ + path: `/user/login`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * No description @@ -431,7 +567,12 @@ export class Api extends HttpClient { * @summary Logs out current logged in user session * @request GET:/user/logout */ - logoutUser: (params?: RequestParams) => this.request(`/user/logout`, "GET", params), + logoutUser: (params: RequestParams = {}) => + this.request({ + path: `/user/logout`, + method: "GET", + ...params, + }), /** * @description This can only be done by the logged in user. @@ -441,8 +582,14 @@ export class Api extends HttpClient { * @summary Create user * @request POST:/user */ - createUser: (body: User, params?: RequestParams) => - this.request(`/user`, "POST", params, body, BodyType.Json), + createUser: (body: User, params: RequestParams = {}) => + this.request({ + path: `/user`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -452,8 +599,14 @@ export class Api extends HttpClient { * @summary Creates list of users with given input array * @request POST:/user/createWithArray */ - createUsersWithArrayInput: (body: User[], params?: RequestParams) => - this.request(`/user/createWithArray`, "POST", params, body, BodyType.Json), + createUsersWithArrayInput: (body: User[], params: RequestParams = {}) => + this.request({ + path: `/user/createWithArray`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -463,7 +616,13 @@ export class Api extends HttpClient { * @summary Creates list of users with given input array * @request POST:/user/createWithList */ - createUsersWithListInput: (body: User[], params?: RequestParams) => - this.request(`/user/createWithList`, "POST", params, body, BodyType.Json), + createUsersWithListInput: (body: User[], params: RequestParams = {}) => + this.request({ + path: `/user/createWithList`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), }; } diff --git a/tests/generated/v2.0/petstore-with-external-docs.ts b/tests/generated/v2.0/petstore-with-external-docs.ts index e7b81457..42d31c01 100644 --- a/tests/generated/v2.0/petstore-with-external-docs.ts +++ b/tests/generated/v2.0/petstore-with-external-docs.ts @@ -22,16 +22,34 @@ export interface ErrorModel { message: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -39,22 +57,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -67,92 +86,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -165,7 +218,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/api * A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * @description Returns all pets from the system that the user has access to @@ -173,8 +226,14 @@ export class Api extends HttpClient { * @name FindPets * @request GET:/pets */ - findPets: (query?: { tags?: string[]; limit?: number }, params?: RequestParams) => - this.request(`/pets${this.addQueryParams(query)}`, "GET", params), + findPets: (query?: { tags?: string[]; limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Creates a new pet in the store. Duplicates are allowed @@ -182,8 +241,15 @@ export class Api extends HttpClient { * @name AddPet * @request POST:/pets */ - addPet: (pet: NewPet, params?: RequestParams) => - this.request(`/pets`, "POST", params, pet, BodyType.Json), + addPet: (pet: NewPet, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "POST", + body: pet, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Returns a user based on a single ID, if the user does not have access to the pet @@ -191,7 +257,13 @@ export class Api extends HttpClient { * @name FindPetById * @request GET:/pets/{id} */ - findPetById: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "GET", params), + findPetById: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description deletes a single pet based on the ID supplied @@ -199,6 +271,11 @@ export class Api extends HttpClient { * @name DeletePet * @request DELETE:/pets/{id} */ - deletePet: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "DELETE", params), + deletePet: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "DELETE", + ...params, + }), }; } diff --git a/tests/generated/v2.0/petstore.ts b/tests/generated/v2.0/petstore.ts index cb707482..7650f4f4 100644 --- a/tests/generated/v2.0/petstore.ts +++ b/tests/generated/v2.0/petstore.ts @@ -24,16 +24,34 @@ export interface Error { message: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -41,22 +59,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -69,92 +88,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -166,7 +219,7 @@ export class HttpClient { * @version 1.0.0 * @baseUrl http://petstore.swagger.io/v1 */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * No description @@ -176,8 +229,14 @@ export class Api extends HttpClient { * @summary List all pets * @request GET:/pets */ - listPets: (query?: { limit?: number }, params?: RequestParams) => - this.request(`/pets${this.addQueryParams(query)}`, "GET", params), + listPets: (query?: { limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * No description @@ -187,7 +246,12 @@ export class Api extends HttpClient { * @summary Create a pet * @request POST:/pets */ - createPets: (params?: RequestParams) => this.request(`/pets`, "POST", params), + createPets: (params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "POST", + ...params, + }), /** * No description @@ -197,6 +261,12 @@ export class Api extends HttpClient { * @summary Info for a specific pet * @request GET:/pets/{petId} */ - showPetById: (petId: string, params?: RequestParams) => this.request(`/pets/${petId}`, "GET", params), + showPetById: (petId: string, params: RequestParams = {}) => + this.request({ + path: `/pets/${petId}`, + method: "GET", + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/query-path-param.ts b/tests/generated/v2.0/query-path-param.ts index 65e5e75a..4e756858 100644 --- a/tests/generated/v2.0/query-path-param.ts +++ b/tests/generated/v2.0/query-path-param.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://unknown.io/v666"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -151,7 +204,7 @@ export class HttpClient { * @version 1.0.0 * @baseUrl http://unknown.io/v666 */ -export class Api extends HttpClient { +export class Api extends HttpClient { foobarbaz = { /** * No description @@ -161,7 +214,13 @@ export class Api extends HttpClient { * @summary List all pets * @request GET:/foobarbaz/{query} */ - listPets: (query?: number, queryParams?: { queryParam?: number }, params?: RequestParams) => - this.request(`/foobarbaz/${query}${this.addQueryParams(queryParams)}`, "GET", params), + listPets: (query?: number, queryParams?: { queryParam?: number }, params: RequestParams = {}) => + this.request({ + path: `/foobarbaz/${query}`, + method: "GET", + query: queryParams, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v2.0/uber.ts b/tests/generated/v2.0/uber.ts index 0f5195c2..b567938a 100644 --- a/tests/generated/v2.0/uber.ts +++ b/tests/generated/v2.0/uber.ts @@ -104,16 +104,34 @@ export interface Error { fields?: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -121,22 +139,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://api.uber.com/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -149,92 +168,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -247,7 +300,7 @@ export class HttpClient { * @baseUrl https://api.uber.com/v1 * Move your app forward with the Uber API */ -export class Api extends HttpClient { +export class Api extends HttpClient { products = { /** * @description The Products endpoint returns information about the Uber products offered at a given location. The response includes the display name and other details about each product, and lists the products in the proper display order. @@ -258,15 +311,15 @@ export class Api extends HttpClient { * @request GET:/products * @secure */ - productsList: (query: { latitude: number; longitude: number }, params?: RequestParams) => - this.request( - `/products${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + productsList: (query: { latitude: number; longitude: number }, params: RequestParams = {}) => + this.request({ + path: `/products`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), }; estimates = { /** @@ -279,8 +332,15 @@ export class Api extends HttpClient { */ priceList: ( query: { start_latitude: number; start_longitude: number; end_latitude?: number; end_longitude: number }, - params?: RequestParams, - ) => this.request(`/estimates/price${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/estimates/price`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description The Time Estimates endpoint returns ETAs for all products offered at a given location, with the responses expressed as integers in seconds. We recommend that this endpoint be called every minute to provide the most accurate, up-to-date ETAs. @@ -292,8 +352,15 @@ export class Api extends HttpClient { */ timeList: ( query: { start_latitude: number; start_longitude: number; customer_uuid?: string; product_id?: string }, - params?: RequestParams, - ) => this.request(`/estimates/time${this.addQueryParams(query)}`, "GET", params), + params: RequestParams = {}, + ) => + this.request({ + path: `/estimates/time`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; me = { /** @@ -304,7 +371,13 @@ export class Api extends HttpClient { * @summary User Profile * @request GET:/me */ - getMe: (params?: RequestParams) => this.request(`/me`, "GET", params), + getMe: (params: RequestParams = {}) => + this.request({ + path: `/me`, + method: "GET", + format: "json", + ...params, + }), }; history = { /** @@ -315,7 +388,13 @@ export class Api extends HttpClient { * @summary User Activity * @request GET:/history */ - historyList: (query?: { offset?: number; limit?: number }, params?: RequestParams) => - this.request(`/history${this.addQueryParams(query)}`, "GET", params), + historyList: (query?: { offset?: number; limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/history`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/additional-properties.ts b/tests/generated/v3.0/additional-properties.ts index eba55c68..bdd232ce 100644 --- a/tests/generated/v3.0/additional-properties.ts +++ b/tests/generated/v3.0/additional-properties.ts @@ -16,16 +16,34 @@ export interface Message { text?: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -33,22 +51,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -61,92 +80,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -157,4 +210,4 @@ export class HttpClient { * @title Additional propeties Example * @version 1.0.0 */ -export class Api extends HttpClient {} +export class Api extends HttpClient {} diff --git a/tests/generated/v3.0/additional-properties2.ts b/tests/generated/v3.0/additional-properties2.ts index 8022f3e0..b0c99964 100644 --- a/tests/generated/v3.0/additional-properties2.ts +++ b/tests/generated/v3.0/additional-properties2.ts @@ -13,16 +13,34 @@ export type Primitive = string | number | boolean | null; export type PrimitiveMap = Record; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -30,22 +48,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -58,92 +77,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -151,6 +204,6 @@ export class HttpClient { } /** - * @title Api + * @title No title */ -export class Api extends HttpClient {} +export class Api extends HttpClient {} diff --git a/tests/generated/v3.0/allof-example.ts b/tests/generated/v3.0/allof-example.ts index 8a6aa15a..681d553c 100644 --- a/tests/generated/v3.0/allof-example.ts +++ b/tests/generated/v3.0/allof-example.ts @@ -17,16 +17,34 @@ export type Dog = Pet & { bark?: boolean; breed?: "Dingo" | "Husky" | "Retriever export type Cat = Pet & { hunts?: boolean; age?: number }; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -34,22 +52,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -62,92 +81,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -158,7 +211,7 @@ export class HttpClient { * @title Allof Example * @version 1.0.0 */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * No description @@ -166,7 +219,13 @@ export class Api extends HttpClient { * @name PetsPartialUpdate * @request PATCH:/pets */ - petsPartialUpdate: (data: Cat | Dog, params?: RequestParams) => - this.request(`/pets`, "PATCH", params, data, BodyType.Json), + petsPartialUpdate: (data: Cat | Dog, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "PATCH", + body: data, + type: ContentType.Json, + ...params, + }), }; } diff --git a/tests/generated/v3.0/anyof-example.ts b/tests/generated/v3.0/anyof-example.ts index ae02d08b..b90b170d 100644 --- a/tests/generated/v3.0/anyof-example.ts +++ b/tests/generated/v3.0/anyof-example.ts @@ -19,16 +19,34 @@ export interface PetByType { hunts?: boolean; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -36,22 +54,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -64,92 +83,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -160,7 +213,7 @@ export class HttpClient { * @title Anyof Example * @version 1.0.0 */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * No description @@ -168,7 +221,13 @@ export class Api extends HttpClient { * @name PetsPartialUpdate * @request PATCH:/pets */ - petsPartialUpdate: (data: PetByAge | PetByType | (PetByAge & PetByType), params?: RequestParams) => - this.request(`/pets`, "PATCH", params, data, BodyType.Json), + petsPartialUpdate: (data: PetByAge | PetByType | (PetByAge & PetByType), params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "PATCH", + body: data, + type: ContentType.Json, + ...params, + }), }; } diff --git a/tests/generated/v3.0/api-with-examples.ts b/tests/generated/v3.0/api-with-examples.ts index 1528034f..e8bf94ea 100644 --- a/tests/generated/v3.0/api-with-examples.ts +++ b/tests/generated/v3.0/api-with-examples.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -150,7 +203,7 @@ export class HttpClient { * @title Simple API overview * @version 2.0.0 */ -export class Api extends HttpClient { +export class Api extends HttpClient { /** * No description * @@ -158,7 +211,13 @@ export class Api extends HttpClient { * @summary List API versions * @request GET:/ */ - listVersionsv2 = (params?: RequestParams) => this.request(`/`, "GET", params); + listVersionsv2 = (params: RequestParams = {}) => + this.request({ + path: `/`, + method: "GET", + format: "json", + ...params, + }); v2 = { /** @@ -168,6 +227,12 @@ export class Api extends HttpClient { * @summary Show API version details * @request GET:/v2 */ - getVersionDetailsv2: (params?: RequestParams) => this.request(`/v2`, "GET", params), + getVersionDetailsv2: (params: RequestParams = {}) => + this.request({ + path: `/v2`, + method: "GET", + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/callback-example.ts b/tests/generated/v3.0/callback-example.ts index 563a66c4..cc3fd87e 100644 --- a/tests/generated/v3.0/callback-example.ts +++ b/tests/generated/v3.0/callback-example.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -150,7 +203,7 @@ export class HttpClient { * @title Callback Example * @version 1.0.0 */ -export class Api extends HttpClient { +export class Api extends HttpClient { streams = { /** * @description subscribes a client to receive out-of-band data @@ -158,7 +211,13 @@ export class Api extends HttpClient { * @name StreamsCreate * @request POST:/streams */ - streamsCreate: (query: { callbackUrl: string }, params?: RequestParams) => - this.request<{ subscriptionId: string }, any>(`/streams${this.addQueryParams(query)}`, "POST", params), + streamsCreate: (query: { callbackUrl: string }, params: RequestParams = {}) => + this.request<{ subscriptionId: string }, any>({ + path: `/streams`, + method: "POST", + query: query, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/components-responses.ts b/tests/generated/v3.0/components-responses.ts index 8f86b14d..57620980 100644 --- a/tests/generated/v3.0/components-responses.ts +++ b/tests/generated/v3.0/components-responses.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -151,7 +204,7 @@ export class HttpClient { * @version latest * Description */ -export class Api extends HttpClient { +export class Api extends HttpClient { api = { /** * No description @@ -159,6 +212,11 @@ export class Api extends HttpClient { * @name GetData * @request GET:/api */ - getData: (params?: RequestParams) => this.request<{ data?: string }, any>(`/api`, "GET", params), + getData: (params: RequestParams = {}) => + this.request<{ data?: string }, any>({ + path: `/api`, + method: "GET", + ...params, + }), }; } diff --git a/tests/generated/v3.0/explode-param-3.0.1.ts b/tests/generated/v3.0/explode-param-3.0.1.ts index cfd020cd..bab58afb 100644 --- a/tests/generated/v3.0/explode-param-3.0.1.ts +++ b/tests/generated/v3.0/explode-param-3.0.1.ts @@ -25,16 +25,34 @@ export interface QueryParams { "page-size"?: number | null; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -42,22 +60,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -70,92 +89,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -167,7 +220,7 @@ export class HttpClient { * @version 0.1 * Documentation */ -export class Api extends HttpClient { +export class Api extends HttpClient { something = { /** * No description @@ -175,7 +228,12 @@ export class Api extends HttpClient { * @name Gets * @request GET:/something/ */ - gets: (query?: { params?: QueryParams }, params?: RequestParams) => - this.request(`/something/${this.addQueryParams(query)}`, "GET", params), + gets: (query?: { params?: QueryParams }, params: RequestParams = {}) => + this.request({ + path: `/something/`, + method: "GET", + query: query, + ...params, + }), }; } diff --git a/tests/generated/v3.0/link-example.ts b/tests/generated/v3.0/link-example.ts index afa01173..0f5912a4 100644 --- a/tests/generated/v3.0/link-example.ts +++ b/tests/generated/v3.0/link-example.ts @@ -26,16 +26,34 @@ export interface Pullrequest { author?: User; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -43,22 +61,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -71,92 +90,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -167,7 +220,7 @@ export class HttpClient { * @title Link Example * @version 1.0.0 */ -export class Api extends HttpClient { +export class Api extends HttpClient { v20 = { /** * No description @@ -175,8 +228,13 @@ export class Api extends HttpClient { * @name GetUserByName * @request GET:/2.0/users/{username} */ - getUserByName: (username: string, params?: RequestParams) => - this.request(`/2.0/users/${username}`, "GET", params), + getUserByName: (username: string, params: RequestParams = {}) => + this.request({ + path: `/2.0/users/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * No description @@ -184,8 +242,13 @@ export class Api extends HttpClient { * @name GetRepositoriesByOwner * @request GET:/2.0/repositories/{username} */ - getRepositoriesByOwner: (username: string, params?: RequestParams) => - this.request(`/2.0/repositories/${username}`, "GET", params), + getRepositoriesByOwner: (username: string, params: RequestParams = {}) => + this.request({ + path: `/2.0/repositories/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * No description @@ -193,8 +256,13 @@ export class Api extends HttpClient { * @name GetRepository * @request GET:/2.0/repositories/{username}/{slug} */ - getRepository: (username: string, slug: string, params?: RequestParams) => - this.request(`/2.0/repositories/${username}/${slug}`, "GET", params), + getRepository: (username: string, slug: string, params: RequestParams = {}) => + this.request({ + path: `/2.0/repositories/${username}/${slug}`, + method: "GET", + format: "json", + ...params, + }), /** * No description @@ -206,13 +274,15 @@ export class Api extends HttpClient { username: string, slug: string, query?: { state?: "open" | "merged" | "declined" }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request( - `/2.0/repositories/${username}/${slug}/pullrequests${this.addQueryParams(query)}`, - "GET", - params, - ), + this.request({ + path: `/2.0/repositories/${username}/${slug}/pullrequests`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * No description @@ -220,8 +290,13 @@ export class Api extends HttpClient { * @name GetPullRequestsById * @request GET:/2.0/repositories/{username}/{slug}/pullrequests/{pid} */ - getPullRequestsById: (username: string, slug: string, pid: string, params?: RequestParams) => - this.request(`/2.0/repositories/${username}/${slug}/pullrequests/${pid}`, "GET", params), + getPullRequestsById: (username: string, slug: string, pid: string, params: RequestParams = {}) => + this.request({ + path: `/2.0/repositories/${username}/${slug}/pullrequests/${pid}`, + method: "GET", + format: "json", + ...params, + }), /** * No description @@ -229,7 +304,11 @@ export class Api extends HttpClient { * @name MergePullRequest * @request POST:/2.0/repositories/{username}/{slug}/pullrequests/{pid}/merge */ - mergePullRequest: (username: string, slug: string, pid: string, params?: RequestParams) => - this.request(`/2.0/repositories/${username}/${slug}/pullrequests/${pid}/merge`, "POST", params), + mergePullRequest: (username: string, slug: string, pid: string, params: RequestParams = {}) => + this.request({ + path: `/2.0/repositories/${username}/${slug}/pullrequests/${pid}/merge`, + method: "POST", + ...params, + }), }; } diff --git a/tests/generated/v3.0/no-definitions-schema.ts b/tests/generated/v3.0/no-definitions-schema.ts index aedac87a..042b3a26 100644 --- a/tests/generated/v3.0/no-definitions-schema.ts +++ b/tests/generated/v3.0/no-definitions-schema.ts @@ -21,16 +21,34 @@ export interface BasicErrorModel { export type ExtendedErrorModel = BasicErrorModel & { rootCause: string }; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -38,22 +56,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -66,92 +85,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -162,4 +215,4 @@ export class HttpClient { * @title Empty schema example * @version 1.0.0 */ -export class Api extends HttpClient {} +export class Api extends HttpClient {} diff --git a/tests/generated/v3.0/nullable-refs.ts b/tests/generated/v3.0/nullable-refs.ts index 9fc8eacb..be56f482 100644 --- a/tests/generated/v3.0/nullable-refs.ts +++ b/tests/generated/v3.0/nullable-refs.ts @@ -23,16 +23,34 @@ export interface TestObject { export type OtherObject = object; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -40,22 +58,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -68,92 +87,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -164,4 +217,4 @@ export class HttpClient { * @title Nullable Refs Example * @version 1.0.0 */ -export class Api extends HttpClient {} +export class Api extends HttpClient {} diff --git a/tests/generated/v3.0/oneof-example.ts b/tests/generated/v3.0/oneof-example.ts index 6876f403..d78a6b97 100644 --- a/tests/generated/v3.0/oneof-example.ts +++ b/tests/generated/v3.0/oneof-example.ts @@ -19,16 +19,34 @@ export interface Cat { age?: number; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -36,22 +54,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -64,92 +83,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -160,7 +213,7 @@ export class HttpClient { * @title Oneof Example * @version 1.0.0 */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * No description @@ -168,7 +221,13 @@ export class Api extends HttpClient { * @name PetsPartialUpdate * @request PATCH:/pets */ - petsPartialUpdate: (data: Cat | Dog, params?: RequestParams) => - this.request(`/pets`, "PATCH", params, data, BodyType.Json), + petsPartialUpdate: (data: Cat | Dog, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "PATCH", + body: data, + type: ContentType.Json, + ...params, + }), }; } diff --git a/tests/generated/v3.0/personal-api-example.ts b/tests/generated/v3.0/personal-api-example.ts index 8ed3c554..0fea46a5 100644 --- a/tests/generated/v3.0/personal-api-example.ts +++ b/tests/generated/v3.0/personal-api-example.ts @@ -210,16 +210,34 @@ export interface ProjectType { teamSize: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -227,22 +245,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://localhost:8080/api/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -255,92 +274,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -348,10 +401,10 @@ export class HttpClient { } /** - * @title Api + * @title No title * @baseUrl http://localhost:8080/api/v1 */ -export class Api extends HttpClient { +export class Api extends HttpClient { auth = { /** * No description @@ -360,8 +413,15 @@ export class Api extends HttpClient { * @name Login * @request POST:/auth */ - login: (data: AuthUserType, params?: RequestParams) => - this.request(`/auth`, "POST", params, data, BodyType.Json), + login: (data: AuthUserType, params: RequestParams = {}) => + this.request({ + path: `/auth`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -371,8 +431,14 @@ export class Api extends HttpClient { * @request POST:/auth/refresh * @secure */ - refresh: (params?: RequestParams) => - this.request(`/auth/refresh`, "POST", params, null, BodyType.Json, true), + refresh: (params: RequestParams = {}) => + this.request({ + path: `/auth/refresh`, + method: "POST", + secure: true, + format: "json", + ...params, + }), }; jobs = { /** @@ -383,8 +449,14 @@ export class Api extends HttpClient { * @request GET:/jobs * @secure */ - getJobs: (params?: RequestParams) => - this.request(`/jobs`, "GET", params, null, BodyType.Json, true), + getJobs: (params: RequestParams = {}) => + this.request({ + path: `/jobs`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -394,8 +466,16 @@ export class Api extends HttpClient { * @request POST:/jobs * @secure */ - addJob: (data: JobUpdateType, params?: RequestParams) => - this.request(`/jobs`, "POST", params, data, BodyType.Json, true), + addJob: (data: JobUpdateType, params: RequestParams = {}) => + this.request({ + path: `/jobs`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -405,8 +485,14 @@ export class Api extends HttpClient { * @request GET:/jobs/{id} * @secure */ - getJob: (id: string, params?: RequestParams) => - this.request(`/jobs/${id}`, "GET", params, null, BodyType.Json, true), + getJob: (id: string, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -416,8 +502,16 @@ export class Api extends HttpClient { * @request PATCH:/jobs/{id} * @secure */ - updateJob: (id: string, data: JobUpdateType, params?: RequestParams) => - this.request(`/jobs/${id}`, "PATCH", params, data, BodyType.Json, true), + updateJob: (id: string, data: JobUpdateType, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -427,8 +521,14 @@ export class Api extends HttpClient { * @request DELETE:/jobs/{id} * @secure */ - deleteJob: (id: string, params?: RequestParams) => - this.request(`/jobs/${id}`, "DELETE", params, null, BodyType.Json, true), + deleteJob: (id: string, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), }; projects = { /** @@ -438,7 +538,13 @@ export class Api extends HttpClient { * @name GetProjects * @request GET:/projects */ - getProjects: (params?: RequestParams) => this.request(`/projects`, "GET", params), + getProjects: (params: RequestParams = {}) => + this.request({ + path: `/projects`, + method: "GET", + format: "json", + ...params, + }), /** * No description @@ -448,8 +554,16 @@ export class Api extends HttpClient { * @request POST:/projects * @secure */ - addProjects: (data: ProjectUpdateType, params?: RequestParams) => - this.request(`/projects`, "POST", params, data, BodyType.Json, true), + addProjects: (data: ProjectUpdateType, params: RequestParams = {}) => + this.request({ + path: `/projects`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -459,8 +573,16 @@ export class Api extends HttpClient { * @request PATCH:/projects/{id} * @secure */ - updateProject: (id: string, data: ProjectUpdateType, params?: RequestParams) => - this.request(`/projects/${id}`, "PATCH", params, data, BodyType.Json, true), + updateProject: (id: string, data: ProjectUpdateType, params: RequestParams = {}) => + this.request({ + path: `/projects/${id}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -469,6 +591,12 @@ export class Api extends HttpClient { * @name DeleteProject * @request DELETE:/projects/{id} */ - deleteProject: (id: string, params?: RequestParams) => this.request(`/projects/${id}`, "DELETE", params), + deleteProject: (id: string, params: RequestParams = {}) => + this.request({ + path: `/projects/${id}`, + method: "DELETE", + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/petstore-expanded.ts b/tests/generated/v3.0/petstore-expanded.ts index aa9a7b35..9eda6120 100644 --- a/tests/generated/v3.0/petstore-expanded.ts +++ b/tests/generated/v3.0/petstore-expanded.ts @@ -22,16 +22,34 @@ export interface Error { message: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -39,22 +57,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -67,92 +86,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -165,7 +218,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/api * A sample API that uses a petstore as an example to demonstrate features in the OpenAPI 3.0 specification */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * @description Returns all pets from the system that the user has access to Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. @@ -173,8 +226,14 @@ export class Api extends HttpClient { * @name FindPets * @request GET:/pets */ - findPets: (query?: { tags?: string[]; limit?: number }, params?: RequestParams) => - this.request(`/pets${this.addQueryParams(query)}`, "GET", params), + findPets: (query?: { tags?: string[]; limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Creates a new pet in the store. Duplicates are allowed @@ -182,8 +241,15 @@ export class Api extends HttpClient { * @name AddPet * @request POST:/pets */ - addPet: (data: NewPet, params?: RequestParams) => - this.request(`/pets`, "POST", params, data, BodyType.Json), + addPet: (data: NewPet, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Returns a user based on a single ID, if the user does not have access to the pet @@ -191,7 +257,13 @@ export class Api extends HttpClient { * @name FindPetById * @request GET:/pets/{id} */ - findPetById: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "GET", params), + findPetById: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description deletes a single pet based on the ID supplied @@ -199,6 +271,11 @@ export class Api extends HttpClient { * @name DeletePet * @request DELETE:/pets/{id} */ - deletePet: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "DELETE", params), + deletePet: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "DELETE", + ...params, + }), }; } diff --git a/tests/generated/v3.0/petstore.ts b/tests/generated/v3.0/petstore.ts index 32ad65b2..54523c57 100644 --- a/tests/generated/v3.0/petstore.ts +++ b/tests/generated/v3.0/petstore.ts @@ -26,16 +26,34 @@ export interface Error { message: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -43,22 +61,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -71,92 +90,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -168,7 +221,7 @@ export class HttpClient { * @version 1.0.0 * @baseUrl http://petstore.swagger.io/v1 */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * No description @@ -178,8 +231,14 @@ export class Api extends HttpClient { * @summary List all pets * @request GET:/pets */ - listPets: (query?: { limit?: number }, params?: RequestParams) => - this.request(`/pets${this.addQueryParams(query)}`, "GET", params), + listPets: (query?: { limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * No description @@ -189,7 +248,12 @@ export class Api extends HttpClient { * @summary Create a pet * @request POST:/pets */ - createPets: (params?: RequestParams) => this.request(`/pets`, "POST", params), + createPets: (params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "POST", + ...params, + }), /** * No description @@ -199,6 +263,12 @@ export class Api extends HttpClient { * @summary Info for a specific pet * @request GET:/pets/{petId} */ - showPetById: (petId: string, params?: RequestParams) => this.request(`/pets/${petId}`, "GET", params), + showPetById: (petId: string, params: RequestParams = {}) => + this.request({ + path: `/pets/${petId}`, + method: "GET", + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/responses.ts b/tests/generated/v3.0/responses.ts index 8f86b14d..933c8a2e 100644 --- a/tests/generated/v3.0/responses.ts +++ b/tests/generated/v3.0/responses.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -151,7 +204,7 @@ export class HttpClient { * @version latest * Description */ -export class Api extends HttpClient { +export class Api extends HttpClient { api = { /** * No description @@ -159,6 +212,12 @@ export class Api extends HttpClient { * @name GetData * @request GET:/api */ - getData: (params?: RequestParams) => this.request<{ data?: string }, any>(`/api`, "GET", params), + getData: (params: RequestParams = {}) => + this.request<{ data?: string }, any>({ + path: `/api`, + method: "GET", + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/swaggerhub-template.ts b/tests/generated/v3.0/swaggerhub-template.ts index dbd89739..c52731a4 100644 --- a/tests/generated/v3.0/swaggerhub-template.ts +++ b/tests/generated/v3.0/swaggerhub-template.ts @@ -9,16 +9,34 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -26,22 +44,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://virtserver.swaggerhub.com/sdfsdfsffs/sdfff/1.0.0"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -152,7 +205,7 @@ export class HttpClient { * @baseUrl https://virtserver.swaggerhub.com/sdfsdfsffs/sdfff/1.0.0 * This is an example of using OAuth2 Application Flow in a specification to describe security to your API. */ -export class Api extends HttpClient { +export class Api extends HttpClient { example = { /** * @description This is an example operation to show how security is applied to the call. @@ -162,8 +215,13 @@ export class Api extends HttpClient { * @request GET:/example * @secure */ - exampleList: (params?: RequestParams) => - this.request(`/example`, "GET", params, null, BodyType.Json, true), + exampleList: (params: RequestParams = {}) => + this.request({ + path: `/example`, + method: "GET", + secure: true, + ...params, + }), }; ping = { /** @@ -174,6 +232,12 @@ export class Api extends HttpClient { * @request GET:/ping * @secure */ - pingList: (params?: RequestParams) => this.request(`/ping`, "GET", params, null, BodyType.Json, true), + pingList: (params: RequestParams = {}) => + this.request({ + path: `/ping`, + method: "GET", + secure: true, + ...params, + }), }; } diff --git a/tests/generated/v3.0/tsoa-odd-types-3.0.2.ts b/tests/generated/v3.0/tsoa-odd-types-3.0.2.ts index 3072904e..1462d21a 100644 --- a/tests/generated/v3.0/tsoa-odd-types-3.0.2.ts +++ b/tests/generated/v3.0/tsoa-odd-types-3.0.2.ts @@ -130,16 +130,34 @@ export interface UserUpdate { id?: string | null; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -147,22 +165,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://localhost:8080/api/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -175,92 +194,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -268,10 +321,10 @@ export class HttpClient { } /** - * @title Api + * @title No title * @baseUrl http://localhost:8080/api/v1 */ -export class Api extends HttpClient { +export class Api extends HttpClient { auth = { /** * No description @@ -280,8 +333,15 @@ export class Api extends HttpClient { * @name Login * @request POST:/auth */ - login: (data?: AuthUser, params?: RequestParams) => - this.request(`/auth`, "POST", params, data, BodyType.Json), + login: (data?: AuthUser, params: RequestParams = {}) => + this.request({ + path: `/auth`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -291,8 +351,14 @@ export class Api extends HttpClient { * @request POST:/auth/refresh * @secure */ - refresh: (params?: RequestParams) => - this.request(`/auth/refresh`, "POST", params, null, BodyType.Json, true), + refresh: (params: RequestParams = {}) => + this.request({ + path: `/auth/refresh`, + method: "POST", + secure: true, + format: "json", + ...params, + }), }; jobs = { /** @@ -303,7 +369,14 @@ export class Api extends HttpClient { * @request GET:/jobs * @secure */ - getJobs: (params?: RequestParams) => this.request(`/jobs`, "GET", params, null, BodyType.Json, true), + getJobs: (params: RequestParams = {}) => + this.request({ + path: `/jobs`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -313,8 +386,16 @@ export class Api extends HttpClient { * @request POST:/jobs * @secure */ - addJob: (data: PickJobGithub, params?: RequestParams) => - this.request(`/jobs`, "POST", params, data, BodyType.Json, true), + addJob: (data: PickJobGithub, params: RequestParams = {}) => + this.request({ + path: `/jobs`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -324,8 +405,14 @@ export class Api extends HttpClient { * @request GET:/jobs/{id} * @secure */ - getJob: (id: string, params?: RequestParams) => - this.request(`/jobs/${id}`, "GET", params, null, BodyType.Json, true), + getJob: (id: string, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -335,8 +422,16 @@ export class Api extends HttpClient { * @request PATCH:/jobs/{id} * @secure */ - updateJob: (id: string, data: JobUpdate, params?: RequestParams) => - this.request(`/jobs/${id}`, "PATCH", params, data, BodyType.Json, true), + updateJob: (id: string, data: JobUpdate, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -346,8 +441,14 @@ export class Api extends HttpClient { * @request DELETE:/jobs/{id} * @secure */ - deleteJob: (id: string, params?: RequestParams) => - this.request(`/jobs/${id}`, "DELETE", params, null, BodyType.Json, true), + deleteJob: (id: string, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), }; projects = { /** @@ -357,7 +458,13 @@ export class Api extends HttpClient { * @name GetProjects * @request GET:/projects */ - getProjects: (params?: RequestParams) => this.request(`/projects`, "GET", params), + getProjects: (params: RequestParams = {}) => + this.request({ + path: `/projects`, + method: "GET", + format: "json", + ...params, + }), /** * No description @@ -367,8 +474,16 @@ export class Api extends HttpClient { * @request POST:/projects * @secure */ - addProjects: (data: ProjectUpdate, params?: RequestParams) => - this.request(`/projects`, "POST", params, data, BodyType.Json, true), + addProjects: (data: ProjectUpdate, params: RequestParams = {}) => + this.request({ + path: `/projects`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -378,8 +493,16 @@ export class Api extends HttpClient { * @request PATCH:/projects/{id} * @secure */ - updateProject: (id: string, data: ProjectUpdate, params?: RequestParams) => - this.request(`/projects/${id}`, "PATCH", params, data, BodyType.Json, true), + updateProject: (id: string, data: ProjectUpdate, params: RequestParams = {}) => + this.request({ + path: `/projects/${id}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), }; users = { /** @@ -390,7 +513,14 @@ export class Api extends HttpClient { * @request GET:/users * @secure */ - getUsers: (params?: RequestParams) => this.request(`/users`, "GET", params, null, BodyType.Json, true), + getUsers: (params: RequestParams = {}) => + this.request({ + path: `/users`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -400,8 +530,16 @@ export class Api extends HttpClient { * @request POST:/users * @secure */ - addUser: (data: AuthUser, params?: RequestParams) => - this.request(`/users`, "POST", params, data, BodyType.Json, true), + addUser: (data: AuthUser, params: RequestParams = {}) => + this.request({ + path: `/users`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -411,8 +549,14 @@ export class Api extends HttpClient { * @request DELETE:/users/{id} * @secure */ - deleteUser: (id: string, params?: RequestParams) => - this.request(`/users/${id}`, "DELETE", params, null, BodyType.Json, true), + deleteUser: (id: string, params: RequestParams = {}) => + this.request({ + path: `/users/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -422,7 +566,15 @@ export class Api extends HttpClient { * @request PATCH:/users/{id} * @secure */ - updateUser: (id: string, data: UserUpdate, params?: RequestParams) => - this.request(`/users/${id}`, "PATCH", params, data, BodyType.Json, true), + updateUser: (id: string, data: UserUpdate, params: RequestParams = {}) => + this.request({ + path: `/users/${id}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/up-banking.ts b/tests/generated/v3.0/up-banking.ts new file mode 100644 index 00000000..db67aa9d --- /dev/null +++ b/tests/generated/v3.0/up-banking.ts @@ -0,0 +1,1083 @@ +/* tslint:disable */ +/* eslint-disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +/** +* Specifies the type of bank account. Currently returned values are `SAVER` +and `TRANSACTIONAL`. +*/ +export enum AccountTypeEnum { + SAVER = "SAVER", + TRANSACTIONAL = "TRANSACTIONAL", +} + +/** + * Provides information about a value of money. + */ +export interface MoneyObject { + /** + * The ISO 4217 currency code. + * + */ + currencyCode: string; + + /** + * The amount of money, formatted as a string in the relevant currency. + * For example, for an Australian dollar value of $10.56, this field will + * be `"10.56"`. The currency symbol is not included in the string. + * + */ + value: string; + + /** + * The amount of money in the smallest denomination for the currency, as a + * 64-bit integer. For example, for an Australian dollar value of $10.56, + * this field will be `1056`. + * + */ + valueInBaseUnits: number; +} + +/** + * Provides information about an Up bank account. + */ +export interface AccountResource { + /** The type of this resource: `accounts` */ + type: string; + + /** + * The unique identifier for this account. + * + */ + id: string; + attributes: { displayName?: string; accountType?: AccountTypeEnum; balance?: MoneyObject; createdAt?: string }; + relationships: { transactions?: { links: { related: string } } }; + links: { self: string }; +} + +/** +* Successful response to get all accounts. This returns a paginated list of +accounts, which can be scrolled by following the `prev` and `next` links +if present. +*/ +export interface ListAccountsResponse { + /** + * The list of accounts returned in this response. + * + */ + data: AccountResource[]; + links: { prev?: string | null; next?: string | null }; +} + +/** + * Successful response to get a single account. + */ +export interface GetAccountResponse { + /** + * The account returned in this response. + * + */ + data: AccountResource; +} + +/** + * Provides information about a category and its ancestry. + */ +export interface CategoryResource { + /** The type of this resource: `categories` */ + type: string; + + /** + * The unique identifier for this category. This is a human-readable but + * URL-safe value. + * + */ + id: string; + attributes: { name?: string }; + relationships: { + parent: { data: { type?: string; id?: string }; links: { related: string } }; + children: { data: { type: string; id: string }[]; links: { related: string } }; + }; + links: { self: string }; +} + +/** +* Successful response to get all categories and their ancestry. The +returned list is not paginated. +*/ +export interface ListCategoriesResponse { + /** + * The list of categories returned in this response. + * + */ + data: CategoryResource[]; +} + +/** + * Successful response to get a single category and its ancestry. + */ +export interface GetCategoryResponse { + /** + * The category returned in this response. + * + */ + data: CategoryResource; +} + +/** + * Basic ping response to verify authentication. + */ +export interface PingResponse { + meta: { id?: string; statusEmoji?: string }; +} + +/** + * Provides information about an error processing a request. + */ +export interface ErrorObject { + /** + * The HTTP status code associated with this error. This can also be + * obtained from the response headers. The status indicates the broad type + * of error according to HTTP semantics. + * + */ + status: string; + + /** + * A short description of this error. This should be stable across + * multiple occurrences of this type of error and typically expands on the + * reason for the status code. + * + */ + title: string; + + /** + * A detailed description of this error. This should be considered unique + * to individual occurrences of an error and subject to change. It is + * useful for debugging purposes. + * + */ + detail: string; + + /** + * If applicable, location in the request that this error relates to. This + * may be a parameter in the query string, or a an attribute in the + * request body. + * + */ + source?: { parameter?: string; pointer?: string }; +} + +/** + * Generic error response that returns one or more errors. + */ +export interface ErrorResponse { + /** + * The list of errors returned in this response. + * + */ + errors: ErrorObject[]; +} + +/** + * Provides information about a tag. + */ +export interface TagResource { + /** The type of this resource: `tags` */ + type: string; + + /** + * The label of the tag, which also acts as the tag’s unique identifier. + * + */ + id: string; + relationships: { transactions?: { links: { related: string } } }; +} + +/** +* Successful response to get all tags. This returns a paginated list of +tags, which can be scrolled by following the `prev` and `next` links if +present. +*/ +export interface ListTagsResponse { + /** + * The list of tags returned in this response. + * + */ + data: TagResource[]; + links: { prev?: string | null; next?: string | null }; +} + +/** + * Uniquely identifies a single tag in the API. + */ +export interface TagInputResourceIdentifier { + /** The type of this resource: `tags` */ + type: string; + + /** + * The label of the tag, which also acts as the tag’s unique identifier. + * + */ + id: string; +} + +/** + * Request to add or remove tags associated with a transaction. + */ +export interface UpdateTransactionTagsRequest { + /** + * The tags to add to or remove from the transaction. + * + */ + data: TagInputResourceIdentifier[]; +} + +/** +* Specifies which stage of processing a transaction is currently at. +Currently returned values are `HELD` and `SETTLED`. When a transaction is +held, its account’s `availableBalance` is affected. When a transaction is +settled, its account’s `currentBalance` is affected. +*/ +export enum TransactionStatusEnum { + HELD = "HELD", + SETTLED = "SETTLED", +} + +/** +* Provides information about the amount at which a transaction was in the +`HELD` status. +*/ +export interface HoldInfoObject { + /** + * The amount of this transaction while in the `HELD` status, in + * Australian dollars. + * + */ + amount: MoneyObject; + + /** + * The foreign currency amount of this transaction while in the `HELD` + * status. This field will be `null` for domestic transactions. The amount + * was converted to the AUD amount reflected in the `amount` field. + * + */ + foreignAmount: MoneyObject | null; +} + +/** +* Provides information about how a Round Up was applied, such as whether or +not a boost was included in the Round Up. +*/ +export interface RoundUpObject { + /** + * The total amount of this Round Up, including any boosts, represented as + * a negative value. + * + */ + amount: MoneyObject; + + /** + * The portion of the Round Up `amount` owing to boosted Round Ups, + * represented as a negative value. If no boost was added to the Round Up + * this field will be `null`. + * + */ + boostPortion: MoneyObject | null; +} + +/** +* Provides information about an instant reimbursement in the form of +cashback. +*/ +export interface CashbackObject { + /** + * A brief description of why this cashback was paid. + * + */ + description: string; + + /** + * The total amount of cashback paid, represented as a positive value. + * + */ + amount: MoneyObject; +} + +export interface TransactionResource { + /** The type of this resource: `transactions` */ + type: string; + + /** + * The unique identifier for this transaction. + * + */ + id: string; + attributes: { + status?: TransactionStatusEnum; + rawText?: string | null; + description?: string; + message?: string | null; + holdInfo?: HoldInfoObject | null; + roundUp?: RoundUpObject | null; + cashback?: CashbackObject | null; + amount?: MoneyObject; + foreignAmount?: MoneyObject | null; + settledAt?: string | null; + createdAt?: string; + }; + relationships: { + account: { data: { type?: string; id?: string }; links: { related: string } }; + category: { data: { type?: string; id?: string }; links: { related: string } }; + parentCategory: { data: { type?: string; id?: string }; links: { related: string } }; + tags: { data: { type: string; id: string }[]; links: { self: string } }; + }; + links: { self: string }; +} + +/** +* Successful response to get all transactions. This returns a paginated +list of transactions, which can be scrolled by following the `prev` and +`next` links if present. +*/ +export interface ListTransactionsResponse { + /** + * The list of transactions returned in this response. + * + */ + data: TransactionResource[]; + links: { prev?: string | null; next?: string | null }; +} + +/** + * Successful response to get a single transaction. + */ +export interface GetTransactionResponse { + /** + * The transaction returned in this response. + * + */ + data: TransactionResource; +} + +/** + * Provides information about a webhook. + */ +export interface WebhookResource { + /** The type of this resource: `webhooks` */ + type: string; + + /** + * The unique identifier for this webhook. + * + */ + id: string; + attributes: { url?: string; description?: string | null; secretKey?: string; createdAt?: string }; + relationships: { logs?: { links: { related: string } } }; + links: { self: string }; +} + +/** +* Successful response to get all webhooks. This returns a paginated list of +webhooks, which can be scrolled by following the `prev` and `next` links +if present. +*/ +export interface ListWebhooksResponse { + /** + * The list of webhooks returned in this response. + * + */ + data: WebhookResource[]; + links: { prev?: string | null; next?: string | null }; +} + +/** + * Represents a webhook specified as request input. + */ +export interface WebhookInputResource { + attributes: { url?: string; description?: string | null }; +} + +/** +* Request to create a new webhook. This currently only requires a `url` +attribute. +*/ +export interface CreateWebhookRequest { + /** + * The webhook resource to create. + * + */ + data: WebhookInputResource; +} + +/** + * Successful response after creating a webhook. + */ +export interface CreateWebhookResponse { + /** + * The webhook that was created. + * + */ + data: WebhookResource; +} + +/** +* Specifies the type of a webhook event. This can be used to determine what +action to take in response to the event, such as which relationships to +expect. +*/ +export enum WebhookEventTypeEnum { + TRANSACTION_CREATED = "TRANSACTION_CREATED", + TRANSACTION_SETTLED = "TRANSACTION_SETTLED", + TRANSACTION_DELETED = "TRANSACTION_DELETED", + PING = "PING", +} + +/** +* Provides the event data used in asynchronous webhook event callbacks to +subscribed endpoints. Webhooks events have defined `eventType`s and may +optionally relate to other resources within the Up API. +*/ +export interface WebhookEventResource { + /** The type of this resource: `webhook-events` */ + type: string; + + /** + * The unique identifier for this event. This will remain constant across + * delivery retries. + * + */ + id: string; + attributes: { eventType?: WebhookEventTypeEnum; createdAt?: string }; + relationships: { + webhook: { data: { type?: string; id?: string }; links: { related: string } }; + transaction: { data: { type?: string; id?: string }; links: { related: string } }; + }; +} + +/** + * Asynchronous callback request used for webhook event delivery. + */ +export interface WebhookEventCallback { + /** + * The webhook event data sent to the subscribed webhook. + * + */ + data: WebhookEventResource; +} + +/** + * Successful response to get a single webhook. + */ +export interface GetWebhookResponse { + /** + * The webhook returned in this response. + * + */ + data: WebhookResource; +} + +/** +* Specifies the nature of the success or failure of a webhook delivery +attempt to the subscribed webhook URL. The currently returned values are +described below: + +- **`DELIVERED`**: The event was delivered to the webhook URL + successfully and a `200` response was received. +- **`UNDELIVERABLE`**: The webhook URL was not reachable, or timed out. +- **`BAD_RESPONSE_CODE`**: The event was delivered to the webhook URL + but a non-`200` response was received. +*/ +export enum WebhookDeliveryStatusEnum { + DELIVERED = "DELIVERED", + UNDELIVERABLE = "UNDELIVERABLE", + BAD_RESPONSE_CODE = "BAD_RESPONSE_CODE", +} + +/** +* Provides historical webhook event delivery information for analysis and +debugging purposes. +*/ +export interface WebhookDeliveryLogResource { + /** The type of this resource: `webhook-delivery-logs` */ + type: string; + + /** + * The unique identifier for this log entry. + * + */ + id: string; + attributes: { + request: { body: string }; + response: { statusCode: number; body: string }; + deliveryStatus?: WebhookDeliveryStatusEnum; + createdAt?: string; + }; + relationships: { webhookEvent: { data: { type?: string; id?: string } } }; +} + +/** +* Successful response to get all delivery logs for a webhook. This returns +a paginated list of delivery logs, which can be scrolled by following the +`next` and `prev` links if present. +*/ +export interface ListWebhookDeliveryLogsResponse { + /** + * The list of delivery logs returned in this response. + * + */ + data: WebhookDeliveryLogResource[]; + links: { prev?: string | null; next?: string | null }; +} + +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ + secure?: boolean; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} + +export type RequestParams = Omit; + +interface ApiConfig { + baseUrl?: string; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; +} + +interface HttpResponse extends Response { + data: D; + error: E; +} + +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", +} + +export class HttpClient { + public baseUrl: string = "https://api.up.com.au/api/v1"; + private securityData: SecurityDataType = null as any; + private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); + + private baseApiParams: RequestParams = { + credentials: "same-origin", + headers: {}, + redirect: "follow", + referrerPolicy: "no-referrer", + }; + + constructor(apiConfig: ApiConfig = {}) { + Object.assign(this, apiConfig); + } + + public setSecurityData = (data: SecurityDataType) => { + this.securityData = data; + }; + + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + + return ( + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) + ); + } + + protected toQueryString(rawQuery?: QueryParamsType): string { + const query = rawQuery || {}; + const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); + return keys + .map((key) => + typeof query[key] === "object" && !Array.isArray(query[key]) + ? this.toQueryString(query[key] as QueryParamsType) + : this.addQueryParam(query, key), + ) + .join("&"); + } + + protected addQueryParams(rawQuery?: QueryParamsType): string { + const queryString = this.toQueryString(rawQuery); + return queryString ? `?${queryString}` : ""; + } + + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { + data.append(key, input[key]); + return data; + }, new FormData()), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), + }; + + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { + return { + ...this.baseApiParams, + ...params1, + ...(params2 || {}), + headers: { + ...(this.baseApiParams.headers || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), + }, + }; + } + + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; + }; + + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } + + if (!response.ok) throw data; + return data; + }); + }; +} + +/** + * @title Up API + * @version v1 + * @baseUrl https://api.up.com.au/api/v1 + * The Up API gives you programmatic access to your balances and + * transaction data. You can request past transactions or set up + * webhooks to receive real-time events when new transactions hit your + * account. It’s new, it’s exciting and it’s just the beginning. + */ +export class Api extends HttpClient { + accounts = { + /** + * @description Retrieve a paginated list of all accounts for the currently authenticated user. The returned list is paginated and can be scrolled by following the `prev` and `next` links where present. + * + * @tags Accounts + * @name AccountsList + * @summary List accounts + * @request GET:/accounts + * @secure + */ + accountsList: (query?: { "page[size]"?: number }, params: RequestParams = {}) => + this.request({ + path: `/accounts`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + + /** + * @description Retrieve a specific account by providing its unique identifier. + * + * @tags Accounts + * @name AccountsDetail + * @summary Retrieve account + * @request GET:/accounts/{id} + * @secure + */ + accountsDetail: (id: string, params: RequestParams = {}) => + this.request({ + path: `/accounts/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), + + /** + * @description Retrieve a list of all transactions for a specific account. The returned list is [paginated](#pagination) and can be scrolled by following the `next` and `prev` links where present. To narrow the results to a specific date range pass one or both of `filter[since]` and `filter[until]` in the query string. These filter parameters **should not** be used for pagination. Results are ordered newest first to oldest last. + * + * @tags Transactions + * @name TransactionsDetail + * @summary List transactions by account + * @request GET:/accounts/{accountId}/transactions + * @secure + */ + transactionsDetail: ( + accountId: string, + query?: { + "page[size]"?: number; + "filter[status]"?: TransactionStatusEnum; + "filter[since]"?: string; + "filter[until]"?: string; + "filter[category]"?: string; + "filter[tag]"?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/accounts/${accountId}/transactions`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + }; + categories = { + /** + * @description Retrieve a list of all categories and their ancestry. The returned list is not paginated. + * + * @tags Categories + * @name CategoriesList + * @summary List categories + * @request GET:/categories + * @secure + */ + categoriesList: (query?: { "filter[parent]"?: string }, params: RequestParams = {}) => + this.request({ + path: `/categories`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + + /** + * @description Retrieve a specific category by providing its unique identifier. + * + * @tags Categories + * @name CategoriesDetail + * @summary Retrieve category + * @request GET:/categories/{id} + * @secure + */ + categoriesDetail: (id: string, params: RequestParams = {}) => + this.request({ + path: `/categories/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), + }; + util = { + /** + * @description Make a basic ping request to the API. This is useful to verify that authentication is functioning correctly. On authentication success an HTTP `200` status is returned. On failure an HTTP `401` error response is returned. + * + * @tags Utility endpoints + * @name PingList + * @summary Ping + * @request GET:/util/ping + * @secure + */ + pingList: (params: RequestParams = {}) => + this.request({ + path: `/util/ping`, + method: "GET", + secure: true, + format: "json", + ...params, + }), + }; + tags = { + /** + * @description Retrieve a list of all tags currently in use. The returned list is [paginated](#pagination) and can be scrolled by following the `next` and `prev` links where present. Results are ordered lexicographically. The `transactions` relationship for each tag exposes a link to get the transactions with the given tag. + * + * @tags Tags + * @name TagsList + * @summary List tags + * @request GET:/tags + * @secure + */ + tagsList: (query?: { "page[size]"?: number }, params: RequestParams = {}) => + this.request({ + path: `/tags`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + }; + transactions = { + /** + * @description Associates one or more tags with a specific transaction. No more than 6 tags may be present on any single transaction. Duplicate tags are silently ignored. An HTTP `204` is returned on success. The associated tags, along with this request URL, are also exposed via the `tags` relationship on the transaction resource returned from `/transactions/{id}`. + * + * @tags Tags + * @name RelationshipsTagsCreate + * @summary Add tags to transaction + * @request POST:/transactions/{transactionId}/relationships/tags + * @secure + */ + relationshipsTagsCreate: (transactionId: string, data: UpdateTransactionTagsRequest, params: RequestParams = {}) => + this.request({ + path: `/transactions/${transactionId}/relationships/tags`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + ...params, + }), + + /** + * @description Disassociates one or more tags from a specific transaction. Tags that are not associated are silently ignored. An HTTP `204` is returned on success. The associated tags, along with this request URL, are also exposed via the `tags` relationship on the transaction resource returned from `/transactions/{id}`. + * + * @tags Tags + * @name RelationshipsTagsDelete + * @summary Remove tags from transaction + * @request DELETE:/transactions/{transactionId}/relationships/tags + * @secure + */ + relationshipsTagsDelete: (transactionId: string, data: UpdateTransactionTagsRequest, params: RequestParams = {}) => + this.request({ + path: `/transactions/${transactionId}/relationships/tags`, + method: "DELETE", + body: data, + secure: true, + type: ContentType.Json, + ...params, + }), + + /** + * @description Retrieve a list of all transactions across all accounts for the currently authenticated user. The returned list is [paginated](#pagination) and can be scrolled by following the `next` and `prev` links where present. To narrow the results to a specific date range pass one or both of `filter[since]` and `filter[until]` in the query string. These filter parameters **should not** be used for pagination. Results are ordered newest first to oldest last. + * + * @tags Transactions + * @name TransactionsList + * @summary List transactions + * @request GET:/transactions + * @secure + */ + transactionsList: ( + query?: { + "page[size]"?: number; + "filter[status]"?: TransactionStatusEnum; + "filter[since]"?: string; + "filter[until]"?: string; + "filter[category]"?: string; + "filter[tag]"?: string; + }, + params: RequestParams = {}, + ) => + this.request({ + path: `/transactions`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + + /** + * @description Retrieve a specific transaction by providing its unique identifier. + * + * @tags Transactions + * @name TransactionsDetail + * @summary Retrieve transaction + * @request GET:/transactions/{id} + * @secure + */ + transactionsDetail: (id: string, params: RequestParams = {}) => + this.request({ + path: `/transactions/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), + }; + webhooks = { + /** + * @description Retrieve a list of configured webhooks. The returned list is [paginated](#pagination) and can be scrolled by following the `next` and `prev` links where present. Results are ordered oldest first to newest last. + * + * @tags Webhooks + * @name WebhooksList + * @summary List webhooks + * @request GET:/webhooks + * @secure + */ + webhooksList: (query?: { "page[size]"?: number }, params: RequestParams = {}) => + this.request({ + path: `/webhooks`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + + /** + * @description Create a new webhook with a given URL. The URL will receive webhook events as JSON-encoded `POST` requests. The URL must respond with a HTTP `200` status on success. There is currently a limit of 10 webhooks at any given time. Once this limit is reached, existing webhooks will need to be deleted before new webhooks can be created. Event delivery is retried with exponential backoff if the URL is unreachable or it does not respond with a `200` status. The response includes a `secretKey` attribute, which is used to sign requests sent to the webhook URL. It will not be returned from any other endpoints within the Up API. If the `secretKey` is lost, simply create a new webhook with the same URL, capture its `secretKey` and then delete the original webhook. See [Handling webhook events](#callback_post_webhookURL) for details on how to process webhook events. It is probably a good idea to test the webhook by [sending it a `PING` event](#post_webhooks_webhookId_ping) after creating it. + * + * @tags Webhooks + * @name WebhooksCreate + * @summary Create webhook + * @request POST:/webhooks + * @secure + */ + webhooksCreate: (data: CreateWebhookRequest, params: RequestParams = {}) => + this.request({ + path: `/webhooks`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), + + /** + * @description Retrieve a specific webhook by providing its unique identifier. + * + * @tags Webhooks + * @name WebhooksDetail + * @summary Retrieve webhook + * @request GET:/webhooks/{id} + * @secure + */ + webhooksDetail: (id: string, params: RequestParams = {}) => + this.request({ + path: `/webhooks/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), + + /** + * @description Delete a specific webhook by providing its unique identifier. Once deleted, webhook events will no longer be sent to the configured URL. + * + * @tags Webhooks + * @name WebhooksDelete + * @summary Delete webhook + * @request DELETE:/webhooks/{id} + * @secure + */ + webhooksDelete: (id: string, params: RequestParams = {}) => + this.request({ + path: `/webhooks/${id}`, + method: "DELETE", + secure: true, + ...params, + }), + + /** + * @description Send a `PING` event to a webhook by providing its unique identifier. This is useful for testing and debugging purposes. The event is delivered asynchronously and its data is returned in the response to this request. + * + * @tags Webhooks + * @name PingCreate + * @summary Ping webhook + * @request POST:/webhooks/{webhookId}/ping + * @secure + */ + pingCreate: (webhookId: string, params: RequestParams = {}) => + this.request({ + path: `/webhooks/${webhookId}/ping`, + method: "POST", + secure: true, + format: "json", + ...params, + }), + + /** + * @description Retrieve a list of delivery logs for a webhook by providing its unique identifier. This is useful for analysis and debugging purposes. The returned list is [paginated](#pagination) and can be scrolled by following the `next` and `prev` links where present. Results are ordered newest first to oldest last. Logs may be automatically purged after a period of time. + * + * @tags Webhooks + * @name LogsDetail + * @summary List webhook logs + * @request GET:/webhooks/{webhookId}/logs + * @secure + */ + logsDetail: (webhookId: string, query?: { "page[size]"?: number }, params: RequestParams = {}) => + this.request({ + path: `/webhooks/${webhookId}/logs`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), + }; +} diff --git a/tests/generated/v3.0/uspto.ts b/tests/generated/v3.0/uspto.ts index 132f25e6..22066aff 100644 --- a/tests/generated/v3.0/uspto.ts +++ b/tests/generated/v3.0/uspto.ts @@ -26,16 +26,34 @@ export interface DataSetList { apis?: { apiKey?: string; apiVersionNumber?: string; apiUrl?: string; apiDocumentationUrl?: string }[]; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -43,22 +61,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "{scheme}://developer.uspto.gov/ds-api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -71,92 +90,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -169,7 +222,7 @@ export class HttpClient { * @baseUrl {scheme}://developer.uspto.gov/ds-api * The Data Set API (DSAPI) allows the public users to discover and search USPTO exported data sets. This is a generic API that allows USPTO users to make any CSV based data files searchable through API. With the help of GET call, it returns the list of data fields that are searchable. With the help of POST call, data can be fetched based on the filters on the field names. Please note that POST call is used to search the actual data. The reason for the POST call is that it allows users to specify any complex search criteria without worry about the GET size limitations as well as encoding of the input parameters. */ -export class Api extends HttpClient { +export class Api extends HttpClient { /** * No description * @@ -178,7 +231,13 @@ export class Api extends HttpClient { * @summary List available data sets * @request GET:/ */ - listDataSets = (params?: RequestParams) => this.request(`/`, "GET", params); + listDataSets = (params: RequestParams = {}) => + this.request({ + path: `/`, + method: "GET", + format: "json", + ...params, + }); dataset = { /** @@ -189,8 +248,13 @@ export class Api extends HttpClient { * @summary Provides the general information about the API and the list of fields that can be used to query the dataset. * @request GET:/{dataset}/{version}/fields */ - listSearchableFields: (dataset: string, version: string, params?: RequestParams) => - this.request(`/${dataset}/${version}/fields`, "GET", params), + listSearchableFields: (dataset: string, version: string, params: RequestParams = {}) => + this.request({ + path: `/${dataset}/${version}/fields`, + method: "GET", + format: "json", + ...params, + }), /** * @description This API is based on Solr/Lucense Search. The data is indexed using SOLR. This GET API returns the list of all the searchable field names that are in the Solr Index. Please see the 'fields' attribute which returns an array of field names. Each field or a combination of fields can be searched using the Solr/Lucene Syntax. Please refer https://lucene.apache.org/core/3_6_2/queryparsersyntax.html#Overview for the query syntax. List of field names that are searchable can be determined using above GET api. @@ -204,14 +268,15 @@ export class Api extends HttpClient { version: string, dataset: string, data: { criteria: string; start?: number; rows?: number }, - params?: RequestParams, + params: RequestParams = {}, ) => - this.request[], any>( - `/${dataset}/${version}/records`, - "POST", - params, - data, - BodyType.UrlEncoded, - ), + this.request[], void>({ + path: `/${dataset}/${version}/records`, + method: "POST", + body: data, + type: ContentType.UrlEncoded, + format: "json", + ...params, + }), }; } diff --git a/tests/generated/v3.0/wrong-enum-subtypes.ts b/tests/generated/v3.0/wrong-enum-subtypes.ts index 11fc352a..0778b6a5 100644 --- a/tests/generated/v3.0/wrong-enum-subtypes.ts +++ b/tests/generated/v3.0/wrong-enum-subtypes.ts @@ -11,16 +11,34 @@ export type Test = { x?: "A-B"[] } & { y?: string }; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -28,22 +46,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = ""; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -56,92 +75,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -152,4 +205,4 @@ export class HttpClient { * @title Test * @version test */ -export class Api extends HttpClient {} +export class Api extends HttpClient {} diff --git a/tests/schemas/v2.0/authentiq.json b/tests/schemas/v2.0/authentiq.json index ca95491f..d60511d3 100644 --- a/tests/schemas/v2.0/authentiq.json +++ b/tests/schemas/v2.0/authentiq.json @@ -84,6 +84,38 @@ } }, "paths": { + "/wrong-path-params1/{pathParam1}/{path_param2}/{path_param3}/:pathParam4": { + "delete": { + "description": "DDD", + "operationId": "wrong-path-params1", + "parameters": [], + "produces": ["application/json"], + "responses": { + "200": { "description": "Successfully deleted" } + }, + "tags": ["key", "delete"] + } + }, + "/wrong-path-params2": { + "delete": { + "description": "DDD", + "operationId": "wrong-path-params2", + "parameters": [ + { + "description": "DDD", + "in": "path", + "name": "path_param1", + "required": true, + "type": "string" + } + ], + "produces": ["application/json"], + "responses": { + "200": { "description": "Successfully deleted" } + }, + "tags": ["key", "delete"] + } + }, "/key": { "delete": { "description": "Revoke an Authentiq ID using email & phone.\n\nIf called with `email` and `phone` only, a verification code \nwill be sent by email. Do a second call adding `code` to \ncomplete the revocation.\n", diff --git a/tests/schemas/v3.0/up-banking.json b/tests/schemas/v3.0/up-banking.json new file mode 100644 index 00000000..5421f7ef --- /dev/null +++ b/tests/schemas/v3.0/up-banking.json @@ -0,0 +1,2764 @@ +{ + "openapi": "3.0.3", + "info": { + "title": "Up API", + "version": "v1", + "description": "The Up API gives you programmatic access to your balances and\ntransaction data. You can request past transactions or set up\nwebhooks to receive real-time events when new transactions hit your\naccount. It’s new, it’s exciting and it’s just the beginning.\n", + "contact": { + "name": "API Specification and Support", + "url": "https://github.com/up-banking/api" + } + }, + "servers": [ + { + "url": "https://api.up.com.au/api/v1" + } + ], + "components": { + "securitySchemes": { + "bearer_auth": { + "type": "http", + "scheme": "bearer" + } + }, + "schemas": { + "AccountTypeEnum": { + "enum": ["SAVER", "TRANSACTIONAL"], + "description": "Specifies the type of bank account. Currently returned values are `SAVER`\nand `TRANSACTIONAL`.\n" + }, + "MoneyObject": { + "type": "object", + "description": "Provides information about a value of money.\n", + "properties": { + "currencyCode": { + "type": "string", + "description": "The ISO 4217 currency code.\n" + }, + "value": { + "type": "string", + "description": "The amount of money, formatted as a string in the relevant currency.\nFor example, for an Australian dollar value of $10.56, this field will\nbe `\"10.56\"`. The currency symbol is not included in the string.\n" + }, + "valueInBaseUnits": { + "type": "integer", + "description": "The amount of money in the smallest denomination for the currency, as a\n64-bit integer. For example, for an Australian dollar value of $10.56,\nthis field will be `1056`.\n" + } + }, + "required": ["currencyCode", "value", "valueInBaseUnits"] + }, + "AccountResource": { + "type": "object", + "description": "Provides information about an Up bank account.\n", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `accounts`" + }, + "id": { + "type": "string", + "description": "The unique identifier for this account.\n" + }, + "attributes": { + "type": "object", + "properties": { + "displayName": { + "type": "string", + "description": "The name associated with the account in the Up application.\n" + }, + "accountType": { + "description": "The bank account type of this account.\n", + "allOf": [ + { + "$ref": "#/components/schemas/AccountTypeEnum" + } + ] + }, + "balance": { + "description": "The available balance of the account, taking into account any amounts\nthat are currently on hold.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "The date-time at which this account was first opened.\n" + } + }, + "required": ["displayName", "accountType", "balance", "createdAt"] + }, + "relationships": { + "type": "object", + "properties": { + "transactions": { + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + } + } + }, + "required": ["transactions"] + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "The canonical link to this resource within the API.\n" + } + }, + "required": ["self"] + } + }, + "required": ["type", "id", "attributes", "relationships"] + }, + "ListAccountsResponse": { + "type": "object", + "description": "Successful response to get all accounts. This returns a paginated list of\naccounts, which can be scrolled by following the `prev` and `next` links\nif present.\n", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/AccountResource" + }, + "description": "The list of accounts returned in this response.\n" + }, + "links": { + "type": "object", + "properties": { + "prev": { + "type": "string", + "nullable": true, + "description": "The link to the previous page in the results. If this value is `null`\nthere is no previous page.\n" + }, + "next": { + "type": "string", + "nullable": true, + "description": "The link to the next page in the results. If this value is `null`\nthere is no next page.\n" + } + }, + "required": ["prev", "next"] + } + }, + "required": ["data", "links"] + }, + "GetAccountResponse": { + "type": "object", + "description": "Successful response to get a single account.\n", + "properties": { + "data": { + "description": "The account returned in this response.\n", + "allOf": [ + { + "$ref": "#/components/schemas/AccountResource" + } + ] + } + }, + "required": ["data"] + }, + "CategoryResource": { + "type": "object", + "description": "Provides information about a category and its ancestry.\n", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `categories`" + }, + "id": { + "type": "string", + "description": "The unique identifier for this category. This is a human-readable but\nURL-safe value.\n" + }, + "attributes": { + "type": "object", + "properties": { + "name": { + "type": "string", + "description": "The name of this category as seen in the Up application.\n" + } + }, + "required": ["name"] + }, + "relationships": { + "type": "object", + "properties": { + "parent": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `categories`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"], + "nullable": true + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + }, + "required": ["data"] + }, + "children": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `categories`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"] + } + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + }, + "required": ["data"] + } + }, + "required": ["parent", "children"] + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "The canonical link to this resource within the API.\n" + } + }, + "required": ["self"] + } + }, + "required": ["type", "id", "attributes", "relationships"] + }, + "ListCategoriesResponse": { + "type": "object", + "description": "Successful response to get all categories and their ancestry. The\nreturned list is not paginated.\n", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/CategoryResource" + }, + "description": "The list of categories returned in this response.\n" + } + }, + "required": ["data"] + }, + "GetCategoryResponse": { + "type": "object", + "description": "Successful response to get a single category and its ancestry.\n", + "properties": { + "data": { + "description": "The category returned in this response.\n", + "allOf": [ + { + "$ref": "#/components/schemas/CategoryResource" + } + ] + } + }, + "required": ["data"] + }, + "PingResponse": { + "type": "object", + "description": "Basic ping response to verify authentication.\n", + "properties": { + "meta": { + "type": "object", + "properties": { + "id": { + "type": "string", + "description": "The unique identifier of the authenticated customer.\n" + }, + "statusEmoji": { + "type": "string", + "description": "A cute emoji that represents the response status.\n" + } + }, + "required": ["id", "statusEmoji"] + } + }, + "required": ["meta"] + }, + "ErrorObject": { + "type": "object", + "description": "Provides information about an error processing a request.\n", + "properties": { + "status": { + "type": "string", + "description": "The HTTP status code associated with this error. This can also be\nobtained from the response headers. The status indicates the broad type\nof error according to HTTP semantics.\n" + }, + "title": { + "type": "string", + "description": "A short description of this error. This should be stable across\nmultiple occurrences of this type of error and typically expands on the\nreason for the status code.\n" + }, + "detail": { + "type": "string", + "description": "A detailed description of this error. This should be considered unique\nto individual occurrences of an error and subject to change. It is\nuseful for debugging purposes.\n" + }, + "source": { + "type": "object", + "properties": { + "parameter": { + "type": "string", + "description": "If this error relates to a query parameter, the name of the\nparameter.\n" + }, + "pointer": { + "type": "string", + "description": "If this error relates to an attribute in the request body, a\nrfc-6901 JSON pointer to the attribute.\n" + } + }, + "description": "If applicable, location in the request that this error relates to. This\nmay be a parameter in the query string, or a an attribute in the\nrequest body.\n" + } + }, + "required": ["status", "title", "detail"] + }, + "ErrorResponse": { + "type": "object", + "description": "Generic error response that returns one or more errors.\n", + "properties": { + "errors": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ErrorObject" + }, + "description": "The list of errors returned in this response.\n" + } + }, + "required": ["errors"] + }, + "TagResource": { + "type": "object", + "description": "Provides information about a tag.\n", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `tags`" + }, + "id": { + "type": "string", + "description": "The label of the tag, which also acts as the tag’s unique identifier.\n" + }, + "relationships": { + "type": "object", + "properties": { + "transactions": { + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + } + } + }, + "required": ["transactions"] + } + }, + "required": ["type", "id", "relationships"] + }, + "ListTagsResponse": { + "type": "object", + "description": "Successful response to get all tags. This returns a paginated list of\ntags, which can be scrolled by following the `prev` and `next` links if\npresent.\n", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagResource" + }, + "description": "The list of tags returned in this response.\n" + }, + "links": { + "type": "object", + "properties": { + "prev": { + "type": "string", + "nullable": true, + "description": "The link to the previous page in the results. If this value is `null`\nthere is no previous page.\n" + }, + "next": { + "type": "string", + "nullable": true, + "description": "The link to the next page in the results. If this value is `null`\nthere is no next page.\n" + } + }, + "required": ["prev", "next"] + } + }, + "required": ["data", "links"] + }, + "TagInputResourceIdentifier": { + "type": "object", + "description": "Uniquely identifies a single tag in the API.\n", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `tags`" + }, + "id": { + "type": "string", + "description": "The label of the tag, which also acts as the tag’s unique identifier.\n" + } + }, + "required": ["type", "id"] + }, + "UpdateTransactionTagsRequest": { + "type": "object", + "description": "Request to add or remove tags associated with a transaction.\n", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TagInputResourceIdentifier" + }, + "description": "The tags to add to or remove from the transaction.\n" + } + }, + "required": ["data"] + }, + "TransactionStatusEnum": { + "enum": ["HELD", "SETTLED"], + "description": "Specifies which stage of processing a transaction is currently at.\nCurrently returned values are `HELD` and `SETTLED`. When a transaction is\nheld, its account’s `availableBalance` is affected. When a transaction is\nsettled, its account’s `currentBalance` is affected.\n" + }, + "HoldInfoObject": { + "type": "object", + "description": "Provides information about the amount at which a transaction was in the\n`HELD` status.\n", + "properties": { + "amount": { + "description": "The amount of this transaction while in the `HELD` status, in\nAustralian dollars.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + }, + "foreignAmount": { + "nullable": true, + "description": "The foreign currency amount of this transaction while in the `HELD`\nstatus. This field will be `null` for domestic transactions. The amount\nwas converted to the AUD amount reflected in the `amount` field.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + } + }, + "required": ["amount", "foreignAmount"] + }, + "RoundUpObject": { + "type": "object", + "description": "Provides information about how a Round Up was applied, such as whether or\nnot a boost was included in the Round Up.\n", + "properties": { + "amount": { + "description": "The total amount of this Round Up, including any boosts, represented as\na negative value.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + }, + "boostPortion": { + "nullable": true, + "description": "The portion of the Round Up `amount` owing to boosted Round Ups,\nrepresented as a negative value. If no boost was added to the Round Up\nthis field will be `null`.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + } + }, + "required": ["amount", "boostPortion"] + }, + "CashbackObject": { + "type": "object", + "description": "Provides information about an instant reimbursement in the form of\ncashback.\n", + "properties": { + "description": { + "type": "string", + "description": "A brief description of why this cashback was paid.\n" + }, + "amount": { + "description": "The total amount of cashback paid, represented as a positive value.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + } + }, + "required": ["description", "amount"] + }, + "TransactionResource": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `transactions`" + }, + "id": { + "type": "string", + "description": "The unique identifier for this transaction.\n" + }, + "attributes": { + "type": "object", + "properties": { + "status": { + "description": "The current processing status of this transaction, according to\nwhether or not this transaction has settled or is still held.\n", + "allOf": [ + { + "$ref": "#/components/schemas/TransactionStatusEnum" + } + ] + }, + "rawText": { + "type": "string", + "nullable": true, + "description": "The original, unprocessed text of the transaction. This is often not\na perfect indicator of the actual merchant, but it is useful for\nreconciliation purposes in some cases.\n" + }, + "description": { + "type": "string", + "description": "A short description for this transaction. Usually the merchant name\nfor purchases.\n" + }, + "message": { + "type": "string", + "nullable": true, + "description": "Attached message for this transaction, such as a payment message, or a\ntransfer note.\n" + }, + "holdInfo": { + "nullable": true, + "description": "If this transaction is currently in the `HELD` status, or was ever in\nthe `HELD` status, the `amount` and `foreignAmount` of the\ntransaction while `HELD`.\n", + "allOf": [ + { + "$ref": "#/components/schemas/HoldInfoObject" + } + ] + }, + "roundUp": { + "nullable": true, + "description": "Details of how this transaction was rounded-up. If no Round Up was\napplied this field will be `null`.\n", + "allOf": [ + { + "$ref": "#/components/schemas/RoundUpObject" + } + ] + }, + "cashback": { + "nullable": true, + "description": "If all or part of this transaction was instantly reimbursed in the\nform of cashback, details of the reimbursement.\n", + "allOf": [ + { + "$ref": "#/components/schemas/CashbackObject" + } + ] + }, + "amount": { + "description": "The amount of this transaction in Australian dollars. For\ntransactions that were once `HELD` but are now `SETTLED`, refer to\nthe `holdInfo` field for the original `amount` the transaction was\n`HELD` at.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + }, + "foreignAmount": { + "nullable": true, + "description": "The foreign currency amount of this transaction. This field will be\n`null` for domestic transactions. The amount was converted to the AUD\namount reflected in the `amount` of this transaction. Refer to the\n`holdInfo` field for the original `foreignAmount` the transaction was\n`HELD` at.\n", + "allOf": [ + { + "$ref": "#/components/schemas/MoneyObject" + } + ] + }, + "settledAt": { + "type": "string", + "format": "date-time", + "nullable": true, + "description": "The date-time at which this transaction settled. This field will be\n`null` for transactions that are currently in the `HELD` status.\n" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "The date-time at which this transaction was first encountered.\n" + } + }, + "required": [ + "status", + "rawText", + "description", + "message", + "holdInfo", + "roundUp", + "cashback", + "amount", + "foreignAmount", + "settledAt", + "createdAt" + ] + }, + "relationships": { + "type": "object", + "properties": { + "account": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `accounts`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"] + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + }, + "required": ["data"] + }, + "category": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `categories`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"], + "nullable": true + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + }, + "required": ["data"] + }, + "parentCategory": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `categories`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"], + "nullable": true + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + }, + "required": ["data"] + }, + "tags": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `tags`" + }, + "id": { + "type": "string", + "description": "The label of the tag, which also acts as the tag’s unique identifier.\n" + } + }, + "required": ["type", "id"] + } + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "The link to retrieve or modify linkage between this resources and the\nrelated resource(s) in this relationship.\n" + } + }, + "required": ["self"] + } + }, + "required": ["data"] + } + }, + "required": ["account", "category", "parentCategory", "tags"] + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "The canonical link to this resource within the API.\n" + } + }, + "required": ["self"] + } + }, + "required": ["type", "id", "attributes", "relationships"] + }, + "ListTransactionsResponse": { + "type": "object", + "description": "Successful response to get all transactions. This returns a paginated\nlist of transactions, which can be scrolled by following the `prev` and\n`next` links if present.\n", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TransactionResource" + }, + "description": "The list of transactions returned in this response.\n" + }, + "links": { + "type": "object", + "properties": { + "prev": { + "type": "string", + "nullable": true, + "description": "The link to the previous page in the results. If this value is `null`\nthere is no previous page.\n" + }, + "next": { + "type": "string", + "nullable": true, + "description": "The link to the next page in the results. If this value is `null`\nthere is no next page.\n" + } + }, + "required": ["prev", "next"] + } + }, + "required": ["data", "links"] + }, + "GetTransactionResponse": { + "type": "object", + "description": "Successful response to get a single transaction.\n", + "properties": { + "data": { + "description": "The transaction returned in this response.\n", + "allOf": [ + { + "$ref": "#/components/schemas/TransactionResource" + } + ] + } + }, + "required": ["data"] + }, + "WebhookResource": { + "type": "object", + "description": "Provides information about a webhook.\n", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `webhooks`" + }, + "id": { + "type": "string", + "description": "The unique identifier for this webhook.\n" + }, + "attributes": { + "type": "object", + "properties": { + "url": { + "type": "string", + "description": "The URL that this webhook is configured to `POST` events to.\n" + }, + "description": { + "type": "string", + "nullable": true, + "description": "An optional description that was provided at the time the webhook was\ncreated.\n" + }, + "secretKey": { + "type": "string", + "description": "A shared secret key used to sign all webhook events sent to the\nconfigured webhook URL. This field is returned only once, upon the\ninitial creation of the webhook. If lost, create a new webhook and\ndelete this webhook.\n\nThe webhook URL receives a request with a\n`X-Up-Authenticity-Signature` header, which is the SHA-256 HMAC of\nthe entire raw request body signed using this `secretKey`. It is\nadvised to compute and check this signature to verify the\nauthenticity of requests sent to the webhook URL. See\n[Handling webhook events](#callback_post_webhookURL) for full\ndetails.\n" + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "The date-time at which this webhook was created.\n" + } + }, + "required": ["url", "description", "createdAt"] + }, + "relationships": { + "type": "object", + "properties": { + "logs": { + "type": "object", + "properties": { + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + } + } + }, + "required": ["logs"] + }, + "links": { + "type": "object", + "properties": { + "self": { + "type": "string", + "description": "The canonical link to this resource within the API.\n" + } + }, + "required": ["self"] + } + }, + "required": ["type", "id", "attributes", "relationships"] + }, + "ListWebhooksResponse": { + "type": "object", + "description": "Successful response to get all webhooks. This returns a paginated list of\nwebhooks, which can be scrolled by following the `prev` and `next` links\nif present.\n", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookResource" + }, + "description": "The list of webhooks returned in this response.\n" + }, + "links": { + "type": "object", + "properties": { + "prev": { + "type": "string", + "nullable": true, + "description": "The link to the previous page in the results. If this value is `null`\nthere is no previous page.\n" + }, + "next": { + "type": "string", + "nullable": true, + "description": "The link to the next page in the results. If this value is `null`\nthere is no next page.\n" + } + }, + "required": ["prev", "next"] + } + }, + "required": ["data", "links"] + }, + "WebhookInputResource": { + "type": "object", + "description": "Represents a webhook specified as request input.\n", + "properties": { + "attributes": { + "type": "object", + "properties": { + "url": { + "type": "string", + "format": "uri", + "description": "The URL that this webhook should post events to. This must be a valid\nHTTP or HTTPS URL that does not exceed 300 characters in length.\n" + }, + "description": { + "type": "string", + "nullable": true, + "description": "An optional description for this webhook, up to 64 characters in\nlength.\n" + } + }, + "required": ["url"] + } + }, + "required": ["attributes"] + }, + "CreateWebhookRequest": { + "type": "object", + "description": "Request to create a new webhook. This currently only requires a `url`\nattribute.\n", + "properties": { + "data": { + "description": "The webhook resource to create.\n", + "allOf": [ + { + "$ref": "#/components/schemas/WebhookInputResource" + } + ] + } + }, + "required": ["data"] + }, + "CreateWebhookResponse": { + "type": "object", + "description": "Successful response after creating a webhook.\n", + "properties": { + "data": { + "description": "The webhook that was created.\n", + "allOf": [ + { + "$ref": "#/components/schemas/WebhookResource" + } + ] + } + }, + "required": ["data"] + }, + "WebhookEventTypeEnum": { + "enum": ["TRANSACTION_CREATED", "TRANSACTION_SETTLED", "TRANSACTION_DELETED", "PING"], + "description": "Specifies the type of a webhook event. This can be used to determine what\naction to take in response to the event, such as which relationships to\nexpect.\n" + }, + "WebhookEventResource": { + "type": "object", + "description": "Provides the event data used in asynchronous webhook event callbacks to\nsubscribed endpoints. Webhooks events have defined `eventType`s and may\noptionally relate to other resources within the Up API.\n", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `webhook-events`" + }, + "id": { + "type": "string", + "description": "The unique identifier for this event. This will remain constant across\ndelivery retries.\n" + }, + "attributes": { + "type": "object", + "properties": { + "eventType": { + "description": "The type of this event. This can be used to determine what action to\ntake in response to the event.\n", + "allOf": [ + { + "$ref": "#/components/schemas/WebhookEventTypeEnum" + } + ] + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "The date-time at which this event was generated.\n" + } + }, + "required": ["eventType", "createdAt"] + }, + "relationships": { + "type": "object", + "properties": { + "webhook": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `webhooks`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"] + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + }, + "required": ["data"] + }, + "transaction": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `transactions`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"] + }, + "links": { + "type": "object", + "properties": { + "related": { + "type": "string", + "description": "The link to retrieve the related resource(s) in this relationship.\n" + } + }, + "required": ["related"] + } + }, + "required": ["data"] + } + }, + "required": ["webhook"] + } + }, + "required": ["type", "id", "attributes", "relationships"] + }, + "WebhookEventCallback": { + "type": "object", + "description": "Asynchronous callback request used for webhook event delivery.\n", + "properties": { + "data": { + "description": "The webhook event data sent to the subscribed webhook.\n", + "allOf": [ + { + "$ref": "#/components/schemas/WebhookEventResource" + } + ] + } + }, + "required": ["data"] + }, + "GetWebhookResponse": { + "type": "object", + "description": "Successful response to get a single webhook.\n", + "properties": { + "data": { + "description": "The webhook returned in this response.\n", + "allOf": [ + { + "$ref": "#/components/schemas/WebhookResource" + } + ] + } + }, + "required": ["data"] + }, + "WebhookDeliveryStatusEnum": { + "enum": ["DELIVERED", "UNDELIVERABLE", "BAD_RESPONSE_CODE"], + "description": "Specifies the nature of the success or failure of a webhook delivery\nattempt to the subscribed webhook URL. The currently returned values are\ndescribed below:\n\n- **`DELIVERED`**: The event was delivered to the webhook URL\n successfully and a `200` response was received.\n- **`UNDELIVERABLE`**: The webhook URL was not reachable, or timed out.\n- **`BAD_RESPONSE_CODE`**: The event was delivered to the webhook URL\n but a non-`200` response was received.\n" + }, + "WebhookDeliveryLogResource": { + "type": "object", + "description": "Provides historical webhook event delivery information for analysis and\ndebugging purposes.\n", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `webhook-delivery-logs`" + }, + "id": { + "type": "string", + "description": "The unique identifier for this log entry.\n" + }, + "attributes": { + "type": "object", + "properties": { + "request": { + "type": "object", + "properties": { + "body": { + "type": "string", + "description": "The payload that was sent in the request body.\n" + } + }, + "required": ["body"], + "description": "Information about the request that was sent to the webhook URL.\n" + }, + "response": { + "type": "object", + "properties": { + "statusCode": { + "type": "integer", + "description": "The HTTP status code received in the response.\n" + }, + "body": { + "type": "string", + "description": "The payload that was received in the response body.\n" + } + }, + "required": ["statusCode", "body"], + "nullable": true, + "description": "Information about the response that was received from the webhook URL.\n" + }, + "deliveryStatus": { + "description": "The success or failure status of this delivery attempt.\n", + "allOf": [ + { + "$ref": "#/components/schemas/WebhookDeliveryStatusEnum" + } + ] + }, + "createdAt": { + "type": "string", + "format": "date-time", + "description": "The date-time at which this log entry was created.\n" + } + }, + "required": ["request", "response", "deliveryStatus", "createdAt"] + }, + "relationships": { + "type": "object", + "properties": { + "webhookEvent": { + "type": "object", + "properties": { + "data": { + "type": "object", + "properties": { + "type": { + "type": "string", + "description": "The type of this resource: `webhook-events`" + }, + "id": { + "type": "string", + "description": "The unique identifier of the resource within its type.\n" + } + }, + "required": ["type", "id"] + } + }, + "required": ["data"] + } + }, + "required": ["webhookEvent"] + } + }, + "required": ["type", "id", "attributes", "relationships"] + }, + "ListWebhookDeliveryLogsResponse": { + "type": "object", + "description": "Successful response to get all delivery logs for a webhook. This returns\na paginated list of delivery logs, which can be scrolled by following the\n`next` and `prev` links if present.\n", + "properties": { + "data": { + "type": "array", + "items": { + "$ref": "#/components/schemas/WebhookDeliveryLogResource" + }, + "description": "The list of delivery logs returned in this response.\n" + }, + "links": { + "type": "object", + "properties": { + "prev": { + "type": "string", + "nullable": true, + "description": "The link to the previous page in the results. If this value is `null`\nthere is no previous page.\n" + }, + "next": { + "type": "string", + "nullable": true, + "description": "The link to the next page in the results. If this value is `null`\nthere is no next page.\n" + } + }, + "required": ["prev", "next"] + } + }, + "required": ["data", "links"] + } + } + }, + "security": [ + { + "bearer_auth": [] + } + ], + "tags": [ + { + "name": "Accounts", + "description": "Accounts represent the underlying store used to track balances\nand the transactions that have occurred to modify those balances\nover time. Up currently has two types of account: `SAVER`—used to\nearn interest and to hit savings goals, and `TRANSACTIONAL`—used\nfor everyday spending.\n" + }, + { + "name": "Categories", + "description": "Categories enable understanding where your money goes by driving\npowerful insights in Up. All categories in Up are pre-defined\nand are automatically assigned to new purchases in most cases. A\nparent-child relationship is used to represent categories,\nhowever parent categories cannot be directly assigned to\ntransactions.\n" + }, + { + "name": "Tags", + "description": "Tags are custom labels that can be associated with transactions\non Up. Within the Up application, tags provide additional insight\ninto spending. For example, you could have a \"Take Away\" tag that\nyou apply to purchases from food delivery services. The Up API\nallows you to manage the tags associated with transactions. Each\ntransaction may have up to 6 tags.\n\nTags are identified by their labels, which are unique strings,\nso the tag \"Holiday\" has also the `id` `\"Holiday\"`.\n" + }, + { + "name": "Transactions", + "description": "Transactions represent the movement of money into and out of an\naccount. They have many characteristics that vary depending on\nthe kind of transaction. Transactions may be temporarily `HELD`\n(pending) or `SETTLED`, typically depending on which payment\nmethod was used at the point of sale.\n" + }, + { + "name": "Utility endpoints", + "description": "Some endpoints exist not to expose data, but to test the API\nitself. Currently there is only one endpoint in this group: ping!\n" + }, + { + "name": "Webhooks", + "description": "Webhooks provide a mechanism for a configured URL to receive\nevents when transaction activity occurs on Up. You can think of\nwebhooks as being like push notifications for your server-side\napplication.\n" + } + ], + "paths": { + "/accounts": { + "get": { + "tags": ["Accounts"], + "summary": "List accounts", + "description": "Retrieve a paginated list of all accounts for the currently\nauthenticated user. The returned list is paginated and can be scrolled\nby following the `prev` and `next` links where present.\n", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "schema": { + "type": "integer" + }, + "required": false, + "example": 30, + "description": "The number of records to return in each page.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListAccountsResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:HIvThbob76kGCuol" + }, + "pathParameters": {}, + "queryParameters": { + "page[size]": 1 + }, + "payload": null + }, + "response": { + "data": [ + { + "type": "accounts", + "id": "e0746933-045d-4c1b-a0b2-938d3e587583", + "attributes": { + "displayName": "Up Account", + "accountType": "TRANSACTIONAL", + "balance": { + "currencyCode": "AUD", + "value": "1.00", + "valueInBaseUnits": 100 + }, + "createdAt": "2020-09-04T13:37:07+10:00" + }, + "relationships": { + "transactions": { + "links": { + "related": "https://api.up.com.au/api/v1/accounts/e0746933-045d-4c1b-a0b2-938d3e587583/transactions" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/accounts/e0746933-045d-4c1b-a0b2-938d3e587583" + } + } + ], + "links": { + "prev": null, + "next": "https://api.up.com.au/api/v1/accounts?page%5Bafter%5D=WyIyMDIwLTA5LTA0VDAzOjM3OjA3Ljg3MDU4MTAwMFoiLCJlMDc0NjkzMy0wNDVkLTRjMWItYTBiMi05MzhkM2U1ODc1ODMiXQ%3D%3D&page%5Bsize%5D=1" + } + } + } + } + } + } + }, + "/accounts/{id}": { + "get": { + "tags": ["Accounts"], + "summary": "Retrieve account", + "description": "Retrieve a specific account by providing its unique identifier.\n", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "9842e43e-a1f9-4460-a252-364c86df2d3e", + "description": "The unique identifier for the account.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetAccountResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:orwRnj3vlo9ZTw8c" + }, + "pathParameters": { + "id": "66938e72-9d80-4b91-99bf-281ce20b161a" + }, + "queryParameters": {}, + "payload": null + }, + "response": { + "data": { + "type": "accounts", + "id": "66938e72-9d80-4b91-99bf-281ce20b161a", + "attributes": { + "displayName": "🐷 Savings", + "accountType": "SAVER", + "balance": { + "currencyCode": "AUD", + "value": "125.36", + "valueInBaseUnits": 12536 + }, + "createdAt": "2020-09-04T13:37:09+10:00" + }, + "relationships": { + "transactions": { + "links": { + "related": "https://api.up.com.au/api/v1/accounts/66938e72-9d80-4b91-99bf-281ce20b161a/transactions" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/accounts/66938e72-9d80-4b91-99bf-281ce20b161a" + } + } + } + } + } + } + } + }, + "/categories": { + "get": { + "tags": ["Categories"], + "summary": "List categories", + "description": "Retrieve a list of all categories and their ancestry. The returned list\nis not paginated.\n", + "parameters": [ + { + "name": "filter[parent]", + "in": "query", + "schema": { + "type": "string" + }, + "required": false, + "example": "good-life", + "description": "The unique identifier of a parent category for which to\nreturn only its children. Providing an invalid category\nidentifier results in a `404` response.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListCategoriesResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:NbylCaQt4uXPoAdn" + }, + "pathParameters": {}, + "queryParameters": { + "filter[parent]": "good-life" + }, + "payload": null + }, + "response": { + "data": [ + { + "type": "categories", + "id": "hobbies", + "attributes": { + "name": "Hobbies" + }, + "relationships": { + "parent": { + "data": { + "type": "categories", + "id": "good-life" + }, + "links": { + "related": "https://api.up.com.au/api/v1/categories/good-life" + } + }, + "children": { + "data": [], + "links": { + "related": "https://api.up.com.au/api/v1/categories?filter%5Bparent%5D=hobbies" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/categories/hobbies" + } + }, + { + "type": "categories", + "id": "restaurants-and-cafes", + "attributes": { + "name": "Restaurants & Cafes" + }, + "relationships": { + "parent": { + "data": { + "type": "categories", + "id": "good-life" + }, + "links": { + "related": "https://api.up.com.au/api/v1/categories/good-life" + } + }, + "children": { + "data": [], + "links": { + "related": "https://api.up.com.au/api/v1/categories?filter%5Bparent%5D=restaurants-and-cafes" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/categories/restaurants-and-cafes" + } + } + ] + } + } + } + } + } + }, + "/categories/{id}": { + "get": { + "tags": ["Categories"], + "summary": "Retrieve category", + "description": "Retrieve a specific category by providing its unique identifier.\n", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "restaurants-and-cafes", + "description": "The unique identifier for the category.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetCategoryResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:z1uQ6Ph1KhcWXcn1" + }, + "pathParameters": { + "id": "home" + }, + "queryParameters": {}, + "payload": null + }, + "response": { + "data": { + "type": "categories", + "id": "home", + "attributes": { + "name": "Home" + }, + "relationships": { + "parent": { + "data": null + }, + "children": { + "data": [ + { + "type": "categories", + "id": "groceries" + } + ], + "links": { + "related": "https://api.up.com.au/api/v1/categories?filter%5Bparent%5D=home" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/categories/home" + } + } + } + } + } + } + } + }, + "/util/ping": { + "get": { + "tags": ["Utility endpoints"], + "summary": "Ping", + "description": "Make a basic ping request to the API. This is useful to verify that\nauthentication is functioning correctly. On authentication success an\nHTTP `200` status is returned. On failure an HTTP `401` error response\nis returned.\n", + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PingResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:Ei7727gXam4j0JOy" + }, + "pathParameters": {}, + "queryParameters": {}, + "payload": null + }, + "response": { + "meta": { + "id": "7c3c84c7-a02e-4218-96ba-2a6ebc64c594", + "statusEmoji": "⚡️" + } + } + } + }, + "401": { + "description": "Not Authorized", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": {}, + "pathParameters": {}, + "queryParameters": {}, + "payload": null + }, + "response": { + "errors": [ + { + "status": "401", + "title": "Not Authorized", + "detail": "The request was not authenticated because no valid credential was found in the Authorization header, or the Authorization header was not present." + } + ] + } + } + } + } + } + }, + "/tags": { + "get": { + "tags": ["Tags"], + "summary": "List tags", + "description": "Retrieve a list of all tags currently in use. The returned list is\n[paginated](#pagination) and can be scrolled by following the `next`\nand `prev` links where present. Results are ordered lexicographically.\nThe `transactions` relationship for each tag exposes a link\nto get the transactions with the given tag.\n", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "schema": { + "type": "integer" + }, + "required": false, + "example": 50, + "description": "The number of records to return in each page.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTagsResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:mbGGi7jVeVj0qXec" + }, + "pathParameters": {}, + "queryParameters": { + "page[size]": 2 + }, + "payload": null + }, + "response": { + "data": [ + { + "type": "tags", + "id": "Holiday", + "relationships": { + "transactions": { + "links": { + "related": "https://api.up.com.au/api/v1/transactions?filter%5Btag%5D=Holiday" + } + } + } + }, + { + "type": "tags", + "id": "Pizza Night", + "relationships": { + "transactions": { + "links": { + "related": "https://api.up.com.au/api/v1/transactions?filter%5Btag%5D=Pizza+Night" + } + } + } + } + ], + "links": { + "prev": null, + "next": "https://api.up.com.au/api/v1/tags?page%5Bafter%5D=WyJQaXp6YSBOaWdodCJd&page%5Bsize%5D=2" + } + } + } + } + } + } + }, + "/transactions/{transactionId}/relationships/tags": { + "post": { + "tags": ["Tags"], + "summary": "Add tags to transaction", + "description": "Associates one or more tags with a specific transaction. No more than 6\ntags may be present on any single transaction. Duplicate tags are\nsilently ignored. An HTTP `204` is returned on success. The associated\ntags, along with this request URL, are also exposed via the `tags`\nrelationship on the transaction resource returned from\n`/transactions/{id}`.\n", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTransactionTagsRequest" + } + } + } + }, + "parameters": [ + { + "name": "transactionId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "d024c1b8-bc6a-4785-afc6-cd332d2a2efb", + "description": "The unique identifier for the transaction.\n" + } + ], + "responses": { + "204": { + "description": "Successful Response", + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:arTSpKPKqafUZOyn", + "Content-Type": "application/json" + }, + "pathParameters": { + "transactionId": "dd21471e-771b-4367-997a-785e326dcde3" + }, + "queryParameters": {}, + "payload": { + "data": [ + { + "type": "tags", + "id": "Holiday" + }, + { + "type": "tags", + "id": "Queensland" + } + ] + } + }, + "response": null + } + } + } + }, + "delete": { + "tags": ["Tags"], + "summary": "Remove tags from transaction", + "description": "Disassociates one or more tags from a specific transaction. Tags that are\nnot associated are silently ignored. An HTTP `204` is returned on\nsuccess. The associated tags, along with this request URL, are also\nexposed via the `tags` relationship on the transaction resource returned\nfrom `/transactions/{id}`.\n", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UpdateTransactionTagsRequest" + } + } + } + }, + "parameters": [ + { + "name": "transactionId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "d8c190d6-be35-4d64-b2c4-e1aa0c09a0e0", + "description": "The unique identifier for the transaction.\n" + } + ], + "responses": { + "204": { + "description": "Successful Response", + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:cktrwA7Wmm5eSlBA", + "Content-Type": "application/json" + }, + "pathParameters": { + "transactionId": "734affdd-fc33-4dec-b4d1-ce1b2a2fd883" + }, + "queryParameters": {}, + "payload": { + "data": [ + { + "type": "tags", + "id": "Holiday" + }, + { + "type": "tags", + "id": "Queensland" + } + ] + } + }, + "response": null + } + } + } + } + }, + "/transactions": { + "get": { + "tags": ["Transactions"], + "summary": "List transactions", + "description": "Retrieve a list of all transactions across all accounts for the currently\nauthenticated user. The returned list is [paginated](#pagination) and can\nbe scrolled by following the `next` and `prev` links where present. To\nnarrow the results to a specific date range pass one or both of\n`filter[since]` and `filter[until]` in the query string. These filter\nparameters **should not** be used for pagination. Results are ordered\nnewest first to oldest last.\n", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "schema": { + "type": "integer" + }, + "required": false, + "example": 30, + "description": "The number of records to return in each page.\n" + }, + { + "name": "filter[status]", + "in": "query", + "schema": { + "$ref": "#/components/schemas/TransactionStatusEnum" + }, + "required": false, + "example": "HELD", + "description": "The transaction status for which to return records. This\ncan be used to filter `HELD` transactions from those\nthat are `SETTLED`.\n" + }, + { + "name": "filter[since]", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-01-01T01:02:03+10:00", + "description": "The start date-time from which to return records,\nformatted according to rfc-3339. Not to be used for\npagination purposes.\n" + }, + { + "name": "filter[until]", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-02-01T01:02:03+10:00", + "description": "The end date-time up to which to return records,\nformatted according to rfc-3339. Not to be used for\npagination purposes.\n" + }, + { + "name": "filter[category]", + "in": "query", + "schema": { + "type": "string" + }, + "required": false, + "example": "good-life", + "description": "The category identifier for which to filter transactions.\nBoth parent and child categories can be filtered through\nthis parameter. Providing an invalid category identifier\nresults in a `404` response.\n" + }, + { + "name": "filter[tag]", + "in": "query", + "schema": { + "type": "string" + }, + "required": false, + "example": "Holiday", + "description": "A transaction tag to filter for which to return records.\nIf the tag does not exist, zero records are returned and\na success response is given.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTransactionsResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:GghWDaFwjaTZl5EE" + }, + "pathParameters": {}, + "queryParameters": { + "page[size]": 1, + "filter[tag]": "Pizza Night", + "filter[status]": "SETTLED" + }, + "payload": null + }, + "response": { + "data": [ + { + "type": "transactions", + "id": "faf43161-fb81-4e23-a900-c234ac099437", + "attributes": { + "status": "SETTLED", + "rawText": null, + "description": "David Taylor", + "message": "Money for the pizzas last night.", + "holdInfo": null, + "roundUp": null, + "cashback": null, + "amount": { + "currencyCode": "AUD", + "value": "-59.98", + "valueInBaseUnits": -5998 + }, + "foreignAmount": null, + "settledAt": "2020-09-03T06:35:27+10:00", + "createdAt": "2020-09-03T06:35:27+10:00" + }, + "relationships": { + "account": { + "data": { + "type": "accounts", + "id": "091ef233-f7d5-4900-aafc-82f77555e5b2" + }, + "links": { + "related": "https://api.up.com.au/api/v1/accounts/091ef233-f7d5-4900-aafc-82f77555e5b2" + } + }, + "category": { + "data": null + }, + "parentCategory": { + "data": null + }, + "tags": { + "data": [ + { + "type": "tags", + "id": "Pizza Night" + } + ], + "links": { + "self": "https://api.up.com.au/api/v1/transactions/faf43161-fb81-4e23-a900-c234ac099437/relationships/tags" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/transactions/faf43161-fb81-4e23-a900-c234ac099437" + } + } + ], + "links": { + "prev": null, + "next": null + } + } + } + } + } + } + }, + "/transactions/{id}": { + "get": { + "tags": ["Transactions"], + "summary": "Retrieve transaction", + "description": "Retrieve a specific transaction by providing its unique identifier.\n", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "8e1da97e-6490-42eb-9c18-d8fdd94cfddc", + "description": "The unique identifier for the transaction.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetTransactionResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:mYhaIvMQsZr4Jkio" + }, + "pathParameters": { + "id": "75d3cffa-c517-4e64-8e41-acd63156c8b0" + }, + "queryParameters": {}, + "payload": null + }, + "response": { + "data": { + "type": "transactions", + "id": "75d3cffa-c517-4e64-8e41-acd63156c8b0", + "attributes": { + "status": "SETTLED", + "rawText": "WARUNG BEBEK, UBUD INDONES", + "description": "Warung Bebek Bengil", + "message": null, + "holdInfo": { + "amount": { + "currencyCode": "AUD", + "value": "-107.92", + "valueInBaseUnits": -10792 + }, + "foreignAmount": null + }, + "roundUp": { + "amount": { + "currencyCode": "AUD", + "value": "-0.08", + "valueInBaseUnits": -8 + }, + "boostPortion": null + }, + "cashback": null, + "amount": { + "currencyCode": "AUD", + "value": "-107.92", + "valueInBaseUnits": -10792 + }, + "foreignAmount": { + "currencyCode": "IDR", + "value": "-1053698.77", + "valueInBaseUnits": -105369877 + }, + "settledAt": "2020-08-30T11:34:29+10:00", + "createdAt": "2020-09-01T04:00:00+10:00" + }, + "relationships": { + "account": { + "data": { + "type": "accounts", + "id": "139ed96d-9697-4c4a-b221-3d0f72d656cd" + }, + "links": { + "related": "https://api.up.com.au/api/v1/accounts/139ed96d-9697-4c4a-b221-3d0f72d656cd" + } + }, + "category": { + "data": null + }, + "parentCategory": { + "data": null + }, + "tags": { + "data": [], + "links": { + "self": "https://api.up.com.au/api/v1/transactions/75d3cffa-c517-4e64-8e41-acd63156c8b0/relationships/tags" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/transactions/75d3cffa-c517-4e64-8e41-acd63156c8b0" + } + } + } + } + } + } + } + }, + "/accounts/{accountId}/transactions": { + "get": { + "tags": ["Transactions"], + "summary": "List transactions by account", + "description": "Retrieve a list of all transactions for a specific account. The returned\nlist is [paginated](#pagination) and can be scrolled by following the\n`next` and `prev` links where present. To narrow the results to a\nspecific date range pass one or both of `filter[since]` and\n`filter[until]` in the query string. These filter parameters\n**should not** be used for pagination. Results are ordered newest first\nto oldest last.\n", + "parameters": [ + { + "name": "accountId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "86150b64-feaa-4186-a7e4-e84eae764602", + "description": "The unique identifier for the account.\n" + }, + { + "name": "page[size]", + "in": "query", + "schema": { + "type": "integer" + }, + "required": false, + "example": 30, + "description": "The number of records to return in each page.\n" + }, + { + "name": "filter[status]", + "in": "query", + "schema": { + "$ref": "#/components/schemas/TransactionStatusEnum" + }, + "required": false, + "example": "HELD", + "description": "The transaction status for which to return records. This\ncan be used to filter `HELD` transactions from those\nthat are `SETTLED`.\n" + }, + { + "name": "filter[since]", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-01-01T01:02:03+10:00", + "description": "The start date-time from which to return records,\nformatted according to rfc-3339. Not to be used for\npagination purposes.\n" + }, + { + "name": "filter[until]", + "in": "query", + "schema": { + "type": "string", + "format": "date-time" + }, + "required": false, + "example": "2020-02-01T01:02:03+10:00", + "description": "The end date-time up to which to return records,\nformatted according to rfc-3339. Not to be used for\npagination purposes.\n" + }, + { + "name": "filter[category]", + "in": "query", + "schema": { + "type": "string" + }, + "required": false, + "example": "good-life", + "description": "The category identifier for which to filter transactions.\nBoth parent and child categories can be filtered through\nthis parameter. Providing an invalid category identifier\nresults in a `404` response.\n" + }, + { + "name": "filter[tag]", + "in": "query", + "schema": { + "type": "string" + }, + "required": false, + "example": "Holiday", + "description": "A transaction tag to filter for which to return records.\nIf the tag does not exist, zero records are returned and\na success response is given.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListTransactionsResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:gOJGDHqZa3HSYFZD" + }, + "pathParameters": { + "accountId": "a84f4f2b-1281-4f8f-9fbd-3e00fc28af90" + }, + "queryParameters": { + "page[size]": 1, + "filter[status]": "HELD", + "filter[category]": "good-life" + }, + "payload": null + }, + "response": { + "data": [ + { + "type": "transactions", + "id": "f86b92e8-abda-4f8d-9101-59897ff0ca1b", + "attributes": { + "status": "HELD", + "rawText": "Spotify 0123456789", + "description": "Spotify", + "message": null, + "holdInfo": { + "amount": { + "currencyCode": "AUD", + "value": "-11.95", + "valueInBaseUnits": -1195 + }, + "foreignAmount": null + }, + "roundUp": null, + "cashback": null, + "amount": { + "currencyCode": "AUD", + "value": "-11.95", + "valueInBaseUnits": -1195 + }, + "foreignAmount": null, + "settledAt": null, + "createdAt": "2020-09-01T09:28:36+10:00" + }, + "relationships": { + "account": { + "data": { + "type": "accounts", + "id": "a84f4f2b-1281-4f8f-9fbd-3e00fc28af90" + }, + "links": { + "related": "https://api.up.com.au/api/v1/accounts/a84f4f2b-1281-4f8f-9fbd-3e00fc28af90" + } + }, + "category": { + "data": { + "type": "categories", + "id": "tv-and-music" + }, + "links": { + "related": "https://api.up.com.au/api/v1/categories/tv-and-music" + } + }, + "parentCategory": { + "data": { + "type": "categories", + "id": "good-life" + }, + "links": { + "related": "https://api.up.com.au/api/v1/categories/good-life" + } + }, + "tags": { + "data": [], + "links": { + "self": "https://api.up.com.au/api/v1/transactions/f86b92e8-abda-4f8d-9101-59897ff0ca1b/relationships/tags" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/transactions/f86b92e8-abda-4f8d-9101-59897ff0ca1b" + } + } + ], + "links": { + "prev": null, + "next": null + } + } + } + } + } + } + }, + "/webhooks": { + "get": { + "tags": ["Webhooks"], + "summary": "List webhooks", + "description": "Retrieve a list of configured webhooks. The returned list is\n[paginated](#pagination) and can be scrolled by following the `next`\nand `prev` links where present. Results are ordered oldest first to\nnewest last.\n", + "parameters": [ + { + "name": "page[size]", + "in": "query", + "schema": { + "type": "integer" + }, + "required": false, + "example": 30, + "description": "The number of records to return in each page.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListWebhooksResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:9E64pZGsOXbna3ZG" + }, + "pathParameters": {}, + "queryParameters": { + "page[size]": 1 + }, + "payload": null + }, + "response": { + "data": [ + { + "type": "webhooks", + "id": "c4c9bcb9-88aa-4a52-87c8-9eaa9fef735f", + "attributes": { + "url": "http://example.com/webhook-1", + "description": "Webhook number 1", + "createdAt": "2020-09-02T13:37:37+10:00" + }, + "relationships": { + "logs": { + "links": { + "related": "https://api.up.com.au/api/v1/webhooks/c4c9bcb9-88aa-4a52-87c8-9eaa9fef735f/logs" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/webhooks/c4c9bcb9-88aa-4a52-87c8-9eaa9fef735f" + } + } + ], + "links": { + "prev": null, + "next": "https://api.up.com.au/api/v1/webhooks?page%5Bafter%5D=WyIyMDIwLTA5LTAyVDAzOjM3OjM3LjM2MjQxMjAwMFoiLCJjNGM5YmNiOS04OGFhLTRhNTItODdjOC05ZWFhOWZlZjczNWYiXQ%3D%3D&page%5Bsize%5D=1" + } + } + } + } + } + }, + "post": { + "tags": ["Webhooks"], + "summary": "Create webhook", + "description": "Create a new webhook with a given URL. The URL will receive webhook\nevents as JSON-encoded `POST` requests. The URL must respond with a HTTP\n`200` status on success.\n\nThere is currently a limit of 10 webhooks at any given time. Once this\nlimit is reached, existing webhooks will need to be deleted before new\nwebhooks can be created.\n\nEvent delivery is retried with exponential backoff if the URL is\nunreachable or it does not respond with a `200` status. The response\nincludes a `secretKey` attribute, which is used to sign requests sent to\nthe webhook URL. It will not be returned from any other endpoints within\nthe Up API. If the `secretKey` is lost, simply create a new webhook with\nthe same URL, capture its `secretKey` and then delete the original\nwebhook. See [Handling webhook events](#callback_post_webhookURL) for\ndetails on how to process webhook events.\n\nIt is probably a good idea to test the webhook by\n[sending it a `PING` event](#post_webhooks_webhookId_ping) after creating\nit.\n", + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Created", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/CreateWebhookResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:vJCDnqeW8lNkeBA1", + "Content-Type": "application/json" + }, + "pathParameters": {}, + "queryParameters": {}, + "payload": { + "data": { + "attributes": { + "url": "http://example.com/webhook", + "description": "Example webhook" + } + } + } + }, + "response": { + "data": { + "type": "webhooks", + "id": "39b070ae-8595-437f-a3f3-f5ee482ca206", + "attributes": { + "url": "http://example.com/webhook", + "description": "Example webhook", + "secretKey": "UcYEuMacPkZjui0XhUzKeS0z3ETXtYgFDNJ16Gcrk7o4iSh7ZHNS2u7fOEjqtlzR", + "createdAt": "2020-09-04T13:37:38+10:00" + }, + "relationships": { + "logs": { + "links": { + "related": "https://api.up.com.au/api/v1/webhooks/39b070ae-8595-437f-a3f3-f5ee482ca206/logs" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/webhooks/39b070ae-8595-437f-a3f3-f5ee482ca206" + } + } + } + } + } + }, + "callbacks": { + "Event": { + "{webhookURL}": { + "post": { + "summary": "Handling webhook events", + "description": "Once you have created a webhook in the Up API, events are sent to the\nwebhook’s configured URL as JSON-encoded `POST` requests. The webhook\nURL must respond with a HTTP `200` status on success.\n\nIt is important that the URL responds in a timely manner. If the URL\ntakes too long to respond (currently 30s), the request will be timed\nout. For this reason it is strongly advised to avoid any heavy\nprocessing before a response has been returned from the URL. A common\nsolution to this problem is to use a message broker such as RabbitMQ\nto do the work asynchronously.\n\nEvent delivery is retried with exponential backoff in the case of any\nnon-`200` response status, if the URL is unreachable, or if the request\nis timed out.\n\nRefer to the `eventType` attribute in order to determine what course of\naction to take when handling the event. The following event types are\ncurrently sent:\n\n**`PING`**\n\nManually triggered by calls to the webhook `ping` endpoint. Used for\ntesting and debugging purposes.\n\n**`TRANSACTION_CREATED`**\n\nTriggered whenever a new transaction is created in Up. This event\nincludes a `transaction` relationship that provides the unique\nidentifier for the transaction and a link to the transaction within the\nUp API. This link should be used to retrieve the complete transaction\ndata.\n\n**`TRANSACTION_SETTLED`**\n\nTriggered whenever a transaction transitions from the `HELD` status to\nthe `SETTLED` status. This event includes a `transaction` relationship\nthat provides the unique identifier for the transaction and a link to\nthe transaction within the Up API. This link should be used to retrieve\nthe complete transaction data.\n\nDue to external factors in banking processes, on rare occasions this\nevent may not be triggered. Separate `TRANSACTION_DELETED` and\n`TRANSACTION_CREATED` events will be received in its place.\n\n**`TRANSACTION_DELETED`**\n\nTriggered whenever a `HELD` transaction is deleted from Up. This\ngenerally occurs for example when a hotel deposit is returned. This\nevent includes a `transaction` relationship that provides the unique\nidentifier for the transaction, however no link is provided to the\ntransaction within the Up API as it no longer exists.\n\n## Securing Webhook Event Handlers\n\nIncoming webhook event requests include a `X-Up-Authenticity-Signature`\nheader, which can be used to verify that the event was sent by Up.\nVerification of the signature requires knowledge of the shared\n`secretKey` that was returned upon creation of the webhook. This key is\nknown only to your application and to Up.\n\nThe verification process involves:\n\n1. Taking the raw, unparsed webhook event request body.\n2. Computing the SHA-256 HMAC signature of the request body, using the\n shared `secretKey`.\n3. Comparing the computed HMAC signature with the value of the\n `X-Up-Authenticity-Signature` header.\n\nIf the computed SHA-256 HMAC signature matches the\n`X-Up-Authenticity-Signature` header, the request is valid.\n\nA few language-specific examples follow.\n\n**Ruby**:\n\nThis example uses the Ruby on Rails framework.\n\n```ruby\nrequire 'openssl'\n\ndef handle_webhook_event\n received_signature =\n request.headers['X-Up-Authenticity-Signature']\n\n signature = OpenSSL::HMAC.hexdigest(\n 'SHA256',\n secret_key,\n request.raw_post,\n )\n\n if Rack::Utils.secure_compare(received_signature, signature)\n # Process webhook event\n end\nend\n```\n\n**PHP**:\n\nThis example uses the Laravel framework.\n\n```php\npublic function handleWebhookEvent(Request $request) {\n $received_signature = $request->header(\n 'X-Up-Authenticity-Signature',\n ''\n );\n $raw_body = $request->getContent();\n $signature = hash_hmac('sha256', $raw_body, $this->secretKey);\n\n if (hash_equals($signature, $received_signature)) {\n // Process webhook event\n }\n}\n```\n\n**Go**:\n\nThis example is in plain Go.\n\n```go\nimport (\n \"crypto/hmac\"\n \"crypto/sha256\"\n \"encoding/hex\"\n \"io\"\n \"net/http\"\n)\n\nfunc handleWebhookEvent(w http.ResponseWriter, r *http.Request) {\n receivedSignature, _ := hex.DecodeString(\n r.Header.Get(\"X-Up-Authenticity-Signature\"),\n )\n\n mac := hmac.New(sha256.New, secretKey)\n io.Copy(mac, r.Body)\n signature := mac.Sum(nil)\n\n if hmac.Equal(signature, receivedSignature)\n // Process webhook event\n }\n}\n```\n\nIf the `secretKey` for a webhook is lost, simply create a new webhook\nwith the same URL, capture the returned `secretKey` and delete the\noriginal webhook.\n", + "parameters": [ + { + "name": "X-Up-Authenticity-Signature", + "in": "header", + "schema": { + "type": "string" + }, + "required": false, + "example": "317c0a8ea81df3f53c1d2aef5dcbf60492d0df557197b2990e71daa4a0693364", + "description": "The SHA-256 HMAC signature of the raw request body, signed using\nthe `secretKey` of the webhook.\n" + } + ], + "requestBody": { + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookEventCallback" + } + } + } + }, + "responses": { + "200": { + "description": "Successful Response" + } + }, + "x-up:example": { + "type": "examplePayload", + "payload": { + "data": { + "type": "webhook-events", + "id": "8671d400-d9e0-4d99-923c-95c031bc6739", + "attributes": { + "eventType": "TRANSACTION_CREATED", + "createdAt": "2020-09-04T13:37:38+10:00" + }, + "relationships": { + "webhook": { + "data": { + "type": "webhooks", + "id": "3c62e0a3-86e5-4dcd-a217-d7c1d096ba0e" + }, + "links": { + "related": "https://api.up.com.au/api/v1/webhooks/3c62e0a3-86e5-4dcd-a217-d7c1d096ba0e" + } + }, + "transaction": { + "data": { + "type": "transactions", + "id": "468ec9d9-aac6-4c8a-ba85-141a39d09b91" + }, + "links": { + "related": "https://api.up.com.au/api/v1/transactions/468ec9d9-aac6-4c8a-ba85-141a39d09b91" + } + } + } + } + } + } + } + } + } + } + } + }, + "/webhooks/{id}": { + "get": { + "tags": ["Webhooks"], + "summary": "Retrieve webhook", + "description": "Retrieve a specific webhook by providing its unique identifier.\n", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "bc11e3ed-362e-43ab-b141-ef4f6251faa5", + "description": "The unique identifier for the webhook.\n" + } + ], + "responses": { + "200": { + "description": "Successful Response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/GetWebhookResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:qqUmYsIcKyjjLBBM" + }, + "pathParameters": { + "id": "c6715e53-68d8-4315-b183-5993dea31603" + }, + "queryParameters": {}, + "payload": null + }, + "response": { + "data": { + "type": "webhooks", + "id": "c6715e53-68d8-4315-b183-5993dea31603", + "attributes": { + "url": "http://example.com/webhook-2", + "description": "Webhook number 2", + "createdAt": "2020-09-03T13:37:39+10:00" + }, + "relationships": { + "logs": { + "links": { + "related": "https://api.up.com.au/api/v1/webhooks/c6715e53-68d8-4315-b183-5993dea31603/logs" + } + } + }, + "links": { + "self": "https://api.up.com.au/api/v1/webhooks/c6715e53-68d8-4315-b183-5993dea31603" + } + } + } + } + } + } + }, + "delete": { + "tags": ["Webhooks"], + "summary": "Delete webhook", + "description": "Delete a specific webhook by providing its unique identifier. Once\ndeleted, webhook events will no longer be sent to the configured URL.\n", + "parameters": [ + { + "name": "id", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "81f485ae-0e10-493d-95f3-a9c1dd4b6b6a", + "description": "The unique identifier for the webhook.\n" + } + ], + "responses": { + "204": { + "description": "Deleted", + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:wJTpdJqQniotjF64" + }, + "pathParameters": { + "id": "a64bdc5f-d245-4678-a1af-9894318ebcec" + }, + "queryParameters": {}, + "payload": null + }, + "response": null + } + } + } + } + }, + "/webhooks/{webhookId}/ping": { + "post": { + "tags": ["Webhooks"], + "summary": "Ping webhook", + "description": "Send a `PING` event to a webhook by providing its unique identifier.\nThis is useful for testing and debugging purposes. The event is delivered\nasynchronously and its data is returned in the response to this request.\n", + "parameters": [ + { + "name": "webhookId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "6ef4bb23-53f1-4a3d-aa5c-a6e9121c5da3", + "description": "The unique identifier for the webhook.\n" + } + ], + "responses": { + "201": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/WebhookEventCallback" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:TPZKsyrzLBxjuJjl", + "Content-Type": "application/json" + }, + "pathParameters": { + "webhookId": "7a72c637-9a0d-4dfd-8f1a-dc2a75b484b7" + }, + "queryParameters": {}, + "payload": "" + }, + "response": { + "data": { + "type": "webhook-events", + "id": "fb177d1d-003f-4e9a-831a-62194652937d", + "attributes": { + "eventType": "PING", + "createdAt": "2020-09-04T13:37:41+10:00" + }, + "relationships": { + "webhook": { + "data": { + "type": "webhooks", + "id": "7a72c637-9a0d-4dfd-8f1a-dc2a75b484b7" + }, + "links": { + "related": "https://api.up.com.au/api/v1/webhooks/7a72c637-9a0d-4dfd-8f1a-dc2a75b484b7" + } + } + } + } + } + } + } + } + } + }, + "/webhooks/{webhookId}/logs": { + "get": { + "tags": ["Webhooks"], + "summary": "List webhook logs", + "description": "Retrieve a list of delivery logs for a webhook by providing its unique\nidentifier. This is useful for analysis and debugging purposes. The\nreturned list is [paginated](#pagination) and can be scrolled by\nfollowing the `next` and `prev` links where present. Results are ordered\nnewest first to oldest last. Logs may be automatically purged after a\nperiod of time.\n", + "parameters": [ + { + "name": "webhookId", + "in": "path", + "schema": { + "type": "string" + }, + "required": true, + "example": "49733526-b90d-436a-8a75-9715a1d7cc5b", + "description": "The unique identifier for the webhook.\n" + }, + { + "name": "page[size]", + "in": "query", + "schema": { + "type": "integer" + }, + "required": false, + "example": 30, + "description": "The number of records to return in each page.\n" + } + ], + "responses": { + "200": { + "description": "Successful response", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ListWebhookDeliveryLogsResponse" + } + } + }, + "x-up:example": { + "type": "exampleRequestResponse", + "request": { + "headers": { + "Authorization": "Bearer up:demo:cDMrkDxg8msPDmVC" + }, + "pathParameters": { + "webhookId": "843f52cf-ceab-43cc-a7c6-449cf82c49e3" + }, + "queryParameters": { + "page[size]": 1 + }, + "payload": null + }, + "response": { + "data": [ + { + "type": "webhook-delivery-logs", + "id": "7dfbd731-5537-46ab-b658-7676f6024475", + "attributes": { + "request": { + "body": "{\"data\":{\"type\":\"webhook-events\",\"id\":\"9dee0635-accd-42a0-b2b5-af5914692a17\",\"attributes\":{\"eventType\":\"TRANSACTION_CREATED\",\"createdAt\":\"2020-09-03T13:38:43+10:00\"},\"relationships\":{\"webhook\":{\"data\":{\"type\":\"webhooks\",\"id\":\"843f52cf-ceab-43cc-a7c6-449cf82c49e3\"},\"links\":{\"related\":\"https://api.up.com.au/api/v1/webhooks/843f52cf-ceab-43cc-a7c6-449cf82c49e3\"}},\"transaction\":{\"data\":{\"type\":\"transactions\",\"id\":\"a131f7ec-681f-4bf4-9dc9-b25ba94c02dc\"},\"links\":{\"related\":\"https://api.up.com.au/api/v1/transactions/a131f7ec-681f-4bf4-9dc9-b25ba94c02dc\"}}}}}" + }, + "response": { + "statusCode": 200, + "body": "{\"ok\":true}" + }, + "deliveryStatus": "DELIVERED", + "createdAt": "2020-09-03T13:38:43+10:00" + }, + "relationships": { + "webhookEvent": { + "data": { + "type": "webhook-events", + "id": "9dee0635-accd-42a0-b2b5-af5914692a17" + } + } + } + } + ], + "links": { + "prev": null, + "next": "https://api.up.com.au/api/v1/webhooks/843f52cf-ceab-43cc-a7c6-449cf82c49e3/logs?page%5Bafter%5D=WyIyMDIwLTA5LTAzVDAzOjM4OjQzLjYxMzE3MTAwMFoiLCI3ZGZiZDczMS01NTM3LTQ2YWItYjY1OC03Njc2ZjYwMjQ0NzUiXQ%3D%3D&page%5Bsize%5D=1" + } + } + } + } + } + } + } + } +} diff --git a/tests/spec/defaultAsSuccess/schema.ts b/tests/spec/defaultAsSuccess/schema.ts index 0c4d035b..4c981422 100644 --- a/tests/spec/defaultAsSuccess/schema.ts +++ b/tests/spec/defaultAsSuccess/schema.ts @@ -61,16 +61,34 @@ export interface PushToken { sub: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -78,22 +96,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://6-dot-authentiqio.appspot.com"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -106,92 +125,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -204,7 +257,7 @@ export class HttpClient { * @baseUrl https://6-dot-authentiqio.appspot.com * Strong authentication, without the passwords. */ -export class Api extends HttpClient { +export class Api extends HttpClient { key = { /** * @description Revoke an Authentiq ID using email & phone. If called with `email` and `phone` only, a verification code will be sent by email. Do a second call adding `code` to complete the revocation. @@ -213,8 +266,14 @@ export class Api extends HttpClient { * @name KeyRevokeNosecret * @request DELETE:/key */ - keyRevokeNosecret: (query: { email: string; phone: string; code?: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key${this.addQueryParams(query)}`, "DELETE", params), + keyRevokeNosecret: (query: { email: string; phone: string; code?: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Register a new ID `JWT(sub, devtoken)` v5: `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -223,8 +282,14 @@ export class Api extends HttpClient { * @name KeyRegister * @request POST:/key */ - keyRegister: (body: AuthentiqID, params?: RequestParams) => - this.request<{ secret?: string; status?: string }, Error>(`/key`, "POST", params, body), + keyRegister: (body: AuthentiqID, params: RequestParams = {}) => + this.request<{ secret?: string; status?: string }, Error>({ + path: `/key`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Revoke an Identity (Key) with a revocation secret @@ -233,8 +298,14 @@ export class Api extends HttpClient { * @name KeyRevoke * @request DELETE:/key/{PK} */ - keyRevoke: (PK: string, query: { secret: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}${this.addQueryParams(query)}`, "DELETE", params), + keyRevoke: (PK: string, query: { secret: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Get public details of an Authentiq ID. @@ -243,8 +314,13 @@ export class Api extends HttpClient { * @name GetKey * @request GET:/key/{PK} */ - getKey: (PK: string, params?: RequestParams) => - this.request<{ since?: string; status?: string; sub?: string }, Error>(`/key/${PK}`, "GET", params), + getKey: (PK: string, params: RequestParams = {}) => + this.request<{ since?: string; status?: string; sub?: string }, Error>({ + path: `/key/${PK}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD info on Authentiq ID @@ -253,7 +329,12 @@ export class Api extends HttpClient { * @name HeadKey * @request HEAD:/key/{PK} */ - headKey: (PK: string, params?: RequestParams) => this.request(`/key/${PK}`, "HEAD", params), + headKey: (PK: string, params: RequestParams = {}) => + this.request({ + path: `/key/${PK}`, + method: "HEAD", + ...params, + }), /** * @description update properties of an Authentiq ID. (not operational in v4; use PUT for now) v5: POST issuer-signed email & phone scopes in a self-signed JWT See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -262,8 +343,14 @@ export class Api extends HttpClient { * @name KeyUpdate * @request POST:/key/{PK} */ - keyUpdate: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "POST", params, body), + keyUpdate: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Update Authentiq ID by replacing the object. v4: `JWT(sub,email,phone)` to bind email/phone hash; v5: POST issuer-signed email & phone scopes and PUT to update registration `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -272,8 +359,14 @@ export class Api extends HttpClient { * @name KeyBind * @request PUT:/key/{PK} */ - keyBind: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "PUT", params, body), + keyBind: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "PUT", + body: body, + format: "json", + ...params, + }), }; login = { /** @@ -283,8 +376,15 @@ export class Api extends HttpClient { * @name PushLoginRequest * @request POST:/login */ - pushLoginRequest: (query: { callback: string }, body: PushToken, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/login${this.addQueryParams(query)}`, "POST", params, body), + pushLoginRequest: (query: { callback: string }, body: PushToken, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/login`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), }; scope = { /** @@ -294,13 +394,15 @@ export class Api extends HttpClient { * @name SignRequest * @request POST:/scope */ - signRequest: (body: Claims, query?: { test?: number }, params?: RequestParams) => - this.request<{ job?: string; status?: string }, Error>( - `/scope${this.addQueryParams(query)}`, - "POST", - params, - body, - ), + signRequest: (body: Claims, query?: { test?: number }, params: RequestParams = {}) => + this.request<{ job?: string; status?: string }, Error>({ + path: `/scope`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), /** * @description delete a verification job @@ -309,8 +411,13 @@ export class Api extends HttpClient { * @name SignDelete * @request DELETE:/scope/{job} */ - signDelete: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "DELETE", params), + signDelete: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "DELETE", + format: "json", + ...params, + }), /** * @description get the status / current content of a verification job @@ -319,8 +426,13 @@ export class Api extends HttpClient { * @name SignRetrieve * @request GET:/scope/{job} */ - signRetrieve: (job: string, params?: RequestParams) => - this.request<{ exp?: number; field?: string; sub?: string }, Error>(`/scope/${job}`, "GET", params), + signRetrieve: (job: string, params: RequestParams = {}) => + this.request<{ exp?: number; field?: string; sub?: string }, Error>({ + path: `/scope/${job}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD to get the status of a verification job @@ -329,8 +441,12 @@ export class Api extends HttpClient { * @name SignRetrieveHead * @request HEAD:/scope/{job} */ - signRetrieveHead: (job: string, params?: RequestParams) => - this.request(`/scope/${job}`, "HEAD", params), + signRetrieveHead: (job: string, params: RequestParams = {}) => + this.request({ + path: `/scope/${job}`, + method: "HEAD", + ...params, + }), /** * @description this is a scope confirmation @@ -339,8 +455,14 @@ export class Api extends HttpClient { * @name SignConfirm * @request POST:/scope/{job} */ - signConfirm: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "POST", params, null, BodyType.Json), + signConfirm: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "POST", + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description authority updates a JWT with its signature See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -349,7 +471,11 @@ export class Api extends HttpClient { * @name SignUpdate * @request PUT:/scope/{job} */ - signUpdate: (job: string, params?: RequestParams) => - this.request<{ jwt?: string; status?: string }, Error>(`/scope/${job}`, "PUT", params), + signUpdate: (job: string, params: RequestParams = {}) => + this.request<{ jwt?: string; status?: string }, Error>({ + path: `/scope/${job}`, + method: "PUT", + ...params, + }), }; } diff --git a/tests/spec/defaultResponse/schema.json b/tests/spec/defaultResponse/schema.json new file mode 100644 index 00000000..7629acb1 --- /dev/null +++ b/tests/spec/defaultResponse/schema.json @@ -0,0 +1,57 @@ +{ + "swagger": "2.0", + "info": { + "version": "1.0.0", + "title": "Swagger Petstore", + "description": "A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification", + "termsOfService": "http://swagger.io/terms/", + "contact": { + "name": "Swagger API Team", + "email": "apiteam@swagger.io", + "url": "http://swagger.io" + }, + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0.html" + } + }, + "host": "petstore.swagger.io", + "basePath": "/api", + "schemes": ["http"], + "consumes": ["application/json"], + "produces": ["application/json"], + "paths": { + "/pets": { + "get": { + "description": "Returns all pets from the system that the user has access to\nNam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia.\n\nSed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien.\n", + "operationId": "findPets", + "parameters": [ + { + "name": "tags", + "in": "query", + "description": "tags to filter by", + "required": false, + "type": "array", + "collectionFormat": "csv", + "items": { + "type": "string" + } + }, + { + "name": "limit", + "in": "query", + "description": "maximum number of results to return", + "required": false, + "type": "integer", + "format": "int32" + } + ], + "responses": { + "200": {}, + "default": {} + } + } + } + }, + "definitions": {} +} diff --git a/tests/spec/defaultResponse/schema.ts b/tests/spec/defaultResponse/schema.ts new file mode 100644 index 00000000..0dea62eb --- /dev/null +++ b/tests/spec/defaultResponse/schema.ts @@ -0,0 +1,224 @@ +/* tslint:disable */ +/* eslint-disable */ +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ + secure?: boolean; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} + +export type RequestParams = Omit; + +interface ApiConfig { + baseUrl?: string; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; +} + +interface HttpResponse extends Response { + data: D; + error: E; +} + +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", +} + +export class HttpClient { + public baseUrl: string = "http://petstore.swagger.io/api"; + private securityData: SecurityDataType = null as any; + private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); + + private baseApiParams: RequestParams = { + credentials: "same-origin", + headers: {}, + redirect: "follow", + referrerPolicy: "no-referrer", + }; + + constructor(apiConfig: ApiConfig = {}) { + Object.assign(this, apiConfig); + } + + public setSecurityData = (data: SecurityDataType) => { + this.securityData = data; + }; + + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + + return ( + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) + ); + } + + protected toQueryString(rawQuery?: QueryParamsType): string { + const query = rawQuery || {}; + const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); + return keys + .map((key) => + typeof query[key] === "object" && !Array.isArray(query[key]) + ? this.toQueryString(query[key] as QueryParamsType) + : this.addQueryParam(query, key), + ) + .join("&"); + } + + protected addQueryParams(rawQuery?: QueryParamsType): string { + const queryString = this.toQueryString(rawQuery); + return queryString ? `?${queryString}` : ""; + } + + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { + data.append(key, input[key]); + return data; + }, new FormData()), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), + }; + + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { + return { + ...this.baseApiParams, + ...params1, + ...(params2 || {}), + headers: { + ...(this.baseApiParams.headers || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), + }, + }; + } + + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; + }; + + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } + + if (!response.ok) throw data; + return data; + }); + }; +} + +/** + * @title Swagger Petstore + * @version 1.0.0 + * @baseUrl http://petstore.swagger.io/api + * A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification + */ +export class Api extends HttpClient { + pets = { + /** + * @description Returns all pets from the system that the user has access to Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. + * + * @name FindPets + * @request GET:/pets + */ + findPets: (query?: { tags?: string[]; limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + ...params, + }), + }; +} diff --git a/tests/spec/defaultResponse/test.js b/tests/spec/defaultResponse/test.js new file mode 100644 index 00000000..bc3609ad --- /dev/null +++ b/tests/spec/defaultResponse/test.js @@ -0,0 +1,25 @@ +const { generateApi } = require("../../../src"); +const { resolve } = require("path"); +const validateGeneratedModule = require("../../helpers/validateGeneratedModule"); +const createSchemasInfos = require("../../helpers/createSchemaInfos"); + +const schemas = createSchemasInfos({ absolutePathToSchemas: resolve(__dirname, "./") }); + +schemas.forEach(({ absolutePath, apiFileName }) => { + generateApi({ + name: apiFileName, + spec: require(absolutePath), + output: resolve(__dirname, "./"), + defaultResponseType: "unknown", + }) + .then(() => { + const diagnostics = validateGeneratedModule({ + pathToFile: resolve(__dirname, `./${apiFileName}`), + }); + if (diagnostics.length) throw "Failed"; + }) + .catch((e) => { + console.error("--default-response option test failed."); + throw e; + }); +}); diff --git a/tests/spec/enumNamesAsValues/schema.ts b/tests/spec/enumNamesAsValues/schema.ts index a660c0be..a49d39cf 100644 --- a/tests/spec/enumNamesAsValues/schema.ts +++ b/tests/spec/enumNamesAsValues/schema.ts @@ -207,16 +207,34 @@ export interface ProjectType { teamSize: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -224,22 +242,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://localhost:8080/api/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -252,92 +271,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -345,10 +398,10 @@ export class HttpClient { } /** - * @title Api + * @title No title * @baseUrl http://localhost:8080/api/v1 */ -export class Api extends HttpClient { +export class Api extends HttpClient { auth = { /** * No description @@ -357,8 +410,15 @@ export class Api extends HttpClient { * @name Login * @request POST:/auth */ - login: (data: AuthUserType, params?: RequestParams) => - this.request(`/auth`, "POST", params, data, BodyType.Json), + login: (data: AuthUserType, params: RequestParams = {}) => + this.request({ + path: `/auth`, + method: "POST", + body: data, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -368,8 +428,14 @@ export class Api extends HttpClient { * @request POST:/auth/refresh * @secure */ - refresh: (params?: RequestParams) => - this.request(`/auth/refresh`, "POST", params, null, BodyType.Json, true), + refresh: (params: RequestParams = {}) => + this.request({ + path: `/auth/refresh`, + method: "POST", + secure: true, + format: "json", + ...params, + }), }; jobs = { /** @@ -380,8 +446,14 @@ export class Api extends HttpClient { * @request GET:/jobs * @secure */ - getJobs: (params?: RequestParams) => - this.request(`/jobs`, "GET", params, null, BodyType.Json, true), + getJobs: (params: RequestParams = {}) => + this.request({ + path: `/jobs`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -391,8 +463,16 @@ export class Api extends HttpClient { * @request POST:/jobs * @secure */ - addJob: (data: JobUpdateType, params?: RequestParams) => - this.request(`/jobs`, "POST", params, data, BodyType.Json, true), + addJob: (data: JobUpdateType, params: RequestParams = {}) => + this.request({ + path: `/jobs`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -402,8 +482,14 @@ export class Api extends HttpClient { * @request GET:/jobs/{id} * @secure */ - getJob: (id: string, params?: RequestParams) => - this.request(`/jobs/${id}`, "GET", params, null, BodyType.Json, true), + getJob: (id: string, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -413,8 +499,16 @@ export class Api extends HttpClient { * @request PATCH:/jobs/{id} * @secure */ - updateJob: (id: string, data: JobUpdateType, params?: RequestParams) => - this.request(`/jobs/${id}`, "PATCH", params, data, BodyType.Json, true), + updateJob: (id: string, data: JobUpdateType, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -424,8 +518,14 @@ export class Api extends HttpClient { * @request DELETE:/jobs/{id} * @secure */ - deleteJob: (id: string, params?: RequestParams) => - this.request(`/jobs/${id}`, "DELETE", params, null, BodyType.Json, true), + deleteJob: (id: string, params: RequestParams = {}) => + this.request({ + path: `/jobs/${id}`, + method: "DELETE", + secure: true, + format: "json", + ...params, + }), }; projects = { /** @@ -435,7 +535,13 @@ export class Api extends HttpClient { * @name GetProjects * @request GET:/projects */ - getProjects: (params?: RequestParams) => this.request(`/projects`, "GET", params), + getProjects: (params: RequestParams = {}) => + this.request({ + path: `/projects`, + method: "GET", + format: "json", + ...params, + }), /** * No description @@ -445,8 +551,16 @@ export class Api extends HttpClient { * @request POST:/projects * @secure */ - addProjects: (data: ProjectUpdateType, params?: RequestParams) => - this.request(`/projects`, "POST", params, data, BodyType.Json, true), + addProjects: (data: ProjectUpdateType, params: RequestParams = {}) => + this.request({ + path: `/projects`, + method: "POST", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -456,8 +570,16 @@ export class Api extends HttpClient { * @request PATCH:/projects/{id} * @secure */ - updateProject: (id: string, data: ProjectUpdateType, params?: RequestParams) => - this.request(`/projects/${id}`, "PATCH", params, data, BodyType.Json, true), + updateProject: (id: string, data: ProjectUpdateType, params: RequestParams = {}) => + this.request({ + path: `/projects/${id}`, + method: "PATCH", + body: data, + secure: true, + type: ContentType.Json, + format: "json", + ...params, + }), /** * No description @@ -466,6 +588,12 @@ export class Api extends HttpClient { * @name DeleteProject * @request DELETE:/projects/{id} */ - deleteProject: (id: string, params?: RequestParams) => this.request(`/projects/${id}`, "DELETE", params), + deleteProject: (id: string, params: RequestParams = {}) => + this.request({ + path: `/projects/${id}`, + method: "DELETE", + format: "json", + ...params, + }), }; } diff --git a/tests/spec/extractRequestParams/schema.ts b/tests/spec/extractRequestParams/schema.ts index 2c23f570..20a7a468 100644 --- a/tests/spec/extractRequestParams/schema.ts +++ b/tests/spec/extractRequestParams/schema.ts @@ -90,16 +90,34 @@ export interface SignRequestParams { test?: number; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -107,22 +125,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://6-dot-authentiqio.appspot.com"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -135,92 +154,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -233,7 +286,7 @@ export class HttpClient { * @baseUrl https://6-dot-authentiqio.appspot.com * Strong authentication, without the passwords. */ -export class Api extends HttpClient { +export class Api extends HttpClient { key = { /** * @description Revoke an Authentiq ID using email & phone. If called with `email` and `phone` only, a verification code will be sent by email. Do a second call adding `code` to complete the revocation. @@ -242,8 +295,14 @@ export class Api extends HttpClient { * @name KeyRevokeNosecret * @request DELETE:/key */ - keyRevokeNosecret: (query: KeyRevokeNosecretParams, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key${this.addQueryParams(query)}`, "DELETE", params), + keyRevokeNosecret: (query: KeyRevokeNosecretParams, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Register a new ID `JWT(sub, devtoken)` v5: `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -252,8 +311,14 @@ export class Api extends HttpClient { * @name KeyRegister * @request POST:/key */ - keyRegister: (body: AuthentiqID, params?: RequestParams) => - this.request<{ secret?: string; status?: string }, Error>(`/key`, "POST", params, body), + keyRegister: (body: AuthentiqID, params: RequestParams = {}) => + this.request<{ secret?: string; status?: string }, Error>({ + path: `/key`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Revoke an Identity (Key) with a revocation secret @@ -262,8 +327,14 @@ export class Api extends HttpClient { * @name KeyRevoke * @request DELETE:/key/{PK} */ - keyRevoke: ({ PK, ...query }: KeyRevokeParams, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}${this.addQueryParams(query)}`, "DELETE", params), + keyRevoke: ({ PK, ...query }: KeyRevokeParams, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Get public details of an Authentiq ID. @@ -272,8 +343,13 @@ export class Api extends HttpClient { * @name GetKey * @request GET:/key/{PK} */ - getKey: (PK: string, params?: RequestParams) => - this.request<{ since?: string; status?: string; sub?: string }, Error>(`/key/${PK}`, "GET", params), + getKey: (PK: string, params: RequestParams = {}) => + this.request<{ since?: string; status?: string; sub?: string }, Error>({ + path: `/key/${PK}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD info on Authentiq ID @@ -282,7 +358,12 @@ export class Api extends HttpClient { * @name HeadKey * @request HEAD:/key/{PK} */ - headKey: (PK: string, params?: RequestParams) => this.request(`/key/${PK}`, "HEAD", params), + headKey: (PK: string, params: RequestParams = {}) => + this.request({ + path: `/key/${PK}`, + method: "HEAD", + ...params, + }), /** * @description update properties of an Authentiq ID. (not operational in v4; use PUT for now) v5: POST issuer-signed email & phone scopes in a self-signed JWT See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -291,8 +372,14 @@ export class Api extends HttpClient { * @name KeyUpdate * @request POST:/key/{PK} */ - keyUpdate: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "POST", params, body), + keyUpdate: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Update Authentiq ID by replacing the object. v4: `JWT(sub,email,phone)` to bind email/phone hash; v5: POST issuer-signed email & phone scopes and PUT to update registration `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -301,8 +388,14 @@ export class Api extends HttpClient { * @name KeyBind * @request PUT:/key/{PK} */ - keyBind: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "PUT", params, body), + keyBind: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "PUT", + body: body, + format: "json", + ...params, + }), }; login = { /** @@ -312,8 +405,15 @@ export class Api extends HttpClient { * @name PushLoginRequest * @request POST:/login */ - pushLoginRequest: (query: PushLoginRequestParams, body: PushToken, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/login${this.addQueryParams(query)}`, "POST", params, body), + pushLoginRequest: (query: PushLoginRequestParams, body: PushToken, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/login`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), }; scope = { /** @@ -323,13 +423,15 @@ export class Api extends HttpClient { * @name SignRequest * @request POST:/scope */ - signRequest: (query: SignRequestParams, body: Claims, params?: RequestParams) => - this.request<{ job?: string; status?: string }, Error>( - `/scope${this.addQueryParams(query)}`, - "POST", - params, - body, - ), + signRequest: (query: SignRequestParams, body: Claims, params: RequestParams = {}) => + this.request<{ job?: string; status?: string }, Error>({ + path: `/scope`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), /** * @description delete a verification job @@ -338,8 +440,13 @@ export class Api extends HttpClient { * @name SignDelete * @request DELETE:/scope/{job} */ - signDelete: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "DELETE", params), + signDelete: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "DELETE", + format: "json", + ...params, + }), /** * @description get the status / current content of a verification job @@ -348,8 +455,13 @@ export class Api extends HttpClient { * @name SignRetrieve * @request GET:/scope/{job} */ - signRetrieve: (job: string, params?: RequestParams) => - this.request<{ exp?: number; field?: string; sub?: string }, Error>(`/scope/${job}`, "GET", params), + signRetrieve: (job: string, params: RequestParams = {}) => + this.request<{ exp?: number; field?: string; sub?: string }, Error>({ + path: `/scope/${job}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD to get the status of a verification job @@ -358,8 +470,12 @@ export class Api extends HttpClient { * @name SignRetrieveHead * @request HEAD:/scope/{job} */ - signRetrieveHead: (job: string, params?: RequestParams) => - this.request(`/scope/${job}`, "HEAD", params), + signRetrieveHead: (job: string, params: RequestParams = {}) => + this.request({ + path: `/scope/${job}`, + method: "HEAD", + ...params, + }), /** * @description this is a scope confirmation @@ -368,8 +484,14 @@ export class Api extends HttpClient { * @name SignConfirm * @request POST:/scope/{job} */ - signConfirm: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "POST", params, null, BodyType.Json), + signConfirm: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "POST", + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description authority updates a JWT with its signature See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -378,7 +500,11 @@ export class Api extends HttpClient { * @name SignUpdate * @request PUT:/scope/{job} */ - signUpdate: (job: string, params?: RequestParams) => - this.request<{ jwt?: string; status?: string }, Error>(`/scope/${job}`, "PUT", params), + signUpdate: (job: string, params: RequestParams = {}) => + this.request<{ jwt?: string; status?: string }, Error>({ + path: `/scope/${job}`, + method: "PUT", + ...params, + }), }; } diff --git a/tests/spec/js/schema.d.ts b/tests/spec/js/schema.d.ts index 5f3e0767..7423b21d 100644 --- a/tests/spec/js/schema.d.ts +++ b/tests/spec/js/schema.d.ts @@ -1694,45 +1694,68 @@ export interface UserUpdate { name?: string; } export declare type Users = User[]; -export declare type RequestParams = Omit & { +export declare type QueryParamsType = Record; +export declare type ResponseFormat = keyof Omit; +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; -export declare type RequestQueryParamsType = Record; -interface ApiConfig { + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + /** request cancellation token */ + cancelToken?: CancelToken; +} +export declare type RequestParams = Omit; +interface ApiConfig { + baseUrl?: string; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { data: D; error: E; } -declare enum BodyType { - Json = 0, - FormData = 1, - UrlEncoded = 2, +declare type CancelToken = Symbol | string | number; +export declare enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export declare class HttpClient { baseUrl: string; private securityData; private securityWorker; + private abortControllers; private baseApiParams; constructor(apiConfig?: ApiConfig); setSecurityData: (data: SecurityDataType) => void; private addQueryParam; - protected toQueryString(rawQuery?: RequestQueryParamsType): string; - protected addQueryParams(rawQuery?: RequestQueryParamsType): string; - private bodyFormatters; - private mergeRequestOptions; - private safeParseResponse; - request: ( - path: string, - method: string, - { secure, ...params }?: RequestParams, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ) => Promise>; + protected toQueryString(rawQuery?: QueryParamsType): string; + protected addQueryParams(rawQuery?: QueryParamsType): string; + private contentFormatters; + private mergeRequestParams; + private createAbortSignal; + abortRequest: (cancelToken: CancelToken) => void; + request: ({ + body, + secure, + path, + type, + query, + format, + baseUrl, + cancelToken, + ...params + }: FullRequestParams) => Promise>; } /** * @title GitHub @@ -1740,7 +1763,7 @@ export declare class HttpClient { * @baseUrl https://api.github.com * Powerful collaboration, code review, and code management for open source and private projects. */ -export declare class Api extends HttpClient { +export declare class Api extends HttpClient { emojis: { /** * @description Lists all the emojis available to use on GitHub. @@ -1748,7 +1771,7 @@ export declare class Api extends HttpClient Promise, unknown>>; + emojisList: (params?: RequestParams) => Promise, void>>; }; events: { /** @@ -1757,7 +1780,7 @@ export declare class Api extends HttpClient Promise>; + eventsList: (params?: RequestParams) => Promise>; }; feeds: { /** @@ -1766,7 +1789,7 @@ export declare class Api extends HttpClient Promise>; + feedsList: (params?: RequestParams) => Promise>; }; gists: { /** @@ -1780,14 +1803,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a gist. * * @name GistsCreate * @request POST:/gists */ - gistsCreate: (body: PostGist, params?: RequestParams) => Promise>; + gistsCreate: (body: PostGist, params?: RequestParams) => Promise>; /** * @description List all public gists. * @@ -1799,7 +1822,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List the authenticated user's starred gists. * @@ -1811,49 +1834,49 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a gist. * * @name GistsDelete * @request DELETE:/gists/{id} */ - gistsDelete: (id: number, params?: RequestParams) => Promise>; + gistsDelete: (id: number, params?: RequestParams) => Promise>; /** * @description Get a single gist. * * @name GistsDetail * @request GET:/gists/{id} */ - gistsDetail: (id: number, params?: RequestParams) => Promise>; + gistsDetail: (id: number, params?: RequestParams) => Promise>; /** * @description Edit a gist. * * @name GistsPartialUpdate * @request PATCH:/gists/{id} */ - gistsPartialUpdate: (id: number, body: PatchGist, params?: RequestParams) => Promise>; + gistsPartialUpdate: (id: number, body: PatchGist, params?: RequestParams) => Promise>; /** * @description List comments on a gist. * * @name CommentsDetail * @request GET:/gists/{id}/comments */ - commentsDetail: (id: number, params?: RequestParams) => Promise>; + commentsDetail: (id: number, params?: RequestParams) => Promise>; /** * @description Create a commen * * @name CommentsCreate * @request POST:/gists/{id}/comments */ - commentsCreate: (id: number, body: CommentBody, params?: RequestParams) => Promise>; + commentsCreate: (id: number, body: CommentBody, params?: RequestParams) => Promise>; /** * @description Delete a comment. * * @name CommentsDelete * @request DELETE:/gists/{id}/comments/{commentId} */ - commentsDelete: (id: number, commentId: number, params?: RequestParams) => Promise>; + commentsDelete: (id: number, commentId: number, params?: RequestParams) => Promise>; /** * @description Get a single comment. * @@ -1862,7 +1885,7 @@ export declare class Api extends HttpClient Promise>; + commentsDetail2: (id: number, commentId: number, params?: RequestParams) => Promise>; /** * @description Edit a comment. * @@ -1874,35 +1897,35 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Fork a gist. * * @name ForksCreate * @request POST:/gists/{id}/forks */ - forksCreate: (id: number, params?: RequestParams) => Promise>; + forksCreate: (id: number, params?: RequestParams) => Promise>; /** * @description Unstar a gist. * * @name StarDelete * @request DELETE:/gists/{id}/star */ - starDelete: (id: number, params?: RequestParams) => Promise>; + starDelete: (id: number, params?: RequestParams) => Promise>; /** * @description Check if a gist is starred. * * @name StarDetail * @request GET:/gists/{id}/star */ - starDetail: (id: number, params?: RequestParams) => Promise>; + starDetail: (id: number, params?: RequestParams) => Promise>; /** * @description Star a gist. * * @name StarUpdate * @request PUT:/gists/{id}/star */ - starUpdate: (id: number, params?: RequestParams) => Promise>; + starUpdate: (id: number, params?: RequestParams) => Promise>; }; gitignore: { /** @@ -1911,14 +1934,14 @@ export declare class Api extends HttpClient Promise>; + templatesList: (params?: RequestParams) => Promise>; /** * @description Get a single template. * * @name TemplatesDetail * @request GET:/gitignore/templates/{language} */ - templatesDetail: (language: string, params?: RequestParams) => Promise>; + templatesDetail: (language: string, params?: RequestParams) => Promise>; }; issues: { /** @@ -1937,7 +1960,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; }; legacy: { /** @@ -1952,7 +1975,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Find repositories by keyword. Note, this legacy method does not follow the v3 pagination pattern. This method returns up to 100 results per page and pages can be fetched using the start_page parameter. * @@ -1968,14 +1991,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description This API call is added for compatibility reasons only. * * @name UserEmailDetail * @request GET:/legacy/user/email/{email} */ - userEmailDetail: (email: string, params?: RequestParams) => Promise>; + userEmailDetail: (email: string, params?: RequestParams) => Promise>; /** * @description Find users by keyword. * @@ -1990,7 +2013,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; }; markdown: { /** @@ -1999,14 +2022,14 @@ export declare class Api extends HttpClient Promise>; + markdownCreate: (body: Markdown, params?: RequestParams) => Promise>; /** * @description Render a Markdown document in raw mode * * @name PostMarkdown * @request POST:/markdown/raw */ - postMarkdown: (params?: RequestParams) => Promise>; + postMarkdown: (params?: RequestParams) => Promise>; }; meta: { /** @@ -2015,7 +2038,7 @@ export declare class Api extends HttpClient Promise>; + metaList: (params?: RequestParams) => Promise>; }; networks: { /** @@ -2024,7 +2047,7 @@ export declare class Api extends HttpClient Promise>; + eventsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; }; notifications: { /** @@ -2040,42 +2063,42 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Mark as read. Marking a notification as "read" removes it from the default view on GitHub.com. * * @name NotificationsUpdate * @request PUT:/notifications */ - notificationsUpdate: (body: NotificationMarkRead, params?: RequestParams) => Promise>; + notificationsUpdate: (body: NotificationMarkRead, params?: RequestParams) => Promise>; /** * @description View a single thread. * * @name ThreadsDetail * @request GET:/notifications/threads/{id} */ - threadsDetail: (id: number, params?: RequestParams) => Promise>; + threadsDetail: (id: number, params?: RequestParams) => Promise>; /** * @description Mark a thread as read * * @name ThreadsPartialUpdate * @request PATCH:/notifications/threads/{id} */ - threadsPartialUpdate: (id: number, params?: RequestParams) => Promise>; + threadsPartialUpdate: (id: number, params?: RequestParams) => Promise>; /** * @description Delete a Thread Subscription. * * @name ThreadsSubscriptionDelete * @request DELETE:/notifications/threads/{id}/subscription */ - threadsSubscriptionDelete: (id: number, params?: RequestParams) => Promise>; + threadsSubscriptionDelete: (id: number, params?: RequestParams) => Promise>; /** * @description Get a Thread Subscription. * * @name ThreadsSubscriptionDetail * @request GET:/notifications/threads/{id}/subscription */ - threadsSubscriptionDetail: (id: number, params?: RequestParams) => Promise>; + threadsSubscriptionDetail: (id: number, params?: RequestParams) => Promise>; /** * @description Set a Thread Subscription. This lets you subscribe to a thread, or ignore it. Subscribing to a thread is unnecessary if the user is already subscribed to the repository. Ignoring a thread will mute all future notifications (until you comment or get @mentioned). * @@ -2086,7 +2109,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; }; orgs: { /** @@ -2095,21 +2118,21 @@ export declare class Api extends HttpClient Promise>; + orgsDetail: (org: string, params?: RequestParams) => Promise>; /** * @description Edit an Organization. * * @name OrgsPartialUpdate * @request PATCH:/orgs/{org} */ - orgsPartialUpdate: (org: string, body: PatchOrg, params?: RequestParams) => Promise>; + orgsPartialUpdate: (org: string, body: PatchOrg, params?: RequestParams) => Promise>; /** * @description List public events for an organization. * * @name EventsDetail * @request GET:/orgs/{org}/events */ - eventsDetail: (org: string, params?: RequestParams) => Promise>; + eventsDetail: (org: string, params?: RequestParams) => Promise>; /** * @description List issues. List all issues for a given organization for the authenticated user. * @@ -2127,21 +2150,21 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Members list. List all users who are members of an organization. A member is a user tha belongs to at least 1 team in the organization. If the authenticated user is also an owner of this organization then both concealed and public members will be returned. If the requester is not an owner of the organization the query will be redirected to the public members list. * * @name MembersDetail * @request GET:/orgs/{org}/members */ - membersDetail: (org: string, params?: RequestParams) => Promise>; + membersDetail: (org: string, params?: RequestParams) => Promise>; /** * @description Remove a member. Removing a user from this list will remove them from all teams and they will no longer have any access to the organization's repositories. * * @name MembersDelete * @request DELETE:/orgs/{org}/members/{username} */ - membersDelete: (org: string, username: string, params?: RequestParams) => Promise>; + membersDelete: (org: string, username: string, params?: RequestParams) => Promise>; /** * @description Check if a user is, publicly or privately, a member of the organization. * @@ -2150,21 +2173,21 @@ export declare class Api extends HttpClient Promise>; + membersDetail2: (org: string, username: string, params?: RequestParams) => Promise>; /** * @description Public members list. Members of an organization can choose to have their membership publicized or not. * * @name PublicMembersDetail * @request GET:/orgs/{org}/public_members */ - publicMembersDetail: (org: string, params?: RequestParams) => Promise>; + publicMembersDetail: (org: string, params?: RequestParams) => Promise>; /** * @description Conceal a user's membership. * * @name PublicMembersDelete * @request DELETE:/orgs/{org}/public_members/{username} */ - publicMembersDelete: (org: string, username: string, params?: RequestParams) => Promise>; + publicMembersDelete: (org: string, username: string, params?: RequestParams) => Promise>; /** * @description Check public membership. * @@ -2173,18 +2196,14 @@ export declare class Api extends HttpClient Promise>; + publicMembersDetail2: (org: string, username: string, params?: RequestParams) => Promise>; /** * @description Publicize a user's membership. * * @name PublicMembersUpdate * @request PUT:/orgs/{org}/public_members/{username} */ - publicMembersUpdate: (org: string, username: string, params?: RequestParams) => Promise>; + publicMembersUpdate: (org: string, username: string, params?: RequestParams) => Promise>; /** * @description List repositories for the specified org. * @@ -2197,28 +2216,28 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. * * @name ReposCreate * @request POST:/orgs/{org}/repos */ - reposCreate: (org: string, body: PostRepo, params?: RequestParams) => Promise>; + reposCreate: (org: string, body: PostRepo, params?: RequestParams) => Promise>; /** * @description List teams. * * @name TeamsDetail * @request GET:/orgs/{org}/teams */ - teamsDetail: (org: string, params?: RequestParams) => Promise>; + teamsDetail: (org: string, params?: RequestParams) => Promise>; /** * @description Create team. In order to create a team, the authenticated user must be an owner of organization. * * @name TeamsCreate * @request POST:/orgs/{org}/teams */ - teamsCreate: (org: string, body: OrgTeamsPost, params?: RequestParams) => Promise>; + teamsCreate: (org: string, body: OrgTeamsPost, params?: RequestParams) => Promise>; }; rateLimit: { /** @@ -2227,7 +2246,7 @@ export declare class Api extends HttpClient Promise>; + rateLimitList: (params?: RequestParams) => Promise>; }; repos: { /** @@ -2236,14 +2255,14 @@ export declare class Api extends HttpClient Promise>; + reposDelete: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Get repository. * * @name ReposDetail * @request GET:/repos/{owner}/{repo} */ - reposDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + reposDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Edit repository. * @@ -2255,14 +2274,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List assignees. This call lists all the available assignees (owner + collaborators) to which issues may be assigned. * * @name AssigneesDetail * @request GET:/repos/{owner}/{repo}/assignees */ - assigneesDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + assigneesDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Check assignee. You may also check to see if a particular user is an assignee for a repository. * @@ -2276,14 +2295,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get list of branches * * @name BranchesDetail * @request GET:/repos/{owner}/{repo}/branches */ - branchesDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + branchesDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Get Branch * @@ -2297,14 +2316,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List. When authenticating as an organization owner of an organization-owned repository, all organization owners are included in the list of collaborators. Otherwise, only users with access to the repository are returned in the collaborators list. * * @name CollaboratorsDetail * @request GET:/repos/{owner}/{repo}/collaborators */ - collaboratorsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + collaboratorsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Remove collaborator. * @@ -2316,7 +2335,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Check if user is a collaborator * @@ -2330,7 +2349,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Add collaborator. * @@ -2342,18 +2361,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List commit comments for a repository. Comments are ordered by ascending ID. * * @name CommentsDetail * @request GET:/repos/{owner}/{repo}/comments */ - commentsDetail: ( - owner: string, - repo: string, - params?: RequestParams, - ) => Promise>; + commentsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Delete a commit comment * @@ -2365,7 +2380,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single commit comment. * @@ -2379,7 +2394,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Update a commit comment. * @@ -2392,7 +2407,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List commits on a repository. * @@ -2410,7 +2425,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get the combined Status for a specific Ref The Combined status endpoint is currently available for developers to preview. During the preview period, the API may change without advance notice. Please see the blog post for full details. To access this endpoint during the preview period, you must provide a custom media type in the Accept header: application/vnd.github.she-hulk-preview+json * @@ -2422,7 +2437,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single commit. * @@ -2436,7 +2451,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List comments for a single commitList comments for a single commit. * @@ -2448,7 +2463,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a commit comment. * @@ -2461,7 +2476,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Compare two commits * @@ -2474,7 +2489,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a file. This method deletes a file in a repository. * @@ -2487,7 +2502,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get contents. This method returns the contents of a file or directory in a repository. Files and symlinks support a custom media type for getting the raw content. Directories and submodules do not support custom media types. Note: This API supports files up to 1 megabyte in size. Here can be many outcomes. For details see "http://developer.github.com/v3/repos/contents/" * @@ -2503,7 +2518,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a file. * @@ -2516,7 +2531,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get list of contributors. * @@ -2530,7 +2545,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Users with pull access can view deployments for a repository * @@ -2541,7 +2556,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Users with push access can create a deployment for a given ref * @@ -2553,7 +2568,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Users with pull access can view deployment statuses for a deployment * @@ -2565,7 +2580,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a Deployment Status Users with push access can create deployment statuses for a given deployment: * @@ -2578,14 +2593,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Deprecated. List downloads for a repository. * * @name DownloadsDetail * @request GET:/repos/{owner}/{repo}/downloads */ - downloadsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + downloadsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Deprecated. Delete a download. * @@ -2597,7 +2612,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Deprecated. Get a single download. * @@ -2611,14 +2626,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get list of repository events. * * @name EventsDetail * @request GET:/repos/{owner}/{repo}/events */ - eventsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + eventsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description List forks. * @@ -2632,7 +2647,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a fork. Forking a Repository happens asynchronously. Therefore, you may have to wai a short period before accessing the git objects. If this takes longer than 5 minutes, be sure to contact Support. * @@ -2644,7 +2659,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a Blob. * @@ -2656,7 +2671,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a Blob. Since blobs can be any arbitrary binary data, the input and responses for the blob API takes an encoding parameter that can be either utf-8 or base64. If your data cannot be losslessly sent as a UTF-8 string, you can base64 encode it. * @@ -2668,7 +2683,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a Commit. * @@ -2680,7 +2695,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a Commit. * @@ -2692,14 +2707,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get all References * * @name GitRefsDetail * @request GET:/repos/{owner}/{repo}/git/refs */ - gitRefsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + gitRefsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Create a Reference * @@ -2711,7 +2726,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a Reference Example: Deleting a branch: DELETE /repos/octocat/Hello-World/git/refs/heads/feature-a Example: Deleting a tag: DELETE /repos/octocat/Hello-World/git/refs/tags/v1.0 * @@ -2723,7 +2738,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a Reference * @@ -2737,7 +2752,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Update a Reference * @@ -2750,7 +2765,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a Tag Object. Note that creating a tag object does not create the reference that makes a tag in Git. If you want to create an annotated tag in Git, you have to do this call to create the tag object, and then create the refs/tags/[tag] reference. If you want to create a lightweight tag, you only have to create the tag reference - this call would be unnecessary. * @@ -2762,7 +2777,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a Tag. * @@ -2774,7 +2789,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a Tree. The tree creation API will take nested entries as well. If both a tree and a nested path modifying that tree are specified, it will overwrite the contents of that tree with the new path contents and write a new tree out. * @@ -2786,7 +2801,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a Tree. * @@ -2801,14 +2816,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get list of hooks. * * @name HooksDetail * @request GET:/repos/{owner}/{repo}/hooks */ - hooksDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + hooksDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Create a hook. * @@ -2820,7 +2835,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a hook. * @@ -2832,7 +2847,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get single hook. * @@ -2846,7 +2861,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Edit a hook. * @@ -2859,7 +2874,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Test a push hook. This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook is not subscribed to push events, the server will respond with 204 but no test POST will be generated. Note: Previously /repos/:owner/:repo/hooks/:id/tes * @@ -2871,7 +2886,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List issues for a repository. * @@ -2890,7 +2905,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create an issue. Any user with pull access to a repository can create an issue. * @@ -2902,7 +2917,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List comments in a repository. * @@ -2918,7 +2933,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a comment. * @@ -2930,7 +2945,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single comment. * @@ -2944,7 +2959,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Edit a comment. * @@ -2957,7 +2972,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List issue events for a repository. * @@ -2968,7 +2983,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single event. * @@ -2982,7 +2997,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single issue * @@ -2996,7 +3011,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Edit an issue. Issue owners and users with push access can edit an issue. * @@ -3009,7 +3024,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List comments on an issue. * @@ -3023,7 +3038,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a comment. * @@ -3036,7 +3051,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List events for an issue. * @@ -3050,7 +3065,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Remove all labels from an issue. * @@ -3062,7 +3077,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List labels on an issue. * @@ -3074,7 +3089,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Add labels to an issue. * @@ -3087,7 +3102,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Replace all labels for an issue. Sending an empty array ([]) will remove all Labels from the Issue. * @@ -3100,7 +3115,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Remove a label from an issue. * @@ -3115,14 +3130,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get list of keys. * * @name KeysDetail * @request GET:/repos/{owner}/{repo}/keys */ - keysDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + keysDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Create a key. * @@ -3134,7 +3149,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a key. * @@ -3146,7 +3161,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a key * @@ -3160,14 +3175,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List all labels for this repository. * * @name LabelsDetail * @request GET:/repos/{owner}/{repo}/labels */ - labelsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + labelsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Create a label. * @@ -3179,7 +3194,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a label. * @@ -3191,7 +3206,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single label. * @@ -3205,7 +3220,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Update a label. * @@ -3218,7 +3233,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List languages. List languages for the specified repository. The value on the right of a language is the number of bytes of code written in that language. * @@ -3229,7 +3244,7 @@ export declare class Api extends HttpClient Promise, unknown>>; + ) => Promise, void>>; /** * @description Perform a merge. * @@ -3241,7 +3256,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List milestones for a repository. * @@ -3257,7 +3272,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a milestone. * @@ -3269,7 +3284,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a milestone. * @@ -3281,7 +3296,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single milestone. * @@ -3295,7 +3310,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Update a milestone. * @@ -3308,7 +3323,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get labels for every issue in a milestone. * @@ -3320,7 +3335,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List your notifications in a repository List all notifications for the current user. * @@ -3336,7 +3351,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Mark notifications as read in a repository. Marking all notifications in a repository as "read" removes them from the default view on GitHub.com. * @@ -3348,7 +3363,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List pull requests. * @@ -3364,7 +3379,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a pull request. * @@ -3376,7 +3391,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List comments in a repository. By default, Review Comments are ordered by ascending ID. * @@ -3392,7 +3407,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a comment. * @@ -3404,7 +3419,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single comment. * @@ -3418,7 +3433,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Edit a comment. * @@ -3431,7 +3446,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single pull request. * @@ -3445,7 +3460,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Update a pull request. * @@ -3458,7 +3473,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List comments on a pull request. * @@ -3472,7 +3487,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a comment. #TODO Alternative input ( http://developer.github.com/v3/pulls/comments/ ) description: | Alternative Input. Instead of passing commit_id, path, and position you can reply to an existing Pull Request Comment like this: body Required string in_reply_to Required number - Comment id to reply to. * @@ -3485,7 +3500,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List commits on a pull request. * @@ -3497,7 +3512,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List pull requests files. * @@ -3509,7 +3524,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get if a pull request has been merged. * @@ -3521,7 +3536,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Merge a pull request (Merge Button's) * @@ -3534,7 +3549,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get the README. This method returns the preferred README for a repository. * @@ -3548,14 +3563,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Users with push access to the repository will receive all releases (i.e., published releases and draft releases). Users with pull access will receive published releases only * * @name ReleasesDetail * @request GET:/repos/{owner}/{repo}/releases */ - releasesDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + releasesDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Create a release Users with push access to the repository can create a release. * @@ -3567,7 +3582,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Delete a release asset * @@ -3579,7 +3594,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single release asset * @@ -3591,7 +3606,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Edit a release asset Users with push access to the repository can edit a release asset. * @@ -3604,7 +3619,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Users with push access to the repository can delete a release. * @@ -3616,7 +3631,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single release * @@ -3630,7 +3645,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Users with push access to the repository can edit a release * @@ -3643,7 +3658,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List assets for a release * @@ -3657,14 +3672,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List Stargazers. * * @name StargazersDetail * @request GET:/repos/{owner}/{repo}/stargazers */ - stargazersDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + stargazersDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Get the number of additions and deletions per week. Returns a weekly aggregate of the number of additions and deletions pushed to a repository. * @@ -3675,7 +3690,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get the last year of commit activity data. Returns the last year of commit activity grouped by week. The days array is a group of commits per day, starting on Sunday. * @@ -3686,7 +3701,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get contributors list with additions, deletions, and commit counts. * @@ -3697,7 +3712,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get the weekly commit count for the repo owner and everyone else. * @@ -3708,7 +3723,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get the number of commits per hour in each day. Each array contains the day number, hour number, and number of commits 0-6 Sunday - Saturday 0-23 Hour of day Number of commits For example, [2, 14, 25] indicates that there were 25 total commits, during the 2.00pm hour on Tuesdays. All times are based on the time zone of individual commits. * @@ -3719,7 +3734,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List Statuses for a specific Ref. * @@ -3731,7 +3746,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a Status. * @@ -3744,21 +3759,21 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List watchers. * * @name SubscribersDetail * @request GET:/repos/{owner}/{repo}/subscribers */ - subscribersDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + subscribersDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Delete a Repository Subscription. * * @name SubscriptionDelete * @request DELETE:/repos/{owner}/{repo}/subscription */ - subscriptionDelete: (owner: string, repo: string, params?: RequestParams) => Promise>; + subscriptionDelete: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Get a Repository Subscription. * @@ -3769,7 +3784,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Set a Repository Subscription * @@ -3781,28 +3796,28 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get list of tags. * * @name TagsDetail * @request GET:/repos/{owner}/{repo}/tags */ - tagsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + tagsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Get list of teams * * @name TeamsDetail * @request GET:/repos/{owner}/{repo}/teams */ - teamsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + teamsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description List Stargazers. New implementation. * * @name WatchersDetail * @request GET:/repos/{owner}/{repo}/watchers */ - watchersDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + watchersDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Get archive link. This method will return a 302 to a URL to download a tarball or zipball archive for a repository. Please make sure your HTTP framework is configured to follow redirects or you will need to use the Location header to make a second GET request. Note: For private repositories, these links are temporary and expire quickly. * @@ -3817,7 +3832,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; }; repositories: { /** @@ -3831,7 +3846,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; }; search: { /** @@ -3847,7 +3862,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Find issues by state and keyword. (This method returns up to 100 results per page.) * @@ -3861,7 +3876,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Search repositories. * @@ -3875,7 +3890,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Search users. * @@ -3889,7 +3904,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; }; teams: { /** @@ -3898,39 +3913,35 @@ export declare class Api extends HttpClient Promise>; + teamsDelete: (teamId: number, params?: RequestParams) => Promise>; /** * @description Get team. * * @name TeamsDetail * @request GET:/teams/{teamId} */ - teamsDetail: (teamId: number, params?: RequestParams) => Promise>; + teamsDetail: (teamId: number, params?: RequestParams) => Promise>; /** * @description Edit team. In order to edit a team, the authenticated user must be an owner of the org that the team is associated with. * * @name TeamsPartialUpdate * @request PATCH:/teams/{teamId} */ - teamsPartialUpdate: ( - teamId: number, - body: EditTeam, - params?: RequestParams, - ) => Promise>; + teamsPartialUpdate: (teamId: number, body: EditTeam, params?: RequestParams) => Promise>; /** * @description List team members. In order to list members in a team, the authenticated user must be a member of the team. * * @name MembersDetail * @request GET:/teams/{teamId}/members */ - membersDetail: (teamId: number, params?: RequestParams) => Promise>; + membersDetail: (teamId: number, params?: RequestParams) => Promise>; /** * @description The "Remove team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Remove team membership API instead. It allows you to remove both active and pending memberships. Remove team member. In order to remove a user from a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. NOTE This does not delete the user, it just remove them from the team. * * @name MembersDelete * @request DELETE:/teams/{teamId}/members/{username} */ - membersDelete: (teamId: number, username: string, params?: RequestParams) => Promise>; + membersDelete: (teamId: number, username: string, params?: RequestParams) => Promise>; /** * @description The "Get team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Get team membership API instead. It allows you to get both active and pending memberships. Get team member. In order to get if a user is a member of a team, the authenticated user mus be a member of the team. * @@ -3939,25 +3950,25 @@ export declare class Api extends HttpClient Promise>; + membersDetail2: (teamId: number, username: string, params?: RequestParams) => Promise>; /** * @description The API (described below) is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Add team membership API instead. It allows you to invite new organization members to your teams. Add team member. In order to add a user to a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. * * @name MembersUpdate * @request PUT:/teams/{teamId}/members/{username} */ - membersUpdate: (teamId: number, username: string, params?: RequestParams) => Promise>; + membersUpdate: ( + teamId: number, + username: string, + params?: RequestParams, + ) => Promise>; /** * @description Remove team membership. In order to remove a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. NOTE: This does not delete the user, it just removes their membership from the team. * * @name MembershipsDelete * @request DELETE:/teams/{teamId}/memberships/{username} */ - membershipsDelete: ( - teamId: number, - username: string, - params?: RequestParams, - ) => Promise>; + membershipsDelete: (teamId: number, username: string, params?: RequestParams) => Promise>; /** * @description Get team membership. In order to get a user's membership with a team, the authenticated user must be a member of the team or an owner of the team's organization. * @@ -3968,7 +3979,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Add team membership. In order to add a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. If the user is already a part of the team's organization (meaning they're on at least one other team in the organization), this endpoint will add the user to the team. If the user is completely unaffiliated with the team's organization (meaning they're on none of the organization's teams), this endpoint will send an invitation to the user via email. This newly-created membership will be in the 'pending' state until the user accepts the invitation, at which point the membership will transition to the 'active' state and the user will be added as a member of the team. * @@ -3979,14 +3990,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List team repos * * @name ReposDetail * @request GET:/teams/{teamId}/repos */ - reposDetail: (teamId: number, params?: RequestParams) => Promise>; + reposDetail: (teamId: number, params?: RequestParams) => Promise>; /** * @description In order to remove a repository from a team, the authenticated user must be an owner of the org that the team is associated with. NOTE: This does not delete the repository, it just removes it from the team. * @@ -3998,7 +4009,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Check if a team manages a repository * @@ -4012,7 +4023,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description In order to add a repository to a team, the authenticated user must be an owner of the org that the team is associated with. Also, the repository must be owned by the organization, or a direct fork of a repository owned by the organization. * @@ -4024,7 +4035,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; }; user: { /** @@ -4033,70 +4044,70 @@ export declare class Api extends HttpClient Promise>; + userList: (params?: RequestParams) => Promise>; /** * @description Update the authenticated user. * * @name UserPartialUpdate * @request PATCH:/user */ - userPartialUpdate: (body: UserUpdate, params?: RequestParams) => Promise>; + userPartialUpdate: (body: UserUpdate, params?: RequestParams) => Promise>; /** * @description Delete email address(es). You can include a single email address or an array of addresses. * * @name EmailsDelete * @request DELETE:/user/emails */ - emailsDelete: (body: UserEmails, params?: RequestParams) => Promise>; + emailsDelete: (body: UserEmails, params?: RequestParams) => Promise>; /** * @description List email addresses for a user. In the final version of the API, this method will return an array of hashes with extended information for each email address indicating if the address has been verified and if it's primary email address for GitHub. Until API v3 is finalized, use the application/vnd.github.v3 media type to get other response format. * * @name EmailsList * @request GET:/user/emails */ - emailsList: (params?: RequestParams) => Promise>; + emailsList: (params?: RequestParams) => Promise>; /** * @description Add email address(es). You can post a single email address or an array of addresses. * * @name EmailsCreate * @request POST:/user/emails */ - emailsCreate: (body: EmailsPost, params?: RequestParams) => Promise>; + emailsCreate: (body: EmailsPost, params?: RequestParams) => Promise>; /** * @description List the authenticated user's followers * * @name FollowersList * @request GET:/user/followers */ - followersList: (params?: RequestParams) => Promise>; + followersList: (params?: RequestParams) => Promise>; /** * @description List who the authenticated user is following. * * @name FollowingList * @request GET:/user/following */ - followingList: (params?: RequestParams) => Promise>; + followingList: (params?: RequestParams) => Promise>; /** * @description Unfollow a user. Unfollowing a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. * * @name FollowingDelete * @request DELETE:/user/following/{username} */ - followingDelete: (username: string, params?: RequestParams) => Promise>; + followingDelete: (username: string, params?: RequestParams) => Promise>; /** * @description Check if you are following a user. * * @name FollowingDetail * @request GET:/user/following/{username} */ - followingDetail: (username: string, params?: RequestParams) => Promise>; + followingDetail: (username: string, params?: RequestParams) => Promise>; /** * @description Follow a user. Following a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. * * @name FollowingUpdate * @request PUT:/user/following/{username} */ - followingUpdate: (username: string, params?: RequestParams) => Promise>; + followingUpdate: (username: string, params?: RequestParams) => Promise>; /** * @description List issues. List all issues across owned and member repositories for the authenticated user. * @@ -4113,42 +4124,42 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List your public keys. Lists the current user's keys. Management of public keys via the API requires that you are authenticated through basic auth, or OAuth with the 'user', 'write:public_key' scopes. * * @name KeysList * @request GET:/user/keys */ - keysList: (params?: RequestParams) => Promise>; + keysList: (params?: RequestParams) => Promise>; /** * @description Create a public key. * * @name KeysCreate * @request POST:/user/keys */ - keysCreate: (body: UserKeysPost, params?: RequestParams) => Promise>; + keysCreate: (body: UserKeysPost, params?: RequestParams) => Promise>; /** * @description Delete a public key. Removes a public key. Requires that you are authenticated via Basic Auth or via OAuth with at least admin:public_key scope. * * @name KeysDelete * @request DELETE:/user/keys/{keyId} */ - keysDelete: (keyId: number, params?: RequestParams) => Promise>; + keysDelete: (keyId: number, params?: RequestParams) => Promise>; /** * @description Get a single public key. * * @name KeysDetail * @request GET:/user/keys/{keyId} */ - keysDetail: (keyId: number, params?: RequestParams) => Promise>; + keysDetail: (keyId: number, params?: RequestParams) => Promise>; /** * @description List public and private organizations for the authenticated user. * * @name OrgsList * @request GET:/user/orgs */ - orgsList: (params?: RequestParams) => Promise>; + orgsList: (params?: RequestParams) => Promise>; /** * @description List repositories for the authenticated user. Note that this does not include repositories owned by organizations which the user can access. You can lis user organizations and list organization repositories separately. * @@ -4160,14 +4171,14 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. * * @name ReposCreate * @request POST:/user/repos */ - reposCreate: (body: PostRepo, params?: RequestParams) => Promise>; + reposCreate: (body: PostRepo, params?: RequestParams) => Promise>; /** * @description List repositories being starred by the authenticated user. * @@ -4180,63 +4191,63 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Unstar a repository * * @name StarredDelete * @request DELETE:/user/starred/{owner}/{repo} */ - starredDelete: (owner: string, repo: string, params?: RequestParams) => Promise>; + starredDelete: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Check if you are starring a repository. * * @name StarredDetail * @request GET:/user/starred/{owner}/{repo} */ - starredDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + starredDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Star a repository. * * @name StarredUpdate * @request PUT:/user/starred/{owner}/{repo} */ - starredUpdate: (owner: string, repo: string, params?: RequestParams) => Promise>; + starredUpdate: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description List repositories being watched by the authenticated user. * * @name SubscriptionsList * @request GET:/user/subscriptions */ - subscriptionsList: (params?: RequestParams) => Promise>; + subscriptionsList: (params?: RequestParams) => Promise>; /** * @description Stop watching a repository * * @name SubscriptionsDelete * @request DELETE:/user/subscriptions/{owner}/{repo} */ - subscriptionsDelete: (owner: string, repo: string, params?: RequestParams) => Promise>; + subscriptionsDelete: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Check if you are watching a repository. * * @name SubscriptionsDetail * @request GET:/user/subscriptions/{owner}/{repo} */ - subscriptionsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; + subscriptionsDetail: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description Watch a repository. * * @name SubscriptionsUpdate * @request PUT:/user/subscriptions/{owner}/{repo} */ - subscriptionsUpdate: (owner: string, repo: string, params?: RequestParams) => Promise>; + subscriptionsUpdate: (owner: string, repo: string, params?: RequestParams) => Promise>; /** * @description List all of the teams across all of the organizations to which the authenticated user belongs. This method requires user or repo scope when authenticating via OAuth. * * @name TeamsList * @request GET:/user/teams */ - teamsList: (params?: RequestParams) => Promise>; + teamsList: (params?: RequestParams) => Promise>; }; users: { /** @@ -4250,35 +4261,35 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description Get a single user. * * @name UsersDetail * @request GET:/users/{username} */ - usersDetail: (username: string, params?: RequestParams) => Promise>; + usersDetail: (username: string, params?: RequestParams) => Promise>; /** * @description If you are authenticated as the given user, you will see your private events. Otherwise, you'll only see public events. * * @name EventsDetail * @request GET:/users/{username}/events */ - eventsDetail: (username: string, params?: RequestParams) => Promise>; + eventsDetail: (username: string, params?: RequestParams) => Promise>; /** * @description This is the user's organization dashboard. You must be authenticated as the user to view this. * * @name EventsOrgsDetail * @request GET:/users/{username}/events/orgs/{org} */ - eventsOrgsDetail: (username: string, org: string, params?: RequestParams) => Promise>; + eventsOrgsDetail: (username: string, org: string, params?: RequestParams) => Promise>; /** * @description List a user's followers * * @name FollowersDetail * @request GET:/users/{username}/followers */ - followersDetail: (username: string, params?: RequestParams) => Promise>; + followersDetail: (username: string, params?: RequestParams) => Promise>; /** * @description Check if one user follows another. * @@ -4289,7 +4300,7 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List a users gists. * @@ -4302,35 +4313,35 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List public keys for a user. Lists the verified public keys for a user. This is accessible by anyone. * * @name KeysDetail * @request GET:/users/{username}/keys */ - keysDetail: (username: string, params?: RequestParams) => Promise>; + keysDetail: (username: string, params?: RequestParams) => Promise>; /** * @description List all public organizations for a user. * * @name OrgsDetail * @request GET:/users/{username}/orgs */ - orgsDetail: (username: string, params?: RequestParams) => Promise>; + orgsDetail: (username: string, params?: RequestParams) => Promise>; /** * @description These are events that you'll only see public events. * * @name ReceivedEventsDetail * @request GET:/users/{username}/received_events */ - receivedEventsDetail: (username: string, params?: RequestParams) => Promise>; + receivedEventsDetail: (username: string, params?: RequestParams) => Promise>; /** * @description List public events that a user has received * * @name ReceivedEventsPublicDetail * @request GET:/users/{username}/received_events/public */ - receivedEventsPublicDetail: (username: string, params?: RequestParams) => Promise>; + receivedEventsPublicDetail: (username: string, params?: RequestParams) => Promise>; /** * @description List public repositories for the specified user. * @@ -4343,21 +4354,21 @@ export declare class Api extends HttpClient Promise>; + ) => Promise>; /** * @description List repositories being starred by a user. * * @name StarredDetail * @request GET:/users/{username}/starred */ - starredDetail: (username: string, params?: RequestParams) => Promise>; + starredDetail: (username: string, params?: RequestParams) => Promise>; /** * @description List repositories being watched by a user. * * @name SubscriptionsDetail * @request GET:/users/{username}/subscriptions */ - subscriptionsDetail: (username: string, params?: RequestParams) => Promise>; + subscriptionsDetail: (username: string, params?: RequestParams) => Promise>; }; } export {}; diff --git a/tests/spec/js/schema.js b/tests/spec/js/schema.js index 664976ee..b89c359e 100644 --- a/tests/spec/js/schema.js +++ b/tests/spec/js/schema.js @@ -9,67 +9,88 @@ * --------------------------------------------------------------- */ -var BodyType; -(function (BodyType) { - BodyType[(BodyType["Json"] = 0)] = "Json"; - BodyType[(BodyType["FormData"] = 1)] = "FormData"; - BodyType[(BodyType["UrlEncoded"] = 2)] = "UrlEncoded"; -})(BodyType || (BodyType = {})); +export var ContentType; +(function (ContentType) { + ContentType["Json"] = "application/json"; + ContentType["FormData"] = "multipart/form-data"; + ContentType["UrlEncoded"] = "application/x-www-form-urlencoded"; +})(ContentType || (ContentType = {})); export class HttpClient { constructor(apiConfig = {}) { this.baseUrl = "https://api.github.com"; this.securityData = null; this.securityWorker = null; + this.abortControllers = new Map(); this.baseApiParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; this.setSecurityData = (data) => { this.securityData = data; }; - this.bodyFormatters = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input) => - Object.keys(input).reduce((data, key) => { + this.contentFormatters = { + [ContentType.Json]: (input) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input) => this.toQueryString(input), + }; + this.createAbortSignal = (cancelToken) => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - this.safeParseResponse = (response) => { - const r = response; - r.data = null; - r.error = null; - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + this.abortRequest = (cancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } }; - this.request = (path, method, { secure, ...params } = {}, body, bodyType, secureByDefault) => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); + this.request = ({ body, secure, path, type, query, format = "json", baseUrl, cancelToken, ...params }) => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response; + r.data = null; + r.error = null; + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } if (!response.ok) throw data; return data; }); @@ -77,8 +98,11 @@ export class HttpClient { Object.assign(this, apiConfig); } addQueryParam(query, key) { + const value = query[key]; return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } toQueryString(rawQuery) { @@ -96,15 +120,15 @@ export class HttpClient { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - mergeRequestOptions(params, securityParams) { + mergeRequestParams(params1, params2) { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } @@ -125,7 +149,13 @@ export class Api extends HttpClient { * @name EmojisList * @request GET:/emojis */ - emojisList: (params) => this.request(`/emojis`, "GET", params), + emojisList: (params = {}) => + this.request({ + path: `/emojis`, + method: "GET", + format: "json", + ...params, + }), }; this.events = { /** @@ -134,7 +164,13 @@ export class Api extends HttpClient { * @name EventsList * @request GET:/events */ - eventsList: (params) => this.request(`/events`, "GET", params), + eventsList: (params = {}) => + this.request({ + path: `/events`, + method: "GET", + format: "json", + ...params, + }), }; this.feeds = { /** @@ -143,7 +179,13 @@ export class Api extends HttpClient { * @name FeedsList * @request GET:/feeds */ - feedsList: (params) => this.request(`/feeds`, "GET", params), + feedsList: (params = {}) => + this.request({ + path: `/feeds`, + method: "GET", + format: "json", + ...params, + }), }; this.gists = { /** @@ -152,70 +194,136 @@ export class Api extends HttpClient { * @name GistsList * @request GET:/gists */ - gistsList: (query, params) => this.request(`/gists${this.addQueryParams(query)}`, "GET", params), + gistsList: (query, params = {}) => + this.request({ + path: `/gists`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a gist. * * @name GistsCreate * @request POST:/gists */ - gistsCreate: (body, params) => this.request(`/gists`, "POST", params, body, BodyType.Json), + gistsCreate: (body, params = {}) => + this.request({ + path: `/gists`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List all public gists. * * @name PublicList * @request GET:/gists/public */ - publicList: (query, params) => this.request(`/gists/public${this.addQueryParams(query)}`, "GET", params), + publicList: (query, params = {}) => + this.request({ + path: `/gists/public`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List the authenticated user's starred gists. * * @name StarredList * @request GET:/gists/starred */ - starredList: (query, params) => this.request(`/gists/starred${this.addQueryParams(query)}`, "GET", params), + starredList: (query, params = {}) => + this.request({ + path: `/gists/starred`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Delete a gist. * * @name GistsDelete * @request DELETE:/gists/{id} */ - gistsDelete: (id, params) => this.request(`/gists/${id}`, "DELETE", params), + gistsDelete: (id, params = {}) => + this.request({ + path: `/gists/${id}`, + method: "DELETE", + ...params, + }), /** * @description Get a single gist. * * @name GistsDetail * @request GET:/gists/{id} */ - gistsDetail: (id, params) => this.request(`/gists/${id}`, "GET", params), + gistsDetail: (id, params = {}) => + this.request({ + path: `/gists/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a gist. * * @name GistsPartialUpdate * @request PATCH:/gists/{id} */ - gistsPartialUpdate: (id, body, params) => this.request(`/gists/${id}`, "PATCH", params, body, BodyType.Json), + gistsPartialUpdate: (id, body, params = {}) => + this.request({ + path: `/gists/${id}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List comments on a gist. * * @name CommentsDetail * @request GET:/gists/{id}/comments */ - commentsDetail: (id, params) => this.request(`/gists/${id}/comments`, "GET", params), + commentsDetail: (id, params = {}) => + this.request({ + path: `/gists/${id}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a commen * * @name CommentsCreate * @request POST:/gists/{id}/comments */ - commentsCreate: (id, body, params) => this.request(`/gists/${id}/comments`, "POST", params, body), + commentsCreate: (id, body, params = {}) => + this.request({ + path: `/gists/${id}/comments`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a comment. * * @name CommentsDelete * @request DELETE:/gists/{id}/comments/{commentId} */ - commentsDelete: (id, commentId, params) => this.request(`/gists/${id}/comments/${commentId}`, "DELETE", params), + commentsDelete: (id, commentId, params = {}) => + this.request({ + path: `/gists/${id}/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single comment. * @@ -224,43 +332,76 @@ export class Api extends HttpClient { * @originalName commentsDetail * @duplicate */ - commentsDetail2: (id, commentId, params) => this.request(`/gists/${id}/comments/${commentId}`, "GET", params), + commentsDetail2: (id, commentId, params = {}) => + this.request({ + path: `/gists/${id}/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a comment. * * @name CommentsPartialUpdate * @request PATCH:/gists/{id}/comments/{commentId} */ - commentsPartialUpdate: (id, commentId, body, params) => - this.request(`/gists/${id}/comments/${commentId}`, "PATCH", params, body, BodyType.Json), + commentsPartialUpdate: (id, commentId, body, params = {}) => + this.request({ + path: `/gists/${id}/comments/${commentId}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Fork a gist. * * @name ForksCreate * @request POST:/gists/{id}/forks */ - forksCreate: (id, params) => this.request(`/gists/${id}/forks`, "POST", params), + forksCreate: (id, params = {}) => + this.request({ + path: `/gists/${id}/forks`, + method: "POST", + ...params, + }), /** * @description Unstar a gist. * * @name StarDelete * @request DELETE:/gists/{id}/star */ - starDelete: (id, params) => this.request(`/gists/${id}/star`, "DELETE", params), + starDelete: (id, params = {}) => + this.request({ + path: `/gists/${id}/star`, + method: "DELETE", + ...params, + }), /** * @description Check if a gist is starred. * * @name StarDetail * @request GET:/gists/{id}/star */ - starDetail: (id, params) => this.request(`/gists/${id}/star`, "GET", params), + starDetail: (id, params = {}) => + this.request({ + path: `/gists/${id}/star`, + method: "GET", + ...params, + }), /** * @description Star a gist. * * @name StarUpdate * @request PUT:/gists/{id}/star */ - starUpdate: (id, params) => this.request(`/gists/${id}/star`, "PUT", params), + starUpdate: (id, params = {}) => + this.request({ + path: `/gists/${id}/star`, + method: "PUT", + ...params, + }), }; this.gitignore = { /** @@ -269,14 +410,26 @@ export class Api extends HttpClient { * @name TemplatesList * @request GET:/gitignore/templates */ - templatesList: (params) => this.request(`/gitignore/templates`, "GET", params), + templatesList: (params = {}) => + this.request({ + path: `/gitignore/templates`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single template. * * @name TemplatesDetail * @request GET:/gitignore/templates/{language} */ - templatesDetail: (language, params) => this.request(`/gitignore/templates/${language}`, "GET", params), + templatesDetail: (language, params = {}) => + this.request({ + path: `/gitignore/templates/${language}`, + method: "GET", + format: "json", + ...params, + }), }; this.issues = { /** @@ -285,7 +438,14 @@ export class Api extends HttpClient { * @name IssuesList * @request GET:/issues */ - issuesList: (query, params) => this.request(`/issues${this.addQueryParams(query)}`, "GET", params), + issuesList: (query, params = {}) => + this.request({ + path: `/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; this.legacy = { /** @@ -294,31 +454,54 @@ export class Api extends HttpClient { * @name IssuesSearchDetail * @request GET:/legacy/issues/search/{owner}/{repository}/{state}/{keyword} */ - issuesSearchDetail: (keyword, state, owner, repository, params) => - this.request(`/legacy/issues/search/${owner}/${repository}/${state}/${keyword}`, "GET", params), + issuesSearchDetail: (keyword, state, owner, repository, params = {}) => + this.request({ + path: `/legacy/issues/search/${owner}/${repository}/${state}/${keyword}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Find repositories by keyword. Note, this legacy method does not follow the v3 pagination pattern. This method returns up to 100 results per page and pages can be fetched using the start_page parameter. * * @name ReposSearchDetail * @request GET:/legacy/repos/search/{keyword} */ - reposSearchDetail: (keyword, query, params) => - this.request(`/legacy/repos/search/${keyword}${this.addQueryParams(query)}`, "GET", params), + reposSearchDetail: (keyword, query, params = {}) => + this.request({ + path: `/legacy/repos/search/${keyword}`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description This API call is added for compatibility reasons only. * * @name UserEmailDetail * @request GET:/legacy/user/email/{email} */ - userEmailDetail: (email, params) => this.request(`/legacy/user/email/${email}`, "GET", params), + userEmailDetail: (email, params = {}) => + this.request({ + path: `/legacy/user/email/${email}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Find users by keyword. * * @name UserSearchDetail * @request GET:/legacy/user/search/{keyword} */ - userSearchDetail: (keyword, query, params) => - this.request(`/legacy/user/search/${keyword}${this.addQueryParams(query)}`, "GET", params), + userSearchDetail: (keyword, query, params = {}) => + this.request({ + path: `/legacy/user/search/${keyword}`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; this.markdown = { /** @@ -327,14 +510,26 @@ export class Api extends HttpClient { * @name MarkdownCreate * @request POST:/markdown */ - markdownCreate: (body, params) => this.request(`/markdown`, "POST", params, body, BodyType.Json), + markdownCreate: (body, params = {}) => + this.request({ + path: `/markdown`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description Render a Markdown document in raw mode * * @name PostMarkdown * @request POST:/markdown/raw */ - postMarkdown: (params) => this.request(`/markdown/raw`, "POST", params), + postMarkdown: (params = {}) => + this.request({ + path: `/markdown/raw`, + method: "POST", + ...params, + }), }; this.meta = { /** @@ -343,7 +538,13 @@ export class Api extends HttpClient { * @name MetaList * @request GET:/meta */ - metaList: (params) => this.request(`/meta`, "GET", params), + metaList: (params = {}) => + this.request({ + path: `/meta`, + method: "GET", + format: "json", + ...params, + }), }; this.networks = { /** @@ -352,7 +553,13 @@ export class Api extends HttpClient { * @name EventsDetail * @request GET:/networks/{owner}/{repo}/events */ - eventsDetail: (owner, repo, params) => this.request(`/networks/${owner}/${repo}/events`, "GET", params), + eventsDetail: (owner, repo, params = {}) => + this.request({ + path: `/networks/${owner}/${repo}/events`, + method: "GET", + format: "json", + ...params, + }), }; this.notifications = { /** @@ -361,52 +568,92 @@ export class Api extends HttpClient { * @name NotificationsList * @request GET:/notifications */ - notificationsList: (query, params) => this.request(`/notifications${this.addQueryParams(query)}`, "GET", params), + notificationsList: (query, params = {}) => + this.request({ + path: `/notifications`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Mark as read. Marking a notification as "read" removes it from the default view on GitHub.com. * * @name NotificationsUpdate * @request PUT:/notifications */ - notificationsUpdate: (body, params) => this.request(`/notifications`, "PUT", params, body), + notificationsUpdate: (body, params = {}) => + this.request({ + path: `/notifications`, + method: "PUT", + body: body, + ...params, + }), /** * @description View a single thread. * * @name ThreadsDetail * @request GET:/notifications/threads/{id} */ - threadsDetail: (id, params) => this.request(`/notifications/threads/${id}`, "GET", params), + threadsDetail: (id, params = {}) => + this.request({ + path: `/notifications/threads/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Mark a thread as read * * @name ThreadsPartialUpdate * @request PATCH:/notifications/threads/{id} */ - threadsPartialUpdate: (id, params) => this.request(`/notifications/threads/${id}`, "PATCH", params), + threadsPartialUpdate: (id, params = {}) => + this.request({ + path: `/notifications/threads/${id}`, + method: "PATCH", + ...params, + }), /** * @description Delete a Thread Subscription. * * @name ThreadsSubscriptionDelete * @request DELETE:/notifications/threads/{id}/subscription */ - threadsSubscriptionDelete: (id, params) => - this.request(`/notifications/threads/${id}/subscription`, "DELETE", params), + threadsSubscriptionDelete: (id, params = {}) => + this.request({ + path: `/notifications/threads/${id}/subscription`, + method: "DELETE", + ...params, + }), /** * @description Get a Thread Subscription. * * @name ThreadsSubscriptionDetail * @request GET:/notifications/threads/{id}/subscription */ - threadsSubscriptionDetail: (id, params) => - this.request(`/notifications/threads/${id}/subscription`, "GET", params), + threadsSubscriptionDetail: (id, params = {}) => + this.request({ + path: `/notifications/threads/${id}/subscription`, + method: "GET", + format: "json", + ...params, + }), /** * @description Set a Thread Subscription. This lets you subscribe to a thread, or ignore it. Subscribing to a thread is unnecessary if the user is already subscribed to the repository. Ignoring a thread will mute all future notifications (until you comment or get @mentioned). * * @name ThreadsSubscriptionUpdate * @request PUT:/notifications/threads/{id}/subscription */ - threadsSubscriptionUpdate: (id, body, params) => - this.request(`/notifications/threads/${id}/subscription`, "PUT", params, body, BodyType.Json), + threadsSubscriptionUpdate: (id, body, params = {}) => + this.request({ + path: `/notifications/threads/${id}/subscription`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), }; this.orgs = { /** @@ -415,43 +662,80 @@ export class Api extends HttpClient { * @name OrgsDetail * @request GET:/orgs/{org} */ - orgsDetail: (org, params) => this.request(`/orgs/${org}`, "GET", params), + orgsDetail: (org, params = {}) => + this.request({ + path: `/orgs/${org}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit an Organization. * * @name OrgsPartialUpdate * @request PATCH:/orgs/{org} */ - orgsPartialUpdate: (org, body, params) => this.request(`/orgs/${org}`, "PATCH", params, body, BodyType.Json), + orgsPartialUpdate: (org, body, params = {}) => + this.request({ + path: `/orgs/${org}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List public events for an organization. * * @name EventsDetail * @request GET:/orgs/{org}/events */ - eventsDetail: (org, params) => this.request(`/orgs/${org}/events`, "GET", params), + eventsDetail: (org, params = {}) => + this.request({ + path: `/orgs/${org}/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description List issues. List all issues for a given organization for the authenticated user. * * @name IssuesDetail * @request GET:/orgs/{org}/issues */ - issuesDetail: (org, query, params) => - this.request(`/orgs/${org}/issues${this.addQueryParams(query)}`, "GET", params), + issuesDetail: (org, query, params = {}) => + this.request({ + path: `/orgs/${org}/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Members list. List all users who are members of an organization. A member is a user tha belongs to at least 1 team in the organization. If the authenticated user is also an owner of this organization then both concealed and public members will be returned. If the requester is not an owner of the organization the query will be redirected to the public members list. * * @name MembersDetail * @request GET:/orgs/{org}/members */ - membersDetail: (org, params) => this.request(`/orgs/${org}/members`, "GET", params), + membersDetail: (org, params = {}) => + this.request({ + path: `/orgs/${org}/members`, + method: "GET", + format: "json", + ...params, + }), /** * @description Remove a member. Removing a user from this list will remove them from all teams and they will no longer have any access to the organization's repositories. * * @name MembersDelete * @request DELETE:/orgs/{org}/members/{username} */ - membersDelete: (org, username, params) => this.request(`/orgs/${org}/members/${username}`, "DELETE", params), + membersDelete: (org, username, params = {}) => + this.request({ + path: `/orgs/${org}/members/${username}`, + method: "DELETE", + ...params, + }), /** * @description Check if a user is, publicly or privately, a member of the organization. * @@ -460,22 +744,37 @@ export class Api extends HttpClient { * @originalName membersDetail * @duplicate */ - membersDetail2: (org, username, params) => this.request(`/orgs/${org}/members/${username}`, "GET", params), + membersDetail2: (org, username, params = {}) => + this.request({ + path: `/orgs/${org}/members/${username}`, + method: "GET", + ...params, + }), /** * @description Public members list. Members of an organization can choose to have their membership publicized or not. * * @name PublicMembersDetail * @request GET:/orgs/{org}/public_members */ - publicMembersDetail: (org, params) => this.request(`/orgs/${org}/public_members`, "GET", params), + publicMembersDetail: (org, params = {}) => + this.request({ + path: `/orgs/${org}/public_members`, + method: "GET", + format: "json", + ...params, + }), /** * @description Conceal a user's membership. * * @name PublicMembersDelete * @request DELETE:/orgs/{org}/public_members/{username} */ - publicMembersDelete: (org, username, params) => - this.request(`/orgs/${org}/public_members/${username}`, "DELETE", params), + publicMembersDelete: (org, username, params = {}) => + this.request({ + path: `/orgs/${org}/public_members/${username}`, + method: "DELETE", + ...params, + }), /** * @description Check public membership. * @@ -484,45 +783,80 @@ export class Api extends HttpClient { * @originalName publicMembersDetail * @duplicate */ - publicMembersDetail2: (org, username, params) => - this.request(`/orgs/${org}/public_members/${username}`, "GET", params), + publicMembersDetail2: (org, username, params = {}) => + this.request({ + path: `/orgs/${org}/public_members/${username}`, + method: "GET", + ...params, + }), /** * @description Publicize a user's membership. * * @name PublicMembersUpdate * @request PUT:/orgs/{org}/public_members/{username} */ - publicMembersUpdate: (org, username, params) => - this.request(`/orgs/${org}/public_members/${username}`, "PUT", params), + publicMembersUpdate: (org, username, params = {}) => + this.request({ + path: `/orgs/${org}/public_members/${username}`, + method: "PUT", + ...params, + }), /** * @description List repositories for the specified org. * * @name ReposDetail * @request GET:/orgs/{org}/repos */ - reposDetail: (org, query, params) => - this.request(`/orgs/${org}/repos${this.addQueryParams(query)}`, "GET", params), + reposDetail: (org, query, params = {}) => + this.request({ + path: `/orgs/${org}/repos`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. * * @name ReposCreate * @request POST:/orgs/{org}/repos */ - reposCreate: (org, body, params) => this.request(`/orgs/${org}/repos`, "POST", params, body), + reposCreate: (org, body, params = {}) => + this.request({ + path: `/orgs/${org}/repos`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List teams. * * @name TeamsDetail * @request GET:/orgs/{org}/teams */ - teamsDetail: (org, params) => this.request(`/orgs/${org}/teams`, "GET", params), + teamsDetail: (org, params = {}) => + this.request({ + path: `/orgs/${org}/teams`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create team. In order to create a team, the authenticated user must be an owner of organization. * * @name TeamsCreate * @request POST:/orgs/{org}/teams */ - teamsCreate: (org, body, params) => this.request(`/orgs/${org}/teams`, "POST", params, body, BodyType.Json), + teamsCreate: (org, body, params = {}) => + this.request({ + path: `/orgs/${org}/teams`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), }; this.rateLimit = { /** @@ -531,7 +865,13 @@ export class Api extends HttpClient { * @name RateLimitList * @request GET:/rate_limit */ - rateLimitList: (params) => this.request(`/rate_limit`, "GET", params), + rateLimitList: (params = {}) => + this.request({ + path: `/rate_limit`, + method: "GET", + format: "json", + ...params, + }), }; this.repos = { /** @@ -540,29 +880,53 @@ export class Api extends HttpClient { * @name ReposDelete * @request DELETE:/repos/{owner}/{repo} */ - reposDelete: (owner, repo, params) => this.request(`/repos/${owner}/${repo}`, "DELETE", params), + reposDelete: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Get repository. * * @name ReposDetail * @request GET:/repos/{owner}/{repo} */ - reposDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}`, "GET", params), + reposDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit repository. * * @name ReposPartialUpdate * @request PATCH:/repos/{owner}/{repo} */ - reposPartialUpdate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}`, "PATCH", params, body, BodyType.Json), + reposPartialUpdate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List assignees. This call lists all the available assignees (owner + collaborators) to which issues may be assigned. * * @name AssigneesDetail * @request GET:/repos/{owner}/{repo}/assignees */ - assigneesDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/assignees`, "GET", params), + assigneesDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/assignees`, + method: "GET", + format: "json", + ...params, + }), /** * @description Check assignee. You may also check to see if a particular user is an assignee for a repository. * @@ -571,15 +935,25 @@ export class Api extends HttpClient { * @originalName assigneesDetail * @duplicate */ - assigneesDetail2: (owner, repo, assignee, params) => - this.request(`/repos/${owner}/${repo}/assignees/${assignee}`, "GET", params), + assigneesDetail2: (owner, repo, assignee, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/assignees/${assignee}`, + method: "GET", + ...params, + }), /** * @description Get list of branches * * @name BranchesDetail * @request GET:/repos/{owner}/{repo}/branches */ - branchesDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/branches`, "GET", params), + branchesDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/branches`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get Branch * @@ -588,24 +962,38 @@ export class Api extends HttpClient { * @originalName branchesDetail * @duplicate */ - branchesDetail2: (owner, repo, branch, params) => - this.request(`/repos/${owner}/${repo}/branches/${branch}`, "GET", params), + branchesDetail2: (owner, repo, branch, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/branches/${branch}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List. When authenticating as an organization owner of an organization-owned repository, all organization owners are included in the list of collaborators. Otherwise, only users with access to the repository are returned in the collaborators list. * * @name CollaboratorsDetail * @request GET:/repos/{owner}/{repo}/collaborators */ - collaboratorsDetail: (owner, repo, params) => - this.request(`/repos/${owner}/${repo}/collaborators`, "GET", params), + collaboratorsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators`, + method: "GET", + format: "json", + ...params, + }), /** * @description Remove collaborator. * * @name CollaboratorsDelete * @request DELETE:/repos/{owner}/{repo}/collaborators/{user} */ - collaboratorsDelete: (owner, repo, user, params) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "DELETE", params), + collaboratorsDelete: (owner, repo, user, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators/${user}`, + method: "DELETE", + ...params, + }), /** * @description Check if user is a collaborator * @@ -614,31 +1002,49 @@ export class Api extends HttpClient { * @originalName collaboratorsDetail * @duplicate */ - collaboratorsDetail2: (owner, repo, user, params) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "GET", params), + collaboratorsDetail2: (owner, repo, user, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators/${user}`, + method: "GET", + ...params, + }), /** * @description Add collaborator. * * @name CollaboratorsUpdate * @request PUT:/repos/{owner}/{repo}/collaborators/{user} */ - collaboratorsUpdate: (owner, repo, user, params) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "PUT", params), + collaboratorsUpdate: (owner, repo, user, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/collaborators/${user}`, + method: "PUT", + ...params, + }), /** * @description List commit comments for a repository. Comments are ordered by ascending ID. * * @name CommentsDetail * @request GET:/repos/{owner}/{repo}/comments */ - commentsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/comments`, "GET", params), + commentsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Delete a commit comment * * @name CommentsDelete * @request DELETE:/repos/{owner}/{repo}/comments/{commentId} */ - commentsDelete: (owner, repo, commentId, params) => - this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "DELETE", params), + commentsDelete: (owner, repo, commentId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single commit comment. * @@ -647,32 +1053,54 @@ export class Api extends HttpClient { * @originalName commentsDetail * @duplicate */ - commentsDetail2: (owner, repo, commentId, params) => - this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "GET", params), + commentsDetail2: (owner, repo, commentId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a commit comment. * * @name CommentsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/comments/{commentId} */ - commentsPartialUpdate: (owner, repo, commentId, body, params) => - this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "PATCH", params, body), + commentsPartialUpdate: (owner, repo, commentId, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/comments/${commentId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List commits on a repository. * * @name CommitsDetail * @request GET:/repos/{owner}/{repo}/commits */ - commitsDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/commits${this.addQueryParams(query)}`, "GET", params), + commitsDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Get the combined Status for a specific Ref The Combined status endpoint is currently available for developers to preview. During the preview period, the API may change without advance notice. Please see the blog post for full details. To access this endpoint during the preview period, you must provide a custom media type in the Accept header: application/vnd.github.she-hulk-preview+json * * @name CommitsStatusDetail * @request GET:/repos/{owner}/{repo}/commits/{ref}/status */ - commitsStatusDetail: (owner, repo, ref, params) => - this.request(`/repos/${owner}/${repo}/commits/${ref}/status`, "GET", params), + commitsStatusDetail: (owner, repo, ref, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits/${ref}/status`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single commit. * @@ -681,110 +1109,192 @@ export class Api extends HttpClient { * @originalName commitsDetail * @duplicate */ - commitsDetail2: (owner, repo, shaCode, params) => - this.request(`/repos/${owner}/${repo}/commits/${shaCode}`, "GET", params), + commitsDetail2: (owner, repo, shaCode, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List comments for a single commitList comments for a single commit. * * @name CommitsCommentsDetail * @request GET:/repos/{owner}/{repo}/commits/{shaCode}/comments */ - commitsCommentsDetail: (owner, repo, shaCode, params) => - this.request(`/repos/${owner}/${repo}/commits/${shaCode}/comments`, "GET", params), + commitsCommentsDetail: (owner, repo, shaCode, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits/${shaCode}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a commit comment. * * @name CommitsCommentsCreate * @request POST:/repos/{owner}/{repo}/commits/{shaCode}/comments */ - commitsCommentsCreate: (owner, repo, shaCode, body, params) => - this.request(`/repos/${owner}/${repo}/commits/${shaCode}/comments`, "POST", params, body, BodyType.Json), + commitsCommentsCreate: (owner, repo, shaCode, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/commits/${shaCode}/comments`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Compare two commits * * @name CompareDetail * @request GET:/repos/{owner}/{repo}/compare/{baseId}...{headId} */ - compareDetail: (owner, repo, baseId, headId, params) => - this.request(`/repos/${owner}/${repo}/compare/${baseId}...${headId}`, "GET", params), + compareDetail: (owner, repo, baseId, headId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/compare/${baseId}...${headId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Delete a file. This method deletes a file in a repository. * * @name ContentsDelete * @request DELETE:/repos/{owner}/{repo}/contents/{path} */ - contentsDelete: (owner, repo, path, body, params) => - this.request(`/repos/${owner}/${repo}/contents/${path}`, "DELETE", params, body, BodyType.Json), + contentsDelete: (owner, repo, path, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/contents/${path}`, + method: "DELETE", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get contents. This method returns the contents of a file or directory in a repository. Files and symlinks support a custom media type for getting the raw content. Directories and submodules do not support custom media types. Note: This API supports files up to 1 megabyte in size. Here can be many outcomes. For details see "http://developer.github.com/v3/repos/contents/" * * @name ContentsDetail * @request GET:/repos/{owner}/{repo}/contents/{path} */ - contentsDetail: (owner, repo, path, query, params) => - this.request(`/repos/${owner}/${repo}/contents/${path}${this.addQueryParams(query)}`, "GET", params), + contentsDetail: (owner, repo, path, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/contents/${path}`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a file. * * @name ContentsUpdate * @request PUT:/repos/{owner}/{repo}/contents/{path} */ - contentsUpdate: (owner, repo, path, body, params) => - this.request(`/repos/${owner}/${repo}/contents/${path}`, "PUT", params, body, BodyType.Json), + contentsUpdate: (owner, repo, path, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/contents/${path}`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get list of contributors. * * @name ContributorsDetail * @request GET:/repos/{owner}/{repo}/contributors */ - contributorsDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/contributors${this.addQueryParams(query)}`, "GET", params), + contributorsDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/contributors`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Users with pull access can view deployments for a repository * * @name DeploymentsDetail * @request GET:/repos/{owner}/{repo}/deployments */ - deploymentsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/deployments`, "GET", params), + deploymentsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/deployments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Users with push access can create a deployment for a given ref * * @name DeploymentsCreate * @request POST:/repos/{owner}/{repo}/deployments */ - deploymentsCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/deployments`, "POST", params, body, BodyType.Json), + deploymentsCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/deployments`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Users with pull access can view deployment statuses for a deployment * * @name DeploymentsStatusesDetail * @request GET:/repos/{owner}/{repo}/deployments/{id}/statuses */ - deploymentsStatusesDetail: (owner, repo, id, params) => - this.request(`/repos/${owner}/${repo}/deployments/${id}/statuses`, "GET", params), + deploymentsStatusesDetail: (owner, repo, id, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/deployments/${id}/statuses`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Deployment Status Users with push access can create deployment statuses for a given deployment: * * @name DeploymentsStatusesCreate * @request POST:/repos/{owner}/{repo}/deployments/{id}/statuses */ - deploymentsStatusesCreate: (owner, repo, id, body, params) => - this.request(`/repos/${owner}/${repo}/deployments/${id}/statuses`, "POST", params, body, BodyType.Json), + deploymentsStatusesCreate: (owner, repo, id, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/deployments/${id}/statuses`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description Deprecated. List downloads for a repository. * * @name DownloadsDetail * @request GET:/repos/{owner}/{repo}/downloads */ - downloadsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/downloads`, "GET", params), + downloadsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/downloads`, + method: "GET", + format: "json", + ...params, + }), /** * @description Deprecated. Delete a download. * * @name DownloadsDelete * @request DELETE:/repos/{owner}/{repo}/downloads/{downloadId} */ - downloadsDelete: (owner, repo, downloadId, params) => - this.request(`/repos/${owner}/${repo}/downloads/${downloadId}`, "DELETE", params), + downloadsDelete: (owner, repo, downloadId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/downloads/${downloadId}`, + method: "DELETE", + ...params, + }), /** * @description Deprecated. Get a single download. * @@ -793,86 +1303,151 @@ export class Api extends HttpClient { * @originalName downloadsDetail * @duplicate */ - downloadsDetail2: (owner, repo, downloadId, params) => - this.request(`/repos/${owner}/${repo}/downloads/${downloadId}`, "GET", params), + downloadsDetail2: (owner, repo, downloadId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/downloads/${downloadId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get list of repository events. * * @name EventsDetail * @request GET:/repos/{owner}/{repo}/events */ - eventsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/events`, "GET", params), + eventsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description List forks. * * @name ForksDetail * @request GET:/repos/{owner}/{repo}/forks */ - forksDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/forks${this.addQueryParams(query)}`, "GET", params), + forksDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/forks`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a fork. Forking a Repository happens asynchronously. Therefore, you may have to wai a short period before accessing the git objects. If this takes longer than 5 minutes, be sure to contact Support. * * @name ForksCreate * @request POST:/repos/{owner}/{repo}/forks */ - forksCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/forks`, "POST", params, body, BodyType.Json), + forksCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/forks`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Create a Blob. * * @name GitBlobsCreate * @request POST:/repos/{owner}/{repo}/git/blobs */ - gitBlobsCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/git/blobs`, "POST", params, body, BodyType.Json), + gitBlobsCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/blobs`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Blob. Since blobs can be any arbitrary binary data, the input and responses for the blob API takes an encoding parameter that can be either utf-8 or base64. If your data cannot be losslessly sent as a UTF-8 string, you can base64 encode it. * * @name GitBlobsDetail * @request GET:/repos/{owner}/{repo}/git/blobs/{shaCode} */ - gitBlobsDetail: (owner, repo, shaCode, params) => - this.request(`/repos/${owner}/${repo}/git/blobs/${shaCode}`, "GET", params), + gitBlobsDetail: (owner, repo, shaCode, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/blobs/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Commit. * * @name GitCommitsCreate * @request POST:/repos/{owner}/{repo}/git/commits */ - gitCommitsCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/git/commits`, "POST", params, body, BodyType.Json), + gitCommitsCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/commits`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Commit. * * @name GitCommitsDetail * @request GET:/repos/{owner}/{repo}/git/commits/{shaCode} */ - gitCommitsDetail: (owner, repo, shaCode, params) => - this.request(`/repos/${owner}/${repo}/git/commits/${shaCode}`, "GET", params), + gitCommitsDetail: (owner, repo, shaCode, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/commits/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get all References * * @name GitRefsDetail * @request GET:/repos/{owner}/{repo}/git/refs */ - gitRefsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/git/refs`, "GET", params), + gitRefsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Reference * * @name GitRefsCreate * @request POST:/repos/{owner}/{repo}/git/refs */ - gitRefsCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/git/refs`, "POST", params, body, BodyType.Json), + gitRefsCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Delete a Reference Example: Deleting a branch: DELETE /repos/octocat/Hello-World/git/refs/heads/feature-a Example: Deleting a tag: DELETE /repos/octocat/Hello-World/git/refs/tags/v1.0 * * @name GitRefsDelete * @request DELETE:/repos/{owner}/{repo}/git/refs/{ref} */ - gitRefsDelete: (owner, repo, ref, params) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "DELETE", params), + gitRefsDelete: (owner, repo, ref, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs/${ref}`, + method: "DELETE", + ...params, + }), /** * @description Get a Reference * @@ -881,70 +1456,124 @@ export class Api extends HttpClient { * @originalName gitRefsDetail * @duplicate */ - gitRefsDetail2: (owner, repo, ref, params) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "GET", params), + gitRefsDetail2: (owner, repo, ref, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs/${ref}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a Reference * * @name GitRefsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/git/refs/{ref} */ - gitRefsPartialUpdate: (owner, repo, ref, body, params) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "PATCH", params, body, BodyType.Json), + gitRefsPartialUpdate: (owner, repo, ref, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/refs/${ref}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Create a Tag Object. Note that creating a tag object does not create the reference that makes a tag in Git. If you want to create an annotated tag in Git, you have to do this call to create the tag object, and then create the refs/tags/[tag] reference. If you want to create a lightweight tag, you only have to create the tag reference - this call would be unnecessary. * * @name GitTagsCreate * @request POST:/repos/{owner}/{repo}/git/tags */ - gitTagsCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/git/tags`, "POST", params, body, BodyType.Json), + gitTagsCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/tags`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Tag. * * @name GitTagsDetail * @request GET:/repos/{owner}/{repo}/git/tags/{shaCode} */ - gitTagsDetail: (owner, repo, shaCode, params) => - this.request(`/repos/${owner}/${repo}/git/tags/${shaCode}`, "GET", params), + gitTagsDetail: (owner, repo, shaCode, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/tags/${shaCode}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Tree. The tree creation API will take nested entries as well. If both a tree and a nested path modifying that tree are specified, it will overwrite the contents of that tree with the new path contents and write a new tree out. * * @name GitTreesCreate * @request POST:/repos/{owner}/{repo}/git/trees */ - gitTreesCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/git/trees`, "POST", params, body, BodyType.Json), + gitTreesCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/trees`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get a Tree. * * @name GitTreesDetail * @request GET:/repos/{owner}/{repo}/git/trees/{shaCode} */ - gitTreesDetail: (owner, repo, shaCode, query, params) => - this.request(`/repos/${owner}/${repo}/git/trees/${shaCode}${this.addQueryParams(query)}`, "GET", params), + gitTreesDetail: (owner, repo, shaCode, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/git/trees/${shaCode}`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Get list of hooks. * * @name HooksDetail * @request GET:/repos/{owner}/{repo}/hooks */ - hooksDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/hooks`, "GET", params), + hooksDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a hook. * * @name HooksCreate * @request POST:/repos/{owner}/{repo}/hooks */ - hooksCreate: (owner, repo, body, params) => this.request(`/repos/${owner}/${repo}/hooks`, "POST", params, body), + hooksCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a hook. * * @name HooksDelete * @request DELETE:/repos/{owner}/{repo}/hooks/{hookId} */ - hooksDelete: (owner, repo, hookId, params) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "DELETE", params), + hooksDelete: (owner, repo, hookId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}`, + method: "DELETE", + ...params, + }), /** * @description Get single hook. * @@ -953,55 +1582,93 @@ export class Api extends HttpClient { * @originalName hooksDetail * @duplicate */ - hooksDetail2: (owner, repo, hookId, params) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "GET", params), + hooksDetail2: (owner, repo, hookId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a hook. * * @name HooksPartialUpdate * @request PATCH:/repos/{owner}/{repo}/hooks/{hookId} */ - hooksPartialUpdate: (owner, repo, hookId, body, params) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "PATCH", params, body), + hooksPartialUpdate: (owner, repo, hookId, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description Test a push hook. This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook is not subscribed to push events, the server will respond with 204 but no test POST will be generated. Note: Previously /repos/:owner/:repo/hooks/:id/tes * * @name HooksTestsCreate * @request POST:/repos/{owner}/{repo}/hooks/{hookId}/tests */ - hooksTestsCreate: (owner, repo, hookId, params) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}/tests`, "POST", params), + hooksTestsCreate: (owner, repo, hookId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/hooks/${hookId}/tests`, + method: "POST", + ...params, + }), /** * @description List issues for a repository. * * @name IssuesDetail * @request GET:/repos/{owner}/{repo}/issues */ - issuesDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/issues${this.addQueryParams(query)}`, "GET", params), + issuesDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create an issue. Any user with pull access to a repository can create an issue. * * @name IssuesCreate * @request POST:/repos/{owner}/{repo}/issues */ - issuesCreate: (owner, repo, body, params) => this.request(`/repos/${owner}/${repo}/issues`, "POST", params, body), + issuesCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List comments in a repository. * * @name IssuesCommentsDetail * @request GET:/repos/{owner}/{repo}/issues/comments */ - issuesCommentsDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/issues/comments${this.addQueryParams(query)}`, "GET", params), + issuesCommentsDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/comments`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Delete a comment. * * @name IssuesCommentsDelete * @request DELETE:/repos/{owner}/{repo}/issues/comments/{commentId} */ - issuesCommentsDelete: (owner, repo, commentId, params) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "DELETE", params), + issuesCommentsDelete: (owner, repo, commentId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single comment. * @@ -1010,23 +1677,40 @@ export class Api extends HttpClient { * @originalName issuesCommentsDetail * @duplicate */ - issuesCommentsDetail2: (owner, repo, commentId, params) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "GET", params), + issuesCommentsDetail2: (owner, repo, commentId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a comment. * * @name IssuesCommentsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/issues/comments/{commentId} */ - issuesCommentsPartialUpdate: (owner, repo, commentId, body, params) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "PATCH", params, body), + issuesCommentsPartialUpdate: (owner, repo, commentId, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/comments/${commentId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List issue events for a repository. * * @name IssuesEventsDetail * @request GET:/repos/{owner}/{repo}/issues/events */ - issuesEventsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/issues/events`, "GET", params), + issuesEventsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single event. * @@ -1035,8 +1719,13 @@ export class Api extends HttpClient { * @originalName issuesEventsDetail * @duplicate */ - issuesEventsDetail2: (owner, repo, eventId, params) => - this.request(`/repos/${owner}/${repo}/issues/events/${eventId}`, "GET", params), + issuesEventsDetail2: (owner, repo, eventId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/events/${eventId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get a single issue * @@ -1045,16 +1734,27 @@ export class Api extends HttpClient { * @originalName issuesDetail * @duplicate */ - issuesDetail2: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}`, "GET", params), + issuesDetail2: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit an issue. Issue owners and users with push access can edit an issue. * * @name IssuesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/issues/{number} */ - issuesPartialUpdate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}`, "PATCH", params, body), + issuesPartialUpdate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List comments on an issue. * @@ -1063,16 +1763,27 @@ export class Api extends HttpClient { * @originalName issuesCommentsDetail * @duplicate */ - issuesCommentsDetail3: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/comments`, "GET", params), + issuesCommentsDetail3: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a comment. * * @name IssuesCommentsCreate * @request POST:/repos/{owner}/{repo}/issues/{number}/comments */ - issuesCommentsCreate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/comments`, "POST", params, body), + issuesCommentsCreate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/comments`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List events for an issue. * @@ -1081,40 +1792,66 @@ export class Api extends HttpClient { * @originalName issuesEventsDetail * @duplicate */ - issuesEventsDetail3: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/events`, "GET", params), + issuesEventsDetail3: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/events`, + method: "GET", + format: "json", + ...params, + }), /** * @description Remove all labels from an issue. * * @name IssuesLabelsDelete * @request DELETE:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsDelete: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "DELETE", params), + issuesLabelsDelete: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "DELETE", + ...params, + }), /** * @description List labels on an issue. * * @name IssuesLabelsDetail * @request GET:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsDetail: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "GET", params), + issuesLabelsDetail: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "GET", + format: "json", + ...params, + }), /** * @description Add labels to an issue. * * @name IssuesLabelsCreate * @request POST:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsCreate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "POST", params, body), + issuesLabelsCreate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Replace all labels for an issue. Sending an empty array ([]) will remove all Labels from the Issue. * * @name IssuesLabelsUpdate * @request PUT:/repos/{owner}/{repo}/issues/{number}/labels */ - issuesLabelsUpdate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "PUT", params, body), + issuesLabelsUpdate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels`, + method: "PUT", + body: body, + format: "json", + ...params, + }), /** * @description Remove a label from an issue. * @@ -1123,30 +1860,51 @@ export class Api extends HttpClient { * @originalName issuesLabelsDelete * @duplicate */ - issuesLabelsDelete2: (owner, repo, number, name, params) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels/${name}`, "DELETE", params), + issuesLabelsDelete2: (owner, repo, number, name, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/issues/${number}/labels/${name}`, + method: "DELETE", + ...params, + }), /** * @description Get list of keys. * * @name KeysDetail * @request GET:/repos/{owner}/{repo}/keys */ - keysDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/keys`, "GET", params), + keysDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a key. * * @name KeysCreate * @request POST:/repos/{owner}/{repo}/keys */ - keysCreate: (owner, repo, body, params) => this.request(`/repos/${owner}/${repo}/keys`, "POST", params, body), + keysCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a key. * * @name KeysDelete * @request DELETE:/repos/{owner}/{repo}/keys/{keyId} */ - keysDelete: (owner, repo, keyId, params) => - this.request(`/repos/${owner}/${repo}/keys/${keyId}`, "DELETE", params), + keysDelete: (owner, repo, keyId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys/${keyId}`, + method: "DELETE", + ...params, + }), /** * @description Get a key * @@ -1155,29 +1913,52 @@ export class Api extends HttpClient { * @originalName keysDetail * @duplicate */ - keysDetail2: (owner, repo, keyId, params) => this.request(`/repos/${owner}/${repo}/keys/${keyId}`, "GET", params), + keysDetail2: (owner, repo, keyId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/keys/${keyId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List all labels for this repository. * * @name LabelsDetail * @request GET:/repos/{owner}/{repo}/labels */ - labelsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/labels`, "GET", params), + labelsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a label. * * @name LabelsCreate * @request POST:/repos/{owner}/{repo}/labels */ - labelsCreate: (owner, repo, body, params) => this.request(`/repos/${owner}/${repo}/labels`, "POST", params, body), + labelsCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a label. * * @name LabelsDelete * @request DELETE:/repos/{owner}/{repo}/labels/{name} */ - labelsDelete: (owner, repo, name, params) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "DELETE", params), + labelsDelete: (owner, repo, name, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels/${name}`, + method: "DELETE", + ...params, + }), /** * @description Get a single label. * @@ -1186,55 +1967,95 @@ export class Api extends HttpClient { * @originalName labelsDetail * @duplicate */ - labelsDetail2: (owner, repo, name, params) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "GET", params), + labelsDetail2: (owner, repo, name, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels/${name}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a label. * * @name LabelsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/labels/{name} */ - labelsPartialUpdate: (owner, repo, name, body, params) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "PATCH", params, body), + labelsPartialUpdate: (owner, repo, name, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/labels/${name}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List languages. List languages for the specified repository. The value on the right of a language is the number of bytes of code written in that language. * * @name LanguagesDetail * @request GET:/repos/{owner}/{repo}/languages */ - languagesDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/languages`, "GET", params), + languagesDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/languages`, + method: "GET", + format: "json", + ...params, + }), /** * @description Perform a merge. * * @name MergesCreate * @request POST:/repos/{owner}/{repo}/merges */ - mergesCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/merges`, "POST", params, body, BodyType.Json), + mergesCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/merges`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List milestones for a repository. * * @name MilestonesDetail * @request GET:/repos/{owner}/{repo}/milestones */ - milestonesDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/milestones${this.addQueryParams(query)}`, "GET", params), + milestonesDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a milestone. * * @name MilestonesCreate * @request POST:/repos/{owner}/{repo}/milestones */ - milestonesCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/milestones`, "POST", params, body), + milestonesCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a milestone. * * @name MilestonesDelete * @request DELETE:/repos/{owner}/{repo}/milestones/{number} */ - milestonesDelete: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/milestones/${number}`, "DELETE", params), + milestonesDelete: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}`, + method: "DELETE", + ...params, + }), /** * @description Get a single milestone. * @@ -1243,72 +2064,122 @@ export class Api extends HttpClient { * @originalName milestonesDetail * @duplicate */ - milestonesDetail2: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/milestones/${number}`, "GET", params), + milestonesDetail2: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a milestone. * * @name MilestonesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/milestones/{number} */ - milestonesPartialUpdate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/milestones/${number}`, "PATCH", params, body), + milestonesPartialUpdate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description Get labels for every issue in a milestone. * * @name MilestonesLabelsDetail * @request GET:/repos/{owner}/{repo}/milestones/{number}/labels */ - milestonesLabelsDetail: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/milestones/${number}/labels`, "GET", params), + milestonesLabelsDetail: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/milestones/${number}/labels`, + method: "GET", + format: "json", + ...params, + }), /** * @description List your notifications in a repository List all notifications for the current user. * * @name NotificationsDetail * @request GET:/repos/{owner}/{repo}/notifications */ - notificationsDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/notifications${this.addQueryParams(query)}`, "GET", params), + notificationsDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/notifications`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Mark notifications as read in a repository. Marking all notifications in a repository as "read" removes them from the default view on GitHub.com. * * @name NotificationsUpdate * @request PUT:/repos/{owner}/{repo}/notifications */ - notificationsUpdate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/notifications`, "PUT", params, body), + notificationsUpdate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/notifications`, + method: "PUT", + body: body, + ...params, + }), /** * @description List pull requests. * * @name PullsDetail * @request GET:/repos/{owner}/{repo}/pulls */ - pullsDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/pulls${this.addQueryParams(query)}`, "GET", params), + pullsDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a pull request. * * @name PullsCreate * @request POST:/repos/{owner}/{repo}/pulls */ - pullsCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/pulls`, "POST", params, body, BodyType.Json), + pullsCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List comments in a repository. By default, Review Comments are ordered by ascending ID. * * @name PullsCommentsDetail * @request GET:/repos/{owner}/{repo}/pulls/comments */ - pullsCommentsDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/pulls/comments${this.addQueryParams(query)}`, "GET", params), + pullsCommentsDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Delete a comment. * * @name PullsCommentsDelete * @request DELETE:/repos/{owner}/{repo}/pulls/comments/{commentId} */ - pullsCommentsDelete: (owner, repo, commentId, params) => - this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "DELETE", params), + pullsCommentsDelete: (owner, repo, commentId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments/${commentId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single comment. * @@ -1317,16 +2188,27 @@ export class Api extends HttpClient { * @originalName pullsCommentsDetail * @duplicate */ - pullsCommentsDetail2: (owner, repo, commentId, params) => - this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "GET", params), + pullsCommentsDetail2: (owner, repo, commentId, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments/${commentId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a comment. * * @name PullsCommentsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/pulls/comments/{commentId} */ - pullsCommentsPartialUpdate: (owner, repo, commentId, body, params) => - this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "PATCH", params, body), + pullsCommentsPartialUpdate: (owner, repo, commentId, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/comments/${commentId}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description Get a single pull request. * @@ -1335,16 +2217,28 @@ export class Api extends HttpClient { * @originalName pullsDetail * @duplicate */ - pullsDetail2: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}`, "GET", params), + pullsDetail2: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update a pull request. * * @name PullsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/pulls/{number} */ - pullsPartialUpdate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}`, "PATCH", params, body, BodyType.Json), + pullsPartialUpdate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List comments on a pull request. * @@ -1353,103 +2247,174 @@ export class Api extends HttpClient { * @originalName pullsCommentsDetail * @duplicate */ - pullsCommentsDetail3: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/comments`, "GET", params), + pullsCommentsDetail3: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/comments`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a comment. #TODO Alternative input ( http://developer.github.com/v3/pulls/comments/ ) description: | Alternative Input. Instead of passing commit_id, path, and position you can reply to an existing Pull Request Comment like this: body Required string in_reply_to Required number - Comment id to reply to. * * @name PullsCommentsCreate * @request POST:/repos/{owner}/{repo}/pulls/{number}/comments */ - pullsCommentsCreate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/comments`, "POST", params, body, BodyType.Json), + pullsCommentsCreate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/comments`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List commits on a pull request. * * @name PullsCommitsDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/commits */ - pullsCommitsDetail: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/commits`, "GET", params), + pullsCommitsDetail: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/commits`, + method: "GET", + format: "json", + ...params, + }), /** * @description List pull requests files. * * @name PullsFilesDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/files */ - pullsFilesDetail: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/files`, "GET", params), + pullsFilesDetail: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/files`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get if a pull request has been merged. * * @name PullsMergeDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/merge */ - pullsMergeDetail: (owner, repo, number, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/merge`, "GET", params), + pullsMergeDetail: (owner, repo, number, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/merge`, + method: "GET", + ...params, + }), /** * @description Merge a pull request (Merge Button's) * * @name PullsMergeUpdate * @request PUT:/repos/{owner}/{repo}/pulls/{number}/merge */ - pullsMergeUpdate: (owner, repo, number, body, params) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/merge`, "PUT", params, body, BodyType.Json), + pullsMergeUpdate: (owner, repo, number, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/pulls/${number}/merge`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get the README. This method returns the preferred README for a repository. * * @name ReadmeDetail * @request GET:/repos/{owner}/{repo}/readme */ - readmeDetail: (owner, repo, query, params) => - this.request(`/repos/${owner}/${repo}/readme${this.addQueryParams(query)}`, "GET", params), + readmeDetail: (owner, repo, query, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/readme`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Users with push access to the repository will receive all releases (i.e., published releases and draft releases). Users with pull access will receive published releases only * * @name ReleasesDetail * @request GET:/repos/{owner}/{repo}/releases */ - releasesDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/releases`, "GET", params), + releasesDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a release Users with push access to the repository can create a release. * * @name ReleasesCreate * @request POST:/repos/{owner}/{repo}/releases */ - releasesCreate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/releases`, "POST", params, body), + releasesCreate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a release asset * * @name ReleasesAssetsDelete * @request DELETE:/repos/{owner}/{repo}/releases/assets/{id} */ - releasesAssetsDelete: (owner, repo, id, params) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "DELETE", params), + releasesAssetsDelete: (owner, repo, id, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/assets/${id}`, + method: "DELETE", + ...params, + }), /** * @description Get a single release asset * * @name ReleasesAssetsDetail * @request GET:/repos/{owner}/{repo}/releases/assets/{id} */ - releasesAssetsDetail: (owner, repo, id, params) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "GET", params), + releasesAssetsDetail: (owner, repo, id, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/assets/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit a release asset Users with push access to the repository can edit a release asset. * * @name ReleasesAssetsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/releases/assets/{id} */ - releasesAssetsPartialUpdate: (owner, repo, id, body, params) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "PATCH", params, body, BodyType.Json), + releasesAssetsPartialUpdate: (owner, repo, id, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/assets/${id}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Users with push access to the repository can delete a release. * * @name ReleasesDelete * @request DELETE:/repos/{owner}/{repo}/releases/{id} */ - releasesDelete: (owner, repo, id, params) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "DELETE", params), + releasesDelete: (owner, repo, id, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}`, + method: "DELETE", + ...params, + }), /** * @description Get a single release * @@ -1458,16 +2423,27 @@ export class Api extends HttpClient { * @originalName releasesDetail * @duplicate */ - releasesDetail2: (owner, repo, id, params) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "GET", params), + releasesDetail2: (owner, repo, id, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Users with push access to the repository can edit a release * * @name ReleasesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/releases/{id} */ - releasesPartialUpdate: (owner, repo, id, body, params) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "PATCH", params, body), + releasesPartialUpdate: (owner, repo, id, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}`, + method: "PATCH", + body: body, + format: "json", + ...params, + }), /** * @description List assets for a release * @@ -1476,122 +2452,211 @@ export class Api extends HttpClient { * @originalName releasesAssetsDetail * @duplicate */ - releasesAssetsDetail2: (owner, repo, id, params) => - this.request(`/repos/${owner}/${repo}/releases/${id}/assets`, "GET", params), + releasesAssetsDetail2: (owner, repo, id, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/releases/${id}/assets`, + method: "GET", + format: "json", + ...params, + }), /** * @description List Stargazers. * * @name StargazersDetail * @request GET:/repos/{owner}/{repo}/stargazers */ - stargazersDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/stargazers`, "GET", params), + stargazersDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stargazers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the number of additions and deletions per week. Returns a weekly aggregate of the number of additions and deletions pushed to a repository. * * @name StatsCodeFrequencyDetail * @request GET:/repos/{owner}/{repo}/stats/code_frequency */ - statsCodeFrequencyDetail: (owner, repo, params) => - this.request(`/repos/${owner}/${repo}/stats/code_frequency`, "GET", params), + statsCodeFrequencyDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/code_frequency`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the last year of commit activity data. Returns the last year of commit activity grouped by week. The days array is a group of commits per day, starting on Sunday. * * @name StatsCommitActivityDetail * @request GET:/repos/{owner}/{repo}/stats/commit_activity */ - statsCommitActivityDetail: (owner, repo, params) => - this.request(`/repos/${owner}/${repo}/stats/commit_activity`, "GET", params), + statsCommitActivityDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/commit_activity`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get contributors list with additions, deletions, and commit counts. * * @name StatsContributorsDetail * @request GET:/repos/{owner}/{repo}/stats/contributors */ - statsContributorsDetail: (owner, repo, params) => - this.request(`/repos/${owner}/${repo}/stats/contributors`, "GET", params), + statsContributorsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/contributors`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the weekly commit count for the repo owner and everyone else. * * @name StatsParticipationDetail * @request GET:/repos/{owner}/{repo}/stats/participation */ - statsParticipationDetail: (owner, repo, params) => - this.request(`/repos/${owner}/${repo}/stats/participation`, "GET", params), + statsParticipationDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/participation`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get the number of commits per hour in each day. Each array contains the day number, hour number, and number of commits 0-6 Sunday - Saturday 0-23 Hour of day Number of commits For example, [2, 14, 25] indicates that there were 25 total commits, during the 2.00pm hour on Tuesdays. All times are based on the time zone of individual commits. * * @name StatsPunchCardDetail * @request GET:/repos/{owner}/{repo}/stats/punch_card */ - statsPunchCardDetail: (owner, repo, params) => - this.request(`/repos/${owner}/${repo}/stats/punch_card`, "GET", params), + statsPunchCardDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/stats/punch_card`, + method: "GET", + format: "json", + ...params, + }), /** * @description List Statuses for a specific Ref. * * @name StatusesDetail * @request GET:/repos/{owner}/{repo}/statuses/{ref} */ - statusesDetail: (owner, repo, ref, params) => - this.request(`/repos/${owner}/${repo}/statuses/${ref}`, "GET", params), + statusesDetail: (owner, repo, ref, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/statuses/${ref}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a Status. * * @name StatusesCreate * @request POST:/repos/{owner}/{repo}/statuses/{ref} */ - statusesCreate: (owner, repo, ref, body, params) => - this.request(`/repos/${owner}/${repo}/statuses/${ref}`, "POST", params, body, BodyType.Json), + statusesCreate: (owner, repo, ref, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/statuses/${ref}`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List watchers. * * @name SubscribersDetail * @request GET:/repos/{owner}/{repo}/subscribers */ - subscribersDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/subscribers`, "GET", params), + subscribersDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscribers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Delete a Repository Subscription. * * @name SubscriptionDelete * @request DELETE:/repos/{owner}/{repo}/subscription */ - subscriptionDelete: (owner, repo, params) => - this.request(`/repos/${owner}/${repo}/subscription`, "DELETE", params), + subscriptionDelete: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscription`, + method: "DELETE", + ...params, + }), /** * @description Get a Repository Subscription. * * @name SubscriptionDetail * @request GET:/repos/{owner}/{repo}/subscription */ - subscriptionDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/subscription`, "GET", params), + subscriptionDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscription`, + method: "GET", + format: "json", + ...params, + }), /** * @description Set a Repository Subscription * * @name SubscriptionUpdate * @request PUT:/repos/{owner}/{repo}/subscription */ - subscriptionUpdate: (owner, repo, body, params) => - this.request(`/repos/${owner}/${repo}/subscription`, "PUT", params, body, BodyType.Json), + subscriptionUpdate: (owner, repo, body, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/subscription`, + method: "PUT", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Get list of tags. * * @name TagsDetail * @request GET:/repos/{owner}/{repo}/tags */ - tagsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/tags`, "GET", params), + tagsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/tags`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get list of teams * * @name TeamsDetail * @request GET:/repos/{owner}/{repo}/teams */ - teamsDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/teams`, "GET", params), + teamsDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/teams`, + method: "GET", + format: "json", + ...params, + }), /** * @description List Stargazers. New implementation. * * @name WatchersDetail * @request GET:/repos/{owner}/{repo}/watchers */ - watchersDetail: (owner, repo, params) => this.request(`/repos/${owner}/${repo}/watchers`, "GET", params), + watchersDetail: (owner, repo, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/watchers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Get archive link. This method will return a 302 to a URL to download a tarball or zipball archive for a repository. Please make sure your HTTP framework is configured to follow redirects or you will need to use the Location header to make a second GET request. Note: For private repositories, these links are temporary and expire quickly. * @@ -1600,8 +2665,12 @@ export class Api extends HttpClient { * @originalName reposDetail * @duplicate */ - reposDetail2: (owner, repo, archive_format, path, params) => - this.request(`/repos/${owner}/${repo}/${archive_format}/${path}`, "GET", params), + reposDetail2: (owner, repo, archive_format, path, params = {}) => + this.request({ + path: `/repos/${owner}/${repo}/${archive_format}/${path}`, + method: "GET", + ...params, + }), }; this.repositories = { /** @@ -1610,7 +2679,14 @@ export class Api extends HttpClient { * @name RepositoriesList * @request GET:/repositories */ - repositoriesList: (query, params) => this.request(`/repositories${this.addQueryParams(query)}`, "GET", params), + repositoriesList: (query, params = {}) => + this.request({ + path: `/repositories`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; this.search = { /** @@ -1619,29 +2695,56 @@ export class Api extends HttpClient { * @name CodeList * @request GET:/search/code */ - codeList: (query, params) => this.request(`/search/code${this.addQueryParams(query)}`, "GET", params), + codeList: (query, params = {}) => + this.request({ + path: `/search/code`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Find issues by state and keyword. (This method returns up to 100 results per page.) * * @name IssuesList * @request GET:/search/issues */ - issuesList: (query, params) => this.request(`/search/issues${this.addQueryParams(query)}`, "GET", params), + issuesList: (query, params = {}) => + this.request({ + path: `/search/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Search repositories. * * @name RepositoriesList * @request GET:/search/repositories */ - repositoriesList: (query, params) => - this.request(`/search/repositories${this.addQueryParams(query)}`, "GET", params), + repositoriesList: (query, params = {}) => + this.request({ + path: `/search/repositories`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Search users. * * @name UsersList * @request GET:/search/users */ - usersList: (query, params) => this.request(`/search/users${this.addQueryParams(query)}`, "GET", params), + usersList: (query, params = {}) => + this.request({ + path: `/search/users`, + method: "GET", + query: query, + format: "json", + ...params, + }), }; this.teams = { /** @@ -1650,37 +2753,65 @@ export class Api extends HttpClient { * @name TeamsDelete * @request DELETE:/teams/{teamId} */ - teamsDelete: (teamId, params) => this.request(`/teams/${teamId}`, "DELETE", params), + teamsDelete: (teamId, params = {}) => + this.request({ + path: `/teams/${teamId}`, + method: "DELETE", + ...params, + }), /** * @description Get team. * * @name TeamsDetail * @request GET:/teams/{teamId} */ - teamsDetail: (teamId, params) => this.request(`/teams/${teamId}`, "GET", params), + teamsDetail: (teamId, params = {}) => + this.request({ + path: `/teams/${teamId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Edit team. In order to edit a team, the authenticated user must be an owner of the org that the team is associated with. * * @name TeamsPartialUpdate * @request PATCH:/teams/{teamId} */ - teamsPartialUpdate: (teamId, body, params) => - this.request(`/teams/${teamId}`, "PATCH", params, body, BodyType.Json), + teamsPartialUpdate: (teamId, body, params = {}) => + this.request({ + path: `/teams/${teamId}`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description List team members. In order to list members in a team, the authenticated user must be a member of the team. * * @name MembersDetail * @request GET:/teams/{teamId}/members */ - membersDetail: (teamId, params) => this.request(`/teams/${teamId}/members`, "GET", params), + membersDetail: (teamId, params = {}) => + this.request({ + path: `/teams/${teamId}/members`, + method: "GET", + format: "json", + ...params, + }), /** * @description The "Remove team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Remove team membership API instead. It allows you to remove both active and pending memberships. Remove team member. In order to remove a user from a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. NOTE This does not delete the user, it just remove them from the team. * * @name MembersDelete * @request DELETE:/teams/{teamId}/members/{username} */ - membersDelete: (teamId, username, params) => - this.request(`/teams/${teamId}/members/${username}`, "DELETE", params), + membersDelete: (teamId, username, params = {}) => + this.request({ + path: `/teams/${teamId}/members/${username}`, + method: "DELETE", + ...params, + }), /** * @description The "Get team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Get team membership API instead. It allows you to get both active and pending memberships. Get team member. In order to get if a user is a member of a team, the authenticated user mus be a member of the team. * @@ -1689,53 +2820,87 @@ export class Api extends HttpClient { * @originalName membersDetail * @duplicate */ - membersDetail2: (teamId, username, params) => this.request(`/teams/${teamId}/members/${username}`, "GET", params), + membersDetail2: (teamId, username, params = {}) => + this.request({ + path: `/teams/${teamId}/members/${username}`, + method: "GET", + ...params, + }), /** * @description The API (described below) is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Add team membership API instead. It allows you to invite new organization members to your teams. Add team member. In order to add a user to a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. * * @name MembersUpdate * @request PUT:/teams/{teamId}/members/{username} */ - membersUpdate: (teamId, username, params) => this.request(`/teams/${teamId}/members/${username}`, "PUT", params), + membersUpdate: (teamId, username, params = {}) => + this.request({ + path: `/teams/${teamId}/members/${username}`, + method: "PUT", + ...params, + }), /** * @description Remove team membership. In order to remove a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. NOTE: This does not delete the user, it just removes their membership from the team. * * @name MembershipsDelete * @request DELETE:/teams/{teamId}/memberships/{username} */ - membershipsDelete: (teamId, username, params) => - this.request(`/teams/${teamId}/memberships/${username}`, "DELETE", params), + membershipsDelete: (teamId, username, params = {}) => + this.request({ + path: `/teams/${teamId}/memberships/${username}`, + method: "DELETE", + ...params, + }), /** * @description Get team membership. In order to get a user's membership with a team, the authenticated user must be a member of the team or an owner of the team's organization. * * @name MembershipsDetail * @request GET:/teams/{teamId}/memberships/{username} */ - membershipsDetail: (teamId, username, params) => - this.request(`/teams/${teamId}/memberships/${username}`, "GET", params), + membershipsDetail: (teamId, username, params = {}) => + this.request({ + path: `/teams/${teamId}/memberships/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description Add team membership. In order to add a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. If the user is already a part of the team's organization (meaning they're on at least one other team in the organization), this endpoint will add the user to the team. If the user is completely unaffiliated with the team's organization (meaning they're on none of the organization's teams), this endpoint will send an invitation to the user via email. This newly-created membership will be in the 'pending' state until the user accepts the invitation, at which point the membership will transition to the 'active' state and the user will be added as a member of the team. * * @name MembershipsUpdate * @request PUT:/teams/{teamId}/memberships/{username} */ - membershipsUpdate: (teamId, username, params) => - this.request(`/teams/${teamId}/memberships/${username}`, "PUT", params), + membershipsUpdate: (teamId, username, params = {}) => + this.request({ + path: `/teams/${teamId}/memberships/${username}`, + method: "PUT", + format: "json", + ...params, + }), /** * @description List team repos * * @name ReposDetail * @request GET:/teams/{teamId}/repos */ - reposDetail: (teamId, params) => this.request(`/teams/${teamId}/repos`, "GET", params), + reposDetail: (teamId, params = {}) => + this.request({ + path: `/teams/${teamId}/repos`, + method: "GET", + format: "json", + ...params, + }), /** * @description In order to remove a repository from a team, the authenticated user must be an owner of the org that the team is associated with. NOTE: This does not delete the repository, it just removes it from the team. * * @name ReposDelete * @request DELETE:/teams/{teamId}/repos/{owner}/{repo} */ - reposDelete: (teamId, owner, repo, params) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "DELETE", params), + reposDelete: (teamId, owner, repo, params = {}) => + this.request({ + path: `/teams/${teamId}/repos/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Check if a team manages a repository * @@ -1744,16 +2909,24 @@ export class Api extends HttpClient { * @originalName reposDetail * @duplicate */ - reposDetail2: (teamId, owner, repo, params) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "GET", params), + reposDetail2: (teamId, owner, repo, params = {}) => + this.request({ + path: `/teams/${teamId}/repos/${owner}/${repo}`, + method: "GET", + ...params, + }), /** * @description In order to add a repository to a team, the authenticated user must be an owner of the org that the team is associated with. Also, the repository must be owned by the organization, or a direct fork of a repository owned by the organization. * * @name ReposUpdate * @request PUT:/teams/{teamId}/repos/{owner}/{repo} */ - reposUpdate: (teamId, owner, repo, params) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "PUT", params), + reposUpdate: (teamId, owner, repo, params = {}) => + this.request({ + path: `/teams/${teamId}/repos/${owner}/${repo}`, + method: "PUT", + ...params, + }), }; this.user = { /** @@ -1762,190 +2935,348 @@ export class Api extends HttpClient { * @name UserList * @request GET:/user */ - userList: (params) => this.request(`/user`, "GET", params), + userList: (params = {}) => + this.request({ + path: `/user`, + method: "GET", + format: "json", + ...params, + }), /** * @description Update the authenticated user. * * @name UserPartialUpdate * @request PATCH:/user */ - userPartialUpdate: (body, params) => this.request(`/user`, "PATCH", params, body, BodyType.Json), + userPartialUpdate: (body, params = {}) => + this.request({ + path: `/user`, + method: "PATCH", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Delete email address(es). You can include a single email address or an array of addresses. * * @name EmailsDelete * @request DELETE:/user/emails */ - emailsDelete: (body, params) => this.request(`/user/emails`, "DELETE", params, body, BodyType.Json), + emailsDelete: (body, params = {}) => + this.request({ + path: `/user/emails`, + method: "DELETE", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description List email addresses for a user. In the final version of the API, this method will return an array of hashes with extended information for each email address indicating if the address has been verified and if it's primary email address for GitHub. Until API v3 is finalized, use the application/vnd.github.v3 media type to get other response format. * * @name EmailsList * @request GET:/user/emails */ - emailsList: (params) => this.request(`/user/emails`, "GET", params), + emailsList: (params = {}) => + this.request({ + path: `/user/emails`, + method: "GET", + ...params, + }), /** * @description Add email address(es). You can post a single email address or an array of addresses. * * @name EmailsCreate * @request POST:/user/emails */ - emailsCreate: (body, params) => this.request(`/user/emails`, "POST", params, body), + emailsCreate: (body, params = {}) => + this.request({ + path: `/user/emails`, + method: "POST", + body: body, + ...params, + }), /** * @description List the authenticated user's followers * * @name FollowersList * @request GET:/user/followers */ - followersList: (params) => this.request(`/user/followers`, "GET", params), + followersList: (params = {}) => + this.request({ + path: `/user/followers`, + method: "GET", + format: "json", + ...params, + }), /** * @description List who the authenticated user is following. * * @name FollowingList * @request GET:/user/following */ - followingList: (params) => this.request(`/user/following`, "GET", params), + followingList: (params = {}) => + this.request({ + path: `/user/following`, + method: "GET", + format: "json", + ...params, + }), /** * @description Unfollow a user. Unfollowing a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. * * @name FollowingDelete * @request DELETE:/user/following/{username} */ - followingDelete: (username, params) => this.request(`/user/following/${username}`, "DELETE", params), + followingDelete: (username, params = {}) => + this.request({ + path: `/user/following/${username}`, + method: "DELETE", + ...params, + }), /** * @description Check if you are following a user. * * @name FollowingDetail * @request GET:/user/following/{username} */ - followingDetail: (username, params) => this.request(`/user/following/${username}`, "GET", params), + followingDetail: (username, params = {}) => + this.request({ + path: `/user/following/${username}`, + method: "GET", + ...params, + }), /** * @description Follow a user. Following a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. * * @name FollowingUpdate * @request PUT:/user/following/{username} */ - followingUpdate: (username, params) => this.request(`/user/following/${username}`, "PUT", params), + followingUpdate: (username, params = {}) => + this.request({ + path: `/user/following/${username}`, + method: "PUT", + ...params, + }), /** * @description List issues. List all issues across owned and member repositories for the authenticated user. * * @name IssuesList * @request GET:/user/issues */ - issuesList: (query, params) => this.request(`/user/issues${this.addQueryParams(query)}`, "GET", params), + issuesList: (query, params = {}) => + this.request({ + path: `/user/issues`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List your public keys. Lists the current user's keys. Management of public keys via the API requires that you are authenticated through basic auth, or OAuth with the 'user', 'write:public_key' scopes. * * @name KeysList * @request GET:/user/keys */ - keysList: (params) => this.request(`/user/keys`, "GET", params), + keysList: (params = {}) => + this.request({ + path: `/user/keys`, + method: "GET", + format: "json", + ...params, + }), /** * @description Create a public key. * * @name KeysCreate * @request POST:/user/keys */ - keysCreate: (body, params) => this.request(`/user/keys`, "POST", params, body), + keysCreate: (body, params = {}) => + this.request({ + path: `/user/keys`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Delete a public key. Removes a public key. Requires that you are authenticated via Basic Auth or via OAuth with at least admin:public_key scope. * * @name KeysDelete * @request DELETE:/user/keys/{keyId} */ - keysDelete: (keyId, params) => this.request(`/user/keys/${keyId}`, "DELETE", params), + keysDelete: (keyId, params = {}) => + this.request({ + path: `/user/keys/${keyId}`, + method: "DELETE", + ...params, + }), /** * @description Get a single public key. * * @name KeysDetail * @request GET:/user/keys/{keyId} */ - keysDetail: (keyId, params) => this.request(`/user/keys/${keyId}`, "GET", params), + keysDetail: (keyId, params = {}) => + this.request({ + path: `/user/keys/${keyId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description List public and private organizations for the authenticated user. * * @name OrgsList * @request GET:/user/orgs */ - orgsList: (params) => this.request(`/user/orgs`, "GET", params), + orgsList: (params = {}) => + this.request({ + path: `/user/orgs`, + method: "GET", + format: "json", + ...params, + }), /** * @description List repositories for the authenticated user. Note that this does not include repositories owned by organizations which the user can access. You can lis user organizations and list organization repositories separately. * * @name ReposList * @request GET:/user/repos */ - reposList: (query, params) => this.request(`/user/repos${this.addQueryParams(query)}`, "GET", params), + reposList: (query, params = {}) => + this.request({ + path: `/user/repos`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. * * @name ReposCreate * @request POST:/user/repos */ - reposCreate: (body, params) => this.request(`/user/repos`, "POST", params, body), + reposCreate: (body, params = {}) => + this.request({ + path: `/user/repos`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description List repositories being starred by the authenticated user. * * @name StarredList * @request GET:/user/starred */ - starredList: (query, params) => this.request(`/user/starred${this.addQueryParams(query)}`, "GET", params), + starredList: (query, params = {}) => + this.request({ + path: `/user/starred`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Unstar a repository * * @name StarredDelete * @request DELETE:/user/starred/{owner}/{repo} */ - starredDelete: (owner, repo, params) => this.request(`/user/starred/${owner}/${repo}`, "DELETE", params), + starredDelete: (owner, repo, params = {}) => + this.request({ + path: `/user/starred/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Check if you are starring a repository. * * @name StarredDetail * @request GET:/user/starred/{owner}/{repo} */ - starredDetail: (owner, repo, params) => this.request(`/user/starred/${owner}/${repo}`, "GET", params), + starredDetail: (owner, repo, params = {}) => + this.request({ + path: `/user/starred/${owner}/${repo}`, + method: "GET", + ...params, + }), /** * @description Star a repository. * * @name StarredUpdate * @request PUT:/user/starred/{owner}/{repo} */ - starredUpdate: (owner, repo, params) => this.request(`/user/starred/${owner}/${repo}`, "PUT", params), + starredUpdate: (owner, repo, params = {}) => + this.request({ + path: `/user/starred/${owner}/${repo}`, + method: "PUT", + ...params, + }), /** * @description List repositories being watched by the authenticated user. * * @name SubscriptionsList * @request GET:/user/subscriptions */ - subscriptionsList: (params) => this.request(`/user/subscriptions`, "GET", params), + subscriptionsList: (params = {}) => + this.request({ + path: `/user/subscriptions`, + method: "GET", + format: "json", + ...params, + }), /** * @description Stop watching a repository * * @name SubscriptionsDelete * @request DELETE:/user/subscriptions/{owner}/{repo} */ - subscriptionsDelete: (owner, repo, params) => - this.request(`/user/subscriptions/${owner}/${repo}`, "DELETE", params), + subscriptionsDelete: (owner, repo, params = {}) => + this.request({ + path: `/user/subscriptions/${owner}/${repo}`, + method: "DELETE", + ...params, + }), /** * @description Check if you are watching a repository. * * @name SubscriptionsDetail * @request GET:/user/subscriptions/{owner}/{repo} */ - subscriptionsDetail: (owner, repo, params) => this.request(`/user/subscriptions/${owner}/${repo}`, "GET", params), + subscriptionsDetail: (owner, repo, params = {}) => + this.request({ + path: `/user/subscriptions/${owner}/${repo}`, + method: "GET", + ...params, + }), /** * @description Watch a repository. * * @name SubscriptionsUpdate * @request PUT:/user/subscriptions/{owner}/{repo} */ - subscriptionsUpdate: (owner, repo, params) => this.request(`/user/subscriptions/${owner}/${repo}`, "PUT", params), + subscriptionsUpdate: (owner, repo, params = {}) => + this.request({ + path: `/user/subscriptions/${owner}/${repo}`, + method: "PUT", + ...params, + }), /** * @description List all of the teams across all of the organizations to which the authenticated user belongs. This method requires user or repo scope when authenticating via OAuth. * * @name TeamsList * @request GET:/user/teams */ - teamsList: (params) => this.request(`/user/teams`, "GET", params), + teamsList: (params = {}) => + this.request({ + path: `/user/teams`, + method: "GET", + format: "json", + ...params, + }), }; this.users = { /** @@ -1954,102 +3285,178 @@ export class Api extends HttpClient { * @name UsersList * @request GET:/users */ - usersList: (query, params) => this.request(`/users${this.addQueryParams(query)}`, "GET", params), + usersList: (query, params = {}) => + this.request({ + path: `/users`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Get a single user. * * @name UsersDetail * @request GET:/users/{username} */ - usersDetail: (username, params) => this.request(`/users/${username}`, "GET", params), + usersDetail: (username, params = {}) => + this.request({ + path: `/users/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description If you are authenticated as the given user, you will see your private events. Otherwise, you'll only see public events. * * @name EventsDetail * @request GET:/users/{username}/events */ - eventsDetail: (username, params) => this.request(`/users/${username}/events`, "GET", params), + eventsDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/events`, + method: "GET", + ...params, + }), /** * @description This is the user's organization dashboard. You must be authenticated as the user to view this. * * @name EventsOrgsDetail * @request GET:/users/{username}/events/orgs/{org} */ - eventsOrgsDetail: (username, org, params) => this.request(`/users/${username}/events/orgs/${org}`, "GET", params), + eventsOrgsDetail: (username, org, params = {}) => + this.request({ + path: `/users/${username}/events/orgs/${org}`, + method: "GET", + ...params, + }), /** * @description List a user's followers * * @name FollowersDetail * @request GET:/users/{username}/followers */ - followersDetail: (username, params) => this.request(`/users/${username}/followers`, "GET", params), + followersDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/followers`, + method: "GET", + format: "json", + ...params, + }), /** * @description Check if one user follows another. * * @name FollowingDetail * @request GET:/users/{username}/following/{targetUser} */ - followingDetail: (username, targetUser, params) => - this.request(`/users/${username}/following/${targetUser}`, "GET", params), + followingDetail: (username, targetUser, params = {}) => + this.request({ + path: `/users/${username}/following/${targetUser}`, + method: "GET", + ...params, + }), /** * @description List a users gists. * * @name GistsDetail * @request GET:/users/{username}/gists */ - gistsDetail: (username, query, params) => - this.request(`/users/${username}/gists${this.addQueryParams(query)}`, "GET", params), + gistsDetail: (username, query, params = {}) => + this.request({ + path: `/users/${username}/gists`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List public keys for a user. Lists the verified public keys for a user. This is accessible by anyone. * * @name KeysDetail * @request GET:/users/{username}/keys */ - keysDetail: (username, params) => this.request(`/users/${username}/keys`, "GET", params), + keysDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/keys`, + method: "GET", + format: "json", + ...params, + }), /** * @description List all public organizations for a user. * * @name OrgsDetail * @request GET:/users/{username}/orgs */ - orgsDetail: (username, params) => this.request(`/users/${username}/orgs`, "GET", params), + orgsDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/orgs`, + method: "GET", + format: "json", + ...params, + }), /** * @description These are events that you'll only see public events. * * @name ReceivedEventsDetail * @request GET:/users/{username}/received_events */ - receivedEventsDetail: (username, params) => this.request(`/users/${username}/received_events`, "GET", params), + receivedEventsDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/received_events`, + method: "GET", + ...params, + }), /** * @description List public events that a user has received * * @name ReceivedEventsPublicDetail * @request GET:/users/{username}/received_events/public */ - receivedEventsPublicDetail: (username, params) => - this.request(`/users/${username}/received_events/public`, "GET", params), + receivedEventsPublicDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/received_events/public`, + method: "GET", + ...params, + }), /** * @description List public repositories for the specified user. * * @name ReposDetail * @request GET:/users/{username}/repos */ - reposDetail: (username, query, params) => - this.request(`/users/${username}/repos${this.addQueryParams(query)}`, "GET", params), + reposDetail: (username, query, params = {}) => + this.request({ + path: `/users/${username}/repos`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description List repositories being starred by a user. * * @name StarredDetail * @request GET:/users/{username}/starred */ - starredDetail: (username, params) => this.request(`/users/${username}/starred`, "GET", params), + starredDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/starred`, + method: "GET", + ...params, + }), /** * @description List repositories being watched by a user. * * @name SubscriptionsDetail * @request GET:/users/{username}/subscriptions */ - subscriptionsDetail: (username, params) => this.request(`/users/${username}/subscriptions`, "GET", params), + subscriptionsDetail: (username, params = {}) => + this.request({ + path: `/users/${username}/subscriptions`, + method: "GET", + ...params, + }), }; } } diff --git a/tests/spec/modular/Key.ts b/tests/spec/modular/Key.ts index 1c044a3c..3037203b 100644 --- a/tests/spec/modular/Key.ts +++ b/tests/spec/modular/Key.ts @@ -12,7 +12,7 @@ import { AuthentiqID, Error } from "./data-contracts"; import { HttpClient, RequestParams } from "./http-client"; -export class Key extends HttpClient { +export class Key extends HttpClient { /** * @description Revoke an Authentiq ID using email & phone. If called with `email` and `phone` only, a verification code will be sent by email. Do a second call adding `code` to complete the revocation. * @@ -20,8 +20,13 @@ export class Key extends HttpClient { * @name KeyRevokeNosecret * @request DELETE:/key */ - keyRevokeNosecret = (query: { email: string; phone: string; code?: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key${this.addQueryParams(query)}`, "DELETE", params); + keyRevokeNosecret = (query: { email: string; phone: string; code?: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key`, + method: "DELETE", + query: query, + ...params, + }); /** * @description Register a new ID `JWT(sub, devtoken)` v5: `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples * @@ -29,8 +34,13 @@ export class Key extends HttpClient { * @name KeyRegister * @request POST:/key */ - keyRegister = (body: AuthentiqID, params?: RequestParams) => - this.request<{ secret?: string; status?: string }, Error>(`/key`, "POST", params, body); + keyRegister = (body: AuthentiqID, params: RequestParams = {}) => + this.request<{ secret?: string; status?: string }, Error>({ + path: `/key`, + method: "POST", + body: body, + ...params, + }); /** * @description Revoke an Identity (Key) with a revocation secret * @@ -38,8 +48,13 @@ export class Key extends HttpClient { * @name KeyRevoke * @request DELETE:/key/{PK} */ - keyRevoke = (PK: string, query: { secret: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}${this.addQueryParams(query)}`, "DELETE", params); + keyRevoke = (PK: string, query: { secret: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "DELETE", + query: query, + ...params, + }); /** * @description Get public details of an Authentiq ID. * @@ -47,8 +62,12 @@ export class Key extends HttpClient { * @name GetKey * @request GET:/key/{PK} */ - getKey = (PK: string, params?: RequestParams) => - this.request<{ since?: string; status?: string; sub?: string }, Error>(`/key/${PK}`, "GET", params); + getKey = (PK: string, params: RequestParams = {}) => + this.request<{ since?: string; status?: string; sub?: string }, Error>({ + path: `/key/${PK}`, + method: "GET", + ...params, + }); /** * @description HEAD info on Authentiq ID * @@ -56,7 +75,12 @@ export class Key extends HttpClient { * @name HeadKey * @request HEAD:/key/{PK} */ - headKey = (PK: string, params?: RequestParams) => this.request(`/key/${PK}`, "HEAD", params); + headKey = (PK: string, params: RequestParams = {}) => + this.request({ + path: `/key/${PK}`, + method: "HEAD", + ...params, + }); /** * @description update properties of an Authentiq ID. (not operational in v4; use PUT for now) v5: POST issuer-signed email & phone scopes in a self-signed JWT See: https://github.com/skion/authentiq/wiki/JWT-Examples * @@ -64,8 +88,13 @@ export class Key extends HttpClient { * @name KeyUpdate * @request POST:/key/{PK} */ - keyUpdate = (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "POST", params, body); + keyUpdate = (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "POST", + body: body, + ...params, + }); /** * @description Update Authentiq ID by replacing the object. v4: `JWT(sub,email,phone)` to bind email/phone hash; v5: POST issuer-signed email & phone scopes and PUT to update registration `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples * @@ -73,6 +102,11 @@ export class Key extends HttpClient { * @name KeyBind * @request PUT:/key/{PK} */ - keyBind = (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "PUT", params, body); + keyBind = (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "PUT", + body: body, + ...params, + }); } diff --git a/tests/spec/modular/Login.ts b/tests/spec/modular/Login.ts index 0a419871..67eafad7 100644 --- a/tests/spec/modular/Login.ts +++ b/tests/spec/modular/Login.ts @@ -12,7 +12,7 @@ import { Error, PushToken } from "./data-contracts"; import { HttpClient, RequestParams } from "./http-client"; -export class Login extends HttpClient { +export class Login extends HttpClient { /** * @description push sign-in request See: https://github.com/skion/authentiq/wiki/JWT-Examples * @@ -20,6 +20,25 @@ export class Login extends HttpClient { * @name PushLoginRequest * @request POST:/login */ - pushLoginRequest = (query: { callback: string }, body: PushToken, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/login${this.addQueryParams(query)}`, "POST", params, body); + pushLoginRequest = (query: { callback: string }, body: PushToken, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/login`, + method: "POST", + query: query, + body: body, + ...params, + }); + /** + * @description Get a current key register + * + * @tags key, get + * @name KeyRegister + * @request GET:/login + */ + keyRegister = (params: RequestParams = {}) => + this.request<{ secret?: string; status?: string }, Error>({ + path: `/login`, + method: "GET", + ...params, + }); } diff --git a/tests/spec/modular/Scope.ts b/tests/spec/modular/Scope.ts index 2b2f43f9..c761fb8a 100644 --- a/tests/spec/modular/Scope.ts +++ b/tests/spec/modular/Scope.ts @@ -10,9 +10,9 @@ */ import { Claims, Error } from "./data-contracts"; -import { BodyType, HttpClient, RequestParams } from "./http-client"; +import { ContentType, HttpClient, RequestParams } from "./http-client"; -export class Scope extends HttpClient { +export class Scope extends HttpClient { /** * @description scope verification request See: https://github.com/skion/authentiq/wiki/JWT-Examples * @@ -20,13 +20,14 @@ export class Scope extends HttpClient { * @name SignRequest * @request POST:/scope */ - signRequest = (body: Claims, query?: { test?: number }, params?: RequestParams) => - this.request<{ job?: string; status?: string }, Error>( - `/scope${this.addQueryParams(query)}`, - "POST", - params, - body, - ); + signRequest = (body: Claims, query?: { test?: number }, params: RequestParams = {}) => + this.request<{ job?: string; status?: string }, Error>({ + path: `/scope`, + method: "POST", + query: query, + body: body, + ...params, + }); /** * @description delete a verification job * @@ -34,8 +35,12 @@ export class Scope extends HttpClient { * @name SignDelete * @request DELETE:/scope/{job} */ - signDelete = (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "DELETE", params); + signDelete = (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "DELETE", + ...params, + }); /** * @description get the status / current content of a verification job * @@ -43,8 +48,12 @@ export class Scope extends HttpClient { * @name SignRetrieve * @request GET:/scope/{job} */ - signRetrieve = (job: string, params?: RequestParams) => - this.request<{ exp?: number; field?: string; sub?: string }, Error>(`/scope/${job}`, "GET", params); + signRetrieve = (job: string, params: RequestParams = {}) => + this.request<{ exp?: number; field?: string; sub?: string }, Error>({ + path: `/scope/${job}`, + method: "GET", + ...params, + }); /** * @description HEAD to get the status of a verification job * @@ -52,8 +61,12 @@ export class Scope extends HttpClient { * @name SignRetrieveHead * @request HEAD:/scope/{job} */ - signRetrieveHead = (job: string, params?: RequestParams) => - this.request(`/scope/${job}`, "HEAD", params); + signRetrieveHead = (job: string, params: RequestParams = {}) => + this.request({ + path: `/scope/${job}`, + method: "HEAD", + ...params, + }); /** * @description this is a scope confirmation * @@ -61,8 +74,13 @@ export class Scope extends HttpClient { * @name SignConfirm * @request POST:/scope/{job} */ - signConfirm = (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "POST", params, null, BodyType.Json); + signConfirm = (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "POST", + type: ContentType.Json, + ...params, + }); /** * @description authority updates a JWT with its signature See: https://github.com/skion/authentiq/wiki/JWT-Examples * @@ -70,6 +88,10 @@ export class Scope extends HttpClient { * @name SignUpdate * @request PUT:/scope/{job} */ - signUpdate = (job: string, params?: RequestParams) => - this.request<{ jwt?: string; status?: string }, Error>(`/scope/${job}`, "PUT", params); + signUpdate = (job: string, params: RequestParams = {}) => + this.request<{ jwt?: string; status?: string }, Error>({ + path: `/scope/${job}`, + method: "PUT", + ...params, + }); } diff --git a/tests/spec/modular/http-client.ts b/tests/spec/modular/http-client.ts index 33f5bf06..c8bc241e 100644 --- a/tests/spec/modular/http-client.ts +++ b/tests/spec/modular/http-client.ts @@ -9,39 +9,58 @@ * --------------------------------------------------------------- */ -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; + baseApiParams?: Omit; securityWorker?: (securityData: SecurityDataType) => RequestParams; } -export interface HttpResponse extends Response { +interface HttpResponse extends Response { data: D; error: E; } -export enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://6-dot-authentiqio.appspot.com"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -54,92 +73,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); diff --git a/tests/spec/modular/schema.json b/tests/spec/modular/schema.json index 8c57124b..9712e3ab 100644 --- a/tests/spec/modular/schema.json +++ b/tests/spec/modular/schema.json @@ -438,6 +438,41 @@ } }, "tags": ["login", "post"] + }, + "get": { + "consumes": ["application/jwt"], + "description": "Get a current key register", + "operationId": "key_register", + "parameters": [], + "produces": ["application/json"], + "responses": { + "200": { + "description": "Success", + "schema": { + "properties": { + "secret": { + "description": "revoke key", + "type": "string" + }, + "status": { + "description": "registered", + "type": "string" + } + }, + "type": "object" + } + }, + "409": { + "description": "Key already registered `duplicate-key`", + "schema": { + "$ref": "#/definitions/Error" + } + }, + "default": { + "$ref": "#/responses/ErrorResponse" + } + }, + "tags": ["key", "get"] } }, "/scope": { diff --git a/tests/spec/moduleNameIndex/schema.ts b/tests/spec/moduleNameIndex/schema.ts index 900ed907..ca992f88 100644 --- a/tests/spec/moduleNameIndex/schema.ts +++ b/tests/spec/moduleNameIndex/schema.ts @@ -137,16 +137,34 @@ export interface Amount { */ export type Currency = string; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -154,22 +172,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/v2"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -182,92 +201,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -280,7 +333,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/v2 * This is a sample server Petstore server. You can find out more about Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/). For this sample, you can use the api key `special-key` to test the authorization filters. */ -export class Api extends HttpClient { +export class Api extends HttpClient { pet = { /** * No description @@ -291,8 +344,15 @@ export class Api extends HttpClient { * @request POST:api/v1/pet * @secure */ - addPet: (body: Pet, params?: RequestParams) => - this.request(`api/v1/pet`, "POST", params, body, BodyType.Json, true), + addPet: (body: Pet, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet`, + method: "POST", + body: body, + secure: true, + type: ContentType.Json, + ...params, + }), /** * No description @@ -303,8 +363,15 @@ export class Api extends HttpClient { * @request PUT:api/v1/pet * @secure */ - updatePet: (body: Pet, params?: RequestParams) => - this.request(`api/v1/pet`, "PUT", params, body, BodyType.Json, true), + updatePet: (body: Pet, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet`, + method: "PUT", + body: body, + secure: true, + type: ContentType.Json, + ...params, + }), /** * @description Multiple status values can be provided with comma separated strings @@ -315,15 +382,15 @@ export class Api extends HttpClient { * @request GET:api/v1/pet/findByStatus * @secure */ - findPetsByStatus: (query: { status: ("available" | "pending" | "sold")[] }, params?: RequestParams) => - this.request( - `api/v1/pet/findByStatus${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + findPetsByStatus: (query: { status: ("available" | "pending" | "sold")[] }, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet/findByStatus`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Multiple tags can be provided with comma separated strings. Use tag1, tag2, tag3 for testing. @@ -334,15 +401,15 @@ export class Api extends HttpClient { * @request GET:api/v1/pet/findByTags * @secure */ - findPetsByTags: (query: { tags: string[] }, params?: RequestParams) => - this.request( - `api/v1/pet/findByTags${this.addQueryParams(query)}`, - "GET", - params, - null, - BodyType.Json, - true, - ), + findPetsByTags: (query: { tags: string[] }, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet/findByTags`, + method: "GET", + query: query, + secure: true, + format: "json", + ...params, + }), /** * @description Returns a single pet @@ -353,8 +420,14 @@ export class Api extends HttpClient { * @request GET:api/v1/pet/{petId} * @secure */ - getPetById: (petId: number, params?: RequestParams) => - this.request(`api/v1/pet/${petId}`, "GET", params, null, BodyType.Json, true), + getPetById: (petId: number, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet/${petId}`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -365,8 +438,15 @@ export class Api extends HttpClient { * @request POST:api/v1/pet/{petId} * @secure */ - updatePetWithForm: (petId: number, data: { name?: string; status?: string }, params?: RequestParams) => - this.request(`api/v1/pet/${petId}`, "POST", params, data, BodyType.FormData, true), + updatePetWithForm: (petId: number, data: { name?: string; status?: string }, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet/${petId}`, + method: "POST", + body: data, + secure: true, + type: ContentType.FormData, + ...params, + }), /** * No description @@ -377,8 +457,13 @@ export class Api extends HttpClient { * @request DELETE:api/v1/pet/{petId} * @secure */ - deletePet: (petId: number, params?: RequestParams) => - this.request(`api/v1/pet/${petId}`, "DELETE", params, null, BodyType.Json, true), + deletePet: (petId: number, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet/${petId}`, + method: "DELETE", + secure: true, + ...params, + }), /** * No description @@ -389,8 +474,16 @@ export class Api extends HttpClient { * @request POST:api/v1/pet/{petId}/uploadImage * @secure */ - uploadFile: (petId: number, data: { additionalMetadata?: string; file?: File }, params?: RequestParams) => - this.request(`api/v1/pet/${petId}/uploadImage`, "POST", params, data, BodyType.FormData, true), + uploadFile: (petId: number, data: { additionalMetadata?: string; file?: File }, params: RequestParams = {}) => + this.request({ + path: `api/v1/pet/${petId}/uploadImage`, + method: "POST", + body: data, + secure: true, + type: ContentType.FormData, + format: "json", + ...params, + }), }; store = { /** @@ -402,8 +495,14 @@ export class Api extends HttpClient { * @request GET:api/v1/store/inventory * @secure */ - getInventory: (params?: RequestParams) => - this.request, any>(`api/v1/store/inventory`, "GET", params, null, BodyType.Json, true), + getInventory: (params: RequestParams = {}) => + this.request, any>({ + path: `api/v1/store/inventory`, + method: "GET", + secure: true, + format: "json", + ...params, + }), /** * No description @@ -413,8 +512,15 @@ export class Api extends HttpClient { * @summary Place an order for a pet * @request POST:api/v1/store/order */ - placeOrder: (body: Order, params?: RequestParams) => - this.request(`api/v1/store/order`, "POST", params, body, BodyType.Json), + placeOrder: (body: Order, params: RequestParams = {}) => + this.request({ + path: `api/v1/store/order`, + method: "POST", + body: body, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description For valid response try integer IDs with value <= 5 or > 10. Other values will generated exceptions @@ -424,8 +530,13 @@ export class Api extends HttpClient { * @summary Find purchase order by ID * @request GET:api/v1/store/order/{orderId} */ - getOrderById: (orderId: number, params?: RequestParams) => - this.request(`api/v1/store/order/${orderId}`, "GET", params), + getOrderById: (orderId: number, params: RequestParams = {}) => + this.request({ + path: `api/v1/store/order/${orderId}`, + method: "GET", + format: "json", + ...params, + }), /** * @description For valid response try integer IDs with value < 1000. Anything above 1000 or nonintegers will generate API errors @@ -435,8 +546,12 @@ export class Api extends HttpClient { * @summary Delete purchase order by ID * @request DELETE:api/v1/store/order/{orderId} */ - deleteOrder: (orderId: string, params?: RequestParams) => - this.request(`api/v1/store/order/${orderId}`, "DELETE", params), + deleteOrder: (orderId: string, params: RequestParams = {}) => + this.request({ + path: `api/v1/store/order/${orderId}`, + method: "DELETE", + ...params, + }), }; user = { /** @@ -447,8 +562,14 @@ export class Api extends HttpClient { * @summary Create user * @request POST:api/v1/user */ - createUser: (body: User, params?: RequestParams) => - this.request(`api/v1/user`, "POST", params, body, BodyType.Json), + createUser: (body: User, params: RequestParams = {}) => + this.request({ + path: `api/v1/user`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -458,8 +579,14 @@ export class Api extends HttpClient { * @summary Creates list of users with given input array * @request POST:api/v1/user/createWithArray */ - createUsersWithArrayInput: (body: User[], params?: RequestParams) => - this.request(`api/v1/user/createWithArray`, "POST", params, body, BodyType.Json), + createUsersWithArrayInput: (body: User[], params: RequestParams = {}) => + this.request({ + path: `api/v1/user/createWithArray`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -469,8 +596,14 @@ export class Api extends HttpClient { * @summary Creates list of users with given input array * @request POST:api/v1/user/createWithList */ - createUsersWithListInput: (body: User[], params?: RequestParams) => - this.request(`api/v1/user/createWithList`, "POST", params, body, BodyType.Json), + createUsersWithListInput: (body: User[], params: RequestParams = {}) => + this.request({ + path: `api/v1/user/createWithList`, + method: "POST", + body: body, + type: ContentType.Json, + ...params, + }), /** * No description @@ -480,8 +613,14 @@ export class Api extends HttpClient { * @summary Logs user into the system * @request GET:api/v1/user/login */ - loginUser: (query: { username: string; password: string }, params?: RequestParams) => - this.request(`api/v1/user/login${this.addQueryParams(query)}`, "GET", params), + loginUser: (query: { username: string; password: string }, params: RequestParams = {}) => + this.request({ + path: `api/v1/user/login`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * No description @@ -491,7 +630,12 @@ export class Api extends HttpClient { * @summary Logs out current logged in user session * @request GET:api/v1/user/logout */ - logoutUser: (params?: RequestParams) => this.request(`api/v1/user/logout`, "GET", params), + logoutUser: (params: RequestParams = {}) => + this.request({ + path: `api/v1/user/logout`, + method: "GET", + ...params, + }), /** * No description @@ -501,8 +645,13 @@ export class Api extends HttpClient { * @summary Get user by user name * @request GET:api/v1/user/{username} */ - getUserByName: (username: string, params?: RequestParams) => - this.request(`api/v1/user/${username}`, "GET", params), + getUserByName: (username: string, params: RequestParams = {}) => + this.request({ + path: `api/v1/user/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description This can only be done by the logged in user. @@ -512,8 +661,14 @@ export class Api extends HttpClient { * @summary Updated user * @request PUT:api/v1/user/{username} */ - updateUser: (username: string, body: User, params?: RequestParams) => - this.request(`api/v1/user/${username}`, "PUT", params, body, BodyType.Json), + updateUser: (username: string, body: User, params: RequestParams = {}) => + this.request({ + path: `api/v1/user/${username}`, + method: "PUT", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description This can only be done by the logged in user. @@ -523,8 +678,12 @@ export class Api extends HttpClient { * @summary Delete user * @request DELETE:api/v1/user/{username} */ - deleteUser: (username: string, params?: RequestParams) => - this.request(`api/v1/user/${username}`, "DELETE", params), + deleteUser: (username: string, params: RequestParams = {}) => + this.request({ + path: `api/v1/user/${username}`, + method: "DELETE", + ...params, + }), }; username = { /** @@ -535,8 +694,13 @@ export class Api extends HttpClient { * @summary Get user by user name * @request GET:api/v1/{username} */ - getUserByName: (username: string, params?: RequestParams) => - this.request(`api/v1/${username}`, "GET", params), + getUserByName: (username: string, params: RequestParams = {}) => + this.request({ + path: `api/v1/${username}`, + method: "GET", + format: "json", + ...params, + }), /** * @description This can only be done by the logged in user. @@ -546,8 +710,14 @@ export class Api extends HttpClient { * @summary Updated user * @request PUT:api/v1/{username} */ - updateUser: (username: string, body: User, params?: RequestParams) => - this.request(`api/v1/${username}`, "PUT", params, body, BodyType.Json), + updateUser: (username: string, body: User, params: RequestParams = {}) => + this.request({ + path: `api/v1/${username}`, + method: "PUT", + body: body, + type: ContentType.Json, + ...params, + }), /** * @description This can only be done by the logged in user. @@ -557,7 +727,11 @@ export class Api extends HttpClient { * @summary Delete user * @request DELETE:api/v1/{username} */ - deleteUser: (username: string, params?: RequestParams) => - this.request(`api/v1/${username}`, "DELETE", params), + deleteUser: (username: string, params: RequestParams = {}) => + this.request({ + path: `api/v1/${username}`, + method: "DELETE", + ...params, + }), }; } diff --git a/tests/spec/responses/schema.ts b/tests/spec/responses/schema.ts index 69653382..162d78db 100644 --- a/tests/spec/responses/schema.ts +++ b/tests/spec/responses/schema.ts @@ -61,16 +61,34 @@ export interface PushToken { sub: string; } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } /** Overrided Promise type. Needs for additional typings of `.catch` callback */ @@ -89,22 +107,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "https://6-dot-authentiqio.appspot.com"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -117,92 +136,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): TPromise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): TPromise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -215,7 +268,7 @@ export class HttpClient { * @baseUrl https://6-dot-authentiqio.appspot.com * Strong authentication, without the passwords. */ -export class Api extends HttpClient { +export class Api extends HttpClient { key = { /** * @description Revoke an Authentiq ID using email & phone. If called with `email` and `phone` only, a verification code will be sent by email. Do a second call adding `code` to complete the revocation. @@ -229,8 +282,14 @@ export class Api extends HttpClient { * @response `409` `Error` Confirm with code sent `confirm-first` * @response `default` `Error` */ - keyRevokeNosecret: (query: { email: string; phone: string; code?: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key${this.addQueryParams(query)}`, "DELETE", params), + keyRevokeNosecret: (query: { email: string; phone: string; code?: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Register a new ID `JWT(sub, devtoken)` v5: `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -242,8 +301,14 @@ export class Api extends HttpClient { * @response `409` `Error` Key already registered `duplicate-key` * @response `default` `Error` */ - keyRegister: (body: AuthentiqID, params?: RequestParams) => - this.request<{ secret?: string; status?: string }, Error>(`/key`, "POST", params, body), + keyRegister: (body: AuthentiqID, params: RequestParams = {}) => + this.request<{ secret?: string; status?: string }, Error>({ + path: `/key`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Revoke an Identity (Key) with a revocation secret @@ -256,8 +321,14 @@ export class Api extends HttpClient { * @response `404` `Error` Unknown key `unknown-key` * @response `default` `Error` */ - keyRevoke: (PK: string, query: { secret: string }, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}${this.addQueryParams(query)}`, "DELETE", params), + keyRevoke: (PK: string, query: { secret: string }, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "DELETE", + query: query, + format: "json", + ...params, + }), /** * @description Get public details of an Authentiq ID. @@ -270,8 +341,13 @@ export class Api extends HttpClient { * @response `410` `Error` Key is revoked (gone). `revoked-key` * @response `default` `Error` */ - getKey: (PK: string, params?: RequestParams) => - this.request<{ since?: string; status?: string; sub?: string }, Error>(`/key/${PK}`, "GET", params), + getKey: (PK: string, params: RequestParams = {}) => + this.request<{ since?: string; status?: string; sub?: string }, Error>({ + path: `/key/${PK}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD info on Authentiq ID @@ -279,12 +355,17 @@ export class Api extends HttpClient { * @tags key, head * @name HeadKey * @request HEAD:/key/{PK} - * @response `200` `any` Key exists + * @response `200` `void` Key exists * @response `404` `Error` Unknown key `unknown-key` * @response `410` `Error` Key is revoked `revoked-key` * @response `default` `Error` */ - headKey: (PK: string, params?: RequestParams) => this.request(`/key/${PK}`, "HEAD", params), + headKey: (PK: string, params: RequestParams = {}) => + this.request({ + path: `/key/${PK}`, + method: "HEAD", + ...params, + }), /** * @description update properties of an Authentiq ID. (not operational in v4; use PUT for now) v5: POST issuer-signed email & phone scopes in a self-signed JWT See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -296,8 +377,14 @@ export class Api extends HttpClient { * @response `404` `Error` Unknown key `unknown-key` * @response `default` `Error` */ - keyUpdate: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "POST", params, body), + keyUpdate: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "POST", + body: body, + format: "json", + ...params, + }), /** * @description Update Authentiq ID by replacing the object. v4: `JWT(sub,email,phone)` to bind email/phone hash; v5: POST issuer-signed email & phone scopes and PUT to update registration `JWT(sub, pk, devtoken, ...)` See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -310,8 +397,14 @@ export class Api extends HttpClient { * @response `409` `Error` Already bound to another key `duplicate-hash` * @response `default` `Error` */ - keyBind: (PK: string, body: AuthentiqID, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/key/${PK}`, "PUT", params, body), + keyBind: (PK: string, body: AuthentiqID, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/key/${PK}`, + method: "PUT", + body: body, + format: "json", + ...params, + }), }; login = { /** @@ -324,8 +417,15 @@ export class Api extends HttpClient { * @response `401` `Error` Unauthorized for this callback audience `aud-error` or JWT should be self-signed `auth-error` * @response `default` `Error` */ - pushLoginRequest: (query: { callback: string }, body: PushToken, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/login${this.addQueryParams(query)}`, "POST", params, body), + pushLoginRequest: (query: { callback: string }, body: PushToken, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/login`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), }; scope = { /** @@ -338,13 +438,15 @@ export class Api extends HttpClient { * @response `429` `Error` Too Many Requests on same address / number `rate-limit` * @response `default` `Error` */ - signRequest: (body: Claims, query?: { test?: number }, params?: RequestParams) => - this.request<{ job?: string; status?: string }, Error>( - `/scope${this.addQueryParams(query)}`, - "POST", - params, - body, - ), + signRequest: (body: Claims, query?: { test?: number }, params: RequestParams = {}) => + this.request<{ job?: string; status?: string }, Error>({ + path: `/scope`, + method: "POST", + query: query, + body: body, + format: "json", + ...params, + }), /** * @description delete a verification job @@ -356,8 +458,13 @@ export class Api extends HttpClient { * @response `404` `Error` Job not found `unknown-job` * @response `default` `Error` */ - signDelete: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "DELETE", params), + signDelete: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "DELETE", + format: "json", + ...params, + }), /** * @description get the status / current content of a verification job @@ -366,12 +473,17 @@ export class Api extends HttpClient { * @name SignRetrieve * @request GET:/scope/{job} * @response `200` `{ exp?: number, field?: string, sub?: string }` Successful response (JWT) - * @response `204` `any` Confirmed, waiting for signing + * @response `204` `void` Confirmed, waiting for signing * @response `404` `Error` Job not found `unknown-job` * @response `default` `Error` */ - signRetrieve: (job: string, params?: RequestParams) => - this.request<{ exp?: number; field?: string; sub?: string }, Error>(`/scope/${job}`, "GET", params), + signRetrieve: (job: string, params: RequestParams = {}) => + this.request<{ exp?: number; field?: string; sub?: string }, Error>({ + path: `/scope/${job}`, + method: "GET", + format: "json", + ...params, + }), /** * @description HEAD to get the status of a verification job @@ -379,13 +491,17 @@ export class Api extends HttpClient { * @tags scope, head * @name SignRetrieveHead * @request HEAD:/scope/{job} - * @response `200` `any` Confirmed and signed - * @response `204` `any` Confirmed, waiting for signing + * @response `200` `void` Confirmed and signed + * @response `204` `void` Confirmed, waiting for signing * @response `404` `Error` Job not found `unknown-job` * @response `default` `Error` */ - signRetrieveHead: (job: string, params?: RequestParams) => - this.request(`/scope/${job}`, "HEAD", params), + signRetrieveHead: (job: string, params: RequestParams = {}) => + this.request({ + path: `/scope/${job}`, + method: "HEAD", + ...params, + }), /** * @description this is a scope confirmation @@ -399,8 +515,14 @@ export class Api extends HttpClient { * @response `405` `Error` JWT POSTed to scope `not-supported` * @response `default` `Error` */ - signConfirm: (job: string, params?: RequestParams) => - this.request<{ status?: string }, Error>(`/scope/${job}`, "POST", params, null, BodyType.Json), + signConfirm: (job: string, params: RequestParams = {}) => + this.request<{ status?: string }, Error>({ + path: `/scope/${job}`, + method: "POST", + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description authority updates a JWT with its signature See: https://github.com/skion/authentiq/wiki/JWT-Examples @@ -413,7 +535,11 @@ export class Api extends HttpClient { * @response `409` `Error` Job not confirmed yet `confirm-first` * @response `default` `Error` */ - signUpdate: (job: string, params?: RequestParams) => - this.request<{ jwt?: string; status?: string }, Error>(`/scope/${job}`, "PUT", params), + signUpdate: (job: string, params: RequestParams = {}) => + this.request<{ jwt?: string; status?: string }, Error>({ + path: `/scope/${job}`, + method: "PUT", + ...params, + }), }; } diff --git a/tests/spec/routeTypes/schema.json b/tests/spec/routeTypes/schema.json index 85b71c9e..073d032b 100644 --- a/tests/spec/routeTypes/schema.json +++ b/tests/spec/routeTypes/schema.json @@ -1,8 +1,6 @@ { "swagger": "2.0", - "schemes": [ - "https" - ], + "schemes": ["https"], "host": "api.github.com", "basePath": "/", "info": { @@ -10,10 +8,7 @@ "termsOfService": "https://help.github.com/articles/github-terms-of-service/#b-api-terms", "title": "GitHub", "version": "v3", - "x-apisguru-categories": [ - "collaboration", - "developer_tools" - ], + "x-apisguru-categories": ["collaboration", "developer_tools"], "x-logo": { "url": "https://api.apis.guru/v2/cache/logo/https_twitter.com_github_profile_image.jpeg" }, @@ -31,12 +26,8 @@ "externalDocs": { "url": "https://developer.github.com/v3/" }, - "consumes": [ - "application/json" - ], - "produces": [ - "application/json" - ], + "consumes": ["application/json"], + "produces": ["application/json"], "securityDefinitions": { "oauth_2_0": { "authorizationUrl": "https://github.com/login/oauth/authorize", @@ -69,7 +60,7 @@ } }, "paths": { - "/emojis": { + "/path-params": { "get": { "description": "Lists all the emojis available to use on GitHub.", "parameters": [ @@ -78,6 +69,21 @@ "in": "header", "name": "Accept", "type": "string" + }, + { + "description": "Tik Token", + "in": "header", + "name": "X-Auth", + "required": true, + "type": "string" + }, + { + "name": "petId", + "in": "path", + "description": "ID of pet to return", + "required": true, + "type": "integer", + "format": "int64" } ], "responses": { @@ -1505,13 +1511,7 @@ { "default": "all", "description": "Issues assigned to you / created by you / mentioning you / you're\nsubscribed to updates for / All issues the authenticated user can see\n", - "enum": [ - "assigned", - "created", - "mentioned", - "subscribed", - "all" - ], + "enum": ["assigned", "created", "mentioned", "subscribed", "all"], "in": "query", "name": "filter", "required": true, @@ -1519,10 +1519,7 @@ }, { "default": "open", - "enum": [ - "open", - "closed" - ], + "enum": ["open", "closed"], "in": "query", "name": "state", "required": true, @@ -1537,11 +1534,7 @@ }, { "default": "created", - "enum": [ - "created", - "updated", - "comments" - ], + "enum": ["created", "updated", "comments"], "in": "query", "name": "sort", "required": true, @@ -1549,10 +1542,7 @@ }, { "default": "desc", - "enum": [ - "asc", - "desc" - ], + "enum": ["asc", "desc"], "in": "query", "name": "direction", "required": true, @@ -1634,10 +1624,7 @@ }, { "description": "Indicates the state of the issues to return. Can be either open or closed.", - "enum": [ - "open", - "closed" - ], + "enum": ["open", "closed"], "in": "path", "name": "state", "required": true, @@ -1726,10 +1713,7 @@ { "default": "desc", "description": "The sort field. if sort param is provided. Can be either asc or desc.", - "enum": [ - "desc", - "asc" - ], + "enum": ["desc", "asc"], "in": "query", "name": "order", "type": "string" @@ -1748,11 +1732,7 @@ }, { "description": "The sort field. One of stars, forks, or updated. Default: results are sorted by best match.", - "enum": [ - "updated", - "stars", - "forks" - ], + "enum": ["updated", "stars", "forks"], "in": "query", "name": "sort", "type": "string" @@ -1896,10 +1876,7 @@ { "default": "desc", "description": "The sort field. if sort param is provided. Can be either asc or desc.", - "enum": [ - "desc", - "asc" - ], + "enum": ["desc", "asc"], "in": "query", "name": "order", "type": "string" @@ -1912,11 +1889,7 @@ }, { "description": "The sort field. One of stars, forks, or updated. Default: results are sorted by best match.", - "enum": [ - "updated", - "stars", - "forks" - ], + "enum": ["updated", "stars", "forks"], "in": "query", "name": "sort", "type": "string" @@ -1996,9 +1969,7 @@ } } ], - "produces": [ - "text/html" - ], + "produces": ["text/html"], "responses": { "200": { "description": "OK", @@ -2047,9 +2018,7 @@ }, "/markdown/raw": { "post": { - "consumes": [ - "text/plain" - ], + "consumes": ["text/plain"], "description": "Render a Markdown document in raw mode", "parameters": [ { @@ -2059,9 +2028,7 @@ "type": "string" } ], - "produces": [ - "text/html" - ], + "produces": ["text/html"], "responses": { "200": { "description": "OK", @@ -2935,13 +2902,7 @@ { "default": "all", "description": "Issues assigned to you / created by you / mentioning you / you're\nsubscribed to updates for / All issues the authenticated user can see\n", - "enum": [ - "assigned", - "created", - "mentioned", - "subscribed", - "all" - ], + "enum": ["assigned", "created", "mentioned", "subscribed", "all"], "in": "query", "name": "filter", "required": true, @@ -2949,10 +2910,7 @@ }, { "default": "open", - "enum": [ - "open", - "closed" - ], + "enum": ["open", "closed"], "in": "query", "name": "state", "required": true, @@ -2967,11 +2925,7 @@ }, { "default": "created", - "enum": [ - "created", - "updated", - "comments" - ], + "enum": ["created", "updated", "comments"], "in": "query", "name": "sort", "required": true, @@ -2979,10 +2933,7 @@ }, { "default": "desc", - "enum": [ - "asc", - "desc" - ], + "enum": ["asc", "desc"], "in": "query", "name": "direction", "required": true, @@ -3630,14 +3581,7 @@ }, { "default": "all", - "enum": [ - "all", - "public", - "private", - "forks", - "sources", - "member" - ], + "enum": ["all", "public", "private", "forks", "sources", "member"], "in": "query", "name": "type", "type": "string" @@ -6676,11 +6620,7 @@ }, { "default": "newes", - "enum": [ - "newes", - "oldes", - "watchers" - ], + "enum": ["newes", "oldes", "watchers"], "in": "query", "name": "sort", "type": "string" @@ -8370,13 +8310,7 @@ { "default": "all", "description": "Issues assigned to you / created by you / mentioning you / you're\nsubscribed to updates for / All issues the authenticated user can see\n", - "enum": [ - "assigned", - "created", - "mentioned", - "subscribed", - "all" - ], + "enum": ["assigned", "created", "mentioned", "subscribed", "all"], "in": "query", "name": "filter", "required": true, @@ -8384,10 +8318,7 @@ }, { "default": "open", - "enum": [ - "open", - "closed" - ], + "enum": ["open", "closed"], "in": "query", "name": "state", "required": true, @@ -8402,11 +8333,7 @@ }, { "default": "created", - "enum": [ - "created", - "updated", - "comments" - ], + "enum": ["created", "updated", "comments"], "in": "query", "name": "sort", "required": true, @@ -8414,10 +8341,7 @@ }, { "default": "desc", - "enum": [ - "asc", - "desc" - ], + "enum": ["asc", "desc"], "in": "query", "name": "direction", "required": true, @@ -8591,10 +8515,7 @@ }, { "description": "", - "enum": [ - "created", - "updated" - ], + "enum": ["created", "updated"], "in": "query", "name": "sort", "type": "string" @@ -10848,10 +10769,7 @@ { "default": "open", "description": "String to filter by state.", - "enum": [ - "open", - "closed" - ], + "enum": ["open", "closed"], "in": "query", "name": "state", "type": "string" @@ -10865,10 +10783,7 @@ { "default": "due_date", "description": "", - "enum": [ - "due_date", - "completeness" - ], + "enum": ["due_date", "completeness"], "in": "query", "name": "sort", "type": "string" @@ -11524,10 +11439,7 @@ { "default": "open", "description": "String to filter by state.", - "enum": [ - "open", - "closed" - ], + "enum": ["open", "closed"], "in": "query", "name": "state", "type": "string" @@ -11706,10 +11618,7 @@ }, { "description": "", - "enum": [ - "created", - "updated" - ], + "enum": ["created", "updated"], "in": "query", "name": "sort", "type": "string" @@ -14674,10 +14583,7 @@ "type": "string" }, { - "enum": [ - "tarball", - "zipball" - ], + "enum": ["tarball", "zipball"], "in": "path", "name": "archive_format", "required": true, @@ -14816,10 +14722,7 @@ { "default": "desc", "description": "The sort field. if sort param is provided. Can be either asc or desc.", - "enum": [ - "desc", - "asc" - ], + "enum": ["desc", "asc"], "in": "query", "name": "order", "type": "string" @@ -14833,9 +14736,7 @@ }, { "description": "Can only be 'indexed', which indicates how recently a file has been indexed\nby the GitHub search infrastructure. If not provided, results are sorted\nby best match.\n", - "enum": [ - "indexed" - ], + "enum": ["indexed"], "in": "query", "name": "sort", "type": "string" @@ -14903,10 +14804,7 @@ { "default": "desc", "description": "The sort field. if sort param is provided. Can be either asc or desc.", - "enum": [ - "desc", - "asc" - ], + "enum": ["desc", "asc"], "in": "query", "name": "order", "type": "string" @@ -14920,11 +14818,7 @@ }, { "description": "The sort field. Can be comments, created, or updated. Default: results are sorted by best match.", - "enum": [ - "updated", - "created", - "comments" - ], + "enum": ["updated", "created", "comments"], "in": "query", "name": "sort", "type": "string" @@ -14992,10 +14886,7 @@ { "default": "desc", "description": "The sort field. if sort param is provided. Can be either asc or desc.", - "enum": [ - "desc", - "asc" - ], + "enum": ["desc", "asc"], "in": "query", "name": "order", "type": "string" @@ -15009,11 +14900,7 @@ }, { "description": "If not provided, results are sorted by best match.", - "enum": [ - "stars", - "forks", - "updated" - ], + "enum": ["stars", "forks", "updated"], "in": "query", "name": "sort", "type": "string" @@ -15081,10 +14968,7 @@ { "default": "desc", "description": "The sort field. if sort param is provided. Can be either asc or desc.", - "enum": [ - "desc", - "asc" - ], + "enum": ["desc", "asc"], "in": "query", "name": "order", "type": "string" @@ -15098,11 +14982,7 @@ }, { "description": "If not provided, results are sorted by best match.", - "enum": [ - "followers", - "repositories", - "joined" - ], + "enum": ["followers", "repositories", "joined"], "in": "query", "name": "sort", "type": "string" @@ -16404,9 +16284,7 @@ "type": "string" } ], - "produces": [ - "application/vnd.github.v3" - ], + "produces": ["application/vnd.github.v3"], "responses": { "200": { "description": "OK", @@ -16834,13 +16712,7 @@ { "default": "all", "description": "Issues assigned to you / created by you / mentioning you / you're\nsubscribed to updates for / All issues the authenticated user can see\n", - "enum": [ - "assigned", - "created", - "mentioned", - "subscribed", - "all" - ], + "enum": ["assigned", "created", "mentioned", "subscribed", "all"], "in": "query", "name": "filter", "required": true, @@ -16848,10 +16720,7 @@ }, { "default": "open", - "enum": [ - "open", - "closed" - ], + "enum": ["open", "closed"], "in": "query", "name": "state", "required": true, @@ -16866,11 +16735,7 @@ }, { "default": "created", - "enum": [ - "created", - "updated", - "comments" - ], + "enum": ["created", "updated", "comments"], "in": "query", "name": "sort", "required": true, @@ -16878,10 +16743,7 @@ }, { "default": "desc", - "enum": [ - "asc", - "desc" - ], + "enum": ["asc", "desc"], "in": "query", "name": "direction", "required": true, @@ -17270,14 +17132,7 @@ "parameters": [ { "default": "all", - "enum": [ - "all", - "public", - "private", - "forks", - "sources", - "member" - ], + "enum": ["all", "public", "private", "forks", "sources", "member"], "in": "query", "name": "type", "type": "string" @@ -17417,10 +17272,7 @@ { "default": "created", "description": "", - "enum": [ - "created", - "updated" - ], + "enum": ["created", "updated"], "in": "query", "name": "sort", "type": "string" @@ -18754,14 +18606,7 @@ }, { "default": "all", - "enum": [ - "all", - "public", - "private", - "forks", - "sources", - "member" - ], + "enum": ["all", "public", "private", "forks", "sources", "member"], "in": "query", "name": "type", "type": "string" @@ -19020,10 +18865,7 @@ "type": "integer" }, "type": { - "enum": [ - "User", - "Organization" - ] + "enum": ["User", "Organization"] }, "updated_at": { "description": "ISO 8601 format: YYYY-MM-DDTHH:MM:SSZ", @@ -19082,9 +18924,7 @@ "type": "string" } }, - "required": [ - "name" - ], + "required": ["name"], "type": "object" }, "assets": { @@ -19105,10 +18945,7 @@ "type": "string" }, "encoding": { - "enum": [ - "utf-8", - "base64" - ] + "enum": ["utf-8", "base64"] }, "sha": { "type": "string" @@ -19270,9 +19107,7 @@ "type": "string" } }, - "required": [ - "body" - ], + "required": ["body"], "type": "object" }, "comments": { @@ -19514,10 +19349,7 @@ "type": "string" } }, - "required": [ - "sha", - "body" - ], + "required": ["sha", "body"], "type": "object" }, "commits": { @@ -20335,16 +20167,10 @@ "type": "string" }, "permission": { - "enum": [ - "pull", - "push", - "admin" - ] + "enum": ["pull", "push", "admin"] } }, - "required": [ - "name" - ], + "required": ["name"], "type": "object" }, "emailsPost": { @@ -20939,10 +20765,7 @@ "type": "integer" }, "state": { - "enum": [ - "open", - "closed" - ] + "enum": ["open", "closed"] }, "title": { "type": "string" @@ -20971,10 +20794,7 @@ "type": "object" }, "state": { - "enum": [ - "open", - "closed" - ] + "enum": ["open", "closed"] }, "title": { "type": "string" @@ -21070,10 +20890,7 @@ "type": "integer" }, "state": { - "enum": [ - "open", - "closed" - ] + "enum": ["open", "closed"] }, "title": { "type": "string" @@ -21102,10 +20919,7 @@ "type": "object" }, "state": { - "enum": [ - "open", - "closed" - ] + "enum": ["open", "closed"] }, "title": { "type": "string" @@ -21477,10 +21291,7 @@ "type": "integer" }, "state": { - "enum": [ - "open", - "closed" - ] + "enum": ["open", "closed"] }, "title": { "type": "string" @@ -21594,11 +21405,7 @@ "type": "string" }, "permission": { - "enum": [ - "pull", - "push", - "admin" - ] + "enum": ["pull", "push", "admin"] }, "repo_names": { "items": { @@ -21607,9 +21414,7 @@ "type": "array" } }, - "required": [ - "name" - ], + "required": ["name"], "type": "object" }, "organization": { @@ -21793,9 +21598,7 @@ "type": "integer" } }, - "required": [ - "name" - ], + "required": ["name"], "type": "object" }, "pullRequest": { @@ -22176,10 +21979,7 @@ "type": "string" }, "state": { - "enum": [ - "open", - "closed" - ] + "enum": ["open", "closed"] }, "title": { "type": "string" @@ -23110,11 +22910,7 @@ "type": "string" } }, - "required": [ - "message", - "parents", - "tree" - ], + "required": ["message", "parents", "tree"], "type": "object" }, "repoEdit": { @@ -23579,11 +23375,7 @@ }, "type": { "description": "String of the type of the tagged object. Normally this is a commit but it can also be a tree or a blob.", - "enum": [ - "commit", - "tree", - "blob" - ] + "enum": ["commit", "tree", "blob"] }, "url": { "type": "string" @@ -23654,20 +23446,10 @@ }, "type": { "description": "String of the type of the object we’re tagging. Normally this is a commit but it can also be a tree or a blob.", - "enum": [ - "commit", - "tree", - "blob" - ] + "enum": ["commit", "tree", "blob"] } }, - "required": [ - "tag", - "message", - "object", - "type", - "tagger" - ], + "required": ["tag", "message", "object", "type", "tagger"], "type": "object" }, "tags": { @@ -23783,13 +23565,7 @@ "properties": { "mode": { "description": "One of 100644 for file (blob), 100755 for executable (blob), 040000 for subdirectory (tree), 160000 for submodule (commit) or 120000 for a blob that specifies the path of a symlink.", - "enum": [ - "100644", - "100755", - "040000", - "160000", - "120000" - ], + "enum": ["100644", "100755", "040000", "160000", "120000"], "type": "string" }, "path": { @@ -23803,11 +23579,7 @@ "type": "integer" }, "type": { - "enum": [ - "blob", - "tree", - "commit" - ], + "enum": ["blob", "tree", "commit"], "type": "string" }, "url": { diff --git a/tests/spec/routeTypes/schema.ts b/tests/spec/routeTypes/schema.ts index 9b897b0d..58c7dd10 100644 --- a/tests/spec/routeTypes/schema.ts +++ b/tests/spec/routeTypes/schema.ts @@ -1434,16 +1434,17 @@ export interface UserUpdate { export type Users = User[]; -export namespace emojis { +export namespace pathParams { /** * @description Lists all the emojis available to use on GitHub. - * - * @name EmojisList - * @request GET:/emojis + * @name PathParamsList + * @request GET:/path-params */ - export namespace EmojisList { + export namespace PathParamsList { + export type RequestParams = { petId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string; "X-Auth": string }; export type ResponseBody = Emojis; } } @@ -1451,13 +1452,14 @@ export namespace emojis { export namespace events { /** * @description List public events. - * * @name EventsList * @request GET:/events */ export namespace EventsList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Events; } } @@ -1465,13 +1467,14 @@ export namespace events { export namespace feeds { /** * @description List Feeds. GitHub provides several timeline resources in Atom format. The Feeds API lists all the feeds available to the authenticating user. - * * @name FeedsList * @request GET:/feeds */ export namespace FeedsList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Feeds; } } @@ -1479,205 +1482,223 @@ export namespace feeds { export namespace gists { /** * @description List the authenticated user's gists or if called anonymously, this will return all public gists. - * * @name GistsList * @request GET:/gists */ export namespace GistsList { + export type RequestParams = {}; export type RequestQuery = { since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gists; } /** * @description Create a gist. - * * @name GistsCreate * @request POST:/gists */ export namespace GistsCreate { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = PostGist; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gist; } /** * @description List all public gists. - * * @name PublicList * @request GET:/gists/public */ export namespace PublicList { + export type RequestParams = {}; export type RequestQuery = { since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gists; } /** * @description List the authenticated user's starred gists. - * * @name StarredList * @request GET:/gists/starred */ export namespace StarredList { + export type RequestParams = {}; export type RequestQuery = { since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gists; } /** * @description Delete a gist. - * * @name GistsDelete * @request DELETE:/gists/{id} */ export namespace GistsDelete { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single gist. - * * @name GistsDetail * @request GET:/gists/{id} */ export namespace GistsDetail { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gist; } /** * @description Edit a gist. - * * @name GistsPartialUpdate * @request PATCH:/gists/{id} */ export namespace GistsPartialUpdate { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = PatchGist; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gist; } /** * @description List comments on a gist. - * * @name CommentsDetail * @request GET:/gists/{id}/comments */ export namespace CommentsDetail { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Comments; } /** * @description Create a commen - * * @name CommentsCreate * @request POST:/gists/{id}/comments */ export namespace CommentsCreate { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = CommentBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Comment; } /** * @description Delete a comment. - * * @name CommentsDelete * @request DELETE:/gists/{id}/comments/{commentId} */ export namespace CommentsDelete { + export type RequestParams = { id: number; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single comment. - * * @name CommentsDetail2 * @request GET:/gists/{id}/comments/{commentId} * @originalName commentsDetail * @duplicate */ export namespace CommentsDetail2 { + export type RequestParams = { id: number; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Comment; } /** * @description Edit a comment. - * * @name CommentsPartialUpdate * @request PATCH:/gists/{id}/comments/{commentId} */ export namespace CommentsPartialUpdate { + export type RequestParams = { id: number; commentId: number }; export type RequestQuery = {}; export type RequestBody = Comment; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Comment; } /** * @description Fork a gist. - * * @name ForksCreate * @request POST:/gists/{id}/forks */ export namespace ForksCreate { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Unstar a gist. - * * @name StarDelete * @request DELETE:/gists/{id}/star */ export namespace StarDelete { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check if a gist is starred. - * * @name StarDetail * @request GET:/gists/{id}/star */ export namespace StarDetail { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Star a gist. - * * @name StarUpdate * @request PUT:/gists/{id}/star */ export namespace StarUpdate { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } } export namespace gitignore { /** * @description Listing available templates. List all templates available to pass as an option when creating a repository. - * * @name TemplatesList * @request GET:/gitignore/templates */ export namespace TemplatesList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gitignore; } /** * @description Get a single template. - * * @name TemplatesDetail * @request GET:/gitignore/templates/{language} */ export namespace TemplatesDetail { + export type RequestParams = { language: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = GitignoreLang; } } @@ -1685,11 +1706,11 @@ export namespace gitignore { export namespace issues { /** * @description List issues. List all issues across all the authenticated user's visible repositories. - * * @name IssuesList * @request GET:/issues */ export namespace IssuesList { + export type RequestParams = {}; export type RequestQuery = { filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; state: "open" | "closed"; @@ -1699,6 +1720,7 @@ export namespace issues { since?: string; }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Issues; } } @@ -1706,22 +1728,23 @@ export namespace issues { export namespace legacy { /** * @description Find issues by state and keyword. - * * @name IssuesSearchDetail * @request GET:/legacy/issues/search/{owner}/{repository}/{state}/{keyword} */ export namespace IssuesSearchDetail { + export type RequestParams = { keyword: string; state: "open" | "closed"; owner: string; repository: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchIssuesByKeyword; } /** * @description Find repositories by keyword. Note, this legacy method does not follow the v3 pagination pattern. This method returns up to 100 results per page and pages can be fetched using the start_page parameter. - * * @name ReposSearchDetail * @request GET:/legacy/repos/search/{keyword} */ export namespace ReposSearchDetail { + export type RequestParams = { keyword: string }; export type RequestQuery = { order?: "desc" | "asc"; language?: string; @@ -1729,28 +1752,31 @@ export namespace legacy { sort?: "updated" | "stars" | "forks"; }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchRepositoriesByKeyword; } /** * @description This API call is added for compatibility reasons only. - * * @name UserEmailDetail * @request GET:/legacy/user/email/{email} */ export namespace UserEmailDetail { + export type RequestParams = { email: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchUserByEmail; } /** * @description Find users by keyword. - * * @name UserSearchDetail * @request GET:/legacy/user/search/{keyword} */ export namespace UserSearchDetail { + export type RequestParams = { keyword: string }; export type RequestQuery = { order?: "desc" | "asc"; start_page?: string; sort?: "updated" | "stars" | "forks" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchUsersByKeyword; } } @@ -1758,38 +1784,41 @@ export namespace legacy { export namespace markdown { /** * @description Render an arbitrary Markdown document - * * @name MarkdownCreate * @request POST:/markdown */ export namespace MarkdownCreate { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = Markdown; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Render a Markdown document in raw mode - * * @name PostMarkdown * @request POST:/markdown/raw */ export namespace PostMarkdown { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } } export namespace meta { /** * @description This gives some information about GitHub.com, the service. - * * @name MetaList * @request GET:/meta */ export namespace MetaList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Meta; } } @@ -1797,13 +1826,14 @@ export namespace meta { export namespace networks { /** * @description List public events for a network of repositories. - * * @name EventsDetail * @request GET:/networks/{owner}/{repo}/events */ export namespace EventsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Events; } } @@ -1811,79 +1841,86 @@ export namespace networks { export namespace notifications { /** * @description List your notifications. List all notifications for the current user, grouped by repository. - * * @name NotificationsList * @request GET:/notifications */ export namespace NotificationsList { + export type RequestParams = {}; export type RequestQuery = { all?: boolean; participating?: boolean; since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Notifications; } /** * @description Mark as read. Marking a notification as "read" removes it from the default view on GitHub.com. - * * @name NotificationsUpdate * @request PUT:/notifications */ export namespace NotificationsUpdate { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = NotificationMarkRead; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description View a single thread. - * * @name ThreadsDetail * @request GET:/notifications/threads/{id} */ export namespace ThreadsDetail { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Notifications; } /** * @description Mark a thread as read - * * @name ThreadsPartialUpdate * @request PATCH:/notifications/threads/{id} */ export namespace ThreadsPartialUpdate { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Delete a Thread Subscription. - * * @name ThreadsSubscriptionDelete * @request DELETE:/notifications/threads/{id}/subscription */ export namespace ThreadsSubscriptionDelete { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a Thread Subscription. - * * @name ThreadsSubscriptionDetail * @request GET:/notifications/threads/{id}/subscription */ export namespace ThreadsSubscriptionDetail { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Subscription; } /** * @description Set a Thread Subscription. This lets you subscribe to a thread, or ignore it. Subscribing to a thread is unnecessary if the user is already subscribed to the repository. Ignoring a thread will mute all future notifications (until you comment or get @mentioned). - * * @name ThreadsSubscriptionUpdate * @request PUT:/notifications/threads/{id}/subscription */ export namespace ThreadsSubscriptionUpdate { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = PutSubscription; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Subscription; } } @@ -1891,44 +1928,47 @@ export namespace notifications { export namespace orgs { /** * @description Get an Organization. - * * @name OrgsDetail * @request GET:/orgs/{org} */ export namespace OrgsDetail { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Organization; } /** * @description Edit an Organization. - * * @name OrgsPartialUpdate * @request PATCH:/orgs/{org} */ export namespace OrgsPartialUpdate { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = PatchOrg; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Organization; } /** * @description List public events for an organization. - * * @name EventsDetail * @request GET:/orgs/{org}/events */ export namespace EventsDetail { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Events; } /** * @description List issues. List all issues for a given organization for the authenticated user. - * * @name IssuesDetail * @request GET:/orgs/{org}/issues */ export namespace IssuesDetail { + export type RequestParams = { org: string }; export type RequestQuery = { filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; state: "open" | "closed"; @@ -1938,131 +1978,143 @@ export namespace orgs { since?: string; }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Issues; } /** * @description Members list. List all users who are members of an organization. A member is a user tha belongs to at least 1 team in the organization. If the authenticated user is also an owner of this organization then both concealed and public members will be returned. If the requester is not an owner of the organization the query will be redirected to the public members list. - * * @name MembersDetail * @request GET:/orgs/{org}/members */ export namespace MembersDetail { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Remove a member. Removing a user from this list will remove them from all teams and they will no longer have any access to the organization's repositories. - * * @name MembersDelete * @request DELETE:/orgs/{org}/members/{username} */ export namespace MembersDelete { + export type RequestParams = { org: string; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check if a user is, publicly or privately, a member of the organization. - * * @name MembersDetail2 * @request GET:/orgs/{org}/members/{username} * @originalName membersDetail * @duplicate */ export namespace MembersDetail2 { + export type RequestParams = { org: string; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Public members list. Members of an organization can choose to have their membership publicized or not. - * * @name PublicMembersDetail * @request GET:/orgs/{org}/public_members */ export namespace PublicMembersDetail { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Conceal a user's membership. - * * @name PublicMembersDelete * @request DELETE:/orgs/{org}/public_members/{username} */ export namespace PublicMembersDelete { + export type RequestParams = { org: string; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check public membership. - * * @name PublicMembersDetail2 * @request GET:/orgs/{org}/public_members/{username} * @originalName publicMembersDetail * @duplicate */ export namespace PublicMembersDetail2 { + export type RequestParams = { org: string; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Publicize a user's membership. - * * @name PublicMembersUpdate * @request PUT:/orgs/{org}/public_members/{username} */ export namespace PublicMembersUpdate { + export type RequestParams = { org: string; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List repositories for the specified org. - * * @name ReposDetail * @request GET:/orgs/{org}/repos */ export namespace ReposDetail { + export type RequestParams = { org: string }; export type RequestQuery = { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repos; } /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. - * * @name ReposCreate * @request POST:/orgs/{org}/repos */ export namespace ReposCreate { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = PostRepo; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repos; } /** * @description List teams. - * * @name TeamsDetail * @request GET:/orgs/{org}/teams */ export namespace TeamsDetail { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Teams; } /** * @description Create team. In order to create a team, the authenticated user must be an owner of organization. - * * @name TeamsCreate * @request POST:/orgs/{org}/teams */ export namespace TeamsCreate { + export type RequestParams = { org: string }; export type RequestQuery = {}; export type RequestBody = OrgTeamsPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Team; } } @@ -2070,13 +2122,14 @@ export namespace orgs { export namespace rateLimit { /** * @description Get your current rate limit status Note: Accessing this endpoint does not count against your rate limit. - * * @name RateLimitList * @request GET:/rate_limit */ export namespace RateLimitList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = RateLimit; } } @@ -2084,621 +2137,675 @@ export namespace rateLimit { export namespace repos { /** * @description Delete a Repository. Deleting a repository requires admin access. If OAuth is used, the delete_repo scope is required. - * * @name ReposDelete * @request DELETE:/repos/{owner}/{repo} */ export namespace ReposDelete { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get repository. - * * @name ReposDetail * @request GET:/repos/{owner}/{repo} */ export namespace ReposDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repo; } /** * @description Edit repository. - * * @name ReposPartialUpdate * @request PATCH:/repos/{owner}/{repo} */ export namespace ReposPartialUpdate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = RepoEdit; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repo; } /** * @description List assignees. This call lists all the available assignees (owner + collaborators) to which issues may be assigned. - * * @name AssigneesDetail * @request GET:/repos/{owner}/{repo}/assignees */ export namespace AssigneesDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Assignees; } /** * @description Check assignee. You may also check to see if a particular user is an assignee for a repository. - * * @name AssigneesDetail2 * @request GET:/repos/{owner}/{repo}/assignees/{assignee} * @originalName assigneesDetail * @duplicate */ export namespace AssigneesDetail2 { + export type RequestParams = { owner: string; repo: string; assignee: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get list of branches - * * @name BranchesDetail * @request GET:/repos/{owner}/{repo}/branches */ export namespace BranchesDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Branches; } /** * @description Get Branch - * * @name BranchesDetail2 * @request GET:/repos/{owner}/{repo}/branches/{branch} * @originalName branchesDetail * @duplicate */ export namespace BranchesDetail2 { + export type RequestParams = { owner: string; repo: string; branch: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Branch; } /** * @description List. When authenticating as an organization owner of an organization-owned repository, all organization owners are included in the list of collaborators. Otherwise, only users with access to the repository are returned in the collaborators list. - * * @name CollaboratorsDetail * @request GET:/repos/{owner}/{repo}/collaborators */ export namespace CollaboratorsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Remove collaborator. - * * @name CollaboratorsDelete * @request DELETE:/repos/{owner}/{repo}/collaborators/{user} */ export namespace CollaboratorsDelete { + export type RequestParams = { owner: string; repo: string; user: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check if user is a collaborator - * * @name CollaboratorsDetail2 * @request GET:/repos/{owner}/{repo}/collaborators/{user} * @originalName collaboratorsDetail * @duplicate */ export namespace CollaboratorsDetail2 { + export type RequestParams = { owner: string; repo: string; user: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Add collaborator. - * * @name CollaboratorsUpdate * @request PUT:/repos/{owner}/{repo}/collaborators/{user} */ export namespace CollaboratorsUpdate { + export type RequestParams = { owner: string; repo: string; user: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List commit comments for a repository. Comments are ordered by ascending ID. - * * @name CommentsDetail * @request GET:/repos/{owner}/{repo}/comments */ export namespace CommentsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = RepoComments; } /** * @description Delete a commit comment - * * @name CommentsDelete * @request DELETE:/repos/{owner}/{repo}/comments/{commentId} */ export namespace CommentsDelete { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single commit comment. - * * @name CommentsDetail2 * @request GET:/repos/{owner}/{repo}/comments/{commentId} * @originalName commentsDetail * @duplicate */ export namespace CommentsDetail2 { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CommitComment; } /** * @description Update a commit comment. - * * @name CommentsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/comments/{commentId} */ export namespace CommentsPartialUpdate { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = CommentBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CommitComment; } /** * @description List commits on a repository. - * * @name CommitsDetail * @request GET:/repos/{owner}/{repo}/commits */ export namespace CommitsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { since?: string; sha?: string; path?: string; author?: string; until?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Commits; } /** * @description Get the combined Status for a specific Ref The Combined status endpoint is currently available for developers to preview. During the preview period, the API may change without advance notice. Please see the blog post for full details. To access this endpoint during the preview period, you must provide a custom media type in the Accept header: application/vnd.github.she-hulk-preview+json - * * @name CommitsStatusDetail * @request GET:/repos/{owner}/{repo}/commits/{ref}/status */ export namespace CommitsStatusDetail { + export type RequestParams = { owner: string; repo: string; ref: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = RefStatus; } /** * @description Get a single commit. - * * @name CommitsDetail2 * @request GET:/repos/{owner}/{repo}/commits/{shaCode} * @originalName commitsDetail * @duplicate */ export namespace CommitsDetail2 { + export type RequestParams = { owner: string; repo: string; shaCode: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Commit; } /** * @description List comments for a single commitList comments for a single commit. - * * @name CommitsCommentsDetail * @request GET:/repos/{owner}/{repo}/commits/{shaCode}/comments */ export namespace CommitsCommentsDetail { + export type RequestParams = { owner: string; repo: string; shaCode: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = RepoComments; } /** * @description Create a commit comment. - * * @name CommitsCommentsCreate * @request POST:/repos/{owner}/{repo}/commits/{shaCode}/comments */ export namespace CommitsCommentsCreate { + export type RequestParams = { owner: string; repo: string; shaCode: string }; export type RequestQuery = {}; export type RequestBody = CommitCommentBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CommitComment; } /** * @description Compare two commits - * * @name CompareDetail * @request GET:/repos/{owner}/{repo}/compare/{baseId}...{headId} */ export namespace CompareDetail { + export type RequestParams = { owner: string; repo: string; baseId: string; headId: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CompareCommits; } /** * @description Delete a file. This method deletes a file in a repository. - * * @name ContentsDelete * @request DELETE:/repos/{owner}/{repo}/contents/{path} */ export namespace ContentsDelete { + export type RequestParams = { owner: string; repo: string; path: string }; export type RequestQuery = {}; export type RequestBody = DeleteFileBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = DeleteFile; } /** * @description Get contents. This method returns the contents of a file or directory in a repository. Files and symlinks support a custom media type for getting the raw content. Directories and submodules do not support custom media types. Note: This API supports files up to 1 megabyte in size. Here can be many outcomes. For details see "http://developer.github.com/v3/repos/contents/" - * * @name ContentsDetail * @request GET:/repos/{owner}/{repo}/contents/{path} */ export namespace ContentsDetail { + export type RequestParams = { owner: string; repo: string; path: string }; export type RequestQuery = { path?: string; ref?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = ContentsPath; } /** * @description Create a file. - * * @name ContentsUpdate * @request PUT:/repos/{owner}/{repo}/contents/{path} */ export namespace ContentsUpdate { + export type RequestParams = { owner: string; repo: string; path: string }; export type RequestQuery = {}; export type RequestBody = CreateFileBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CreateFile; } /** * @description Get list of contributors. - * * @name ContributorsDetail * @request GET:/repos/{owner}/{repo}/contributors */ export namespace ContributorsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { anon: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Users with pull access can view deployments for a repository - * * @name DeploymentsDetail * @request GET:/repos/{owner}/{repo}/deployments */ export namespace DeploymentsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = RepoDeployments; } /** * @description Users with push access can create a deployment for a given ref - * * @name DeploymentsCreate * @request POST:/repos/{owner}/{repo}/deployments */ export namespace DeploymentsCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = Deployment; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = DeploymentResp; } /** * @description Users with pull access can view deployment statuses for a deployment - * * @name DeploymentsStatusesDetail * @request GET:/repos/{owner}/{repo}/deployments/{id}/statuses */ export namespace DeploymentsStatusesDetail { + export type RequestParams = { owner: string; repo: string; id: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = DeploymentStatuses; } /** * @description Create a Deployment Status Users with push access can create deployment statuses for a given deployment: - * * @name DeploymentsStatusesCreate * @request POST:/repos/{owner}/{repo}/deployments/{id}/statuses */ export namespace DeploymentsStatusesCreate { + export type RequestParams = { owner: string; repo: string; id: number }; export type RequestQuery = {}; export type RequestBody = DeploymentStatusesCreate; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Deprecated. List downloads for a repository. - * * @name DownloadsDetail * @request GET:/repos/{owner}/{repo}/downloads */ export namespace DownloadsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Downloads; } /** * @description Deprecated. Delete a download. - * * @name DownloadsDelete * @request DELETE:/repos/{owner}/{repo}/downloads/{downloadId} */ export namespace DownloadsDelete { + export type RequestParams = { owner: string; repo: string; downloadId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Deprecated. Get a single download. - * * @name DownloadsDetail2 * @request GET:/repos/{owner}/{repo}/downloads/{downloadId} * @originalName downloadsDetail * @duplicate */ export namespace DownloadsDetail2 { + export type RequestParams = { owner: string; repo: string; downloadId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Download; } /** * @description Get list of repository events. - * * @name EventsDetail * @request GET:/repos/{owner}/{repo}/events */ export namespace EventsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Events; } /** * @description List forks. - * * @name ForksDetail * @request GET:/repos/{owner}/{repo}/forks */ export namespace ForksDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { sort?: "newes" | "oldes" | "watchers" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Forks; } /** * @description Create a fork. Forking a Repository happens asynchronously. Therefore, you may have to wai a short period before accessing the git objects. If this takes longer than 5 minutes, be sure to contact Support. - * * @name ForksCreate * @request POST:/repos/{owner}/{repo}/forks */ export namespace ForksCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = ForkBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repo; } /** * @description Create a Blob. - * * @name GitBlobsCreate * @request POST:/repos/{owner}/{repo}/git/blobs */ export namespace GitBlobsCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = Blob; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Blobs; } /** * @description Get a Blob. Since blobs can be any arbitrary binary data, the input and responses for the blob API takes an encoding parameter that can be either utf-8 or base64. If your data cannot be losslessly sent as a UTF-8 string, you can base64 encode it. - * * @name GitBlobsDetail * @request GET:/repos/{owner}/{repo}/git/blobs/{shaCode} */ export namespace GitBlobsDetail { + export type RequestParams = { owner: string; repo: string; shaCode: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Blob; } /** * @description Create a Commit. - * * @name GitCommitsCreate * @request POST:/repos/{owner}/{repo}/git/commits */ export namespace GitCommitsCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = RepoCommitBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = GitCommit; } /** * @description Get a Commit. - * * @name GitCommitsDetail * @request GET:/repos/{owner}/{repo}/git/commits/{shaCode} */ export namespace GitCommitsDetail { + export type RequestParams = { owner: string; repo: string; shaCode: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = RepoCommit; } /** * @description Get all References - * * @name GitRefsDetail * @request GET:/repos/{owner}/{repo}/git/refs */ export namespace GitRefsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Refs; } /** * @description Create a Reference - * * @name GitRefsCreate * @request POST:/repos/{owner}/{repo}/git/refs */ export namespace GitRefsCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = RefsBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = HeadBranch; } /** * @description Delete a Reference Example: Deleting a branch: DELETE /repos/octocat/Hello-World/git/refs/heads/feature-a Example: Deleting a tag: DELETE /repos/octocat/Hello-World/git/refs/tags/v1.0 - * * @name GitRefsDelete * @request DELETE:/repos/{owner}/{repo}/git/refs/{ref} */ export namespace GitRefsDelete { + export type RequestParams = { owner: string; repo: string; ref: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a Reference - * * @name GitRefsDetail2 * @request GET:/repos/{owner}/{repo}/git/refs/{ref} * @originalName gitRefsDetail * @duplicate */ export namespace GitRefsDetail2 { + export type RequestParams = { owner: string; repo: string; ref: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = HeadBranch; } /** * @description Update a Reference - * * @name GitRefsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/git/refs/{ref} */ export namespace GitRefsPartialUpdate { + export type RequestParams = { owner: string; repo: string; ref: string }; export type RequestQuery = {}; export type RequestBody = GitRefPatch; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = HeadBranch; } /** * @description Create a Tag Object. Note that creating a tag object does not create the reference that makes a tag in Git. If you want to create an annotated tag in Git, you have to do this call to create the tag object, and then create the refs/tags/[tag] reference. If you want to create a lightweight tag, you only have to create the tag reference - this call would be unnecessary. - * * @name GitTagsCreate * @request POST:/repos/{owner}/{repo}/git/tags */ export namespace GitTagsCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = TagBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Tag; } /** * @description Get a Tag. - * * @name GitTagsDetail * @request GET:/repos/{owner}/{repo}/git/tags/{shaCode} */ export namespace GitTagsDetail { + export type RequestParams = { owner: string; repo: string; shaCode: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Tag; } /** * @description Create a Tree. The tree creation API will take nested entries as well. If both a tree and a nested path modifying that tree are specified, it will overwrite the contents of that tree with the new path contents and write a new tree out. - * * @name GitTreesCreate * @request POST:/repos/{owner}/{repo}/git/trees */ export namespace GitTreesCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = Tree; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Trees; } /** * @description Get a Tree. - * * @name GitTreesDetail * @request GET:/repos/{owner}/{repo}/git/trees/{shaCode} */ export namespace GitTreesDetail { + export type RequestParams = { owner: string; repo: string; shaCode: string }; export type RequestQuery = { recursive?: number }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Tree; } /** * @description Get list of hooks. - * * @name HooksDetail * @request GET:/repos/{owner}/{repo}/hooks */ export namespace HooksDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Hook; } /** * @description Create a hook. - * * @name HooksCreate * @request POST:/repos/{owner}/{repo}/hooks */ export namespace HooksCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = HookBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Hook; } /** * @description Delete a hook. - * * @name HooksDelete * @request DELETE:/repos/{owner}/{repo}/hooks/{hookId} */ export namespace HooksDelete { + export type RequestParams = { owner: string; repo: string; hookId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get single hook. - * * @name HooksDetail2 * @request GET:/repos/{owner}/{repo}/hooks/{hookId} * @originalName hooksDetail * @duplicate */ export namespace HooksDetail2 { + export type RequestParams = { owner: string; repo: string; hookId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Hook; } /** * @description Edit a hook. - * * @name HooksPartialUpdate * @request PATCH:/repos/{owner}/{repo}/hooks/{hookId} */ export namespace HooksPartialUpdate { + export type RequestParams = { owner: string; repo: string; hookId: number }; export type RequestQuery = {}; export type RequestBody = HookBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Hook; } /** * @description Test a push hook. This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook is not subscribed to push events, the server will respond with 204 but no test POST will be generated. Note: Previously /repos/:owner/:repo/hooks/:id/tes - * * @name HooksTestsCreate * @request POST:/repos/{owner}/{repo}/hooks/{hookId}/tests */ export namespace HooksTestsCreate { + export type RequestParams = { owner: string; repo: string; hookId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List issues for a repository. - * * @name IssuesDetail * @request GET:/repos/{owner}/{repo}/issues */ export namespace IssuesDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; state: "open" | "closed"; @@ -2708,872 +2815,949 @@ export namespace repos { since?: string; }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Issues; } /** * @description Create an issue. Any user with pull access to a repository can create an issue. - * * @name IssuesCreate * @request POST:/repos/{owner}/{repo}/issues */ export namespace IssuesCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = Issue; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Issue; } /** * @description List comments in a repository. - * * @name IssuesCommentsDetail * @request GET:/repos/{owner}/{repo}/issues/comments */ export namespace IssuesCommentsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { direction?: string; sort?: "created" | "updated"; since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssuesComments; } /** * @description Delete a comment. - * * @name IssuesCommentsDelete * @request DELETE:/repos/{owner}/{repo}/issues/comments/{commentId} */ export namespace IssuesCommentsDelete { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single comment. - * * @name IssuesCommentsDetail2 * @request GET:/repos/{owner}/{repo}/issues/comments/{commentId} * @originalName issuesCommentsDetail * @duplicate */ export namespace IssuesCommentsDetail2 { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssuesComment; } /** * @description Edit a comment. - * * @name IssuesCommentsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/issues/comments/{commentId} */ export namespace IssuesCommentsPartialUpdate { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = CommentBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssuesComment; } /** * @description List issue events for a repository. - * * @name IssuesEventsDetail * @request GET:/repos/{owner}/{repo}/issues/events */ export namespace IssuesEventsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssueEvents; } /** * @description Get a single event. - * * @name IssuesEventsDetail2 * @request GET:/repos/{owner}/{repo}/issues/events/{eventId} * @originalName issuesEventsDetail * @duplicate */ export namespace IssuesEventsDetail2 { + export type RequestParams = { owner: string; repo: string; eventId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssueEvent; } /** * @description Get a single issue - * * @name IssuesDetail2 * @request GET:/repos/{owner}/{repo}/issues/{number} * @originalName issuesDetail * @duplicate */ export namespace IssuesDetail2 { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Issue; } /** * @description Edit an issue. Issue owners and users with push access can edit an issue. - * * @name IssuesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/issues/{number} */ export namespace IssuesPartialUpdate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = Issue; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Issue; } /** * @description List comments on an issue. - * * @name IssuesCommentsDetail3 * @request GET:/repos/{owner}/{repo}/issues/{number}/comments * @originalName issuesCommentsDetail * @duplicate */ export namespace IssuesCommentsDetail3 { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssuesComments; } /** * @description Create a comment. - * * @name IssuesCommentsCreate * @request POST:/repos/{owner}/{repo}/issues/{number}/comments */ export namespace IssuesCommentsCreate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = CommentBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssuesComment; } /** * @description List events for an issue. - * * @name IssuesEventsDetail3 * @request GET:/repos/{owner}/{repo}/issues/{number}/events * @originalName issuesEventsDetail * @duplicate */ export namespace IssuesEventsDetail3 { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssueEvents; } /** * @description Remove all labels from an issue. - * * @name IssuesLabelsDelete * @request DELETE:/repos/{owner}/{repo}/issues/{number}/labels */ export namespace IssuesLabelsDelete { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List labels on an issue. - * * @name IssuesLabelsDetail * @request GET:/repos/{owner}/{repo}/issues/{number}/labels */ export namespace IssuesLabelsDetail { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Labels; } /** * @description Add labels to an issue. - * * @name IssuesLabelsCreate * @request POST:/repos/{owner}/{repo}/issues/{number}/labels */ export namespace IssuesLabelsCreate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = EmailsPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Label; } /** * @description Replace all labels for an issue. Sending an empty array ([]) will remove all Labels from the Issue. - * * @name IssuesLabelsUpdate * @request PUT:/repos/{owner}/{repo}/issues/{number}/labels */ export namespace IssuesLabelsUpdate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = EmailsPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Label; } /** * @description Remove a label from an issue. - * * @name IssuesLabelsDelete2 * @request DELETE:/repos/{owner}/{repo}/issues/{number}/labels/{name} * @originalName issuesLabelsDelete * @duplicate */ export namespace IssuesLabelsDelete2 { + export type RequestParams = { owner: string; repo: string; number: number; name: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get list of keys. - * * @name KeysDetail * @request GET:/repos/{owner}/{repo}/keys */ export namespace KeysDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Keys; } /** * @description Create a key. - * * @name KeysCreate * @request POST:/repos/{owner}/{repo}/keys */ export namespace KeysCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = UserKeysPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = UserKeysKeyId; } /** * @description Delete a key. - * * @name KeysDelete * @request DELETE:/repos/{owner}/{repo}/keys/{keyId} */ export namespace KeysDelete { + export type RequestParams = { owner: string; repo: string; keyId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a key - * * @name KeysDetail2 * @request GET:/repos/{owner}/{repo}/keys/{keyId} * @originalName keysDetail * @duplicate */ export namespace KeysDetail2 { + export type RequestParams = { owner: string; repo: string; keyId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = UserKeysKeyId; } /** * @description List all labels for this repository. - * * @name LabelsDetail * @request GET:/repos/{owner}/{repo}/labels */ export namespace LabelsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Labels; } /** * @description Create a label. - * * @name LabelsCreate * @request POST:/repos/{owner}/{repo}/labels */ export namespace LabelsCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = EmailsPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Label; } /** * @description Delete a label. - * * @name LabelsDelete * @request DELETE:/repos/{owner}/{repo}/labels/{name} */ export namespace LabelsDelete { + export type RequestParams = { owner: string; repo: string; name: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single label. - * * @name LabelsDetail2 * @request GET:/repos/{owner}/{repo}/labels/{name} * @originalName labelsDetail * @duplicate */ export namespace LabelsDetail2 { + export type RequestParams = { owner: string; repo: string; name: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Label; } /** * @description Update a label. - * * @name LabelsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/labels/{name} */ export namespace LabelsPartialUpdate { + export type RequestParams = { owner: string; repo: string; name: string }; export type RequestQuery = {}; export type RequestBody = EmailsPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Label; } /** * @description List languages. List languages for the specified repository. The value on the right of a language is the number of bytes of code written in that language. - * * @name LanguagesDetail * @request GET:/repos/{owner}/{repo}/languages */ export namespace LanguagesDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Languages; } /** * @description Perform a merge. - * * @name MergesCreate * @request POST:/repos/{owner}/{repo}/merges */ export namespace MergesCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = MergesBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = MergesSuccessful; } /** * @description List milestones for a repository. - * * @name MilestonesDetail * @request GET:/repos/{owner}/{repo}/milestones */ export namespace MilestonesDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { state?: "open" | "closed"; direction?: string; sort?: "due_date" | "completeness" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Milestone; } /** * @description Create a milestone. - * * @name MilestonesCreate * @request POST:/repos/{owner}/{repo}/milestones */ export namespace MilestonesCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = MilestoneUpdate; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Milestone; } /** * @description Delete a milestone. - * * @name MilestonesDelete * @request DELETE:/repos/{owner}/{repo}/milestones/{number} */ export namespace MilestonesDelete { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single milestone. - * * @name MilestonesDetail2 * @request GET:/repos/{owner}/{repo}/milestones/{number} * @originalName milestonesDetail * @duplicate */ export namespace MilestonesDetail2 { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Milestone; } /** * @description Update a milestone. - * * @name MilestonesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/milestones/{number} */ export namespace MilestonesPartialUpdate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = MilestoneUpdate; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Milestone; } /** * @description Get labels for every issue in a milestone. - * * @name MilestonesLabelsDetail * @request GET:/repos/{owner}/{repo}/milestones/{number}/labels */ export namespace MilestonesLabelsDetail { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Labels; } /** * @description List your notifications in a repository List all notifications for the current user. - * * @name NotificationsDetail * @request GET:/repos/{owner}/{repo}/notifications */ export namespace NotificationsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { all?: boolean; participating?: boolean; since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Notifications; } /** * @description Mark notifications as read in a repository. Marking all notifications in a repository as "read" removes them from the default view on GitHub.com. - * * @name NotificationsUpdate * @request PUT:/repos/{owner}/{repo}/notifications */ export namespace NotificationsUpdate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = NotificationMarkRead; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List pull requests. - * * @name PullsDetail * @request GET:/repos/{owner}/{repo}/pulls */ export namespace PullsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { state?: "open" | "closed"; head?: string; base?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Pulls; } /** * @description Create a pull request. - * * @name PullsCreate * @request POST:/repos/{owner}/{repo}/pulls */ export namespace PullsCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = PullsPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Pulls; } /** * @description List comments in a repository. By default, Review Comments are ordered by ascending ID. - * * @name PullsCommentsDetail * @request GET:/repos/{owner}/{repo}/pulls/comments */ export namespace PullsCommentsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { direction?: string; sort?: "created" | "updated"; since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = IssuesComments; } /** * @description Delete a comment. - * * @name PullsCommentsDelete * @request DELETE:/repos/{owner}/{repo}/pulls/comments/{commentId} */ export namespace PullsCommentsDelete { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single comment. - * * @name PullsCommentsDetail2 * @request GET:/repos/{owner}/{repo}/pulls/comments/{commentId} * @originalName pullsCommentsDetail * @duplicate */ export namespace PullsCommentsDetail2 { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = PullsComment; } /** * @description Edit a comment. - * * @name PullsCommentsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/pulls/comments/{commentId} */ export namespace PullsCommentsPartialUpdate { + export type RequestParams = { owner: string; repo: string; commentId: number }; export type RequestQuery = {}; export type RequestBody = CommentBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = PullsComment; } /** * @description Get a single pull request. - * * @name PullsDetail2 * @request GET:/repos/{owner}/{repo}/pulls/{number} * @originalName pullsDetail * @duplicate */ export namespace PullsDetail2 { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = PullRequest; } /** * @description Update a pull request. - * * @name PullsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/pulls/{number} */ export namespace PullsPartialUpdate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = PullUpdate; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repo; } /** * @description List comments on a pull request. - * * @name PullsCommentsDetail3 * @request GET:/repos/{owner}/{repo}/pulls/{number}/comments * @originalName pullsCommentsDetail * @duplicate */ export namespace PullsCommentsDetail3 { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = PullsComment; } /** * @description Create a comment. #TODO Alternative input ( http://developer.github.com/v3/pulls/comments/ ) description: | Alternative Input. Instead of passing commit_id, path, and position you can reply to an existing Pull Request Comment like this: body Required string in_reply_to Required number - Comment id to reply to. - * * @name PullsCommentsCreate * @request POST:/repos/{owner}/{repo}/pulls/{number}/comments */ export namespace PullsCommentsCreate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = PullsCommentPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = PullsComment; } /** * @description List commits on a pull request. - * * @name PullsCommitsDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/commits */ export namespace PullsCommitsDetail { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Commits; } /** * @description List pull requests files. - * * @name PullsFilesDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/files */ export namespace PullsFilesDetail { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Pulls; } /** * @description Get if a pull request has been merged. - * * @name PullsMergeDetail * @request GET:/repos/{owner}/{repo}/pulls/{number}/merge */ export namespace PullsMergeDetail { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Merge a pull request (Merge Button's) - * * @name PullsMergeUpdate * @request PUT:/repos/{owner}/{repo}/pulls/{number}/merge */ export namespace PullsMergeUpdate { + export type RequestParams = { owner: string; repo: string; number: number }; export type RequestQuery = {}; export type RequestBody = MergePullBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Merge; } /** * @description Get the README. This method returns the preferred README for a repository. - * * @name ReadmeDetail * @request GET:/repos/{owner}/{repo}/readme */ export namespace ReadmeDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = { ref?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = ContentsPath; } /** * @description Users with push access to the repository will receive all releases (i.e., published releases and draft releases). Users with pull access will receive published releases only - * * @name ReleasesDetail * @request GET:/repos/{owner}/{repo}/releases */ export namespace ReleasesDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Releases; } /** * @description Create a release Users with push access to the repository can create a release. - * * @name ReleasesCreate * @request POST:/repos/{owner}/{repo}/releases */ export namespace ReleasesCreate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = ReleaseCreate; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Release; } /** * @description Delete a release asset - * * @name ReleasesAssetsDelete * @request DELETE:/repos/{owner}/{repo}/releases/assets/{id} */ export namespace ReleasesAssetsDelete { + export type RequestParams = { owner: string; repo: string; id: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single release asset - * * @name ReleasesAssetsDetail * @request GET:/repos/{owner}/{repo}/releases/assets/{id} */ export namespace ReleasesAssetsDetail { + export type RequestParams = { owner: string; repo: string; id: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Asset; } /** * @description Edit a release asset Users with push access to the repository can edit a release asset. - * * @name ReleasesAssetsPartialUpdate * @request PATCH:/repos/{owner}/{repo}/releases/assets/{id} */ export namespace ReleasesAssetsPartialUpdate { + export type RequestParams = { owner: string; repo: string; id: string }; export type RequestQuery = {}; export type RequestBody = AssetPatch; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Asset; } /** * @description Users with push access to the repository can delete a release. - * * @name ReleasesDelete * @request DELETE:/repos/{owner}/{repo}/releases/{id} */ export namespace ReleasesDelete { + export type RequestParams = { owner: string; repo: string; id: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single release - * * @name ReleasesDetail2 * @request GET:/repos/{owner}/{repo}/releases/{id} * @originalName releasesDetail * @duplicate */ export namespace ReleasesDetail2 { + export type RequestParams = { owner: string; repo: string; id: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Release; } /** * @description Users with push access to the repository can edit a release - * * @name ReleasesPartialUpdate * @request PATCH:/repos/{owner}/{repo}/releases/{id} */ export namespace ReleasesPartialUpdate { + export type RequestParams = { owner: string; repo: string; id: string }; export type RequestQuery = {}; export type RequestBody = ReleaseCreate; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Release; } /** * @description List assets for a release - * * @name ReleasesAssetsDetail2 * @request GET:/repos/{owner}/{repo}/releases/{id}/assets * @originalName releasesAssetsDetail * @duplicate */ export namespace ReleasesAssetsDetail2 { + export type RequestParams = { owner: string; repo: string; id: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Assets; } /** * @description List Stargazers. - * * @name StargazersDetail * @request GET:/repos/{owner}/{repo}/stargazers */ export namespace StargazersDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Get the number of additions and deletions per week. Returns a weekly aggregate of the number of additions and deletions pushed to a repository. - * * @name StatsCodeFrequencyDetail * @request GET:/repos/{owner}/{repo}/stats/code_frequency */ export namespace StatsCodeFrequencyDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CodeFrequencyStats; } /** * @description Get the last year of commit activity data. Returns the last year of commit activity grouped by week. The days array is a group of commits per day, starting on Sunday. - * * @name StatsCommitActivityDetail * @request GET:/repos/{owner}/{repo}/stats/commit_activity */ export namespace StatsCommitActivityDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CommitActivityStats; } /** * @description Get contributors list with additions, deletions, and commit counts. - * * @name StatsContributorsDetail * @request GET:/repos/{owner}/{repo}/stats/contributors */ export namespace StatsContributorsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = ContributorsStats; } /** * @description Get the weekly commit count for the repo owner and everyone else. - * * @name StatsParticipationDetail * @request GET:/repos/{owner}/{repo}/stats/participation */ export namespace StatsParticipationDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = ParticipationStats; } /** * @description Get the number of commits per hour in each day. Each array contains the day number, hour number, and number of commits 0-6 Sunday - Saturday 0-23 Hour of day Number of commits For example, [2, 14, 25] indicates that there were 25 total commits, during the 2.00pm hour on Tuesdays. All times are based on the time zone of individual commits. - * * @name StatsPunchCardDetail * @request GET:/repos/{owner}/{repo}/stats/punch_card */ export namespace StatsPunchCardDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = CodeFrequencyStats; } /** * @description List Statuses for a specific Ref. - * * @name StatusesDetail * @request GET:/repos/{owner}/{repo}/statuses/{ref} */ export namespace StatusesDetail { + export type RequestParams = { owner: string; repo: string; ref: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Ref; } /** * @description Create a Status. - * * @name StatusesCreate * @request POST:/repos/{owner}/{repo}/statuses/{ref} */ export namespace StatusesCreate { + export type RequestParams = { owner: string; repo: string; ref: string }; export type RequestQuery = {}; export type RequestBody = HeadBranch; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Ref; } /** * @description List watchers. - * * @name SubscribersDetail * @request GET:/repos/{owner}/{repo}/subscribers */ export namespace SubscribersDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Delete a Repository Subscription. - * * @name SubscriptionDelete * @request DELETE:/repos/{owner}/{repo}/subscription */ export namespace SubscriptionDelete { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a Repository Subscription. - * * @name SubscriptionDetail * @request GET:/repos/{owner}/{repo}/subscription */ export namespace SubscriptionDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Subscription; } /** * @description Set a Repository Subscription - * * @name SubscriptionUpdate * @request PUT:/repos/{owner}/{repo}/subscription */ export namespace SubscriptionUpdate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = SubscriptionBody; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Subscription; } /** * @description Get list of tags. - * * @name TagsDetail * @request GET:/repos/{owner}/{repo}/tags */ export namespace TagsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Tags; } /** * @description Get list of teams - * * @name TeamsDetail * @request GET:/repos/{owner}/{repo}/teams */ export namespace TeamsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Teams; } /** * @description List Stargazers. New implementation. - * * @name WatchersDetail * @request GET:/repos/{owner}/{repo}/watchers */ export namespace WatchersDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Get archive link. This method will return a 302 to a URL to download a tarball or zipball archive for a repository. Please make sure your HTTP framework is configured to follow redirects or you will need to use the Location header to make a second GET request. Note: For private repositories, these links are temporary and expire quickly. - * * @name ReposDetail2 * @request GET:/repos/{owner}/{repo}/{archive_format}/{path} * @originalName reposDetail * @duplicate */ export namespace ReposDetail2 { + export type RequestParams = { owner: string; repo: string; archive_format: "tarball" | "zipball"; path: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } } @@ -3581,13 +3765,14 @@ export namespace repos { export namespace repositories { /** * @description List all public repositories. This provides a dump of every public repository, in the order that they were created. Note: Pagination is powered exclusively by the since parameter. is the Link header to get the URL for the next page of repositories. - * * @name RepositoriesList * @request GET:/repositories */ export namespace RepositoriesList { + export type RequestParams = {}; export type RequestQuery = { since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repos; } } @@ -3595,46 +3780,50 @@ export namespace repositories { export namespace search { /** * @description Search code. - * * @name CodeList * @request GET:/search/code */ export namespace CodeList { + export type RequestParams = {}; export type RequestQuery = { order?: "desc" | "asc"; q: string; sort?: "indexed" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchCode; } /** * @description Find issues by state and keyword. (This method returns up to 100 results per page.) - * * @name IssuesList * @request GET:/search/issues */ export namespace IssuesList { + export type RequestParams = {}; export type RequestQuery = { order?: "desc" | "asc"; q: string; sort?: "updated" | "created" | "comments" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchIssues; } /** * @description Search repositories. - * * @name RepositoriesList * @request GET:/search/repositories */ export namespace RepositoriesList { + export type RequestParams = {}; export type RequestQuery = { order?: "desc" | "asc"; q: string; sort?: "stars" | "forks" | "updated" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchRepositories; } /** * @description Search users. - * * @name UsersList * @request GET:/search/users */ export namespace UsersList { + export type RequestParams = {}; export type RequestQuery = { order?: "desc" | "asc"; q: string; sort?: "followers" | "repositories" | "joined" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = SearchUsers; } } @@ -3642,160 +3831,174 @@ export namespace search { export namespace teams { /** * @description Delete team. In order to delete a team, the authenticated user must be an owner of the org that the team is associated with. - * * @name TeamsDelete * @request DELETE:/teams/{teamId} */ export namespace TeamsDelete { + export type RequestParams = { teamId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get team. - * * @name TeamsDetail * @request GET:/teams/{teamId} */ export namespace TeamsDetail { + export type RequestParams = { teamId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Team; } /** * @description Edit team. In order to edit a team, the authenticated user must be an owner of the org that the team is associated with. - * * @name TeamsPartialUpdate * @request PATCH:/teams/{teamId} */ export namespace TeamsPartialUpdate { + export type RequestParams = { teamId: number }; export type RequestQuery = {}; export type RequestBody = EditTeam; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Team; } /** * @description List team members. In order to list members in a team, the authenticated user must be a member of the team. - * * @name MembersDetail * @request GET:/teams/{teamId}/members */ export namespace MembersDetail { + export type RequestParams = { teamId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description The "Remove team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Remove team membership API instead. It allows you to remove both active and pending memberships. Remove team member. In order to remove a user from a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. NOTE This does not delete the user, it just remove them from the team. - * * @name MembersDelete * @request DELETE:/teams/{teamId}/members/{username} */ export namespace MembersDelete { + export type RequestParams = { teamId: number; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description The "Get team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Get team membership API instead. It allows you to get both active and pending memberships. Get team member. In order to get if a user is a member of a team, the authenticated user mus be a member of the team. - * * @name MembersDetail2 * @request GET:/teams/{teamId}/members/{username} * @originalName membersDetail * @duplicate */ export namespace MembersDetail2 { + export type RequestParams = { teamId: number; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description The API (described below) is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Add team membership API instead. It allows you to invite new organization members to your teams. Add team member. In order to add a user to a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. - * * @name MembersUpdate * @request PUT:/teams/{teamId}/members/{username} */ export namespace MembersUpdate { + export type RequestParams = { teamId: number; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Remove team membership. In order to remove a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. NOTE: This does not delete the user, it just removes their membership from the team. - * * @name MembershipsDelete * @request DELETE:/teams/{teamId}/memberships/{username} */ export namespace MembershipsDelete { + export type RequestParams = { teamId: number; username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get team membership. In order to get a user's membership with a team, the authenticated user must be a member of the team or an owner of the team's organization. - * * @name MembershipsDetail * @request GET:/teams/{teamId}/memberships/{username} */ export namespace MembershipsDetail { + export type RequestParams = { teamId: number; username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = TeamMembership; } /** * @description Add team membership. In order to add a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. If the user is already a part of the team's organization (meaning they're on at least one other team in the organization), this endpoint will add the user to the team. If the user is completely unaffiliated with the team's organization (meaning they're on none of the organization's teams), this endpoint will send an invitation to the user via email. This newly-created membership will be in the 'pending' state until the user accepts the invitation, at which point the membership will transition to the 'active' state and the user will be added as a member of the team. - * * @name MembershipsUpdate * @request PUT:/teams/{teamId}/memberships/{username} */ export namespace MembershipsUpdate { + export type RequestParams = { teamId: number; username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = TeamMembership; } /** * @description List team repos - * * @name ReposDetail * @request GET:/teams/{teamId}/repos */ export namespace ReposDetail { + export type RequestParams = { teamId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = TeamRepos; } /** * @description In order to remove a repository from a team, the authenticated user must be an owner of the org that the team is associated with. NOTE: This does not delete the repository, it just removes it from the team. - * * @name ReposDelete * @request DELETE:/teams/{teamId}/repos/{owner}/{repo} */ export namespace ReposDelete { + export type RequestParams = { teamId: number; owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check if a team manages a repository - * * @name ReposDetail2 * @request GET:/teams/{teamId}/repos/{owner}/{repo} * @originalName reposDetail * @duplicate */ export namespace ReposDetail2 { + export type RequestParams = { teamId: number; owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } /** * @description In order to add a repository to a team, the authenticated user must be an owner of the org that the team is associated with. Also, the repository must be owned by the organization, or a direct fork of a repository owned by the organization. - * * @name ReposUpdate * @request PUT:/teams/{teamId}/repos/{owner}/{repo} */ export namespace ReposUpdate { + export type RequestParams = { teamId: number; owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } } @@ -3803,121 +4006,131 @@ export namespace teams { export namespace user { /** * @description Get the authenticated user. - * * @name UserList * @request GET:/user */ export namespace UserList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = User; } /** * @description Update the authenticated user. - * * @name UserPartialUpdate * @request PATCH:/user */ export namespace UserPartialUpdate { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = UserUpdate; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = User; } /** * @description Delete email address(es). You can include a single email address or an array of addresses. - * * @name EmailsDelete * @request DELETE:/user/emails */ export namespace EmailsDelete { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = UserEmails; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List email addresses for a user. In the final version of the API, this method will return an array of hashes with extended information for each email address indicating if the address has been verified and if it's primary email address for GitHub. Until API v3 is finalized, use the application/vnd.github.v3 media type to get other response format. - * * @name EmailsList * @request GET:/user/emails */ export namespace EmailsList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = UserEmails; } /** * @description Add email address(es). You can post a single email address or an array of addresses. - * * @name EmailsCreate * @request POST:/user/emails */ export namespace EmailsCreate { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = EmailsPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } /** * @description List the authenticated user's followers - * * @name FollowersList * @request GET:/user/followers */ export namespace FollowersList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description List who the authenticated user is following. - * * @name FollowingList * @request GET:/user/following */ export namespace FollowingList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Unfollow a user. Unfollowing a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. - * * @name FollowingDelete * @request DELETE:/user/following/{username} */ export namespace FollowingDelete { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check if you are following a user. - * * @name FollowingDetail * @request GET:/user/following/{username} */ export namespace FollowingDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Follow a user. Following a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. - * * @name FollowingUpdate * @request PUT:/user/following/{username} */ export namespace FollowingUpdate { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List issues. List all issues across owned and member repositories for the authenticated user. - * * @name IssuesList * @request GET:/user/issues */ export namespace IssuesList { + export type RequestParams = {}; export type RequestQuery = { filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; state: "open" | "closed"; @@ -3927,182 +4140,199 @@ export namespace user { since?: string; }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Issues; } /** * @description List your public keys. Lists the current user's keys. Management of public keys via the API requires that you are authenticated through basic auth, or OAuth with the 'user', 'write:public_key' scopes. - * * @name KeysList * @request GET:/user/keys */ export namespace KeysList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gitignore; } /** * @description Create a public key. - * * @name KeysCreate * @request POST:/user/keys */ export namespace KeysCreate { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = UserKeysPost; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = UserKeysKeyId; } /** * @description Delete a public key. Removes a public key. Requires that you are authenticated via Basic Auth or via OAuth with at least admin:public_key scope. - * * @name KeysDelete * @request DELETE:/user/keys/{keyId} */ export namespace KeysDelete { + export type RequestParams = { keyId: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Get a single public key. - * * @name KeysDetail * @request GET:/user/keys/{keyId} */ export namespace KeysDetail { + export type RequestParams = { keyId: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = UserKeysKeyId; } /** * @description List public and private organizations for the authenticated user. - * * @name OrgsList * @request GET:/user/orgs */ export namespace OrgsList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gitignore; } /** * @description List repositories for the authenticated user. Note that this does not include repositories owned by organizations which the user can access. You can lis user organizations and list organization repositories separately. - * * @name ReposList * @request GET:/user/repos */ export namespace ReposList { + export type RequestParams = {}; export type RequestQuery = { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repos; } /** * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. - * * @name ReposCreate * @request POST:/user/repos */ export namespace ReposCreate { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = PostRepo; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repos; } /** * @description List repositories being starred by the authenticated user. - * * @name StarredList * @request GET:/user/starred */ export namespace StarredList { + export type RequestParams = {}; export type RequestQuery = { direction?: string; sort?: "created" | "updated" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gitignore; } /** * @description Unstar a repository - * * @name StarredDelete * @request DELETE:/user/starred/{owner}/{repo} */ export namespace StarredDelete { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check if you are starring a repository. - * * @name StarredDetail * @request GET:/user/starred/{owner}/{repo} */ export namespace StarredDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Star a repository. - * * @name StarredUpdate * @request PUT:/user/starred/{owner}/{repo} */ export namespace StarredUpdate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List repositories being watched by the authenticated user. - * * @name SubscriptionsList * @request GET:/user/subscriptions */ export namespace SubscriptionsList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repos; } /** * @description Stop watching a repository - * * @name SubscriptionsDelete * @request DELETE:/user/subscriptions/{owner}/{repo} */ export namespace SubscriptionsDelete { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Check if you are watching a repository. - * * @name SubscriptionsDetail * @request GET:/user/subscriptions/{owner}/{repo} */ export namespace SubscriptionsDetail { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description Watch a repository. - * * @name SubscriptionsUpdate * @request PUT:/user/subscriptions/{owner}/{repo} */ export namespace SubscriptionsUpdate { + export type RequestParams = { owner: string; repo: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List all of the teams across all of the organizations to which the authenticated user belongs. This method requires user or repo scope when authenticating via OAuth. - * * @name TeamsList * @request GET:/user/teams */ export namespace TeamsList { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = TeamsList; } } @@ -4110,2753 +4340,170 @@ export namespace user { export namespace users { /** * @description Get all users. This provides a dump of every user, in the order that they signed up for GitHub. Note: Pagination is powered exclusively by the since parameter. Use the Link header to get the URL for the next page of users. - * * @name UsersList * @request GET:/users */ export namespace UsersList { + export type RequestParams = {}; export type RequestQuery = { since?: number }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Get a single user. - * * @name UsersDetail * @request GET:/users/{username} */ export namespace UsersDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = User; } /** * @description If you are authenticated as the given user, you will see your private events. Otherwise, you'll only see public events. - * * @name EventsDetail * @request GET:/users/{username}/events */ export namespace EventsDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } /** * @description This is the user's organization dashboard. You must be authenticated as the user to view this. - * * @name EventsOrgsDetail * @request GET:/users/{username}/events/orgs/{org} */ export namespace EventsOrgsDetail { + export type RequestParams = { username: string; org: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } /** * @description List a user's followers - * * @name FollowersDetail * @request GET:/users/{username}/followers */ export namespace FollowersDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Users; } /** * @description Check if one user follows another. - * * @name FollowingDetail * @request GET:/users/{username}/following/{targetUser} */ export namespace FollowingDetail { + export type RequestParams = { username: string; targetUser: string }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = { Accept?: string }; + export type ResponseBody = void; } /** * @description List a users gists. - * * @name GistsDetail * @request GET:/users/{username}/gists */ export namespace GistsDetail { + export type RequestParams = { username: string }; export type RequestQuery = { since?: string }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gists; } /** * @description List public keys for a user. Lists the verified public keys for a user. This is accessible by anyone. - * * @name KeysDetail * @request GET:/users/{username}/keys */ export namespace KeysDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gitignore; } /** * @description List all public organizations for a user. - * * @name OrgsDetail * @request GET:/users/{username}/orgs */ export namespace OrgsDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Gitignore; } /** * @description These are events that you'll only see public events. - * * @name ReceivedEventsDetail * @request GET:/users/{username}/received_events */ export namespace ReceivedEventsDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } /** * @description List public events that a user has received - * * @name ReceivedEventsPublicDetail * @request GET:/users/{username}/received_events/public */ export namespace ReceivedEventsPublicDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } /** * @description List public repositories for the specified user. - * * @name ReposDetail * @request GET:/users/{username}/repos */ export namespace ReposDetail { + export type RequestParams = { username: string }; export type RequestQuery = { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = Repos; } /** * @description List repositories being starred by a user. - * * @name StarredDetail * @request GET:/users/{username}/starred */ export namespace StarredDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } /** * @description List repositories being watched by a user. - * * @name SubscriptionsDetail * @request GET:/users/{username}/subscriptions */ export namespace SubscriptionsDetail { + export type RequestParams = { username: string }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = { Accept?: string }; export type ResponseBody = any; } } - -export type RequestParams = Omit & { - secure?: boolean; -}; - -export type RequestQueryParamsType = Record; - -interface ApiConfig { - baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; -} - -interface HttpResponse extends Response { - data: D; - error: E; -} - -enum BodyType { - Json, - FormData, - UrlEncoded, -} - -export class HttpClient { - public baseUrl: string = "https://api.github.com"; - private securityData: SecurityDataType = null as any; - private securityWorker: null | ApiConfig["securityWorker"] = null; - - private baseApiParams: RequestParams = { - credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, - redirect: "follow", - referrerPolicy: "no-referrer", - }; - - constructor(apiConfig: ApiConfig = {}) { - Object.assign(this, apiConfig); - } - - public setSecurityData = (data: SecurityDataType) => { - this.securityData = data; - }; - - private addQueryParam(query: RequestQueryParamsType, key: string) { - return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) - ); - } - - protected toQueryString(rawQuery?: RequestQueryParamsType): string { - const query = rawQuery || {}; - const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); - return keys - .map((key) => - typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) - : this.addQueryParam(query, key), - ) - .join("&"); - } - - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { - const queryString = this.toQueryString(rawQuery); - return queryString ? `?${queryString}` : ""; - } - - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { - data.append(key, input[key]); - return data; - }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), - }; - - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { - return { - ...this.baseApiParams, - ...params, - ...(securityParams || {}), - headers: { - ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), - }, - }; - } - - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); - }; - - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; - - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); - if (!response.ok) throw data; - return data; - }); - }; -} - -/** - * @title GitHub - * @version v3 - * @baseUrl https://api.github.com - * Powerful collaboration, code review, and code management for open source and private projects. - */ -export class Api extends HttpClient { - emojis = { - /** - * @description Lists all the emojis available to use on GitHub. - * - * @name EmojisList - * @request GET:/emojis - */ - emojisList: (params?: RequestParams) => this.request(`/emojis`, "GET", params), - }; - events = { - /** - * @description List public events. - * - * @name EventsList - * @request GET:/events - */ - eventsList: (params?: RequestParams) => this.request(`/events`, "GET", params), - }; - feeds = { - /** - * @description List Feeds. GitHub provides several timeline resources in Atom format. The Feeds API lists all the feeds available to the authenticating user. - * - * @name FeedsList - * @request GET:/feeds - */ - feedsList: (params?: RequestParams) => this.request(`/feeds`, "GET", params), - }; - gists = { - /** - * @description List the authenticated user's gists or if called anonymously, this will return all public gists. - * - * @name GistsList - * @request GET:/gists - */ - gistsList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/gists${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Create a gist. - * - * @name GistsCreate - * @request POST:/gists - */ - gistsCreate: (body: PostGist, params?: RequestParams) => - this.request(`/gists`, "POST", params, body, BodyType.Json), - - /** - * @description List all public gists. - * - * @name PublicList - * @request GET:/gists/public - */ - publicList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/gists/public${this.addQueryParams(query)}`, "GET", params), - - /** - * @description List the authenticated user's starred gists. - * - * @name StarredList - * @request GET:/gists/starred - */ - starredList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/gists/starred${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Delete a gist. - * - * @name GistsDelete - * @request DELETE:/gists/{id} - */ - gistsDelete: (id: number, params?: RequestParams) => this.request(`/gists/${id}`, "DELETE", params), - - /** - * @description Get a single gist. - * - * @name GistsDetail - * @request GET:/gists/{id} - */ - gistsDetail: (id: number, params?: RequestParams) => this.request(`/gists/${id}`, "GET", params), - - /** - * @description Edit a gist. - * - * @name GistsPartialUpdate - * @request PATCH:/gists/{id} - */ - gistsPartialUpdate: (id: number, body: PatchGist, params?: RequestParams) => - this.request(`/gists/${id}`, "PATCH", params, body, BodyType.Json), - - /** - * @description List comments on a gist. - * - * @name CommentsDetail - * @request GET:/gists/{id}/comments - */ - commentsDetail: (id: number, params?: RequestParams) => - this.request(`/gists/${id}/comments`, "GET", params), - - /** - * @description Create a commen - * - * @name CommentsCreate - * @request POST:/gists/{id}/comments - */ - commentsCreate: (id: number, body: CommentBody, params?: RequestParams) => - this.request(`/gists/${id}/comments`, "POST", params, body), - - /** - * @description Delete a comment. - * - * @name CommentsDelete - * @request DELETE:/gists/{id}/comments/{commentId} - */ - commentsDelete: (id: number, commentId: number, params?: RequestParams) => - this.request(`/gists/${id}/comments/${commentId}`, "DELETE", params), - - /** - * @description Get a single comment. - * - * @name CommentsDetail2 - * @request GET:/gists/{id}/comments/{commentId} - * @originalName commentsDetail - * @duplicate - */ - commentsDetail2: (id: number, commentId: number, params?: RequestParams) => - this.request(`/gists/${id}/comments/${commentId}`, "GET", params), - - /** - * @description Edit a comment. - * - * @name CommentsPartialUpdate - * @request PATCH:/gists/{id}/comments/{commentId} - */ - commentsPartialUpdate: (id: number, commentId: number, body: Comment, params?: RequestParams) => - this.request(`/gists/${id}/comments/${commentId}`, "PATCH", params, body, BodyType.Json), - - /** - * @description Fork a gist. - * - * @name ForksCreate - * @request POST:/gists/{id}/forks - */ - forksCreate: (id: number, params?: RequestParams) => this.request(`/gists/${id}/forks`, "POST", params), - - /** - * @description Unstar a gist. - * - * @name StarDelete - * @request DELETE:/gists/{id}/star - */ - starDelete: (id: number, params?: RequestParams) => this.request(`/gists/${id}/star`, "DELETE", params), - - /** - * @description Check if a gist is starred. - * - * @name StarDetail - * @request GET:/gists/{id}/star - */ - starDetail: (id: number, params?: RequestParams) => this.request(`/gists/${id}/star`, "GET", params), - - /** - * @description Star a gist. - * - * @name StarUpdate - * @request PUT:/gists/{id}/star - */ - starUpdate: (id: number, params?: RequestParams) => this.request(`/gists/${id}/star`, "PUT", params), - }; - gitignore = { - /** - * @description Listing available templates. List all templates available to pass as an option when creating a repository. - * - * @name TemplatesList - * @request GET:/gitignore/templates - */ - templatesList: (params?: RequestParams) => this.request(`/gitignore/templates`, "GET", params), - - /** - * @description Get a single template. - * - * @name TemplatesDetail - * @request GET:/gitignore/templates/{language} - */ - templatesDetail: (language: string, params?: RequestParams) => - this.request(`/gitignore/templates/${language}`, "GET", params), - }; - issues = { - /** - * @description List issues. List all issues across all the authenticated user's visible repositories. - * - * @name IssuesList - * @request GET:/issues - */ - issuesList: ( - query: { - filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; - state: "open" | "closed"; - labels: string; - sort: "created" | "updated" | "comments"; - direction: "asc" | "desc"; - since?: string; - }, - params?: RequestParams, - ) => this.request(`/issues${this.addQueryParams(query)}`, "GET", params), - }; - legacy = { - /** - * @description Find issues by state and keyword. - * - * @name IssuesSearchDetail - * @request GET:/legacy/issues/search/{owner}/{repository}/{state}/{keyword} - */ - issuesSearchDetail: ( - keyword: string, - state: "open" | "closed", - owner: string, - repository: string, - params?: RequestParams, - ) => - this.request( - `/legacy/issues/search/${owner}/${repository}/${state}/${keyword}`, - "GET", - params, - ), - - /** - * @description Find repositories by keyword. Note, this legacy method does not follow the v3 pagination pattern. This method returns up to 100 results per page and pages can be fetched using the start_page parameter. - * - * @name ReposSearchDetail - * @request GET:/legacy/repos/search/{keyword} - */ - reposSearchDetail: ( - keyword: string, - query?: { order?: "desc" | "asc"; language?: string; start_page?: string; sort?: "updated" | "stars" | "forks" }, - params?: RequestParams, - ) => - this.request( - `/legacy/repos/search/${keyword}${this.addQueryParams(query)}`, - "GET", - params, - ), - - /** - * @description This API call is added for compatibility reasons only. - * - * @name UserEmailDetail - * @request GET:/legacy/user/email/{email} - */ - userEmailDetail: (email: string, params?: RequestParams) => - this.request(`/legacy/user/email/${email}`, "GET", params), - - /** - * @description Find users by keyword. - * - * @name UserSearchDetail - * @request GET:/legacy/user/search/{keyword} - */ - userSearchDetail: ( - keyword: string, - query?: { order?: "desc" | "asc"; start_page?: string; sort?: "updated" | "stars" | "forks" }, - params?: RequestParams, - ) => - this.request( - `/legacy/user/search/${keyword}${this.addQueryParams(query)}`, - "GET", - params, - ), - }; - markdown = { - /** - * @description Render an arbitrary Markdown document - * - * @name MarkdownCreate - * @request POST:/markdown - */ - markdownCreate: (body: Markdown, params?: RequestParams) => - this.request(`/markdown`, "POST", params, body, BodyType.Json), - - /** - * @description Render a Markdown document in raw mode - * - * @name PostMarkdown - * @request POST:/markdown/raw - */ - postMarkdown: (params?: RequestParams) => this.request(`/markdown/raw`, "POST", params), - }; - meta = { - /** - * @description This gives some information about GitHub.com, the service. - * - * @name MetaList - * @request GET:/meta - */ - metaList: (params?: RequestParams) => this.request(`/meta`, "GET", params), - }; - networks = { - /** - * @description List public events for a network of repositories. - * - * @name EventsDetail - * @request GET:/networks/{owner}/{repo}/events - */ - eventsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/networks/${owner}/${repo}/events`, "GET", params), - }; - notifications = { - /** - * @description List your notifications. List all notifications for the current user, grouped by repository. - * - * @name NotificationsList - * @request GET:/notifications - */ - notificationsList: (query?: { all?: boolean; participating?: boolean; since?: string }, params?: RequestParams) => - this.request(`/notifications${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Mark as read. Marking a notification as "read" removes it from the default view on GitHub.com. - * - * @name NotificationsUpdate - * @request PUT:/notifications - */ - notificationsUpdate: (body: NotificationMarkRead, params?: RequestParams) => - this.request(`/notifications`, "PUT", params, body), - - /** - * @description View a single thread. - * - * @name ThreadsDetail - * @request GET:/notifications/threads/{id} - */ - threadsDetail: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}`, "GET", params), - - /** - * @description Mark a thread as read - * - * @name ThreadsPartialUpdate - * @request PATCH:/notifications/threads/{id} - */ - threadsPartialUpdate: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}`, "PATCH", params), - - /** - * @description Delete a Thread Subscription. - * - * @name ThreadsSubscriptionDelete - * @request DELETE:/notifications/threads/{id}/subscription - */ - threadsSubscriptionDelete: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}/subscription`, "DELETE", params), - - /** - * @description Get a Thread Subscription. - * - * @name ThreadsSubscriptionDetail - * @request GET:/notifications/threads/{id}/subscription - */ - threadsSubscriptionDetail: (id: number, params?: RequestParams) => - this.request(`/notifications/threads/${id}/subscription`, "GET", params), - - /** - * @description Set a Thread Subscription. This lets you subscribe to a thread, or ignore it. Subscribing to a thread is unnecessary if the user is already subscribed to the repository. Ignoring a thread will mute all future notifications (until you comment or get @mentioned). - * - * @name ThreadsSubscriptionUpdate - * @request PUT:/notifications/threads/{id}/subscription - */ - threadsSubscriptionUpdate: (id: number, body: PutSubscription, params?: RequestParams) => - this.request(`/notifications/threads/${id}/subscription`, "PUT", params, body, BodyType.Json), - }; - orgs = { - /** - * @description Get an Organization. - * - * @name OrgsDetail - * @request GET:/orgs/{org} - */ - orgsDetail: (org: string, params?: RequestParams) => this.request(`/orgs/${org}`, "GET", params), - - /** - * @description Edit an Organization. - * - * @name OrgsPartialUpdate - * @request PATCH:/orgs/{org} - */ - orgsPartialUpdate: (org: string, body: PatchOrg, params?: RequestParams) => - this.request(`/orgs/${org}`, "PATCH", params, body, BodyType.Json), - - /** - * @description List public events for an organization. - * - * @name EventsDetail - * @request GET:/orgs/{org}/events - */ - eventsDetail: (org: string, params?: RequestParams) => - this.request(`/orgs/${org}/events`, "GET", params), - - /** - * @description List issues. List all issues for a given organization for the authenticated user. - * - * @name IssuesDetail - * @request GET:/orgs/{org}/issues - */ - issuesDetail: ( - org: string, - query: { - filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; - state: "open" | "closed"; - labels: string; - sort: "created" | "updated" | "comments"; - direction: "asc" | "desc"; - since?: string; - }, - params?: RequestParams, - ) => this.request(`/orgs/${org}/issues${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Members list. List all users who are members of an organization. A member is a user tha belongs to at least 1 team in the organization. If the authenticated user is also an owner of this organization then both concealed and public members will be returned. If the requester is not an owner of the organization the query will be redirected to the public members list. - * - * @name MembersDetail - * @request GET:/orgs/{org}/members - */ - membersDetail: (org: string, params?: RequestParams) => - this.request(`/orgs/${org}/members`, "GET", params), - - /** - * @description Remove a member. Removing a user from this list will remove them from all teams and they will no longer have any access to the organization's repositories. - * - * @name MembersDelete - * @request DELETE:/orgs/{org}/members/{username} - */ - membersDelete: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/members/${username}`, "DELETE", params), - - /** - * @description Check if a user is, publicly or privately, a member of the organization. - * - * @name MembersDetail2 - * @request GET:/orgs/{org}/members/{username} - * @originalName membersDetail - * @duplicate - */ - membersDetail2: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/members/${username}`, "GET", params), - - /** - * @description Public members list. Members of an organization can choose to have their membership publicized or not. - * - * @name PublicMembersDetail - * @request GET:/orgs/{org}/public_members - */ - publicMembersDetail: (org: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members`, "GET", params), - - /** - * @description Conceal a user's membership. - * - * @name PublicMembersDelete - * @request DELETE:/orgs/{org}/public_members/{username} - */ - publicMembersDelete: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members/${username}`, "DELETE", params), - - /** - * @description Check public membership. - * - * @name PublicMembersDetail2 - * @request GET:/orgs/{org}/public_members/{username} - * @originalName publicMembersDetail - * @duplicate - */ - publicMembersDetail2: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members/${username}`, "GET", params), - - /** - * @description Publicize a user's membership. - * - * @name PublicMembersUpdate - * @request PUT:/orgs/{org}/public_members/{username} - */ - publicMembersUpdate: (org: string, username: string, params?: RequestParams) => - this.request(`/orgs/${org}/public_members/${username}`, "PUT", params), - - /** - * @description List repositories for the specified org. - * - * @name ReposDetail - * @request GET:/orgs/{org}/repos - */ - reposDetail: ( - org: string, - query?: { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }, - params?: RequestParams, - ) => this.request(`/orgs/${org}/repos${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. - * - * @name ReposCreate - * @request POST:/orgs/{org}/repos - */ - reposCreate: (org: string, body: PostRepo, params?: RequestParams) => - this.request(`/orgs/${org}/repos`, "POST", params, body), - - /** - * @description List teams. - * - * @name TeamsDetail - * @request GET:/orgs/{org}/teams - */ - teamsDetail: (org: string, params?: RequestParams) => this.request(`/orgs/${org}/teams`, "GET", params), - - /** - * @description Create team. In order to create a team, the authenticated user must be an owner of organization. - * - * @name TeamsCreate - * @request POST:/orgs/{org}/teams - */ - teamsCreate: (org: string, body: OrgTeamsPost, params?: RequestParams) => - this.request(`/orgs/${org}/teams`, "POST", params, body, BodyType.Json), - }; - rateLimit = { - /** - * @description Get your current rate limit status Note: Accessing this endpoint does not count against your rate limit. - * - * @name RateLimitList - * @request GET:/rate_limit - */ - rateLimitList: (params?: RequestParams) => this.request(`/rate_limit`, "GET", params), - }; - repos = { - /** - * @description Delete a Repository. Deleting a repository requires admin access. If OAuth is used, the delete_repo scope is required. - * - * @name ReposDelete - * @request DELETE:/repos/{owner}/{repo} - */ - reposDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}`, "DELETE", params), - - /** - * @description Get repository. - * - * @name ReposDetail - * @request GET:/repos/{owner}/{repo} - */ - reposDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}`, "GET", params), - - /** - * @description Edit repository. - * - * @name ReposPartialUpdate - * @request PATCH:/repos/{owner}/{repo} - */ - reposPartialUpdate: (owner: string, repo: string, body: RepoEdit, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}`, "PATCH", params, body, BodyType.Json), - - /** - * @description List assignees. This call lists all the available assignees (owner + collaborators) to which issues may be assigned. - * - * @name AssigneesDetail - * @request GET:/repos/{owner}/{repo}/assignees - */ - assigneesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/assignees`, "GET", params), - - /** - * @description Check assignee. You may also check to see if a particular user is an assignee for a repository. - * - * @name AssigneesDetail2 - * @request GET:/repos/{owner}/{repo}/assignees/{assignee} - * @originalName assigneesDetail - * @duplicate - */ - assigneesDetail2: (owner: string, repo: string, assignee: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/assignees/${assignee}`, "GET", params), - - /** - * @description Get list of branches - * - * @name BranchesDetail - * @request GET:/repos/{owner}/{repo}/branches - */ - branchesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/branches`, "GET", params), - - /** - * @description Get Branch - * - * @name BranchesDetail2 - * @request GET:/repos/{owner}/{repo}/branches/{branch} - * @originalName branchesDetail - * @duplicate - */ - branchesDetail2: (owner: string, repo: string, branch: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/branches/${branch}`, "GET", params), - - /** - * @description List. When authenticating as an organization owner of an organization-owned repository, all organization owners are included in the list of collaborators. Otherwise, only users with access to the repository are returned in the collaborators list. - * - * @name CollaboratorsDetail - * @request GET:/repos/{owner}/{repo}/collaborators - */ - collaboratorsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators`, "GET", params), - - /** - * @description Remove collaborator. - * - * @name CollaboratorsDelete - * @request DELETE:/repos/{owner}/{repo}/collaborators/{user} - */ - collaboratorsDelete: (owner: string, repo: string, user: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "DELETE", params), - - /** - * @description Check if user is a collaborator - * - * @name CollaboratorsDetail2 - * @request GET:/repos/{owner}/{repo}/collaborators/{user} - * @originalName collaboratorsDetail - * @duplicate - */ - collaboratorsDetail2: (owner: string, repo: string, user: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "GET", params), - - /** - * @description Add collaborator. - * - * @name CollaboratorsUpdate - * @request PUT:/repos/{owner}/{repo}/collaborators/{user} - */ - collaboratorsUpdate: (owner: string, repo: string, user: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/collaborators/${user}`, "PUT", params), - - /** - * @description List commit comments for a repository. Comments are ordered by ascending ID. - * - * @name CommentsDetail - * @request GET:/repos/{owner}/{repo}/comments - */ - commentsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/comments`, "GET", params), - - /** - * @description Delete a commit comment - * - * @name CommentsDelete - * @request DELETE:/repos/{owner}/{repo}/comments/{commentId} - */ - commentsDelete: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "DELETE", params), - - /** - * @description Get a single commit comment. - * - * @name CommentsDetail2 - * @request GET:/repos/{owner}/{repo}/comments/{commentId} - * @originalName commentsDetail - * @duplicate - */ - commentsDetail2: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "GET", params), - - /** - * @description Update a commit comment. - * - * @name CommentsPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/comments/{commentId} - */ - commentsPartialUpdate: ( - owner: string, - repo: string, - commentId: number, - body: CommentBody, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/comments/${commentId}`, "PATCH", params, body), - - /** - * @description List commits on a repository. - * - * @name CommitsDetail - * @request GET:/repos/{owner}/{repo}/commits - */ - commitsDetail: ( - owner: string, - repo: string, - query?: { since?: string; sha?: string; path?: string; author?: string; until?: string }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/commits${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Get the combined Status for a specific Ref The Combined status endpoint is currently available for developers to preview. During the preview period, the API may change without advance notice. Please see the blog post for full details. To access this endpoint during the preview period, you must provide a custom media type in the Accept header: application/vnd.github.she-hulk-preview+json - * - * @name CommitsStatusDetail - * @request GET:/repos/{owner}/{repo}/commits/{ref}/status - */ - commitsStatusDetail: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/commits/${ref}/status`, "GET", params), - - /** - * @description Get a single commit. - * - * @name CommitsDetail2 - * @request GET:/repos/{owner}/{repo}/commits/{shaCode} - * @originalName commitsDetail - * @duplicate - */ - commitsDetail2: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/commits/${shaCode}`, "GET", params), - - /** - * @description List comments for a single commitList comments for a single commit. - * - * @name CommitsCommentsDetail - * @request GET:/repos/{owner}/{repo}/commits/{shaCode}/comments - */ - commitsCommentsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/commits/${shaCode}/comments`, "GET", params), - - /** - * @description Create a commit comment. - * - * @name CommitsCommentsCreate - * @request POST:/repos/{owner}/{repo}/commits/{shaCode}/comments - */ - commitsCommentsCreate: ( - owner: string, - repo: string, - shaCode: string, - body: CommitCommentBody, - params?: RequestParams, - ) => - this.request( - `/repos/${owner}/${repo}/commits/${shaCode}/comments`, - "POST", - params, - body, - BodyType.Json, - ), - - /** - * @description Compare two commits - * - * @name CompareDetail - * @request GET:/repos/{owner}/{repo}/compare/{baseId}...{headId} - */ - compareDetail: (owner: string, repo: string, baseId: string, headId: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/compare/${baseId}...${headId}`, "GET", params), - - /** - * @description Delete a file. This method deletes a file in a repository. - * - * @name ContentsDelete - * @request DELETE:/repos/{owner}/{repo}/contents/{path} - */ - contentsDelete: (owner: string, repo: string, path: string, body: DeleteFileBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/contents/${path}`, "DELETE", params, body, BodyType.Json), - - /** - * @description Get contents. This method returns the contents of a file or directory in a repository. Files and symlinks support a custom media type for getting the raw content. Directories and submodules do not support custom media types. Note: This API supports files up to 1 megabyte in size. Here can be many outcomes. For details see "http://developer.github.com/v3/repos/contents/" - * - * @name ContentsDetail - * @request GET:/repos/{owner}/{repo}/contents/{path} - */ - contentsDetail: ( - owner: string, - repo: string, - path: string, - query?: { path?: string; ref?: string }, - params?: RequestParams, - ) => - this.request( - `/repos/${owner}/${repo}/contents/${path}${this.addQueryParams(query)}`, - "GET", - params, - ), - - /** - * @description Create a file. - * - * @name ContentsUpdate - * @request PUT:/repos/{owner}/{repo}/contents/{path} - */ - contentsUpdate: (owner: string, repo: string, path: string, body: CreateFileBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/contents/${path}`, "PUT", params, body, BodyType.Json), - - /** - * @description Get list of contributors. - * - * @name ContributorsDetail - * @request GET:/repos/{owner}/{repo}/contributors - */ - contributorsDetail: (owner: string, repo: string, query: { anon: string }, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/contributors${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Users with pull access can view deployments for a repository - * - * @name DeploymentsDetail - * @request GET:/repos/{owner}/{repo}/deployments - */ - deploymentsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/deployments`, "GET", params), - - /** - * @description Users with push access can create a deployment for a given ref - * - * @name DeploymentsCreate - * @request POST:/repos/{owner}/{repo}/deployments - */ - deploymentsCreate: (owner: string, repo: string, body: Deployment, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/deployments`, "POST", params, body, BodyType.Json), - - /** - * @description Users with pull access can view deployment statuses for a deployment - * - * @name DeploymentsStatusesDetail - * @request GET:/repos/{owner}/{repo}/deployments/{id}/statuses - */ - deploymentsStatusesDetail: (owner: string, repo: string, id: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/deployments/${id}/statuses`, "GET", params), - - /** - * @description Create a Deployment Status Users with push access can create deployment statuses for a given deployment: - * - * @name DeploymentsStatusesCreate - * @request POST:/repos/{owner}/{repo}/deployments/{id}/statuses - */ - deploymentsStatusesCreate: ( - owner: string, - repo: string, - id: number, - body: DeploymentStatusesCreate, - params?: RequestParams, - ) => - this.request(`/repos/${owner}/${repo}/deployments/${id}/statuses`, "POST", params, body, BodyType.Json), - - /** - * @description Deprecated. List downloads for a repository. - * - * @name DownloadsDetail - * @request GET:/repos/{owner}/{repo}/downloads - */ - downloadsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/downloads`, "GET", params), - - /** - * @description Deprecated. Delete a download. - * - * @name DownloadsDelete - * @request DELETE:/repos/{owner}/{repo}/downloads/{downloadId} - */ - downloadsDelete: (owner: string, repo: string, downloadId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/downloads/${downloadId}`, "DELETE", params), - - /** - * @description Deprecated. Get a single download. - * - * @name DownloadsDetail2 - * @request GET:/repos/{owner}/{repo}/downloads/{downloadId} - * @originalName downloadsDetail - * @duplicate - */ - downloadsDetail2: (owner: string, repo: string, downloadId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/downloads/${downloadId}`, "GET", params), - - /** - * @description Get list of repository events. - * - * @name EventsDetail - * @request GET:/repos/{owner}/{repo}/events - */ - eventsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/events`, "GET", params), - - /** - * @description List forks. - * - * @name ForksDetail - * @request GET:/repos/{owner}/{repo}/forks - */ - forksDetail: ( - owner: string, - repo: string, - query?: { sort?: "newes" | "oldes" | "watchers" }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/forks${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Create a fork. Forking a Repository happens asynchronously. Therefore, you may have to wai a short period before accessing the git objects. If this takes longer than 5 minutes, be sure to contact Support. - * - * @name ForksCreate - * @request POST:/repos/{owner}/{repo}/forks - */ - forksCreate: (owner: string, repo: string, body: ForkBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/forks`, "POST", params, body, BodyType.Json), - - /** - * @description Create a Blob. - * - * @name GitBlobsCreate - * @request POST:/repos/{owner}/{repo}/git/blobs - */ - gitBlobsCreate: (owner: string, repo: string, body: Blob, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/blobs`, "POST", params, body, BodyType.Json), - - /** - * @description Get a Blob. Since blobs can be any arbitrary binary data, the input and responses for the blob API takes an encoding parameter that can be either utf-8 or base64. If your data cannot be losslessly sent as a UTF-8 string, you can base64 encode it. - * - * @name GitBlobsDetail - * @request GET:/repos/{owner}/{repo}/git/blobs/{shaCode} - */ - gitBlobsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/blobs/${shaCode}`, "GET", params), - - /** - * @description Create a Commit. - * - * @name GitCommitsCreate - * @request POST:/repos/{owner}/{repo}/git/commits - */ - gitCommitsCreate: (owner: string, repo: string, body: RepoCommitBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/commits`, "POST", params, body, BodyType.Json), - - /** - * @description Get a Commit. - * - * @name GitCommitsDetail - * @request GET:/repos/{owner}/{repo}/git/commits/{shaCode} - */ - gitCommitsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/commits/${shaCode}`, "GET", params), - - /** - * @description Get all References - * - * @name GitRefsDetail - * @request GET:/repos/{owner}/{repo}/git/refs - */ - gitRefsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs`, "GET", params), - - /** - * @description Create a Reference - * - * @name GitRefsCreate - * @request POST:/repos/{owner}/{repo}/git/refs - */ - gitRefsCreate: (owner: string, repo: string, body: RefsBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs`, "POST", params, body, BodyType.Json), - - /** - * @description Delete a Reference Example: Deleting a branch: DELETE /repos/octocat/Hello-World/git/refs/heads/feature-a Example: Deleting a tag: DELETE /repos/octocat/Hello-World/git/refs/tags/v1.0 - * - * @name GitRefsDelete - * @request DELETE:/repos/{owner}/{repo}/git/refs/{ref} - */ - gitRefsDelete: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "DELETE", params), - - /** - * @description Get a Reference - * - * @name GitRefsDetail2 - * @request GET:/repos/{owner}/{repo}/git/refs/{ref} - * @originalName gitRefsDetail - * @duplicate - */ - gitRefsDetail2: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "GET", params), - - /** - * @description Update a Reference - * - * @name GitRefsPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/git/refs/{ref} - */ - gitRefsPartialUpdate: (owner: string, repo: string, ref: string, body: GitRefPatch, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/refs/${ref}`, "PATCH", params, body, BodyType.Json), - - /** - * @description Create a Tag Object. Note that creating a tag object does not create the reference that makes a tag in Git. If you want to create an annotated tag in Git, you have to do this call to create the tag object, and then create the refs/tags/[tag] reference. If you want to create a lightweight tag, you only have to create the tag reference - this call would be unnecessary. - * - * @name GitTagsCreate - * @request POST:/repos/{owner}/{repo}/git/tags - */ - gitTagsCreate: (owner: string, repo: string, body: TagBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/tags`, "POST", params, body, BodyType.Json), - - /** - * @description Get a Tag. - * - * @name GitTagsDetail - * @request GET:/repos/{owner}/{repo}/git/tags/{shaCode} - */ - gitTagsDetail: (owner: string, repo: string, shaCode: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/tags/${shaCode}`, "GET", params), - - /** - * @description Create a Tree. The tree creation API will take nested entries as well. If both a tree and a nested path modifying that tree are specified, it will overwrite the contents of that tree with the new path contents and write a new tree out. - * - * @name GitTreesCreate - * @request POST:/repos/{owner}/{repo}/git/trees - */ - gitTreesCreate: (owner: string, repo: string, body: Tree, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/git/trees`, "POST", params, body, BodyType.Json), - - /** - * @description Get a Tree. - * - * @name GitTreesDetail - * @request GET:/repos/{owner}/{repo}/git/trees/{shaCode} - */ - gitTreesDetail: ( - owner: string, - repo: string, - shaCode: string, - query?: { recursive?: number }, - params?: RequestParams, - ) => - this.request( - `/repos/${owner}/${repo}/git/trees/${shaCode}${this.addQueryParams(query)}`, - "GET", - params, - ), - - /** - * @description Get list of hooks. - * - * @name HooksDetail - * @request GET:/repos/{owner}/{repo}/hooks - */ - hooksDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks`, "GET", params), - - /** - * @description Create a hook. - * - * @name HooksCreate - * @request POST:/repos/{owner}/{repo}/hooks - */ - hooksCreate: (owner: string, repo: string, body: HookBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks`, "POST", params, body), - - /** - * @description Delete a hook. - * - * @name HooksDelete - * @request DELETE:/repos/{owner}/{repo}/hooks/{hookId} - */ - hooksDelete: (owner: string, repo: string, hookId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "DELETE", params), - - /** - * @description Get single hook. - * - * @name HooksDetail2 - * @request GET:/repos/{owner}/{repo}/hooks/{hookId} - * @originalName hooksDetail - * @duplicate - */ - hooksDetail2: (owner: string, repo: string, hookId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "GET", params), - - /** - * @description Edit a hook. - * - * @name HooksPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/hooks/{hookId} - */ - hooksPartialUpdate: (owner: string, repo: string, hookId: number, body: HookBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}`, "PATCH", params, body), - - /** - * @description Test a push hook. This will trigger the hook with the latest push to the current repository if the hook is subscribed to push events. If the hook is not subscribed to push events, the server will respond with 204 but no test POST will be generated. Note: Previously /repos/:owner/:repo/hooks/:id/tes - * - * @name HooksTestsCreate - * @request POST:/repos/{owner}/{repo}/hooks/{hookId}/tests - */ - hooksTestsCreate: (owner: string, repo: string, hookId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/hooks/${hookId}/tests`, "POST", params), - - /** - * @description List issues for a repository. - * - * @name IssuesDetail - * @request GET:/repos/{owner}/{repo}/issues - */ - issuesDetail: ( - owner: string, - repo: string, - query: { - filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; - state: "open" | "closed"; - labels: string; - sort: "created" | "updated" | "comments"; - direction: "asc" | "desc"; - since?: string; - }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/issues${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Create an issue. Any user with pull access to a repository can create an issue. - * - * @name IssuesCreate - * @request POST:/repos/{owner}/{repo}/issues - */ - issuesCreate: (owner: string, repo: string, body: Issue, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues`, "POST", params, body), - - /** - * @description List comments in a repository. - * - * @name IssuesCommentsDetail - * @request GET:/repos/{owner}/{repo}/issues/comments - */ - issuesCommentsDetail: ( - owner: string, - repo: string, - query?: { direction?: string; sort?: "created" | "updated"; since?: string }, - params?: RequestParams, - ) => - this.request( - `/repos/${owner}/${repo}/issues/comments${this.addQueryParams(query)}`, - "GET", - params, - ), - - /** - * @description Delete a comment. - * - * @name IssuesCommentsDelete - * @request DELETE:/repos/{owner}/{repo}/issues/comments/{commentId} - */ - issuesCommentsDelete: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "DELETE", params), - - /** - * @description Get a single comment. - * - * @name IssuesCommentsDetail2 - * @request GET:/repos/{owner}/{repo}/issues/comments/{commentId} - * @originalName issuesCommentsDetail - * @duplicate - */ - issuesCommentsDetail2: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "GET", params), - - /** - * @description Edit a comment. - * - * @name IssuesCommentsPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/issues/comments/{commentId} - */ - issuesCommentsPartialUpdate: ( - owner: string, - repo: string, - commentId: number, - body: CommentBody, - params?: RequestParams, - ) => - this.request(`/repos/${owner}/${repo}/issues/comments/${commentId}`, "PATCH", params, body), - - /** - * @description List issue events for a repository. - * - * @name IssuesEventsDetail - * @request GET:/repos/{owner}/{repo}/issues/events - */ - issuesEventsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/events`, "GET", params), - - /** - * @description Get a single event. - * - * @name IssuesEventsDetail2 - * @request GET:/repos/{owner}/{repo}/issues/events/{eventId} - * @originalName issuesEventsDetail - * @duplicate - */ - issuesEventsDetail2: (owner: string, repo: string, eventId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/events/${eventId}`, "GET", params), - - /** - * @description Get a single issue - * - * @name IssuesDetail2 - * @request GET:/repos/{owner}/{repo}/issues/{number} - * @originalName issuesDetail - * @duplicate - */ - issuesDetail2: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}`, "GET", params), - - /** - * @description Edit an issue. Issue owners and users with push access can edit an issue. - * - * @name IssuesPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/issues/{number} - */ - issuesPartialUpdate: (owner: string, repo: string, number: number, body: Issue, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}`, "PATCH", params, body), - - /** - * @description List comments on an issue. - * - * @name IssuesCommentsDetail3 - * @request GET:/repos/{owner}/{repo}/issues/{number}/comments - * @originalName issuesCommentsDetail - * @duplicate - */ - issuesCommentsDetail3: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/comments`, "GET", params), - - /** - * @description Create a comment. - * - * @name IssuesCommentsCreate - * @request POST:/repos/{owner}/{repo}/issues/{number}/comments - */ - issuesCommentsCreate: (owner: string, repo: string, number: number, body: CommentBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/comments`, "POST", params, body), - - /** - * @description List events for an issue. - * - * @name IssuesEventsDetail3 - * @request GET:/repos/{owner}/{repo}/issues/{number}/events - * @originalName issuesEventsDetail - * @duplicate - */ - issuesEventsDetail3: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/events`, "GET", params), - - /** - * @description Remove all labels from an issue. - * - * @name IssuesLabelsDelete - * @request DELETE:/repos/{owner}/{repo}/issues/{number}/labels - */ - issuesLabelsDelete: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "DELETE", params), - - /** - * @description List labels on an issue. - * - * @name IssuesLabelsDetail - * @request GET:/repos/{owner}/{repo}/issues/{number}/labels - */ - issuesLabelsDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "GET", params), - - /** - * @description Add labels to an issue. - * - * @name IssuesLabelsCreate - * @request POST:/repos/{owner}/{repo}/issues/{number}/labels - */ - issuesLabelsCreate: (owner: string, repo: string, number: number, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "POST", params, body), - - /** - * @description Replace all labels for an issue. Sending an empty array ([]) will remove all Labels from the Issue. - * - * @name IssuesLabelsUpdate - * @request PUT:/repos/{owner}/{repo}/issues/{number}/labels - */ - issuesLabelsUpdate: (owner: string, repo: string, number: number, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels`, "PUT", params, body), - - /** - * @description Remove a label from an issue. - * - * @name IssuesLabelsDelete2 - * @request DELETE:/repos/{owner}/{repo}/issues/{number}/labels/{name} - * @originalName issuesLabelsDelete - * @duplicate - */ - issuesLabelsDelete2: (owner: string, repo: string, number: number, name: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/issues/${number}/labels/${name}`, "DELETE", params), - - /** - * @description Get list of keys. - * - * @name KeysDetail - * @request GET:/repos/{owner}/{repo}/keys - */ - keysDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys`, "GET", params), - - /** - * @description Create a key. - * - * @name KeysCreate - * @request POST:/repos/{owner}/{repo}/keys - */ - keysCreate: (owner: string, repo: string, body: UserKeysPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys`, "POST", params, body), - - /** - * @description Delete a key. - * - * @name KeysDelete - * @request DELETE:/repos/{owner}/{repo}/keys/{keyId} - */ - keysDelete: (owner: string, repo: string, keyId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys/${keyId}`, "DELETE", params), - - /** - * @description Get a key - * - * @name KeysDetail2 - * @request GET:/repos/{owner}/{repo}/keys/{keyId} - * @originalName keysDetail - * @duplicate - */ - keysDetail2: (owner: string, repo: string, keyId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/keys/${keyId}`, "GET", params), - - /** - * @description List all labels for this repository. - * - * @name LabelsDetail - * @request GET:/repos/{owner}/{repo}/labels - */ - labelsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels`, "GET", params), - - /** - * @description Create a label. - * - * @name LabelsCreate - * @request POST:/repos/{owner}/{repo}/labels - */ - labelsCreate: (owner: string, repo: string, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels`, "POST", params, body), - - /** - * @description Delete a label. - * - * @name LabelsDelete - * @request DELETE:/repos/{owner}/{repo}/labels/{name} - */ - labelsDelete: (owner: string, repo: string, name: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "DELETE", params), - - /** - * @description Get a single label. - * - * @name LabelsDetail2 - * @request GET:/repos/{owner}/{repo}/labels/{name} - * @originalName labelsDetail - * @duplicate - */ - labelsDetail2: (owner: string, repo: string, name: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "GET", params), - - /** - * @description Update a label. - * - * @name LabelsPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/labels/{name} - */ - labelsPartialUpdate: (owner: string, repo: string, name: string, body: EmailsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/labels/${name}`, "PATCH", params, body), - - /** - * @description List languages. List languages for the specified repository. The value on the right of a language is the number of bytes of code written in that language. - * - * @name LanguagesDetail - * @request GET:/repos/{owner}/{repo}/languages - */ - languagesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/languages`, "GET", params), - - /** - * @description Perform a merge. - * - * @name MergesCreate - * @request POST:/repos/{owner}/{repo}/merges - */ - mergesCreate: (owner: string, repo: string, body: MergesBody, params?: RequestParams) => - this.request( - `/repos/${owner}/${repo}/merges`, - "POST", - params, - body, - BodyType.Json, - ), - - /** - * @description List milestones for a repository. - * - * @name MilestonesDetail - * @request GET:/repos/{owner}/{repo}/milestones - */ - milestonesDetail: ( - owner: string, - repo: string, - query?: { state?: "open" | "closed"; direction?: string; sort?: "due_date" | "completeness" }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/milestones${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Create a milestone. - * - * @name MilestonesCreate - * @request POST:/repos/{owner}/{repo}/milestones - */ - milestonesCreate: (owner: string, repo: string, body: MilestoneUpdate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones`, "POST", params, body), - - /** - * @description Delete a milestone. - * - * @name MilestonesDelete - * @request DELETE:/repos/{owner}/{repo}/milestones/{number} - */ - milestonesDelete: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones/${number}`, "DELETE", params), - - /** - * @description Get a single milestone. - * - * @name MilestonesDetail2 - * @request GET:/repos/{owner}/{repo}/milestones/{number} - * @originalName milestonesDetail - * @duplicate - */ - milestonesDetail2: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones/${number}`, "GET", params), - - /** - * @description Update a milestone. - * - * @name MilestonesPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/milestones/{number} - */ - milestonesPartialUpdate: ( - owner: string, - repo: string, - number: number, - body: MilestoneUpdate, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/milestones/${number}`, "PATCH", params, body), - - /** - * @description Get labels for every issue in a milestone. - * - * @name MilestonesLabelsDetail - * @request GET:/repos/{owner}/{repo}/milestones/{number}/labels - */ - milestonesLabelsDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/milestones/${number}/labels`, "GET", params), - - /** - * @description List your notifications in a repository List all notifications for the current user. - * - * @name NotificationsDetail - * @request GET:/repos/{owner}/{repo}/notifications - */ - notificationsDetail: ( - owner: string, - repo: string, - query?: { all?: boolean; participating?: boolean; since?: string }, - params?: RequestParams, - ) => - this.request( - `/repos/${owner}/${repo}/notifications${this.addQueryParams(query)}`, - "GET", - params, - ), - - /** - * @description Mark notifications as read in a repository. Marking all notifications in a repository as "read" removes them from the default view on GitHub.com. - * - * @name NotificationsUpdate - * @request PUT:/repos/{owner}/{repo}/notifications - */ - notificationsUpdate: (owner: string, repo: string, body: NotificationMarkRead, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/notifications`, "PUT", params, body), - - /** - * @description List pull requests. - * - * @name PullsDetail - * @request GET:/repos/{owner}/{repo}/pulls - */ - pullsDetail: ( - owner: string, - repo: string, - query?: { state?: "open" | "closed"; head?: string; base?: string }, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/pulls${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Create a pull request. - * - * @name PullsCreate - * @request POST:/repos/{owner}/{repo}/pulls - */ - pullsCreate: (owner: string, repo: string, body: PullsPost, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls`, "POST", params, body, BodyType.Json), - - /** - * @description List comments in a repository. By default, Review Comments are ordered by ascending ID. - * - * @name PullsCommentsDetail - * @request GET:/repos/{owner}/{repo}/pulls/comments - */ - pullsCommentsDetail: ( - owner: string, - repo: string, - query?: { direction?: string; sort?: "created" | "updated"; since?: string }, - params?: RequestParams, - ) => - this.request( - `/repos/${owner}/${repo}/pulls/comments${this.addQueryParams(query)}`, - "GET", - params, - ), - - /** - * @description Delete a comment. - * - * @name PullsCommentsDelete - * @request DELETE:/repos/{owner}/{repo}/pulls/comments/{commentId} - */ - pullsCommentsDelete: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "DELETE", params), - - /** - * @description Get a single comment. - * - * @name PullsCommentsDetail2 - * @request GET:/repos/{owner}/{repo}/pulls/comments/{commentId} - * @originalName pullsCommentsDetail - * @duplicate - */ - pullsCommentsDetail2: (owner: string, repo: string, commentId: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "GET", params), - - /** - * @description Edit a comment. - * - * @name PullsCommentsPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/pulls/comments/{commentId} - */ - pullsCommentsPartialUpdate: ( - owner: string, - repo: string, - commentId: number, - body: CommentBody, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/pulls/comments/${commentId}`, "PATCH", params, body), - - /** - * @description Get a single pull request. - * - * @name PullsDetail2 - * @request GET:/repos/{owner}/{repo}/pulls/{number} - * @originalName pullsDetail - * @duplicate - */ - pullsDetail2: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}`, "GET", params), - - /** - * @description Update a pull request. - * - * @name PullsPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/pulls/{number} - */ - pullsPartialUpdate: (owner: string, repo: string, number: number, body: PullUpdate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}`, "PATCH", params, body, BodyType.Json), - - /** - * @description List comments on a pull request. - * - * @name PullsCommentsDetail3 - * @request GET:/repos/{owner}/{repo}/pulls/{number}/comments - * @originalName pullsCommentsDetail - * @duplicate - */ - pullsCommentsDetail3: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/comments`, "GET", params), - - /** - * @description Create a comment. #TODO Alternative input ( http://developer.github.com/v3/pulls/comments/ ) description: | Alternative Input. Instead of passing commit_id, path, and position you can reply to an existing Pull Request Comment like this: body Required string in_reply_to Required number - Comment id to reply to. - * - * @name PullsCommentsCreate - * @request POST:/repos/{owner}/{repo}/pulls/{number}/comments - */ - pullsCommentsCreate: ( - owner: string, - repo: string, - number: number, - body: PullsCommentPost, - params?: RequestParams, - ) => - this.request( - `/repos/${owner}/${repo}/pulls/${number}/comments`, - "POST", - params, - body, - BodyType.Json, - ), - - /** - * @description List commits on a pull request. - * - * @name PullsCommitsDetail - * @request GET:/repos/{owner}/{repo}/pulls/{number}/commits - */ - pullsCommitsDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/commits`, "GET", params), - - /** - * @description List pull requests files. - * - * @name PullsFilesDetail - * @request GET:/repos/{owner}/{repo}/pulls/{number}/files - */ - pullsFilesDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/files`, "GET", params), - - /** - * @description Get if a pull request has been merged. - * - * @name PullsMergeDetail - * @request GET:/repos/{owner}/{repo}/pulls/{number}/merge - */ - pullsMergeDetail: (owner: string, repo: string, number: number, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/merge`, "GET", params), - - /** - * @description Merge a pull request (Merge Button's) - * - * @name PullsMergeUpdate - * @request PUT:/repos/{owner}/{repo}/pulls/{number}/merge - */ - pullsMergeUpdate: (owner: string, repo: string, number: number, body: MergePullBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/pulls/${number}/merge`, "PUT", params, body, BodyType.Json), - - /** - * @description Get the README. This method returns the preferred README for a repository. - * - * @name ReadmeDetail - * @request GET:/repos/{owner}/{repo}/readme - */ - readmeDetail: (owner: string, repo: string, query?: { ref?: string }, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/readme${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Users with push access to the repository will receive all releases (i.e., published releases and draft releases). Users with pull access will receive published releases only - * - * @name ReleasesDetail - * @request GET:/repos/{owner}/{repo}/releases - */ - releasesDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases`, "GET", params), - - /** - * @description Create a release Users with push access to the repository can create a release. - * - * @name ReleasesCreate - * @request POST:/repos/{owner}/{repo}/releases - */ - releasesCreate: (owner: string, repo: string, body: ReleaseCreate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases`, "POST", params, body), - - /** - * @description Delete a release asset - * - * @name ReleasesAssetsDelete - * @request DELETE:/repos/{owner}/{repo}/releases/assets/{id} - */ - releasesAssetsDelete: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "DELETE", params), - - /** - * @description Get a single release asset - * - * @name ReleasesAssetsDetail - * @request GET:/repos/{owner}/{repo}/releases/assets/{id} - */ - releasesAssetsDetail: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "GET", params), - - /** - * @description Edit a release asset Users with push access to the repository can edit a release asset. - * - * @name ReleasesAssetsPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/releases/assets/{id} - */ - releasesAssetsPartialUpdate: (owner: string, repo: string, id: string, body: AssetPatch, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/assets/${id}`, "PATCH", params, body, BodyType.Json), - - /** - * @description Users with push access to the repository can delete a release. - * - * @name ReleasesDelete - * @request DELETE:/repos/{owner}/{repo}/releases/{id} - */ - releasesDelete: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "DELETE", params), - - /** - * @description Get a single release - * - * @name ReleasesDetail2 - * @request GET:/repos/{owner}/{repo}/releases/{id} - * @originalName releasesDetail - * @duplicate - */ - releasesDetail2: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "GET", params), - - /** - * @description Users with push access to the repository can edit a release - * - * @name ReleasesPartialUpdate - * @request PATCH:/repos/{owner}/{repo}/releases/{id} - */ - releasesPartialUpdate: (owner: string, repo: string, id: string, body: ReleaseCreate, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}`, "PATCH", params, body), - - /** - * @description List assets for a release - * - * @name ReleasesAssetsDetail2 - * @request GET:/repos/{owner}/{repo}/releases/{id}/assets - * @originalName releasesAssetsDetail - * @duplicate - */ - releasesAssetsDetail2: (owner: string, repo: string, id: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/releases/${id}/assets`, "GET", params), - - /** - * @description List Stargazers. - * - * @name StargazersDetail - * @request GET:/repos/{owner}/{repo}/stargazers - */ - stargazersDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stargazers`, "GET", params), - - /** - * @description Get the number of additions and deletions per week. Returns a weekly aggregate of the number of additions and deletions pushed to a repository. - * - * @name StatsCodeFrequencyDetail - * @request GET:/repos/{owner}/{repo}/stats/code_frequency - */ - statsCodeFrequencyDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/code_frequency`, "GET", params), - - /** - * @description Get the last year of commit activity data. Returns the last year of commit activity grouped by week. The days array is a group of commits per day, starting on Sunday. - * - * @name StatsCommitActivityDetail - * @request GET:/repos/{owner}/{repo}/stats/commit_activity - */ - statsCommitActivityDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/commit_activity`, "GET", params), - - /** - * @description Get contributors list with additions, deletions, and commit counts. - * - * @name StatsContributorsDetail - * @request GET:/repos/{owner}/{repo}/stats/contributors - */ - statsContributorsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/contributors`, "GET", params), - - /** - * @description Get the weekly commit count for the repo owner and everyone else. - * - * @name StatsParticipationDetail - * @request GET:/repos/{owner}/{repo}/stats/participation - */ - statsParticipationDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/participation`, "GET", params), - - /** - * @description Get the number of commits per hour in each day. Each array contains the day number, hour number, and number of commits 0-6 Sunday - Saturday 0-23 Hour of day Number of commits For example, [2, 14, 25] indicates that there were 25 total commits, during the 2.00pm hour on Tuesdays. All times are based on the time zone of individual commits. - * - * @name StatsPunchCardDetail - * @request GET:/repos/{owner}/{repo}/stats/punch_card - */ - statsPunchCardDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/stats/punch_card`, "GET", params), - - /** - * @description List Statuses for a specific Ref. - * - * @name StatusesDetail - * @request GET:/repos/{owner}/{repo}/statuses/{ref} - */ - statusesDetail: (owner: string, repo: string, ref: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/statuses/${ref}`, "GET", params), - - /** - * @description Create a Status. - * - * @name StatusesCreate - * @request POST:/repos/{owner}/{repo}/statuses/{ref} - */ - statusesCreate: (owner: string, repo: string, ref: string, body: HeadBranch, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/statuses/${ref}`, "POST", params, body, BodyType.Json), - - /** - * @description List watchers. - * - * @name SubscribersDetail - * @request GET:/repos/{owner}/{repo}/subscribers - */ - subscribersDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscribers`, "GET", params), - - /** - * @description Delete a Repository Subscription. - * - * @name SubscriptionDelete - * @request DELETE:/repos/{owner}/{repo}/subscription - */ - subscriptionDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscription`, "DELETE", params), - - /** - * @description Get a Repository Subscription. - * - * @name SubscriptionDetail - * @request GET:/repos/{owner}/{repo}/subscription - */ - subscriptionDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscription`, "GET", params), - - /** - * @description Set a Repository Subscription - * - * @name SubscriptionUpdate - * @request PUT:/repos/{owner}/{repo}/subscription - */ - subscriptionUpdate: (owner: string, repo: string, body: SubscriptionBody, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/subscription`, "PUT", params, body, BodyType.Json), - - /** - * @description Get list of tags. - * - * @name TagsDetail - * @request GET:/repos/{owner}/{repo}/tags - */ - tagsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/tags`, "GET", params), - - /** - * @description Get list of teams - * - * @name TeamsDetail - * @request GET:/repos/{owner}/{repo}/teams - */ - teamsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/teams`, "GET", params), - - /** - * @description List Stargazers. New implementation. - * - * @name WatchersDetail - * @request GET:/repos/{owner}/{repo}/watchers - */ - watchersDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/repos/${owner}/${repo}/watchers`, "GET", params), - - /** - * @description Get archive link. This method will return a 302 to a URL to download a tarball or zipball archive for a repository. Please make sure your HTTP framework is configured to follow redirects or you will need to use the Location header to make a second GET request. Note: For private repositories, these links are temporary and expire quickly. - * - * @name ReposDetail2 - * @request GET:/repos/{owner}/{repo}/{archive_format}/{path} - * @originalName reposDetail - * @duplicate - */ - reposDetail2: ( - owner: string, - repo: string, - archive_format: "tarball" | "zipball", - path: string, - params?: RequestParams, - ) => this.request(`/repos/${owner}/${repo}/${archive_format}/${path}`, "GET", params), - }; - repositories = { - /** - * @description List all public repositories. This provides a dump of every public repository, in the order that they were created. Note: Pagination is powered exclusively by the since parameter. is the Link header to get the URL for the next page of repositories. - * - * @name RepositoriesList - * @request GET:/repositories - */ - repositoriesList: (query?: { since?: string }, params?: RequestParams) => - this.request(`/repositories${this.addQueryParams(query)}`, "GET", params), - }; - search = { - /** - * @description Search code. - * - * @name CodeList - * @request GET:/search/code - */ - codeList: (query: { order?: "desc" | "asc"; q: string; sort?: "indexed" }, params?: RequestParams) => - this.request(`/search/code${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Find issues by state and keyword. (This method returns up to 100 results per page.) - * - * @name IssuesList - * @request GET:/search/issues - */ - issuesList: ( - query: { order?: "desc" | "asc"; q: string; sort?: "updated" | "created" | "comments" }, - params?: RequestParams, - ) => this.request(`/search/issues${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Search repositories. - * - * @name RepositoriesList - * @request GET:/search/repositories - */ - repositoriesList: ( - query: { order?: "desc" | "asc"; q: string; sort?: "stars" | "forks" | "updated" }, - params?: RequestParams, - ) => this.request(`/search/repositories${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Search users. - * - * @name UsersList - * @request GET:/search/users - */ - usersList: ( - query: { order?: "desc" | "asc"; q: string; sort?: "followers" | "repositories" | "joined" }, - params?: RequestParams, - ) => this.request(`/search/users${this.addQueryParams(query)}`, "GET", params), - }; - teams = { - /** - * @description Delete team. In order to delete a team, the authenticated user must be an owner of the org that the team is associated with. - * - * @name TeamsDelete - * @request DELETE:/teams/{teamId} - */ - teamsDelete: (teamId: number, params?: RequestParams) => - this.request(`/teams/${teamId}`, "DELETE", params), - - /** - * @description Get team. - * - * @name TeamsDetail - * @request GET:/teams/{teamId} - */ - teamsDetail: (teamId: number, params?: RequestParams) => this.request(`/teams/${teamId}`, "GET", params), - - /** - * @description Edit team. In order to edit a team, the authenticated user must be an owner of the org that the team is associated with. - * - * @name TeamsPartialUpdate - * @request PATCH:/teams/{teamId} - */ - teamsPartialUpdate: (teamId: number, body: EditTeam, params?: RequestParams) => - this.request(`/teams/${teamId}`, "PATCH", params, body, BodyType.Json), - - /** - * @description List team members. In order to list members in a team, the authenticated user must be a member of the team. - * - * @name MembersDetail - * @request GET:/teams/{teamId}/members - */ - membersDetail: (teamId: number, params?: RequestParams) => - this.request(`/teams/${teamId}/members`, "GET", params), - - /** - * @description The "Remove team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Remove team membership API instead. It allows you to remove both active and pending memberships. Remove team member. In order to remove a user from a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. NOTE This does not delete the user, it just remove them from the team. - * - * @name MembersDelete - * @request DELETE:/teams/{teamId}/members/{username} - */ - membersDelete: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/members/${username}`, "DELETE", params), - - /** - * @description The "Get team member" API is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Get team membership API instead. It allows you to get both active and pending memberships. Get team member. In order to get if a user is a member of a team, the authenticated user mus be a member of the team. - * - * @name MembersDetail2 - * @request GET:/teams/{teamId}/members/{username} - * @originalName membersDetail - * @duplicate - */ - membersDetail2: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/members/${username}`, "GET", params), - - /** - * @description The API (described below) is deprecated and is scheduled for removal in the next major version of the API. We recommend using the Add team membership API instead. It allows you to invite new organization members to your teams. Add team member. In order to add a user to a team, the authenticated user must have 'admin' permissions to the team or be an owner of the org that the team is associated with. - * - * @name MembersUpdate - * @request PUT:/teams/{teamId}/members/{username} - */ - membersUpdate: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/members/${username}`, "PUT", params), - - /** - * @description Remove team membership. In order to remove a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. NOTE: This does not delete the user, it just removes their membership from the team. - * - * @name MembershipsDelete - * @request DELETE:/teams/{teamId}/memberships/{username} - */ - membershipsDelete: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/memberships/${username}`, "DELETE", params), - - /** - * @description Get team membership. In order to get a user's membership with a team, the authenticated user must be a member of the team or an owner of the team's organization. - * - * @name MembershipsDetail - * @request GET:/teams/{teamId}/memberships/{username} - */ - membershipsDetail: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/memberships/${username}`, "GET", params), - - /** - * @description Add team membership. In order to add a membership between a user and a team, the authenticated user must have 'admin' permissions to the team or be an owner of the organization that the team is associated with. If the user is already a part of the team's organization (meaning they're on at least one other team in the organization), this endpoint will add the user to the team. If the user is completely unaffiliated with the team's organization (meaning they're on none of the organization's teams), this endpoint will send an invitation to the user via email. This newly-created membership will be in the 'pending' state until the user accepts the invitation, at which point the membership will transition to the 'active' state and the user will be added as a member of the team. - * - * @name MembershipsUpdate - * @request PUT:/teams/{teamId}/memberships/{username} - */ - membershipsUpdate: (teamId: number, username: string, params?: RequestParams) => - this.request(`/teams/${teamId}/memberships/${username}`, "PUT", params), - - /** - * @description List team repos - * - * @name ReposDetail - * @request GET:/teams/{teamId}/repos - */ - reposDetail: (teamId: number, params?: RequestParams) => - this.request(`/teams/${teamId}/repos`, "GET", params), - - /** - * @description In order to remove a repository from a team, the authenticated user must be an owner of the org that the team is associated with. NOTE: This does not delete the repository, it just removes it from the team. - * - * @name ReposDelete - * @request DELETE:/teams/{teamId}/repos/{owner}/{repo} - */ - reposDelete: (teamId: number, owner: string, repo: string, params?: RequestParams) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "DELETE", params), - - /** - * @description Check if a team manages a repository - * - * @name ReposDetail2 - * @request GET:/teams/{teamId}/repos/{owner}/{repo} - * @originalName reposDetail - * @duplicate - */ - reposDetail2: (teamId: number, owner: string, repo: string, params?: RequestParams) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "GET", params), - - /** - * @description In order to add a repository to a team, the authenticated user must be an owner of the org that the team is associated with. Also, the repository must be owned by the organization, or a direct fork of a repository owned by the organization. - * - * @name ReposUpdate - * @request PUT:/teams/{teamId}/repos/{owner}/{repo} - */ - reposUpdate: (teamId: number, owner: string, repo: string, params?: RequestParams) => - this.request(`/teams/${teamId}/repos/${owner}/${repo}`, "PUT", params), - }; - user = { - /** - * @description Get the authenticated user. - * - * @name UserList - * @request GET:/user - */ - userList: (params?: RequestParams) => this.request(`/user`, "GET", params), - - /** - * @description Update the authenticated user. - * - * @name UserPartialUpdate - * @request PATCH:/user - */ - userPartialUpdate: (body: UserUpdate, params?: RequestParams) => - this.request(`/user`, "PATCH", params, body, BodyType.Json), - - /** - * @description Delete email address(es). You can include a single email address or an array of addresses. - * - * @name EmailsDelete - * @request DELETE:/user/emails - */ - emailsDelete: (body: UserEmails, params?: RequestParams) => - this.request(`/user/emails`, "DELETE", params, body, BodyType.Json), - - /** - * @description List email addresses for a user. In the final version of the API, this method will return an array of hashes with extended information for each email address indicating if the address has been verified and if it's primary email address for GitHub. Until API v3 is finalized, use the application/vnd.github.v3 media type to get other response format. - * - * @name EmailsList - * @request GET:/user/emails - */ - emailsList: (params?: RequestParams) => this.request(`/user/emails`, "GET", params), - - /** - * @description Add email address(es). You can post a single email address or an array of addresses. - * - * @name EmailsCreate - * @request POST:/user/emails - */ - emailsCreate: (body: EmailsPost, params?: RequestParams) => - this.request(`/user/emails`, "POST", params, body), - - /** - * @description List the authenticated user's followers - * - * @name FollowersList - * @request GET:/user/followers - */ - followersList: (params?: RequestParams) => this.request(`/user/followers`, "GET", params), - - /** - * @description List who the authenticated user is following. - * - * @name FollowingList - * @request GET:/user/following - */ - followingList: (params?: RequestParams) => this.request(`/user/following`, "GET", params), - - /** - * @description Unfollow a user. Unfollowing a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. - * - * @name FollowingDelete - * @request DELETE:/user/following/{username} - */ - followingDelete: (username: string, params?: RequestParams) => - this.request(`/user/following/${username}`, "DELETE", params), - - /** - * @description Check if you are following a user. - * - * @name FollowingDetail - * @request GET:/user/following/{username} - */ - followingDetail: (username: string, params?: RequestParams) => - this.request(`/user/following/${username}`, "GET", params), - - /** - * @description Follow a user. Following a user requires the user to be logged in and authenticated with basic auth or OAuth with the user:follow scope. - * - * @name FollowingUpdate - * @request PUT:/user/following/{username} - */ - followingUpdate: (username: string, params?: RequestParams) => - this.request(`/user/following/${username}`, "PUT", params), - - /** - * @description List issues. List all issues across owned and member repositories for the authenticated user. - * - * @name IssuesList - * @request GET:/user/issues - */ - issuesList: ( - query: { - filter: "assigned" | "created" | "mentioned" | "subscribed" | "all"; - state: "open" | "closed"; - labels: string; - sort: "created" | "updated" | "comments"; - direction: "asc" | "desc"; - since?: string; - }, - params?: RequestParams, - ) => this.request(`/user/issues${this.addQueryParams(query)}`, "GET", params), - - /** - * @description List your public keys. Lists the current user's keys. Management of public keys via the API requires that you are authenticated through basic auth, or OAuth with the 'user', 'write:public_key' scopes. - * - * @name KeysList - * @request GET:/user/keys - */ - keysList: (params?: RequestParams) => this.request(`/user/keys`, "GET", params), - - /** - * @description Create a public key. - * - * @name KeysCreate - * @request POST:/user/keys - */ - keysCreate: (body: UserKeysPost, params?: RequestParams) => - this.request(`/user/keys`, "POST", params, body), - - /** - * @description Delete a public key. Removes a public key. Requires that you are authenticated via Basic Auth or via OAuth with at least admin:public_key scope. - * - * @name KeysDelete - * @request DELETE:/user/keys/{keyId} - */ - keysDelete: (keyId: number, params?: RequestParams) => - this.request(`/user/keys/${keyId}`, "DELETE", params), - - /** - * @description Get a single public key. - * - * @name KeysDetail - * @request GET:/user/keys/{keyId} - */ - keysDetail: (keyId: number, params?: RequestParams) => - this.request(`/user/keys/${keyId}`, "GET", params), - - /** - * @description List public and private organizations for the authenticated user. - * - * @name OrgsList - * @request GET:/user/orgs - */ - orgsList: (params?: RequestParams) => this.request(`/user/orgs`, "GET", params), - - /** - * @description List repositories for the authenticated user. Note that this does not include repositories owned by organizations which the user can access. You can lis user organizations and list organization repositories separately. - * - * @name ReposList - * @request GET:/user/repos - */ - reposList: ( - query?: { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }, - params?: RequestParams, - ) => this.request(`/user/repos${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Create a new repository for the authenticated user. OAuth users must supply repo scope. - * - * @name ReposCreate - * @request POST:/user/repos - */ - reposCreate: (body: PostRepo, params?: RequestParams) => - this.request(`/user/repos`, "POST", params, body), - - /** - * @description List repositories being starred by the authenticated user. - * - * @name StarredList - * @request GET:/user/starred - */ - starredList: (query?: { direction?: string; sort?: "created" | "updated" }, params?: RequestParams) => - this.request(`/user/starred${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Unstar a repository - * - * @name StarredDelete - * @request DELETE:/user/starred/{owner}/{repo} - */ - starredDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/starred/${owner}/${repo}`, "DELETE", params), - - /** - * @description Check if you are starring a repository. - * - * @name StarredDetail - * @request GET:/user/starred/{owner}/{repo} - */ - starredDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/starred/${owner}/${repo}`, "GET", params), - - /** - * @description Star a repository. - * - * @name StarredUpdate - * @request PUT:/user/starred/{owner}/{repo} - */ - starredUpdate: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/starred/${owner}/${repo}`, "PUT", params), - - /** - * @description List repositories being watched by the authenticated user. - * - * @name SubscriptionsList - * @request GET:/user/subscriptions - */ - subscriptionsList: (params?: RequestParams) => this.request(`/user/subscriptions`, "GET", params), - - /** - * @description Stop watching a repository - * - * @name SubscriptionsDelete - * @request DELETE:/user/subscriptions/{owner}/{repo} - */ - subscriptionsDelete: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/subscriptions/${owner}/${repo}`, "DELETE", params), - - /** - * @description Check if you are watching a repository. - * - * @name SubscriptionsDetail - * @request GET:/user/subscriptions/{owner}/{repo} - */ - subscriptionsDetail: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/subscriptions/${owner}/${repo}`, "GET", params), - - /** - * @description Watch a repository. - * - * @name SubscriptionsUpdate - * @request PUT:/user/subscriptions/{owner}/{repo} - */ - subscriptionsUpdate: (owner: string, repo: string, params?: RequestParams) => - this.request(`/user/subscriptions/${owner}/${repo}`, "PUT", params), - - /** - * @description List all of the teams across all of the organizations to which the authenticated user belongs. This method requires user or repo scope when authenticating via OAuth. - * - * @name TeamsList - * @request GET:/user/teams - */ - teamsList: (params?: RequestParams) => this.request(`/user/teams`, "GET", params), - }; - users = { - /** - * @description Get all users. This provides a dump of every user, in the order that they signed up for GitHub. Note: Pagination is powered exclusively by the since parameter. Use the Link header to get the URL for the next page of users. - * - * @name UsersList - * @request GET:/users - */ - usersList: (query?: { since?: number }, params?: RequestParams) => - this.request(`/users${this.addQueryParams(query)}`, "GET", params), - - /** - * @description Get a single user. - * - * @name UsersDetail - * @request GET:/users/{username} - */ - usersDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}`, "GET", params), - - /** - * @description If you are authenticated as the given user, you will see your private events. Otherwise, you'll only see public events. - * - * @name EventsDetail - * @request GET:/users/{username}/events - */ - eventsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/events`, "GET", params), - - /** - * @description This is the user's organization dashboard. You must be authenticated as the user to view this. - * - * @name EventsOrgsDetail - * @request GET:/users/{username}/events/orgs/{org} - */ - eventsOrgsDetail: (username: string, org: string, params?: RequestParams) => - this.request(`/users/${username}/events/orgs/${org}`, "GET", params), - - /** - * @description List a user's followers - * - * @name FollowersDetail - * @request GET:/users/{username}/followers - */ - followersDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/followers`, "GET", params), - - /** - * @description Check if one user follows another. - * - * @name FollowingDetail - * @request GET:/users/{username}/following/{targetUser} - */ - followingDetail: (username: string, targetUser: string, params?: RequestParams) => - this.request(`/users/${username}/following/${targetUser}`, "GET", params), - - /** - * @description List a users gists. - * - * @name GistsDetail - * @request GET:/users/{username}/gists - */ - gistsDetail: (username: string, query?: { since?: string }, params?: RequestParams) => - this.request(`/users/${username}/gists${this.addQueryParams(query)}`, "GET", params), - - /** - * @description List public keys for a user. Lists the verified public keys for a user. This is accessible by anyone. - * - * @name KeysDetail - * @request GET:/users/{username}/keys - */ - keysDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/keys`, "GET", params), - - /** - * @description List all public organizations for a user. - * - * @name OrgsDetail - * @request GET:/users/{username}/orgs - */ - orgsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/orgs`, "GET", params), - - /** - * @description These are events that you'll only see public events. - * - * @name ReceivedEventsDetail - * @request GET:/users/{username}/received_events - */ - receivedEventsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/received_events`, "GET", params), - - /** - * @description List public events that a user has received - * - * @name ReceivedEventsPublicDetail - * @request GET:/users/{username}/received_events/public - */ - receivedEventsPublicDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/received_events/public`, "GET", params), - - /** - * @description List public repositories for the specified user. - * - * @name ReposDetail - * @request GET:/users/{username}/repos - */ - reposDetail: ( - username: string, - query?: { type?: "all" | "public" | "private" | "forks" | "sources" | "member" }, - params?: RequestParams, - ) => this.request(`/users/${username}/repos${this.addQueryParams(query)}`, "GET", params), - - /** - * @description List repositories being starred by a user. - * - * @name StarredDetail - * @request GET:/users/{username}/starred - */ - starredDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/starred`, "GET", params), - - /** - * @description List repositories being watched by a user. - * - * @name SubscriptionsDetail - * @request GET:/users/{username}/subscriptions - */ - subscriptionsDetail: (username: string, params?: RequestParams) => - this.request(`/users/${username}/subscriptions`, "GET", params), - }; -} diff --git a/tests/spec/routeTypes/test.js b/tests/spec/routeTypes/test.js index 9492fa59..6d31c76f 100644 --- a/tests/spec/routeTypes/test.js +++ b/tests/spec/routeTypes/test.js @@ -1,23 +1,26 @@ const { generateApi } = require("../../../src"); const { resolve } = require("path"); -const validateGeneratedModule = require("../../helpers/validateGeneratedModule") -const createSchemasInfos = require("../../helpers/createSchemaInfos") +const validateGeneratedModule = require("../../helpers/validateGeneratedModule"); +const createSchemasInfos = require("../../helpers/createSchemaInfos"); -const schemas = createSchemasInfos({ absolutePathToSchemas: resolve(__dirname, "./") }) +const schemas = createSchemasInfos({ absolutePathToSchemas: resolve(__dirname, "./") }); schemas.forEach(({ absolutePath, apiFileName }) => { generateApi({ name: apiFileName, input: absolutePath, - output: resolve(__dirname, './'), + output: resolve(__dirname, "./"), generateRouteTypes: true, + generateClient: false, }) - .then(() => { - const diagnostics = validateGeneratedModule({ pathToFile: resolve(__dirname, `./${apiFileName}`) }) - if (diagnostics.length) throw "Failed" - }) - .catch(e => { - console.error("routeTypes option test failed.") - throw e - }) -}) \ No newline at end of file + .then(() => { + const diagnostics = validateGeneratedModule({ + pathToFile: resolve(__dirname, `./${apiFileName}`), + }); + if (diagnostics.length) throw "Failed"; + }) + .catch((e) => { + console.error("routeTypes option test failed."); + throw e; + }); +}); diff --git a/tests/spec/specProperty/schema.ts b/tests/spec/specProperty/schema.ts index d271f073..5e3fa50b 100644 --- a/tests/spec/specProperty/schema.ts +++ b/tests/spec/specProperty/schema.ts @@ -49,60 +49,82 @@ export interface PageTemplateResponseDto { export namespace pets { /** * @description Returns all pets from the system that the user has access to Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. - * * @name FindPets * @request GET:/pets */ export namespace FindPets { + export type RequestParams = {}; export type RequestQuery = { tags?: string[]; limit?: number }; export type RequestBody = never; + export type RequestHeaders = {}; export type ResponseBody = Pet[]; } /** * @description Creates a new pet in the store. Duplicates are allowed - * * @name AddPet * @request POST:/pets */ export namespace AddPet { + export type RequestParams = {}; export type RequestQuery = {}; export type RequestBody = NewPet; + export type RequestHeaders = {}; export type ResponseBody = Pet; } /** * @description Returns a user based on a single ID, if the user does not have access to the pet - * * @name FindPetById * @request GET:/pets/{id} */ export namespace FindPetById { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; + export type RequestHeaders = {}; export type ResponseBody = Pet; } /** * @description deletes a single pet based on the ID supplied - * * @name DeletePet * @request DELETE:/pets/{id} */ export namespace DeletePet { + export type RequestParams = { id: number }; export type RequestQuery = {}; export type RequestBody = never; - export type ResponseBody = any; + export type RequestHeaders = {}; + export type ResponseBody = void; } } -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -110,22 +132,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://petstore.swagger.io/api"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -138,92 +161,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -236,7 +293,7 @@ export class HttpClient { * @baseUrl http://petstore.swagger.io/api * A sample API that uses a petstore as an example to demonstrate features in the swagger-2.0 specification */ -export class Api extends HttpClient { +export class Api extends HttpClient { pets = { /** * @description Returns all pets from the system that the user has access to Nam sed condimentum est. Maecenas tempor sagittis sapien, nec rhoncus sem sagittis sit amet. Aenean at gravida augue, ac iaculis sem. Curabitur odio lorem, ornare eget elementum nec, cursus id lectus. Duis mi turpis, pulvinar ac eros ac, tincidunt varius justo. In hac habitasse platea dictumst. Integer at adipiscing ante, a sagittis ligula. Aenean pharetra tempor ante molestie imperdiet. Vivamus id aliquam diam. Cras quis velit non tortor eleifend sagittis. Praesent at enim pharetra urna volutpat venenatis eget eget mauris. In eleifend fermentum facilisis. Praesent enim enim, gravida ac sodales sed, placerat id erat. Suspendisse lacus dolor, consectetur non augue vel, vehicula interdum libero. Morbi euismod sagittis libero sed lacinia. Sed tempus felis lobortis leo pulvinar rutrum. Nam mattis velit nisl, eu condimentum ligula luctus nec. Phasellus semper velit eget aliquet faucibus. In a mattis elit. Phasellus vel urna viverra, condimentum lorem id, rhoncus nibh. Ut pellentesque posuere elementum. Sed a varius odio. Morbi rhoncus ligula libero, vel eleifend nunc tristique vitae. Fusce et sem dui. Aenean nec scelerisque tortor. Fusce malesuada accumsan magna vel tempus. Quisque mollis felis eu dolor tristique, sit amet auctor felis gravida. Sed libero lorem, molestie sed nisl in, accumsan tempor nisi. Fusce sollicitudin massa ut lacinia mattis. Sed vel eleifend lorem. Pellentesque vitae felis pretium, pulvinar elit eu, euismod sapien. @@ -244,8 +301,14 @@ export class Api extends HttpClient { * @name FindPets * @request GET:/pets */ - findPets: (query?: { tags?: string[]; limit?: number }, params?: RequestParams) => - this.request(`/pets${this.addQueryParams(query)}`, "GET", params), + findPets: (query?: { tags?: string[]; limit?: number }, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "GET", + query: query, + format: "json", + ...params, + }), /** * @description Creates a new pet in the store. Duplicates are allowed @@ -253,8 +316,15 @@ export class Api extends HttpClient { * @name AddPet * @request POST:/pets */ - addPet: (pet: NewPet, params?: RequestParams) => - this.request(`/pets`, "POST", params, pet, BodyType.Json), + addPet: (pet: NewPet, params: RequestParams = {}) => + this.request({ + path: `/pets`, + method: "POST", + body: pet, + type: ContentType.Json, + format: "json", + ...params, + }), /** * @description Returns a user based on a single ID, if the user does not have access to the pet @@ -262,7 +332,13 @@ export class Api extends HttpClient { * @name FindPetById * @request GET:/pets/{id} */ - findPetById: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "GET", params), + findPetById: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "GET", + format: "json", + ...params, + }), /** * @description deletes a single pet based on the ID supplied @@ -270,6 +346,11 @@ export class Api extends HttpClient { * @name DeletePet * @request DELETE:/pets/{id} */ - deletePet: (id: number, params?: RequestParams) => this.request(`/pets/${id}`, "DELETE", params), + deletePet: (id: number, params: RequestParams = {}) => + this.request({ + path: `/pets/${id}`, + method: "DELETE", + ...params, + }), }; } diff --git a/tests/spec/unionEnums/schema.ts b/tests/spec/unionEnums/schema.ts index 8c3544a7..3c92176d 100644 --- a/tests/spec/unionEnums/schema.ts +++ b/tests/spec/unionEnums/schema.ts @@ -19,16 +19,34 @@ export type NumberEnum = 1 | 2 | 3 | 4; */ export type IntEnumWithNames = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9; -export type RequestParams = Omit & { +export type QueryParamsType = Record; +export type ResponseFormat = keyof Omit; + +export interface FullRequestParams extends Omit { + /** set parameter to `true` for call `securityWorker` for this request */ secure?: boolean; -}; + /** request path */ + path: string; + /** content type of request body */ + type?: ContentType; + /** query params */ + query?: QueryParamsType; + /** format of response (i.e. response.json() -> format: "json") */ + format?: keyof Omit; + /** request body */ + body?: unknown; + /** base url */ + baseUrl?: string; + /** request cancellation token */ + cancelToken?: CancelToken; +} -export type RequestQueryParamsType = Record; +export type RequestParams = Omit; -interface ApiConfig { +interface ApiConfig { baseUrl?: string; - baseApiParams?: RequestParams; - securityWorker?: (securityData: SecurityDataType) => RequestParams; + baseApiParams?: Omit; + securityWorker?: (securityData: SecurityDataType) => RequestParams | void; } interface HttpResponse extends Response { @@ -36,22 +54,23 @@ interface HttpResponse extends R error: E; } -enum BodyType { - Json, - FormData, - UrlEncoded, +type CancelToken = Symbol | string | number; + +export enum ContentType { + Json = "application/json", + FormData = "multipart/form-data", + UrlEncoded = "application/x-www-form-urlencoded", } export class HttpClient { public baseUrl: string = "http://localhost:8080/api/v1"; private securityData: SecurityDataType = null as any; private securityWorker: null | ApiConfig["securityWorker"] = null; + private abortControllers = new Map(); private baseApiParams: RequestParams = { credentials: "same-origin", - headers: { - "Content-Type": "application/json", - }, + headers: {}, redirect: "follow", referrerPolicy: "no-referrer", }; @@ -64,92 +83,126 @@ export class HttpClient { this.securityData = data; }; - private addQueryParam(query: RequestQueryParamsType, key: string) { + private addQueryParam(query: QueryParamsType, key: string) { + const value = query[key]; + return ( - encodeURIComponent(key) + "=" + encodeURIComponent(Array.isArray(query[key]) ? query[key].join(",") : query[key]) + encodeURIComponent(key) + + "=" + + encodeURIComponent(Array.isArray(value) ? value.join(",") : typeof value === "number" ? value : `${value}`) ); } - protected toQueryString(rawQuery?: RequestQueryParamsType): string { + protected toQueryString(rawQuery?: QueryParamsType): string { const query = rawQuery || {}; const keys = Object.keys(query).filter((key) => "undefined" !== typeof query[key]); return keys .map((key) => typeof query[key] === "object" && !Array.isArray(query[key]) - ? this.toQueryString(query[key] as object) + ? this.toQueryString(query[key] as QueryParamsType) : this.addQueryParam(query, key), ) .join("&"); } - protected addQueryParams(rawQuery?: RequestQueryParamsType): string { + protected addQueryParams(rawQuery?: QueryParamsType): string { const queryString = this.toQueryString(rawQuery); return queryString ? `?${queryString}` : ""; } - private bodyFormatters: Record any> = { - [BodyType.Json]: JSON.stringify, - [BodyType.FormData]: (input: any) => - Object.keys(input).reduce((data, key) => { + private contentFormatters: Record any> = { + [ContentType.Json]: (input: any) => (input !== null && typeof input === "object" ? JSON.stringify(input) : input), + [ContentType.FormData]: (input: any) => + Object.keys(input || {}).reduce((data, key) => { data.append(key, input[key]); return data; }, new FormData()), - [BodyType.UrlEncoded]: (input: any) => this.toQueryString(input), + [ContentType.UrlEncoded]: (input: any) => this.toQueryString(input), }; - private mergeRequestOptions(params: RequestParams, securityParams?: RequestParams): RequestParams { + private mergeRequestParams(params1: RequestParams, params2?: RequestParams): RequestParams { return { ...this.baseApiParams, - ...params, - ...(securityParams || {}), + ...params1, + ...(params2 || {}), headers: { ...(this.baseApiParams.headers || {}), - ...(params.headers || {}), - ...((securityParams && securityParams.headers) || {}), + ...(params1.headers || {}), + ...((params2 && params2.headers) || {}), }, }; } - private safeParseResponse = (response: Response): Promise> => { - const r = response as HttpResponse; - r.data = (null as unknown) as T; - r.error = (null as unknown) as E; - - return response - .json() - .then((data) => { - if (r.ok) { - r.data = data; - } else { - r.error = data; - } - return r; - }) - .catch((e) => { - r.error = e; - return r; - }); + private createAbortSignal = (cancelToken: CancelToken): AbortSignal | undefined => { + if (this.abortControllers.has(cancelToken)) { + const abortController = this.abortControllers.get(cancelToken); + if (abortController) { + return abortController.signal; + } + return void 0; + } + + const abortController = new AbortController(); + this.abortControllers.set(cancelToken, abortController); + return abortController.signal; }; - public request = ( - path: string, - method: string, - { secure, ...params }: RequestParams = {}, - body?: any, - bodyType?: BodyType, - secureByDefault?: boolean, - ): Promise> => { - const requestUrl = `${this.baseUrl}${path}`; - const secureOptions = - (secureByDefault || secure) && this.securityWorker ? this.securityWorker(this.securityData) : {}; - const requestOptions = { - ...this.mergeRequestOptions(params, secureOptions), - method, - body: body ? this.bodyFormatters[bodyType || BodyType.Json](body) : null, - }; + public abortRequest = (cancelToken: CancelToken) => { + const abortController = this.abortControllers.get(cancelToken); + + if (abortController) { + abortController.abort(); + this.abortControllers.delete(cancelToken); + } + }; + + public request = ({ + body, + secure, + path, + type, + query, + format = "json", + baseUrl, + cancelToken, + ...params + }: FullRequestParams): Promise> => { + const secureParams = (secure && this.securityWorker && this.securityWorker(this.securityData)) || {}; + const requestParams = this.mergeRequestParams(params, secureParams); + const queryString = query && this.toQueryString(query); + const payloadFormatter = this.contentFormatters[type || ContentType.Json]; + + return fetch(`${baseUrl || this.baseUrl || ""}${path}${queryString ? `?${queryString}` : ""}`, { + headers: { + ...(type ? { "Content-Type": type } : {}), + ...(requestParams.headers || {}), + }, + ...requestParams, + signal: cancelToken ? this.createAbortSignal(cancelToken) : void 0, + body: typeof body === "undefined" || body === null ? null : payloadFormatter(body), + }).then(async (response) => { + const r = response as HttpResponse; + r.data = (null as unknown) as T; + r.error = (null as unknown) as E; + + const data = await response[format]() + .then((data) => { + if (r.ok) { + r.data = data; + } else { + r.error = data; + } + return r; + }) + .catch((e) => { + r.error = e; + return r; + }); + + if (cancelToken) { + this.abortControllers.delete(cancelToken); + } - return fetch(requestUrl, requestOptions).then(async (response) => { - const data = await this.safeParseResponse(response); if (!response.ok) throw data; return data; }); @@ -157,7 +210,7 @@ export class HttpClient { } /** - * @title Api + * @title No title * @baseUrl http://localhost:8080/api/v1 */ -export class Api extends HttpClient {} +export class Api extends HttpClient {}