@ruiapp/rapid-core 0.1.77 → 0.1.78
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/dist/index.js +7 -3
- package/package.json +1 -1
- package/rollup.config.js +16 -16
- package/src/core/actionHandler.ts +22 -22
- package/src/core/eventManager.ts +20 -20
- package/src/core/facility.ts +7 -7
- package/src/core/http/formDataParser.ts +89 -89
- package/src/core/pluginManager.ts +175 -175
- package/src/core/providers/runtimeProvider.ts +5 -5
- package/src/core/request.ts +86 -86
- package/src/core/response.ts +76 -76
- package/src/core/routeContext.ts +43 -43
- package/src/core/routesBuilder.ts +88 -88
- package/src/dataAccess/dataAccessor.ts +137 -137
- package/src/dataAccess/entityManager.ts +4 -0
- package/src/deno-std/datetime/to_imf.ts +32 -32
- package/src/deno-std/encoding/base64.ts +141 -141
- package/src/facilities/log/LogFacility.ts +35 -35
- package/src/helpers/entityHelpers.ts +76 -76
- package/src/index.ts +44 -44
- package/src/plugins/auth/actionHandlers/changePassword.ts +54 -54
- package/src/plugins/auth/actionHandlers/createSession.ts +63 -63
- package/src/plugins/auth/actionHandlers/deleteSession.ts +18 -18
- package/src/plugins/auth/actionHandlers/getMyProfile.ts +35 -35
- package/src/plugins/auth/actionHandlers/index.ts +8 -8
- package/src/plugins/auth/actionHandlers/resetPassword.ts +38 -38
- package/src/plugins/auth/models/AccessToken.ts +56 -56
- package/src/plugins/auth/models/index.ts +3 -3
- package/src/plugins/auth/routes/changePassword.ts +15 -15
- package/src/plugins/auth/routes/getMyProfile.ts +15 -15
- package/src/plugins/auth/routes/index.ts +7 -7
- package/src/plugins/auth/routes/resetPassword.ts +15 -15
- package/src/plugins/auth/routes/signin.ts +15 -15
- package/src/plugins/auth/routes/signout.ts +15 -15
- package/src/plugins/cronJob/CronJobPluginTypes.ts +49 -49
- package/src/plugins/cronJob/actionHandlers/index.ts +4 -4
- package/src/plugins/cronJob/actionHandlers/runCronJob.ts +29 -29
- package/src/plugins/cronJob/routes/index.ts +3 -3
- package/src/plugins/cronJob/routes/runCronJob.ts +15 -15
- package/src/plugins/dataManage/actionHandlers/addEntityRelations.ts +20 -20
- package/src/plugins/dataManage/actionHandlers/countCollectionEntities.ts +15 -15
- package/src/plugins/dataManage/actionHandlers/createCollectionEntitiesBatch.ts +42 -42
- package/src/plugins/dataManage/actionHandlers/createCollectionEntity.ts +24 -24
- package/src/plugins/dataManage/actionHandlers/findCollectionEntities.ts +26 -26
- package/src/plugins/dataManage/actionHandlers/findCollectionEntityById.ts +21 -21
- package/src/plugins/dataManage/actionHandlers/queryDatabase.ts +22 -22
- package/src/plugins/dataManage/actionHandlers/removeEntityRelations.ts +20 -20
- package/src/plugins/dataManage/actionHandlers/updateCollectionEntityById.ts +35 -35
- package/src/plugins/entityAccessControl/EntityAccessControlPlugin.ts +146 -146
- package/src/plugins/fileManage/actionHandlers/downloadDocument.ts +36 -36
- package/src/plugins/fileManage/actionHandlers/uploadFile.ts +33 -33
- package/src/plugins/fileManage/routes/downloadDocument.ts +15 -15
- package/src/plugins/fileManage/routes/downloadFile.ts +15 -15
- package/src/plugins/fileManage/routes/index.ts +5 -5
- package/src/plugins/fileManage/routes/uploadFile.ts +15 -15
- package/src/plugins/metaManage/actionHandlers/getMetaModelDetail.ts +10 -10
- package/src/plugins/metaManage/actionHandlers/listMetaModels.ts +9 -9
- package/src/plugins/metaManage/actionHandlers/listMetaRoutes.ts +9 -9
- package/src/plugins/routeManage/actionHandlers/httpProxy.ts +13 -13
- package/src/plugins/sequence/SequenceService.ts +81 -81
- package/src/plugins/sequence/actionHandlers/generateSn.ts +32 -32
- package/src/plugins/sequence/actionHandlers/index.ts +4 -4
- package/src/plugins/sequence/models/SequenceAutoIncrementRecord.ts +49 -49
- package/src/plugins/sequence/models/SequenceRule.ts +42 -42
- package/src/plugins/sequence/models/index.ts +4 -4
- package/src/plugins/sequence/routes/generateSn.ts +15 -15
- package/src/plugins/sequence/routes/index.ts +3 -3
- package/src/plugins/sequence/segment-utility.ts +11 -11
- package/src/plugins/sequence/segments/index.ts +9 -9
- package/src/plugins/serverOperation/ServerOperationPlugin.ts +91 -91
- package/src/plugins/serverOperation/ServerOperationPluginTypes.ts +15 -15
- package/src/plugins/serverOperation/actionHandlers/index.ts +4 -4
- package/src/plugins/setting/SettingService.ts +213 -213
- package/src/plugins/setting/actionHandlers/getSystemSettingValues.ts +30 -30
- package/src/plugins/setting/actionHandlers/getUserSettingValues.ts +38 -38
- package/src/plugins/setting/actionHandlers/index.ts +6 -6
- package/src/plugins/setting/actionHandlers/setSystemSettingValues.ts +30 -30
- package/src/plugins/setting/models/SystemSettingGroupSetting.ts +57 -57
- package/src/plugins/setting/models/SystemSettingItem.ts +42 -42
- package/src/plugins/setting/models/SystemSettingItemSetting.ts +73 -73
- package/src/plugins/setting/models/UserSettingGroupSetting.ts +57 -57
- package/src/plugins/setting/models/UserSettingItem.ts +49 -49
- package/src/plugins/setting/models/UserSettingItemSetting.ts +73 -73
- package/src/plugins/setting/models/index.ts +8 -8
- package/src/plugins/setting/routes/getSystemSettingValues.ts +15 -15
- package/src/plugins/setting/routes/getUserSettingValues.ts +15 -15
- package/src/plugins/setting/routes/index.ts +5 -5
- package/src/plugins/setting/routes/setSystemSettingValues.ts +15 -15
- package/src/plugins/stateMachine/actionHandlers/index.ts +4 -4
- package/src/plugins/stateMachine/actionHandlers/sendStateMachineEvent.ts +51 -51
- package/src/plugins/stateMachine/models/StateMachine.ts +42 -42
- package/src/plugins/stateMachine/models/index.ts +3 -3
- package/src/plugins/stateMachine/routes/index.ts +3 -3
- package/src/plugins/stateMachine/routes/sendStateMachineEvent.ts +15 -15
- package/src/polyfill.ts +5 -5
- package/src/proxy/mod.ts +38 -38
- package/src/utilities/accessControlUtility.ts +33 -33
- package/src/utilities/fsUtility.ts +61 -61
- package/src/utilities/httpUtility.ts +19 -19
- package/src/utilities/jwtUtility.ts +26 -26
- package/src/utilities/timeUtility.ts +9 -9
- package/tsconfig.json +19 -19
package/dist/index.js
CHANGED
|
@@ -2885,6 +2885,7 @@ async function createEntity(server, dataAccessor, options, plugin) {
|
|
|
2885
2885
|
if (!targetEntityId) {
|
|
2886
2886
|
const targetEntity = fieldValue;
|
|
2887
2887
|
const newTargetEntity = await createEntity(server, targetDataAccessor, {
|
|
2888
|
+
routeContext,
|
|
2888
2889
|
entity: targetEntity,
|
|
2889
2890
|
});
|
|
2890
2891
|
newEntityOneRelationProps[property.code] = newTargetEntity;
|
|
@@ -2951,6 +2952,7 @@ async function createEntity(server, dataAccessor, options, plugin) {
|
|
|
2951
2952
|
targetEntity[property.selfIdColumnName] = newEntity.id;
|
|
2952
2953
|
}
|
|
2953
2954
|
const newTargetEntity = await createEntity(server, targetDataAccessor, {
|
|
2955
|
+
routeContext,
|
|
2954
2956
|
entity: targetEntity,
|
|
2955
2957
|
});
|
|
2956
2958
|
if (property.linkTableName) {
|
|
@@ -3115,6 +3117,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
3115
3117
|
if (!targetEntityId) {
|
|
3116
3118
|
const targetEntity = fieldValue;
|
|
3117
3119
|
const newTargetEntity = await createEntity(server, targetDataAccessor, {
|
|
3120
|
+
routeContext,
|
|
3118
3121
|
entity: targetEntity,
|
|
3119
3122
|
});
|
|
3120
3123
|
updatedEntityOneRelationProps[property.code] = newTargetEntity;
|
|
@@ -3191,6 +3194,7 @@ async function updateEntityById(server, dataAccessor, options, plugin) {
|
|
|
3191
3194
|
targetEntity[property.selfIdColumnName] = id;
|
|
3192
3195
|
}
|
|
3193
3196
|
const newTargetEntity = await createEntity(server, targetDataAccessor, {
|
|
3197
|
+
routeContext,
|
|
3194
3198
|
entity: targetEntity,
|
|
3195
3199
|
});
|
|
3196
3200
|
if (property.linkTableName) {
|
|
@@ -7323,9 +7327,9 @@ class EntityAccessControlPlugin {
|
|
|
7323
7327
|
if (!userId) {
|
|
7324
7328
|
return;
|
|
7325
7329
|
}
|
|
7326
|
-
const actions = await server.queryDatabaseObject(`select distinct a.* from sys_actions a
|
|
7327
|
-
inner join oc_role_sys_action_links ra on a.id = ra.action_id
|
|
7328
|
-
inner join oc_role_user_links ru on ru.role_id = ra.role_id
|
|
7330
|
+
const actions = await server.queryDatabaseObject(`select distinct a.* from sys_actions a
|
|
7331
|
+
inner join oc_role_sys_action_links ra on a.id = ra.action_id
|
|
7332
|
+
inner join oc_role_user_links ru on ru.role_id = ra.role_id
|
|
7329
7333
|
where ru.user_id = $1;`, [userId]);
|
|
7330
7334
|
routeContext.state.allowedActions = actions.map((item) => item.code);
|
|
7331
7335
|
}
|
package/package.json
CHANGED
package/rollup.config.js
CHANGED
|
@@ -1,16 +1,16 @@
|
|
|
1
|
-
import typescript from "rollup-plugin-typescript2";
|
|
2
|
-
import tscAlias from "rollup-plugin-tsc-alias";
|
|
3
|
-
|
|
4
|
-
export default {
|
|
5
|
-
input: ["src/index.ts"],
|
|
6
|
-
output: [
|
|
7
|
-
{
|
|
8
|
-
dir: "dist",
|
|
9
|
-
entryFileNames: "[name].js",
|
|
10
|
-
format: "cjs",
|
|
11
|
-
exports: "named",
|
|
12
|
-
},
|
|
13
|
-
],
|
|
14
|
-
plugins: [typescript(), tscAlias()],
|
|
15
|
-
external: [],
|
|
16
|
-
};
|
|
1
|
+
import typescript from "rollup-plugin-typescript2";
|
|
2
|
+
import tscAlias from "rollup-plugin-tsc-alias";
|
|
3
|
+
|
|
4
|
+
export default {
|
|
5
|
+
input: ["src/index.ts"],
|
|
6
|
+
output: [
|
|
7
|
+
{
|
|
8
|
+
dir: "dist",
|
|
9
|
+
entryFileNames: "[name].js",
|
|
10
|
+
format: "cjs",
|
|
11
|
+
exports: "named",
|
|
12
|
+
},
|
|
13
|
+
],
|
|
14
|
+
plugins: [typescript(), tscAlias()],
|
|
15
|
+
external: [],
|
|
16
|
+
};
|
|
@@ -1,22 +1,22 @@
|
|
|
1
|
-
import { RpdApplicationConfig } from "~/types";
|
|
2
|
-
import { IRpdServer, RapidPlugin } from "./server";
|
|
3
|
-
import { Next, RouteContext } from "./routeContext";
|
|
4
|
-
import { Logger } from "~/facilities/log/LogFacility";
|
|
5
|
-
|
|
6
|
-
export interface ActionHandlerContext {
|
|
7
|
-
logger: Logger;
|
|
8
|
-
routerContext: RouteContext;
|
|
9
|
-
next: Next;
|
|
10
|
-
server: IRpdServer;
|
|
11
|
-
applicationConfig: RpdApplicationConfig;
|
|
12
|
-
input?: any;
|
|
13
|
-
output?: any;
|
|
14
|
-
status?: Response["status"];
|
|
15
|
-
}
|
|
16
|
-
|
|
17
|
-
export type ActionHandler = (ctx: ActionHandlerContext, options: any) => void | Promise<void>;
|
|
18
|
-
|
|
19
|
-
export interface IPluginActionHandler {
|
|
20
|
-
code: string;
|
|
21
|
-
handler: (plugin: RapidPlugin, ctx: ActionHandlerContext, options: any) => void | Promise<void>;
|
|
22
|
-
}
|
|
1
|
+
import { RpdApplicationConfig } from "~/types";
|
|
2
|
+
import { IRpdServer, RapidPlugin } from "./server";
|
|
3
|
+
import { Next, RouteContext } from "./routeContext";
|
|
4
|
+
import { Logger } from "~/facilities/log/LogFacility";
|
|
5
|
+
|
|
6
|
+
export interface ActionHandlerContext {
|
|
7
|
+
logger: Logger;
|
|
8
|
+
routerContext: RouteContext;
|
|
9
|
+
next: Next;
|
|
10
|
+
server: IRpdServer;
|
|
11
|
+
applicationConfig: RpdApplicationConfig;
|
|
12
|
+
input?: any;
|
|
13
|
+
output?: any;
|
|
14
|
+
status?: Response["status"];
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type ActionHandler = (ctx: ActionHandlerContext, options: any) => void | Promise<void>;
|
|
18
|
+
|
|
19
|
+
export interface IPluginActionHandler {
|
|
20
|
+
code: string;
|
|
21
|
+
handler: (plugin: RapidPlugin, ctx: ActionHandlerContext, options: any) => void | Promise<void>;
|
|
22
|
+
}
|
package/src/core/eventManager.ts
CHANGED
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
import { EventEmitter } from "events";
|
|
2
|
-
|
|
3
|
-
export default class EventManager<EventTypes extends Record<string, any[]>> {
|
|
4
|
-
#eventEmitter: EventEmitter;
|
|
5
|
-
|
|
6
|
-
constructor() {
|
|
7
|
-
this.#eventEmitter = new EventEmitter();
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
on<K extends keyof EventTypes>(eventName: K, listener: (...args: EventTypes[K]) => void) {
|
|
11
|
-
this.#eventEmitter.on(eventName as string, listener);
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
async emit<K extends keyof EventTypes>(eventName: K, ...args: EventTypes[K]) {
|
|
15
|
-
const listeners = this.#eventEmitter.listeners(eventName as string);
|
|
16
|
-
for (const listener of listeners) {
|
|
17
|
-
await listener(...args);
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}
|
|
1
|
+
import { EventEmitter } from "events";
|
|
2
|
+
|
|
3
|
+
export default class EventManager<EventTypes extends Record<string, any[]>> {
|
|
4
|
+
#eventEmitter: EventEmitter;
|
|
5
|
+
|
|
6
|
+
constructor() {
|
|
7
|
+
this.#eventEmitter = new EventEmitter();
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
on<K extends keyof EventTypes>(eventName: K, listener: (...args: EventTypes[K]) => void) {
|
|
11
|
+
this.#eventEmitter.on(eventName as string, listener);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
async emit<K extends keyof EventTypes>(eventName: K, ...args: EventTypes[K]) {
|
|
15
|
+
const listeners = this.#eventEmitter.listeners(eventName as string);
|
|
16
|
+
for (const listener of listeners) {
|
|
17
|
+
await listener(...args);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
package/src/core/facility.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { IRpdServer } from "./server";
|
|
2
|
-
|
|
3
|
-
export interface FacilityFactory {
|
|
4
|
-
name: string;
|
|
5
|
-
|
|
6
|
-
createFacility: (server: IRpdServer, options?: any) => Promise<any>;
|
|
7
|
-
}
|
|
1
|
+
import { IRpdServer } from "./server";
|
|
2
|
+
|
|
3
|
+
export interface FacilityFactory {
|
|
4
|
+
name: string;
|
|
5
|
+
|
|
6
|
+
createFacility: (server: IRpdServer, options?: any) => Promise<any>;
|
|
7
|
+
}
|
|
@@ -1,89 +1,89 @@
|
|
|
1
|
-
import type { RapidRequest } from "../request";
|
|
2
|
-
|
|
3
|
-
export type BodyData = Record<string, string | File | (string | File)[]>;
|
|
4
|
-
export type ParseBodyOptions = {
|
|
5
|
-
/**
|
|
6
|
-
* Parse all fields with multiple values should be parsed as an array.
|
|
7
|
-
* @default false
|
|
8
|
-
* @example
|
|
9
|
-
* ```ts
|
|
10
|
-
* const data = new FormData()
|
|
11
|
-
* data.append('file', 'aaa')
|
|
12
|
-
* data.append('file', 'bbb')
|
|
13
|
-
* data.append('message', 'hello')
|
|
14
|
-
* ```
|
|
15
|
-
*
|
|
16
|
-
* If `all` is `false`:
|
|
17
|
-
* parseBody should return `{ file: 'bbb', message: 'hello' }`
|
|
18
|
-
*
|
|
19
|
-
* If `all` is `true`:
|
|
20
|
-
* parseBody should return `{ file: ['aaa', 'bbb'], message: 'hello' }`
|
|
21
|
-
*/
|
|
22
|
-
all?: boolean;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
export const parseFormDataBody = async <T extends BodyData = BodyData>(request: Request, options: ParseBodyOptions = { all: false }): Promise<T> => {
|
|
26
|
-
const contentType = request.headers.get("Content-Type");
|
|
27
|
-
|
|
28
|
-
if (isFormDataContent(contentType)) {
|
|
29
|
-
return parseFormData<T>(request, options);
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
return {} as T;
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
function isFormDataContent(contentType: string | null): boolean {
|
|
36
|
-
if (contentType === null) {
|
|
37
|
-
return false;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
return contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded");
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
async function parseFormData<T extends BodyData = BodyData>(request: Request, options: ParseBodyOptions): Promise<T> {
|
|
44
|
-
const formData = await (request as Request).formData();
|
|
45
|
-
|
|
46
|
-
if (formData) {
|
|
47
|
-
return convertFormDataToBodyData<T>(formData, options);
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
return {} as T;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
function convertFormDataToBodyData<T extends BodyData = BodyData>(formData: FormData, options: ParseBodyOptions): T {
|
|
54
|
-
const form: BodyData = {};
|
|
55
|
-
|
|
56
|
-
formData.forEach((value, key) => {
|
|
57
|
-
const shouldParseAllValues = options.all || key.endsWith("[]");
|
|
58
|
-
|
|
59
|
-
if (!shouldParseAllValues) {
|
|
60
|
-
form[key] = value;
|
|
61
|
-
} else {
|
|
62
|
-
handleParsingAllValues(form, key, value);
|
|
63
|
-
}
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
return form as T;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
const handleParsingAllValues = (form: BodyData, key: string, value: FormDataEntryValue): void => {
|
|
70
|
-
if (form[key] && isArrayField(form[key])) {
|
|
71
|
-
appendToExistingArray(form[key] as (string | File)[], value);
|
|
72
|
-
} else if (form[key]) {
|
|
73
|
-
convertToNewArray(form, key, value);
|
|
74
|
-
} else {
|
|
75
|
-
form[key] = value;
|
|
76
|
-
}
|
|
77
|
-
};
|
|
78
|
-
|
|
79
|
-
function isArrayField(field: unknown): field is (string | File)[] {
|
|
80
|
-
return Array.isArray(field);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
const appendToExistingArray = (arr: (string | File)[], value: FormDataEntryValue): void => {
|
|
84
|
-
arr.push(value);
|
|
85
|
-
};
|
|
86
|
-
|
|
87
|
-
const convertToNewArray = (form: BodyData, key: string, value: FormDataEntryValue): void => {
|
|
88
|
-
form[key] = [form[key] as string | File, value];
|
|
89
|
-
};
|
|
1
|
+
import type { RapidRequest } from "../request";
|
|
2
|
+
|
|
3
|
+
export type BodyData = Record<string, string | File | (string | File)[]>;
|
|
4
|
+
export type ParseBodyOptions = {
|
|
5
|
+
/**
|
|
6
|
+
* Parse all fields with multiple values should be parsed as an array.
|
|
7
|
+
* @default false
|
|
8
|
+
* @example
|
|
9
|
+
* ```ts
|
|
10
|
+
* const data = new FormData()
|
|
11
|
+
* data.append('file', 'aaa')
|
|
12
|
+
* data.append('file', 'bbb')
|
|
13
|
+
* data.append('message', 'hello')
|
|
14
|
+
* ```
|
|
15
|
+
*
|
|
16
|
+
* If `all` is `false`:
|
|
17
|
+
* parseBody should return `{ file: 'bbb', message: 'hello' }`
|
|
18
|
+
*
|
|
19
|
+
* If `all` is `true`:
|
|
20
|
+
* parseBody should return `{ file: ['aaa', 'bbb'], message: 'hello' }`
|
|
21
|
+
*/
|
|
22
|
+
all?: boolean;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export const parseFormDataBody = async <T extends BodyData = BodyData>(request: Request, options: ParseBodyOptions = { all: false }): Promise<T> => {
|
|
26
|
+
const contentType = request.headers.get("Content-Type");
|
|
27
|
+
|
|
28
|
+
if (isFormDataContent(contentType)) {
|
|
29
|
+
return parseFormData<T>(request, options);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return {} as T;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
function isFormDataContent(contentType: string | null): boolean {
|
|
36
|
+
if (contentType === null) {
|
|
37
|
+
return false;
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return contentType.startsWith("multipart/form-data") || contentType.startsWith("application/x-www-form-urlencoded");
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
async function parseFormData<T extends BodyData = BodyData>(request: Request, options: ParseBodyOptions): Promise<T> {
|
|
44
|
+
const formData = await (request as Request).formData();
|
|
45
|
+
|
|
46
|
+
if (formData) {
|
|
47
|
+
return convertFormDataToBodyData<T>(formData, options);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return {} as T;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function convertFormDataToBodyData<T extends BodyData = BodyData>(formData: FormData, options: ParseBodyOptions): T {
|
|
54
|
+
const form: BodyData = {};
|
|
55
|
+
|
|
56
|
+
formData.forEach((value, key) => {
|
|
57
|
+
const shouldParseAllValues = options.all || key.endsWith("[]");
|
|
58
|
+
|
|
59
|
+
if (!shouldParseAllValues) {
|
|
60
|
+
form[key] = value;
|
|
61
|
+
} else {
|
|
62
|
+
handleParsingAllValues(form, key, value);
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
return form as T;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
const handleParsingAllValues = (form: BodyData, key: string, value: FormDataEntryValue): void => {
|
|
70
|
+
if (form[key] && isArrayField(form[key])) {
|
|
71
|
+
appendToExistingArray(form[key] as (string | File)[], value);
|
|
72
|
+
} else if (form[key]) {
|
|
73
|
+
convertToNewArray(form, key, value);
|
|
74
|
+
} else {
|
|
75
|
+
form[key] = value;
|
|
76
|
+
}
|
|
77
|
+
};
|
|
78
|
+
|
|
79
|
+
function isArrayField(field: unknown): field is (string | File)[] {
|
|
80
|
+
return Array.isArray(field);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
const appendToExistingArray = (arr: (string | File)[], value: FormDataEntryValue): void => {
|
|
84
|
+
arr.push(value);
|
|
85
|
+
};
|
|
86
|
+
|
|
87
|
+
const convertToNewArray = (form: BodyData, key: string, value: FormDataEntryValue): void => {
|
|
88
|
+
form[key] = [form[key] as string | File, value];
|
|
89
|
+
};
|