@ic-reactor/candid 3.0.14-beta.1 → 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.
- package/dist/metadata-display-reactor.d.ts +66 -11
- package/dist/metadata-display-reactor.d.ts.map +1 -1
- package/dist/metadata-display-reactor.js +48 -12
- package/dist/metadata-display-reactor.js.map +1 -1
- package/dist/visitor/arguments/helpers.d.ts +20 -5
- package/dist/visitor/arguments/helpers.d.ts.map +1 -1
- package/dist/visitor/arguments/helpers.js +39 -5
- package/dist/visitor/arguments/helpers.js.map +1 -1
- package/dist/visitor/arguments/index.d.ts.map +1 -1
- package/dist/visitor/arguments/index.js +28 -27
- package/dist/visitor/arguments/index.js.map +1 -1
- package/dist/visitor/arguments/types.d.ts +102 -18
- package/dist/visitor/arguments/types.d.ts.map +1 -1
- package/dist/visitor/arguments/types.js +25 -1
- package/dist/visitor/arguments/types.js.map +1 -1
- package/dist/visitor/returns/index.d.ts.map +1 -1
- package/dist/visitor/returns/index.js +24 -13
- package/dist/visitor/returns/index.js.map +1 -1
- package/dist/visitor/returns/types.d.ts +48 -10
- package/dist/visitor/returns/types.d.ts.map +1 -1
- package/package.json +2 -2
- package/src/metadata-display-reactor.ts +86 -14
- package/src/visitor/arguments/helpers.ts +48 -6
- package/src/visitor/arguments/index.test.ts +55 -55
- package/src/visitor/arguments/index.ts +36 -27
- package/src/visitor/arguments/types.ts +113 -21
- package/src/visitor/returns/index.test.ts +29 -29
- package/src/visitor/returns/index.ts +52 -21
- package/src/visitor/returns/types.ts +60 -17
|
@@ -1,16 +1,21 @@
|
|
|
1
1
|
import type { BaseActor, FunctionName, FunctionType, ActorMethodReturnType } from "@ic-reactor/core";
|
|
2
2
|
import type { VisitorDataType, TextFormat, NumberFormat } from "../types";
|
|
3
|
-
export type { TextFormat, NumberFormat };
|
|
4
|
-
|
|
3
|
+
export type { VisitorDataType, TextFormat, NumberFormat };
|
|
4
|
+
/**
|
|
5
|
+
* The display type category after transformation.
|
|
6
|
+
* Maps Candid types to JavaScript-friendly display types.
|
|
7
|
+
*/
|
|
5
8
|
export type DisplayType = "string" | "number" | "boolean" | "null" | "object" | "array" | "variant" | "result" | "nullable" | "recursive" | "blob" | "unknown";
|
|
6
9
|
/**
|
|
7
10
|
* Base properties shared by all result nodes.
|
|
8
11
|
*/
|
|
9
|
-
interface ResultNodeBase<T extends
|
|
12
|
+
interface ResultNodeBase<T extends VisitorDataType = VisitorDataType> {
|
|
10
13
|
/** The Candid type category */
|
|
11
14
|
type: T;
|
|
12
|
-
/**
|
|
15
|
+
/** Raw label from Candid definition */
|
|
13
16
|
label: string;
|
|
17
|
+
/** Human-readable formatted label for display */
|
|
18
|
+
displayLabel: string;
|
|
14
19
|
/** Original Candid type name */
|
|
15
20
|
candidType: string;
|
|
16
21
|
/** What it becomes after display transformation */
|
|
@@ -20,10 +25,14 @@ interface ResultNodeBase<T extends NodeType = NodeType> {
|
|
|
20
25
|
/** Value after display transformation (present after resolution) */
|
|
21
26
|
value?: unknown;
|
|
22
27
|
}
|
|
23
|
-
type NodeTypeExtras<T extends
|
|
28
|
+
type NodeTypeExtras<T extends VisitorDataType> = T extends "record" ? {
|
|
24
29
|
fields: Record<string, ResultNode>;
|
|
25
30
|
} : T extends "variant" ? {
|
|
26
|
-
|
|
31
|
+
/** All variant options as schema */
|
|
32
|
+
options: Record<string, ResultNode>;
|
|
33
|
+
/** The resolved selected option value */
|
|
34
|
+
selectedValue: ResultNode;
|
|
35
|
+
/** The selected option key (populated after resolution) */
|
|
27
36
|
selected?: string;
|
|
28
37
|
} : T extends "tuple" | "vector" ? {
|
|
29
38
|
items: ResultNode[];
|
|
@@ -57,14 +66,14 @@ type NodeTypeExtras<T extends NodeType> = T extends "record" ? {
|
|
|
57
66
|
* resolved children directly in their structure fields.
|
|
58
67
|
* Primitive types store the display value in `value`.
|
|
59
68
|
*/
|
|
60
|
-
export type ResultNode<T extends
|
|
69
|
+
export type ResultNode<T extends VisitorDataType = VisitorDataType> = ResultNodeBase<T> & NodeTypeExtras<T> & {
|
|
61
70
|
/** Resolve this node with a value, returning a new resolved node */
|
|
62
71
|
resolve(data: unknown): ResolvedNode<T>;
|
|
63
72
|
};
|
|
64
73
|
/**
|
|
65
74
|
* A resolved node has `raw` populated and children resolved.
|
|
66
75
|
*/
|
|
67
|
-
export type ResolvedNode<T extends
|
|
76
|
+
export type ResolvedNode<T extends VisitorDataType = VisitorDataType> = ResultNode<T> & {
|
|
68
77
|
raw: unknown;
|
|
69
78
|
};
|
|
70
79
|
export type RecordNode = ResultNode<"record">;
|
|
@@ -80,23 +89,52 @@ export type TextNode = ResultNode<"text">;
|
|
|
80
89
|
export type BooleanNode = ResultNode<"boolean">;
|
|
81
90
|
export type NullNode = ResultNode<"null">;
|
|
82
91
|
export type UnknownNode = ResultNode<"unknown">;
|
|
92
|
+
/**
|
|
93
|
+
* Metadata for a single method's return values.
|
|
94
|
+
* Use this to render method results.
|
|
95
|
+
*/
|
|
83
96
|
export interface MethodMeta<A = BaseActor, Name extends FunctionName<A> = FunctionName<A>> {
|
|
97
|
+
/** Whether this is a "query" or "update" call */
|
|
84
98
|
functionType: FunctionType;
|
|
99
|
+
/** The method name as defined in the Candid interface */
|
|
85
100
|
functionName: Name;
|
|
101
|
+
/** Array of result node descriptors, one per return value */
|
|
86
102
|
returns: ResultNode[];
|
|
103
|
+
/** Number of return values */
|
|
87
104
|
returnCount: number;
|
|
88
105
|
/**
|
|
89
106
|
* Resolve the method result schema with actual return data.
|
|
107
|
+
* @param data The raw return data from the canister
|
|
108
|
+
* @returns A resolved result with display-friendly values
|
|
90
109
|
*/
|
|
91
|
-
resolve(data: ActorMethodReturnType<A[Name]>):
|
|
110
|
+
resolve(data: ActorMethodReturnType<A[Name]>): MethodResult<A>;
|
|
92
111
|
}
|
|
93
|
-
|
|
112
|
+
/**
|
|
113
|
+
* A resolved method result with display-friendly values.
|
|
114
|
+
*/
|
|
115
|
+
export interface MethodResult<A = BaseActor> {
|
|
116
|
+
/** Whether this is a "query" or "update" call */
|
|
94
117
|
functionType: FunctionType;
|
|
118
|
+
/** The method name */
|
|
95
119
|
functionName: FunctionName<A>;
|
|
120
|
+
/** Resolved return values */
|
|
96
121
|
results: ResolvedNode[];
|
|
122
|
+
/** Original raw data from the canister */
|
|
97
123
|
raw: ActorMethodReturnType<A[FunctionName<A>]>;
|
|
98
124
|
}
|
|
125
|
+
/**
|
|
126
|
+
* Service-level metadata mapping method names to their return metadata.
|
|
127
|
+
*/
|
|
99
128
|
export type ServiceMeta<A = BaseActor> = {
|
|
100
129
|
[K in FunctionName<A>]: MethodMeta<A, K>;
|
|
101
130
|
};
|
|
131
|
+
/**
|
|
132
|
+
* Props type for result display components.
|
|
133
|
+
*/
|
|
134
|
+
export type ResultDisplayProps<T extends VisitorDataType = VisitorDataType> = {
|
|
135
|
+
/** The resolved result node */
|
|
136
|
+
node: ResolvedNode<T>;
|
|
137
|
+
/** Nesting depth for indentation */
|
|
138
|
+
depth?: number;
|
|
139
|
+
};
|
|
102
140
|
//# sourceMappingURL=types.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/visitor/returns/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,SAAS,EACT,YAAY,EACZ,YAAY,EACZ,qBAAqB,EACtB,MAAM,kBAAkB,CAAA;AACzB,OAAO,KAAK,EAAE,eAAe,EAAE,UAAU,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AAEzE,YAAY,EAAE,UAAU,EAAE,YAAY,EAAE,CAAA;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../src/visitor/returns/types.ts"],"names":[],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ic-reactor/candid",
|
|
3
|
-
"version": "3.0.14-beta.
|
|
3
|
+
"version": "3.0.14-beta.2",
|
|
4
4
|
"description": "IC Reactor Candid Adapter - Fetch and parse Candid definitions from Internet Computer canisters",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.js",
|
|
@@ -44,7 +44,7 @@
|
|
|
44
44
|
"dependencies": {
|
|
45
45
|
"@noble/hashes": "^2.0.1",
|
|
46
46
|
"zod": "^4.3.5",
|
|
47
|
-
"@ic-reactor/core": "^3.0.14-beta.
|
|
47
|
+
"@ic-reactor/core": "^3.0.14-beta.2"
|
|
48
48
|
},
|
|
49
49
|
"peerDependencies": {
|
|
50
50
|
"zod": "^4.3.5",
|
|
@@ -12,10 +12,11 @@ import {
|
|
|
12
12
|
FieldVisitor,
|
|
13
13
|
ArgumentsMeta,
|
|
14
14
|
ArgumentsServiceMeta,
|
|
15
|
+
MetadataError,
|
|
15
16
|
} from "./visitor/arguments"
|
|
16
17
|
import {
|
|
17
18
|
MethodMeta,
|
|
18
|
-
|
|
19
|
+
MethodResult,
|
|
19
20
|
ResultFieldVisitor,
|
|
20
21
|
ServiceMeta,
|
|
21
22
|
} from "./visitor/returns"
|
|
@@ -33,13 +34,39 @@ import {
|
|
|
33
34
|
* It extends the base Reactor and adds metadata generation capabilities.
|
|
34
35
|
* Unlike DisplayReactor, it does not use a separate codec for transformation.
|
|
35
36
|
* Instead, it uses the metadata visitor to resolve raw values into display-ready structures.
|
|
37
|
+
*
|
|
38
|
+
* ## Usage
|
|
39
|
+
*
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const reactor = new MetadataDisplayReactor({
|
|
42
|
+
* canisterId: "ryjl3-tyaaa-aaaaa-aaaba-cai",
|
|
43
|
+
* clientManager,
|
|
44
|
+
* name: "ICPLedger",
|
|
45
|
+
* })
|
|
46
|
+
*
|
|
47
|
+
* await reactor.initialize()
|
|
48
|
+
*
|
|
49
|
+
* // Get form metadata
|
|
50
|
+
* const argMeta = reactor.getInputMeta("icrc1_transfer")
|
|
51
|
+
* console.log(argMeta.args) // Field descriptors
|
|
52
|
+
* console.log(argMeta.defaults) // Default values
|
|
53
|
+
*
|
|
54
|
+
* // Get result metadata
|
|
55
|
+
* const resultMeta = reactor.getOutputMeta("icrc1_transfer")
|
|
56
|
+
*
|
|
57
|
+
* // Call with display types
|
|
58
|
+
* const result = await reactor.callMethod({
|
|
59
|
+
* functionName: "icrc1_transfer",
|
|
60
|
+
* args: [{ to: { owner: "aaaaa-aa" }, amount: "1000000" }]
|
|
61
|
+
* })
|
|
62
|
+
* ```
|
|
36
63
|
*/
|
|
37
64
|
declare module "@ic-reactor/core" {
|
|
38
65
|
interface TransformArgsRegistry<T> {
|
|
39
66
|
metadata: TransformArgsRegistry<T>["display"]
|
|
40
67
|
}
|
|
41
68
|
interface TransformReturnRegistry<T, A = BaseActor> {
|
|
42
|
-
metadata:
|
|
69
|
+
metadata: MethodResult<A>
|
|
43
70
|
}
|
|
44
71
|
}
|
|
45
72
|
|
|
@@ -98,37 +125,44 @@ export class MetadataDisplayReactor<A = BaseActor> extends CandidDisplayReactor<
|
|
|
98
125
|
// ══════════════════════════════════════════════════════════════════════════
|
|
99
126
|
// METADATA ACCESS
|
|
100
127
|
// ══════════════════════════════════════════════════════════════════════════
|
|
128
|
+
|
|
101
129
|
/**
|
|
102
|
-
* Get
|
|
130
|
+
* Get input field metadata for a method.
|
|
103
131
|
* Use this to generate input forms.
|
|
132
|
+
*
|
|
133
|
+
* @param methodName The method name to get metadata for
|
|
134
|
+
* @returns ArgumentsMeta containing args, defaults, and validation schema
|
|
104
135
|
*/
|
|
105
|
-
public
|
|
136
|
+
public getInputMeta<M extends FunctionName<A>>(
|
|
106
137
|
methodName: M
|
|
107
138
|
): ArgumentsMeta<A, M> | undefined {
|
|
108
139
|
return this.argumentMeta?.[methodName]
|
|
109
140
|
}
|
|
110
141
|
|
|
111
142
|
/**
|
|
112
|
-
* Get
|
|
143
|
+
* Get output field metadata for a method.
|
|
113
144
|
* Use this to render results.
|
|
145
|
+
*
|
|
146
|
+
* @param methodName The method name to get metadata for
|
|
147
|
+
* @returns MethodMeta containing return schema and resolve function
|
|
114
148
|
*/
|
|
115
|
-
public
|
|
149
|
+
public getOutputMeta<M extends FunctionName<A>>(
|
|
116
150
|
methodName: M
|
|
117
151
|
): MethodMeta<A, M> | undefined {
|
|
118
152
|
return this.resultMeta?.[methodName]
|
|
119
153
|
}
|
|
120
154
|
|
|
121
155
|
/**
|
|
122
|
-
* Get all
|
|
156
|
+
* Get all input metadata for all methods.
|
|
123
157
|
*/
|
|
124
|
-
public
|
|
158
|
+
public getAllInputMeta(): ArgumentsServiceMeta<A> | null {
|
|
125
159
|
return this.argumentMeta
|
|
126
160
|
}
|
|
127
161
|
|
|
128
162
|
/**
|
|
129
|
-
* Get all
|
|
163
|
+
* Get all output metadata for all methods.
|
|
130
164
|
*/
|
|
131
|
-
public
|
|
165
|
+
public getAllOutputMeta(): ServiceMeta<A> | null {
|
|
132
166
|
return this.resultMeta
|
|
133
167
|
}
|
|
134
168
|
|
|
@@ -154,11 +188,15 @@ export class MetadataDisplayReactor<A = BaseActor> extends CandidDisplayReactor<
|
|
|
154
188
|
protected override transformResult<M extends FunctionName<A>>(
|
|
155
189
|
methodName: M,
|
|
156
190
|
result: ActorMethodReturnType<A[M]>
|
|
157
|
-
):
|
|
191
|
+
): MethodResult<A> {
|
|
158
192
|
// Get metadata and generate resolved result
|
|
159
|
-
const meta = this.
|
|
193
|
+
const meta = this.getOutputMeta(methodName)
|
|
160
194
|
if (!meta) {
|
|
161
|
-
throw new
|
|
195
|
+
throw new MetadataError(
|
|
196
|
+
`No output metadata found for method`,
|
|
197
|
+
String(methodName),
|
|
198
|
+
"method"
|
|
199
|
+
)
|
|
162
200
|
}
|
|
163
201
|
|
|
164
202
|
return meta.resolve(result)
|
|
@@ -166,6 +204,9 @@ export class MetadataDisplayReactor<A = BaseActor> extends CandidDisplayReactor<
|
|
|
166
204
|
|
|
167
205
|
/**
|
|
168
206
|
* Perform a dynamic call and return result with metadata.
|
|
207
|
+
*
|
|
208
|
+
* @param options Method registration and call options
|
|
209
|
+
* @returns Object containing the result and metadata
|
|
169
210
|
*/
|
|
170
211
|
public async callDynamicWithMeta<T = unknown>(
|
|
171
212
|
options: DynamicMethodOptions & { args?: unknown[] }
|
|
@@ -177,8 +218,39 @@ export class MetadataDisplayReactor<A = BaseActor> extends CandidDisplayReactor<
|
|
|
177
218
|
args: options.args as any,
|
|
178
219
|
})) as T
|
|
179
220
|
|
|
180
|
-
const meta = this.
|
|
221
|
+
const meta = this.getOutputMeta(options.functionName as any)!
|
|
181
222
|
|
|
182
223
|
return { result, meta }
|
|
183
224
|
}
|
|
184
225
|
}
|
|
226
|
+
|
|
227
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
228
|
+
// Factory Function
|
|
229
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Create and initialize a MetadataDisplayReactor.
|
|
233
|
+
* This is a convenience function that creates the reactor and calls initialize().
|
|
234
|
+
*
|
|
235
|
+
* @param options Reactor configuration options
|
|
236
|
+
* @returns Initialized MetadataDisplayReactor
|
|
237
|
+
*
|
|
238
|
+
* @example
|
|
239
|
+
* ```typescript
|
|
240
|
+
* const reactor = await createMetadataReactor({
|
|
241
|
+
* canisterId: "ryjl3-tyaaa-aaaaa-aaaba-cai",
|
|
242
|
+
* clientManager,
|
|
243
|
+
* name: "ICPLedger",
|
|
244
|
+
* })
|
|
245
|
+
*
|
|
246
|
+
* // Reactor is ready to use
|
|
247
|
+
* const methods = reactor.getMethodNames()
|
|
248
|
+
* ```
|
|
249
|
+
*/
|
|
250
|
+
export async function createMetadataReactor<A = BaseActor>(
|
|
251
|
+
options: CandidDisplayReactorParameters<A>
|
|
252
|
+
): Promise<MetadataDisplayReactor<A>> {
|
|
253
|
+
const reactor = new MetadataDisplayReactor<A>(options)
|
|
254
|
+
await reactor.initialize()
|
|
255
|
+
return reactor
|
|
256
|
+
}
|
|
@@ -9,12 +9,16 @@ import {
|
|
|
9
9
|
VariantField,
|
|
10
10
|
} from "./types"
|
|
11
11
|
|
|
12
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
13
|
+
// Type Guards
|
|
14
|
+
// ════════════════════════════════════════════════════════════════════════════
|
|
15
|
+
|
|
12
16
|
/**
|
|
13
17
|
* Type guard for checking specific field types.
|
|
14
18
|
*
|
|
15
19
|
* @example
|
|
16
20
|
* ```tsx
|
|
17
|
-
* function FieldInput({ field }: { field:
|
|
21
|
+
* function FieldInput({ field }: { field: FieldNode }) {
|
|
18
22
|
* if (isFieldType(field, 'record')) {
|
|
19
23
|
* // field is now typed as RecordField
|
|
20
24
|
* return <RecordInput field={field} />
|
|
@@ -34,7 +38,10 @@ export function isFieldType<T extends VisitorDataType>(
|
|
|
34
38
|
return field.type === type
|
|
35
39
|
}
|
|
36
40
|
|
|
37
|
-
/**
|
|
41
|
+
/**
|
|
42
|
+
* Check if a field is a compound type (contains other fields).
|
|
43
|
+
* Compound types: record, variant, tuple, optional, vector, recursive
|
|
44
|
+
*/
|
|
38
45
|
export function isCompoundField(field: FieldNode): field is CompoundField {
|
|
39
46
|
return [
|
|
40
47
|
"record",
|
|
@@ -46,16 +53,38 @@ export function isCompoundField(field: FieldNode): field is CompoundField {
|
|
|
46
53
|
].includes(field.type)
|
|
47
54
|
}
|
|
48
55
|
|
|
49
|
-
/**
|
|
56
|
+
/**
|
|
57
|
+
* Check if a field is a primitive type.
|
|
58
|
+
* Primitive types: principal, number, text, boolean, null
|
|
59
|
+
*/
|
|
50
60
|
export function isPrimitiveField(field: FieldNode): field is PrimitiveField {
|
|
51
61
|
return ["principal", "number", "text", "boolean", "null"].includes(field.type)
|
|
52
62
|
}
|
|
53
63
|
|
|
54
|
-
/**
|
|
64
|
+
/**
|
|
65
|
+
* Check if a field has child fields array (for iteration).
|
|
66
|
+
* Applies to: record (fields), tuple (fields)
|
|
67
|
+
*/
|
|
55
68
|
export function hasChildFields(
|
|
56
69
|
field: FieldNode
|
|
57
|
-
): field is RecordField |
|
|
58
|
-
return
|
|
70
|
+
): field is RecordField | TupleField {
|
|
71
|
+
return (
|
|
72
|
+
(field.type === "record" || field.type === "tuple") &&
|
|
73
|
+
"fields" in field &&
|
|
74
|
+
Array.isArray((field as RecordField).fields)
|
|
75
|
+
)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/**
|
|
79
|
+
* Check if a field has variant options (for iteration).
|
|
80
|
+
* Applies to: variant (options)
|
|
81
|
+
*/
|
|
82
|
+
export function hasOptions(field: FieldNode): field is VariantField {
|
|
83
|
+
return (
|
|
84
|
+
field.type === "variant" &&
|
|
85
|
+
"options" in field &&
|
|
86
|
+
Array.isArray((field as VariantField).options)
|
|
87
|
+
)
|
|
59
88
|
}
|
|
60
89
|
|
|
61
90
|
// ════════════════════════════════════════════════════════════════════════════
|
|
@@ -72,6 +101,7 @@ export function hasChildFields(
|
|
|
72
101
|
* formatLabel("_0_") // "Item 0"
|
|
73
102
|
* formatLabel("created_at") // "Created At"
|
|
74
103
|
* formatLabel("userAddress") // "User Address"
|
|
104
|
+
* formatLabel("__ret0") // "Result 0"
|
|
75
105
|
* ```
|
|
76
106
|
*/
|
|
77
107
|
export function formatLabel(label: string): string {
|
|
@@ -81,12 +111,24 @@ export function formatLabel(label: string): string {
|
|
|
81
111
|
return `Arg ${num}`
|
|
82
112
|
}
|
|
83
113
|
|
|
114
|
+
// Handle return labels: __ret0 -> Result 0
|
|
115
|
+
if (label.startsWith("__ret")) {
|
|
116
|
+
const num = label.slice(5)
|
|
117
|
+
return `Result ${num}`
|
|
118
|
+
}
|
|
119
|
+
|
|
84
120
|
// Handle tuple index labels: _0_ -> Item 0
|
|
85
121
|
if (/^_\d+_$/.test(label)) {
|
|
86
122
|
const num = label.slice(1, -1)
|
|
87
123
|
return `Item ${num}`
|
|
88
124
|
}
|
|
89
125
|
|
|
126
|
+
// Handle simple index labels: _0 -> Item 0
|
|
127
|
+
if (/^_\d+$/.test(label)) {
|
|
128
|
+
const num = label.slice(1)
|
|
129
|
+
return `Item ${num}`
|
|
130
|
+
}
|
|
131
|
+
|
|
90
132
|
// Handle item labels for vectors: label_item -> Item
|
|
91
133
|
if (label.endsWith("_item")) {
|
|
92
134
|
return "Item"
|