soon-fetch 2.0.1 → 2.1.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 CHANGED
@@ -20,6 +20,7 @@
20
20
  - [Restful Url Params](#restful-url-params)
21
21
  - [Timeout](#timeout)
22
22
  - [Rapid Define APIs](#rapid-define-apis)
23
+ - [API](#api)
23
24
  - [Support Me](#support-me)
24
25
 
25
26
  ### Example
@@ -31,19 +32,12 @@
31
32
  import { createSoon, parseUrlOptions, type SoonOptions } from "soon-fetch";
32
33
 
33
34
  const request = <T>(url: string, options?: SoonOptions) => {
34
- // _url : url handled with baseURL , options.query , options.params
35
- // _options: 1. merge baseOptions and options,
36
- // 2. transfer merged options from SoonOptions to raw fetch options
37
- // 3. json object body would be auto stringified and add header { "Content-Type": "application/json" }
38
35
  const [_url, _options] = parseUrlOptions({
39
36
  url,
40
37
  options,
41
38
  baseURL: "/api",
42
39
  baseOptions: {
43
- // would override by options.timeout
44
40
  timeout: 20 * 1000,
45
- // would merged with options.headers
46
- // the same-key header would override by options.headers
47
41
  headers: { Authorization: localStorage.getItem("token") ?? "" },
48
42
  },
49
43
  });
@@ -125,12 +119,81 @@ soon.get(url, { timeout: 1000 * 20 });
125
119
  })
126
120
  ```
127
121
 
122
+ ### API
123
+
124
+ #### SoonOptions
125
+
126
+ ```ts
127
+ // function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
128
+ // RequestInit is fetch's init options
129
+ type SoonOptions = Omit<RequestInit, "body"> & {
130
+ query?:
131
+ | Record<
132
+ string,
133
+ | string
134
+ | number
135
+ | boolean
136
+ | null
137
+ | undefined
138
+ | (string | number | boolean | null | undefined)[]
139
+ >
140
+ | URLSearchParams;
141
+ params?: Record<string, string | number>;
142
+ timeout?: number;
143
+ body?: RequestInit["body"] | object;
144
+ };
145
+ ```
146
+
147
+ #### parseUrlOptions
148
+
149
+ `parseUrlOptions` source code:
150
+
151
+ ```ts
152
+ function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
153
+ url: string;
154
+ options?: Options;
155
+ baseURL?: string;
156
+ baseOptions?: Options;
157
+ }) {
158
+ const { url, options, baseURL, baseOptions } = urlOptions;
159
+ //override baseOptions
160
+ const _options = { ...baseOptions, ...options };
161
+
162
+ //signal merge signals by AbortSignal.any
163
+ _options.signal = mergeSignals(
164
+ [baseOptions?.signal, options?.signal],
165
+ _options.timeout
166
+ );
167
+
168
+ //url handled with baseURL , options.query , options.params
169
+ const _url = mergeUrl(url, { ..._options, baseURL });
170
+
171
+ //body auto stringify json body
172
+ let _body = options?.body;
173
+ let is_body_json = isBodyJson(_body);
174
+ _options.body = is_body_json ? JSON.stringify(_body) : _body;
175
+
176
+ //headers merge headers , the same-key header would be override by options.headers
177
+ //if body is json ,then add header "Content-Type": "application/json" }
178
+ const headers = mergeHeaders(
179
+ baseOptions?.headers,
180
+ options?.headers,
181
+ is_body_json ? { "Content-Type": "application/json" } : undefined
182
+ );
183
+ _options.headers = headers;
184
+
185
+ return [_url, _options as Options & { headers: Headers }] as const;
186
+ }
187
+ ```
188
+
189
+ You can customize your own parse function with the functions exported below:
190
+ `mergeHeaders`, `mergeSignals`, `mergeUrl`, `isBodyJson`
191
+
128
192
  ### Support Me
129
193
 
130
194
  If you like this library , you can give a **star** on github.
131
195
  GitHub: https://github.com/leafio/soon-fetch
132
196
 
133
- > I'm looking for a frontend job , expecting an offer or chance for me .
134
197
  > Email: leafnote@outlook.com
135
198
 
136
199
  [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
@@ -151,11 +214,13 @@ GitHub: https://github.com/leafio/soon-fetch
151
214
  - [示例](#示例)
152
215
 
153
216
  - [特别功能](#特别功能)
217
+
154
218
  - [快捷方法](#快捷方法)
155
219
  - [Restful Url 参数自动处理](#restful-url-参数自动处理)
156
220
  - [超时](#超时)
157
221
  - [快速定义 API](#快速定义-api)
158
222
 
223
+ - [API](#api-1)
159
224
  - [支持一下](#支持一下)
160
225
 
161
226
  ### 示例
@@ -165,19 +230,12 @@ GitHub: https://github.com/leafio/soon-fetch
165
230
 
166
231
  ```typescript
167
232
  const request = <T>(url: string, options?: SoonOptions) => {
168
- // _url : url 根据 baseURL , options.query , options.params 进行拼接
169
- // _options: 1. 合并 baseOptions 和 options
170
- // 2. 合并结果 从 SoonOptions 转换至 原生 fetch options
171
- // 3. json object 会自动 stringified , 并且添加 header { "Content-Type": "application/json" }
172
233
  const [_url, _options] = parseUrlOptions({
173
234
  url,
174
235
  options,
175
236
  baseURL: "/api",
176
237
  baseOptions: {
177
- // 会被 options.timeout 覆盖
178
238
  timeout: 20 * 1000,
179
- // 将与 options.headers 合并
180
- // 相同key的 header 会被options.headers覆盖
181
239
  headers: { Authorization: localStorage.getItem("token") ?? "" },
182
240
  },
183
241
  });
@@ -258,12 +316,81 @@ soon.get(url, { timeout: 1000 * 20 });
258
316
  })
259
317
  ```
260
318
 
319
+ ### API
320
+
321
+ #### SoonOptions
322
+
323
+ ```ts
324
+ // function fetch(input: RequestInfo | URL, init?: RequestInit): Promise<Response>
325
+ // RequestInit 为原生 fetch 的 init 选项
326
+ type SoonOptions = Omit<RequestInit, "body"> & {
327
+ query?:
328
+ | Record<
329
+ string,
330
+ | string
331
+ | number
332
+ | boolean
333
+ | null
334
+ | undefined
335
+ | (string | number | boolean | null | undefined)[]
336
+ >
337
+ | URLSearchParams;
338
+ params?: Record<string, string | number>;
339
+ timeout?: number;
340
+ body?: RequestInit["body"] | object;
341
+ };
342
+ ```
343
+ #### parseUrlOptions
344
+
345
+ `parseUrlOptions` 源码如下:
346
+
347
+ ```ts
348
+ function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
349
+ url: string;
350
+ options?: Options;
351
+ baseURL?: string;
352
+ baseOptions?: Options;
353
+ }) {
354
+ const { url, options, baseURL, baseOptions } = urlOptions;
355
+ // 覆盖 baseOptions
356
+ const _options = { ...baseOptions, ...options };
357
+
358
+ // 以 AbortSignal.any 的方式合并 baseOptions.signal 、 options.signal 、
359
+ // 以及 AbortSignal.timeout( _options.timeout)
360
+ _options.signal = mergeSignals(
361
+ [baseOptions?.signal, options?.signal],
362
+ _options.timeout
363
+ );
364
+
365
+ //根据 baseURL , options.query , options.params 解析出完整的url
366
+ const _url = mergeUrl(url, { ..._options, baseURL });
367
+
368
+ // 自动stringify json-object类的body
369
+ let _body = options?.body;
370
+ let is_body_json = isBodyJson(_body);
371
+ _options.body = is_body_json ? JSON.stringify(_body) : _body;
372
+
373
+ //合并headers, 相同key值的header会被options.headers覆盖
374
+ //当body 为 json ,自动添加 header "Content-Type": "application/json" }
375
+ const headers = mergeHeaders(
376
+ baseOptions?.headers,
377
+ options?.headers,
378
+ is_body_json ? { "Content-Type": "application/json" } : undefined
379
+ );
380
+ _options.headers = headers;
381
+
382
+ return [_url, _options as Options & { headers: Headers }] as const;
383
+ }
384
+ ```
385
+
386
+ 如有特殊需要,可以根据下方的函数定制你自己的解析函数来替代 `parseUrlOptions`:
387
+ `mergeHeaders`, `mergeSignals`, `mergeUrl`, `isBodyJson`
388
+
261
389
  ### 支持一下
262
390
 
263
391
  喜欢 soon-fetch 的话 , 在 github 上给个 **star** 吧.
264
392
  GitHub: https://github.com/leafio/soon-fetch
265
393
 
266
- > 我目前在找前端的工作,有岗位机会的话,可以联系我。
267
394
  > Email: leafnote@outlook.com
268
395
 
269
396
  [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
package/dist/index.cjs.js CHANGED
@@ -1 +1 @@
1
- "use strict";const t=t=>{const r=[],e=t.match(/:([^:/\d]+)\/?/g);return e&&e.forEach((t=>{r.push(t.replace(/\//g,"").replace(/:/g,""))})),r},r=(t="")=>t.startsWith("http"),e=(t="")=>r(t)?t:((t="")=>{let r=t;return t&&(r=((t="")=>t.endsWith("/")?t.slice(0,-1):t)(r),t.startsWith("/")||(r="/"+r)),r})(t),n=t=>{if(!t)return[];if(t instanceof URLSearchParams||"string"==typeof t||Array.isArray(t))return Array.from(new URLSearchParams(t).entries());const r=[];return Object.keys(t).forEach((e=>{const n=t[e];(Array.isArray(n)?n:[n]).forEach((t=>{r.push([e,t??""])}))})),r},a=(a,o)=>{const{query:s,params:i,baseURL:c}=o;let f=a.trim();t(a).forEach((t=>{i&&(f=f.replace(":"+t,""+i[t]))}));const[p,u]=f.split("?"),h=new URLSearchParams([...n(u),...n(s)]);let y=((t,n)=>{let a=e(t);return r(a)||(a=e(n)+a),a})(p,c);return h.size&&(y=y+"?"+h),y},o=(...t)=>{const r=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,e)=>{r.set(e,t)}))})),r},s=(t,r)=>{const e=(r??[]).filter((t=>!!t));return t&&e.push(AbortSignal.timeout(t)),e.length?AbortSignal.any(e):void 0};function i(t){let r=!1,e=t;var n;return e&&"object"==typeof e&&!(e instanceof Blob||e instanceof ArrayBuffer||e instanceof FormData||e instanceof File||e instanceof DataView||e instanceof URLSearchParams||e instanceof ReadableStream||(n=e,n instanceof Int8Array||n instanceof Uint8Array||n instanceof Uint8ClampedArray||n instanceof Int16Array||n instanceof Uint16Array||n instanceof Int32Array||n instanceof Uint32Array||n instanceof Float32Array||n instanceof Float64Array||n instanceof BigInt64Array||n instanceof BigUint64Array))&&(r=!0,e=JSON.stringify(e)),[e,r]}const c=["get","post","put","delete","patch"];function f(t,r){const e={};return t.forEach((t=>{e[t]=(e,n)=>r(e,{...n,method:t})})),e}function p(r){return(e,n)=>{const a={},o=!!t(e).length;return c.forEach((t=>{const s=t.toUpperCase();a[s]=()=>(...a)=>{const[s,i]=a,c="get"===t?"query":"body";return r(e,{...n,method:t,params:o?s:void 0,[c]:o?i:s})}})),a}}exports.createShortAPI=p,exports.createShortMethods=f,exports.createSoon=function(t){const r=t;return{request:r,API:p(r),...f([...c,"head","options"],r)}},exports.mergeHeaders=o,exports.mergeSignals=s,exports.mergeUrl=a,exports.parseUrlOptions=function(t){const{url:r,options:e,baseURL:n,baseOptions:c}=t,f={...c,...e};f.signal=s(f.timeout,[f.signal]);const p=a(r,{...f,baseURL:n}),[u,h]=i(f.body);f.body=u;const y=o(c?.headers,e?.headers,h?{"Content-Type":"application/json"}:void 0);return f.headers=y,[p,f]},exports.stringifyBody=i;
1
+ "use strict";const t=t=>{const r=[],e=t.match(/:([^:/\d]+)\/?/g);return e&&e.forEach((t=>{r.push(t.replace(/\//g,"").replace(/:/g,""))})),r},r=(t="")=>t.endsWith("/")?t.slice(0,-1):t,e=(t="")=>t.startsWith("/")?t:"/"+t,n=(t="")=>t.startsWith("http"),a=t=>{if(!t)return[];if(t instanceof URLSearchParams||"string"==typeof t||Array.isArray(t))return Array.from(new URLSearchParams(t).entries());const r=[];return Object.keys(t).forEach((e=>{const n=t[e];(Array.isArray(n)?n:[n]).forEach((t=>{r.push([e,t??""])}))})),r},o=(o,s)=>{const{query:i,params:c,baseURL:f}=s;let p=o.trim();t(o).forEach((t=>{c&&(p=p.replace(":"+t,""+c[t]))}));const[u,h]=p.split("?"),y=new URLSearchParams([...a(h),...a(i)]);let l=((t,a)=>{if(n(t))return t;const o=n(a)?a:e(a);return r(o)+r(e(t))})(u,f);return y.size&&(l=l+"?"+y),l},s=(...t)=>{const r=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,e)=>{r.set(e,t)}))})),r};function i(t,r){const e=(t??[]).filter((t=>!!t));return r&&e.push(AbortSignal.timeout(r)),e.length?AbortSignal.any(e):void 0}function c(t){return!(!t||"object"!=typeof t||(t instanceof Blob||t instanceof ArrayBuffer||t instanceof FormData||t instanceof File||t instanceof DataView||t instanceof URLSearchParams||t instanceof ReadableStream||(r=t,r instanceof Int8Array||r instanceof Uint8Array||r instanceof Uint8ClampedArray||r instanceof Int16Array||r instanceof Uint16Array||r instanceof Int32Array||r instanceof Uint32Array||r instanceof Float32Array||r instanceof Float64Array||r instanceof BigInt64Array||r instanceof BigUint64Array)));var r}const f=["get","post","put","delete","patch"];function p(t,r){const e={};return t.forEach((t=>{e[t]=(e,n)=>r(e,{...n,method:t})})),e}function u(r){return(e,n)=>{const a={},o=!!t(e).length;return f.forEach((t=>{const s=t.toUpperCase();a[s]=()=>(...a)=>{const[s,i]=a,c="get"===t?"query":"body";return r(e,{...n,method:t,params:o?s:void 0,[c]:o?i:s})}})),a}}exports.createShortAPI=u,exports.createShortMethods=p,exports.createSoon=function(t){const r=t;return{request:r,API:u(r),...p([...f,"head","options"],r)}},exports.isBodyJson=c,exports.mergeHeaders=s,exports.mergeSignals=i,exports.mergeUrl=o,exports.parseUrlOptions=function(t){const{url:r,options:e,baseURL:n,baseOptions:a}=t,f={...a,...e};f.signal=i([a?.signal,e?.signal],f.timeout);const p=o(r,{...f,baseURL:n});let u=e?.body,h=c(u);f.body=h?JSON.stringify(u):u;const y=s(a?.headers,e?.headers,h?{"Content-Type":"application/json"}:void 0);return f.headers=y,[p,f]};
package/dist/index.d.ts CHANGED
@@ -1,44 +1,46 @@
1
- type SoonOptions = RequestInit & {
2
- query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
3
- params?: Record<string, string | number>;
4
- timeout?: number;
5
- };
6
- type GetUrlKey<Url> = Url extends `${string}/:${infer Key}/${infer Right}` ? `${Key}` | GetUrlKey<`/${Right}`> : Url extends `${string}/:${infer Key}` ? `${Key}` : never;
7
- type OptionParams<Args> = NonNullable<Args> extends never ? [] : keyof NonNullable<Args> extends never ? [] : Exclude<Args, NonNullable<Args>> extends never ? [params: Args] : [params?: Args];
8
- type OptionQuery<Args> = NonNullable<Args> extends never ? [] : keyof NonNullable<Args> extends never ? [] : Exclude<Args, NonNullable<Args>> extends never ? Partial<Args> extends Args ? [query?: Args] : [query: Args] : [query?: Args];
9
- type OptionBody<Args> = NonNullable<Args> extends never ? [] : Exclude<Args, NonNullable<Args>> extends never ? [body: Args] : [body?: Args];
10
- type Tuple2Union<T> = T extends [infer T1, infer T2, ...infer R] ? T1 | T2 | Tuple2Union<R> : T extends [infer T_Only] ? T_Only : never;
11
-
12
- declare const mergeUrl: (url: string, config: {
13
- query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
14
- params?: Record<string, string | number>;
15
- baseURL?: string;
16
- }) => string;
17
- declare const mergeHeaders: (...headersList: (HeadersInit | undefined)[]) => Headers;
18
- declare const mergeSignals: (timeout?: number, signals?: (AbortSignal | null | undefined)[]) => AbortSignal | undefined;
19
- declare function stringifyBody(body?: any): [body: any, isBodyJson: boolean];
20
- declare function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
21
- url: string;
22
- options?: Options;
23
- baseURL?: string;
24
- baseOptions?: Options;
25
- }): readonly [string, Options & {
26
- headers: Headers;
27
- }];
28
- declare function createSoon<T extends (url: string, options?: SoonOptions) => Promise<any>>(requestFun: T): {
29
- options: T;
30
- get: T;
31
- post: T;
32
- put: T;
33
- delete: T;
34
- patch: T;
35
- head: T;
36
- request: T;
37
- API: <Url extends string>(url: Url, options?: Parameters<T>[1] | undefined) => Record<"GET", <Req = undefined, Res = Awaited<ReturnType<T>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionQuery<Req>]) => Promise<Res>> & Record<"POST" | "PATCH" | "DELETE" | "PUT", <Req = undefined, Res_1 = Awaited<ReturnType<T>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res_1>>;
38
- };
39
- declare function createShortMethods<Methods extends string[], RequestFun extends <T>(url: string, options?: {
40
- method?: string;
41
- }) => Promise<any>>(methods: Methods, requestFun: RequestFun): Record<Tuple2Union<Methods>, typeof requestFun>;
42
- declare function createShortAPI<requestFun extends <T>(url: string, options?: SoonOptions) => Promise<any>>(requestFun: requestFun): <Url extends string>(url: Url, options?: Parameters<requestFun>[1]) => Record<"GET", <Req = undefined, Res = Awaited<ReturnType<requestFun>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionQuery<Req>]) => Promise<Res>> & Record<"POST" | "PATCH" | "DELETE" | "PUT", <Req = undefined, Res_1 = Awaited<ReturnType<requestFun>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res_1>>;
43
-
44
- export { type SoonOptions, createShortAPI, createShortMethods, createSoon, mergeHeaders, mergeSignals, mergeUrl, parseUrlOptions, stringifyBody };
1
+ type SoonOptions = Omit<RequestInit, "body"> & {
2
+ query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
3
+ params?: Record<string, string | number>;
4
+ timeout?: number;
5
+ body?: RequestInit["body"] | object;
6
+ };
7
+ type GetUrlKey<Url> = Url extends `${string}/:${infer Key}/${infer Right}` ? `${Key}` | GetUrlKey<`/${Right}`> : Url extends `${string}/:${infer Key}` ? `${Key}` : never;
8
+ type OptionParams<Args> = NonNullable<Args> extends never ? [] : keyof NonNullable<Args> extends never ? [] : Exclude<Args, NonNullable<Args>> extends never ? [params: Args] : [params?: Args];
9
+ type OptionQuery<Args> = NonNullable<Args> extends never ? [] : keyof NonNullable<Args> extends never ? [] : Exclude<Args, NonNullable<Args>> extends never ? Partial<Args> extends Args ? [query?: Args] : [query: Args] : [query?: Args];
10
+ type OptionBody<Args> = NonNullable<Args> extends never ? [] : Exclude<Args, NonNullable<Args>> extends never ? [body: Args] : [body?: Args];
11
+ type Tuple2Union<T> = T extends [infer T1, infer T2, ...infer R] ? T1 | T2 | Tuple2Union<R> : T extends [infer T_Only] ? T_Only : never;
12
+
13
+ declare const mergeUrl: (url: string, config: {
14
+ query?: Record<string, string | number | boolean | null | undefined | (string | number | boolean | null | undefined)[]> | URLSearchParams;
15
+ params?: Record<string, string | number>;
16
+ baseURL?: string;
17
+ }) => string;
18
+ declare const mergeHeaders: (...headersList: (HeadersInit | undefined)[]) => Headers;
19
+ declare function mergeSignals(signals?: (AbortSignal | null | undefined)[], timeout?: number): AbortSignal | undefined;
20
+ declare function isBodyJson(body: any): boolean;
21
+ declare function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
22
+ url: string;
23
+ options?: Options;
24
+ baseURL?: string;
25
+ baseOptions?: Options;
26
+ }): readonly [string, Options & {
27
+ headers: Headers;
28
+ body?: BodyInit | null;
29
+ }];
30
+ declare function createSoon<T extends (url: string, options?: SoonOptions) => Promise<any>>(requestFun: T): {
31
+ options: T;
32
+ get: T;
33
+ post: T;
34
+ put: T;
35
+ delete: T;
36
+ patch: T;
37
+ head: T;
38
+ request: T;
39
+ API: <Url extends string>(url: Url, options?: Parameters<T>[1] | undefined) => Record<"GET", <Req = undefined, Res = Awaited<ReturnType<T>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionQuery<Req>]) => Promise<Res>> & Record<"POST" | "PATCH" | "DELETE" | "PUT", <Req = undefined, Res = Awaited<ReturnType<T>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>>;
40
+ };
41
+ declare function createShortMethods<Methods extends string[], RequestFun extends <T>(url: string, options?: {
42
+ method?: string;
43
+ }) => Promise<any>>(methods: Methods, requestFun: RequestFun): Record<Tuple2Union<Methods>, typeof requestFun>;
44
+ declare function createShortAPI<requestFun extends <T>(url: string, options?: SoonOptions) => Promise<any>>(requestFun: requestFun): <Url extends string>(url: Url, options?: Parameters<requestFun>[1]) => Record<"GET", <Req = undefined, Res = Awaited<ReturnType<requestFun>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionQuery<Req>]) => Promise<Res>> & Record<"POST" | "PATCH" | "DELETE" | "PUT", <Req = undefined, Res = Awaited<ReturnType<requestFun>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>>;
45
+
46
+ export { type SoonOptions, createShortAPI, createShortMethods, createSoon, isBodyJson, mergeHeaders, mergeSignals, mergeUrl, parseUrlOptions };
package/dist/index.js CHANGED
@@ -1 +1 @@
1
- const t=t=>{const n=[],r=t.match(/:([^:/\d]+)\/?/g);return r&&r.forEach((t=>{n.push(t.replace(/\//g,"").replace(/:/g,""))})),n},n=(t="")=>t.startsWith("http"),r=(t="")=>n(t)?t:((t="")=>{let n=t;return t&&(n=((t="")=>t.endsWith("/")?t.slice(0,-1):t)(n),t.startsWith("/")||(n="/"+n)),n})(t),e=t=>{if(!t)return[];if(t instanceof URLSearchParams||"string"==typeof t||Array.isArray(t))return Array.from(new URLSearchParams(t).entries());const n=[];return Object.keys(t).forEach((r=>{const e=t[r];(Array.isArray(e)?e:[e]).forEach((t=>{n.push([r,t??""])}))})),n},a=(a,o)=>{const{query:s,params:i,baseURL:c}=o;let f=a.trim();t(a).forEach((t=>{i&&(f=f.replace(":"+t,""+i[t]))}));const[u,h]=f.split("?"),y=new URLSearchParams([...e(h),...e(s)]);let l=((t,e)=>{let a=r(t);return n(a)||(a=r(e)+a),a})(u,c);return y.size&&(l=l+"?"+y),l},o=(...t)=>{const n=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,r)=>{n.set(r,t)}))})),n},s=(t,n)=>{const r=(n??[]).filter((t=>!!t));return t&&r.push(AbortSignal.timeout(t)),r.length?AbortSignal.any(r):void 0};function i(t){let n=!1,r=t;var e;return r&&"object"==typeof r&&!(r instanceof Blob||r instanceof ArrayBuffer||r instanceof FormData||r instanceof File||r instanceof DataView||r instanceof URLSearchParams||r instanceof ReadableStream||(e=r,e instanceof Int8Array||e instanceof Uint8Array||e instanceof Uint8ClampedArray||e instanceof Int16Array||e instanceof Uint16Array||e instanceof Int32Array||e instanceof Uint32Array||e instanceof Float32Array||e instanceof Float64Array||e instanceof BigInt64Array||e instanceof BigUint64Array))&&(n=!0,r=JSON.stringify(r)),[r,n]}function c(t){const{url:n,options:r,baseURL:e,baseOptions:c}=t,f={...c,...r};f.signal=s(f.timeout,[f.signal]);const u=a(n,{...f,baseURL:e}),[h,y]=i(f.body);f.body=h;const l=o(c?.headers,r?.headers,y?{"Content-Type":"application/json"}:void 0);return f.headers=l,[u,f]}const f=["get","post","put","delete","patch"];function u(t){const n=t;return{request:n,API:y(n),...h([...f,"head","options"],n)}}function h(t,n){const r={};return t.forEach((t=>{r[t]=(r,e)=>n(r,{...e,method:t})})),r}function y(n){return(r,e)=>{const a={},o=!!t(r).length;return f.forEach((t=>{const s=t.toUpperCase();a[s]=()=>(...a)=>{const[s,i]=a,c="get"===t?"query":"body";return n(r,{...e,method:t,params:o?s:void 0,[c]:o?i:s})}})),a}}export{y as createShortAPI,h as createShortMethods,u as createSoon,o as mergeHeaders,s as mergeSignals,a as mergeUrl,c as parseUrlOptions,i as stringifyBody};
1
+ const t=t=>{const n=[],r=t.match(/:([^:/\d]+)\/?/g);return r&&r.forEach((t=>{n.push(t.replace(/\//g,"").replace(/:/g,""))})),n},n=(t="")=>t.endsWith("/")?t.slice(0,-1):t,r=(t="")=>t.startsWith("/")?t:"/"+t,e=(t="")=>t.startsWith("http"),a=t=>{if(!t)return[];if(t instanceof URLSearchParams||"string"==typeof t||Array.isArray(t))return Array.from(new URLSearchParams(t).entries());const n=[];return Object.keys(t).forEach((r=>{const e=t[r];(Array.isArray(e)?e:[e]).forEach((t=>{n.push([r,t??""])}))})),n},o=(o,s)=>{const{query:i,params:c,baseURL:f}=s;let u=o.trim();t(o).forEach((t=>{c&&(u=u.replace(":"+t,""+c[t]))}));const[h,y]=u.split("?"),l=new URLSearchParams([...a(y),...a(i)]);let p=((t,a)=>{if(e(t))return t;const o=e(a)?a:r(a);return n(o)+n(r(t))})(h,f);return l.size&&(p=p+"?"+l),p},s=(...t)=>{const n=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,r)=>{n.set(r,t)}))})),n};function i(t,n){const r=(t??[]).filter((t=>!!t));return n&&r.push(AbortSignal.timeout(n)),r.length?AbortSignal.any(r):void 0}function c(t){return!(!t||"object"!=typeof t||(t instanceof Blob||t instanceof ArrayBuffer||t instanceof FormData||t instanceof File||t instanceof DataView||t instanceof URLSearchParams||t instanceof ReadableStream||(n=t,n instanceof Int8Array||n instanceof Uint8Array||n instanceof Uint8ClampedArray||n instanceof Int16Array||n instanceof Uint16Array||n instanceof Int32Array||n instanceof Uint32Array||n instanceof Float32Array||n instanceof Float64Array||n instanceof BigInt64Array||n instanceof BigUint64Array)));var n}function f(t){const{url:n,options:r,baseURL:e,baseOptions:a}=t,f={...a,...r};f.signal=i([a?.signal,r?.signal],f.timeout);const u=o(n,{...f,baseURL:e});let h=r?.body,y=c(h);f.body=y?JSON.stringify(h):h;const l=s(a?.headers,r?.headers,y?{"Content-Type":"application/json"}:void 0);return f.headers=l,[u,f]}const u=["get","post","put","delete","patch"];function h(t){const n=t;return{request:n,API:l(n),...y([...u,"head","options"],n)}}function y(t,n){const r={};return t.forEach((t=>{r[t]=(r,e)=>n(r,{...e,method:t})})),r}function l(n){return(r,e)=>{const a={},o=!!t(r).length;return u.forEach((t=>{const s=t.toUpperCase();a[s]=()=>(...a)=>{const[s,i]=a,c="get"===t?"query":"body";return n(r,{...e,method:t,params:o?s:void 0,[c]:o?i:s})}})),a}}export{l as createShortAPI,y as createShortMethods,h as createSoon,c as isBodyJson,s as mergeHeaders,i as mergeSignals,o as mergeUrl,f as parseUrlOptions};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "soon-fetch",
3
- "version": "2.0.1",
3
+ "version": "2.1.1",
4
4
  "description": "a 3Kb request lib alternative to axios",
5
5
  "homepage": "https://github.com/leafio/soon-fetch",
6
6
  "main": "./dist/index.cjs.js",