@asterdoc/render 0.0.0-stage → 0.9.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 +25 -0
- package/README.md +264 -2
- package/dist/check-BA5xdYgi.d.ts +69 -0
- package/dist/chunk-4QVR6LUY.js +98 -0
- package/dist/chunk-ICQLU4FL.js +630 -0
- package/dist/chunk-PNYKTSIT.js +1267 -0
- package/dist/chunk-U7LF3GN4.js +34 -0
- package/dist/context-BmjDcc_j.d.ts +32 -0
- package/dist/docx.d.ts +37 -0
- package/dist/docx.js +38 -0
- package/dist/index.d.ts +32 -0
- package/dist/index.js +69 -0
- package/dist/layer-bindings-CFXyN7SM.d.ts +94 -0
- package/dist/pdf.d.ts +620 -0
- package/dist/pdf.js +4638 -0
- package/dist/signatures-DPaL4gay.d.ts +20 -0
- package/dist/signatures-cS3V0yR3.d.ts +27 -0
- package/dist/text/field-formatter.d.ts +46 -0
- package/dist/text/field-formatter.js +21 -0
- package/dist/text.d.ts +44 -0
- package/dist/text.js +77 -0
- package/package.json +103 -3
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import {
|
|
2
|
+
bindingDataPath,
|
|
3
|
+
pathSegments
|
|
4
|
+
} from "./chunk-4QVR6LUY.js";
|
|
5
|
+
|
|
6
|
+
// src/text/field-formatter.ts
|
|
7
|
+
import { MISSING_RATING_SCALE, UNSUPPORTED_LIST_JOIN } from "@asterdoc/format";
|
|
8
|
+
var organizationPartyKeys = /* @__PURE__ */ new Set(["legalName", "domicile", "entityType", "entityId", "taxId"]);
|
|
9
|
+
function inferredPartyType(value) {
|
|
10
|
+
return Object.keys(value).some((key) => organizationPartyKeys.has(key)) ? "organization" : "person";
|
|
11
|
+
}
|
|
12
|
+
var rawValues = /* @__PURE__ */ new WeakMap();
|
|
13
|
+
var renderedValues = /* @__PURE__ */ new WeakMap();
|
|
14
|
+
var FormattedFieldValue = class {
|
|
15
|
+
constructor(value, text) {
|
|
16
|
+
if (value !== null && typeof value === "object") {
|
|
17
|
+
for (const [key, member] of Object.entries(value)) {
|
|
18
|
+
if (key === "toString" || key === "__proto__" || key === "constructor" || key === "prototype") continue;
|
|
19
|
+
Object.defineProperty(this, key, { configurable: false, enumerable: true, value: member, writable: false });
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
rawValues.set(this, value);
|
|
23
|
+
renderedValues.set(this, text);
|
|
24
|
+
}
|
|
25
|
+
get raw() {
|
|
26
|
+
return rawValues.get(this);
|
|
27
|
+
}
|
|
28
|
+
toString() {
|
|
29
|
+
return renderedValues.get(this) ?? "";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
function unwrapFormattedValue(value) {
|
|
33
|
+
return value instanceof FormattedFieldValue ? value.raw : value;
|
|
34
|
+
}
|
|
35
|
+
var ArtifactFieldFormatError = class extends Error {
|
|
36
|
+
path;
|
|
37
|
+
fieldType;
|
|
38
|
+
status;
|
|
39
|
+
issues;
|
|
40
|
+
constructor(path, fieldType, status, issues, cause) {
|
|
41
|
+
const detail = issues.map((entry) => entry.message).join("; ") || `Unable to format ${fieldType}.`;
|
|
42
|
+
super(`Cannot format ${path} (${fieldType}, ${status}): ${detail}`, cause instanceof Error ? { cause } : void 0);
|
|
43
|
+
this.name = "ArtifactFieldFormatError";
|
|
44
|
+
this.path = path;
|
|
45
|
+
this.fieldType = fieldType;
|
|
46
|
+
this.status = status;
|
|
47
|
+
this.issues = issues;
|
|
48
|
+
}
|
|
49
|
+
};
|
|
50
|
+
function isRecord(value) {
|
|
51
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
52
|
+
}
|
|
53
|
+
function isMissing(value) {
|
|
54
|
+
return value === null || value === void 0;
|
|
55
|
+
}
|
|
56
|
+
function childPath(path, segment) {
|
|
57
|
+
return typeof segment === "number" ? `${path}[${segment}]` : `${path}.${segment}`;
|
|
58
|
+
}
|
|
59
|
+
function formatIssue(path, fieldType, code, message) {
|
|
60
|
+
return new ArtifactFieldFormatError(path, fieldType, "invalid", [{ code, message, path, kind: fieldType }]);
|
|
61
|
+
}
|
|
62
|
+
function progressiveText(options, status) {
|
|
63
|
+
if (!options?.progressive) return void 0;
|
|
64
|
+
return status === "missing" ? options.progressive.missing ?? "\u2014" : options.progressive.incomplete ?? "\u2026";
|
|
65
|
+
}
|
|
66
|
+
function missingValue(value, path, fieldType, options) {
|
|
67
|
+
const text = progressiveText(options, "missing");
|
|
68
|
+
return text === void 0 ? value : new FormattedFieldValue(value, text);
|
|
69
|
+
}
|
|
70
|
+
function presentIssuePath(path, issuePath) {
|
|
71
|
+
if (!issuePath) return path;
|
|
72
|
+
if (issuePath === path || issuePath.startsWith(`${path}.`) || issuePath.startsWith(`${path}[`)) return issuePath;
|
|
73
|
+
return issuePath.startsWith("[") ? `${path}${issuePath}` : `${path}.${issuePath}`;
|
|
74
|
+
}
|
|
75
|
+
function presentIssues(issues, path, fieldType) {
|
|
76
|
+
return issues.map((issue) => ({
|
|
77
|
+
...issue,
|
|
78
|
+
path: presentIssuePath(path, issue.path),
|
|
79
|
+
kind: issue.kind ?? fieldType
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
function presentResult(result, value, path, fieldType, options) {
|
|
83
|
+
if (result.success) return new FormattedFieldValue(value, result.value);
|
|
84
|
+
if (result.status === "missing") return missingValue(value, path, fieldType, options);
|
|
85
|
+
if (result.status === "incomplete") {
|
|
86
|
+
const text = progressiveText(options, "incomplete");
|
|
87
|
+
if (text !== void 0) return new FormattedFieldValue(value, text);
|
|
88
|
+
}
|
|
89
|
+
throw new ArtifactFieldFormatError(path, fieldType, result.status, presentIssues(result.issues, path, fieldType));
|
|
90
|
+
}
|
|
91
|
+
function guardFormatting(path, fieldType, run) {
|
|
92
|
+
try {
|
|
93
|
+
return run();
|
|
94
|
+
} catch (error) {
|
|
95
|
+
if (error instanceof ArtifactFieldFormatError) throw error;
|
|
96
|
+
throw new ArtifactFieldFormatError(path, fieldType, "error", [{
|
|
97
|
+
code: "formatter_error",
|
|
98
|
+
message: error instanceof Error ? error.message : "Unexpected formatter failure.",
|
|
99
|
+
path,
|
|
100
|
+
kind: fieldType,
|
|
101
|
+
cause: error
|
|
102
|
+
}], error);
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
function callFormatter(path, fieldType, value, call, options) {
|
|
106
|
+
return guardFormatting(path, fieldType, () => presentResult(call(), value, path, fieldType, options));
|
|
107
|
+
}
|
|
108
|
+
function callFormatterWithFallback(path, fieldType, value, call, fallback) {
|
|
109
|
+
return guardFormatting(path, fieldType, () => {
|
|
110
|
+
const result = call();
|
|
111
|
+
const fellShort = !result.success && result.status === "unsupported" && result.issues.some((entry) => entry.code === fallback.code);
|
|
112
|
+
if (!fellShort) return presentResult(result, value, path, fieldType, fallback.options);
|
|
113
|
+
const substitute = fallback.substitute();
|
|
114
|
+
if (!substitute.success) return presentResult(substitute, value, path, fieldType, fallback.options);
|
|
115
|
+
return new FormattedFieldValue(value, substitute.value);
|
|
116
|
+
});
|
|
117
|
+
}
|
|
118
|
+
function recordInput(value, path, fieldType) {
|
|
119
|
+
if (isRecord(value)) return value;
|
|
120
|
+
throw formatIssue(path, fieldType, "invalid_value", `Expected an object for ${fieldType}.`);
|
|
121
|
+
}
|
|
122
|
+
function dateInput(value, path, fieldType) {
|
|
123
|
+
if (typeof value === "string" || value instanceof Date) return value;
|
|
124
|
+
throw formatIssue(path, fieldType, "invalid_value", `Expected an ISO string or Date for ${fieldType}.`);
|
|
125
|
+
}
|
|
126
|
+
function stringInput(value, path, fieldType) {
|
|
127
|
+
if (typeof value === "string") return value;
|
|
128
|
+
throw formatIssue(path, fieldType, "invalid_value", `Expected a string for ${fieldType}.`);
|
|
129
|
+
}
|
|
130
|
+
function numberInput(value, path, fieldType) {
|
|
131
|
+
if (typeof value === "number" && Number.isFinite(value)) return value;
|
|
132
|
+
throw formatIssue(path, fieldType, "invalid_value", `Expected a finite number for ${fieldType}.`);
|
|
133
|
+
}
|
|
134
|
+
function booleanInput(value, path, fieldType) {
|
|
135
|
+
if (typeof value === "boolean") return value;
|
|
136
|
+
throw formatIssue(path, fieldType, "invalid_value", "Expected a boolean value.");
|
|
137
|
+
}
|
|
138
|
+
function optionInput(value, path, fieldType) {
|
|
139
|
+
if (typeof value === "string" || typeof value === "number" && Number.isFinite(value)) return value;
|
|
140
|
+
throw formatIssue(path, fieldType, "invalid_value", `Expected a string or number ${fieldType} value.`);
|
|
141
|
+
}
|
|
142
|
+
function optionListInput(value, path, fieldType) {
|
|
143
|
+
if (!Array.isArray(value)) throw formatIssue(path, fieldType, "invalid_value", `Expected an array of ${fieldType} values.`);
|
|
144
|
+
return value.map((entry) => optionInput(entry, path, fieldType));
|
|
145
|
+
}
|
|
146
|
+
function commaJoinedLabels(formatter, values, options) {
|
|
147
|
+
const labels = [];
|
|
148
|
+
for (const value of values) {
|
|
149
|
+
const result = formatter.safeFormatEnum(value, { options });
|
|
150
|
+
if (!result.success) return result;
|
|
151
|
+
labels.push(result.value);
|
|
152
|
+
}
|
|
153
|
+
return { success: true, status: "formatted", value: labels.join(", ") };
|
|
154
|
+
}
|
|
155
|
+
function formatLeaf(formatter, field, value, path, options) {
|
|
156
|
+
if (isMissing(value)) return missingValue(value, path, field.type, options);
|
|
157
|
+
try {
|
|
158
|
+
switch (field.type) {
|
|
159
|
+
case "money":
|
|
160
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatMoney(recordInput(value, path, field.type), options?.money), options);
|
|
161
|
+
case "address":
|
|
162
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatAddress(recordInput(value, path, field.type)), options);
|
|
163
|
+
case "phone":
|
|
164
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatPhone(typeof value === "string" ? value : recordInput(value, path, field.type)), options);
|
|
165
|
+
case "person":
|
|
166
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatPerson(recordInput(value, path, field.type)), options);
|
|
167
|
+
case "organization":
|
|
168
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatOrganization(recordInput(value, path, field.type)), options);
|
|
169
|
+
case "coordinate":
|
|
170
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatCoordinate(recordInput(value, path, field.type)), options);
|
|
171
|
+
case "bbox":
|
|
172
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatBbox(recordInput(value, path, field.type)), options);
|
|
173
|
+
case "duration":
|
|
174
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatDuration(stringInput(value, path, field.type)), options);
|
|
175
|
+
case "identification":
|
|
176
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatIdentification(recordInput(value, path, field.type)), options);
|
|
177
|
+
case "date":
|
|
178
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatDate(dateInput(value, path, field.type)), options);
|
|
179
|
+
case "datetime":
|
|
180
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatDatetime(dateInput(value, path, field.type)), options);
|
|
181
|
+
case "time":
|
|
182
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatTime(stringInput(value, path, field.type)), options);
|
|
183
|
+
case "number":
|
|
184
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatNumber(numberInput(value, path, field.type)), options);
|
|
185
|
+
case "percentage":
|
|
186
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatPercentage(numberInput(value, path, field.type)), options);
|
|
187
|
+
case "boolean":
|
|
188
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatBoolean(booleanInput(value, path, field.type)), options);
|
|
189
|
+
case "enum":
|
|
190
|
+
if (options?.choices === "value") {
|
|
191
|
+
const choice = optionInput(value, path, field.type);
|
|
192
|
+
return new FormattedFieldValue(value, String(choice));
|
|
193
|
+
}
|
|
194
|
+
return callFormatter(path, field.type, value, () => formatter.safeFormatEnum(optionInput(value, path, field.type), { options: field.enum }), options);
|
|
195
|
+
case "multiselect":
|
|
196
|
+
if (options?.choices === "value") {
|
|
197
|
+
return new FormattedFieldValue(value, optionListInput(value, path, field.type).map(String).join(", "));
|
|
198
|
+
}
|
|
199
|
+
return callFormatterWithFallback(
|
|
200
|
+
path,
|
|
201
|
+
field.type,
|
|
202
|
+
value,
|
|
203
|
+
() => formatter.safeFormatMultiselect(optionListInput(value, path, field.type), { options: field.enum }),
|
|
204
|
+
{
|
|
205
|
+
code: UNSUPPORTED_LIST_JOIN,
|
|
206
|
+
substitute: () => commaJoinedLabels(formatter, optionListInput(value, path, field.type), field.enum),
|
|
207
|
+
options
|
|
208
|
+
}
|
|
209
|
+
);
|
|
210
|
+
case "text":
|
|
211
|
+
case "email":
|
|
212
|
+
case "uuid":
|
|
213
|
+
case "uri":
|
|
214
|
+
return stringInput(value, path, field.type);
|
|
215
|
+
// An absent `max` is left out, so a formatter-level rating scale still applies.
|
|
216
|
+
case "rating":
|
|
217
|
+
return callFormatterWithFallback(
|
|
218
|
+
path,
|
|
219
|
+
field.type,
|
|
220
|
+
value,
|
|
221
|
+
() => formatter.safeFormatRating(numberInput(value, path, field.type), field.max === void 0 ? {} : { max: field.max }),
|
|
222
|
+
{
|
|
223
|
+
code: MISSING_RATING_SCALE,
|
|
224
|
+
substitute: () => formatter.safeFormatNumber(numberInput(value, path, field.type)),
|
|
225
|
+
options
|
|
226
|
+
}
|
|
227
|
+
);
|
|
228
|
+
}
|
|
229
|
+
} catch (error) {
|
|
230
|
+
if (error instanceof ArtifactFieldFormatError) throw error;
|
|
231
|
+
throw new ArtifactFieldFormatError(path, field.type, "error", [{
|
|
232
|
+
code: "field_format_error",
|
|
233
|
+
message: error instanceof Error ? error.message : "Unexpected field formatting failure.",
|
|
234
|
+
path,
|
|
235
|
+
kind: field.type,
|
|
236
|
+
cause: error
|
|
237
|
+
}], error);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
function formatFieldValue(formatter, field, value, path, options) {
|
|
241
|
+
if (field.type === "list") {
|
|
242
|
+
if (isMissing(value)) return missingValue(value, path, field.type, options);
|
|
243
|
+
if (!Array.isArray(value)) throw formatIssue(path, field.type, "invalid_value", "Expected an array for a list field.");
|
|
244
|
+
return value.map((item, index) => formatFieldValue(formatter, field.item, item, childPath(path, index), options));
|
|
245
|
+
}
|
|
246
|
+
if (field.type === "fieldset") {
|
|
247
|
+
if (isMissing(value)) return missingValue(value, path, field.type, options);
|
|
248
|
+
if (!isRecord(value)) throw formatIssue(path, field.type, "invalid_value", "Expected an object for a fieldset.");
|
|
249
|
+
const result = { ...value };
|
|
250
|
+
for (const [key, child] of Object.entries(field.fields)) {
|
|
251
|
+
if (Object.prototype.hasOwnProperty.call(value, key) || options?.progressive) {
|
|
252
|
+
result[key] = formatFieldValue(formatter, child, value[key], childPath(path, key), options);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
return result;
|
|
256
|
+
}
|
|
257
|
+
return formatLeaf(formatter, field, value, path, options);
|
|
258
|
+
}
|
|
259
|
+
function formatDefinitionValue(formatter, type, value, path, options) {
|
|
260
|
+
if (isMissing(value)) return missingValue(value, path, type, options);
|
|
261
|
+
try {
|
|
262
|
+
switch (type) {
|
|
263
|
+
case "money":
|
|
264
|
+
return callFormatter(path, type, value, () => formatter.safeFormatMoney(recordInput(value, path, type), options?.money), options);
|
|
265
|
+
case "address":
|
|
266
|
+
return callFormatter(path, type, value, () => formatter.safeFormatAddress(recordInput(value, path, type)), options);
|
|
267
|
+
case "phone":
|
|
268
|
+
return callFormatter(path, type, value, () => formatter.safeFormatPhone(typeof value === "string" ? value : recordInput(value, path, type)), options);
|
|
269
|
+
case "person":
|
|
270
|
+
return callFormatter(path, type, value, () => formatter.safeFormatPerson(recordInput(value, path, type)), options);
|
|
271
|
+
case "organization":
|
|
272
|
+
return callFormatter(path, type, value, () => formatter.safeFormatOrganization(recordInput(value, path, type)), options);
|
|
273
|
+
case "party": {
|
|
274
|
+
const party = recordInput(value, path, type);
|
|
275
|
+
return callFormatter(path, type, value, () => formatter.safeFormatParty(party, { partyType: inferredPartyType(party) }), options);
|
|
276
|
+
}
|
|
277
|
+
case "coordinate":
|
|
278
|
+
return callFormatter(path, type, value, () => formatter.safeFormatCoordinate(recordInput(value, path, type)), options);
|
|
279
|
+
case "bbox":
|
|
280
|
+
return callFormatter(path, type, value, () => formatter.safeFormatBbox(recordInput(value, path, type)), options);
|
|
281
|
+
case "duration":
|
|
282
|
+
return callFormatter(path, type, value, () => formatter.safeFormatDuration(stringInput(value, path, type)), options);
|
|
283
|
+
case "identification":
|
|
284
|
+
return callFormatter(path, type, value, () => formatter.safeFormatIdentification(recordInput(value, path, type)), options);
|
|
285
|
+
case "attachment":
|
|
286
|
+
return callFormatter(path, type, value, () => formatter.safeFormatAttachment(recordInput(value, path, type)), options);
|
|
287
|
+
case "signature":
|
|
288
|
+
return callFormatter(path, type, value, () => formatter.safeFormatSignature(recordInput(value, path, type)), options);
|
|
289
|
+
case "date":
|
|
290
|
+
return callFormatter(path, type, value, () => formatter.safeFormatDate(dateInput(value, path, type)), options);
|
|
291
|
+
case "datetime":
|
|
292
|
+
return callFormatter(path, type, value, () => formatter.safeFormatDatetime(dateInput(value, path, type)), options);
|
|
293
|
+
case "time":
|
|
294
|
+
return callFormatter(path, type, value, () => formatter.safeFormatTime(stringInput(value, path, type)), options);
|
|
295
|
+
case "number":
|
|
296
|
+
return callFormatter(path, type, value, () => formatter.safeFormatNumber(numberInput(value, path, type)), options);
|
|
297
|
+
// A computed value carries no field, so only a formatter-level scale can apply.
|
|
298
|
+
case "rating":
|
|
299
|
+
return callFormatterWithFallback(
|
|
300
|
+
path,
|
|
301
|
+
type,
|
|
302
|
+
value,
|
|
303
|
+
() => formatter.safeFormatRating(numberInput(value, path, type)),
|
|
304
|
+
{
|
|
305
|
+
code: MISSING_RATING_SCALE,
|
|
306
|
+
substitute: () => formatter.safeFormatNumber(numberInput(value, path, type)),
|
|
307
|
+
options
|
|
308
|
+
}
|
|
309
|
+
);
|
|
310
|
+
case "integer": {
|
|
311
|
+
const number = numberInput(value, path, type);
|
|
312
|
+
if (!Number.isInteger(number)) throw formatIssue(path, type, "invalid_value", "Expected an integer value.");
|
|
313
|
+
return callFormatter(path, type, value, () => formatter.safeFormatNumber(number), options);
|
|
314
|
+
}
|
|
315
|
+
case "percentage":
|
|
316
|
+
return callFormatter(path, type, value, () => formatter.safeFormatPercentage(numberInput(value, path, type)), options);
|
|
317
|
+
case "boolean":
|
|
318
|
+
return callFormatter(path, type, value, () => formatter.safeFormatBoolean(booleanInput(value, path, type)), options);
|
|
319
|
+
case "string":
|
|
320
|
+
return stringInput(value, path, type);
|
|
321
|
+
default:
|
|
322
|
+
throw new ArtifactFieldFormatError(path, type, "unsupported", [{ code: "unsupported_type", message: `Unsupported computed value type ${JSON.stringify(type)}.`, path, kind: type }]);
|
|
323
|
+
}
|
|
324
|
+
} catch (error) {
|
|
325
|
+
if (error instanceof ArtifactFieldFormatError) throw error;
|
|
326
|
+
throw new ArtifactFieldFormatError(path, type, "error", [{ code: "computed_format_error", message: error instanceof Error ? error.message : "Unexpected computed value formatting failure.", path, kind: type, cause: error }], error);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function formatParties(formatter, form, value, path, options, role) {
|
|
330
|
+
if (isMissing(value)) return missingValue(value, path, "party", options);
|
|
331
|
+
if (Array.isArray(value)) return value.map((entry, index) => formatParties(formatter, form, entry, childPath(path, index), options, role));
|
|
332
|
+
const party = recordInput(value, path, "party");
|
|
333
|
+
const partyType = role ? form.parties?.[role]?.partyType : void 0;
|
|
334
|
+
const resolvedPartyType = partyType === "person" || partyType === "organization" ? partyType : inferredPartyType(party);
|
|
335
|
+
return callFormatter(path, "party", value, () => formatter.safeFormatParty(party, { partyType: resolvedPartyType }), options);
|
|
336
|
+
}
|
|
337
|
+
function formatAnnexes(formatter, form, value, options) {
|
|
338
|
+
if (!isRecord(value)) {
|
|
339
|
+
if (isMissing(value)) return options?.progressive ? {} : value;
|
|
340
|
+
throw formatIssue("annexes", "attachment", "invalid_value", "Expected annexes to be an object.");
|
|
341
|
+
}
|
|
342
|
+
const result = { ...value };
|
|
343
|
+
for (const [key, annexValue] of Object.entries(value)) {
|
|
344
|
+
const path = `annexes.${key}`;
|
|
345
|
+
const definition = form.annexes?.[key];
|
|
346
|
+
if (!definition && !form.allowAdditionalAnnexes) throw formatIssue(path, "attachment", "unknown_path", `Unknown annex ${JSON.stringify(key)}.`);
|
|
347
|
+
if (isMissing(annexValue)) result[key] = missingValue(annexValue, path, "attachment", options);
|
|
348
|
+
else result[key] = callFormatter(path, "attachment", annexValue, () => formatter.safeFormatAttachment(recordInput(annexValue, path, "attachment")), options);
|
|
349
|
+
}
|
|
350
|
+
for (const key of Object.keys(form.annexes ?? {})) {
|
|
351
|
+
if (!Object.prototype.hasOwnProperty.call(result, key) && options?.progressive) {
|
|
352
|
+
result[key] = missingValue(void 0, `annexes.${key}`, "attachment", options);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
return result;
|
|
356
|
+
}
|
|
357
|
+
function formatDefs(formatter, definitions, values, options) {
|
|
358
|
+
if (!isRecord(values)) {
|
|
359
|
+
if (isMissing(values)) return values;
|
|
360
|
+
throw formatIssue("defs", "computed", "invalid_value", "Expected computed values to be an object.");
|
|
361
|
+
}
|
|
362
|
+
const result = { ...values };
|
|
363
|
+
for (const [key, definition] of Object.entries(definitions ?? {})) {
|
|
364
|
+
if (Object.prototype.hasOwnProperty.call(values, key)) {
|
|
365
|
+
result[key] = formatDefinitionValue(formatter, definition.type, values[key], `defs.${key}`, options);
|
|
366
|
+
} else if (options?.progressive) {
|
|
367
|
+
result[key] = missingValue(void 0, `defs.${key}`, definition.type, options);
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
for (const key of Object.keys(values)) {
|
|
371
|
+
if (!definitions?.[key]) throw formatIssue(`defs.${key}`, "computed", "unknown_path", `Unknown computed value ${JSON.stringify(key)}.`);
|
|
372
|
+
}
|
|
373
|
+
return result;
|
|
374
|
+
}
|
|
375
|
+
function formatFieldData(data, form, formatter, options) {
|
|
376
|
+
const result = { ...data };
|
|
377
|
+
const nestedFields = isRecord(data.fields);
|
|
378
|
+
const fieldValues = isRecord(data.fields) ? data.fields : data;
|
|
379
|
+
const formattedFields = { ...fieldValues };
|
|
380
|
+
for (const [key, field] of Object.entries(form.fields ?? {})) {
|
|
381
|
+
if (Object.prototype.hasOwnProperty.call(fieldValues, key) || options?.progressive) {
|
|
382
|
+
formattedFields[key] = formatFieldValue(formatter, field, fieldValues[key], `fields.${key}`, options);
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (nestedFields) result.fields = formattedFields;
|
|
386
|
+
else Object.assign(result, formattedFields);
|
|
387
|
+
if (Object.prototype.hasOwnProperty.call(data, "parties") || options?.progressive && form.parties) {
|
|
388
|
+
const parties = data.parties;
|
|
389
|
+
if (!isMissing(parties) && !isRecord(parties)) throw formatIssue("parties", "party", "invalid_value", "Expected parties to be an object.");
|
|
390
|
+
const partyValues = isRecord(parties) ? parties : {};
|
|
391
|
+
const formattedParties = { ...partyValues };
|
|
392
|
+
for (const [role, value] of Object.entries(partyValues)) {
|
|
393
|
+
if (!form.parties?.[role]) throw formatIssue(`parties.${role}`, "party", "unknown_path", `Unknown party role ${JSON.stringify(role)}.`);
|
|
394
|
+
formattedParties[role] = formatParties(formatter, form, value, `parties.${role}`, options, role);
|
|
395
|
+
}
|
|
396
|
+
for (const role of Object.keys(form.parties ?? {})) {
|
|
397
|
+
if (!Object.prototype.hasOwnProperty.call(formattedParties, role) && options?.progressive) {
|
|
398
|
+
formattedParties[role] = formatParties(formatter, form, void 0, `parties.${role}`, options, role);
|
|
399
|
+
}
|
|
400
|
+
}
|
|
401
|
+
result.parties = formattedParties;
|
|
402
|
+
}
|
|
403
|
+
if (Object.prototype.hasOwnProperty.call(data, "defs")) result.defs = formatDefs(formatter, form.defs, data.defs, options);
|
|
404
|
+
if (Object.prototype.hasOwnProperty.call(data, "defs") === false && options?.progressive && form.defs) {
|
|
405
|
+
result.defs = formatDefs(formatter, form.defs, {}, options);
|
|
406
|
+
}
|
|
407
|
+
if (Object.prototype.hasOwnProperty.call(data, "annexes") || options?.progressive && form.annexes) {
|
|
408
|
+
result.annexes = formatAnnexes(formatter, form, data.annexes, options);
|
|
409
|
+
}
|
|
410
|
+
return result;
|
|
411
|
+
}
|
|
412
|
+
var signingRoots = /* @__PURE__ */ new Set(["_signers", "_captures"]);
|
|
413
|
+
function isIndex(segment) {
|
|
414
|
+
return /^\d+$/.test(segment) && Number.isSafeInteger(Number(segment));
|
|
415
|
+
}
|
|
416
|
+
var anyPath = /* @__PURE__ */ Symbol("any-path");
|
|
417
|
+
var leafPath = Object.freeze({});
|
|
418
|
+
var blockedPathSegments = /* @__PURE__ */ new Set(["__proto__", "prototype", "constructor"]);
|
|
419
|
+
function objectPath(entries) {
|
|
420
|
+
return Object.freeze(entries);
|
|
421
|
+
}
|
|
422
|
+
function mergePaths(...nodes) {
|
|
423
|
+
if (nodes.some((node) => node === anyPath)) return anyPath;
|
|
424
|
+
return objectPath(Object.assign({}, ...nodes));
|
|
425
|
+
}
|
|
426
|
+
var moneyPath = objectPath({ amount: leafPath, currency: leafPath });
|
|
427
|
+
var addressPath = objectPath({
|
|
428
|
+
line1: leafPath,
|
|
429
|
+
line2: leafPath,
|
|
430
|
+
locality: leafPath,
|
|
431
|
+
region: leafPath,
|
|
432
|
+
postalCode: leafPath,
|
|
433
|
+
country: leafPath
|
|
434
|
+
});
|
|
435
|
+
var phonePath = objectPath({ number: leafPath, type: leafPath, extension: leafPath });
|
|
436
|
+
var personPath = objectPath({ name: leafPath, title: leafPath, firstName: leafPath, middleName: leafPath, lastName: leafPath, suffix: leafPath });
|
|
437
|
+
var organizationPath = objectPath({
|
|
438
|
+
name: leafPath,
|
|
439
|
+
legalName: leafPath,
|
|
440
|
+
domicile: leafPath,
|
|
441
|
+
entityType: leafPath,
|
|
442
|
+
entityId: leafPath,
|
|
443
|
+
taxId: leafPath
|
|
444
|
+
});
|
|
445
|
+
var coordinatePath = objectPath({ lat: leafPath, lon: leafPath });
|
|
446
|
+
var bboxPath = objectPath({
|
|
447
|
+
southWest: coordinatePath,
|
|
448
|
+
northEast: coordinatePath
|
|
449
|
+
});
|
|
450
|
+
var identificationPath = objectPath({
|
|
451
|
+
type: leafPath,
|
|
452
|
+
number: leafPath,
|
|
453
|
+
issuer: leafPath,
|
|
454
|
+
issueDate: leafPath,
|
|
455
|
+
expiryDate: leafPath
|
|
456
|
+
});
|
|
457
|
+
var attachmentPath = objectPath({ name: leafPath, mimeType: leafPath, checksum: leafPath });
|
|
458
|
+
var signaturePath = objectPath({ image: leafPath, timestamp: leafPath, method: leafPath, type: leafPath, metadata: anyPath });
|
|
459
|
+
var signerPath = objectPath({
|
|
460
|
+
signerId: leafPath,
|
|
461
|
+
capacity: leafPath,
|
|
462
|
+
_role: leafPath,
|
|
463
|
+
_partyId: leafPath,
|
|
464
|
+
id: leafPath,
|
|
465
|
+
signer: objectPath({
|
|
466
|
+
id: leafPath,
|
|
467
|
+
person: personPath,
|
|
468
|
+
adopted: objectPath({ signature: signaturePath, initials: signaturePath })
|
|
469
|
+
})
|
|
470
|
+
});
|
|
471
|
+
var partyRuntimePath = objectPath({
|
|
472
|
+
id: leafPath,
|
|
473
|
+
_role: leafPath,
|
|
474
|
+
signatories: objectPath({ "#": signerPath }),
|
|
475
|
+
_captures: anyPath,
|
|
476
|
+
_signers: anyPath
|
|
477
|
+
});
|
|
478
|
+
var pathNodesByType = {
|
|
479
|
+
money: moneyPath,
|
|
480
|
+
address: addressPath,
|
|
481
|
+
phone: phonePath,
|
|
482
|
+
person: personPath,
|
|
483
|
+
organization: organizationPath,
|
|
484
|
+
party: mergePaths(personPath, organizationPath, partyRuntimePath),
|
|
485
|
+
coordinate: coordinatePath,
|
|
486
|
+
bbox: bboxPath,
|
|
487
|
+
identification: identificationPath,
|
|
488
|
+
attachment: attachmentPath,
|
|
489
|
+
signature: signaturePath,
|
|
490
|
+
string: leafPath,
|
|
491
|
+
text: leafPath,
|
|
492
|
+
email: leafPath,
|
|
493
|
+
uuid: leafPath,
|
|
494
|
+
uri: leafPath,
|
|
495
|
+
duration: leafPath,
|
|
496
|
+
date: leafPath,
|
|
497
|
+
datetime: leafPath,
|
|
498
|
+
time: leafPath,
|
|
499
|
+
number: leafPath,
|
|
500
|
+
integer: leafPath,
|
|
501
|
+
percentage: leafPath,
|
|
502
|
+
rating: leafPath,
|
|
503
|
+
boolean: leafPath,
|
|
504
|
+
enum: leafPath,
|
|
505
|
+
multiselect: leafPath
|
|
506
|
+
};
|
|
507
|
+
function pathNodeForType(type) {
|
|
508
|
+
return pathNodesByType[type];
|
|
509
|
+
}
|
|
510
|
+
function hasOwn(value, key) {
|
|
511
|
+
return value !== null && typeof value === "object" && Object.prototype.hasOwnProperty.call(value, key);
|
|
512
|
+
}
|
|
513
|
+
function validatePathSyntax(path) {
|
|
514
|
+
if (!path || path.startsWith(".") || path.endsWith(".") || path.includes("..")) return false;
|
|
515
|
+
return path.split(".").every((segment) => /^[^.[\]]+(?:\[\d+\])*$/.test(segment));
|
|
516
|
+
}
|
|
517
|
+
function validatePathNode(node, segments, index, path, fieldType) {
|
|
518
|
+
if (index >= segments.length || node === anyPath) return;
|
|
519
|
+
const segment = segments[index];
|
|
520
|
+
if (blockedPathSegments.has(segment)) {
|
|
521
|
+
throw formatIssue(path, fieldType, "unknown_path", `Blocked path segment ${JSON.stringify(segment)}.`);
|
|
522
|
+
}
|
|
523
|
+
let child;
|
|
524
|
+
if (Object.prototype.hasOwnProperty.call(node, segment)) {
|
|
525
|
+
child = node[segment];
|
|
526
|
+
} else if (Object.prototype.hasOwnProperty.call(node, "#")) {
|
|
527
|
+
if (!isIndex(segment)) {
|
|
528
|
+
throw formatIssue(path, fieldType, "unknown_path", `Expected a safe numeric index before ${JSON.stringify(segment)}.`);
|
|
529
|
+
}
|
|
530
|
+
child = node["#"];
|
|
531
|
+
} else if (Object.prototype.hasOwnProperty.call(node, "*")) {
|
|
532
|
+
child = node["*"];
|
|
533
|
+
}
|
|
534
|
+
if (!child) {
|
|
535
|
+
throw formatIssue(path, fieldType, "unknown_path", `Unknown ${fieldType} member ${JSON.stringify(segment)}.`);
|
|
536
|
+
}
|
|
537
|
+
validatePathNode(child, segments, index + 1, path, fieldType);
|
|
538
|
+
}
|
|
539
|
+
function validateDeclaredField(field, segments, index, path) {
|
|
540
|
+
if (index >= segments.length) return;
|
|
541
|
+
const segment = segments[index];
|
|
542
|
+
if (field.type === "list") {
|
|
543
|
+
if (!isIndex(segment)) throw formatIssue(path, field.type, "unknown_path", `Expected a list index before ${JSON.stringify(segment)}.`);
|
|
544
|
+
return validateDeclaredField(field.item, segments, index + 1, path);
|
|
545
|
+
}
|
|
546
|
+
if (field.type === "fieldset") {
|
|
547
|
+
const child = hasOwn(field.fields, segment) ? field.fields[segment] : void 0;
|
|
548
|
+
if (!child) throw formatIssue(path, field.type, "unknown_path", `Unknown nested field ${JSON.stringify(segment)}.`);
|
|
549
|
+
return validateDeclaredField(child, segments, index + 1, path);
|
|
550
|
+
}
|
|
551
|
+
const node = pathNodeForType(field.type);
|
|
552
|
+
if (!node) throw formatIssue(path, field.type, "unsupported_path", `Unsupported field type ${JSON.stringify(field.type)}.`);
|
|
553
|
+
validatePathNode(node, segments, index, path, field.type);
|
|
554
|
+
}
|
|
555
|
+
function validatePartyPath(form, segments, path) {
|
|
556
|
+
const role = segments[0];
|
|
557
|
+
const definition = role && hasOwn(form.parties, role) ? form.parties?.[role] : void 0;
|
|
558
|
+
if (!role || !definition) throw formatIssue(path, "party", "unknown_path", `Unknown party role ${JSON.stringify(role)}.`);
|
|
559
|
+
if (segments.length === 1) return;
|
|
560
|
+
const max = definition.max ?? 1;
|
|
561
|
+
const segment = segments[1];
|
|
562
|
+
const indexed = isIndex(segment);
|
|
563
|
+
const isCollection = max > 1;
|
|
564
|
+
if (indexed) {
|
|
565
|
+
if (!isCollection) throw formatIssue(path, "party", "unknown_path", `Party role ${JSON.stringify(role)} does not accept an index.`);
|
|
566
|
+
if (Number(segment) >= max) throw formatIssue(path, "party", "unknown_path", `Party index ${segment} is outside the declared maximum of ${max}.`);
|
|
567
|
+
if (segments.length === 2) return;
|
|
568
|
+
validatePathNode(partyPathNode(definition.partyType), segments, 2, path, "party");
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (isCollection) throw formatIssue(path, "party", "unknown_path", `Party role ${JSON.stringify(role)} requires an index.`);
|
|
572
|
+
validatePathNode(partyPathNode(definition.partyType), segments, 1, path, "party");
|
|
573
|
+
}
|
|
574
|
+
function partyPathNode(partyType) {
|
|
575
|
+
const identity = partyType === "person" ? personPath : partyType === "organization" ? organizationPath : mergePaths(personPath, organizationPath);
|
|
576
|
+
return mergePaths(identity, partyRuntimePath);
|
|
577
|
+
}
|
|
578
|
+
function validateBindingPath(form, sourcePath, bindingKey) {
|
|
579
|
+
const path = bindingDataPath(sourcePath);
|
|
580
|
+
if (!validatePathSyntax(path)) throw formatIssue(`bindings.${bindingKey}`, "path", "unknown_path", `Malformed field path ${JSON.stringify(sourcePath)}.`);
|
|
581
|
+
const segments = pathSegments(path);
|
|
582
|
+
if (segments.length === 0) throw formatIssue(`bindings.${bindingKey}`, "path", "unknown_path", `Unknown field path ${JSON.stringify(sourcePath)}.`);
|
|
583
|
+
const root = segments[0];
|
|
584
|
+
if (root === "parties") {
|
|
585
|
+
validatePartyPath(form, segments.slice(1), sourcePath);
|
|
586
|
+
return;
|
|
587
|
+
}
|
|
588
|
+
if (root === "defs") {
|
|
589
|
+
const definitionKey = segments[1];
|
|
590
|
+
const definition = definitionKey && hasOwn(form.defs, definitionKey) ? form.defs?.[definitionKey] : void 0;
|
|
591
|
+
if (!definition) throw formatIssue(sourcePath, "computed", "unknown_path", `Unknown computed value ${JSON.stringify(definitionKey)}.`);
|
|
592
|
+
if (segments.length > 2) {
|
|
593
|
+
const node = pathNodeForType(definition.type);
|
|
594
|
+
if (!node) throw formatIssue(sourcePath, "computed", "unsupported_path", `Unsupported computed value type ${JSON.stringify(definition.type)}.`);
|
|
595
|
+
validatePathNode(node, segments, 2, sourcePath, definition.type);
|
|
596
|
+
}
|
|
597
|
+
return;
|
|
598
|
+
}
|
|
599
|
+
if (root === "annexes") {
|
|
600
|
+
const annex = segments[1];
|
|
601
|
+
if (!annex || !hasOwn(form.annexes, annex) && !form.allowAdditionalAnnexes) {
|
|
602
|
+
throw formatIssue(sourcePath, "attachment", "unknown_path", `Unknown annex ${JSON.stringify(annex)}.`);
|
|
603
|
+
}
|
|
604
|
+
if (segments.length > 2) validatePathNode(attachmentPath, segments, 2, sourcePath, "attachment");
|
|
605
|
+
return;
|
|
606
|
+
}
|
|
607
|
+
const field = form.fields?.[root];
|
|
608
|
+
if (field) {
|
|
609
|
+
validateDeclaredField(field, segments, 1, sourcePath);
|
|
610
|
+
return;
|
|
611
|
+
}
|
|
612
|
+
if (signingRoots.has(root)) return;
|
|
613
|
+
throw formatIssue(sourcePath, "path", "unknown_path", `Unknown field path ${JSON.stringify(sourcePath)}.`);
|
|
614
|
+
}
|
|
615
|
+
function validateFieldBindings(form, bindings) {
|
|
616
|
+
for (const [bindingKey, sourcePath] of Object.entries(bindings)) {
|
|
617
|
+
validateBindingPath(form, sourcePath, bindingKey);
|
|
618
|
+
}
|
|
619
|
+
}
|
|
620
|
+
|
|
621
|
+
export {
|
|
622
|
+
FormattedFieldValue,
|
|
623
|
+
unwrapFormattedValue,
|
|
624
|
+
ArtifactFieldFormatError,
|
|
625
|
+
formatFieldValue,
|
|
626
|
+
formatDefinitionValue,
|
|
627
|
+
formatParties,
|
|
628
|
+
formatFieldData,
|
|
629
|
+
validateFieldBindings
|
|
630
|
+
};
|