@docusign/iam-sdk
Version:
Developer-friendly & type-safe Typescript SDK specifically catered to leverage *@docusign/iam-sdk* API.
116 lines • 4.24 kB
JavaScript
/*
* Code generated by Speakeasy (https://speakeasy.com). DO NOT EDIT.
*/
// Not needed if lax mode
import * as z from "zod/v3";
import { startCountingDefaultToZeroValue } from "./defaultToZeroValue.js";
import { RFCDate } from "./rfcdate.js";
import { startCountingUnrecognized } from "./unrecognized.js";
/**
* Smart union parser that tries all schemas and returns the best match
* based on the number of populated fields.
*/
export function smartUnion(options) {
return z.unknown().transform((input, ctx) => {
const candidates = [];
const errors = options.map(() => []);
const parentUnrecognizedCtr = startCountingUnrecognized();
const parentZeroDefaultCtr = startCountingDefaultToZeroValue();
// Filter out invalid options
for (const [i, option] of options.entries()) {
const unrecognizedCtr = startCountingUnrecognized();
const zeroDefaultCtr = startCountingDefaultToZeroValue();
const result = option.safeParse(input);
const inexactCount = unrecognizedCtr.end();
const zeroDefaultCount = zeroDefaultCtr.end();
if (result.success) {
candidates.push({
data: result.data,
inexactCount,
zeroDefaultCount,
fieldCount: -1, // We'll count this later if needed
});
continue;
}
errors[i].push(...result.error.issues);
}
// No valid options
if (candidates.length === 0) {
parentUnrecognizedCtr.end(0);
parentZeroDefaultCtr.end(0);
ctx.addIssue({
code: "invalid_union",
unionErrors: errors.map(issues => new z.ZodError(issues)),
});
return z.NEVER;
}
let best = candidates[0];
// Find the best option
for (const candidate of candidates) {
// Minor optimization to avoid counting fields if there's only one candidate
if (candidates.length > 1) {
candidate.fieldCount = countFieldsRecursive(candidate.data);
}
best = better(candidate, best);
}
// The cost of this union should be the cost of the best candidate not all the candidates
parentUnrecognizedCtr.end(best.inexactCount);
parentZeroDefaultCtr.end(best.zeroDefaultCount);
return best.data;
});
}
function better(a, b) {
// First prefer exact matches over inexact ones
const aIsExact = a.inexactCount === 0;
const bIsExact = b.inexactCount === 0;
if (aIsExact !== bIsExact) {
return aIsExact ? a : b;
}
// Then compare field counts
const actualFieldCountA = a.fieldCount - a.zeroDefaultCount;
const actualFieldCountB = b.fieldCount - b.zeroDefaultCount;
if (actualFieldCountA !== actualFieldCountB) {
return actualFieldCountA > actualFieldCountB ? a : b;
}
return a.inexactCount < b.inexactCount ? a : b;
}
/**
* Counts the number of fields in a parsed value recursively.
* @param `parsed` assumed to *not* contain cycles
* fieldCount: total number of fields found
* inexactCount: number of primitive values that are not unrecognized enum values
*/
function countFieldsRecursive(parsed) {
let fieldCount = 0;
const queue = [parsed];
let index = 0;
while (index < queue.length) {
const value = queue[index++];
if (value === undefined) {
continue;
}
// Check if it's a primitive value
const type = typeof value;
if (value === null
|| type === "number"
|| type === "string"
|| type === "boolean"
|| type === "bigint"
|| value instanceof Date
|| value instanceof RFCDate) {
fieldCount++;
continue;
}
// Handle arrays
if (Array.isArray(value)) {
queue.push(...value);
continue;
}
// Handle objects
if (type === "object") {
queue.push(...Object.values(value));
}
}
return fieldCount;
}
//# sourceMappingURL=smartUnion.js.map