@spec2ts/openapi-client 3.1.3 → 4.0.1
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 +11 -8
- package/dist/bin/oapi2tsclient.d.mts +1 -0
- package/dist/bin/oapi2tsclient.mjs +8 -0
- package/dist/cli/index.d.mts +24 -0
- package/dist/cli/index.mjs +2 -0
- package/dist/command-C4XUi5ys.mjs +143 -0
- package/dist/index.d.mts +2 -0
- package/dist/index.mjs +2 -0
- package/dist/openapi-generator-B6yW0z4d.d.mts +25 -0
- package/dist/openapi-generator-IB_huQ-a.mjs +414 -0
- package/package.json +76 -69
- package/bin/oapi2tsclient.js +0 -4
- package/cli/command.d.ts +0 -20
- package/cli/command.js +0 -168
- package/cli/index.d.ts +0 -1
- package/cli/index.js +0 -9
- package/index.d.ts +0 -1
- package/index.js +0 -17
- package/lib/core-generator.d.ts +0 -7
- package/lib/core-generator.js +0 -155
- package/lib/core-parser.d.ts +0 -24
- package/lib/core-parser.js +0 -239
- package/lib/openapi-generator.d.ts +0 -22
- package/lib/openapi-generator.js +0 -39
- package/lib/server-parser.d.ts +0 -4
- package/lib/server-parser.js +0 -79
- package/lib/templates/_client.tpl.d.ts +0 -81
- package/lib/templates/_client.tpl.js +0 -204
- package/lib/templates/_client.tpl.ts +0 -271
- package/lib/util.d.ts +0 -1
- package/lib/util.js +0 -21
package/lib/core-parser.js
DELETED
|
@@ -1,239 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.isMethod = exports.parseOperation = void 0;
|
|
4
|
-
const ts = require("typescript");
|
|
5
|
-
const core = require("@spec2ts/core");
|
|
6
|
-
const core_parser_1 = require("@spec2ts/jsonschema/lib/core-parser");
|
|
7
|
-
const core_parser_2 = require("@spec2ts/openapi/lib/core-parser");
|
|
8
|
-
const util_1 = require("./util");
|
|
9
|
-
const methods = ["GET", "PUT", "POST", "DELETE", "OPTIONS", "HEAD", "PATCH", "TRACE"];
|
|
10
|
-
const contentTypes = {
|
|
11
|
-
"*/*": "json",
|
|
12
|
-
"application/json": "json",
|
|
13
|
-
"application/x-www-form-urlencoded": "form",
|
|
14
|
-
"multipart/form-data": "multipart",
|
|
15
|
-
};
|
|
16
|
-
function parseOperation(path, item, method, operation, context) {
|
|
17
|
-
const result = {
|
|
18
|
-
name: getOperationVar(method, path, operation.operationId, context),
|
|
19
|
-
paramsVars: {},
|
|
20
|
-
args: [],
|
|
21
|
-
query: [],
|
|
22
|
-
header: [],
|
|
23
|
-
response: core.keywordType.void
|
|
24
|
-
};
|
|
25
|
-
parseArgs(result, item, operation, context);
|
|
26
|
-
parseResponses(result, path, method, operation, context);
|
|
27
|
-
return result;
|
|
28
|
-
}
|
|
29
|
-
exports.parseOperation = parseOperation;
|
|
30
|
-
function parseArgs(result, item, operation, context) {
|
|
31
|
-
parseParameters(result, item, operation, context);
|
|
32
|
-
if (operation.requestBody) {
|
|
33
|
-
parseRequestBody(result, operation.requestBody, context);
|
|
34
|
-
}
|
|
35
|
-
result.args.push(core.createParameter("options", {
|
|
36
|
-
type: ts.factory.createTypeReferenceNode("RequestOptions", undefined),
|
|
37
|
-
questionToken: true,
|
|
38
|
-
}));
|
|
39
|
-
}
|
|
40
|
-
function parseResponses(result, path, method, operation, context) {
|
|
41
|
-
const operationName = (0, core_parser_2.getOperationName)(method, path, operation.operationId, context);
|
|
42
|
-
result.response = getTypeFromResponses(operationName, operation.responses, context);
|
|
43
|
-
result.responseJSON = isJSONResponse(operation.responses, context);
|
|
44
|
-
result.responseVoid = result.response === core.keywordType.void;
|
|
45
|
-
}
|
|
46
|
-
function parseParameters(result, item, operation, context) {
|
|
47
|
-
const parameters = fixDeepObjects([
|
|
48
|
-
...resolveReferences(item.parameters, context),
|
|
49
|
-
...resolveReferences(operation.parameters, context),
|
|
50
|
-
]);
|
|
51
|
-
result.query = parameters.filter((p) => p.in === "query");
|
|
52
|
-
result.header = parameters.filter((p) => p.in === "header");
|
|
53
|
-
const argNames = result.paramsVars = createParametersNames(parameters);
|
|
54
|
-
let objectBindingParams = parameters;
|
|
55
|
-
if (context.options.inlineRequired) {
|
|
56
|
-
const [required, optional] = splitParameters(parameters);
|
|
57
|
-
objectBindingParams = optional;
|
|
58
|
-
required.forEach(p => {
|
|
59
|
-
result.args.push(core.createParameter(argNames[p.name], {
|
|
60
|
-
type: (0, core_parser_1.getTypeFromSchema)(p.schema, context),
|
|
61
|
-
}));
|
|
62
|
-
});
|
|
63
|
-
}
|
|
64
|
-
if (!objectBindingParams.length) {
|
|
65
|
-
return;
|
|
66
|
-
}
|
|
67
|
-
result.args.push(core.createParameter(core.createObjectBinding(objectBindingParams.map(({ name }) => ({ name: argNames[name] }))), {
|
|
68
|
-
initializer: objectBindingParams.some(p => p.required) ? undefined : ts.factory.createObjectLiteralExpression(),
|
|
69
|
-
type: ts.factory.createTypeLiteralNode(objectBindingParams.map((p) => core.createPropertySignature({
|
|
70
|
-
name: argNames[p.name],
|
|
71
|
-
questionToken: !p.required,
|
|
72
|
-
type: (0, core_parser_1.getTypeFromSchema)(p.schema, context)
|
|
73
|
-
}))),
|
|
74
|
-
}));
|
|
75
|
-
}
|
|
76
|
-
function parseRequestBody(result, requestBody, context) {
|
|
77
|
-
const body = (0, core_parser_1.resolveReference)(requestBody, context);
|
|
78
|
-
const [schema, mode] = getSchemaFromContent(body.content);
|
|
79
|
-
const type = (0, core_parser_1.getTypeFromSchema)(schema, context);
|
|
80
|
-
const bodyVar = result.bodyVar = (0, util_1.camelCase)(type.name || getReferenceName(schema) || "body");
|
|
81
|
-
result.bodyMode = mode;
|
|
82
|
-
result.args.push(core.createParameter(bodyVar, { type }));
|
|
83
|
-
}
|
|
84
|
-
function createParametersNames(parameters) {
|
|
85
|
-
const argNames = {};
|
|
86
|
-
parameters.forEach(({ name }) => {
|
|
87
|
-
// strip leading namespaces, eg. foo.name -> name
|
|
88
|
-
const stripped = (0, util_1.camelCase)(name.replace(/.+\./, ""));
|
|
89
|
-
// keep the prefix if the stripped-down name is already taken
|
|
90
|
-
argNames[name] = stripped in argNames ? (0, util_1.camelCase)(name) : stripped;
|
|
91
|
-
});
|
|
92
|
-
return argNames;
|
|
93
|
-
}
|
|
94
|
-
function splitParameters(parameters) {
|
|
95
|
-
const required = [];
|
|
96
|
-
const optional = [];
|
|
97
|
-
parameters.forEach(p => {
|
|
98
|
-
if (p.required)
|
|
99
|
-
required.push(p);
|
|
100
|
-
else
|
|
101
|
-
optional.push(p);
|
|
102
|
-
});
|
|
103
|
-
return [required, optional];
|
|
104
|
-
}
|
|
105
|
-
function getTypeFromResponses(operationName, res, context) {
|
|
106
|
-
const codes = Object.keys(res);
|
|
107
|
-
const types = [];
|
|
108
|
-
codes.forEach(code => {
|
|
109
|
-
const isOK = isOKResponse(code, codes.length);
|
|
110
|
-
const type = getTypeFromResponse(res[code], context);
|
|
111
|
-
if (!type)
|
|
112
|
-
console.log(res[code]);
|
|
113
|
-
if (ts.isTypeReferenceNode(type) || core.isKeywordTypeNode(type)) {
|
|
114
|
-
isOK && types.push(type);
|
|
115
|
-
}
|
|
116
|
-
else {
|
|
117
|
-
const name = (0, core_parser_2.getResponseName)(operationName, code, context);
|
|
118
|
-
context.aliases.push(core.createTypeOrInterfaceDeclaration({
|
|
119
|
-
modifiers: [core.modifier.export],
|
|
120
|
-
name, type
|
|
121
|
-
}));
|
|
122
|
-
if (isOK) {
|
|
123
|
-
types.push(ts.factory.createTypeReferenceNode(name, undefined));
|
|
124
|
-
}
|
|
125
|
-
}
|
|
126
|
-
});
|
|
127
|
-
if (types.length === 1) {
|
|
128
|
-
return types[0];
|
|
129
|
-
}
|
|
130
|
-
return ts.factory.createUnionTypeNode(types);
|
|
131
|
-
}
|
|
132
|
-
function isJSONResponse(responses, context) {
|
|
133
|
-
var _a, _b;
|
|
134
|
-
const codes = Object.keys(responses);
|
|
135
|
-
const resCode = codes.find(code => isOKResponse(code, codes.length));
|
|
136
|
-
if (!resCode) {
|
|
137
|
-
return false;
|
|
138
|
-
}
|
|
139
|
-
const response = (0, core_parser_1.resolveReference)(responses[resCode], context);
|
|
140
|
-
return (!!((_a = response === null || response === void 0 ? void 0 : response.content) === null || _a === void 0 ? void 0 : _a["application/json"]) ||
|
|
141
|
-
!!((_b = response === null || response === void 0 ? void 0 : response.content) === null || _b === void 0 ? void 0 : _b["*/*"]));
|
|
142
|
-
}
|
|
143
|
-
function isOKResponse(code, codesCount) {
|
|
144
|
-
return codesCount === 1 || parseInt(code, 10) < 400;
|
|
145
|
-
}
|
|
146
|
-
//#endregion
|
|
147
|
-
//#region Private
|
|
148
|
-
function isMethod(method) {
|
|
149
|
-
return methods.includes(method);
|
|
150
|
-
}
|
|
151
|
-
exports.isMethod = isMethod;
|
|
152
|
-
//#endregion
|
|
153
|
-
//#region Private
|
|
154
|
-
function getTypeFromResponse(res, context) {
|
|
155
|
-
res = (0, core_parser_1.resolveReference)(res, context);
|
|
156
|
-
if (!(res === null || res === void 0 ? void 0 : res.content)) {
|
|
157
|
-
return core.keywordType.void;
|
|
158
|
-
}
|
|
159
|
-
return (0, core_parser_1.getTypeFromSchema)(getSchemaFromContent(res.content)[0], context);
|
|
160
|
-
}
|
|
161
|
-
function getSchemaFromContent(content) {
|
|
162
|
-
var _a;
|
|
163
|
-
const res = Object.entries(contentTypes).find(([t]) => t in content);
|
|
164
|
-
let schema;
|
|
165
|
-
let mode;
|
|
166
|
-
if (res) {
|
|
167
|
-
const [contentType, contentMode] = res;
|
|
168
|
-
mode = contentMode;
|
|
169
|
-
schema = (_a = content === null || content === void 0 ? void 0 : content[contentType]) === null || _a === void 0 ? void 0 : _a.schema;
|
|
170
|
-
}
|
|
171
|
-
return [schema || { type: "string" }, mode];
|
|
172
|
-
}
|
|
173
|
-
function resolveReferences(array, context) {
|
|
174
|
-
var _a;
|
|
175
|
-
return (_a = array === null || array === void 0 ? void 0 : array.map(ref => (0, core_parser_1.resolveReference)(ref, context))) !== null && _a !== void 0 ? _a : [];
|
|
176
|
-
}
|
|
177
|
-
function getReferenceName(obj) {
|
|
178
|
-
if ((0, core_parser_1.isReference)(obj)) {
|
|
179
|
-
return (0, util_1.camelCase)(obj.$ref.split("/").slice(-1)[0]);
|
|
180
|
-
}
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Despite its name, OpenApi's `deepObject` serialization does not support
|
|
184
|
-
* deeply nested objects. As a workaround we detect parameters that contain
|
|
185
|
-
* square brackets and merge them into a single object.
|
|
186
|
-
*/
|
|
187
|
-
function fixDeepObjects(params) {
|
|
188
|
-
const res = [];
|
|
189
|
-
const merged = {};
|
|
190
|
-
params.forEach((p) => {
|
|
191
|
-
const m = /^(.+?)\[(.*?)\]/.exec(p.name);
|
|
192
|
-
if (!m) {
|
|
193
|
-
res.push(p);
|
|
194
|
-
return;
|
|
195
|
-
}
|
|
196
|
-
const [, name, prop] = m;
|
|
197
|
-
let obj = merged[name];
|
|
198
|
-
if (!obj) {
|
|
199
|
-
obj = merged[name] = {
|
|
200
|
-
name,
|
|
201
|
-
in: p.in,
|
|
202
|
-
style: "deepObject",
|
|
203
|
-
schema: {
|
|
204
|
-
type: "object",
|
|
205
|
-
properties: {},
|
|
206
|
-
},
|
|
207
|
-
};
|
|
208
|
-
res.push(obj);
|
|
209
|
-
}
|
|
210
|
-
obj.schema.properties[prop] = p.schema;
|
|
211
|
-
});
|
|
212
|
-
return res;
|
|
213
|
-
}
|
|
214
|
-
function getOperationVar(verb, path, operationId, context) {
|
|
215
|
-
const id = getOperationVarId(operationId);
|
|
216
|
-
if (id) {
|
|
217
|
-
return id;
|
|
218
|
-
}
|
|
219
|
-
return getPathVar(`${verb} ${path}`, context);
|
|
220
|
-
}
|
|
221
|
-
function getPathVar(path, context) {
|
|
222
|
-
path = path.replace(/\{(.+?)\}/, "by $1").replace(/\{(.+?)\}/g, "and $1");
|
|
223
|
-
let name = (0, util_1.camelCase)(path);
|
|
224
|
-
const count = (context.names[name] = (context.names[name] || 0) + 1);
|
|
225
|
-
if (count > 1) {
|
|
226
|
-
name += count;
|
|
227
|
-
}
|
|
228
|
-
return name;
|
|
229
|
-
}
|
|
230
|
-
function getOperationVarId(id) {
|
|
231
|
-
if (!id)
|
|
232
|
-
return;
|
|
233
|
-
if (id.match(/[^\w\s]/))
|
|
234
|
-
return;
|
|
235
|
-
id = (0, util_1.camelCase)(id);
|
|
236
|
-
if (core.isValidIdentifier(id))
|
|
237
|
-
return id;
|
|
238
|
-
}
|
|
239
|
-
//#endregion
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
import * as ts from "typescript";
|
|
2
|
-
import type { OpenAPIObject } from "openapi3-ts/oas31";
|
|
3
|
-
import { ParserOptions } from "@spec2ts/jsonschema/lib/core-parser";
|
|
4
|
-
export interface OApiGeneratorOptions extends ParserOptions {
|
|
5
|
-
inlineRequired?: boolean;
|
|
6
|
-
importFetch?: "node-fetch" | "cross-fetch" | "isomorphic-fetch";
|
|
7
|
-
typesPath?: string;
|
|
8
|
-
baseUrl?: string;
|
|
9
|
-
prefix?: string;
|
|
10
|
-
}
|
|
11
|
-
export declare function generateClientFromFile(file: string, options: OApiGeneratorOptions & {
|
|
12
|
-
typesPath: string;
|
|
13
|
-
}): Promise<SeparatedClientResult>;
|
|
14
|
-
export declare function generateClientFromFile(file: string, options?: OApiGeneratorOptions): Promise<ts.SourceFile>;
|
|
15
|
-
export declare function generateClient(spec: OpenAPIObject, options: OApiGeneratorOptions & {
|
|
16
|
-
typesPath: string;
|
|
17
|
-
}): Promise<SeparatedClientResult>;
|
|
18
|
-
export declare function generateClient(spec: OpenAPIObject, options?: OApiGeneratorOptions): Promise<ts.SourceFile>;
|
|
19
|
-
export interface SeparatedClientResult {
|
|
20
|
-
client: ts.SourceFile;
|
|
21
|
-
types: ts.SourceFile;
|
|
22
|
-
}
|
package/lib/openapi-generator.js
DELETED
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.generateClient = exports.generateClientFromFile = void 0;
|
|
4
|
-
const path = require("path");
|
|
5
|
-
const ts = require("typescript");
|
|
6
|
-
const core = require("@spec2ts/core");
|
|
7
|
-
const json_schema_ref_parser_1 = require("@apidevtools/json-schema-ref-parser");
|
|
8
|
-
const core_parser_1 = require("@spec2ts/jsonschema/lib/core-parser");
|
|
9
|
-
const core_parser_2 = require("@spec2ts/openapi/lib/core-parser");
|
|
10
|
-
const core_generator_1 = require("./core-generator");
|
|
11
|
-
async function generateClientFromFile(file, options = {}) {
|
|
12
|
-
const schema = await json_schema_ref_parser_1.default.parse(file);
|
|
13
|
-
return generateClient(schema, {
|
|
14
|
-
cwd: path.resolve(path.dirname(file)) + "/",
|
|
15
|
-
...options
|
|
16
|
-
});
|
|
17
|
-
}
|
|
18
|
-
exports.generateClientFromFile = generateClientFromFile;
|
|
19
|
-
async function generateClient(spec, options = {}) {
|
|
20
|
-
if (!options.parseReference) {
|
|
21
|
-
options.parseReference = core_parser_2.parseReference;
|
|
22
|
-
}
|
|
23
|
-
const context = await (0, core_parser_1.createContext)(spec, options);
|
|
24
|
-
let file = await core.createSourceFileFromFile(__dirname + "/templates/_client.tpl.ts");
|
|
25
|
-
if (context.options.typesPath) {
|
|
26
|
-
context.typesFile = ts.createSourceFile("types.ts", "", ts.ScriptTarget.Latest, false, ts.ScriptKind.TS);
|
|
27
|
-
}
|
|
28
|
-
file = (0, core_generator_1.generateServers)(file, spec, context);
|
|
29
|
-
file = (0, core_generator_1.generateDefaults)(file, context);
|
|
30
|
-
file = (0, core_generator_1.generateFunctions)(file, spec, context);
|
|
31
|
-
if (context.options.typesPath) {
|
|
32
|
-
return {
|
|
33
|
-
client: file,
|
|
34
|
-
types: context.typesFile
|
|
35
|
-
};
|
|
36
|
-
}
|
|
37
|
-
return file;
|
|
38
|
-
}
|
|
39
|
-
exports.generateClient = generateClient;
|
package/lib/server-parser.d.ts
DELETED
package/lib/server-parser.js
DELETED
|
@@ -1,79 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.defaultBaseUrl = exports.parseServers = void 0;
|
|
4
|
-
const ts = require("typescript");
|
|
5
|
-
const core = require("@spec2ts/core");
|
|
6
|
-
const util_1 = require("./util");
|
|
7
|
-
function parseServers(servers) {
|
|
8
|
-
const props = servers.map((server, i) => [serverName(server, i), generateServerExpression(server)]);
|
|
9
|
-
return core.createObjectLiteral(props);
|
|
10
|
-
}
|
|
11
|
-
exports.parseServers = parseServers;
|
|
12
|
-
function defaultBaseUrl(servers) {
|
|
13
|
-
return ts.factory.createStringLiteral(defaultUrl(servers[0]));
|
|
14
|
-
}
|
|
15
|
-
exports.defaultBaseUrl = defaultBaseUrl;
|
|
16
|
-
function serverName(server, index) {
|
|
17
|
-
return server.description ?
|
|
18
|
-
(0, util_1.camelCase)(server.description.replace(/\W+/, " ")) :
|
|
19
|
-
`server${index + 1}`;
|
|
20
|
-
}
|
|
21
|
-
function generateServerExpression(server) {
|
|
22
|
-
return server.variables ?
|
|
23
|
-
createServerFunction(server.url, server.variables) :
|
|
24
|
-
ts.factory.createStringLiteral(server.url);
|
|
25
|
-
}
|
|
26
|
-
function createServerFunction(template, vars) {
|
|
27
|
-
const params = [
|
|
28
|
-
core.createParameter(core.createObjectBinding(Object.entries(vars || {}).map(([name, value]) => {
|
|
29
|
-
return {
|
|
30
|
-
name,
|
|
31
|
-
initializer: createLiteral(value.default),
|
|
32
|
-
};
|
|
33
|
-
})), {
|
|
34
|
-
type: ts.factory.createTypeLiteralNode(Object.entries(vars || {}).map(([name, value]) => {
|
|
35
|
-
return core.createPropertySignature({
|
|
36
|
-
name,
|
|
37
|
-
type: value.enum ?
|
|
38
|
-
ts.factory.createUnionTypeNode(createUnion(value.enum)) :
|
|
39
|
-
ts.factory.createUnionTypeNode([
|
|
40
|
-
core.keywordType.string,
|
|
41
|
-
core.keywordType.number,
|
|
42
|
-
core.keywordType.boolean,
|
|
43
|
-
]),
|
|
44
|
-
});
|
|
45
|
-
})),
|
|
46
|
-
}),
|
|
47
|
-
];
|
|
48
|
-
return core.createArrowFunction(params, createTemplate(template));
|
|
49
|
-
}
|
|
50
|
-
function createUnion(strs) {
|
|
51
|
-
return strs.map((e) => ts.factory.createLiteralTypeNode(createLiteral(e)));
|
|
52
|
-
}
|
|
53
|
-
function createTemplate(url) {
|
|
54
|
-
const tokens = url.split(/{([\s\S]+?)}/g);
|
|
55
|
-
const spans = [];
|
|
56
|
-
const len = tokens.length;
|
|
57
|
-
for (let i = 1; i < len; i += 2) {
|
|
58
|
-
spans.push(ts.factory.createTemplateSpan(ts.factory.createIdentifier(tokens[i]), (i === len - 2 ? ts.factory.createTemplateTail : ts.factory.createTemplateMiddle)(tokens[i + 1])));
|
|
59
|
-
}
|
|
60
|
-
return ts.factory.createTemplateExpression(ts.factory.createTemplateHead(tokens[0]), spans);
|
|
61
|
-
}
|
|
62
|
-
function createLiteral(v) {
|
|
63
|
-
switch (typeof v) {
|
|
64
|
-
case "string":
|
|
65
|
-
return ts.factory.createStringLiteral(v);
|
|
66
|
-
case "boolean":
|
|
67
|
-
return v ? ts.factory.createTrue() : ts.factory.createFalse();
|
|
68
|
-
case "number":
|
|
69
|
-
return ts.factory.createNumericLiteral(String(v));
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function defaultUrl(server) {
|
|
73
|
-
if (!server)
|
|
74
|
-
return "/";
|
|
75
|
-
const { url, variables } = server;
|
|
76
|
-
if (!variables)
|
|
77
|
-
return url;
|
|
78
|
-
return url.replace(/\{(.+?)\}/g, (m, name) => variables[name] ? String(variables[name].default) : m);
|
|
79
|
-
}
|
|
@@ -1,81 +0,0 @@
|
|
|
1
|
-
export declare const defaults: RequestOptions;
|
|
2
|
-
export declare const servers: {};
|
|
3
|
-
export type RequestOptions = {
|
|
4
|
-
baseUrl?: string;
|
|
5
|
-
fetch?: typeof fetch;
|
|
6
|
-
headers?: Record<string, string | undefined>;
|
|
7
|
-
} & Omit<RequestInit, "body" | "headers">;
|
|
8
|
-
export type ApiResponse<T> = {
|
|
9
|
-
status: number;
|
|
10
|
-
statusText: string;
|
|
11
|
-
headers: Record<string, string>;
|
|
12
|
-
data: T;
|
|
13
|
-
};
|
|
14
|
-
type Encoders = Array<(s: string) => string>;
|
|
15
|
-
type TagFunction = (strings: TemplateStringsArray, ...values: any[]) => string;
|
|
16
|
-
type FetchRequestOptions = RequestOptions & {
|
|
17
|
-
body?: string | FormData;
|
|
18
|
-
};
|
|
19
|
-
type JsonRequestOptions = RequestOptions & {
|
|
20
|
-
body: unknown;
|
|
21
|
-
};
|
|
22
|
-
type FormRequestOptions<T extends Record<string, unknown>> = RequestOptions & {
|
|
23
|
-
body: T;
|
|
24
|
-
};
|
|
25
|
-
type MultipartRequestOptions = RequestOptions & {
|
|
26
|
-
body: Record<string, any>;
|
|
27
|
-
};
|
|
28
|
-
/** Utilities functions */
|
|
29
|
-
export declare const _: {
|
|
30
|
-
encodeReserved: (typeof encodeURI)[];
|
|
31
|
-
allowReserved: (typeof encodeURI)[];
|
|
32
|
-
/** Deeply remove all properties with undefined values. */
|
|
33
|
-
stripUndefined<T extends Record<string, U | undefined>, U>(obj?: T | undefined): Record<string, U> | undefined;
|
|
34
|
-
isEmpty(v: unknown): boolean;
|
|
35
|
-
/** Creates a tag-function to encode template strings with the given encoders. */
|
|
36
|
-
encode(encoders: Encoders, delimiter?: string): TagFunction;
|
|
37
|
-
/** Separate array values by the given delimiter. */
|
|
38
|
-
delimited(delimiter?: string): (params: Record<string, any>, encoders?: Encoders) => string;
|
|
39
|
-
/** Join URLs parts. */
|
|
40
|
-
joinUrl(...parts: Array<string | undefined>): string;
|
|
41
|
-
};
|
|
42
|
-
/** Functions to serialize query parameters in different styles. */
|
|
43
|
-
export declare const QS: {
|
|
44
|
-
/** Join params using an ampersand and prepends a questionmark if not empty. */
|
|
45
|
-
query(...params: string[]): string;
|
|
46
|
-
/**
|
|
47
|
-
* Serializes nested objects according to the `deepObject` style specified in
|
|
48
|
-
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#style-values
|
|
49
|
-
*/
|
|
50
|
-
deep(params: Record<string, any>, [k, v]?: (typeof encodeURI)[]): string;
|
|
51
|
-
/**
|
|
52
|
-
* Property values of type array or object generate separate parameters
|
|
53
|
-
* for each value of the array, or key-value-pair of the map.
|
|
54
|
-
* For other types of properties this property has no effect.
|
|
55
|
-
* See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#encoding-object
|
|
56
|
-
*/
|
|
57
|
-
explode(params: Record<string, any>, encoders?: (typeof encodeURI)[]): string;
|
|
58
|
-
form: (params: Record<string, any>, encoders?: Encoders) => string;
|
|
59
|
-
pipe: (params: Record<string, any>, encoders?: Encoders) => string;
|
|
60
|
-
space: (params: Record<string, any>, encoders?: Encoders) => string;
|
|
61
|
-
};
|
|
62
|
-
/** Http request base methods. */
|
|
63
|
-
export declare const http: {
|
|
64
|
-
fetch(url: string, req?: FetchRequestOptions): Promise<ApiResponse<string | undefined>>;
|
|
65
|
-
fetchJson(url: string, req?: FetchRequestOptions): Promise<ApiResponse<any>>;
|
|
66
|
-
fetchVoid(url: string, req?: FetchRequestOptions): Promise<ApiResponse<undefined>>;
|
|
67
|
-
json({ body, headers, ...req }: JsonRequestOptions): FetchRequestOptions;
|
|
68
|
-
form<T extends Record<string, unknown>>({ body, headers, ...req }: FormRequestOptions<T>): FetchRequestOptions;
|
|
69
|
-
multipart({ body, ...req }: MultipartRequestOptions): FetchRequestOptions;
|
|
70
|
-
headers(headers: Headers): Record<string, string>;
|
|
71
|
-
};
|
|
72
|
-
export declare class HttpError extends Error {
|
|
73
|
-
status: number;
|
|
74
|
-
statusText: string;
|
|
75
|
-
headers: Record<string, string>;
|
|
76
|
-
data?: Record<string, unknown>;
|
|
77
|
-
constructor(status: number, statusText: string, url: string, headers: Headers, text?: string);
|
|
78
|
-
}
|
|
79
|
-
/** Utility Type to extract returns type from a method. */
|
|
80
|
-
export type ApiResult<Fn> = Fn extends (...args: any) => Promise<ApiResponse<infer T>> ? T : never;
|
|
81
|
-
export {};
|
|
@@ -1,204 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.HttpError = exports.http = exports.QS = exports._ = exports.servers = exports.defaults = void 0;
|
|
4
|
-
exports.defaults = {
|
|
5
|
-
baseUrl: "/",
|
|
6
|
-
};
|
|
7
|
-
exports.servers = {};
|
|
8
|
-
/** Utilities functions */
|
|
9
|
-
exports._ = {
|
|
10
|
-
// Encode param names and values as URIComponent
|
|
11
|
-
encodeReserved: [encodeURI, encodeURIComponent],
|
|
12
|
-
allowReserved: [encodeURI, encodeURI],
|
|
13
|
-
/** Deeply remove all properties with undefined values. */
|
|
14
|
-
stripUndefined(obj) {
|
|
15
|
-
return obj && JSON.parse(JSON.stringify(obj));
|
|
16
|
-
},
|
|
17
|
-
isEmpty(v) {
|
|
18
|
-
return typeof v === "object" && !!v ?
|
|
19
|
-
Object.keys(v).length === 0 && v.constructor === Object :
|
|
20
|
-
v === undefined;
|
|
21
|
-
},
|
|
22
|
-
/** Creates a tag-function to encode template strings with the given encoders. */
|
|
23
|
-
encode(encoders, delimiter = ",") {
|
|
24
|
-
return (strings, ...values) => {
|
|
25
|
-
return strings.reduce((prev, s, i) => { var _a; return `${prev}${s}${q((_a = values[i]) !== null && _a !== void 0 ? _a : "", i)}`; }, "");
|
|
26
|
-
};
|
|
27
|
-
function q(v, i) {
|
|
28
|
-
const encoder = encoders[i % encoders.length];
|
|
29
|
-
if (typeof v === "object") {
|
|
30
|
-
if (Array.isArray(v)) {
|
|
31
|
-
return v.map(encoder).join(delimiter);
|
|
32
|
-
}
|
|
33
|
-
const flat = Object.entries(v).reduce((flat, entry) => [...flat, ...entry], []);
|
|
34
|
-
return flat.map(encoder).join(delimiter);
|
|
35
|
-
}
|
|
36
|
-
return encoder(String(v));
|
|
37
|
-
}
|
|
38
|
-
},
|
|
39
|
-
/** Separate array values by the given delimiter. */
|
|
40
|
-
delimited(delimiter = ",") {
|
|
41
|
-
return (params, encoders = exports._.encodeReserved) => Object.entries(params)
|
|
42
|
-
.filter(([, value]) => !exports._.isEmpty(value))
|
|
43
|
-
.map(([name, value]) => exports._.encode(encoders, delimiter) `${name}=${value}`)
|
|
44
|
-
.join("&");
|
|
45
|
-
},
|
|
46
|
-
/** Join URLs parts. */
|
|
47
|
-
joinUrl(...parts) {
|
|
48
|
-
return parts
|
|
49
|
-
.filter(Boolean)
|
|
50
|
-
.join("/")
|
|
51
|
-
.replace(/([^:]\/)\/+/, "$1");
|
|
52
|
-
}
|
|
53
|
-
};
|
|
54
|
-
/** Functions to serialize query parameters in different styles. */
|
|
55
|
-
exports.QS = {
|
|
56
|
-
/** Join params using an ampersand and prepends a questionmark if not empty. */
|
|
57
|
-
query(...params) {
|
|
58
|
-
const s = params.filter(p => !!p).join("&");
|
|
59
|
-
return s && `?${s}`;
|
|
60
|
-
},
|
|
61
|
-
/**
|
|
62
|
-
* Serializes nested objects according to the `deepObject` style specified in
|
|
63
|
-
* https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#style-values
|
|
64
|
-
*/
|
|
65
|
-
deep(params, [k, v] = exports._.encodeReserved) {
|
|
66
|
-
const qk = exports._.encode([(s) => s, k]);
|
|
67
|
-
const qv = exports._.encode([(s) => s, v]);
|
|
68
|
-
// don't add index to arrays
|
|
69
|
-
// https://github.com/expressjs/body-parser/issues/289
|
|
70
|
-
const visit = (obj, prefix = "") => Object.entries(obj)
|
|
71
|
-
.filter(([, v]) => !exports._.isEmpty(v))
|
|
72
|
-
.map(([prop, v]) => {
|
|
73
|
-
const isValueObject = typeof v === "object";
|
|
74
|
-
const index = Array.isArray(obj) && !isValueObject ? "" : prop;
|
|
75
|
-
const key = prefix ? qk `${prefix}[${index}]` : prop;
|
|
76
|
-
if (isValueObject) {
|
|
77
|
-
return visit(v, key);
|
|
78
|
-
}
|
|
79
|
-
return qv `${key}=${v}`;
|
|
80
|
-
})
|
|
81
|
-
.join("&");
|
|
82
|
-
return visit(params);
|
|
83
|
-
},
|
|
84
|
-
/**
|
|
85
|
-
* Property values of type array or object generate separate parameters
|
|
86
|
-
* for each value of the array, or key-value-pair of the map.
|
|
87
|
-
* For other types of properties this property has no effect.
|
|
88
|
-
* See https://github.com/OAI/OpenAPI-Specification/blob/master/versions/3.0.0.md#encoding-object
|
|
89
|
-
*/
|
|
90
|
-
explode(params, encoders = exports._.encodeReserved) {
|
|
91
|
-
const q = exports._.encode(encoders);
|
|
92
|
-
return Object.entries(params)
|
|
93
|
-
.filter(([, value]) => typeof value !== "undefined")
|
|
94
|
-
.map(([name, value]) => {
|
|
95
|
-
if (Array.isArray(value)) {
|
|
96
|
-
return value.map((v) => q `${name}=${v}`).join("&");
|
|
97
|
-
}
|
|
98
|
-
if (typeof value === "object") {
|
|
99
|
-
return exports.QS.explode(value, encoders);
|
|
100
|
-
}
|
|
101
|
-
return q `${name}=${value}`;
|
|
102
|
-
})
|
|
103
|
-
.join("&");
|
|
104
|
-
},
|
|
105
|
-
form: exports._.delimited(),
|
|
106
|
-
pipe: exports._.delimited("|"),
|
|
107
|
-
space: exports._.delimited("%20"),
|
|
108
|
-
};
|
|
109
|
-
/** Http request base methods. */
|
|
110
|
-
exports.http = {
|
|
111
|
-
async fetch(url, req) {
|
|
112
|
-
const { baseUrl, headers, fetch: customFetch, ...init } = { ...exports.defaults, ...req };
|
|
113
|
-
const href = exports._.joinUrl(baseUrl, url);
|
|
114
|
-
const res = await (customFetch || fetch)(href, {
|
|
115
|
-
...init,
|
|
116
|
-
headers: exports._.stripUndefined({ ...exports.defaults.headers, ...headers }),
|
|
117
|
-
});
|
|
118
|
-
let text;
|
|
119
|
-
try {
|
|
120
|
-
text = await res.text();
|
|
121
|
-
}
|
|
122
|
-
catch (err) { /* ok */ }
|
|
123
|
-
if (!res.ok) {
|
|
124
|
-
throw new HttpError(res.status, res.statusText, href, res.headers, text);
|
|
125
|
-
}
|
|
126
|
-
return {
|
|
127
|
-
status: res.status,
|
|
128
|
-
statusText: res.statusText,
|
|
129
|
-
headers: exports.http.headers(res.headers),
|
|
130
|
-
data: text
|
|
131
|
-
};
|
|
132
|
-
},
|
|
133
|
-
async fetchJson(url, req = {}) {
|
|
134
|
-
const res = await exports.http.fetch(url, {
|
|
135
|
-
...req,
|
|
136
|
-
headers: {
|
|
137
|
-
...req.headers,
|
|
138
|
-
Accept: "application/json",
|
|
139
|
-
},
|
|
140
|
-
});
|
|
141
|
-
res.data = res.data && JSON.parse(res.data);
|
|
142
|
-
return res;
|
|
143
|
-
},
|
|
144
|
-
async fetchVoid(url, req = {}) {
|
|
145
|
-
const res = await exports.http.fetch(url, {
|
|
146
|
-
...req,
|
|
147
|
-
headers: {
|
|
148
|
-
...req.headers,
|
|
149
|
-
Accept: "application/json",
|
|
150
|
-
},
|
|
151
|
-
});
|
|
152
|
-
return res;
|
|
153
|
-
},
|
|
154
|
-
json({ body, headers, ...req }) {
|
|
155
|
-
return {
|
|
156
|
-
...req,
|
|
157
|
-
body: JSON.stringify(body),
|
|
158
|
-
headers: {
|
|
159
|
-
...headers,
|
|
160
|
-
"Content-Type": "application/json",
|
|
161
|
-
},
|
|
162
|
-
};
|
|
163
|
-
},
|
|
164
|
-
form({ body, headers, ...req }) {
|
|
165
|
-
return {
|
|
166
|
-
...req,
|
|
167
|
-
body: exports.QS.form(body),
|
|
168
|
-
headers: {
|
|
169
|
-
...headers,
|
|
170
|
-
"Content-Type": "application/x-www-form-urlencoded",
|
|
171
|
-
},
|
|
172
|
-
};
|
|
173
|
-
},
|
|
174
|
-
multipart({ body, ...req }) {
|
|
175
|
-
const data = new FormData();
|
|
176
|
-
Object.entries(body).forEach(([name, value]) => {
|
|
177
|
-
data.append(name, value);
|
|
178
|
-
});
|
|
179
|
-
return {
|
|
180
|
-
...req,
|
|
181
|
-
body: data,
|
|
182
|
-
};
|
|
183
|
-
},
|
|
184
|
-
headers(headers) {
|
|
185
|
-
const res = {};
|
|
186
|
-
headers.forEach((value, key) => res[key] = value);
|
|
187
|
-
return res;
|
|
188
|
-
}
|
|
189
|
-
};
|
|
190
|
-
class HttpError extends Error {
|
|
191
|
-
constructor(status, statusText, url, headers, text) {
|
|
192
|
-
super(`${url} - ${statusText} (${status})`);
|
|
193
|
-
this.status = status;
|
|
194
|
-
this.statusText = statusText;
|
|
195
|
-
this.headers = exports.http.headers(headers);
|
|
196
|
-
if (text) {
|
|
197
|
-
try {
|
|
198
|
-
this.data = JSON.parse(text);
|
|
199
|
-
}
|
|
200
|
-
catch (err) { /* ok */ }
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
}
|
|
204
|
-
exports.HttpError = HttpError;
|