soon-fetch 2.0.1 → 2.1.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.
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,58 @@ soon.get(url, { timeout: 1000 * 20 });
125
119
  })
126
120
  ```
127
121
 
122
+ ### API
123
+
124
+ #### parseUrlOptions
125
+
126
+ `parseUrlOptions` source code:
127
+
128
+ ```ts
129
+ function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
130
+ url: string;
131
+ options?: Options;
132
+ baseURL?: string;
133
+ baseOptions?: Options;
134
+ }) {
135
+ const { url, options, baseURL, baseOptions } = urlOptions;
136
+ //override baseOptions
137
+ const _options = { ...baseOptions, ...options };
138
+
139
+ //signal merge signals by AbortSignal.any
140
+ _options.signal = mergeSignals(
141
+ [baseOptions?.signal, options?.signal],
142
+ _options.timeout
143
+ );
144
+
145
+ //url handled with baseURL , options.query , options.params
146
+ const _url = mergeUrl(url, { ..._options, baseURL });
147
+
148
+ //body auto stringify json body
149
+ let _body = options?.body;
150
+ let is_body_json = isBodyJson(_body);
151
+ _options.body = is_body_json ? JSON.stringify(_body) : _body;
152
+
153
+ //headers merge headers , the same-key header would be override by options.headers
154
+ //if body is json ,then add header "Content-Type": "application/json" }
155
+ const headers = mergeHeaders(
156
+ baseOptions?.headers,
157
+ options?.headers,
158
+ is_body_json ? { "Content-Type": "application/json" } : undefined
159
+ );
160
+ _options.headers = headers;
161
+
162
+ return [_url, _options as Options & { headers: Headers }] as const;
163
+ }
164
+ ```
165
+
166
+ You can customize your own parse function with the functions exported below:
167
+ `mergeHeaders`, `mergeSignals`, `mergeUrl`, `isBodyJson`
168
+
128
169
  ### Support Me
129
170
 
130
171
  If you like this library , you can give a **star** on github.
131
172
  GitHub: https://github.com/leafio/soon-fetch
132
173
 
133
- > I'm looking for a frontend job , expecting an offer or chance for me .
134
174
  > Email: leafnote@outlook.com
135
175
 
136
176
  [English](#soon-fetch) | [中文](#soon-fetch-1) | [Installation](#安装-installation)
@@ -151,11 +191,13 @@ GitHub: https://github.com/leafio/soon-fetch
151
191
  - [示例](#示例)
152
192
 
153
193
  - [特别功能](#特别功能)
194
+
154
195
  - [快捷方法](#快捷方法)
155
196
  - [Restful Url 参数自动处理](#restful-url-参数自动处理)
156
197
  - [超时](#超时)
157
198
  - [快速定义 API](#快速定义-api)
158
199
 
200
+ - [API](#api-1)
159
201
  - [支持一下](#支持一下)
160
202
 
161
203
  ### 示例
@@ -165,19 +207,12 @@ GitHub: https://github.com/leafio/soon-fetch
165
207
 
166
208
  ```typescript
167
209
  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
210
  const [_url, _options] = parseUrlOptions({
173
211
  url,
174
212
  options,
175
213
  baseURL: "/api",
176
214
  baseOptions: {
177
- // 会被 options.timeout 覆盖
178
215
  timeout: 20 * 1000,
179
- // 将与 options.headers 合并
180
- // 相同key的 header 会被options.headers覆盖
181
216
  headers: { Authorization: localStorage.getItem("token") ?? "" },
182
217
  },
183
218
  });
@@ -258,12 +293,58 @@ soon.get(url, { timeout: 1000 * 20 });
258
293
  })
259
294
  ```
260
295
 
296
+ ### API
297
+
298
+ #### parseUrlOptions
299
+
300
+ `parseUrlOptions` 源码如下:
301
+
302
+ ```ts
303
+ function parseUrlOptions<Options extends SoonOptions>(urlOptions: {
304
+ url: string;
305
+ options?: Options;
306
+ baseURL?: string;
307
+ baseOptions?: Options;
308
+ }) {
309
+ const { url, options, baseURL, baseOptions } = urlOptions;
310
+ //override baseOptions
311
+ const _options = { ...baseOptions, ...options };
312
+
313
+ //signal merge signals by AbortSignal.any
314
+ _options.signal = mergeSignals(
315
+ [baseOptions?.signal, options?.signal],
316
+ _options.timeout
317
+ );
318
+
319
+ //url handled with baseURL , options.query , options.params
320
+ const _url = mergeUrl(url, { ..._options, baseURL });
321
+
322
+ //body auto stringify json body
323
+ let _body = options?.body;
324
+ let is_body_json = isBodyJson(_body);
325
+ _options.body = is_body_json ? JSON.stringify(_body) : _body;
326
+
327
+ //headers merge headers , the same-key header would be override by options.headers
328
+ //if body is json ,then add header "Content-Type": "application/json" }
329
+ const headers = mergeHeaders(
330
+ baseOptions?.headers,
331
+ options?.headers,
332
+ is_body_json ? { "Content-Type": "application/json" } : undefined
333
+ );
334
+ _options.headers = headers;
335
+
336
+ return [_url, _options as Options & { headers: Headers }] as const;
337
+ }
338
+ ```
339
+
340
+ 如有特殊需要,可以根据下方的函数定制你自己的解析函数来替代 `parseUrlOptions`:
341
+ `mergeHeaders`, `mergeSignals`, `mergeUrl`, `isBodyJson`
342
+
261
343
  ### 支持一下
262
344
 
263
345
  喜欢 soon-fetch 的话 , 在 github 上给个 **star** 吧.
264
346
  GitHub: https://github.com/leafio/soon-fetch
265
347
 
266
- > 我目前在找前端的工作,有岗位机会的话,可以联系我。
267
348
  > Email: leafnote@outlook.com
268
349
 
269
350
  [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 e=[],r=t.match(/:([^:/\d]+)\/?/g);return r&&r.forEach((t=>{e.push(t.replace(/\//g,"").replace(/:/g,""))})),e},e=(t="")=>t.startsWith("http"),r=(t="")=>e(t)?t:((t="")=>{let e=t;return t&&(e=((t="")=>t.endsWith("/")?t.slice(0,-1):t)(e),t.startsWith("/")||(e="/"+e)),e})(t),n=t=>{if(!t)return[];if(t instanceof URLSearchParams||"string"==typeof t||Array.isArray(t))return Array.from(new URLSearchParams(t).entries());const e=[];return Object.keys(t).forEach((r=>{const n=t[r];(Array.isArray(n)?n:[n]).forEach((t=>{e.push([r,t??""])}))})),e},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 l=((t,n)=>{let a=r(t);return e(a)||(a=r(n)+a),a})(p,c);return h.size&&(l=l+"?"+h),l},o=(...t)=>{const e=new Headers;return t.forEach((t=>{t&&new Headers(t).forEach(((t,r)=>{e.set(r,t)}))})),e};function s(t,e){const r=(t??[]).filter((t=>!!t));return e&&r.push(AbortSignal.timeout(e)),r.length?AbortSignal.any(r):void 0}function i(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||(e=t,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)));var e}const c=["get","post","put","delete","patch"];function f(t,e){const r={};return t.forEach((t=>{r[t]=(r,n)=>e(r,{...n,method:t})})),r}function p(e){return(r,n)=>{const a={},o=!!t(r).length;return c.forEach((t=>{const s=t.toUpperCase();a[s]=()=>(...a)=>{const[s,i]=a,c="get"===t?"query":"body";return e(r,{...n,method:t,params:o?s:void 0,[c]:o?i:s})}})),a}}exports.createShortAPI=p,exports.createShortMethods=f,exports.createSoon=function(t){const e=t;return{request:e,API:p(e),...f([...c,"head","options"],e)}},exports.isBodyJson=i,exports.mergeHeaders=o,exports.mergeSignals=s,exports.mergeUrl=a,exports.parseUrlOptions=function(t){const{url:e,options:r,baseURL:n,baseOptions:c}=t,f={...c,...r};f.signal=s([c?.signal,r?.signal],f.timeout);const p=a(e,{...f,baseURL:n});let u=r?.body,h=i(u);f.body=h?JSON.stringify(u):u;const l=o(c?.headers,r?.headers,h?{"Content-Type":"application/json"}:void 0);return f.headers=l,[p,f]};
package/dist/index.d.ts CHANGED
@@ -1,44 +1,44 @@
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 = 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 function mergeSignals(signals?: (AbortSignal | null | undefined)[], timeout?: number): AbortSignal | undefined;
19
+ declare function isBodyJson(body: any): 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 = Awaited<ReturnType<T>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>>;
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 = Awaited<ReturnType<requestFun>>>() => (...arg: [...OptionParams<{ [key in GetUrlKey<Url>]: string | number; }>, ...OptionBody<Req>]) => Promise<Res>>;
43
+
44
+ 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.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};function s(t,n){const r=(t??[]).filter((t=>!!t));return n&&r.push(AbortSignal.timeout(n)),r.length?AbortSignal.any(r):void 0}function i(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 c(t){const{url:n,options:r,baseURL:e,baseOptions:c}=t,f={...c,...r};f.signal=s([c?.signal,r?.signal],f.timeout);const u=a(n,{...f,baseURL:e});let h=r?.body,y=i(h);f.body=y?JSON.stringify(h):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,i as isBodyJson,o as mergeHeaders,s as mergeSignals,a as mergeUrl,c 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.0",
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",