@wishknish/knishio-client-ts 0.7.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/LICENSE +674 -0
- package/README.md +425 -0
- package/dist/index.cjs +9961 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.iife.js +32241 -0
- package/dist/index.iife.js.map +1 -0
- package/dist/index.js +9853 -0
- package/dist/index.js.map +1 -0
- package/package.json +113 -0
- package/src/AuthToken.ts +214 -0
- package/src/KnishIOClient.ts +2020 -0
- package/src/constants.ts +398 -0
- package/src/core/Atom.ts +646 -0
- package/src/core/AtomMeta.ts +278 -0
- package/src/core/Meta.ts +428 -0
- package/src/core/Molecule.ts +825 -0
- package/src/core/PolicyMeta.ts +130 -0
- package/src/core/TokenUnit.ts +148 -0
- package/src/core/Wallet.ts +467 -0
- package/src/exception/AtomIndexException.ts +97 -0
- package/src/exception/AtomsMissingException.ts +109 -0
- package/src/exception/AuthorizationRejectedException.ts +63 -0
- package/src/exception/BalanceInsufficientException.ts +58 -0
- package/src/exception/BaseException.ts +275 -0
- package/src/exception/BatchIdException.ts +58 -0
- package/src/exception/CodeException.ts +119 -0
- package/src/exception/DecryptionKeyException.ts +65 -0
- package/src/exception/InvalidResponseException.ts +112 -0
- package/src/exception/MetaMissingException.ts +58 -0
- package/src/exception/MolecularHashMismatchException.ts +115 -0
- package/src/exception/MolecularHashMissingException.ts +58 -0
- package/src/exception/NegativeAmountException.ts +58 -0
- package/src/exception/PolicyInvalidException.ts +58 -0
- package/src/exception/SignatureMalformedException.ts +58 -0
- package/src/exception/SignatureMismatchException.ts +98 -0
- package/src/exception/StackableUnitAmountException.ts +65 -0
- package/src/exception/StackableUnitDecimalsException.ts +65 -0
- package/src/exception/TransferBalanceException.ts +98 -0
- package/src/exception/TransferMalformedException.ts +58 -0
- package/src/exception/TransferMismatchedException.ts +58 -0
- package/src/exception/TransferRemainderException.ts +58 -0
- package/src/exception/TransferToSelfException.ts +58 -0
- package/src/exception/TransferUnbalancedException.ts +58 -0
- package/src/exception/UnauthenticatedException.ts +147 -0
- package/src/exception/WalletCredentialException.ts +108 -0
- package/src/exception/WalletShadowException.ts +65 -0
- package/src/exception/WrongTokenTypeException.ts +58 -0
- package/src/exception/index.ts +272 -0
- package/src/index.ts +512 -0
- package/src/instance/rules/Callback.ts +257 -0
- package/src/instance/rules/Condition.ts +96 -0
- package/src/instance/rules/Meta.ts +163 -0
- package/src/instance/rules/Rule.ts +29 -0
- package/src/instance/rules/exception/RuleArgumentException.ts +65 -0
- package/src/libraries/CheckMolecule.ts +581 -0
- package/src/libraries/Decimal.ts +94 -0
- package/src/libraries/Dot.ts +202 -0
- package/src/libraries/GraphQLClient.ts +276 -0
- package/src/libraries/Hex.ts +155 -0
- package/src/libraries/UrqlClientWrapper.ts +336 -0
- package/src/libraries/array.ts +91 -0
- package/src/libraries/crypto.ts +816 -0
- package/src/libraries/strings.ts +458 -0
- package/src/mutation/Mutation.ts +103 -0
- package/src/mutation/MutationActiveSession.ts +108 -0
- package/src/mutation/MutationClaimShadowWallet.ts +91 -0
- package/src/mutation/MutationCreateIdentifier.ts +86 -0
- package/src/mutation/MutationCreateMeta.ts +92 -0
- package/src/mutation/MutationCreateRule.ts +90 -0
- package/src/mutation/MutationCreateToken.ts +92 -0
- package/src/mutation/MutationCreateWallet.ts +78 -0
- package/src/mutation/MutationDepositBufferToken.ts +72 -0
- package/src/mutation/MutationLinkIdentifier.ts +87 -0
- package/src/mutation/MutationProposeMolecule.ts +147 -0
- package/src/mutation/MutationRequestAuthorization.ts +77 -0
- package/src/mutation/MutationRequestAuthorizationGuest.ts +85 -0
- package/src/mutation/MutationRequestTokens.ts +98 -0
- package/src/mutation/MutationTransferTokens.ts +87 -0
- package/src/mutation/MutationWithdrawBufferToken.ts +73 -0
- package/src/query/Query.ts +187 -0
- package/src/query/QueryActiveSession.ts +89 -0
- package/src/query/QueryAtom.ts +275 -0
- package/src/query/QueryBalance.ts +102 -0
- package/src/query/QueryBatch.ts +145 -0
- package/src/query/QueryBatchHistory.ts +86 -0
- package/src/query/QueryContinuId.ts +91 -0
- package/src/query/QueryMetaType.ts +177 -0
- package/src/query/QueryMetaTypeViaAtom.ts +199 -0
- package/src/query/QueryPolicy.ts +91 -0
- package/src/query/QueryToken.ts +90 -0
- package/src/query/QueryUserActivity.ts +153 -0
- package/src/query/QueryWalletBundle.ts +92 -0
- package/src/query/QueryWalletList.ts +106 -0
- package/src/response/EnhancedResponse.ts +345 -0
- package/src/response/Response.ts +254 -0
- package/src/response/ResponseActiveSession.ts +72 -0
- package/src/response/ResponseAtom.ts +132 -0
- package/src/response/ResponseAuthorizationGuest.ts +119 -0
- package/src/response/ResponseBalance.ts +153 -0
- package/src/response/ResponseClaimShadowWallet.ts +56 -0
- package/src/response/ResponseContinuId.ts +101 -0
- package/src/response/ResponseCreateIdentifier.ts +56 -0
- package/src/response/ResponseCreateMeta.ts +58 -0
- package/src/response/ResponseCreateRule.ts +56 -0
- package/src/response/ResponseCreateToken.ts +58 -0
- package/src/response/ResponseCreateWallet.ts +58 -0
- package/src/response/ResponseLinkIdentifier.ts +87 -0
- package/src/response/ResponseMetaBatch.ts +72 -0
- package/src/response/ResponseMetaType.ts +108 -0
- package/src/response/ResponseMetaTypeViaAtom.ts +108 -0
- package/src/response/ResponsePolicy.ts +90 -0
- package/src/response/ResponseProposeMolecule.ts +155 -0
- package/src/response/ResponseQueryActiveSession.ts +105 -0
- package/src/response/ResponseQueryUserActivity.ts +89 -0
- package/src/response/ResponseRequestAuthorization.ts +100 -0
- package/src/response/ResponseRequestAuthorizationGuest.ts +133 -0
- package/src/response/ResponseRequestTokens.ts +58 -0
- package/src/response/ResponseTransferTokens.ts +72 -0
- package/src/response/ResponseWalletBundle.ts +95 -0
- package/src/response/ResponseWalletList.ts +165 -0
- package/src/schemas/index.ts +457 -0
- package/src/subscribe/ActiveSessionSubscribe.ts +72 -0
- package/src/subscribe/ActiveWalletSubscribe.ts +99 -0
- package/src/subscribe/CreateMoleculeSubscribe.ts +106 -0
- package/src/subscribe/Subscribe.ts +182 -0
- package/src/subscribe/WalletStatusSubscribe.ts +70 -0
- package/src/subscribe/index.ts +59 -0
- package/src/types/assertions.ts +722 -0
- package/src/types/client.ts +567 -0
- package/src/types/crypto.ts +541 -0
- package/src/types/graphql.ts +630 -0
- package/src/types/guards.ts +659 -0
- package/src/types/index.ts +614 -0
- package/src/types/response.ts +133 -0
- package/src/types/template-literals.ts +382 -0
- package/src/validation/UNIVERSAL_CONFIGURATION_INTERFACES.ts +580 -0
- package/src/validation/ValidationService.ts +607 -0
- package/src/validation/schemas.ts +447 -0
- package/src/versions/HashAtom.ts +170 -0
- package/src/versions/Version4.ts +120 -0
- package/src/versions/index.ts +80 -0
|
@@ -0,0 +1,336 @@
|
|
|
1
|
+
/*
|
|
2
|
+
(
|
|
3
|
+
(/(
|
|
4
|
+
(//(
|
|
5
|
+
(///(
|
|
6
|
+
(/////(
|
|
7
|
+
(//////( )
|
|
8
|
+
(////////( (/)
|
|
9
|
+
(////////( (///)
|
|
10
|
+
(//////////( (////)
|
|
11
|
+
(//////////( (//////)
|
|
12
|
+
(////////////( (///////)
|
|
13
|
+
(/////////////( (/////////)
|
|
14
|
+
(//////////////( (///////////)
|
|
15
|
+
(///////////////( (/////////////)
|
|
16
|
+
(////////////////( (//////////////)
|
|
17
|
+
((((((((((((((((((( (((((((((((((((
|
|
18
|
+
((((((((((((((((((( ((((((((((((((
|
|
19
|
+
((((((((((((((((((( ((((((((((((((
|
|
20
|
+
(((((((((((((((((((( (((((((((((((
|
|
21
|
+
(((((((((((((((((((( ((((((((((((
|
|
22
|
+
((((((((((((((((((( ((((((((((((
|
|
23
|
+
((((((((((((((((((( ((((((((((
|
|
24
|
+
((((((((((((((((((/ (((((((((
|
|
25
|
+
(((((((((((((((((( ((((((((
|
|
26
|
+
((((((((((((((((( (((((((
|
|
27
|
+
(((((((((((((((((( (((((
|
|
28
|
+
################# ##
|
|
29
|
+
################ #
|
|
30
|
+
################# ##
|
|
31
|
+
%################ ###
|
|
32
|
+
###############( ####
|
|
33
|
+
############### ####
|
|
34
|
+
############### ######
|
|
35
|
+
%#############( (#######
|
|
36
|
+
%############# #########
|
|
37
|
+
############( ##########
|
|
38
|
+
########### #############
|
|
39
|
+
######### ##############
|
|
40
|
+
%######
|
|
41
|
+
|
|
42
|
+
Powered by Knish.IO: Connecting a Decentralized World
|
|
43
|
+
|
|
44
|
+
Please visit https://github.com/WishKnish/KnishIO-Client-TS for information.
|
|
45
|
+
|
|
46
|
+
License: https://github.com/WishKnish/KnishIO-Client-TS/blob/master/LICENSE
|
|
47
|
+
*/
|
|
48
|
+
|
|
49
|
+
import {
|
|
50
|
+
createClient,
|
|
51
|
+
subscriptionExchange,
|
|
52
|
+
cacheExchange,
|
|
53
|
+
fetchExchange,
|
|
54
|
+
Client,
|
|
55
|
+
OperationResult
|
|
56
|
+
} from '@urql/core'
|
|
57
|
+
import { createClient as createWSClient, Client as WSClient } from 'graphql-ws'
|
|
58
|
+
import { pipe, map, SubscriptionLike } from 'wonka'
|
|
59
|
+
import type { DocumentNode } from 'graphql'
|
|
60
|
+
import type Wallet from '@/core/Wallet'
|
|
61
|
+
import { GraphQLRequestSchema, GraphQLResponseSchema, parseWithSchema } from '@/schemas'
|
|
62
|
+
|
|
63
|
+
// Enhanced type definitions with proper constraints
|
|
64
|
+
interface SocketConfig {
|
|
65
|
+
socketUri: string
|
|
66
|
+
appKey?: string
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
interface AuthData {
|
|
70
|
+
token: string
|
|
71
|
+
pubkey: string | null
|
|
72
|
+
wallet: Wallet | null
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
interface GraphQLRequestParams {
|
|
76
|
+
query?: DocumentNode
|
|
77
|
+
mutation?: DocumentNode
|
|
78
|
+
variables?: Record<string, unknown>
|
|
79
|
+
operationName?: string
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
interface FormattedResponse<TData = unknown> {
|
|
83
|
+
data: TData | null | undefined
|
|
84
|
+
errors?: Array<{
|
|
85
|
+
message: string
|
|
86
|
+
locations?: Array<{ line: number; column: number }>
|
|
87
|
+
path?: Array<string | number>
|
|
88
|
+
extensions?: Record<string, unknown>
|
|
89
|
+
}>
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
interface UrqlClientConfig {
|
|
93
|
+
serverUri: string
|
|
94
|
+
socket?: SocketConfig | null
|
|
95
|
+
encrypt?: boolean
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
interface SubscriptionManager {
|
|
99
|
+
unsubscribe: () => void
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* URQL GraphQL Client Wrapper with Enhanced Type Safety
|
|
104
|
+
*
|
|
105
|
+
* Provides a unified interface for GraphQL operations with subscription support
|
|
106
|
+
* Implements TypeScript 2025 patterns with proper generics and runtime validation
|
|
107
|
+
*/
|
|
108
|
+
class UrqlClientWrapper {
|
|
109
|
+
private $__client: Client
|
|
110
|
+
private $__authToken: string = ''
|
|
111
|
+
private $__pubkey: string | null = null
|
|
112
|
+
private $__wallet: Wallet | null = null
|
|
113
|
+
private readonly serverUri: string
|
|
114
|
+
private soketi: SocketConfig | null
|
|
115
|
+
private cipherLink: boolean
|
|
116
|
+
private readonly $__subscriptionManager: Map<string, SubscriptionManager> = new Map()
|
|
117
|
+
|
|
118
|
+
constructor(config: UrqlClientConfig) {
|
|
119
|
+
const { serverUri, socket = null, encrypt = false } = config
|
|
120
|
+
|
|
121
|
+
this.serverUri = serverUri
|
|
122
|
+
this.soketi = socket
|
|
123
|
+
this.cipherLink = !!encrypt
|
|
124
|
+
this.$__client = this.createUrqlClient({ serverUri, socket, encrypt })
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
private createUrqlClient({
|
|
128
|
+
serverUri,
|
|
129
|
+
socket,
|
|
130
|
+
encrypt
|
|
131
|
+
}: {
|
|
132
|
+
serverUri: string
|
|
133
|
+
socket?: SocketConfig | null
|
|
134
|
+
encrypt?: boolean
|
|
135
|
+
}): Client {
|
|
136
|
+
const exchanges = [cacheExchange, fetchExchange]
|
|
137
|
+
|
|
138
|
+
// Add subscription support if socket is configured
|
|
139
|
+
if (socket && socket.socketUri) {
|
|
140
|
+
const wsClient: WSClient = createWSClient({
|
|
141
|
+
url: socket.socketUri,
|
|
142
|
+
connectionParams: () => ({
|
|
143
|
+
authToken: this.$__authToken
|
|
144
|
+
})
|
|
145
|
+
})
|
|
146
|
+
|
|
147
|
+
exchanges.push(subscriptionExchange({
|
|
148
|
+
forwardSubscription: operation => ({
|
|
149
|
+
subscribe: sink => {
|
|
150
|
+
const disposable = wsClient.subscribe(operation, sink)
|
|
151
|
+
return { unsubscribe: disposable }
|
|
152
|
+
}
|
|
153
|
+
})
|
|
154
|
+
}))
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
return createClient({
|
|
158
|
+
url: serverUri,
|
|
159
|
+
exchanges,
|
|
160
|
+
fetchOptions: () => ({
|
|
161
|
+
headers: {
|
|
162
|
+
'X-Auth-Token': this.$__authToken
|
|
163
|
+
},
|
|
164
|
+
// Add 60 second timeout for debugging
|
|
165
|
+
signal: AbortSignal.timeout(60000)
|
|
166
|
+
})
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
setAuthData({ token, pubkey, wallet }: AuthData): void {
|
|
171
|
+
this.$__authToken = token
|
|
172
|
+
this.$__pubkey = pubkey
|
|
173
|
+
this.$__wallet = wallet
|
|
174
|
+
|
|
175
|
+
// Recreate client with new auth data
|
|
176
|
+
this.$__client = this.createUrqlClient({
|
|
177
|
+
serverUri: this.serverUri,
|
|
178
|
+
socket: this.soketi,
|
|
179
|
+
encrypt: this.cipherLink
|
|
180
|
+
})
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
async query<TData = unknown>(request: GraphQLRequestParams): Promise<FormattedResponse<TData>> {
|
|
184
|
+
const { query, variables } = request
|
|
185
|
+
if (!query) {
|
|
186
|
+
throw new Error('Query is required')
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const result = await this.$__client.query(query, variables).toPromise()
|
|
190
|
+
return this.formatResponse<TData>(result)
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
async mutate<TData = unknown>(request: GraphQLRequestParams): Promise<FormattedResponse<TData>> {
|
|
194
|
+
const { mutation, variables } = request
|
|
195
|
+
if (!mutation) {
|
|
196
|
+
throw new Error('Mutation is required')
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
const result = await this.$__client.mutation(mutation, variables).toPromise()
|
|
200
|
+
return this.formatResponse<TData>(result)
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
subscribe<TData = unknown>(
|
|
204
|
+
request: GraphQLRequestParams,
|
|
205
|
+
closure: (result: FormattedResponse<TData>) => void
|
|
206
|
+
): { unsubscribe: () => void } {
|
|
207
|
+
const { query, variables, operationName } = request
|
|
208
|
+
if (!query) {
|
|
209
|
+
throw new Error('Query is required for subscription')
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
const subscription: SubscriptionLike = pipe(
|
|
213
|
+
this.$__client.subscription(query, variables),
|
|
214
|
+
map(result => {
|
|
215
|
+
closure(this.formatResponse<TData>(result))
|
|
216
|
+
})
|
|
217
|
+
).subscribe(() => {})
|
|
218
|
+
|
|
219
|
+
// Store subscription for later cleanup
|
|
220
|
+
if (operationName) {
|
|
221
|
+
this.$__subscriptionManager.set(operationName, {
|
|
222
|
+
unsubscribe: () => subscription.unsubscribe()
|
|
223
|
+
})
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
return {
|
|
227
|
+
unsubscribe: () => operationName ? this.unsubscribe(operationName) : subscription.unsubscribe()
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
private formatResponse<TData = unknown>(result: OperationResult<TData>): FormattedResponse<TData> {
|
|
232
|
+
// Transform URQL result to match GraphQL standard response format
|
|
233
|
+
const response: FormattedResponse<TData> = {
|
|
234
|
+
data: result.data ?? null
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
// Format errors according to GraphQL spec
|
|
238
|
+
if (result.error) {
|
|
239
|
+
response.errors = [{
|
|
240
|
+
message: result.error.message,
|
|
241
|
+
locations: result.error.graphQLErrors?.[0]?.locations,
|
|
242
|
+
path: result.error.graphQLErrors?.[0]?.path,
|
|
243
|
+
extensions: result.error.graphQLErrors?.[0]?.extensions
|
|
244
|
+
}]
|
|
245
|
+
}
|
|
246
|
+
|
|
247
|
+
return response
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
socketDisconnect(): void {
|
|
251
|
+
if (this.soketi) {
|
|
252
|
+
// Unsubscribe from all active subscriptions
|
|
253
|
+
this.unsubscribeAll()
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
unsubscribe(operationName: string): void {
|
|
258
|
+
const subscription = this.$__subscriptionManager.get(operationName)
|
|
259
|
+
if (subscription) {
|
|
260
|
+
subscription.unsubscribe()
|
|
261
|
+
this.$__subscriptionManager.delete(operationName)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
unsubscribeAll(): void {
|
|
266
|
+
this.$__subscriptionManager.forEach((subscription, operationName) => {
|
|
267
|
+
this.unsubscribe(operationName)
|
|
268
|
+
})
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
unsubscribeFromChannel(operationName: string): void {
|
|
272
|
+
this.unsubscribe(operationName)
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
setEncryption(encrypt: boolean = false): void {
|
|
276
|
+
this.cipherLink = encrypt
|
|
277
|
+
this.$__client = this.createUrqlClient({
|
|
278
|
+
serverUri: this.serverUri,
|
|
279
|
+
socket: this.soketi,
|
|
280
|
+
encrypt
|
|
281
|
+
})
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Getters
|
|
285
|
+
getAuthToken(): string {
|
|
286
|
+
return this.$__authToken
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
getPubKey(): string | null {
|
|
290
|
+
return this.$__pubkey
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
getWallet(): Wallet | null {
|
|
294
|
+
return this.$__wallet
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
getServerUri(): string {
|
|
298
|
+
return this.serverUri
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
getSocketUri(): string | null {
|
|
302
|
+
return this.soketi ? this.soketi.socketUri : null
|
|
303
|
+
}
|
|
304
|
+
|
|
305
|
+
getUri(): string {
|
|
306
|
+
return this.serverUri
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
// Setters
|
|
310
|
+
setUri(uri: string): void {
|
|
311
|
+
this.serverUri = uri
|
|
312
|
+
this.$__client = this.createUrqlClient({
|
|
313
|
+
serverUri: uri,
|
|
314
|
+
socket: this.soketi,
|
|
315
|
+
encrypt: this.cipherLink
|
|
316
|
+
})
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
setSocketUri({ socketUri, appKey }: SocketConfig): void {
|
|
320
|
+
this.soketi = { socketUri, appKey }
|
|
321
|
+
this.$__client = this.createUrqlClient({
|
|
322
|
+
serverUri: this.serverUri,
|
|
323
|
+
socket: this.soketi,
|
|
324
|
+
encrypt: this.cipherLink
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
export default UrqlClientWrapper
|
|
330
|
+
export type {
|
|
331
|
+
SocketConfig,
|
|
332
|
+
AuthData,
|
|
333
|
+
GraphQLRequestParams,
|
|
334
|
+
FormattedResponse,
|
|
335
|
+
UrqlClientConfig
|
|
336
|
+
}
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Array utility functions
|
|
3
|
+
* Essential utilities for KnishIO SDK operations
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Deep clone an object or array
|
|
8
|
+
* Matches JavaScript SDK deepCloning function exactly
|
|
9
|
+
* Used by Molecule.toJSON() and other operations requiring immutable copies
|
|
10
|
+
*/
|
|
11
|
+
export function deepCloning<T>(
|
|
12
|
+
o: T, // Object to clone
|
|
13
|
+
h?: any[] // Cache for circular reference handling
|
|
14
|
+
): T {
|
|
15
|
+
let i: any
|
|
16
|
+
let r: any
|
|
17
|
+
let x: any
|
|
18
|
+
|
|
19
|
+
const t = [Array, Date, Number, String, Boolean] // Types to treat specially
|
|
20
|
+
const s = Object.prototype.toString // Shortcut to toString
|
|
21
|
+
h = h || [] // Create cache if not provided
|
|
22
|
+
|
|
23
|
+
// Search cache for our object (handle circular references)
|
|
24
|
+
for (i = 0; i < h.length; i += 2) {
|
|
25
|
+
if (o === h[i]) {
|
|
26
|
+
return h[i + 1] as T
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
// Clone o if it is an uncached object and not null
|
|
31
|
+
if (!r && o && typeof o === 'object') {
|
|
32
|
+
r = {} // Default result template: plain object
|
|
33
|
+
|
|
34
|
+
// Handle special types by comparing toString outputs
|
|
35
|
+
for (i = 0; i < t.length; i++) {
|
|
36
|
+
// @ts-ignore - Dynamic type construction
|
|
37
|
+
if (s.call(o) === s.call(x = new t[i](o as any))) {
|
|
38
|
+
r = i ? x : []
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
h.push(o, r) // Add to cache before recursive call
|
|
43
|
+
|
|
44
|
+
// Copy properties recursively
|
|
45
|
+
for (i in o) {
|
|
46
|
+
if (Object.prototype.hasOwnProperty.call(o, i)) {
|
|
47
|
+
r[i] = deepCloning((o as any)[i], h)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
return r || o
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Split an array into chunks of specified size
|
|
57
|
+
* Used for batch processing operations
|
|
58
|
+
*/
|
|
59
|
+
export function chunkArray<T>(arr: T[], size: number): T[][] {
|
|
60
|
+
if (!arr.length) {
|
|
61
|
+
return []
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
return [arr.slice(0, size)].concat(chunkArray(arr.slice(size), size))
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/**
|
|
68
|
+
* Find elements that are different between arrays
|
|
69
|
+
* Returns elements that are unique to each array
|
|
70
|
+
*/
|
|
71
|
+
export function diff<T>(...arrays: T[][]): T[] {
|
|
72
|
+
return [].concat(...arrays.map((arr, i) => {
|
|
73
|
+
const others = arrays.slice(0)
|
|
74
|
+
others.splice(i, 1)
|
|
75
|
+
const unique = [...new Set([].concat(...others as any))]
|
|
76
|
+
return arr.filter(item => !unique.includes(item))
|
|
77
|
+
}) as any)
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Find common elements across all arrays
|
|
82
|
+
* Returns only elements present in all arrays
|
|
83
|
+
*/
|
|
84
|
+
export function intersect<T>(...arrays: T[][]): T[] {
|
|
85
|
+
if (arrays.length === 0) return []
|
|
86
|
+
if (arrays.length === 1) return arrays[0]
|
|
87
|
+
|
|
88
|
+
return arrays.reduce((first, second) =>
|
|
89
|
+
first.filter(item => second.includes(item))
|
|
90
|
+
)
|
|
91
|
+
}
|