@mx-space/api-client 1.0.0-alpha.2 → 1.0.0-alpha.4

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 (61) hide show
  1. package/dist/adaptors/axios.cjs +47 -0
  2. package/dist/adaptors/axios.cjs.map +1 -0
  3. package/dist/adaptors/axios.js +38 -0
  4. package/dist/adaptors/axios.js.map +1 -0
  5. package/dist/adaptors/axios.min.cjs +2 -0
  6. package/dist/adaptors/axios.min.cjs.map +1 -0
  7. package/dist/adaptors/axios.min.js +2 -0
  8. package/dist/adaptors/axios.min.js.map +1 -0
  9. package/dist/adaptors/axios.umd.js +51 -0
  10. package/dist/adaptors/axios.umd.js.map +1 -0
  11. package/dist/adaptors/axios.umd.min.js +2 -0
  12. package/dist/adaptors/axios.umd.min.js.map +1 -0
  13. package/dist/adaptors/ky.cjs +73 -0
  14. package/dist/adaptors/ky.cjs.map +1 -0
  15. package/dist/adaptors/ky.js +63 -0
  16. package/dist/adaptors/ky.js.map +1 -0
  17. package/dist/adaptors/ky.min.cjs +2 -0
  18. package/dist/adaptors/ky.min.cjs.map +1 -0
  19. package/dist/adaptors/ky.min.js +2 -0
  20. package/dist/adaptors/ky.min.js.map +1 -0
  21. package/dist/adaptors/ky.umd.js +77 -0
  22. package/dist/adaptors/ky.umd.js.map +1 -0
  23. package/dist/adaptors/ky.umd.min.js +2 -0
  24. package/dist/adaptors/ky.umd.min.js.map +1 -0
  25. package/dist/adaptors/umi-request.cjs +37 -0
  26. package/dist/adaptors/umi-request.cjs.map +1 -0
  27. package/dist/adaptors/umi-request.js +32 -0
  28. package/dist/adaptors/umi-request.js.map +1 -0
  29. package/dist/adaptors/umi-request.min.cjs +2 -0
  30. package/dist/adaptors/umi-request.min.cjs.map +1 -0
  31. package/dist/adaptors/umi-request.min.js +2 -0
  32. package/dist/adaptors/umi-request.min.js.map +1 -0
  33. package/dist/adaptors/umi-request.umd.js +41 -0
  34. package/dist/adaptors/umi-request.umd.js.map +1 -0
  35. package/dist/adaptors/umi-request.umd.min.js +2 -0
  36. package/dist/adaptors/umi-request.umd.min.js.map +1 -0
  37. package/{build → dist}/index.cjs +0 -0
  38. package/{build → dist}/index.cjs.map +0 -0
  39. package/{build → dist}/index.js +0 -0
  40. package/{build → dist}/index.js.map +0 -0
  41. package/{build → dist}/index.min.cjs +0 -0
  42. package/{build → dist}/index.min.cjs.map +0 -0
  43. package/{build → dist}/index.min.js +0 -0
  44. package/{build → dist}/index.min.js.map +0 -0
  45. package/{build → dist}/index.umd.js +0 -0
  46. package/{build → dist}/index.umd.js.map +0 -0
  47. package/{build → dist}/index.umd.min.js +0 -0
  48. package/{build → dist}/index.umd.min.js.map +0 -0
  49. package/package.json +40 -10
  50. package/readme.md +1 -4
  51. package/adaptors/axios.ts +0 -44
  52. package/adaptors/ky.ts +0 -76
  53. package/adaptors/umi-request.ts +0 -38
  54. package/core/attach-request.ts +0 -43
  55. package/core/client.ts +0 -252
  56. package/core/error.ts +0 -10
  57. package/core/index.ts +0 -2
  58. package/utils/auto-bind.ts +0 -48
  59. package/utils/camelcase-keys.ts +0 -26
  60. package/utils/index.ts +0 -53
  61. package/utils/path.ts +0 -6
File without changes
package/package.json CHANGED
@@ -1,14 +1,43 @@
1
1
  {
2
2
  "name": "@mx-space/api-client",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-alpha.4",
4
4
  "type": "module",
5
5
  "description": "A api client for mx-space server@next",
6
6
  "author": "Innei",
7
7
  "license": "MIT",
8
- "main": "build/index.cjs",
9
- "module": "build/index.js",
8
+ "main": "dist/index.cjs",
9
+ "module": "dist/index.js",
10
10
  "types": "types/index.d.ts",
11
- "unpkg": "build/index.umd.min.js",
11
+ "unpkg": "dist/index.umd.min.js",
12
+ "typesVersions": {
13
+ "*": {
14
+ ".": [
15
+ "./types/index.d.ts"
16
+ ],
17
+ "./adaptors/*": [
18
+ "./types/adaptors/*.d.ts"
19
+ ]
20
+ }
21
+ },
22
+ "exports": {
23
+ ".": {
24
+ "types": "./types/index.d.ts",
25
+ "import": "./dist/index.js",
26
+ "require": "./dist/index.cjs"
27
+ },
28
+ "./package.json": "./package.json",
29
+ "./adaptors/*": {
30
+ "types": "./types/adaptors/*.d.ts",
31
+ "import": {
32
+ "type": "./types/adaptors/*.d.ts",
33
+ "default": "./dist/adaptors/*.js"
34
+ },
35
+ "require": {
36
+ "type": "./types/adaptors/*.d.ts",
37
+ "default": "./dist/adaptors/*.cjs"
38
+ }
39
+ }
40
+ },
12
41
  "husky": {
13
42
  "hooks": {
14
43
  "pre-commit": "lint-staged"
@@ -39,7 +68,7 @@
39
68
  "postbuild": "tsc-alias -p tsconfig.build.json && tsc-alias -p tsconfig.cjs.json && npm run types",
40
69
  "types": "rm -rf types && tsc --build tsconfig.types.json && tsc-alias -p tsconfig.types.json",
41
70
  "package": "NODE_ENV=production npm run build && rollup -c",
42
- "prepackage": "rm -rf build",
71
+ "prepackage": "rm -rf dist",
43
72
  "test": "vitest",
44
73
  "dev": "vite"
45
74
  },
@@ -48,21 +77,22 @@
48
77
  "@rollup/plugin-node-resolve": "14.0.1",
49
78
  "@rollup/plugin-typescript": "8.5.0",
50
79
  "@types/cors": "2.8.12",
51
- "@types/lodash": "4.14.184",
52
- "@types/node": "16.11.58",
80
+ "@types/lodash": "4.14.186",
81
+ "@types/node": "16.11.65",
53
82
  "abort-controller": "3.0.0",
54
83
  "axios": "0.27.2",
55
84
  "camelcase-keys": "8.0.2",
56
85
  "gh-pages": "4.0.0",
86
+ "globby": "*",
57
87
  "isomorphic-unfetch": "3.1.0",
58
- "jsdom": "20.0.0",
88
+ "jsdom": "20.0.1",
59
89
  "ky": "0.31.3",
60
90
  "lodash": "4.17.21",
61
91
  "node-fetch": "3.2.10",
62
- "rollup": "2.79.0",
92
+ "rollup": "2.79.1",
63
93
  "rollup-plugin-peer-deps-external": "2.2.4",
64
94
  "rollup-plugin-terser": "7.0.2",
65
95
  "tsc-alias": "1.7.0",
66
96
  "umi-request": "1.4.0"
67
97
  }
68
- }
98
+ }
package/readme.md CHANGED
@@ -20,9 +20,6 @@
20
20
  以 `axios` 为例。
21
21
 
22
22
  ```ts
23
- // esm format (spa recommend)
24
- // cjs format (ssr recommend)
25
- // import { axiosAdaptor } from '@mx-space/api-client/lib/adaptors/axios'
26
23
  import {
27
24
  AggregateController,
28
25
  CategoryController,
@@ -31,7 +28,7 @@ import {
31
28
  allControllers, // ...
32
29
  createClient,
33
30
  } from '@mx-space/api-client'
34
- import { axiosAdaptor } from '@mx-space/api-client/esm/adaptors/axios'
31
+ import { axiosAdaptor } from '@mx-space/api-client/adaptors/axios'
35
32
 
36
33
  const endpoint = 'https://api.innei.dev/v2'
37
34
  const client = createClient(axiosAdaptor)(endpoint)
package/adaptors/axios.ts DELETED
@@ -1,44 +0,0 @@
1
- import type { AxiosInstance, AxiosResponse } from 'axios'
2
- import axios from 'axios'
3
-
4
- import type { IRequestAdapter } from '~/interfaces/adapter'
5
-
6
- // eslint-disable-next-line spaced-comment
7
- const $http = /*#__PURE__*/ axios.create({})
8
-
9
- // ignore axios `method` declare not assignable to `Method`
10
- export const axiosAdaptor: IRequestAdapter<
11
- AxiosInstance,
12
- AxiosResponse<unknown>
13
- > = Object.preventExtensions({
14
- get default() {
15
- return $http
16
- },
17
- responseWrapper: {} as any as AxiosResponse<unknown>,
18
- get(url, options) {
19
- // @ts-ignore
20
- return $http.get(url, options)
21
- },
22
- post(url, options) {
23
- const { data, ...config } = options || {}
24
- // @ts-ignore
25
- return $http.post(url, data, config)
26
- },
27
- put(url, options) {
28
- const { data, ...config } = options || {}
29
- // @ts-ignore
30
- return $http.put(url, data, config)
31
- },
32
- delete(url, options) {
33
- const { ...config } = options || {}
34
- // @ts-ignore
35
- return $http.delete(url, config)
36
- },
37
- patch(url, options) {
38
- const { data, ...config } = options || {}
39
- // @ts-ignore
40
- return $http.patch(url, data, config)
41
- },
42
- })
43
-
44
- export default axiosAdaptor
package/adaptors/ky.ts DELETED
@@ -1,76 +0,0 @@
1
- import ky from 'ky'
2
- import type { Options, ResponsePromise } from 'ky'
3
- import type { KyInstance } from 'ky/distribution/types/ky'
4
-
5
- import type { IRequestAdapter } from '~/interfaces/adapter'
6
-
7
- // eslint-disable-next-line spaced-comment
8
- const $http: KyInstance = /*#__PURE__*/ ky.create({})
9
- // TODO post data not only json,
10
- const getDataFromKyResponse = async (response: ResponsePromise) => {
11
- const res = await response
12
-
13
- const isJsonType = res.headers
14
- .get('content-type')
15
- ?.includes('application/json')
16
- const json = isJsonType ? await res.clone().json() : null
17
-
18
- const result: Awaited<ResponsePromise> & {
19
- data: any
20
- } = {
21
- ...res,
22
- data: json ?? (await res.clone().text()),
23
- }
24
- return result
25
- }
26
-
27
- export const createKyAdaptor = (ky: KyInstance) => {
28
- const adaptor: IRequestAdapter<KyInstance, ResponsePromise> =
29
- Object.preventExtensions({
30
- get default() {
31
- return ky
32
- },
33
-
34
- responseWrapper: {} as any as ResponsePromise,
35
- get(url, options) {
36
- return getDataFromKyResponse(ky.get(url, options))
37
- },
38
- post(url, options) {
39
- const data = options.data
40
- delete options.data
41
- const kyOptions: Options = {
42
- ...options,
43
- json: data,
44
- }
45
-
46
- return getDataFromKyResponse(ky.post(url, kyOptions))
47
- },
48
- put(url, options) {
49
- const data = options.data
50
- delete options.data
51
- const kyOptions: Options = {
52
- ...options,
53
- json: data,
54
- }
55
- return getDataFromKyResponse(ky.put(url, kyOptions))
56
- },
57
-
58
- patch(url, options) {
59
- const data = options.data
60
- delete options.data
61
- const kyOptions: Options = {
62
- ...options,
63
- json: data,
64
- }
65
- return getDataFromKyResponse(ky.patch(url, kyOptions))
66
- },
67
- delete(url, options) {
68
- return getDataFromKyResponse(ky.delete(url, options))
69
- },
70
- })
71
- return adaptor
72
- }
73
-
74
- export const defaultKyAdaptor = createKyAdaptor($http)
75
-
76
- export default defaultKyAdaptor
@@ -1,38 +0,0 @@
1
- import type { RequestMethod, RequestResponse } from 'umi-request'
2
- import { extend } from 'umi-request'
3
-
4
- import type { IRequestAdapter } from '~/interfaces/adapter'
5
-
6
- // eslint-disable-next-line spaced-comment
7
- const $http = /*#__PURE__*/ extend({
8
- getResponse: true,
9
- requestType: 'json',
10
- responseType: 'json',
11
- })
12
-
13
- export const umiAdaptor: IRequestAdapter<
14
- RequestMethod<true>,
15
- RequestResponse
16
- > = Object.preventExtensions({
17
- get default() {
18
- return $http
19
- },
20
- responseWrapper: {} as any as RequestResponse,
21
- get(url, options) {
22
- return $http.get(url, options)
23
- },
24
- post(url, options) {
25
- return $http.post(url, options)
26
- },
27
- put(url, options) {
28
- return $http.put(url, options)
29
- },
30
- delete(url, options) {
31
- return $http.delete(url, options)
32
- },
33
- patch(url, options) {
34
- return $http.patch(url, options)
35
- },
36
- })
37
-
38
- export default umiAdaptor
@@ -1,43 +0,0 @@
1
- import type { HTTPClient } from '.'
2
-
3
- export function attachRequestMethod<T extends HTTPClient<any, any>>(target: T) {
4
- Object.defineProperty(target, '$$get', {
5
- value(url: string, options?: any) {
6
- // HINT: method get only accept search params;
7
- const { params = {}, ...rest } = options
8
- const qs = handleSearchParams(params)
9
-
10
- return target.instance.get(`${url}${qs ? `${`?${qs}`}` : ''}`, rest)
11
- },
12
- })
13
- ;(['put', 'post', 'patch', 'delete'] as const).forEach((method) => {
14
- Object.defineProperty(target, `$$${method}`, {
15
- value(path: string, options?: any) {
16
- return target.instance[method](path, options)
17
- },
18
- })
19
- })
20
- }
21
- // FIXME: only support string value
22
- function handleSearchParams(obj: URLSearchParams | Record<string, string>) {
23
- if (!obj && typeof obj !== 'object') {
24
- throw new TypeError('params must be object.')
25
- }
26
-
27
- if (obj instanceof URLSearchParams) {
28
- return obj.toString()
29
- }
30
- const search = new URLSearchParams()
31
-
32
- Object.entries<any>(obj).forEach(([k, v]) => {
33
- if (
34
- typeof v === 'undefined' ||
35
- Object.prototype.toString.call(v) === '[object Null]'
36
- ) {
37
- return
38
- }
39
- search.set(k, v)
40
- })
41
-
42
- return search.toString()
43
- }
package/core/client.ts DELETED
@@ -1,252 +0,0 @@
1
- import type {
2
- IAdaptorRequestResponseType,
3
- IRequestAdapter,
4
- } from '~/interfaces/adapter'
5
- import type { ClientOptions } from '~/interfaces/client'
6
- import type { IController } from '~/interfaces/controller'
7
- import type { RequestOptions } from '~/interfaces/instance'
8
- import type { IRequestHandler, Method } from '~/interfaces/request'
9
- import type { Class } from '~/interfaces/types'
10
- import { isPlainObject } from '~/utils'
11
- import { camelcaseKeys } from '~/utils/camelcase-keys'
12
- import { resolveFullPath } from '~/utils/path'
13
-
14
- import { allContollerNames } from '../controllers'
15
- import { attachRequestMethod } from './attach-request'
16
- import { RequestError } from './error'
17
-
18
- const methodPrefix = '_$'
19
- export type { HTTPClient }
20
- class HTTPClient<
21
- T extends IRequestAdapter = IRequestAdapter,
22
- ResponseWrapper = unknown,
23
- > {
24
- private readonly _proxy: IRequestHandler<ResponseWrapper>
25
-
26
- constructor(
27
- private readonly _endpoint: string,
28
- private _adaptor: T,
29
- private options: Omit<ClientOptions, 'controllers'> = {},
30
- ) {
31
- this._endpoint = _endpoint
32
- .replace(/\/*$/, '')
33
- .replace('localhost', '127.0.0.1')
34
- this._proxy = this.buildRoute(this)()
35
- options.transformResponse =
36
- options.transformResponse || ((data) => camelcaseKeys(data))
37
-
38
- this.initGetClient()
39
-
40
- attachRequestMethod(this)
41
- }
42
-
43
- private initGetClient() {
44
- for (const name of allContollerNames) {
45
- Object.defineProperty(this, name, {
46
- get() {
47
- const client = Reflect.get(this, `${methodPrefix}${name}`)
48
- if (!client) {
49
- throw new ReferenceError(
50
- `${
51
- name.charAt(0).toUpperCase() + name.slice(1)
52
- } Client not inject yet, please inject with client.injectClients(...)`,
53
- )
54
- }
55
- return client
56
- },
57
- configurable: false,
58
- enumerable: false,
59
- })
60
- }
61
- }
62
-
63
- public injectControllers(...Controller: Class<IController>[]): void
64
- public injectControllers(Controller: Class<IController>[]): void
65
- public injectControllers(Controller: any, ...rest: any[]) {
66
- Controller = Array.isArray(Controller) ? Controller : [Controller, ...rest]
67
- for (const Client of Controller) {
68
- const cl = new Client(this)
69
-
70
- if (Array.isArray(cl.name)) {
71
- for (const name of cl.name) {
72
- attach.call(this, name, cl)
73
- }
74
- } else {
75
- attach.call(this, cl.name, cl)
76
- }
77
- }
78
-
79
- function attach(this: any, name: string, cl: IController) {
80
- Object.defineProperty(this, `${methodPrefix}${name.toLowerCase()}`, {
81
- get() {
82
- return cl
83
- },
84
- enumerable: false,
85
- configurable: false,
86
- })
87
- }
88
- }
89
-
90
- get endpoint() {
91
- return this._endpoint
92
- }
93
-
94
- get instance() {
95
- return this._adaptor
96
- }
97
-
98
- public request(options: {
99
- url: string
100
- method?: string
101
- data?: any
102
- params?: any
103
- }) {
104
- return (this as any)[`$$${String(options.method || 'get').toLowerCase()}`](
105
- options.url,
106
- options,
107
- ) as Promise<IAdaptorRequestResponseType<any>>
108
- }
109
-
110
- public get proxy() {
111
- return this._proxy
112
- }
113
-
114
- private buildRoute(manager: this): () => IRequestHandler<ResponseWrapper> {
115
- // eslint-disable-next-line @typescript-eslint/no-empty-function
116
- const noop = () => {}
117
- const methods = ['get', 'post', 'delete', 'patch', 'put']
118
- const reflectors = [
119
- 'toString',
120
- 'valueOf',
121
- 'inspect',
122
- 'constructor',
123
- Symbol.toPrimitive,
124
- ]
125
- // eslint-disable-next-line @typescript-eslint/no-this-alias
126
- const that = this
127
-
128
- return () => {
129
- const route = ['']
130
-
131
- const handler: any = {
132
- get(target: any, name: Method) {
133
- if (reflectors.includes(name))
134
- return (withBase?: boolean) => {
135
- if (withBase) {
136
- const path = resolveFullPath(that.endpoint, route.join('/'))
137
- route.length = 0
138
- return path
139
- } else {
140
- const path = route.join('/')
141
- route.length = 0
142
- return path.startsWith('/') ? path : `/${path}`
143
- }
144
- }
145
- if (methods.includes(name)) {
146
- return async (options: RequestOptions) => {
147
- const url = resolveFullPath(that.endpoint, route.join('/'))
148
- route.length = 0
149
- let res: Record<string, any> & { data: any }
150
- try {
151
- res = await manager.request({
152
- method: name,
153
- ...options,
154
- url,
155
- })
156
- } catch (e: any) {
157
- let message = e.message
158
- let code =
159
- e.code ||
160
- e.status ||
161
- e.statusCode ||
162
- e.response?.status ||
163
- e.response?.statusCode ||
164
- e.response?.code ||
165
- 500
166
-
167
- if (that.options.getCodeMessageFromException) {
168
- const errorInfo = that.options.getCodeMessageFromException(e)
169
- message = errorInfo.message || message
170
- code = errorInfo.code || code
171
- }
172
-
173
- throw that.options.customThrowResponseError
174
- ? that.options.customThrowResponseError(e)
175
- : new RequestError(message, code, url, e)
176
- }
177
-
178
- const data = res.data
179
- if (!data) {
180
- return null
181
- }
182
-
183
- const transform =
184
- (Array.isArray(data) || isPlainObject(data)) &&
185
- that.options.transformResponse
186
- ? that.options.transformResponse(data)
187
- : data
188
-
189
- if (transform && typeof transform === 'object') {
190
- Object.defineProperty(transform, '$raw', {
191
- get() {
192
- return res
193
- },
194
- enumerable: false,
195
- configurable: false,
196
- })
197
-
198
- // attach request config onto response
199
-
200
- Object.defineProperty(transform, '$request', {
201
- get() {
202
- return {
203
- url,
204
- method: name,
205
- options,
206
- }
207
- },
208
- enumerable: false,
209
- })
210
- }
211
-
212
- return transform
213
- }
214
- }
215
- route.push(name)
216
- return new Proxy(noop, handler)
217
- },
218
- // @ts-ignore
219
- apply(target: any, _, args) {
220
- route.push(...args.filter((x: string) => x !== null))
221
- return new Proxy(noop, handler)
222
- },
223
- }
224
-
225
- return new Proxy(noop, handler) as any
226
- }
227
- }
228
- }
229
-
230
- export function createClient<T extends IRequestAdapter>(adapter: T) {
231
- return <
232
- ResponseWrapper = T extends { responseWrapper: infer Type }
233
- ? Type extends undefined
234
- ? unknown
235
- : Type
236
- : unknown,
237
- >(
238
- endpoint: string,
239
- options?: ClientOptions,
240
- ) => {
241
- const client = new HTTPClient<T, ResponseWrapper>(
242
- endpoint,
243
- adapter,
244
- options,
245
- )
246
- const { controllers } = options || {}
247
- if (controllers) {
248
- client.injectControllers(controllers)
249
- }
250
- return client
251
- }
252
- }
package/core/error.ts DELETED
@@ -1,10 +0,0 @@
1
- export class RequestError extends Error {
2
- constructor(
3
- message: string,
4
- public status: number,
5
- public path: string,
6
- public raw: any,
7
- ) {
8
- super(message)
9
- }
10
- }
package/core/index.ts DELETED
@@ -1,2 +0,0 @@
1
- export * from './client'
2
- export * from './error'
@@ -1,48 +0,0 @@
1
- // @ts-nocheck
2
- // @copy: https://github.com/sindresorhus/auto-bind/blob/main/index.js
3
-
4
- // Gets all non-builtin properties up the prototype chain.
5
- const getAllProperties = (object) => {
6
- const properties = new Set()
7
-
8
- do {
9
- for (const key of Reflect.ownKeys(object)) {
10
- properties.add([object, key])
11
- }
12
- } while (
13
- (object = Reflect.getPrototypeOf(object)) &&
14
- object !== Object.prototype
15
- )
16
-
17
- return properties
18
- }
19
-
20
- export function autoBind(self, { include, exclude } = {}) {
21
- const filter = (key) => {
22
- const match = (pattern) =>
23
- typeof pattern === 'string' ? key === pattern : pattern.test(key)
24
-
25
- if (include) {
26
- return include.some(match)
27
- }
28
-
29
- if (exclude) {
30
- return !exclude.some(match)
31
- }
32
-
33
- return true
34
- }
35
-
36
- for (const [object, key] of getAllProperties(self.constructor.prototype)) {
37
- if (key === 'constructor' || !filter(key)) {
38
- continue
39
- }
40
-
41
- const descriptor = Reflect.getOwnPropertyDescriptor(object, key)
42
- if (descriptor && typeof descriptor.value === 'function') {
43
- self[key] = self[key].bind(self)
44
- }
45
- }
46
-
47
- return self
48
- }
@@ -1,26 +0,0 @@
1
- import { isPlainObject } from '.'
2
-
3
- /**
4
- * A simple camelCase function that only handles strings, but not handling symbol, date, or other complex case.
5
- * If you need to handle more complex cases, please use camelcase-keys package.
6
- */
7
- export const camelcaseKeys = <T = any>(obj: any): T => {
8
- if (Array.isArray(obj)) {
9
- return obj.map((x) => camelcaseKeys(x)) as any
10
- }
11
-
12
- if (isPlainObject(obj)) {
13
- return Object.keys(obj).reduce((result: any, key) => {
14
- result[camelcase(key)] = camelcaseKeys(obj[key])
15
- return result
16
- }, {}) as any
17
- }
18
-
19
- return obj
20
- }
21
-
22
- export function camelcase(str: string) {
23
- return str.replace(/([-_][a-z])/gi, ($1) => {
24
- return $1.toUpperCase().replace('-', '').replace('_', '')
25
- })
26
- }