@ic-reactor/candid 3.0.14-beta.0 → 3.0.14-beta.2

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 (33) hide show
  1. package/dist/metadata-display-reactor.d.ts +66 -11
  2. package/dist/metadata-display-reactor.d.ts.map +1 -1
  3. package/dist/metadata-display-reactor.js +48 -12
  4. package/dist/metadata-display-reactor.js.map +1 -1
  5. package/dist/visitor/arguments/helpers.d.ts +22 -7
  6. package/dist/visitor/arguments/helpers.d.ts.map +1 -1
  7. package/dist/visitor/arguments/helpers.js +39 -5
  8. package/dist/visitor/arguments/helpers.js.map +1 -1
  9. package/dist/visitor/arguments/index.d.ts.map +1 -1
  10. package/dist/visitor/arguments/index.js +26 -34
  11. package/dist/visitor/arguments/index.js.map +1 -1
  12. package/dist/visitor/arguments/types.d.ts +120 -132
  13. package/dist/visitor/arguments/types.d.ts.map +1 -1
  14. package/dist/visitor/arguments/types.js +25 -1
  15. package/dist/visitor/arguments/types.js.map +1 -1
  16. package/dist/visitor/constants.d.ts.map +1 -1
  17. package/dist/visitor/constants.js +19 -17
  18. package/dist/visitor/constants.js.map +1 -1
  19. package/dist/visitor/returns/index.d.ts.map +1 -1
  20. package/dist/visitor/returns/index.js +24 -13
  21. package/dist/visitor/returns/index.js.map +1 -1
  22. package/dist/visitor/returns/types.d.ts +48 -10
  23. package/dist/visitor/returns/types.d.ts.map +1 -1
  24. package/package.json +2 -2
  25. package/src/metadata-display-reactor.ts +86 -14
  26. package/src/visitor/arguments/helpers.ts +50 -8
  27. package/src/visitor/arguments/index.test.ts +105 -61
  28. package/src/visitor/arguments/index.ts +38 -36
  29. package/src/visitor/arguments/types.ts +211 -220
  30. package/src/visitor/constants.ts +24 -15
  31. package/src/visitor/returns/index.test.ts +30 -30
  32. package/src/visitor/returns/index.ts +52 -21
  33. package/src/visitor/returns/types.ts +60 -17
@@ -2,21 +2,34 @@ import type { BaseActor, FunctionName, FunctionType } from "@ic-reactor/core"
2
2
  import * as z from "zod"
3
3
  import type { VisitorDataType, TextFormat, NumberFormat } from "../types"
4
4
 
5
- export type { TextFormat, NumberFormat }
5
+ export type { VisitorDataType, TextFormat, NumberFormat }
6
6
 
7
7
  // ════════════════════════════════════════════════════════════════════════════
8
- // Field Type Union
8
+ // Custom Error Class
9
9
  // ════════════════════════════════════════════════════════════════════════════
10
10
 
11
- export type ArgumentFieldType = VisitorDataType
11
+ /**
12
+ * Custom error class for metadata-related errors.
13
+ * Provides additional context about the field path and Candid type.
14
+ */
15
+ export class MetadataError extends Error {
16
+ constructor(
17
+ message: string,
18
+ public readonly fieldPath?: string,
19
+ public readonly candidType?: string
20
+ ) {
21
+ super(message)
22
+ this.name = "MetadataError"
23
+ }
24
+ }
12
25
 
13
26
  // ════════════════════════════════════════════════════════════════════════════
14
- // Component Type Hints
27
+ // Component & UI Types
15
28
  // ════════════════════════════════════════════════════════════════════════════
16
29
 
17
30
  /**
18
31
  * Suggested component type for rendering the field.
19
- * This eliminates the need for switch statements in the frontend.
32
+ * Use this to map field types to your UI components.
20
33
  */
21
34
  export type FieldComponentType =
22
35
  | "record-container"
@@ -33,13 +46,8 @@ export type FieldComponentType =
33
46
  | "recursive-lazy"
34
47
  | "unknown-fallback"
35
48
 
36
- // ════════════════════════════════════════════════════════════════════════════
37
- // Render Hints for UI Rendering Strategy
38
- // ════════════════════════════════════════════════════════════════════════════
39
-
40
49
  /**
41
50
  * Input type hints for HTML input elements.
42
- * Used by primitive fields to suggest the appropriate input type.
43
51
  */
44
52
  export type InputType =
45
53
  | "text"
@@ -51,49 +59,28 @@ export type InputType =
51
59
 
52
60
  /**
53
61
  * Rendering hints for the UI.
54
- * Eliminates the need for frontend to maintain COMPLEX_TYPES arrays.
55
62
  */
56
63
  export interface RenderHint {
57
- /** Whether this field has its own container/card styling (compound types) */
58
64
  isCompound: boolean
59
- /** Whether this is a leaf input (primitive types) */
60
65
  isPrimitive: boolean
61
- /** Suggested input type for HTML input elements */
62
66
  inputType?: InputType
63
- /** Description or help text for the field (derived from Candid) */
64
67
  description?: string
65
68
  }
66
69
 
67
- // ════════════════════════════════════════════════════════════════════════════
68
- // Primitive Input Props
69
- // ════════════════════════════════════════════════════════════════════════════
70
-
71
70
  /**
72
71
  * Pre-computed HTML input props for primitive fields.
73
- * Can be spread directly onto an input element.
74
72
  */
75
73
  export interface PrimitiveInputProps {
76
- /** HTML input type - includes format-specific types */
77
74
  type?: "text" | "number" | "checkbox" | "email" | "url" | "tel"
78
- /** Placeholder text */
79
75
  placeholder?: string
80
- /** Minimum value for number inputs */
81
76
  min?: string | number
82
- /** Maximum value for number inputs */
83
77
  max?: string | number
84
- /** Step value for number inputs */
85
78
  step?: string | number
86
- /** Pattern for text inputs (e.g., phone numbers) */
87
79
  pattern?: string
88
- /** Input mode for virtual keyboards */
89
80
  inputMode?: "text" | "numeric" | "decimal" | "email" | "tel" | "url"
90
- /** Autocomplete hint */
91
81
  autoComplete?: string
92
- /** Whether to check spelling */
93
82
  spellCheck?: boolean
94
- /** Minimum length for text inputs */
95
83
  minLength?: number
96
- /** Maximum length for text inputs */
97
84
  maxLength?: number
98
85
  }
99
86
 
@@ -101,197 +88,223 @@ export interface PrimitiveInputProps {
101
88
  // Base Field Interface
102
89
  // ════════════════════════════════════════════════════════════════════════════
103
90
 
91
+ /**
92
+ * Base properties shared by all field nodes.
93
+ */
104
94
  interface FieldBase<T extends VisitorDataType = VisitorDataType> {
105
- /** The field type */
95
+ /** The Candid type category (record, variant, text, number, etc.) */
106
96
  type: T
107
- /** Raw label from Candid: "__arg0", "_0_" */
97
+ /** Raw label from Candid definition */
108
98
  label: string
109
- /** Pre-formatted display label for UI rendering */
99
+ /** Human-readable formatted label for display */
110
100
  displayLabel: string
111
- /** Form field name path for binding */
101
+ /** Form path compatible with TanStack Form (e.g., "[0]", "[0].owner") */
112
102
  name: string
113
- /** Suggested component type for rendering this field */
103
+ /** Suggested component type for rendering */
114
104
  component: FieldComponentType
115
- /** Rendering hints for UI strategy */
105
+ /** UI rendering hints */
116
106
  renderHint: RenderHint
117
- /** Zod schema for field validation */
107
+ /** Zod validation schema */
118
108
  schema: z.ZodTypeAny
119
- /** Original Candid type name for reference */
109
+ /** Original Candid type name */
120
110
  candidType: string
111
+ /** Default value for form initialization */
112
+ defaultValue: unknown
121
113
  }
122
114
 
123
115
  // ════════════════════════════════════════════════════════════════════════════
124
- // Type-Specific Extras
116
+ // Field Extras - Type-Specific Properties
125
117
  // ════════════════════════════════════════════════════════════════════════════
126
118
 
127
- /**
128
- * Blob field size limits.
129
- */
119
+ /** Blob upload limits configuration */
130
120
  export interface BlobLimits {
131
- /** Maximum bytes when entering as hex (e.g., 512 bytes) */
132
121
  maxHexBytes: number
133
- /** Maximum file size in bytes (e.g., 2MB ICP limit) */
134
122
  maxFileBytes: number
135
- /** Maximum hex display length before truncation */
136
123
  maxHexDisplayLength: number
137
124
  }
138
125
 
139
- /**
140
- * Validation result for blob input.
141
- */
126
+ /** Blob validation result */
142
127
  export interface BlobValidationResult {
143
- /** Whether the input is valid */
144
128
  valid: boolean
145
- /** Error message if invalid */
146
129
  error?: string
147
130
  }
148
131
 
132
+ interface RecordExtras {
133
+ /** Child fields of the record */
134
+ fields: FieldNode[]
135
+ /** Default value as object with all field defaults */
136
+ defaultValue: Record<string, unknown>
137
+ }
138
+
139
+ interface VariantExtras {
140
+ /** All variant options as fields */
141
+ options: FieldNode[]
142
+ /** The default selected option key */
143
+ defaultOption: string
144
+ /** Default value with the first option selected */
145
+ defaultValue: Record<string, unknown>
146
+ /** Get default value for a specific option */
147
+ getOptionDefault: (option: string) => Record<string, unknown>
148
+ /** Get field descriptor for a specific option */
149
+ getOption: (option: string) => FieldNode
150
+ /** Get currently selected option key from a value */
151
+ getSelectedKey: (value: Record<string, unknown>) => string
152
+ /** Get the field for the currently selected option */
153
+ getSelectedOption: (value: Record<string, unknown>) => FieldNode
154
+ }
155
+
156
+ interface TupleExtras {
157
+ /** Tuple element fields */
158
+ fields: FieldNode[]
159
+ /** Default value as array of element defaults */
160
+ defaultValue: unknown[]
161
+ }
162
+
163
+ interface OptionalExtras {
164
+ /** The inner type field */
165
+ innerField: FieldNode
166
+ /** Default value is always null */
167
+ defaultValue: null
168
+ /** Get default value of the inner type when enabling */
169
+ getInnerDefault: () => unknown
170
+ /** Check if a value represents an enabled optional */
171
+ isEnabled: (value: unknown) => boolean
172
+ }
173
+
174
+ interface VectorExtras {
175
+ /** Template field for vector items */
176
+ itemField: FieldNode
177
+ /** Default value is empty array */
178
+ defaultValue: unknown[]
179
+ /** Get default value for a new item */
180
+ getItemDefault: () => unknown
181
+ /** Create a field node for an item at a specific index */
182
+ createItemField: (index: number, overrides?: { label?: string }) => FieldNode
183
+ }
184
+
185
+ interface BlobExtras {
186
+ /** Template field for blob bytes */
187
+ itemField: FieldNode
188
+ /** Accepted input formats */
189
+ acceptedFormats: ("hex" | "base64" | "file")[]
190
+ /** Upload limits */
191
+ limits: BlobLimits
192
+ /** Normalize hex input string */
193
+ normalizeHex: (input: string) => string
194
+ /** Validate blob input */
195
+ validateInput: (value: string | Uint8Array) => BlobValidationResult
196
+ /** Default value is empty string */
197
+ defaultValue: string
198
+ }
199
+
200
+ interface RecursiveExtras {
201
+ /** The recursive type name */
202
+ typeName: string
203
+ /** Lazily extract the inner type */
204
+ extract: () => FieldNode
205
+ /** Get default value of the inner type */
206
+ getInnerDefault: () => unknown
207
+ /** Default value is undefined */
208
+ defaultValue: undefined
209
+ }
210
+
211
+ interface PrincipalExtras {
212
+ /** Maximum Principal string length */
213
+ maxLength: number
214
+ /** Minimum Principal string length */
215
+ minLength: number
216
+ /** Detected text format */
217
+ format: TextFormat
218
+ /** Pre-computed HTML input props */
219
+ inputProps: PrimitiveInputProps
220
+ /** Default value is empty string */
221
+ defaultValue: string
222
+ }
223
+
224
+ interface NumberExtras {
225
+ /** Whether the number is unsigned (nat vs int) */
226
+ unsigned: boolean
227
+ /** Whether the number is a float */
228
+ isFloat: boolean
229
+ /** Bit width (8, 16, 32, 64) */
230
+ bits?: number
231
+ /** Minimum value as string */
232
+ min?: string
233
+ /** Maximum value as string */
234
+ max?: string
235
+ /** Detected number format */
236
+ format: NumberFormat
237
+ /** Pre-computed HTML input props */
238
+ inputProps: PrimitiveInputProps
239
+ /** Default value is empty string */
240
+ defaultValue: string
241
+ }
242
+
243
+ interface TextExtras {
244
+ /** Minimum text length */
245
+ minLength?: number
246
+ /** Maximum text length */
247
+ maxLength?: number
248
+ /** Whether to use multiline input */
249
+ multiline?: boolean
250
+ /** Detected text format */
251
+ format: TextFormat
252
+ /** Pre-computed HTML input props */
253
+ inputProps: PrimitiveInputProps
254
+ /** Default value is empty string */
255
+ defaultValue: string
256
+ }
257
+
258
+ interface BooleanExtras {
259
+ /** Pre-computed HTML input props */
260
+ inputProps: PrimitiveInputProps
261
+ /** Default value is false */
262
+ defaultValue: boolean
263
+ }
264
+
265
+ interface NullExtras {
266
+ /** Default value is null */
267
+ defaultValue: null
268
+ }
269
+
270
+ interface UnknownExtras {
271
+ /** Default value is undefined */
272
+ defaultValue: undefined
273
+ }
274
+
149
275
  type FieldExtras<T extends VisitorDataType> = T extends "record"
150
- ? {
151
- /** Child fields in the record */
152
- fields: FieldNode[]
153
- /** Map of field label to its metadata for quick lookup */
154
- fieldMap: Map<string, FieldNode>
155
- defaultValue: Record<string, unknown>
156
- }
276
+ ? RecordExtras
157
277
  : T extends "variant"
158
- ? {
159
- /** All variant option fields */
160
- fields: FieldNode[]
161
- /** List of variant option names */
162
- options: string[]
163
- /** Default selected option */
164
- defaultOption: string
165
- /** Map of option name to its field metadata */
166
- optionMap: Map<string, FieldNode>
167
- defaultValue: Record<string, unknown>
168
- /** Get default value for a specific option */
169
- getOptionDefault: (option: string) => Record<string, unknown>
170
- /** Get the field for a specific option */
171
- getField: (option: string) => FieldNode
172
- /** Get the currently selected option from a value */
173
- getSelectedOption: (value: Record<string, unknown>) => string
174
- /** Get the selected field from a value */
175
- getSelectedField: (value: Record<string, unknown>) => FieldNode
176
- }
278
+ ? VariantExtras
177
279
  : T extends "tuple"
178
- ? {
179
- /** Tuple element fields in order */
180
- fields: FieldNode[]
181
- defaultValue: unknown[]
182
- }
280
+ ? TupleExtras
183
281
  : T extends "optional"
184
- ? {
185
- /** The inner field when value is present */
186
- innerField: FieldNode
187
- defaultValue: null
188
- /** Get default value when enabling the optional */
189
- getInnerDefault: () => unknown
190
- /** Check if a value represents an enabled optional */
191
- isEnabled: (value: unknown) => boolean
192
- }
282
+ ? OptionalExtras
193
283
  : T extends "vector"
194
- ? {
195
- /** Template field for vector items */
196
- itemField: FieldNode
197
- defaultValue: unknown[]
198
- /** Get a new item with default values */
199
- getItemDefault: () => unknown
200
- /** Create a properly configured item field for a specific index */
201
- createItemField: (
202
- index: number,
203
- overrides?: { label?: string }
204
- ) => FieldNode
205
- }
284
+ ? VectorExtras
206
285
  : T extends "blob"
207
- ? {
208
- /** Item field for individual bytes (nat8) */
209
- itemField: FieldNode
210
- /** Accepted input formats */
211
- acceptedFormats: ("hex" | "base64" | "file")[]
212
- /** Size limits for blob input */
213
- limits: BlobLimits
214
- /** Normalize hex input */
215
- normalizeHex: (input: string) => string
216
- /** Validate blob input value */
217
- validateInput: (
218
- value: string | Uint8Array
219
- ) => BlobValidationResult
220
- defaultValue: string
221
- }
286
+ ? BlobExtras
222
287
  : T extends "recursive"
223
- ? {
224
- /** Type name for the recursive type */
225
- typeName: string
226
- /** Lazily extract the inner field to prevent infinite loops */
227
- extract: () => FieldNode
228
- /** Get default value for the recursive type (evaluates lazily) */
229
- getInnerDefault: () => unknown
230
- defaultValue: undefined
231
- }
288
+ ? RecursiveExtras
232
289
  : T extends "principal"
233
- ? {
234
- maxLength: number
235
- minLength: number
236
- /** Detected format based on label heuristics */
237
- format: TextFormat
238
- /** Pre-computed HTML input props */
239
- inputProps: PrimitiveInputProps
240
- defaultValue: string
241
- }
290
+ ? PrincipalExtras
242
291
  : T extends "number"
243
- ? {
244
- /** Whether this is an unsigned type */
245
- unsigned: boolean
246
- /** Whether this is a floating point type */
247
- isFloat: boolean
248
- /** Bit width if applicable (8, 16, 32, 64, or undefined for unbounded) */
249
- bits?: number
250
- /** Minimum value constraint (for bounded types) */
251
- min?: string
252
- /** Maximum value constraint (for bounded types) */
253
- max?: string
254
- /** Detected format based on label heuristics */
255
- format: NumberFormat
256
- /** Pre-computed HTML input props */
257
- inputProps: PrimitiveInputProps
258
- defaultValue: string
259
- }
292
+ ? NumberExtras
260
293
  : T extends "text"
261
- ? {
262
- /** Minimum length constraint */
263
- minLength?: number
264
- /** Maximum length constraint */
265
- maxLength?: number
266
- /** Whether to render as multiline textarea */
267
- multiline?: boolean
268
- /** Detected format based on label heuristics */
269
- format: TextFormat
270
- /** Pre-computed HTML input props */
271
- inputProps: PrimitiveInputProps
272
- defaultValue: string
273
- }
294
+ ? TextExtras
274
295
  : T extends "boolean"
275
- ? {
276
- /** Pre-computed HTML input props */
277
- inputProps: PrimitiveInputProps
278
- defaultValue: boolean
279
- }
296
+ ? BooleanExtras
280
297
  : T extends "null"
281
- ? {
282
- defaultValue: null
283
- }
298
+ ? NullExtras
284
299
  : T extends "unknown"
285
- ? {
286
- defaultValue: undefined
287
- }
300
+ ? UnknownExtras
288
301
  : {}
289
302
 
290
303
  /**
291
304
  * A unified field node that contains all metadata needed for rendering.
292
305
  */
293
306
  export type FieldNode<T extends VisitorDataType = VisitorDataType> =
294
- FieldBase<T> & FieldExtras<T>
307
+ T extends any ? FieldBase<T> & FieldExtras<T> : never
295
308
 
296
309
  export type RecordField = FieldNode<"record">
297
310
  export type VariantField = FieldNode<"variant">
@@ -308,74 +321,52 @@ export type NullField = FieldNode<"null">
308
321
  export type UnknownField = FieldNode<"unknown">
309
322
 
310
323
  // ════════════════════════════════════════════════════════════════════════════
311
- // Form Metadata - TanStack Form Integration
324
+ // Form Metadata
312
325
  // ════════════════════════════════════════════════════════════════════════════
313
326
 
314
327
  /**
315
- * Form metadata for a Candid method.
316
- * Contains all information needed to create a TanStack Form instance.
328
+ * Metadata for a single method's input arguments.
329
+ * Use this to generate dynamic forms for calling canister methods.
317
330
  */
318
331
  export interface ArgumentsMeta<
319
332
  A = BaseActor,
320
333
  Name extends FunctionName<A> = FunctionName<A>,
321
334
  > {
322
- /** Whether this is a "query" or "update" function */
335
+ /** Whether this is a "query" or "update" call */
323
336
  functionType: FunctionType
324
- /** The function name */
337
+ /** The method name as defined in the Candid interface */
325
338
  functionName: Name
326
- /** Argument field definitions for rendering */
327
- fields: FieldNode[]
328
- /** Default values for all arguments (as a tuple) */
329
- defaultValues: unknown[]
330
- /** Combined Zod schema for all arguments */
339
+ /** Array of field descriptors, one per argument */
340
+ args: FieldNode[]
341
+ /** Default values suitable for form initialization */
342
+ defaults: unknown[]
343
+ /** Zod schema for validating all arguments together */
331
344
  schema: z.ZodTuple<[z.ZodTypeAny, ...z.ZodTypeAny[]]>
332
- /** Number of arguments */
345
+ /** Number of arguments (0 for no-arg methods) */
333
346
  argCount: number
334
- /** Whether the function takes no arguments */
335
- isNoArgs: boolean
336
- }
337
-
338
- /**
339
- * Options that can be spread into useForm().
340
- * Pre-configured with defaultValues and validators.
341
- */
342
- export interface FormOptions {
343
- /** Initial form values */
344
- defaultValues: unknown[]
345
- /** Validators using the Zod schema */
346
- validators: {
347
- onChange: z.ZodTypeAny
348
- onBlur: z.ZodTypeAny
349
- }
347
+ /** True if this method takes no arguments */
348
+ isEmpty: boolean
350
349
  }
351
350
 
352
351
  /**
353
- * Service-level form metadata.
354
- * Maps each method name to its FormMeta.
352
+ * Service-level metadata mapping method names to their argument metadata.
355
353
  */
356
354
  export type ArgumentsServiceMeta<A = BaseActor> = {
357
355
  [K in FunctionName<A>]: ArgumentsMeta<A, K>
358
356
  }
359
357
 
360
358
  // ════════════════════════════════════════════════════════════════════════════
361
- // Type Utilities & Guards
359
+ // Type Utilities
362
360
  // ════════════════════════════════════════════════════════════════════════════
363
361
 
364
- /** Extract a specific field type */
365
- export type FieldByType<T extends ArgumentFieldType> = Extract<
362
+ /**
363
+ * Extract field type by VisitorDataType.
364
+ */
365
+ export type FieldByType<T extends VisitorDataType> = Extract<
366
366
  FieldNode,
367
367
  { type: T }
368
368
  >
369
369
 
370
- /**
371
- * Props type helper for field components.
372
- * Use this to type your field components for better DX.
373
- */
374
- export type FieldProps<T extends ArgumentFieldType> = {
375
- field: FieldByType<T>
376
- renderField?: (child: FieldNode) => React.ReactNode
377
- }
378
-
379
370
  /** Compound field types that contain other fields */
380
371
  export type CompoundField =
381
372
  | RecordField
@@ -385,7 +376,7 @@ export type CompoundField =
385
376
  | VectorField
386
377
  | RecursiveField
387
378
 
388
- /** Primitive field types */
379
+ /** Primitive field types with direct values */
389
380
  export type PrimitiveField =
390
381
  | PrincipalField
391
382
  | NumberField
@@ -30,27 +30,36 @@ const CYCLE_KEYS_REGEX = new RegExp(
30
30
  "i"
31
31
  )
32
32
 
33
- const EMAIL_KEYS_REGEX = /email|mail/i
34
- const PHONE_KEYS_REGEX = /phone|tel|mobile/i
35
- const URL_KEYS_REGEX = /url|link|website/i
36
- const UUID_KEYS_REGEX = /uuid|guid/i
37
- const BITCOIN_KEYS_REGEX = /bitcoin|btc/i
38
- const ETHEREUM_KEYS_REGEX = /ethereum|eth/i
39
33
  const ACCOUNT_ID_KEYS_REGEX =
40
- /account_id|account_identifier|ledger_account|block_hash|transaction_hash|tx_hash/i
41
- const PRINCIPAL_KEYS_REGEX = /canister|principal/i
34
+ /account_identifier|ledger_account|block_hash|transaction_hash|tx_hash/i
35
+
36
+ const tokenize = (label: string): Set<string> => {
37
+ const parts = label
38
+ .replace(/_/g, " ")
39
+ .replace(/([a-z])([A-Z])/g, "$1 $2")
40
+ .toLowerCase()
41
+ .split(/[\s-]+/)
42
+ return new Set(parts)
43
+ }
42
44
 
43
45
  export const checkTextFormat = (label?: string): TextFormat => {
44
46
  if (!label) return "plain"
47
+
45
48
  if (TAMESTAMP_KEYS_REGEX.test(label)) return "timestamp"
46
- if (EMAIL_KEYS_REGEX.test(label)) return "email"
47
- if (PHONE_KEYS_REGEX.test(label)) return "phone"
48
- if (URL_KEYS_REGEX.test(label)) return "url"
49
- if (UUID_KEYS_REGEX.test(label)) return "uuid"
50
- if (BITCOIN_KEYS_REGEX.test(label)) return "btc"
51
- if (ETHEREUM_KEYS_REGEX.test(label)) return "eth"
52
49
  if (ACCOUNT_ID_KEYS_REGEX.test(label)) return "account-id"
53
- if (PRINCIPAL_KEYS_REGEX.test(label)) return "principal"
50
+
51
+ const tokens = tokenize(label)
52
+
53
+ if (tokens.has("email") || tokens.has("mail")) return "email"
54
+ if (tokens.has("phone") || tokens.has("tel") || tokens.has("mobile"))
55
+ return "phone"
56
+ if (tokens.has("url") || tokens.has("link") || tokens.has("website"))
57
+ return "url"
58
+ if (tokens.has("uuid") || tokens.has("guid")) return "uuid"
59
+ if (tokens.has("btc") || tokens.has("bitcoin")) return "btc"
60
+ if (tokens.has("eth") || tokens.has("ethereum")) return "eth"
61
+ if (tokens.has("principal") || tokens.has("canister")) return "principal"
62
+
54
63
  return "plain"
55
64
  }
56
65