@ic-reactor/candid 3.0.7-beta.2 → 3.0.8-beta.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.
Files changed (53) hide show
  1. package/dist/display-reactor.d.ts +3 -2
  2. package/dist/display-reactor.d.ts.map +1 -1
  3. package/dist/display-reactor.js +6 -0
  4. package/dist/display-reactor.js.map +1 -1
  5. package/dist/index.d.ts +1 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +1 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/metadata-display-reactor.d.ts +73 -0
  10. package/dist/metadata-display-reactor.d.ts.map +1 -0
  11. package/dist/metadata-display-reactor.js +128 -0
  12. package/dist/metadata-display-reactor.js.map +1 -0
  13. package/dist/visitor/arguments/index.d.ts +69 -0
  14. package/dist/visitor/arguments/index.d.ts.map +1 -0
  15. package/dist/visitor/arguments/index.js +277 -0
  16. package/dist/visitor/arguments/index.js.map +1 -0
  17. package/dist/visitor/arguments/types.d.ts +92 -0
  18. package/dist/visitor/arguments/types.d.ts.map +1 -0
  19. package/dist/visitor/arguments/types.js +2 -0
  20. package/dist/visitor/arguments/types.js.map +1 -0
  21. package/dist/visitor/constants.d.ts +4 -0
  22. package/dist/visitor/constants.d.ts.map +1 -0
  23. package/dist/visitor/constants.js +61 -0
  24. package/dist/visitor/constants.js.map +1 -0
  25. package/dist/visitor/helpers.d.ts +30 -0
  26. package/dist/visitor/helpers.d.ts.map +1 -0
  27. package/dist/visitor/helpers.js +200 -0
  28. package/dist/visitor/helpers.js.map +1 -0
  29. package/dist/visitor/returns/index.d.ts +76 -0
  30. package/dist/visitor/returns/index.d.ts.map +1 -0
  31. package/dist/visitor/returns/index.js +426 -0
  32. package/dist/visitor/returns/index.js.map +1 -0
  33. package/dist/visitor/returns/types.d.ts +143 -0
  34. package/dist/visitor/returns/types.d.ts.map +1 -0
  35. package/dist/visitor/returns/types.js +2 -0
  36. package/dist/visitor/returns/types.js.map +1 -0
  37. package/dist/visitor/types.d.ts +6 -0
  38. package/dist/visitor/types.d.ts.map +1 -0
  39. package/dist/visitor/types.js +3 -0
  40. package/dist/visitor/types.js.map +1 -0
  41. package/package.json +3 -2
  42. package/src/display-reactor.ts +10 -2
  43. package/src/index.ts +1 -0
  44. package/src/metadata-display-reactor.ts +184 -0
  45. package/src/visitor/arguments/index.test.ts +882 -0
  46. package/src/visitor/arguments/index.ts +405 -0
  47. package/src/visitor/arguments/types.ts +168 -0
  48. package/src/visitor/constants.ts +62 -0
  49. package/src/visitor/helpers.ts +221 -0
  50. package/src/visitor/returns/index.test.ts +2027 -0
  51. package/src/visitor/returns/index.ts +553 -0
  52. package/src/visitor/returns/types.ts +272 -0
  53. package/src/visitor/types.ts +29 -0
@@ -0,0 +1,221 @@
1
+ import { IDL } from "./types"
2
+
3
+ export const extractAndSortArgs = <T extends Record<string, unknown>>(
4
+ argsObject: T
5
+ ): Array<T[keyof T]> => {
6
+ if (!argsObject || typeof argsObject !== "object") return []
7
+
8
+ const args: Array<T[keyof T]> = []
9
+ let index = 0
10
+
11
+ while (Object.prototype.hasOwnProperty.call(argsObject, `arg${index}`)) {
12
+ args.push(argsObject[`arg${index}`] as T[keyof T])
13
+ index++
14
+ }
15
+
16
+ return args
17
+ }
18
+
19
+ /**
20
+ * Normalize form state by converting objects with numeric string keys to arrays.
21
+ * TanStack Form sometimes creates { "0": value, "1": value } instead of [value, value]
22
+ * when using indexed field paths like "parent.0.child".
23
+ *
24
+ * This function also handles the variant cleanup case where objects have mixed
25
+ * numeric and named keys (e.g., { "0": old, "Add": current }) by removing
26
+ * orphaned numeric keys.
27
+ *
28
+ * This function recursively processes the form state and fixes these issues.
29
+ */
30
+ export const normalizeFormState = <T>(value: T): T => {
31
+ // Handle null/undefined
32
+ if (value === null || value === undefined) {
33
+ return value
34
+ }
35
+
36
+ // Handle arrays - recursively normalize each element
37
+ if (Array.isArray(value)) {
38
+ return value.map(normalizeFormState) as T
39
+ }
40
+
41
+ // Handle objects
42
+ if (typeof value === "object") {
43
+ const obj = value as Record<string, unknown>
44
+ const keys = Object.keys(obj)
45
+
46
+ // Separate numeric and non-numeric keys
47
+ const numericKeys = keys.filter((k) => /^\d+$/.test(k))
48
+ const namedKeys = keys.filter((k) => !/^\d+$/.test(k))
49
+
50
+ // Case 1: All keys are numeric - convert to array
51
+ if (numericKeys.length > 0 && namedKeys.length === 0) {
52
+ const sortedNums = numericKeys.map(Number).sort((a, b) => a - b)
53
+ // Check if keys are consecutive starting from 0
54
+ if (sortedNums.every((num, idx) => num === idx)) {
55
+ return sortedNums.map((k) => normalizeFormState(obj[String(k)])) as T
56
+ }
57
+ }
58
+
59
+ // Case 2: Mixed keys (variant case) - keep only named keys, remove orphan numeric keys
60
+ if (numericKeys.length > 0 && namedKeys.length > 0) {
61
+ const result: Record<string, unknown> = {}
62
+ for (const key of namedKeys) {
63
+ result[key] = normalizeFormState(obj[key])
64
+ }
65
+ return result as T
66
+ }
67
+
68
+ // Case 3: All named keys - recursively normalize all values
69
+ const result: Record<string, unknown> = {}
70
+ for (const [key, val] of Object.entries(obj)) {
71
+ result[key] = normalizeFormState(val)
72
+ }
73
+ return result as T
74
+ }
75
+
76
+ // Return primitives as-is
77
+ return value
78
+ }
79
+
80
+ export const convertNanoToDate = (nano: bigint) => {
81
+ return new Date(Number(nano) / 1000000)
82
+ }
83
+
84
+ export const convertToCycle = (cycles: bigint) => {
85
+ const mcycles = cycles / BigInt(1_000_000)
86
+ if (mcycles >= BigInt(1_000_000)) {
87
+ const tcycles = mcycles / BigInt(1_000_000)
88
+ return `${tcycles.toLocaleString()} T`
89
+ }
90
+ return `${mcycles.toLocaleString()} M`
91
+ }
92
+
93
+ export const convertStringToNumber = (value: string) => {
94
+ const bits = value.length
95
+ if (bits >= 16) {
96
+ return BigInt(value)
97
+ } else {
98
+ return Number(value)
99
+ }
100
+ }
101
+
102
+ export const validateNumberError = (t: IDL.Type) => {
103
+ return function validate(value: string) {
104
+ if (value === "") {
105
+ return true
106
+ }
107
+
108
+ const bits = value.length
109
+ if (bits >= 16) {
110
+ try {
111
+ const valueAsBigInt = BigInt(value)
112
+ t.covariant(valueAsBigInt)
113
+ return true
114
+ } catch (error) {
115
+ return (error as Error).message || "Failed to convert to BigInt"
116
+ }
117
+ } else {
118
+ try {
119
+ const valueAsNumber = Number(value)
120
+ t.covariant(valueAsNumber)
121
+ return true
122
+ } catch (error) {
123
+ return (error as Error).message || "Failed to convert to number"
124
+ }
125
+ }
126
+ }
127
+ }
128
+
129
+ export const validateError = (t: IDL.Type) => {
130
+ return function validate(value: unknown) {
131
+ try {
132
+ t.covariant(value)
133
+ return true
134
+ } catch (error) {
135
+ return (error as Error).message || "An error occurred"
136
+ }
137
+ }
138
+ }
139
+
140
+ export function isQuery(func: IDL.FuncClass): boolean {
141
+ return (
142
+ func.annotations.includes("query") ||
143
+ func.annotations.includes("composite_query")
144
+ )
145
+ }
146
+
147
+ export function isUrl(str: string): boolean {
148
+ if (typeof str !== "string") return false
149
+ return str.startsWith("http") || str.startsWith("https")
150
+ }
151
+
152
+ export function isImage(str: string): boolean {
153
+ if (typeof str !== "string") return false
154
+ // Check if the string starts with 'data:image' (indicating base64-encoded image)
155
+ if (str.startsWith("data:image")) {
156
+ return true
157
+ }
158
+
159
+ // List of common image file extensions
160
+ const imageExtensions = [".jpg", ".jpeg", ".png", ".gif", ".svg"]
161
+
162
+ // Check if the string ends with any of the image extensions (indicating image URL)
163
+ if (imageExtensions.some((ext) => str.endsWith(ext))) {
164
+ return true
165
+ }
166
+
167
+ return false
168
+ }
169
+
170
+ export function isUuid(str: string): boolean {
171
+ if (typeof str !== "string") return false
172
+ return /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i.test(
173
+ str
174
+ )
175
+ }
176
+
177
+ export function isCanisterId(str: string): boolean {
178
+ if (typeof str !== "string") return false
179
+ if (str.length !== 27) return false
180
+ // All canister IDs end with "-cai"
181
+ return str.endsWith("-cai")
182
+ }
183
+
184
+ export function isBtcAddress(str: string): boolean {
185
+ if (typeof str !== "string") return false
186
+ // Bech32 (Mainnet: bc1, Testnet: tb1, Regtest: bcrt1)
187
+ if (/^(bc1|tb1|bcrt1)[a-zA-HJ-NP-Z0-9]{25,60}$/.test(str)) return true
188
+ // Base58 (Mainnet: 1/3, Testnet: m/n/2)
189
+ if (/^[13mn2][a-km-zA-HJ-NP-Z1-9]{25,34}$/.test(str)) return true
190
+ return false
191
+ }
192
+
193
+ export function isEthAddress(str: string): boolean {
194
+ if (typeof str !== "string") return false
195
+ return /^0x[a-fA-F0-9]{40}$/.test(str)
196
+ }
197
+
198
+ export function isAccountIdentifier(str: string): boolean {
199
+ if (typeof str !== "string") return false
200
+ // 64 characters hex string (standard for ICP account ids and hashes)
201
+ return /^[a-fA-F0-9]{64}$/.test(str)
202
+ }
203
+
204
+ export function isIsoDate(str: string): boolean {
205
+ if (typeof str !== "string") return false
206
+ // Basic ISO 8601 / RFC 3339 format check
207
+ // YYYY-MM-DDTHH:mm:ss.sssZ (optional milliseconds/nanoseconds and timezone)
208
+ return /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d+)?(?:Z|[+-]\d{2}:?\d{2})$/.test(
209
+ str
210
+ )
211
+ }
212
+
213
+ export function uint8ArrayToHexString(bytes: Uint8Array | number[]): string {
214
+ if (!bytes) return ""
215
+ if (Array.isArray(bytes)) {
216
+ return bytes.map((b) => b.toString(16).padStart(2, "0")).join("")
217
+ }
218
+ return Array.from(bytes)
219
+ .map((b) => b.toString(16).padStart(2, "0"))
220
+ .join("")
221
+ }