@labdigital/commercetools-mock 1.5.0 → 1.6.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 +5 -4
- package/dist/index.cjs +117 -17
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +30 -7
- package/dist/index.d.ts +30 -7
- package/dist/index.js +117 -17
- package/dist/index.js.map +1 -1
- package/package.json +4 -3
- package/src/constants.ts +2 -2
- package/src/ctMock.ts +176 -176
- package/src/exceptions.ts +10 -10
- package/src/helpers.ts +26 -26
- package/src/index.test.ts +173 -173
- package/src/index.ts +3 -3
- package/src/lib/expandParser.ts +19 -19
- package/src/lib/haversine.test.ts +13 -13
- package/src/lib/haversine.ts +14 -14
- package/src/lib/masking.ts +15 -15
- package/src/lib/parser.ts +2 -2
- package/src/lib/predicateParser.test.ts +204 -204
- package/src/lib/predicateParser.ts +398 -398
- package/src/lib/projectionSearchFilter.test.ts +168 -168
- package/src/lib/projectionSearchFilter.ts +272 -269
- package/src/lib/proxy.ts +8 -8
- package/src/oauth/errors.ts +4 -4
- package/src/oauth/helpers.ts +6 -6
- package/src/oauth/server.ts +103 -101
- package/src/oauth/store.ts +27 -27
- package/src/priceSelector.test.ts +68 -68
- package/src/priceSelector.ts +70 -70
- package/src/product-projection-search.ts +296 -296
- package/src/projectAPI.test.ts +3 -3
- package/src/projectAPI.ts +46 -46
- package/src/repositories/abstract.ts +190 -190
- package/src/repositories/associate-role.ts +10 -7
- package/src/repositories/attribute-group.ts +63 -8
- package/src/repositories/business-unit.ts +10 -7
- package/src/repositories/cart-discount.ts +134 -134
- package/src/repositories/cart.ts +517 -514
- package/src/repositories/category.ts +170 -167
- package/src/repositories/channel.ts +114 -111
- package/src/repositories/custom-object.ts +66 -63
- package/src/repositories/customer-group.ts +72 -69
- package/src/repositories/customer.ts +90 -90
- package/src/repositories/discount-code.ts +171 -168
- package/src/repositories/errors.ts +15 -15
- package/src/repositories/extension.ts +79 -76
- package/src/repositories/helpers.ts +180 -180
- package/src/repositories/index.ts +39 -39
- package/src/repositories/inventory-entry.ts +98 -95
- package/src/repositories/my-order.ts +11 -11
- package/src/repositories/order-edit.ts +29 -29
- package/src/repositories/order.test.ts +191 -191
- package/src/repositories/order.ts +393 -393
- package/src/repositories/payment.ts +155 -155
- package/src/repositories/product-discount.ts +149 -149
- package/src/repositories/product-projection.ts +135 -50
- package/src/repositories/product-selection.ts +31 -31
- package/src/repositories/product-type.ts +156 -156
- package/src/repositories/product.ts +600 -597
- package/src/repositories/project.ts +136 -135
- package/src/repositories/quote-request.ts +19 -19
- package/src/repositories/quote.ts +19 -19
- package/src/repositories/review.ts +24 -24
- package/src/repositories/shipping-method.ts +217 -217
- package/src/repositories/shopping-list.ts +49 -49
- package/src/repositories/staged-quote.ts +20 -20
- package/src/repositories/standalone-price.ts +72 -61
- package/src/repositories/state.ts +84 -84
- package/src/repositories/store.ts +114 -114
- package/src/repositories/subscription.ts +40 -40
- package/src/repositories/tax-category.ts +98 -98
- package/src/repositories/type.ts +157 -157
- package/src/repositories/zone.ts +71 -71
- package/src/server.ts +2 -2
- package/src/services/abstract.ts +173 -173
- package/src/services/attribute-group.ts +16 -0
- package/src/services/cart-discount.ts +8 -8
- package/src/services/cart.test.ts +409 -409
- package/src/services/cart.ts +50 -50
- package/src/services/category.test.ts +25 -25
- package/src/services/category.ts +8 -8
- package/src/services/channel.ts +8 -8
- package/src/services/custom-object.test.ts +184 -184
- package/src/services/custom-object.ts +48 -48
- package/src/services/customer-group.ts +8 -8
- package/src/services/customer.test.ts +151 -151
- package/src/services/customer.ts +27 -27
- package/src/services/discount-code.ts +8 -8
- package/src/services/extension.ts +8 -8
- package/src/services/index.ts +52 -44
- package/src/services/inventory-entry.test.ts +162 -162
- package/src/services/inventory-entry.ts +8 -8
- package/src/services/my-cart.test.ts +78 -78
- package/src/services/my-cart.ts +28 -28
- package/src/services/my-customer.test.ts +44 -44
- package/src/services/my-customer.ts +53 -53
- package/src/services/my-order.ts +20 -20
- package/src/services/my-payment.test.ts +65 -65
- package/src/services/my-payment.ts +8 -8
- package/src/services/order.test.ts +527 -527
- package/src/services/order.ts +31 -31
- package/src/services/payment.test.ts +65 -65
- package/src/services/payment.ts +8 -8
- package/src/services/product-discount.ts +8 -8
- package/src/services/product-projection.test.ts +502 -428
- package/src/services/product-projection.ts +32 -18
- package/src/services/product-type.test.ts +56 -56
- package/src/services/product-type.ts +8 -8
- package/src/services/product.test.ts +510 -510
- package/src/services/product.ts +8 -8
- package/src/services/project.ts +34 -34
- package/src/services/shipping-method.test.ts +81 -81
- package/src/services/shipping-method.ts +12 -12
- package/src/services/shopping-list.ts +8 -8
- package/src/services/standalone-price.test.ts +256 -256
- package/src/services/standalone-price.ts +8 -8
- package/src/services/state.test.ts +42 -42
- package/src/services/state.ts +8 -8
- package/src/services/store.test.ts +57 -57
- package/src/services/store.ts +8 -8
- package/src/services/subscription.ts +8 -8
- package/src/services/tax-category.test.ts +61 -61
- package/src/services/tax-category.ts +8 -8
- package/src/services/type.ts +8 -8
- package/src/services/zone.ts +8 -8
- package/src/storage/abstract.ts +58 -58
- package/src/storage/in-memory.ts +419 -419
- package/src/types.ts +82 -82
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@labdigital/commercetools-mock",
|
|
3
3
|
"author": "Michael van Tellingen",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.1",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"main": "dist/index.cjs",
|
|
7
7
|
"module": "dist/index.js",
|
|
@@ -79,9 +79,10 @@
|
|
|
79
79
|
"build": "tsup",
|
|
80
80
|
"build:server": "esbuild src/server.ts --bundle --outfile=dist/server.js --platform=node",
|
|
81
81
|
"publish:ci": "pnpm build && pnpm changeset publish",
|
|
82
|
-
"check": "eslint src && tsc",
|
|
83
82
|
"test": "vitest run",
|
|
84
83
|
"test:ci": "vitest run --coverage",
|
|
85
|
-
"
|
|
84
|
+
"check": "pnpm lint && tsc",
|
|
85
|
+
"format": "eslint src --fix ; prettier --write .",
|
|
86
|
+
"lint": "eslint src && prettier --check ."
|
|
86
87
|
}
|
|
87
88
|
}
|
package/src/constants.ts
CHANGED
package/src/ctMock.ts
CHANGED
|
@@ -17,188 +17,188 @@ import { createServices } from './services/index.js'
|
|
|
17
17
|
import { ProjectRepository } from './repositories/project.js'
|
|
18
18
|
|
|
19
19
|
export type CommercetoolsMockOptions = {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
20
|
+
validateCredentials: boolean
|
|
21
|
+
enableAuthentication: boolean
|
|
22
|
+
defaultProjectKey: string | undefined
|
|
23
|
+
apiHost: RegExp | string
|
|
24
|
+
authHost: RegExp | string
|
|
25
|
+
silent: boolean
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
type AppOptions = { silent?: boolean }
|
|
29
29
|
|
|
30
30
|
const DEFAULT_OPTIONS: CommercetoolsMockOptions = {
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
31
|
+
enableAuthentication: false,
|
|
32
|
+
validateCredentials: false,
|
|
33
|
+
defaultProjectKey: undefined,
|
|
34
|
+
apiHost: DEFAULT_API_HOSTNAME,
|
|
35
|
+
authHost: DEFAULT_AUTH_HOSTNAME,
|
|
36
|
+
silent: false,
|
|
37
37
|
}
|
|
38
38
|
|
|
39
39
|
export class CommercetoolsMock {
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
40
|
+
public app: express.Express
|
|
41
|
+
public options: CommercetoolsMockOptions
|
|
42
|
+
|
|
43
|
+
private _storage: AbstractStorage
|
|
44
|
+
private _oauth2: OAuth2Server
|
|
45
|
+
private _nockScopes: {
|
|
46
|
+
auth: nock.Scope | undefined
|
|
47
|
+
api: nock.Scope | undefined
|
|
48
|
+
} = { auth: undefined, api: undefined }
|
|
49
|
+
private _services: Services | null
|
|
50
|
+
private _repositories: RepositoryMap | null
|
|
51
|
+
private _projectService?: ProjectService
|
|
52
|
+
|
|
53
|
+
constructor(options: Partial<CommercetoolsMockOptions> = {}) {
|
|
54
|
+
this.options = { ...DEFAULT_OPTIONS, ...options }
|
|
55
|
+
this._services = null
|
|
56
|
+
this._repositories = null
|
|
57
|
+
this._projectService = undefined
|
|
58
|
+
|
|
59
|
+
this._storage = new InMemoryStorage()
|
|
60
|
+
this._oauth2 = new OAuth2Server({
|
|
61
|
+
enabled: this.options.enableAuthentication,
|
|
62
|
+
validate: this.options.validateCredentials,
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
this.app = this.createApp({ silent: this.options.silent })
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
start() {
|
|
69
|
+
// Order is important here when the hostnames match
|
|
70
|
+
this.mockAuthHost()
|
|
71
|
+
this.mockApiHost()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
stop() {
|
|
75
|
+
this._nockScopes.auth?.persist(false)
|
|
76
|
+
this._nockScopes.auth = undefined
|
|
77
|
+
|
|
78
|
+
this._nockScopes.api?.persist(false)
|
|
79
|
+
this._nockScopes.api = undefined
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
clear() {
|
|
83
|
+
this._storage.clear()
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
project(projectKey?: string) {
|
|
87
|
+
if (!projectKey && !this.options.defaultProjectKey) {
|
|
88
|
+
throw new Error('No projectKey passed and no default set')
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
if (this._repositories === null) {
|
|
92
|
+
throw new Error('repositories not initialized yet')
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
return new ProjectAPI(
|
|
96
|
+
projectKey || this.options.defaultProjectKey!,
|
|
97
|
+
this._repositories,
|
|
98
|
+
this._storage
|
|
99
|
+
)
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
runServer(port = 3000, options?: AppOptions) {
|
|
103
|
+
const server = this.app.listen(port, () => {
|
|
104
|
+
console.info(`Mock server listening at http://localhost:${port}`)
|
|
105
|
+
})
|
|
106
|
+
server.keepAliveTimeout = 60 * 1000
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
private createApp(options?: AppOptions): express.Express {
|
|
110
|
+
this._repositories = createRepositories(this._storage)
|
|
111
|
+
|
|
112
|
+
const app = express()
|
|
113
|
+
|
|
114
|
+
const projectRouter = express.Router({ mergeParams: true })
|
|
115
|
+
projectRouter.use(express.json())
|
|
116
|
+
|
|
117
|
+
if (!options?.silent) {
|
|
118
|
+
app.use(morgan('tiny'))
|
|
119
|
+
}
|
|
120
|
+
app.use('/oauth', this._oauth2.createRouter())
|
|
121
|
+
|
|
122
|
+
// Only enable auth middleware if we have enabled this
|
|
123
|
+
if (this.options.enableAuthentication) {
|
|
124
|
+
app.use('/:projectKey', this._oauth2.createMiddleware(), projectRouter)
|
|
125
|
+
app.use(
|
|
126
|
+
'/:projectKey/in-store/key=:storeKey',
|
|
127
|
+
this._oauth2.createMiddleware(),
|
|
128
|
+
projectRouter
|
|
129
|
+
)
|
|
130
|
+
} else {
|
|
131
|
+
app.use('/:projectKey', projectRouter)
|
|
132
|
+
app.use('/:projectKey/in-store/key=:storeKey', projectRouter)
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Register the rest api services in the router
|
|
136
|
+
this._services = createServices(projectRouter, this._repositories)
|
|
137
|
+
this._projectService = new ProjectService(
|
|
138
|
+
projectRouter,
|
|
139
|
+
this._repositories.project as ProjectRepository
|
|
140
|
+
)
|
|
141
|
+
|
|
142
|
+
app.use((err: Error, req: Request, resp: Response, next: NextFunction) => {
|
|
143
|
+
if (err instanceof CommercetoolsError) {
|
|
144
|
+
return resp.status(err.statusCode).send({
|
|
145
|
+
statusCode: err.statusCode,
|
|
146
|
+
message: err.message,
|
|
147
|
+
errors: [err.info],
|
|
148
|
+
})
|
|
149
|
+
} else {
|
|
150
|
+
console.error(err)
|
|
151
|
+
return resp.status(500).send({
|
|
152
|
+
error: err.message,
|
|
153
|
+
})
|
|
154
|
+
}
|
|
155
|
+
})
|
|
156
|
+
|
|
157
|
+
return app
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
private mockApiHost() {
|
|
161
|
+
const app = this.app
|
|
162
|
+
|
|
163
|
+
this._nockScopes.api = nock(this.options.apiHost)
|
|
164
|
+
.persist()
|
|
165
|
+
.get(/.*/)
|
|
166
|
+
.reply(async function (uri) {
|
|
167
|
+
const response = await supertest(app)
|
|
168
|
+
.get(uri)
|
|
169
|
+
.set(copyHeaders(this.req.headers))
|
|
170
|
+
return [response.status, response.body]
|
|
171
|
+
})
|
|
172
|
+
.post(/.*/)
|
|
173
|
+
.reply(async function (uri, body) {
|
|
174
|
+
const response = await supertest(app)
|
|
175
|
+
.post(uri)
|
|
176
|
+
.set(copyHeaders(this.req.headers))
|
|
177
|
+
.send(body)
|
|
178
|
+
return [response.status, response.body]
|
|
179
|
+
})
|
|
180
|
+
.delete(/.*/)
|
|
181
|
+
.reply(async function (uri, body) {
|
|
182
|
+
const response = await supertest(app)
|
|
183
|
+
.delete(uri)
|
|
184
|
+
.set(copyHeaders(this.req.headers))
|
|
185
|
+
.send(body)
|
|
186
|
+
return [response.status, response.body]
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
private mockAuthHost() {
|
|
191
|
+
const app = this.app
|
|
192
|
+
|
|
193
|
+
this._nockScopes.auth = nock(this.options.authHost)
|
|
194
|
+
.persist()
|
|
195
|
+
.post(/^\/oauth\/.*/)
|
|
196
|
+
.reply(async function (uri, body) {
|
|
197
|
+
const response = await supertest(app)
|
|
198
|
+
.post(uri + '?' + body)
|
|
199
|
+
.set(copyHeaders(this.req.headers))
|
|
200
|
+
.send()
|
|
201
|
+
return [response.status, response.body]
|
|
202
|
+
})
|
|
203
|
+
}
|
|
204
204
|
}
|
package/src/exceptions.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
export abstract class BaseError {
|
|
2
|
-
|
|
2
|
+
abstract message: string
|
|
3
3
|
}
|
|
4
4
|
|
|
5
5
|
export class CommercetoolsError<T extends BaseError> extends Error {
|
|
6
|
-
|
|
7
|
-
|
|
6
|
+
info: T
|
|
7
|
+
statusCode: number
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
9
|
+
constructor(info: T, statusCode = 400) {
|
|
10
|
+
super(info.message)
|
|
11
|
+
this.info = info
|
|
12
|
+
this.statusCode = statusCode || 500
|
|
13
|
+
}
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export interface InvalidRequestError {
|
|
17
|
-
|
|
18
|
-
|
|
17
|
+
readonly code: 'invalid_request'
|
|
18
|
+
readonly message: string
|
|
19
19
|
}
|
package/src/helpers.ts
CHANGED
|
@@ -2,10 +2,10 @@ import { ParsedQs } from 'qs'
|
|
|
2
2
|
import { v4 as uuidv4 } from 'uuid'
|
|
3
3
|
|
|
4
4
|
export const getBaseResourceProperties = () => ({
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
id: uuidv4(),
|
|
6
|
+
createdAt: new Date().toISOString(),
|
|
7
|
+
lastModifiedAt: new Date().toISOString(),
|
|
8
|
+
version: 0,
|
|
9
9
|
})
|
|
10
10
|
|
|
11
11
|
/**
|
|
@@ -13,36 +13,36 @@ export const getBaseResourceProperties = () => ({
|
|
|
13
13
|
* return obj['foo']['bar']['value']
|
|
14
14
|
*/
|
|
15
15
|
export const nestedLookup = (obj: any, path: string): any => {
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
16
|
+
if (!path || path === '') {
|
|
17
|
+
return obj
|
|
18
|
+
}
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
const parts = path.split('.')
|
|
21
|
+
let val = obj
|
|
22
22
|
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
for (let i = 0; i < parts.length; i++) {
|
|
24
|
+
const part = parts[i]
|
|
25
|
+
if (val == undefined) {
|
|
26
|
+
return undefined
|
|
27
|
+
}
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
val = val[part]
|
|
30
|
+
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
return val
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
export const QueryParamsAsArray = (
|
|
36
|
-
|
|
36
|
+
input: string | ParsedQs | string[] | ParsedQs[] | undefined
|
|
37
37
|
): string[] => {
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
38
|
+
if (input == undefined) {
|
|
39
|
+
return []
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
if (Array.isArray(input)) {
|
|
43
|
+
return input as string[]
|
|
44
|
+
}
|
|
45
|
+
return [input] as string[]
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
export const cloneObject = <T>(o: T): T => JSON.parse(JSON.stringify(o))
|