@cmtlyt/lingshu-toolkit 0.3.0 → 0.5.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.
Files changed (76) hide show
  1. package/dist/247.js +66 -0
  2. package/dist/707.js +8 -2
  3. package/dist/react/index.js +2 -4
  4. package/dist/react/use-mount/index.js +1 -1
  5. package/dist/react/use-ref-state/index.js +1 -3
  6. package/dist/shared/allx/__test__/allsettled.test.d.ts +1 -0
  7. package/dist/shared/allx/__test__/basic.test.d.ts +1 -0
  8. package/dist/shared/allx/__test__/circular-dependency.test.d.ts +1 -0
  9. package/dist/shared/allx/__test__/dependency.test.d.ts +1 -0
  10. package/dist/shared/allx/__test__/edge-cases.test.d.ts +1 -0
  11. package/dist/shared/allx/__test__/error-handling.test.d.ts +1 -0
  12. package/dist/shared/allx/__test__/execution-order.test.d.ts +1 -0
  13. package/dist/shared/allx/__test__/falsy-values.test.d.ts +1 -0
  14. package/dist/shared/allx/__test__/performance.test.d.ts +1 -0
  15. package/dist/shared/allx/__test__/type-checking.test.d.ts +1 -0
  16. package/dist/shared/allx/__test__/use-cases.test.d.ts +1 -0
  17. package/dist/shared/allx/index.d.ts +13 -0
  18. package/dist/shared/allx/index.js +44 -0
  19. package/dist/shared/allx/types.d.ts +13 -0
  20. package/dist/shared/allx/types.js +0 -0
  21. package/dist/shared/allx/utils.d.ts +9 -0
  22. package/dist/shared/allx/utils.js +94 -0
  23. package/dist/shared/animation/index.d.ts +2 -2
  24. package/dist/shared/animation/index.js +19 -13
  25. package/dist/shared/animation/types.d.ts +6 -4
  26. package/dist/shared/animation/utils.d.ts +3 -5
  27. package/dist/shared/animation/utils.js +2 -6
  28. package/dist/shared/api-controller/__test__/index.browser.test.d.ts +1 -0
  29. package/dist/shared/api-controller/__test__/index.node.test.d.ts +1 -0
  30. package/dist/shared/api-controller/create-api.d.ts +26 -0
  31. package/dist/shared/api-controller/create-api.js +79 -0
  32. package/dist/shared/api-controller/index.d.ts +3 -0
  33. package/dist/shared/api-controller/index.js +3 -0
  34. package/dist/shared/api-controller/request.d.ts +7 -0
  35. package/dist/shared/api-controller/request.js +66 -0
  36. package/dist/shared/api-controller/types.d.ts +141 -0
  37. package/dist/shared/api-controller/types.js +0 -0
  38. package/dist/shared/api-controller/utils.d.ts +22 -0
  39. package/dist/shared/api-controller/utils.js +96 -0
  40. package/dist/shared/data-handler/tools.js +1 -3
  41. package/dist/shared/data-mixed-manager/__test__/basic.test.d.ts +1 -0
  42. package/dist/shared/data-mixed-manager/__test__/build-options.test.d.ts +1 -0
  43. package/dist/shared/data-mixed-manager/__test__/constructor-options.test.d.ts +1 -0
  44. package/dist/shared/data-mixed-manager/__test__/data-management.test.d.ts +1 -0
  45. package/dist/shared/data-mixed-manager/__test__/edge-cases.test.d.ts +1 -0
  46. package/dist/shared/data-mixed-manager/__test__/events.browser.test.d.ts +1 -0
  47. package/dist/shared/data-mixed-manager/__test__/events.test.d.ts +1 -0
  48. package/dist/shared/data-mixed-manager/__test__/fixed-slots.test.d.ts +1 -0
  49. package/dist/shared/data-mixed-manager/__test__/insert-mode.test.d.ts +1 -0
  50. package/dist/shared/data-mixed-manager/constants.d.ts +8 -0
  51. package/dist/shared/data-mixed-manager/constants.js +9 -0
  52. package/dist/shared/data-mixed-manager/index.d.ts +128 -0
  53. package/dist/shared/data-mixed-manager/index.js +226 -0
  54. package/dist/shared/data-mixed-manager/types.d.ts +90 -0
  55. package/dist/shared/data-mixed-manager/types.js +0 -0
  56. package/dist/shared/index.d.ts +5 -0
  57. package/dist/shared/index.js +957 -2
  58. package/dist/shared/logger/index.d.ts +5 -0
  59. package/dist/shared/logger/index.js +1 -0
  60. package/dist/shared/throw-error/index.d.ts +1 -0
  61. package/dist/shared/throw-error/index.js +5 -2
  62. package/dist/shared/try-call/index.d.ts +22 -0
  63. package/dist/shared/try-call/index.js +59 -0
  64. package/dist/shared/try-call/index.test.d.ts +1 -0
  65. package/dist/shared/types/base.d.ts +5 -0
  66. package/dist/shared/types/pack.d.ts +1 -1
  67. package/dist/shared/utils/__test__/base.test.d.ts +1 -0
  68. package/dist/shared/utils/__test__/verify.test.d.ts +1 -0
  69. package/dist/shared/utils/base.d.ts +3 -0
  70. package/dist/shared/utils/base.js +6 -0
  71. package/dist/shared/utils/index.d.ts +2 -0
  72. package/dist/shared/utils/index.js +2 -0
  73. package/dist/shared/utils/verify.d.ts +53 -0
  74. package/dist/shared/utils/verify.js +67 -0
  75. package/package.json +10 -7
  76. package/dist/607.js +0 -311
@@ -0,0 +1,66 @@
1
+ import { throwType } from "../throw-error/index.js";
2
+ import { tryCall } from "../try-call/index.js";
3
+ import { isFunction, isNullOrUndef } from "../utils/verify.js";
4
+ import { getBody, targetUrlParser, urlParamsParser } from "./utils.js";
5
+ async function baseRequest(config, getResponse) {
6
+ const { baseUrl, url, method: _method, parser, data, tdto, tvo, onResponse, ...rest } = config;
7
+ const targetUrl = targetUrlParser(url, baseUrl);
8
+ const method = _method?.toUpperCase();
9
+ const requestInfo = tryCall(()=>{
10
+ if (isNullOrUndef(method) || 'GET' === method || 'HEAD' === method) {
11
+ const queryKeys = Object.keys(data || {});
12
+ for(let i = 0; i < queryKeys.length; ++i)targetUrl.searchParams.append(queryKeys[i], data[queryKeys[i]]);
13
+ return new Request(targetUrl, {
14
+ ...rest,
15
+ method
16
+ });
17
+ }
18
+ const body = getBody(data, tdto);
19
+ return new Request(targetUrl, {
20
+ ...rest,
21
+ method,
22
+ body
23
+ });
24
+ });
25
+ const responseInfo = await getResponse(requestInfo);
26
+ const resResult = await tryCall(()=>{
27
+ if (onResponse) return onResponse(responseInfo, config);
28
+ if (!parser) return responseInfo.json();
29
+ if ('stream' === parser) return responseInfo.body;
30
+ const responseHandler = responseInfo[parser];
31
+ if (isFunction(responseHandler)) return Reflect.apply(responseHandler, responseInfo, []);
32
+ throwType('apiController.responseParser', 'Invalid parser');
33
+ });
34
+ return tvo ? tvo(resResult) : resResult;
35
+ }
36
+ async function mockRequest(config) {
37
+ const { onRequest, ...rest } = config;
38
+ return baseRequest(config, async (requestInfo)=>{
39
+ const reqResult = await (onRequest && onRequest(requestInfo, config));
40
+ const responseBody = getBody(reqResult);
41
+ return new Response(responseBody, {
42
+ ...rest
43
+ });
44
+ });
45
+ }
46
+ async function networkRequest(config) {
47
+ return baseRequest(config, fetch);
48
+ }
49
+ function request(config) {
50
+ const url = urlParamsParser(config.url, config.params);
51
+ const { requestMode, requestModeMap } = config;
52
+ const customRequest = (requestModeMap || {})[requestMode || ''];
53
+ if (customRequest) return customRequest({
54
+ ...config,
55
+ url
56
+ });
57
+ if ('mock' === requestMode) return mockRequest({
58
+ ...config,
59
+ url
60
+ });
61
+ return networkRequest({
62
+ ...config,
63
+ url
64
+ });
65
+ }
66
+ export { request };
@@ -0,0 +1,141 @@
1
+ import type { AnyFunc, Cast, Equal, Func } from '../types/base';
2
+ import type { Pack as TPack } from '../types/pack';
3
+ type Empty = {
4
+ __EMPTY__: never;
5
+ };
6
+ /** 请求方法 */
7
+ export type RequestMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH' | 'HEAD' | 'OPTIONS' | (string & {});
8
+ type Parser = 'json' | 'text' | 'blob' | 'arrayBuffer' | 'formData' | 'bytes' | 'stream' | (string & {});
9
+ type RequestMode<E extends string = string & {}> = 'mock' | 'network' | E;
10
+ type EmptyUnwrap<UserR = Empty, T = any> = Equal<UserR, Empty> extends true ? T : UserR;
11
+ interface ParserResultMap<UserR = Empty> {
12
+ json: EmptyUnwrap<UserR>;
13
+ text: string;
14
+ blob: Blob;
15
+ arrayBuffer: ArrayBuffer;
16
+ formData: FormData;
17
+ bytes: Uint8Array;
18
+ stream: ReadableStream | null;
19
+ }
20
+ type ParserResult<P extends Parser, UserR = Empty> = P extends keyof ParserResultMap ? ParserResultMap<UserR>[P] : EmptyUnwrap<UserR>;
21
+ type ParserReturn<RM extends RequestMode, P extends Parser, ReqOutput, UserR = Empty> = RM extends 'network' ? ParserResult<P, UserR> : EmptyUnwrap<UserR, RM extends 'mock' ? ReqOutput : any>;
22
+ type URLParamParser<U extends string, Param extends string = never> = U extends `${string}/:${infer P}/${infer Rest}` ? URLParamParser<`/${Rest}`, Param | P> : U extends `${string}/:${infer P}` ? P | Param : Param;
23
+ type CheckNonParamUrlAPIConfig<A extends APIConfig> = Equal<URLParamParser<A['url']>, never>;
24
+ export interface BaseAPIConfig<Input = any, Output = any, ReqOutput = any, ResOutput = any, DefaultConfig extends DefaultAPIConfig = DefaultAPIConfig, ReqModeMapKeys extends string = string & {}, Url extends string = string> extends RequestInit {
25
+ /**
26
+ * 请求地址
27
+ *
28
+ * @example '/api/user'
29
+ * @example 'https://example.com/api/user'
30
+ */
31
+ url: Url;
32
+ params?: Record<URLParamParser<Url>, string | number>;
33
+ /** 请求模式 */
34
+ requestMode?: RequestMode<ReqModeMapKeys>;
35
+ /** 请求方法 */
36
+ method?: RequestMethod | Lowercase<RequestMethod>;
37
+ /**
38
+ * 响应体解析方式
39
+ * 如果存在 onResponse 的话, 则会使用 onResponse 的返回值, 如果想要屏蔽 onResponse 的继承, 则应该设置 onResponse 为 null
40
+ *
41
+ * @default 'json'
42
+ */
43
+ parser?: Parser;
44
+ /**
45
+ * transform data transfer object
46
+ *
47
+ * @tips GET/HEAD 方法因为是无 body 的请求, 不会触发 tdto 的转换
48
+ *
49
+ * @description hook 顺序: tdto -> onRequest -> onResponse/parser -> tvo
50
+ */
51
+ tdto?: ((data: Input) => any) | null;
52
+ /**
53
+ * transform view object
54
+ *
55
+ * @description hook 顺序: tdto -> onRequest -> onResponse/parser -> tvo
56
+ */
57
+ tvo?: ((data: Awaited<FindNonAny<[ResOutput, ReturnType<NonNullable<DefaultConfig['onResponse']>>]>>) => Output) | null;
58
+ /**
59
+ * 请求前 hook
60
+ *
61
+ * @description hook 顺序: tdto -> onRequest -> onResponse/parser -> tvo
62
+ */
63
+ onRequest?: ((req: Request, config: RequestAPIConfig<Input, Output, ReqOutput, ResOutput, ReqModeMapKeys>) => ReqOutput) | null;
64
+ /**
65
+ * 响应前 hook
66
+ * 会覆盖 parser 的解析方式
67
+ *
68
+ * @description hook 顺序: tdto -> onRequest -> onResponse/parser -> tvo
69
+ */
70
+ onResponse?: ((res: Response, config: RequestAPIConfig<Input, Output, ReqOutput, ResOutput, ReqModeMapKeys>) => ResOutput) | null;
71
+ }
72
+ export interface DefaultAPIConfig<Input = any, Output = any, ReqOutput = any, ResOutput = any, ReqModeMapKeys extends string = string & {}> extends Omit<BaseAPIConfig<Input, Output, ReqOutput, ResOutput, DefaultAPIConfig, ReqModeMapKeys>, 'url'> {
73
+ /** 基本地址 */
74
+ baseUrl?: string;
75
+ /** 请求模式 map */
76
+ requestModeMap?: Record<ReqModeMapKeys, (config: RequestAPIConfig<Input, Output, ReqOutput, ResOutput, ReqModeMapKeys>) => any>;
77
+ }
78
+ export interface RequestAPIConfig<Input = any, Output = any, ReqOutput = any, ResOutput = any, ReqModeMapKeys extends string = string & {}> extends DefaultAPIConfig<Input, Output, ReqOutput, ResOutput, ReqModeMapKeys>, APIConfig<Input, Output, ReqOutput, ResOutput, DefaultAPIConfig, ReqModeMapKeys> {
79
+ /** 请求数据 */
80
+ data?: Input;
81
+ oriUrl: string;
82
+ }
83
+ /**
84
+ * API config
85
+ */
86
+ export type APIConfig<Input = any, Output = any, ReqOutput = any, ResOutput = any, DefaultConfig extends DefaultAPIConfig = DefaultAPIConfig, ReqModeMapKeys extends string = string & {}, Url extends string = string> = BaseAPIConfig<Input, Output, ReqOutput, ResOutput, DefaultConfig, ReqModeMapKeys, Url>;
87
+ export type CallAPIConfig<Input = any, Output = any, ReqOutput = any, ResOutput = any, DefaultConfig extends DefaultAPIConfig = DefaultAPIConfig, ReqModeMapKeys extends string = string & {}, Url extends string = string> = Omit<APIConfig<Input, Output, ReqOutput, ResOutput, DefaultConfig, ReqModeMapKeys, Url>, 'url'>;
88
+ export type DefineAPIConfig<U extends string> = APIConfig<any, any, any, any, any, any, U>;
89
+ /** API map */
90
+ export interface APIMap<U extends string = string & {}> {
91
+ [key: string]: DefineAPIConfig<U> | APIMap<U>;
92
+ }
93
+ export type IsUnknownAny<T> = Equal<T, any> extends true ? true : Equal<T, unknown> extends true ? true : false;
94
+ export type FindNonAny<T extends any[], Other = Empty> = T extends [infer F, ...infer Last] ? IsUnknownAny<F> extends true ? FindNonAny<Last, Other> : F extends Other ? FindNonAny<Last, Other> : F : any;
95
+ type APIHandlerArgs<I, C extends CallAPIConfig, Custom, NonParamUrl extends boolean> = FindNonAny<[
96
+ NonParamUrl extends true ? any : [I, C & Required<Pick<C, 'params'>>],
97
+ Custom extends true ? [I?, C?] : [I?],
98
+ [I?]
99
+ ]>;
100
+ type DefineRequestModes<D extends DefaultAPIConfig> = keyof NonNullable<D['requestModeMap']> & string;
101
+ type RealProp<P extends keyof DefaultAPIConfig & keyof APIConfig, C extends Pick<APIConfig, P>, A extends Pick<APIConfig, P>, D extends DefaultAPIConfig, Other = Empty> = FindNonAny<[C[P], A[P], D[P]], Other>;
102
+ type OnResponseReturn<OnResponse> = OnResponse extends AnyFunc ? ReturnType<OnResponse> : any;
103
+ type CustomCallConfigUnwrap<C extends CallAPIConfig, Custom extends boolean> = Custom extends true ? {
104
+ [K in keyof C as undefined extends C[K] ? never : K]: C[K];
105
+ } : Record<never, Empty>;
106
+ interface Pack<T> extends TPack<T> {
107
+ __value: T;
108
+ }
109
+ type PackUnwrap<P> = P extends Pack<any> ? P['__value'] : P;
110
+ interface OriginalPack<T> extends TPack<T> {
111
+ __originValue: T;
112
+ }
113
+ type OriginalPackUnwrap<P> = P extends OriginalPack<any> ? P['__originValue'] : Promise<P>;
114
+ type CustomRequestModeReturn<RealRM extends RequestMode, InputD extends DefaultAPIConfig, CustomReq = NonNullable<InputD['requestModeMap']>[RealRM]> = IsUnknownAny<RealRM> extends true ? any : Equal<RealRM, string> extends true ? any : CustomReq extends AnyFunc ? OriginalPack<ReturnType<CustomReq>> : any;
115
+ type UserInputResult<UserR, CustomRequestResult> = IsUnknownAny<CustomRequestResult> extends true ? UserR : IsUnknownAny<UserR> extends true ? any : UserR extends CustomRequestResult ? OriginalPack<UserR> : UserR;
116
+ type APIHandlerResult<AConfig extends APIConfig, CallConfig extends CallAPIConfig = APIConfig, UserR = Empty, InputDefault extends DefaultAPIConfig = DefaultAPIConfig, ReqOutput = any, Custom extends boolean = false, CC extends CallAPIConfig = CustomCallConfigUnwrap<CallConfig, Custom>, CustomRequestResult = CustomRequestModeReturn<NonNullable<RealProp<'requestMode', CC, AConfig, InputDefault>>, InputDefault>> = OriginalPackUnwrap<Awaited<PackUnwrap<FindNonAny<[
117
+ UserInputResult<EmptyUnwrap<UserR>, OriginalPackUnwrap<CustomRequestResult>>,
118
+ CustomRequestResult,
119
+ ReturnType<Cast<RealProp<'tvo', CC, AConfig, InputDefault>, AnyFunc>>,
120
+ OnResponseReturn<RealProp<'onResponse', CC, AConfig, InputDefault>>,
121
+ ParserReturn<NonNullable<RealProp<'requestMode', CC, AConfig, InputDefault>>, NonNullable<RealProp<'parser', CC, AConfig, InputDefault>>, ReqOutput, UserR>
122
+ ], undefined | null>>>>;
123
+ type APIInputType<A extends Pick<APIConfig, 'tdto'> = APIConfig, D extends Pick<DefaultAPIConfig, 'tdto'> = DefaultAPIConfig> = Parameters<Cast<FindNonAny<[A['tdto'], D['tdto']], undefined | null>, (...args: any[]) => any>>[0];
124
+ type PropResult<A extends APIConfig, P extends keyof A> = A[P] extends AnyFunc ? ReturnType<A[P]> : unknown;
125
+ export type APITransformMethod<A extends APIConfig, InputD extends DefaultAPIConfig = DefaultAPIConfig, Custom extends boolean = false, NonParamUrl extends boolean = CheckNonParamUrlAPIConfig<A>, I extends APIInputType<A, InputD> = APIInputType<A, InputD>> = (<R = Empty, C extends CallAPIConfig<I, any, PropResult<A, 'onRequest'>, PropResult<A, 'onResponse'>, InputD, DefineRequestModes<InputD>, A['url']> = CallAPIConfig<I, any, PropResult<A, 'onRequest'>, PropResult<A, 'onResponse'>, InputD, DefineRequestModes<InputD>, A['url']>>(...args: APIHandlerArgs<Equal<I, APIInputType<A, InputD>> extends true ? APIInputType<C, {
126
+ tdto: Func<[I]>;
127
+ }> : I, C, Custom, NonParamUrl>) => APIHandlerResult<A, Cast<C, Partial<APIConfig>>, R, InputD, ReturnType<Cast<RealProp<'onRequest', C, A, InputD>, AnyFunc>>, Custom>) & APIInstance<A, InputD>;
128
+ export type APIInstance<A, D> = {
129
+ $: A;
130
+ $$: DefaultAPIConfig extends D ? undefined : D;
131
+ $$r: DefaultAPIConfig;
132
+ } & APIInstanceHandler;
133
+ interface APIInstanceHandler {
134
+ $updateBaseUrl(baseUrl?: string): void;
135
+ }
136
+ export type APIMapTransformMethods<M extends APIMap | Record<string, APIConfig>, D extends DefaultAPIConfig = DefaultAPIConfig> = {
137
+ [K in keyof M as M[K] extends APIConfig ? CheckNonParamUrlAPIConfig<M[K]> extends true ? K : never : K]: M[K] extends APIConfig ? APITransformMethod<M[K], D, false> : APIMapTransformMethods<Cast<M[K], APIMap>, D>;
138
+ } & {
139
+ [K in keyof M as M[K] extends APIConfig ? `${K & string}Custom` : never]: APITransformMethod<Cast<M[K], APIConfig>, D, true>;
140
+ } & APIInstance<M, D>;
141
+ export {};
File without changes
@@ -0,0 +1,22 @@
1
+ import type { APIConfig, APIInstance, APIMap, DefaultAPIConfig } from './types';
2
+ export declare function isAbsUrl(url?: string): boolean;
3
+ export declare function targetUrlParser(_url: string, _baseUrl: string): URL;
4
+ export declare function urlParamsParser(url: string, params: Record<string, string> | undefined): string;
5
+ export declare function getBody(data: any, tdto?: APIConfig['tdto']): any;
6
+ export declare function instanceMemberGetter(prop: string, instanceObj: Record<string, any>): any;
7
+ export declare function createInstance(apiMap: APIConfig | APIMap, realDefaultConfig: DefaultAPIConfig, defaultConfig?: DefaultAPIConfig): {
8
+ $: APIMap<string & {}> | APIConfig;
9
+ $$: any;
10
+ $$r: DefaultAPIConfig<any, any, any, any, string & {}>;
11
+ $updateBaseUrl(baseUrl: string | undefined): void;
12
+ };
13
+ export declare function getInstanceMemberOrApi(target: APIMap, prop: string, receiver: any, instanceObj: APIInstance<any, any>): {
14
+ instanceMember: any;
15
+ api?: undefined;
16
+ isCustom?: undefined;
17
+ } | {
18
+ api: APIMap<string & {}> | import("./types").DefineAPIConfig<string & {}>;
19
+ isCustom: boolean;
20
+ instanceMember?: undefined;
21
+ } | undefined;
22
+ export declare function apiNamesCheck(_apiMap: APIMap, isDeep?: boolean): string[];
@@ -0,0 +1,96 @@
1
+ import { logger } from "../logger/index.js";
2
+ import { throwError, throwType } from "../throw-error/index.js";
3
+ import { getType, isPlainNumber, isString } from "../utils/index.js";
4
+ const ABSOLUTE_URL_REG = /^[a-z][a-z\d+\-.]*:/im;
5
+ function isAbsUrl(url) {
6
+ if (!url) return false;
7
+ return ABSOLUTE_URL_REG.test(url);
8
+ }
9
+ function targetUrlParser(_url, _baseUrl) {
10
+ if (isAbsUrl(_url)) return new URL(_url);
11
+ if (!isAbsUrl(_baseUrl)) throwType('apiController.request', 'baseUrl 配置不合法, 必须是绝对路径');
12
+ const baseUrl = new URL(_baseUrl);
13
+ const basePath = '/' === baseUrl.pathname ? '' : baseUrl.pathname.replace(/\/$/, '');
14
+ const relativePath = _url.startsWith('/') ? _url : `/${_url}`;
15
+ const url = `${basePath}${relativePath}`;
16
+ return new URL(url, baseUrl);
17
+ }
18
+ function urlParamsParser(url, params) {
19
+ if (!url.includes('/:')) return url;
20
+ if (!params) throwType('apiController.parseParams', 'url 中存在 params 参数, params 配置不能为空, 请使用 custom 方法调用并传递 params 配置');
21
+ const urlSplit = url.split('/');
22
+ const emptyKeys = [];
23
+ for(let i = 1; i < urlSplit.length; ++i){
24
+ if (':' !== urlSplit[i][0]) continue;
25
+ const param = urlSplit[i].slice(1);
26
+ const originValue = params[param];
27
+ if (!(isPlainNumber(originValue) || originValue)) {
28
+ emptyKeys.push(param);
29
+ continue;
30
+ }
31
+ const paramValue = encodeURIComponent(String(originValue));
32
+ urlSplit[i] = paramValue;
33
+ }
34
+ if (emptyKeys.length) throwType('apiController.parseParams', `params 配置中缺少 [${emptyKeys.join(', ')}] 参数`);
35
+ return urlSplit.join('/');
36
+ }
37
+ function getBody(data, tdto) {
38
+ const _body = tdto ? tdto(data) : data;
39
+ const bodyType = getType(_body);
40
+ switch(bodyType){
41
+ case 'object':
42
+ case 'array':
43
+ case 'number':
44
+ case 'boolean':
45
+ case 'function':
46
+ return JSON.stringify(_body);
47
+ default:
48
+ return _body;
49
+ }
50
+ }
51
+ function instanceMemberGetter(prop, instanceObj) {
52
+ return instanceObj[prop];
53
+ }
54
+ function createInstance(apiMap, realDefaultConfig, defaultConfig) {
55
+ return {
56
+ $: apiMap,
57
+ $$: defaultConfig,
58
+ $$r: realDefaultConfig,
59
+ $updateBaseUrl (baseUrl) {
60
+ if (isAbsUrl(baseUrl)) realDefaultConfig.baseUrl = baseUrl;
61
+ else {
62
+ const { origin } = globalThis.location || {};
63
+ if (!origin) throwError('apiController.$updateBaseUrl', 'location.origin is undefined');
64
+ const normalizedPath = (baseUrl || '/').startsWith('/') ? baseUrl || '' : `/${baseUrl}`;
65
+ realDefaultConfig.baseUrl = `${origin}${normalizedPath}`;
66
+ }
67
+ }
68
+ };
69
+ }
70
+ function getInstanceMemberOrApi(target, prop, receiver, instanceObj) {
71
+ if (Reflect.getOwnPropertyDescriptor(instanceObj, prop)) return {
72
+ instanceMember: instanceMemberGetter(prop, instanceObj)
73
+ };
74
+ const hasExactProp = isString(prop) && Reflect.has(target, prop);
75
+ const isCustom = isString(prop) && prop.endsWith('Custom') && !hasExactProp;
76
+ const name = isCustom ? prop.slice(0, -6) : prop;
77
+ if (!Reflect.getOwnPropertyDescriptor(target, name)) return;
78
+ const api = Reflect.get(target, name, receiver);
79
+ if (isCustom && !isString(api.url)) return;
80
+ return {
81
+ api,
82
+ isCustom
83
+ };
84
+ }
85
+ function apiNamesCheck(_apiMap, isDeep = false) {
86
+ const apiNames = Reflect.ownKeys(_apiMap);
87
+ const warnNames = [];
88
+ for(let i = 0; i < apiNames.length; i++){
89
+ const name = apiNames[i];
90
+ if (name.endsWith('Custom')) warnNames.push(name);
91
+ if (!isString(_apiMap[name].url)) warnNames.push(...apiNamesCheck(_apiMap[name], true));
92
+ }
93
+ if (!isDeep && warnNames.length > 0) logger.warn('apiController.createApiWithMap', 'api 命名不应该使用 Custom 结尾, 因为这是一个内部实现的方法', warnNames);
94
+ return warnNames;
95
+ }
96
+ export { apiNamesCheck, createInstance, getBody, getInstanceMemberOrApi, instanceMemberGetter, isAbsUrl, targetUrlParser, urlParamsParser };
@@ -1,8 +1,6 @@
1
1
  import { logger } from "../logger/index.js";
2
2
  import { throwType } from "../throw-error/index.js";
3
- function getType(_v) {
4
- return Object.prototype.toString.call(_v).slice(8, -1).toLowerCase();
5
- }
3
+ import { getType } from "../utils/base.js";
6
4
  function typeHandler(type, verifyFn) {
7
5
  return (fullback)=>(_v, actions)=>{
8
6
  if (verifyFn ? verifyFn(_v) : getType(_v) === type) return true;
@@ -0,0 +1,8 @@
1
+ export declare const SLOT_TYPE: {
2
+ readonly fixed: {
3
+ readonly fixedFlag: symbol;
4
+ };
5
+ readonly insert: {
6
+ readonly insertFlag: symbol;
7
+ };
8
+ };
@@ -0,0 +1,9 @@
1
+ const SLOT_TYPE = {
2
+ fixed: {
3
+ fixedFlag: Symbol('fixed')
4
+ },
5
+ insert: {
6
+ insertFlag: Symbol('insert')
7
+ }
8
+ };
9
+ export { SLOT_TYPE };
@@ -0,0 +1,128 @@
1
+ import type { PickRequired } from '../types/base';
2
+ import type { BuildOptions, DataMixedManagerOptions, DMMEventHandler, EventDetailMap, InputSlotConfig, MixedDataItem } from './types';
3
+ /**
4
+ * 通用数据管理器类
5
+ * 支持定坑逻辑处理,不包含具体业务逻辑
6
+ *
7
+ * @template T - 数据类型
8
+ */
9
+ declare class DataMixedManager<T> extends EventTarget {
10
+ addEventListener<E extends keyof EventDetailMap<T>>(type: E, listener: DMMEventHandler<T, E> | null, options?: AddEventListenerOptions | boolean): void;
11
+ removeEventListener<E extends keyof EventDetailMap<T>>(type: E, listener: DMMEventHandler<T, E> | null, options?: EventListenerOptions | boolean): void;
12
+ /** 实例配置 */
13
+ private readonly options;
14
+ /** 位置到定坑配置的映射 */
15
+ private readonly fixedSlots;
16
+ /** 普通数据列表 */
17
+ private readonly dataList;
18
+ /** 混合后的数据 */
19
+ private readonly mixedData;
20
+ /** 最后混合的定坑位置 */
21
+ private lastMixedSlotIdx;
22
+ /** 上次处理的数据长度 */
23
+ private prevDataLength;
24
+ /** 是否正在批量更新 */
25
+ private isBatching;
26
+ constructor(options?: DataMixedManagerOptions<T>);
27
+ /**
28
+ * 初始化事件监听
29
+ * @param listener - 事件监听
30
+ */
31
+ private initListener;
32
+ private getTypeText;
33
+ private buildSlotConfig;
34
+ /**
35
+ * 添加定坑配置
36
+ * @param config - 定坑配置
37
+ * @param buildOptions - 构建选项
38
+ * @returns 返回添加后的定坑位置
39
+ */
40
+ addFixedSlot(config: InputSlotConfig<T>, buildOptions?: BuildOptions): number;
41
+ /**
42
+ * 重新排序定坑位置
43
+ * 当插入模式为 before 或 after 时,需要调整后续定坑的位置
44
+ * @param config - 定坑配置
45
+ * @returns 返回调整后的定坑配置
46
+ */
47
+ private reorderFixedSlots;
48
+ /**
49
+ * 批量添加定坑配置
50
+ * @param configs - 定坑配置数组
51
+ * @param buildOptions - 构建选项
52
+ * @returns 返回添加后的定坑位置数组
53
+ */
54
+ addFixedSlots(configs: InputSlotConfig<T>[], buildOptions?: BuildOptions): number[];
55
+ /**
56
+ * 移除指定位置的定坑配置
57
+ * @param position - 要移除的定坑位置
58
+ * @param buildOptions - 构建选项
59
+ */
60
+ deleteFixedSlot(position: number, buildOptions?: BuildOptions): void;
61
+ /**
62
+ * 批量移除定坑配置
63
+ * @param positions - 要移除的定坑位置数组
64
+ * @param buildOptions - 构建选项
65
+ */
66
+ deleteFixedSlots(positions: number[], buildOptions?: BuildOptions): void;
67
+ /**
68
+ * 批量更新
69
+ * @param callback - 更新回调
70
+ */
71
+ private batchUpdate;
72
+ /**
73
+ * 清除所有定坑配置
74
+ * @param buildOptions - 构建选项
75
+ */
76
+ clearFixedSlots(buildOptions?: BuildOptions): void;
77
+ /**
78
+ * 追加新的数据列表到普通数据列表末尾
79
+ * @param list - 要追加的数据数组
80
+ * @param buildOptions - 构建选项,lazy 为 true 时延迟构建
81
+ */
82
+ appendList(list: T[], buildOptions?: BuildOptions): void;
83
+ /**
84
+ * 清空普通数据列表
85
+ */
86
+ clearList(): void;
87
+ /**
88
+ * 获取混合后的数据
89
+ * @param buildOptions - 构建选项
90
+ * @returns 返回混合后的数据项数组
91
+ */
92
+ getMixedData(buildOptions?: Omit<BuildOptions, 'lazy'>): MixedDataItem<T>[];
93
+ /**
94
+ * 分发事件
95
+ * 同时在实例和 window 对象上触发事件
96
+ * @param name - 事件名称
97
+ * @param data - 事件数据
98
+ */
99
+ private dispatch;
100
+ /**
101
+ * 重新构建混合数据
102
+ * 全局定坑:定坑位置始终固定在全局位置,普通数据在定坑位置之外填充
103
+ * 定坑位置不会因为普通数据的变化而改变
104
+ */
105
+ private buildMixedData;
106
+ /**
107
+ * 切片获取指定范围内的定坑位置
108
+ * @param startIdx - 起始位置
109
+ * @param endIdx - 结束位置,默认为正无穷
110
+ * @returns 返回过滤后的定坑位置数组
111
+ */
112
+ private sliceSlots;
113
+ /**
114
+ * 插入数据(插卡模式)
115
+ * 在指定位置插入数据,会触发全量重建
116
+ * @param config - 定坑配置,必须指定插入模式
117
+ * @returns 返回插入后的实际位置
118
+ */
119
+ insertSlot(config: PickRequired<InputSlotConfig<T>, 'insertMode'>): number;
120
+ insertSlots(configs: PickRequired<InputSlotConfig<T>, 'insertMode'>[]): number[];
121
+ }
122
+ /**
123
+ * 创建数据管理器实例的工厂函数
124
+ * @template T - 数据类型
125
+ * @returns 返回一个新的 DataMixedManager 实例
126
+ */
127
+ export declare function dataMixedManager<T>(options?: DataMixedManagerOptions<T>): DataMixedManager<T>;
128
+ export {};