@map-colonies/openapi-helpers 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +56 -0
- package/dist/common/types.d.ts +4 -0
- package/dist/common/types.d.ts.map +1 -0
- package/dist/common/types.js +3 -0
- package/dist/common/types.js.map +1 -0
- package/dist/generator/generateTypes.d.mts +3 -0
- package/dist/generator/generateTypes.d.mts.map +1 -0
- package/dist/generator/generateTypes.mjs +24 -0
- package/dist/generator/generateTypes.mjs.map +1 -0
- package/dist/requestSender/requestSender.d.ts +15 -0
- package/dist/requestSender/requestSender.d.ts.map +1 -0
- package/dist/requestSender/requestSender.js +94 -0
- package/dist/requestSender/requestSender.js.map +1 -0
- package/dist/requestSender/types.d.ts +95 -0
- package/dist/requestSender/types.d.ts.map +1 -0
- package/dist/requestSender/types.js +3 -0
- package/dist/requestSender/types.js.map +1 -0
- package/package.json +78 -0
package/README.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# openapi-helpers
|
|
2
|
+
This package contains scripts, types and functions to help you work with openapi.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
Run the following commands:
|
|
7
|
+
|
|
8
|
+
```bash
|
|
9
|
+
npm install --save-dev @map-colonies/openapi-helpers supertest prettier openapi-typescript @types/express
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## types-generator
|
|
13
|
+
The package contains a script that wraps the `openapi-typescript` package and generates types for the openapi schema. The script also formats the generated types using `prettier`.
|
|
14
|
+
|
|
15
|
+
The command structure is as follows:
|
|
16
|
+
```bash
|
|
17
|
+
npx @map-colonies/openapi-helpers <input-file> <output-file> --format
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
For example:
|
|
21
|
+
```bash
|
|
22
|
+
npx @map-colonies/openapi-helpers ./openapi3.yaml ./src/openapi.d.ts --format
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## RequestSender
|
|
26
|
+
The package contains a wrapper for the `supertest` package that provides autocomplete for all the requests to the API based on the openapi. The requestSender is initialized with the server's base url and the openapi schema and the types exported by `openapi-typescript`.
|
|
27
|
+
|
|
28
|
+
```typescript
|
|
29
|
+
import { RequestSender } from '@map-colonies/openapi-helpers/requestSender';
|
|
30
|
+
import type { paths, operations } from './src/openapi.d.ts';
|
|
31
|
+
|
|
32
|
+
const requestSender = await createRequestSender<paths, operations>('path/to/openapi3.yaml', expressApp);
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
The requestSender object contains all the paths and operations defined in the openapi schema. For example, to send a request to the `getUsers` operation with the `/users` path and with the `GET` method, you can use the following code:
|
|
36
|
+
|
|
37
|
+
```typescript
|
|
38
|
+
const response = await requestSender.getUsers();
|
|
39
|
+
|
|
40
|
+
// or
|
|
41
|
+
|
|
42
|
+
const response = await requestSender.sendRequest({
|
|
43
|
+
method: 'get',
|
|
44
|
+
path: '/simple-request'
|
|
45
|
+
});
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
The package supports all the operations defined in the openapi schema, either by operation name, or by using the `sendRequest` function with the method, path and parameters.
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
> [!IMPORTANT]
|
|
52
|
+
> For the package function properly, you need to make sure that the following values are configured in your `tsconfig.json` or `jsconfig.json` files under compilerOptions:
|
|
53
|
+
> - module: "NodeNext"
|
|
54
|
+
> - moduleResolution: "NodeNext"
|
|
55
|
+
|
|
56
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAE7C,MAAM,MAAM,aAAa,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;AAClE,MAAM,MAAM,YAAY,CAAC,CAAC,SAAS,WAAW,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,CAAC,CAAC,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/common/types.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateTypes.d.mts","sourceRoot":"","sources":["../../src/generator/generateTypes.mts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import { parseArgs } from 'node:util';
|
|
4
|
+
import { format, resolveConfig } from 'prettier';
|
|
5
|
+
import openapiTS, { astToString } from 'openapi-typescript';
|
|
6
|
+
const ARGS_SLICE = 2;
|
|
7
|
+
const { values: { format: shouldFormat }, positionals, } = parseArgs({
|
|
8
|
+
args: process.argv.slice(ARGS_SLICE),
|
|
9
|
+
options: {
|
|
10
|
+
format: { type: 'boolean', alias: 'f' },
|
|
11
|
+
},
|
|
12
|
+
allowPositionals: true,
|
|
13
|
+
});
|
|
14
|
+
const [openapiPath, destinationPath] = positionals;
|
|
15
|
+
const ESLINT_DISABLE = '/* eslint-disable */\n';
|
|
16
|
+
const ast = await openapiTS(await fs.readFile(openapiPath, 'utf-8'), { exportType: true });
|
|
17
|
+
let content = ESLINT_DISABLE + astToString(ast);
|
|
18
|
+
if (shouldFormat === true) {
|
|
19
|
+
const prettierOptions = await resolveConfig('./src/index.ts');
|
|
20
|
+
content = await format(content, { ...prettierOptions, parser: 'typescript' });
|
|
21
|
+
}
|
|
22
|
+
await fs.writeFile(destinationPath, content);
|
|
23
|
+
console.log('Types generated successfully');
|
|
24
|
+
//# sourceMappingURL=generateTypes.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"generateTypes.mjs","sourceRoot":"","sources":["../../src/generator/generateTypes.mts"],"names":[],"mappings":";AACA,OAAO,EAAE,MAAM,kBAAkB,CAAC;AAClC,OAAO,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AACtC,OAAO,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACjD,OAAO,SAAS,EAAE,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AAE5D,MAAM,UAAU,GAAG,CAAC,CAAC;AAErB,MAAM,EACJ,MAAM,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,EAChC,WAAW,GACZ,GAAG,SAAS,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC;IACpC,OAAO,EAAE;QACP,MAAM,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,GAAG,EAAE;KACxC;IACD,gBAAgB,EAAE,IAAI;CACvB,CAAC,CAAC;AAEH,MAAM,CAAC,WAAW,EAAE,eAAe,CAAC,GAAG,WAAW,CAAC;AAEnD,MAAM,cAAc,GAAG,wBAAwB,CAAC;AAEhD,MAAM,GAAG,GAAG,MAAM,SAAS,CAAC,MAAM,EAAE,CAAC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC,EAAE,EAAE,UAAU,EAAE,IAAI,EAAE,CAAC,CAAC;AAE3F,IAAI,OAAO,GAAG,cAAc,GAAG,WAAW,CAAC,GAAG,CAAC,CAAC;AAEhD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;IAC1B,MAAM,eAAe,GAAG,MAAM,aAAa,CAAC,gBAAgB,CAAC,CAAC;IAE9D,OAAO,GAAG,MAAM,MAAM,CAAC,OAAO,EAAE,EAAE,GAAG,eAAe,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,MAAM,EAAE,CAAC,SAAS,CAAC,eAAe,EAAE,OAAO,CAAC,CAAC;AAE7C,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type express from 'express';
|
|
2
|
+
import type { PathsTemplate, OperationsTemplate, RequestSender } from './types';
|
|
3
|
+
export { RequestSender };
|
|
4
|
+
/**
|
|
5
|
+
* Creates a request sender object that can be used to send fake HTTP requests using supertest based on an OpenAPI specification.
|
|
6
|
+
* The openapi types should be generated using the openapi-typescript package.
|
|
7
|
+
*
|
|
8
|
+
* @template Paths - The type representing the paths defined in the OpenAPI specification.
|
|
9
|
+
* @template Operations - The type representing the operations defined in the OpenAPI specification.
|
|
10
|
+
* @param {string} openapiFilePath - The file path to the OpenAPI specification file.
|
|
11
|
+
* @param {express.Application} app - The Express application instance.
|
|
12
|
+
* @returns {Promise<RequestSender<Paths, Operations>>} A promise that resolves to a RequestSender object.
|
|
13
|
+
*/
|
|
14
|
+
export declare function createRequestSender<Paths extends PathsTemplate = never, Operations extends OperationsTemplate = never>(openapiFilePath: Operations extends never ? never : string, app: express.Application): Promise<RequestSender<Paths, Operations>>;
|
|
15
|
+
//# sourceMappingURL=requestSender.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestSender.d.ts","sourceRoot":"","sources":["../../src/requestSender/requestSender.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,OAAO,MAAM,SAAS,CAAC;AAInC,OAAO,KAAK,EACV,aAAa,EAKb,kBAAkB,EAClB,aAAa,EAEd,MAAM,SAAS,CAAC;AAkFjB,OAAO,EAAE,aAAa,EAAE,CAAC;AAEzB;;;;;;;;;GASG;AACH,wBAAsB,mBAAmB,CAAC,KAAK,SAAS,aAAa,GAAG,KAAK,EAAE,UAAU,SAAS,kBAAkB,GAAG,KAAK,EAC1H,eAAe,EAAE,UAAU,SAAS,KAAK,GAAG,KAAK,GAAG,MAAM,EAC1D,GAAG,EAAE,OAAO,CAAC,WAAW,GACvB,OAAO,CAAC,aAAa,CAAC,KAAK,EAAE,UAAU,CAAC,CAAC,CAqB3C"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.createRequestSender = void 0;
|
|
7
|
+
const node_fs_1 = require("node:fs");
|
|
8
|
+
const supertest_1 = __importDefault(require("supertest"));
|
|
9
|
+
const oas_normalize_1 = __importDefault(require("oas-normalize"));
|
|
10
|
+
function sendRequest(app, options) {
|
|
11
|
+
const method = options.method;
|
|
12
|
+
let actualPath = options.path;
|
|
13
|
+
if ('pathParams' in options && options.pathParams !== undefined) {
|
|
14
|
+
actualPath = Object.entries(options.pathParams).reduce((acc, [key, value]) => acc.replace(`{${key}}`, value), actualPath);
|
|
15
|
+
}
|
|
16
|
+
/* istanbul ignore next */
|
|
17
|
+
if (actualPath.includes('{') || actualPath.includes('}')) {
|
|
18
|
+
throw new Error('Path params are not provided');
|
|
19
|
+
}
|
|
20
|
+
let request = supertest_1.default.agent(app)[method](actualPath);
|
|
21
|
+
if (options.queryParams !== undefined) {
|
|
22
|
+
request = request.query(options.queryParams);
|
|
23
|
+
}
|
|
24
|
+
if ('requestBody' in options && options.requestBody !== undefined) {
|
|
25
|
+
request = request.send(options.requestBody);
|
|
26
|
+
}
|
|
27
|
+
if (options.headers !== undefined) {
|
|
28
|
+
for (const [key, value] of Object.entries(options.headers)) {
|
|
29
|
+
request = request.set(key, value);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
request = request.set('Content-Type', 'application/json');
|
|
33
|
+
// @ts-expect-error whatever
|
|
34
|
+
return request;
|
|
35
|
+
}
|
|
36
|
+
const methods = ['get', 'post', 'put', 'delete', 'patch', 'head', 'options', 'trace'];
|
|
37
|
+
function getOperationsPathAndMethod(openapi) {
|
|
38
|
+
const result = {};
|
|
39
|
+
/* istanbul ignore next */
|
|
40
|
+
if (openapi.paths === undefined) {
|
|
41
|
+
throw new Error('No paths found in the OpenAPI file');
|
|
42
|
+
}
|
|
43
|
+
for (const [path, pathValue] of Object.entries(openapi.paths)) {
|
|
44
|
+
/* istanbul ignore next */
|
|
45
|
+
if (pathValue === undefined) {
|
|
46
|
+
continue;
|
|
47
|
+
}
|
|
48
|
+
const pathObject = pathValue;
|
|
49
|
+
for (const method of methods) {
|
|
50
|
+
if (pathObject[method] !== undefined) {
|
|
51
|
+
const operationId = pathObject[method]?.operationId;
|
|
52
|
+
/* istanbul ignore next */
|
|
53
|
+
if (operationId === undefined) {
|
|
54
|
+
throw new Error(`OperationId is not defined for ${method} method on ${path}`);
|
|
55
|
+
}
|
|
56
|
+
// @ts-expect-error typescript does not allow to assign a generic index, but it is safe in this case
|
|
57
|
+
// as we are iterating over all the paths and methods
|
|
58
|
+
result[operationId] = {
|
|
59
|
+
path,
|
|
60
|
+
method,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return result;
|
|
66
|
+
}
|
|
67
|
+
/**
|
|
68
|
+
* Creates a request sender object that can be used to send fake HTTP requests using supertest based on an OpenAPI specification.
|
|
69
|
+
* The openapi types should be generated using the openapi-typescript package.
|
|
70
|
+
*
|
|
71
|
+
* @template Paths - The type representing the paths defined in the OpenAPI specification.
|
|
72
|
+
* @template Operations - The type representing the operations defined in the OpenAPI specification.
|
|
73
|
+
* @param {string} openapiFilePath - The file path to the OpenAPI specification file.
|
|
74
|
+
* @param {express.Application} app - The Express application instance.
|
|
75
|
+
* @returns {Promise<RequestSender<Paths, Operations>>} A promise that resolves to a RequestSender object.
|
|
76
|
+
*/
|
|
77
|
+
async function createRequestSender(openapiFilePath, app) {
|
|
78
|
+
const fileContent = (0, node_fs_1.readFileSync)(openapiFilePath, 'utf-8');
|
|
79
|
+
const normalized = new oas_normalize_1.default(fileContent);
|
|
80
|
+
const derefed = await normalized.deref();
|
|
81
|
+
const operationsPathAndMethod = getOperationsPathAndMethod(derefed);
|
|
82
|
+
const returnObj = {
|
|
83
|
+
// eslint-disable-next-line @typescript-eslint/promise-function-async
|
|
84
|
+
sendRequest: (options) => sendRequest(app, options),
|
|
85
|
+
};
|
|
86
|
+
for (const [operation, { path, method }] of Object.entries(operationsPathAndMethod)) {
|
|
87
|
+
// @ts-expect-error as we iterate over all the operations, the operationId is always defined
|
|
88
|
+
// eslint-disable-next-line @typescript-eslint/explicit-function-return-type
|
|
89
|
+
returnObj[operation] = async (options) => sendRequest(app, { path, method: method, ...options });
|
|
90
|
+
}
|
|
91
|
+
return returnObj;
|
|
92
|
+
}
|
|
93
|
+
exports.createRequestSender = createRequestSender;
|
|
94
|
+
//# sourceMappingURL=requestSender.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"requestSender.js","sourceRoot":"","sources":["../../src/requestSender/requestSender.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import type { OmitProperties, OptionalKeys, Prettify, RequiredKeys } from 'ts-essentials';
|
|
2
|
+
import type * as supertest from 'supertest';
|
|
3
|
+
import type { AddIfNotNever, PickWritable } from '../common/types';
|
|
4
|
+
export type Methods = 'get' | 'post' | 'put' | 'delete' | 'patch' | 'head' | 'options' | 'trace';
|
|
5
|
+
export type OperationsTemplate = Record<string, any>;
|
|
6
|
+
export type PathsTemplate = Record<string, {
|
|
7
|
+
parameters: {
|
|
8
|
+
query?: any;
|
|
9
|
+
header?: any;
|
|
10
|
+
path?: any;
|
|
11
|
+
cookie?: any;
|
|
12
|
+
};
|
|
13
|
+
} & {
|
|
14
|
+
[key in Methods]?: OperationsTemplate;
|
|
15
|
+
}>;
|
|
16
|
+
interface Headers {
|
|
17
|
+
headers?: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
type HasContent<T> = [T] extends [{
|
|
20
|
+
content: any;
|
|
21
|
+
}] ? T['content']['application/json'] : never;
|
|
22
|
+
type ResponseObjectToFlat<T> = [T] extends [{
|
|
23
|
+
responses: any;
|
|
24
|
+
}] ? {
|
|
25
|
+
[res in keyof T['responses']]: {
|
|
26
|
+
status: res;
|
|
27
|
+
body: HasContent<T['responses'][res]>;
|
|
28
|
+
};
|
|
29
|
+
}[keyof T['responses']] : never;
|
|
30
|
+
type PathParamsObj<T> = [T] extends [{
|
|
31
|
+
parameters: {
|
|
32
|
+
path: NonNullable<any>;
|
|
33
|
+
};
|
|
34
|
+
}] ? {
|
|
35
|
+
pathParams: T['parameters']['path'];
|
|
36
|
+
} : never;
|
|
37
|
+
type QueryParamsObj<T> = [T] extends [{
|
|
38
|
+
parameters: {
|
|
39
|
+
query?: NonNullable<any>;
|
|
40
|
+
};
|
|
41
|
+
}] ? [T] extends [{
|
|
42
|
+
parameters: {
|
|
43
|
+
query?: never;
|
|
44
|
+
};
|
|
45
|
+
}] ? {
|
|
46
|
+
queryParams?: Record<string, string>;
|
|
47
|
+
} : [RequiredKeys<T['parameters']['query']>] extends [OptionalKeys<T['parameters']['query']>] ? {
|
|
48
|
+
queryParams?: T['parameters']['query'];
|
|
49
|
+
} : {
|
|
50
|
+
queryParams: T['parameters']['query'];
|
|
51
|
+
} : {
|
|
52
|
+
queryParams?: Record<string, string>;
|
|
53
|
+
};
|
|
54
|
+
type ContentOrUndefined<T extends {
|
|
55
|
+
content: any;
|
|
56
|
+
} | undefined> = [T] extends [{
|
|
57
|
+
content: any;
|
|
58
|
+
}] ? PickWritable<T['content']['application/json']> : undefined;
|
|
59
|
+
type RequestBodyObj<T> = [T] extends [{
|
|
60
|
+
requestBody: {
|
|
61
|
+
content: any;
|
|
62
|
+
};
|
|
63
|
+
}] ? {
|
|
64
|
+
requestBody: PickWritable<T['requestBody']['content']['application/json']>;
|
|
65
|
+
} : T extends {
|
|
66
|
+
requestBody?: undefined;
|
|
67
|
+
} ? {
|
|
68
|
+
requestBody?: any;
|
|
69
|
+
} : T extends {
|
|
70
|
+
requestBody?: {
|
|
71
|
+
content: any;
|
|
72
|
+
};
|
|
73
|
+
} ? {
|
|
74
|
+
requestBody?: ContentOrUndefined<T['requestBody']>;
|
|
75
|
+
} : {
|
|
76
|
+
requestBody?: any;
|
|
77
|
+
};
|
|
78
|
+
type RequestOptionsWithoutPathParams<T> = QueryParamsObj<T> & RequestBodyObj<T> & Headers;
|
|
79
|
+
export type RequestOptions<T> = AddIfNotNever<RequestOptionsWithoutPathParams<T>, PathParamsObj<T>>;
|
|
80
|
+
export type PathRequestOptions<Paths extends PathsTemplate, Path extends keyof Paths, Method extends keyof OmitProperties<Omit<Paths[Path], 'parameters'>, undefined>> = RequestOptions<Paths[Path][Method]> & {
|
|
81
|
+
path: Path;
|
|
82
|
+
method: Method;
|
|
83
|
+
};
|
|
84
|
+
export type RequestReturn<T> = Promise<ResponseObjectToFlat<T> & Omit<Awaited<supertest.Test>, 'body' | 'status'>> & supertest.Test;
|
|
85
|
+
export type OperationsNames<Operations extends OperationsTemplate> = keyof Operations;
|
|
86
|
+
type OperationRequestOptional<Operations extends OperationsTemplate, Operation extends OperationsNames<Operations>> = (options?: RequestOptions<Operations[Operation]>) => RequestReturn<Operations[Operation]>;
|
|
87
|
+
type OperationRequestRequired<Operations extends OperationsTemplate, Operation extends OperationsNames<Operations>> = (options: RequestOptions<Operations[Operation]>) => RequestReturn<Operations[Operation]>;
|
|
88
|
+
type SendRequest<Paths extends PathsTemplate> = <Path extends keyof Paths, Method extends keyof OmitProperties<Omit<Paths[Path], 'parameters'>, undefined>>(options: PathRequestOptions<Paths, Path, Method>) => RequestReturn<Paths[Path][Method]>;
|
|
89
|
+
export type RequestSender<Paths extends PathsTemplate, Operations extends OperationsTemplate> = Prettify<{
|
|
90
|
+
sendRequest: SendRequest<Paths>;
|
|
91
|
+
} & {
|
|
92
|
+
[operation in OperationsNames<Operations>]: RequiredKeys<RequestOptions<Operations[operation]>> extends OptionalKeys<RequestOptions<Operations[operation]>> ? OperationRequestOptional<Operations, operation> : OperationRequestRequired<Operations, operation>;
|
|
93
|
+
}>;
|
|
94
|
+
export {};
|
|
95
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/requestSender/types.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/requestSender/types.ts"],"names":[],"mappings":""}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@map-colonies/openapi-helpers",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A package that provides utilities for working with openapi files",
|
|
5
|
+
"exports": {
|
|
6
|
+
"./requestSender": {
|
|
7
|
+
"default": "./dist/requestSender/requestSender.js",
|
|
8
|
+
"types": "./dist/requestSender/requestSender.d.ts"
|
|
9
|
+
}
|
|
10
|
+
},
|
|
11
|
+
"bin": "./dist/generator/generateTypes.mjs",
|
|
12
|
+
"scripts": {
|
|
13
|
+
"format": "prettier --check .",
|
|
14
|
+
"format:fix": "prettier --write .",
|
|
15
|
+
"prelint:fix": "npm run format:fix",
|
|
16
|
+
"prelint": "npm run format",
|
|
17
|
+
"lint": "eslint .",
|
|
18
|
+
"lint:fix": "eslint --fix .",
|
|
19
|
+
"test": "jest --config=./tests/configurations/jest.config.js",
|
|
20
|
+
"prebuild": "npm run clean",
|
|
21
|
+
"build": "tsc --project tsconfig.build.json",
|
|
22
|
+
"generate:test:types": "npm run build && node dist/generator/generateTypes.mjs tests/supertest/openapi3.yaml tests/supertest/types.d.ts",
|
|
23
|
+
"clean": "rimraf dist",
|
|
24
|
+
"prepublish": "npm run build"
|
|
25
|
+
},
|
|
26
|
+
"repository": {
|
|
27
|
+
"type": "git",
|
|
28
|
+
"url": "git+https://github.com/MapColonies/openapi-helpers.git"
|
|
29
|
+
},
|
|
30
|
+
"author": "MapColonies",
|
|
31
|
+
"license": "ISC",
|
|
32
|
+
"bugs": {
|
|
33
|
+
"url": "https://github.com/MapColonies/openapi-helpers/issues"
|
|
34
|
+
},
|
|
35
|
+
"husky": {
|
|
36
|
+
"hooks": {
|
|
37
|
+
"pre-commit": "pretty-quick --staged",
|
|
38
|
+
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
"files": [
|
|
42
|
+
"dist/**/*"
|
|
43
|
+
],
|
|
44
|
+
"publishConfig": {
|
|
45
|
+
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"homepage": "https://github.com/MapColonies/openapi-helpers#readme",
|
|
48
|
+
"dependencies": {
|
|
49
|
+
"oas-normalize": "^11.1.1",
|
|
50
|
+
"ts-essentials": "^10.0.1",
|
|
51
|
+
"yaml": "^2.5.0"
|
|
52
|
+
},
|
|
53
|
+
"peerDependencies": {
|
|
54
|
+
"@types/express": "^4.17.21",
|
|
55
|
+
"openapi-typescript": "^7.3.0",
|
|
56
|
+
"prettier": "^3.3.3",
|
|
57
|
+
"supertest": "^7.0.0"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@commitlint/cli": "^11.0.0",
|
|
61
|
+
"@commitlint/config-conventional": "^11.0.0",
|
|
62
|
+
"@map-colonies/eslint-config": "^4.0.0",
|
|
63
|
+
"@types/jest": "^29.5.12",
|
|
64
|
+
"@types/node": "^22.2.0",
|
|
65
|
+
"@types/supertest": "^6.0.2",
|
|
66
|
+
"body-parser": "^1.20.2",
|
|
67
|
+
"commitlint": "^11.0.0",
|
|
68
|
+
"cz-conventional-changelog": "^3.3.0",
|
|
69
|
+
"eslint": "^8.56.0",
|
|
70
|
+
"expect-type": "^0.19.0",
|
|
71
|
+
"express": "^4.17.1",
|
|
72
|
+
"husky": "^4.3.5",
|
|
73
|
+
"jest": "^29.7.0",
|
|
74
|
+
"pretty-quick": "^4.0.0",
|
|
75
|
+
"ts-jest": "^29.1.5",
|
|
76
|
+
"typescript": "^5.4.5"
|
|
77
|
+
}
|
|
78
|
+
}
|