@elizaos/plugin-form 2.0.0-alpha.10 → 2.0.0-alpha.11
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/chunk-4B5QLNVA.js +187 -0
- package/dist/chunk-ARWZY3NX.js +284 -0
- package/dist/chunk-R4VBS2YK.js +1597 -0
- package/dist/chunk-TBCL2ILB.js +172 -0
- package/dist/chunk-WY4WK3HD.js +57 -0
- package/dist/chunk-XHECCAUT.js +544 -0
- package/dist/chunk-YTWANJ3R.js +64 -0
- package/dist/context-MHPFYZZ2.js +9 -0
- package/dist/extractor-UWASKXKD.js +11 -0
- package/dist/index.d.ts +3213 -2
- package/dist/index.js +428 -2829
- package/dist/restore-S7JLME4H.js +9 -0
- package/dist/service-TCCXKV3T.js +7 -0
- package/package.json +13 -11
- package/dist/index.js.map +0 -30
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import {
|
|
2
|
+
buildTemplateValues,
|
|
3
|
+
renderTemplate,
|
|
4
|
+
resolveControlTemplates
|
|
5
|
+
} from "./chunk-WY4WK3HD.js";
|
|
6
|
+
|
|
7
|
+
// src/providers/context.ts
|
|
8
|
+
import { logger } from "@elizaos/core";
|
|
9
|
+
var formContextProvider = {
|
|
10
|
+
name: "FORM_CONTEXT",
|
|
11
|
+
description: "Provides context about active form sessions",
|
|
12
|
+
/**
|
|
13
|
+
* Get form context for the current message.
|
|
14
|
+
*
|
|
15
|
+
* @param runtime - Agent runtime for service access
|
|
16
|
+
* @param message - The user message being processed
|
|
17
|
+
* @param _state - Current agent state (unused)
|
|
18
|
+
* @returns Provider result with form context (data, values, text)
|
|
19
|
+
*/
|
|
20
|
+
get: async (runtime, message, _state) => {
|
|
21
|
+
try {
|
|
22
|
+
const formService = runtime.getService("FORM");
|
|
23
|
+
if (!formService) {
|
|
24
|
+
return { data: { hasActiveForm: false }, values: { formContext: "" }, text: "" };
|
|
25
|
+
}
|
|
26
|
+
const entityId = message.entityId;
|
|
27
|
+
const roomId = message.roomId;
|
|
28
|
+
if (!entityId || !roomId) {
|
|
29
|
+
return { data: { hasActiveForm: false }, values: { formContext: "" }, text: "" };
|
|
30
|
+
}
|
|
31
|
+
const session = await formService.getActiveSession(entityId, roomId);
|
|
32
|
+
const stashed = await formService.getStashedSessions(entityId);
|
|
33
|
+
if (!session && stashed.length === 0) {
|
|
34
|
+
return {
|
|
35
|
+
data: { hasActiveForm: false, stashedCount: 0 },
|
|
36
|
+
values: { formContext: "" },
|
|
37
|
+
text: ""
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
let contextText = "";
|
|
41
|
+
let contextState;
|
|
42
|
+
if (session) {
|
|
43
|
+
contextState = formService.getSessionContext(session);
|
|
44
|
+
const form = formService.getForm(session.formId);
|
|
45
|
+
const templateValues = buildTemplateValues(session);
|
|
46
|
+
const resolve = (v) => renderTemplate(v, templateValues);
|
|
47
|
+
contextState = {
|
|
48
|
+
...contextState,
|
|
49
|
+
filledFields: contextState.filledFields.map((f) => ({
|
|
50
|
+
...f,
|
|
51
|
+
label: resolve(f.label) ?? f.label
|
|
52
|
+
})),
|
|
53
|
+
missingRequired: contextState.missingRequired.map((f) => ({
|
|
54
|
+
...f,
|
|
55
|
+
label: resolve(f.label) ?? f.label,
|
|
56
|
+
description: resolve(f.description),
|
|
57
|
+
askPrompt: resolve(f.askPrompt)
|
|
58
|
+
})),
|
|
59
|
+
uncertainFields: contextState.uncertainFields.map((f) => ({
|
|
60
|
+
...f,
|
|
61
|
+
label: resolve(f.label) ?? f.label
|
|
62
|
+
})),
|
|
63
|
+
nextField: contextState.nextField ? resolveControlTemplates(contextState.nextField, templateValues) : null
|
|
64
|
+
};
|
|
65
|
+
const controls = form?.controls ?? [];
|
|
66
|
+
const filledKeys = new Set(contextState.filledFields.map((f) => f.key));
|
|
67
|
+
const controlByKey = new Map(controls.map((c) => [c.key, c]));
|
|
68
|
+
const requiredFilled = contextState.filledFields.filter(
|
|
69
|
+
(f) => controlByKey.get(f.key)?.required
|
|
70
|
+
);
|
|
71
|
+
const optionalFilled = contextState.filledFields.filter(
|
|
72
|
+
(f) => !controlByKey.get(f.key)?.required
|
|
73
|
+
);
|
|
74
|
+
const optionalMissing = controls.filter(
|
|
75
|
+
(c) => !c.hidden && !c.required && !filledKeys.has(c.key)
|
|
76
|
+
);
|
|
77
|
+
const fmt = (items) => items.length === 0 ? "none" : items.map((i) => i.displayValue ? `${i.key} (${i.displayValue})` : i.key).join(", ");
|
|
78
|
+
contextText = `# Active Form: ${form?.name || session.formId}
|
|
79
|
+
`;
|
|
80
|
+
contextText += `Progress: ${contextState.progress}%
|
|
81
|
+
|
|
82
|
+
`;
|
|
83
|
+
contextText += `Required fields we don't have: ${fmt(contextState.missingRequired)}
|
|
84
|
+
`;
|
|
85
|
+
contextText += `Required fields we do have: ${fmt(requiredFilled)}
|
|
86
|
+
|
|
87
|
+
`;
|
|
88
|
+
contextText += `Optional fields we don't have: ${fmt(optionalMissing)}
|
|
89
|
+
`;
|
|
90
|
+
contextText += `Optional fields we do have: ${fmt(optionalFilled)}
|
|
91
|
+
|
|
92
|
+
`;
|
|
93
|
+
if (contextState.uncertainFields.length > 0) {
|
|
94
|
+
contextText += `Needs confirmation:
|
|
95
|
+
`;
|
|
96
|
+
for (const f of contextState.uncertainFields) {
|
|
97
|
+
contextText += `- ${f.label}: "${f.value}" (${Math.round(f.confidence * 100)}% confident)
|
|
98
|
+
`;
|
|
99
|
+
}
|
|
100
|
+
contextText += "\n";
|
|
101
|
+
}
|
|
102
|
+
if (contextState.pendingExternalFields.length > 0) {
|
|
103
|
+
contextText += `Waiting for external action:
|
|
104
|
+
`;
|
|
105
|
+
for (const f of contextState.pendingExternalFields) {
|
|
106
|
+
const mins = Math.floor((Date.now() - f.activatedAt) / 6e4);
|
|
107
|
+
contextText += `- ${f.label}: ${f.instructions} (${mins < 1 ? "just now" : `${mins}m ago`})`;
|
|
108
|
+
if (f.address) contextText += ` Address: ${f.address}`;
|
|
109
|
+
contextText += "\n";
|
|
110
|
+
}
|
|
111
|
+
contextText += "\n";
|
|
112
|
+
}
|
|
113
|
+
if (contextState.pendingExternalFields.length > 0) {
|
|
114
|
+
const p = contextState.pendingExternalFields[0];
|
|
115
|
+
contextText += `Instruction: Waiting for external action. Remind user: "${p.instructions}"
|
|
116
|
+
`;
|
|
117
|
+
} else if (contextState.pendingCancelConfirmation) {
|
|
118
|
+
contextText += `Instruction: User is trying to cancel. Confirm they really want to lose progress.
|
|
119
|
+
`;
|
|
120
|
+
} else if (contextState.uncertainFields.length > 0) {
|
|
121
|
+
const u = contextState.uncertainFields[0];
|
|
122
|
+
contextText += `Instruction: Ask user to confirm "${u.label}" = "${u.value}".
|
|
123
|
+
`;
|
|
124
|
+
} else if (contextState.missingRequired.length > 0) {
|
|
125
|
+
contextText += `Instruction: Please nudge the user into helping complete required fields. The user can provide one or several answers in a single message; the form accepts them all.
|
|
126
|
+
`;
|
|
127
|
+
} else if (contextState.status === "ready") {
|
|
128
|
+
contextText += `Instruction: All required fields collected. Nudge user to submit.
|
|
129
|
+
`;
|
|
130
|
+
} else if (optionalMissing.length > 0) {
|
|
131
|
+
contextText += `Instruction: Required fields are done. Optionally nudge for remaining optional fields, or nudge to submit.
|
|
132
|
+
`;
|
|
133
|
+
}
|
|
134
|
+
} else {
|
|
135
|
+
contextState = {
|
|
136
|
+
hasActiveForm: false,
|
|
137
|
+
progress: 0,
|
|
138
|
+
filledFields: [],
|
|
139
|
+
missingRequired: [],
|
|
140
|
+
uncertainFields: [],
|
|
141
|
+
nextField: null,
|
|
142
|
+
stashedCount: stashed.length,
|
|
143
|
+
pendingExternalFields: []
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
if (stashed.length > 0) {
|
|
147
|
+
contextText += `
|
|
148
|
+
Saved forms: User has ${stashed.length} saved form(s). They can say "resume" to restore one.
|
|
149
|
+
`;
|
|
150
|
+
for (const s of stashed) {
|
|
151
|
+
const f = formService.getForm(s.formId);
|
|
152
|
+
const ctx = formService.getSessionContext(s);
|
|
153
|
+
contextText += `- ${f?.name || s.formId} (${ctx.progress}% complete)
|
|
154
|
+
`;
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
return {
|
|
158
|
+
// Full context object for programmatic access
|
|
159
|
+
// WHY: Restore action and others read data.nextField, data.filledFields, etc.
|
|
160
|
+
data: JSON.parse(JSON.stringify(contextState)),
|
|
161
|
+
// String values for template substitution (e.g. in prompts: formContext, formProgress, formStatus)
|
|
162
|
+
values: {
|
|
163
|
+
formContext: contextText,
|
|
164
|
+
hasActiveForm: String(contextState.hasActiveForm),
|
|
165
|
+
formProgress: String(contextState.progress),
|
|
166
|
+
formStatus: contextState.status || "",
|
|
167
|
+
stashedCount: String(stashed.length)
|
|
168
|
+
},
|
|
169
|
+
// Human-readable text for agent (injected into prompt)
|
|
170
|
+
text: contextText
|
|
171
|
+
};
|
|
172
|
+
} catch (error) {
|
|
173
|
+
logger.error("[FormContextProvider] Error:", String(error));
|
|
174
|
+
return {
|
|
175
|
+
data: { hasActiveForm: false, error: true },
|
|
176
|
+
values: { formContext: "Error loading form context." },
|
|
177
|
+
text: "Error loading form context."
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
};
|
|
182
|
+
var context_default = formContextProvider;
|
|
183
|
+
|
|
184
|
+
export {
|
|
185
|
+
formContextProvider,
|
|
186
|
+
context_default
|
|
187
|
+
};
|
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
// src/validation.ts
|
|
2
|
+
var typeHandlers = /* @__PURE__ */ new Map();
|
|
3
|
+
function registerTypeHandler(type, handler) {
|
|
4
|
+
typeHandlers.set(type, handler);
|
|
5
|
+
}
|
|
6
|
+
function getTypeHandler(type) {
|
|
7
|
+
return typeHandlers.get(type);
|
|
8
|
+
}
|
|
9
|
+
function clearTypeHandlers() {
|
|
10
|
+
typeHandlers.clear();
|
|
11
|
+
}
|
|
12
|
+
function validateField(value, control) {
|
|
13
|
+
if (control.required) {
|
|
14
|
+
if (value === void 0 || value === null || value === "") {
|
|
15
|
+
return {
|
|
16
|
+
valid: false,
|
|
17
|
+
error: `${control.label || control.key} is required`
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
if (value === void 0 || value === null || value === "") {
|
|
22
|
+
return { valid: true };
|
|
23
|
+
}
|
|
24
|
+
const handler = typeHandlers.get(control.type);
|
|
25
|
+
if (handler?.validate) {
|
|
26
|
+
const result = handler.validate(value, control);
|
|
27
|
+
if (!result.valid) {
|
|
28
|
+
return result;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
switch (control.type) {
|
|
32
|
+
case "email":
|
|
33
|
+
return validateEmail(value, control);
|
|
34
|
+
case "number":
|
|
35
|
+
return validateNumber(value, control);
|
|
36
|
+
case "boolean":
|
|
37
|
+
return validateBoolean(value, control);
|
|
38
|
+
case "date":
|
|
39
|
+
return validateDate(value, control);
|
|
40
|
+
case "select":
|
|
41
|
+
return validateSelect(value, control);
|
|
42
|
+
case "file":
|
|
43
|
+
return validateFile(value, control);
|
|
44
|
+
default:
|
|
45
|
+
return validateText(value, control);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
function validateText(value, control) {
|
|
49
|
+
const strValue = String(value);
|
|
50
|
+
if (control.pattern) {
|
|
51
|
+
const regex = new RegExp(control.pattern);
|
|
52
|
+
if (!regex.test(strValue)) {
|
|
53
|
+
return {
|
|
54
|
+
valid: false,
|
|
55
|
+
error: `${control.label || control.key} has invalid format`
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (control.minLength !== void 0 && strValue.length < control.minLength) {
|
|
60
|
+
return {
|
|
61
|
+
valid: false,
|
|
62
|
+
error: `${control.label || control.key} must be at least ${control.minLength} characters`
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
if (control.maxLength !== void 0 && strValue.length > control.maxLength) {
|
|
66
|
+
return {
|
|
67
|
+
valid: false,
|
|
68
|
+
error: `${control.label || control.key} must be at most ${control.maxLength} characters`
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
if (control.enum && control.enum.length > 0) {
|
|
72
|
+
if (!control.enum.includes(strValue)) {
|
|
73
|
+
return {
|
|
74
|
+
valid: false,
|
|
75
|
+
error: `${control.label || control.key} must be one of: ${control.enum.join(", ")}`
|
|
76
|
+
};
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
return { valid: true };
|
|
80
|
+
}
|
|
81
|
+
function validateEmail(value, control) {
|
|
82
|
+
const strValue = String(value);
|
|
83
|
+
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
|
84
|
+
if (!emailRegex.test(strValue)) {
|
|
85
|
+
return {
|
|
86
|
+
valid: false,
|
|
87
|
+
error: `${control.label || control.key} must be a valid email address`
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
return validateText(value, control);
|
|
91
|
+
}
|
|
92
|
+
function validateNumber(value, control) {
|
|
93
|
+
const numValue = typeof value === "number" ? value : parseFloat(String(value).replace(/[,$]/g, ""));
|
|
94
|
+
if (Number.isNaN(numValue)) {
|
|
95
|
+
return {
|
|
96
|
+
valid: false,
|
|
97
|
+
error: `${control.label || control.key} must be a number`
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
if (control.min !== void 0 && numValue < control.min) {
|
|
101
|
+
return {
|
|
102
|
+
valid: false,
|
|
103
|
+
error: `${control.label || control.key} must be at least ${control.min}`
|
|
104
|
+
};
|
|
105
|
+
}
|
|
106
|
+
if (control.max !== void 0 && numValue > control.max) {
|
|
107
|
+
return {
|
|
108
|
+
valid: false,
|
|
109
|
+
error: `${control.label || control.key} must be at most ${control.max}`
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
return { valid: true };
|
|
113
|
+
}
|
|
114
|
+
function validateBoolean(value, _control) {
|
|
115
|
+
if (typeof value === "boolean") {
|
|
116
|
+
return { valid: true };
|
|
117
|
+
}
|
|
118
|
+
const strValue = String(value).toLowerCase();
|
|
119
|
+
const truthy = ["true", "yes", "1", "on"];
|
|
120
|
+
const falsy = ["false", "no", "0", "off"];
|
|
121
|
+
if (truthy.includes(strValue) || falsy.includes(strValue)) {
|
|
122
|
+
return { valid: true };
|
|
123
|
+
}
|
|
124
|
+
return { valid: false, error: "Must be true or false" };
|
|
125
|
+
}
|
|
126
|
+
function validateDate(value, control) {
|
|
127
|
+
let dateValue;
|
|
128
|
+
if (value instanceof Date) {
|
|
129
|
+
dateValue = value;
|
|
130
|
+
} else if (typeof value === "string" || typeof value === "number") {
|
|
131
|
+
dateValue = new Date(value);
|
|
132
|
+
} else {
|
|
133
|
+
return {
|
|
134
|
+
valid: false,
|
|
135
|
+
error: `${control.label || control.key} must be a valid date`
|
|
136
|
+
};
|
|
137
|
+
}
|
|
138
|
+
if (Number.isNaN(dateValue.getTime())) {
|
|
139
|
+
return {
|
|
140
|
+
valid: false,
|
|
141
|
+
error: `${control.label || control.key} must be a valid date`
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
if (control.min !== void 0 && dateValue.getTime() < control.min) {
|
|
145
|
+
return {
|
|
146
|
+
valid: false,
|
|
147
|
+
error: `${control.label || control.key} is too early`
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
if (control.max !== void 0 && dateValue.getTime() > control.max) {
|
|
151
|
+
return {
|
|
152
|
+
valid: false,
|
|
153
|
+
error: `${control.label || control.key} is too late`
|
|
154
|
+
};
|
|
155
|
+
}
|
|
156
|
+
return { valid: true };
|
|
157
|
+
}
|
|
158
|
+
function validateSelect(value, control) {
|
|
159
|
+
if (!control.options || control.options.length === 0) {
|
|
160
|
+
return { valid: true };
|
|
161
|
+
}
|
|
162
|
+
const strValue = String(value);
|
|
163
|
+
const validValues = control.options.map((opt) => opt.value);
|
|
164
|
+
if (!validValues.includes(strValue)) {
|
|
165
|
+
return {
|
|
166
|
+
valid: false,
|
|
167
|
+
error: `${control.label || control.key} must be one of the available options`
|
|
168
|
+
};
|
|
169
|
+
}
|
|
170
|
+
return { valid: true };
|
|
171
|
+
}
|
|
172
|
+
function validateFile(value, control) {
|
|
173
|
+
if (!control.file) {
|
|
174
|
+
return { valid: true };
|
|
175
|
+
}
|
|
176
|
+
const files = Array.isArray(value) ? value : [value];
|
|
177
|
+
if (control.file.maxFiles && files.length > control.file.maxFiles) {
|
|
178
|
+
return {
|
|
179
|
+
valid: false,
|
|
180
|
+
error: `Maximum ${control.file.maxFiles} files allowed`
|
|
181
|
+
};
|
|
182
|
+
}
|
|
183
|
+
for (const file of files) {
|
|
184
|
+
if (!file || typeof file !== "object") continue;
|
|
185
|
+
const fileObj = file;
|
|
186
|
+
if (control.file.maxSize && fileObj.size && fileObj.size > control.file.maxSize) {
|
|
187
|
+
return {
|
|
188
|
+
valid: false,
|
|
189
|
+
error: `File size exceeds maximum of ${formatBytes(control.file.maxSize)}`
|
|
190
|
+
};
|
|
191
|
+
}
|
|
192
|
+
if (control.file.accept && fileObj.mimeType) {
|
|
193
|
+
const accepted = control.file.accept.some(
|
|
194
|
+
(pattern) => matchesMimeType(fileObj.mimeType, pattern)
|
|
195
|
+
);
|
|
196
|
+
if (!accepted) {
|
|
197
|
+
return {
|
|
198
|
+
valid: false,
|
|
199
|
+
error: `File type ${fileObj.mimeType} is not accepted`
|
|
200
|
+
};
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
return { valid: true };
|
|
205
|
+
}
|
|
206
|
+
function matchesMimeType(mimeType, pattern) {
|
|
207
|
+
if (pattern === "*/*") return true;
|
|
208
|
+
if (pattern.endsWith("/*")) {
|
|
209
|
+
const prefix = pattern.slice(0, -1);
|
|
210
|
+
return mimeType.startsWith(prefix);
|
|
211
|
+
}
|
|
212
|
+
return mimeType === pattern;
|
|
213
|
+
}
|
|
214
|
+
function formatBytes(bytes) {
|
|
215
|
+
if (bytes < 1024) return `${bytes} B`;
|
|
216
|
+
if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
|
|
217
|
+
if (bytes < 1024 * 1024 * 1024) return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
218
|
+
return `${(bytes / (1024 * 1024 * 1024)).toFixed(1)} GB`;
|
|
219
|
+
}
|
|
220
|
+
function parseValue(value, control) {
|
|
221
|
+
const handler = typeHandlers.get(control.type);
|
|
222
|
+
if (handler?.parse) {
|
|
223
|
+
return handler.parse(value);
|
|
224
|
+
}
|
|
225
|
+
switch (control.type) {
|
|
226
|
+
case "number":
|
|
227
|
+
return parseFloat(value.replace(/[,$]/g, ""));
|
|
228
|
+
case "boolean": {
|
|
229
|
+
const lower = value.toLowerCase();
|
|
230
|
+
return ["true", "yes", "1", "on"].includes(lower);
|
|
231
|
+
}
|
|
232
|
+
case "date": {
|
|
233
|
+
const timestamp = Date.parse(value);
|
|
234
|
+
return Number.isFinite(timestamp) ? new Date(timestamp).toISOString() : value;
|
|
235
|
+
}
|
|
236
|
+
default:
|
|
237
|
+
return value;
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function formatValue(value, control) {
|
|
241
|
+
if (value === void 0 || value === null) return "";
|
|
242
|
+
const handler = typeHandlers.get(control.type);
|
|
243
|
+
if (handler?.format) {
|
|
244
|
+
return handler.format(value);
|
|
245
|
+
}
|
|
246
|
+
if (control.sensitive) {
|
|
247
|
+
const strVal = String(value);
|
|
248
|
+
if (strVal.length > 8) {
|
|
249
|
+
return `${strVal.slice(0, 4)}...${strVal.slice(-4)}`;
|
|
250
|
+
}
|
|
251
|
+
return "****";
|
|
252
|
+
}
|
|
253
|
+
switch (control.type) {
|
|
254
|
+
case "number":
|
|
255
|
+
return typeof value === "number" ? value.toLocaleString() : String(value);
|
|
256
|
+
case "boolean":
|
|
257
|
+
return value ? "Yes" : "No";
|
|
258
|
+
case "date":
|
|
259
|
+
return value instanceof Date ? value.toLocaleDateString() : String(value);
|
|
260
|
+
case "select":
|
|
261
|
+
if (control.options) {
|
|
262
|
+
const option = control.options.find((opt) => opt.value === String(value));
|
|
263
|
+
if (option) return option.label;
|
|
264
|
+
}
|
|
265
|
+
return String(value);
|
|
266
|
+
case "file":
|
|
267
|
+
if (Array.isArray(value)) {
|
|
268
|
+
return value.map((f) => f.name || "file").join(", ");
|
|
269
|
+
}
|
|
270
|
+
return value.name || "file";
|
|
271
|
+
default:
|
|
272
|
+
return String(value);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
export {
|
|
277
|
+
registerTypeHandler,
|
|
278
|
+
getTypeHandler,
|
|
279
|
+
clearTypeHandlers,
|
|
280
|
+
validateField,
|
|
281
|
+
matchesMimeType,
|
|
282
|
+
parseValue,
|
|
283
|
+
formatValue
|
|
284
|
+
};
|