@typia/utils 12.0.0-dev.20260309 → 12.0.0-dev.20260310
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/lib/http/internal/HttpLlmApplicationComposer.mjs +5 -1
- package/lib/http/internal/HttpLlmApplicationComposer.mjs.map +1 -1
- package/lib/index.mjs +9 -9
- package/lib/utils/LlmJson.mjs +9 -2
- package/lib/utils/LlmJson.mjs.map +1 -1
- package/lib/utils/internal/stringifyValidationFailure.js +17 -15
- package/lib/utils/internal/stringifyValidationFailure.js.map +1 -1
- package/lib/utils/internal/stringifyValidationFailure.mjs +17 -15
- package/lib/utils/internal/stringifyValidationFailure.mjs.map +1 -1
- package/lib/validators/internal/OpenApiOneOfValidator.mjs +5 -1
- package/lib/validators/internal/OpenApiOneOfValidator.mjs.map +1 -1
- package/package.json +2 -2
- package/src/converters/LlmSchemaConverter.ts +647 -647
- package/src/converters/OpenApiConverter.ts +285 -285
- package/src/converters/index.ts +5 -5
- package/src/converters/internal/LlmDescriptionInverter.ts +178 -178
- package/src/converters/internal/LlmParametersComposer.ts +52 -52
- package/src/converters/internal/OpenApiConstraintShifter.ts +154 -154
- package/src/converters/internal/OpenApiExclusiveEmender.ts +46 -46
- package/src/converters/internal/OpenApiV3Downgrader.ts +355 -355
- package/src/converters/internal/OpenApiV3Upgrader.ts +470 -470
- package/src/converters/internal/OpenApiV3_1Upgrader.ts +685 -685
- package/src/converters/internal/SwaggerV2Downgrader.ts +424 -424
- package/src/converters/internal/SwaggerV2Upgrader.ts +523 -523
- package/src/http/HttpError.ts +107 -107
- package/src/http/HttpLlm.ts +167 -167
- package/src/http/HttpMigration.ts +92 -92
- package/src/http/index.ts +3 -3
- package/src/http/internal/HttpLlmApplicationComposer.ts +361 -361
- package/src/http/internal/HttpLlmFunctionFetcher.ts +37 -37
- package/src/http/internal/HttpMigrateApplicationComposer.ts +56 -56
- package/src/http/internal/HttpMigrateRouteAccessor.ts +135 -135
- package/src/http/internal/HttpMigrateRouteComposer.ts +505 -505
- package/src/http/internal/HttpMigrateRouteFetcher.ts +203 -203
- package/src/index.ts +4 -4
- package/src/utils/ArrayUtil.ts +42 -42
- package/src/utils/LlmJson.ts +141 -141
- package/src/utils/MapUtil.ts +15 -15
- package/src/utils/NamingConvention.ts +205 -205
- package/src/utils/Singleton.ts +17 -17
- package/src/utils/StringUtil.ts +14 -14
- package/src/utils/dedent.ts +57 -57
- package/src/utils/index.ts +8 -8
- package/src/utils/internal/EndpointUtil.ts +44 -44
- package/src/utils/internal/JsonDescriptor.ts +70 -70
- package/src/utils/internal/OpenApiTypeCheckerBase.ts +822 -822
- package/src/utils/internal/coerceLlmArguments.ts +314 -314
- package/src/utils/internal/parseLenientJson.ts +894 -894
- package/src/utils/internal/stringifyValidationFailure.ts +415 -411
- package/src/validators/LlmTypeChecker.ts +402 -402
- package/src/validators/OpenApiTypeChecker.ts +297 -297
- package/src/validators/OpenApiV3TypeChecker.ts +70 -70
- package/src/validators/OpenApiV3_1TypeChecker.ts +86 -86
- package/src/validators/OpenApiValidator.ts +94 -94
- package/src/validators/SwaggerV2TypeChecker.ts +71 -71
- package/src/validators/functional/_isBigintString.ts +8 -8
- package/src/validators/functional/_isFormatByte.ts +7 -7
- package/src/validators/functional/_isFormatDate.ts +3 -3
- package/src/validators/functional/_isFormatDateTime.ts +4 -4
- package/src/validators/functional/_isFormatDuration.ts +4 -4
- package/src/validators/functional/_isFormatEmail.ts +4 -4
- package/src/validators/functional/_isFormatHostname.ts +4 -4
- package/src/validators/functional/_isFormatIdnEmail.ts +4 -4
- package/src/validators/functional/_isFormatIdnHostname.ts +4 -4
- package/src/validators/functional/_isFormatIpv4.ts +4 -4
- package/src/validators/functional/_isFormatIpv6.ts +4 -4
- package/src/validators/functional/_isFormatIri.ts +3 -3
- package/src/validators/functional/_isFormatIriReference.ts +4 -4
- package/src/validators/functional/_isFormatJsonPointer.ts +3 -3
- package/src/validators/functional/_isFormatPassword.ts +1 -1
- package/src/validators/functional/_isFormatRegex.ts +8 -8
- package/src/validators/functional/_isFormatRelativeJsonPointer.ts +4 -4
- package/src/validators/functional/_isFormatTime.ts +4 -4
- package/src/validators/functional/_isFormatUri.ts +6 -6
- package/src/validators/functional/_isFormatUriReference.ts +5 -5
- package/src/validators/functional/_isFormatUriTemplate.ts +4 -4
- package/src/validators/functional/_isFormatUrl.ts +4 -4
- package/src/validators/functional/_isFormatUuid.ts +3 -3
- package/src/validators/functional/_isUniqueItems.ts +159 -159
- package/src/validators/index.ts +14 -14
- package/src/validators/internal/IOpenApiValidatorContext.ts +17 -17
- package/src/validators/internal/OpenApiArrayValidator.ts +49 -49
- package/src/validators/internal/OpenApiBooleanValidator.ts +11 -11
- package/src/validators/internal/OpenApiConstantValidator.ts +11 -11
- package/src/validators/internal/OpenApiIntegerValidator.ts +49 -49
- package/src/validators/internal/OpenApiNumberValidator.ts +48 -48
- package/src/validators/internal/OpenApiObjectValidator.ts +83 -83
- package/src/validators/internal/OpenApiOneOfValidator.ts +309 -309
- package/src/validators/internal/OpenApiSchemaNamingRule.ts +124 -124
- package/src/validators/internal/OpenApiStationValidator.ts +115 -115
- package/src/validators/internal/OpenApiStringValidator.ts +88 -88
- package/src/validators/internal/OpenApiTupleValidator.ts +55 -55
|
@@ -1,203 +1,203 @@
|
|
|
1
|
-
import { IHttpConnection, IHttpResponse } from "@typia/interface";
|
|
2
|
-
|
|
3
|
-
import { HttpError } from "../HttpError";
|
|
4
|
-
import type { HttpMigration } from "../HttpMigration";
|
|
5
|
-
|
|
6
|
-
export namespace HttpMigrateRouteFetcher {
|
|
7
|
-
export const execute = async (
|
|
8
|
-
props: HttpMigration.IFetchProps,
|
|
9
|
-
): Promise<unknown> => {
|
|
10
|
-
const result: IHttpResponse = await _Propagate("request", props);
|
|
11
|
-
props.route.success?.media;
|
|
12
|
-
if (result.status !== 200 && result.status !== 201)
|
|
13
|
-
throw new HttpError(
|
|
14
|
-
props.route.method.toUpperCase() as "GET",
|
|
15
|
-
props.route.path,
|
|
16
|
-
result.status,
|
|
17
|
-
result.headers,
|
|
18
|
-
result.body as string,
|
|
19
|
-
);
|
|
20
|
-
return result.body;
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
export const propagate = (
|
|
24
|
-
props: HttpMigration.IFetchProps,
|
|
25
|
-
): Promise<IHttpResponse> => _Propagate("propagate", props);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
const _Propagate = async (
|
|
29
|
-
from: string,
|
|
30
|
-
props: HttpMigration.IFetchProps,
|
|
31
|
-
): Promise<IHttpResponse> => {
|
|
32
|
-
// VALIDATE PARAMETERS
|
|
33
|
-
const error = (message: string) =>
|
|
34
|
-
new Error(`Error on MigrateRouteFetcher.${from}(): ${message}`);
|
|
35
|
-
if (Array.isArray(props.parameters)) {
|
|
36
|
-
if (props.route.parameters.length !== props.parameters.length)
|
|
37
|
-
throw error(`number of parameters is not matched.`);
|
|
38
|
-
} else if (
|
|
39
|
-
props.route.parameters.every(
|
|
40
|
-
(p) => (props.parameters as Record<string, any>)[p.key] !== undefined,
|
|
41
|
-
) === false
|
|
42
|
-
)
|
|
43
|
-
throw error(`number of parameters is not matched.`);
|
|
44
|
-
|
|
45
|
-
// VALIDATE QUERY
|
|
46
|
-
if (!!props.route.query !== !!props.query)
|
|
47
|
-
throw error(`query is not matched.`);
|
|
48
|
-
else if (!!props.route.body !== (props.body !== undefined))
|
|
49
|
-
throw error(`body is not matched.`);
|
|
50
|
-
|
|
51
|
-
// INIT REQUEST DATA
|
|
52
|
-
const headers: Record<string, IHttpConnection.HeaderValue | undefined> = {
|
|
53
|
-
...(props.connection.headers ?? {}),
|
|
54
|
-
...(props.route.body?.type &&
|
|
55
|
-
props.route.body.type !== "multipart/form-data"
|
|
56
|
-
? { "Content-Type": props.route.body.type }
|
|
57
|
-
: {}),
|
|
58
|
-
};
|
|
59
|
-
const init: RequestInit = {
|
|
60
|
-
...(props.connection.options ?? {}),
|
|
61
|
-
method: props.route.method.toUpperCase(),
|
|
62
|
-
headers: (() => {
|
|
63
|
-
const output: [string, string][] = [];
|
|
64
|
-
for (const [key, value] of Object.entries(headers))
|
|
65
|
-
if (value === undefined) continue;
|
|
66
|
-
else if (Array.isArray(value))
|
|
67
|
-
for (const v of value) output.push([key, String(v)]);
|
|
68
|
-
else output.push([key, String(value)]);
|
|
69
|
-
return output;
|
|
70
|
-
})(),
|
|
71
|
-
};
|
|
72
|
-
if (props.body !== undefined)
|
|
73
|
-
init.body = (
|
|
74
|
-
props.route.body?.type === "application/x-www-form-urlencoded"
|
|
75
|
-
? requestQueryBody(props.body)
|
|
76
|
-
: props.route.body?.type === "multipart/form-data"
|
|
77
|
-
? requestFormDataBody(props.body)
|
|
78
|
-
: props.route.body?.type === "application/json"
|
|
79
|
-
? JSON.stringify(props.body)
|
|
80
|
-
: props.body
|
|
81
|
-
) as any;
|
|
82
|
-
|
|
83
|
-
// DO REQUEST
|
|
84
|
-
const resolvedPath: string =
|
|
85
|
-
props.connection.host.endsWith("/") === false &&
|
|
86
|
-
props.route.emendedPath.startsWith("/") === false
|
|
87
|
-
? `/${getPath(props)}`
|
|
88
|
-
: getPath(props);
|
|
89
|
-
const url: URL = new URL(`${props.connection.host}${resolvedPath}`);
|
|
90
|
-
|
|
91
|
-
const response: Response = await (props.connection.fetch ?? fetch)(url, init);
|
|
92
|
-
const status: number = response.status;
|
|
93
|
-
const out = (body: unknown): IHttpResponse => ({
|
|
94
|
-
status,
|
|
95
|
-
headers: responseHeaders(response.headers),
|
|
96
|
-
body,
|
|
97
|
-
});
|
|
98
|
-
|
|
99
|
-
if (status === 200 || status === 201) {
|
|
100
|
-
// SUCCESS CASE
|
|
101
|
-
if (props.route.method.toUpperCase() === "HEAD") return out(undefined);
|
|
102
|
-
else if (
|
|
103
|
-
props.route.success === null ||
|
|
104
|
-
props.route.success.type === "text/plain"
|
|
105
|
-
)
|
|
106
|
-
return out(await response.text());
|
|
107
|
-
else if (props.route.success.type === "application/json") {
|
|
108
|
-
const text: string = await response.text();
|
|
109
|
-
return out(text.length ? JSON.parse(text) : undefined);
|
|
110
|
-
} else if (props.route.success.type === "application/x-www-form-urlencoded")
|
|
111
|
-
return out(new URLSearchParams(await response.text()));
|
|
112
|
-
else if (props.route.success.type === "multipart/form-data")
|
|
113
|
-
return out(await response.formData());
|
|
114
|
-
throw error("Unsupported response body type.");
|
|
115
|
-
} else {
|
|
116
|
-
// FAILURE CASE
|
|
117
|
-
const type: string = (
|
|
118
|
-
response.headers.get("content-type") ??
|
|
119
|
-
response.headers.get("Content-Type") ??
|
|
120
|
-
""
|
|
121
|
-
)
|
|
122
|
-
.split(";")[0]!
|
|
123
|
-
.trim();
|
|
124
|
-
if (type === "" || type.startsWith("text/"))
|
|
125
|
-
return out(await response.text());
|
|
126
|
-
else if (type === "application/json") return out(await response.json());
|
|
127
|
-
else if (type === "application/x-www-form-urlencoded")
|
|
128
|
-
return out(new URLSearchParams(await response.text()));
|
|
129
|
-
else if (type === "multipart/form-data")
|
|
130
|
-
return out(await response.formData());
|
|
131
|
-
else if (type === "application/octet-stream")
|
|
132
|
-
return out(await response.blob());
|
|
133
|
-
return out(await response.text());
|
|
134
|
-
}
|
|
135
|
-
};
|
|
136
|
-
|
|
137
|
-
const getPath = (
|
|
138
|
-
props: Pick<HttpMigration.IFetchProps, "route" | "parameters" | "query">,
|
|
139
|
-
): string => {
|
|
140
|
-
let path: string = props.route.emendedPath;
|
|
141
|
-
props.route.parameters.forEach((p, i) => {
|
|
142
|
-
path = path.replace(
|
|
143
|
-
`:${p.key}`,
|
|
144
|
-
encodeURIComponent(
|
|
145
|
-
String(
|
|
146
|
-
(Array.isArray(props.parameters)
|
|
147
|
-
? props.parameters[i]
|
|
148
|
-
: props.parameters[p.key]) ?? "null",
|
|
149
|
-
),
|
|
150
|
-
),
|
|
151
|
-
);
|
|
152
|
-
});
|
|
153
|
-
if (props.route.query) path += getQueryPath(props.query ?? {});
|
|
154
|
-
return path;
|
|
155
|
-
};
|
|
156
|
-
|
|
157
|
-
const getQueryPath = (query: Record<string, any>): string => {
|
|
158
|
-
const variables = new URLSearchParams();
|
|
159
|
-
for (const [key, value] of Object.entries(query))
|
|
160
|
-
if (undefined === value) continue;
|
|
161
|
-
else if (Array.isArray(value))
|
|
162
|
-
value.forEach((elem: any) => variables.append(key, String(elem)));
|
|
163
|
-
else variables.set(key, String(value));
|
|
164
|
-
return 0 === variables.size ? "" : `?${variables.toString()}`;
|
|
165
|
-
};
|
|
166
|
-
|
|
167
|
-
const requestQueryBody = (input: any): URLSearchParams => {
|
|
168
|
-
const q: URLSearchParams = new URLSearchParams();
|
|
169
|
-
for (const [key, value] of Object.entries(input))
|
|
170
|
-
if (value === undefined) continue;
|
|
171
|
-
else if (Array.isArray(value))
|
|
172
|
-
value.forEach((elem) => q.append(key, String(elem)));
|
|
173
|
-
else q.set(key, String(value));
|
|
174
|
-
return q;
|
|
175
|
-
};
|
|
176
|
-
const requestFormDataBody = (input: Record<string, any>): FormData => {
|
|
177
|
-
const encoded: FormData = new FormData();
|
|
178
|
-
const append = (key: string) => (value: any) => {
|
|
179
|
-
if (value === undefined) return;
|
|
180
|
-
else if (typeof File === "function" && value instanceof File)
|
|
181
|
-
encoded.append(key, value, value.name);
|
|
182
|
-
else encoded.append(key, value);
|
|
183
|
-
};
|
|
184
|
-
for (const [key, value] of Object.entries(input))
|
|
185
|
-
if (Array.isArray(value)) value.map(append(key));
|
|
186
|
-
else append(key)(value);
|
|
187
|
-
return encoded;
|
|
188
|
-
};
|
|
189
|
-
|
|
190
|
-
const responseHeaders = (
|
|
191
|
-
headers: Headers,
|
|
192
|
-
): Record<string, string | string[]> => {
|
|
193
|
-
const output: Record<string, string | string[]> = {};
|
|
194
|
-
headers.forEach((value, key) => {
|
|
195
|
-
if (key === "set-cookie") {
|
|
196
|
-
output[key] ??= [];
|
|
197
|
-
(output[key] as string[]).push(
|
|
198
|
-
...value.split(";").map((str) => str.trim()),
|
|
199
|
-
);
|
|
200
|
-
} else output[key] = value;
|
|
201
|
-
});
|
|
202
|
-
return output;
|
|
203
|
-
};
|
|
1
|
+
import { IHttpConnection, IHttpResponse } from "@typia/interface";
|
|
2
|
+
|
|
3
|
+
import { HttpError } from "../HttpError";
|
|
4
|
+
import type { HttpMigration } from "../HttpMigration";
|
|
5
|
+
|
|
6
|
+
export namespace HttpMigrateRouteFetcher {
|
|
7
|
+
export const execute = async (
|
|
8
|
+
props: HttpMigration.IFetchProps,
|
|
9
|
+
): Promise<unknown> => {
|
|
10
|
+
const result: IHttpResponse = await _Propagate("request", props);
|
|
11
|
+
props.route.success?.media;
|
|
12
|
+
if (result.status !== 200 && result.status !== 201)
|
|
13
|
+
throw new HttpError(
|
|
14
|
+
props.route.method.toUpperCase() as "GET",
|
|
15
|
+
props.route.path,
|
|
16
|
+
result.status,
|
|
17
|
+
result.headers,
|
|
18
|
+
result.body as string,
|
|
19
|
+
);
|
|
20
|
+
return result.body;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export const propagate = (
|
|
24
|
+
props: HttpMigration.IFetchProps,
|
|
25
|
+
): Promise<IHttpResponse> => _Propagate("propagate", props);
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const _Propagate = async (
|
|
29
|
+
from: string,
|
|
30
|
+
props: HttpMigration.IFetchProps,
|
|
31
|
+
): Promise<IHttpResponse> => {
|
|
32
|
+
// VALIDATE PARAMETERS
|
|
33
|
+
const error = (message: string) =>
|
|
34
|
+
new Error(`Error on MigrateRouteFetcher.${from}(): ${message}`);
|
|
35
|
+
if (Array.isArray(props.parameters)) {
|
|
36
|
+
if (props.route.parameters.length !== props.parameters.length)
|
|
37
|
+
throw error(`number of parameters is not matched.`);
|
|
38
|
+
} else if (
|
|
39
|
+
props.route.parameters.every(
|
|
40
|
+
(p) => (props.parameters as Record<string, any>)[p.key] !== undefined,
|
|
41
|
+
) === false
|
|
42
|
+
)
|
|
43
|
+
throw error(`number of parameters is not matched.`);
|
|
44
|
+
|
|
45
|
+
// VALIDATE QUERY
|
|
46
|
+
if (!!props.route.query !== !!props.query)
|
|
47
|
+
throw error(`query is not matched.`);
|
|
48
|
+
else if (!!props.route.body !== (props.body !== undefined))
|
|
49
|
+
throw error(`body is not matched.`);
|
|
50
|
+
|
|
51
|
+
// INIT REQUEST DATA
|
|
52
|
+
const headers: Record<string, IHttpConnection.HeaderValue | undefined> = {
|
|
53
|
+
...(props.connection.headers ?? {}),
|
|
54
|
+
...(props.route.body?.type &&
|
|
55
|
+
props.route.body.type !== "multipart/form-data"
|
|
56
|
+
? { "Content-Type": props.route.body.type }
|
|
57
|
+
: {}),
|
|
58
|
+
};
|
|
59
|
+
const init: RequestInit = {
|
|
60
|
+
...(props.connection.options ?? {}),
|
|
61
|
+
method: props.route.method.toUpperCase(),
|
|
62
|
+
headers: (() => {
|
|
63
|
+
const output: [string, string][] = [];
|
|
64
|
+
for (const [key, value] of Object.entries(headers))
|
|
65
|
+
if (value === undefined) continue;
|
|
66
|
+
else if (Array.isArray(value))
|
|
67
|
+
for (const v of value) output.push([key, String(v)]);
|
|
68
|
+
else output.push([key, String(value)]);
|
|
69
|
+
return output;
|
|
70
|
+
})(),
|
|
71
|
+
};
|
|
72
|
+
if (props.body !== undefined)
|
|
73
|
+
init.body = (
|
|
74
|
+
props.route.body?.type === "application/x-www-form-urlencoded"
|
|
75
|
+
? requestQueryBody(props.body)
|
|
76
|
+
: props.route.body?.type === "multipart/form-data"
|
|
77
|
+
? requestFormDataBody(props.body)
|
|
78
|
+
: props.route.body?.type === "application/json"
|
|
79
|
+
? JSON.stringify(props.body)
|
|
80
|
+
: props.body
|
|
81
|
+
) as any;
|
|
82
|
+
|
|
83
|
+
// DO REQUEST
|
|
84
|
+
const resolvedPath: string =
|
|
85
|
+
props.connection.host.endsWith("/") === false &&
|
|
86
|
+
props.route.emendedPath.startsWith("/") === false
|
|
87
|
+
? `/${getPath(props)}`
|
|
88
|
+
: getPath(props);
|
|
89
|
+
const url: URL = new URL(`${props.connection.host}${resolvedPath}`);
|
|
90
|
+
|
|
91
|
+
const response: Response = await (props.connection.fetch ?? fetch)(url, init);
|
|
92
|
+
const status: number = response.status;
|
|
93
|
+
const out = (body: unknown): IHttpResponse => ({
|
|
94
|
+
status,
|
|
95
|
+
headers: responseHeaders(response.headers),
|
|
96
|
+
body,
|
|
97
|
+
});
|
|
98
|
+
|
|
99
|
+
if (status === 200 || status === 201) {
|
|
100
|
+
// SUCCESS CASE
|
|
101
|
+
if (props.route.method.toUpperCase() === "HEAD") return out(undefined);
|
|
102
|
+
else if (
|
|
103
|
+
props.route.success === null ||
|
|
104
|
+
props.route.success.type === "text/plain"
|
|
105
|
+
)
|
|
106
|
+
return out(await response.text());
|
|
107
|
+
else if (props.route.success.type === "application/json") {
|
|
108
|
+
const text: string = await response.text();
|
|
109
|
+
return out(text.length ? JSON.parse(text) : undefined);
|
|
110
|
+
} else if (props.route.success.type === "application/x-www-form-urlencoded")
|
|
111
|
+
return out(new URLSearchParams(await response.text()));
|
|
112
|
+
else if (props.route.success.type === "multipart/form-data")
|
|
113
|
+
return out(await response.formData());
|
|
114
|
+
throw error("Unsupported response body type.");
|
|
115
|
+
} else {
|
|
116
|
+
// FAILURE CASE
|
|
117
|
+
const type: string = (
|
|
118
|
+
response.headers.get("content-type") ??
|
|
119
|
+
response.headers.get("Content-Type") ??
|
|
120
|
+
""
|
|
121
|
+
)
|
|
122
|
+
.split(";")[0]!
|
|
123
|
+
.trim();
|
|
124
|
+
if (type === "" || type.startsWith("text/"))
|
|
125
|
+
return out(await response.text());
|
|
126
|
+
else if (type === "application/json") return out(await response.json());
|
|
127
|
+
else if (type === "application/x-www-form-urlencoded")
|
|
128
|
+
return out(new URLSearchParams(await response.text()));
|
|
129
|
+
else if (type === "multipart/form-data")
|
|
130
|
+
return out(await response.formData());
|
|
131
|
+
else if (type === "application/octet-stream")
|
|
132
|
+
return out(await response.blob());
|
|
133
|
+
return out(await response.text());
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
|
|
137
|
+
const getPath = (
|
|
138
|
+
props: Pick<HttpMigration.IFetchProps, "route" | "parameters" | "query">,
|
|
139
|
+
): string => {
|
|
140
|
+
let path: string = props.route.emendedPath;
|
|
141
|
+
props.route.parameters.forEach((p, i) => {
|
|
142
|
+
path = path.replace(
|
|
143
|
+
`:${p.key}`,
|
|
144
|
+
encodeURIComponent(
|
|
145
|
+
String(
|
|
146
|
+
(Array.isArray(props.parameters)
|
|
147
|
+
? props.parameters[i]
|
|
148
|
+
: props.parameters[p.key]) ?? "null",
|
|
149
|
+
),
|
|
150
|
+
),
|
|
151
|
+
);
|
|
152
|
+
});
|
|
153
|
+
if (props.route.query) path += getQueryPath(props.query ?? {});
|
|
154
|
+
return path;
|
|
155
|
+
};
|
|
156
|
+
|
|
157
|
+
const getQueryPath = (query: Record<string, any>): string => {
|
|
158
|
+
const variables = new URLSearchParams();
|
|
159
|
+
for (const [key, value] of Object.entries(query))
|
|
160
|
+
if (undefined === value) continue;
|
|
161
|
+
else if (Array.isArray(value))
|
|
162
|
+
value.forEach((elem: any) => variables.append(key, String(elem)));
|
|
163
|
+
else variables.set(key, String(value));
|
|
164
|
+
return 0 === variables.size ? "" : `?${variables.toString()}`;
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const requestQueryBody = (input: any): URLSearchParams => {
|
|
168
|
+
const q: URLSearchParams = new URLSearchParams();
|
|
169
|
+
for (const [key, value] of Object.entries(input))
|
|
170
|
+
if (value === undefined) continue;
|
|
171
|
+
else if (Array.isArray(value))
|
|
172
|
+
value.forEach((elem) => q.append(key, String(elem)));
|
|
173
|
+
else q.set(key, String(value));
|
|
174
|
+
return q;
|
|
175
|
+
};
|
|
176
|
+
const requestFormDataBody = (input: Record<string, any>): FormData => {
|
|
177
|
+
const encoded: FormData = new FormData();
|
|
178
|
+
const append = (key: string) => (value: any) => {
|
|
179
|
+
if (value === undefined) return;
|
|
180
|
+
else if (typeof File === "function" && value instanceof File)
|
|
181
|
+
encoded.append(key, value, value.name);
|
|
182
|
+
else encoded.append(key, value);
|
|
183
|
+
};
|
|
184
|
+
for (const [key, value] of Object.entries(input))
|
|
185
|
+
if (Array.isArray(value)) value.map(append(key));
|
|
186
|
+
else append(key)(value);
|
|
187
|
+
return encoded;
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
const responseHeaders = (
|
|
191
|
+
headers: Headers,
|
|
192
|
+
): Record<string, string | string[]> => {
|
|
193
|
+
const output: Record<string, string | string[]> = {};
|
|
194
|
+
headers.forEach((value, key) => {
|
|
195
|
+
if (key === "set-cookie") {
|
|
196
|
+
output[key] ??= [];
|
|
197
|
+
(output[key] as string[]).push(
|
|
198
|
+
...value.split(";").map((str) => str.trim()),
|
|
199
|
+
);
|
|
200
|
+
} else output[key] = value;
|
|
201
|
+
});
|
|
202
|
+
return output;
|
|
203
|
+
};
|
package/src/index.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export * from "./converters/index";
|
|
2
|
-
export * from "./http/index";
|
|
3
|
-
export * from "./utils/index";
|
|
4
|
-
export * from "./validators/index";
|
|
1
|
+
export * from "./converters/index";
|
|
2
|
+
export * from "./http/index";
|
|
3
|
+
export * from "./utils/index";
|
|
4
|
+
export * from "./validators/index";
|
package/src/utils/ArrayUtil.ts
CHANGED
|
@@ -1,42 +1,42 @@
|
|
|
1
|
-
/** @internal */
|
|
2
|
-
export namespace ArrayUtil {
|
|
3
|
-
export const has = <T>(array: T[], pred: (elem: T) => boolean): boolean =>
|
|
4
|
-
array.some(pred);
|
|
5
|
-
|
|
6
|
-
export const add = <T>(
|
|
7
|
-
array: T[],
|
|
8
|
-
value: T,
|
|
9
|
-
pred: (x: T, y: T) => boolean = (x, y) => x === y,
|
|
10
|
-
): boolean => {
|
|
11
|
-
if (array.some((elem) => pred(elem, value))) return false;
|
|
12
|
-
array.push(value);
|
|
13
|
-
return true;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
export const set = <Key, T>(
|
|
17
|
-
array: T[],
|
|
18
|
-
value: T,
|
|
19
|
-
key: (elem: T) => Key,
|
|
20
|
-
): void => {
|
|
21
|
-
if (array.some((elem) => key(elem) === key(value))) return;
|
|
22
|
-
array.push(value);
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const take = <T>(
|
|
26
|
-
array: T[],
|
|
27
|
-
pred: (elem: T) => boolean,
|
|
28
|
-
init: () => T,
|
|
29
|
-
): T => {
|
|
30
|
-
const index: number = array.findIndex(pred);
|
|
31
|
-
if (index !== -1) return array[index]!;
|
|
32
|
-
|
|
33
|
-
const elem: T = init();
|
|
34
|
-
array.push(elem);
|
|
35
|
-
return elem;
|
|
36
|
-
};
|
|
37
|
-
|
|
38
|
-
export const repeat = <T>(
|
|
39
|
-
count: number,
|
|
40
|
-
closure: (index: number, count: number) => T,
|
|
41
|
-
): T[] => new Array(count).fill("").map((_, index) => closure(index, count));
|
|
42
|
-
}
|
|
1
|
+
/** @internal */
|
|
2
|
+
export namespace ArrayUtil {
|
|
3
|
+
export const has = <T>(array: T[], pred: (elem: T) => boolean): boolean =>
|
|
4
|
+
array.some(pred);
|
|
5
|
+
|
|
6
|
+
export const add = <T>(
|
|
7
|
+
array: T[],
|
|
8
|
+
value: T,
|
|
9
|
+
pred: (x: T, y: T) => boolean = (x, y) => x === y,
|
|
10
|
+
): boolean => {
|
|
11
|
+
if (array.some((elem) => pred(elem, value))) return false;
|
|
12
|
+
array.push(value);
|
|
13
|
+
return true;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export const set = <Key, T>(
|
|
17
|
+
array: T[],
|
|
18
|
+
value: T,
|
|
19
|
+
key: (elem: T) => Key,
|
|
20
|
+
): void => {
|
|
21
|
+
if (array.some((elem) => key(elem) === key(value))) return;
|
|
22
|
+
array.push(value);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const take = <T>(
|
|
26
|
+
array: T[],
|
|
27
|
+
pred: (elem: T) => boolean,
|
|
28
|
+
init: () => T,
|
|
29
|
+
): T => {
|
|
30
|
+
const index: number = array.findIndex(pred);
|
|
31
|
+
if (index !== -1) return array[index]!;
|
|
32
|
+
|
|
33
|
+
const elem: T = init();
|
|
34
|
+
array.push(elem);
|
|
35
|
+
return elem;
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
export const repeat = <T>(
|
|
39
|
+
count: number,
|
|
40
|
+
closure: (index: number, count: number) => T,
|
|
41
|
+
): T[] => new Array(count).fill("").map((_, index) => closure(index, count));
|
|
42
|
+
}
|