@hoangvu12/yomi 0.1.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/README.md +191 -0
- package/dist/coerce.d.ts +8 -0
- package/dist/coerce.d.ts.map +1 -0
- package/dist/coerce.js +207 -0
- package/dist/coerce.js.map +1 -0
- package/dist/coercers/array.d.ts +20 -0
- package/dist/coercers/array.d.ts.map +1 -0
- package/dist/coercers/array.js +77 -0
- package/dist/coercers/array.js.map +1 -0
- package/dist/coercers/enum.d.ts +12 -0
- package/dist/coercers/enum.d.ts.map +1 -0
- package/dist/coercers/enum.js +62 -0
- package/dist/coercers/enum.js.map +1 -0
- package/dist/coercers/object.d.ts +23 -0
- package/dist/coercers/object.d.ts.map +1 -0
- package/dist/coercers/object.js +75 -0
- package/dist/coercers/object.js.map +1 -0
- package/dist/coercers/primitive.d.ts +33 -0
- package/dist/coercers/primitive.d.ts.map +1 -0
- package/dist/coercers/primitive.js +160 -0
- package/dist/coercers/primitive.js.map +1 -0
- package/dist/coercers/union.d.ts +35 -0
- package/dist/coercers/union.d.ts.map +1 -0
- package/dist/coercers/union.js +82 -0
- package/dist/coercers/union.js.map +1 -0
- package/dist/flags.d.ts +44 -0
- package/dist/flags.d.ts.map +1 -0
- package/dist/flags.js +42 -0
- package/dist/flags.js.map +1 -0
- package/dist/index.d.ts +81 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +125 -0
- package/dist/index.js.map +1 -0
- package/dist/parse.d.ts +17 -0
- package/dist/parse.d.ts.map +1 -0
- package/dist/parse.js +157 -0
- package/dist/parse.js.map +1 -0
- package/dist/types.d.ts +64 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +48 -0
- package/dist/types.js.map +1 -0
- package/package.json +61 -0
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { Flag } from "../flags.js";
|
|
2
|
+
import { childContext, success, failure, describeType, } from "../types.js";
|
|
3
|
+
function isPlainObject(value) {
|
|
4
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* LLMs often add extra fields we didn't ask for (explanations, confidence scores,
|
|
8
|
+
* reasoning). We ignore these rather than failing, but track them in flags.
|
|
9
|
+
*
|
|
10
|
+
* Missing optional fields are also tracked - callers can detect when defaults
|
|
11
|
+
* were used vs when the LLM explicitly provided values.
|
|
12
|
+
*/
|
|
13
|
+
export function coerceObject(value, schema, ctx) {
|
|
14
|
+
if (!isPlainObject(value)) {
|
|
15
|
+
return failure(`Expected object, got ${describeType(value)}`, ctx, "object", describeType(value));
|
|
16
|
+
}
|
|
17
|
+
const result = {};
|
|
18
|
+
const inputKeys = new Set(Object.keys(value));
|
|
19
|
+
const schemaKeys = new Set(Object.keys(schema));
|
|
20
|
+
for (const key of schemaKeys) {
|
|
21
|
+
const propSchema = schema[key];
|
|
22
|
+
if (!propSchema)
|
|
23
|
+
continue;
|
|
24
|
+
const propCtx = childContext(ctx, key);
|
|
25
|
+
const inputValue = value[key];
|
|
26
|
+
if (!(key in value) || inputValue === undefined) {
|
|
27
|
+
if (propSchema.optional) {
|
|
28
|
+
if ("default" in propSchema) {
|
|
29
|
+
ctx.flags.push({ flag: Flag.DefaultUsed });
|
|
30
|
+
result[key] = propSchema.default;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
ctx.flags.push({ flag: Flag.MissingOptionalKey });
|
|
34
|
+
// Leave undefined - don't add to result
|
|
35
|
+
}
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
return failure(`Missing required property "${key}"`, propCtx, "value", "undefined");
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
const propResult = propSchema.coercer(inputValue, propCtx);
|
|
43
|
+
if (!propResult.success) {
|
|
44
|
+
return propResult;
|
|
45
|
+
}
|
|
46
|
+
result[key] = propResult.value;
|
|
47
|
+
inputKeys.delete(key);
|
|
48
|
+
}
|
|
49
|
+
// Track extra keys so callers know the LLM added unrequested fields
|
|
50
|
+
if (inputKeys.size > 0) {
|
|
51
|
+
const extraKeys = Array.from(inputKeys);
|
|
52
|
+
ctx.flags.push({ flag: Flag.ExtraKeysIgnored, keys: extraKeys });
|
|
53
|
+
}
|
|
54
|
+
return success(result, ctx);
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* For z.record() - a map with string keys and uniform value types.
|
|
58
|
+
* Unlike objects, we don't have a fixed schema - just coerce each value.
|
|
59
|
+
*/
|
|
60
|
+
export function coerceRecord(value, valueCoercer, ctx) {
|
|
61
|
+
if (!isPlainObject(value)) {
|
|
62
|
+
return failure(`Expected object, got ${describeType(value)}`, ctx, "object", describeType(value));
|
|
63
|
+
}
|
|
64
|
+
const result = {};
|
|
65
|
+
for (const [key, val] of Object.entries(value)) {
|
|
66
|
+
const propCtx = childContext(ctx, key);
|
|
67
|
+
const propResult = valueCoercer(val, propCtx);
|
|
68
|
+
if (!propResult.success) {
|
|
69
|
+
return propResult;
|
|
70
|
+
}
|
|
71
|
+
result[key] = propResult.value;
|
|
72
|
+
}
|
|
73
|
+
return success(result, ctx);
|
|
74
|
+
}
|
|
75
|
+
//# sourceMappingURL=object.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"object.js","sourceRoot":"","sources":["../../src/coercers/object.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { type CoerceContext, type CoerceResult } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* String is the most permissive type - almost anything can become a string.
|
|
4
|
+
* This is intentional since LLMs generate text, so stringification is natural.
|
|
5
|
+
*/
|
|
6
|
+
export declare function coerceString(value: unknown, ctx: CoerceContext): CoerceResult<string>;
|
|
7
|
+
/**
|
|
8
|
+
* LLMs often return numbers as strings because they're generating text.
|
|
9
|
+
* "25" is obviously meant to be 25, so we parse it.
|
|
10
|
+
*/
|
|
11
|
+
export declare function coerceNumber(value: unknown, ctx: CoerceContext): CoerceResult<number>;
|
|
12
|
+
/**
|
|
13
|
+
* When the schema expects an integer but LLM returns a float,
|
|
14
|
+
* rounding is more useful than failing. We track the precision loss.
|
|
15
|
+
*/
|
|
16
|
+
export declare function coerceInt(value: unknown, ctx: CoerceContext): CoerceResult<number>;
|
|
17
|
+
/**
|
|
18
|
+
* LLMs return booleans in many forms: "true", "yes", "1", etc.
|
|
19
|
+
* We accept common truthy/falsy representations humans use.
|
|
20
|
+
*/
|
|
21
|
+
export declare function coerceBoolean(value: unknown, ctx: CoerceContext): CoerceResult<boolean>;
|
|
22
|
+
/**
|
|
23
|
+
* JSON has null but TypeScript often uses undefined.
|
|
24
|
+
* We treat them as interchangeable for flexibility.
|
|
25
|
+
*/
|
|
26
|
+
export declare function coerceNull(value: unknown, ctx: CoerceContext): CoerceResult<null>;
|
|
27
|
+
export declare function coerceUndefined(value: unknown, ctx: CoerceContext): CoerceResult<undefined>;
|
|
28
|
+
/**
|
|
29
|
+
* For z.literal(42), we first try exact match, then try coercing
|
|
30
|
+
* to the literal's type. So z.literal(42) accepts both 42 and "42".
|
|
31
|
+
*/
|
|
32
|
+
export declare function coerceLiteral<T extends string | number | boolean>(value: unknown, literal: T, ctx: CoerceContext): CoerceResult<T>;
|
|
33
|
+
//# sourceMappingURL=primitive.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitive.d.ts","sourceRoot":"","sources":["../../src/coercers/primitive.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,EAIlB,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC,CA2BrF;AAED;;;GAGG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC,CA6BrF;AAED;;;GAGG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAAC,MAAM,CAAC,CAclF;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAAC,OAAO,CAAC,CA6CvF;AAED;;;GAGG;AACH,wBAAgB,UAAU,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAAC,IAAI,CAAC,CAgBjF;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,GAAG,YAAY,CAAC,SAAS,CAAC,CAgB3F;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,MAAM,GAAG,MAAM,GAAG,OAAO,EAC/D,KAAK,EAAE,OAAO,EACd,OAAO,EAAE,CAAC,EACV,GAAG,EAAE,aAAa,GACjB,YAAY,CAAC,CAAC,CAAC,CA6BjB"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
import { Flag } from "../flags.js";
|
|
2
|
+
import { success, failure, describeType, } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* String is the most permissive type - almost anything can become a string.
|
|
5
|
+
* This is intentional since LLMs generate text, so stringification is natural.
|
|
6
|
+
*/
|
|
7
|
+
export function coerceString(value, ctx) {
|
|
8
|
+
if (typeof value === "string") {
|
|
9
|
+
return success(value, ctx);
|
|
10
|
+
}
|
|
11
|
+
// Numbers and booleans have obvious string representations
|
|
12
|
+
if (typeof value === "number") {
|
|
13
|
+
ctx.flags.push({ flag: Flag.NumberToString });
|
|
14
|
+
return success(String(value), ctx);
|
|
15
|
+
}
|
|
16
|
+
if (typeof value === "boolean") {
|
|
17
|
+
ctx.flags.push({ flag: Flag.BoolToString });
|
|
18
|
+
return success(String(value), ctx);
|
|
19
|
+
}
|
|
20
|
+
// null/undefined have no meaningful string form - fail rather than return "null"
|
|
21
|
+
if (value === null || value === undefined) {
|
|
22
|
+
return failure("Expected string, got null/undefined", ctx, "string", describeType(value));
|
|
23
|
+
}
|
|
24
|
+
return failure(`Cannot coerce ${describeType(value)} to string`, ctx, "string", describeType(value));
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* LLMs often return numbers as strings because they're generating text.
|
|
28
|
+
* "25" is obviously meant to be 25, so we parse it.
|
|
29
|
+
*/
|
|
30
|
+
export function coerceNumber(value, ctx) {
|
|
31
|
+
if (typeof value === "number") {
|
|
32
|
+
// NaN is technically a number but useless - treat as error
|
|
33
|
+
if (Number.isNaN(value)) {
|
|
34
|
+
return failure("Got NaN", ctx, "number", "NaN");
|
|
35
|
+
}
|
|
36
|
+
return success(value, ctx);
|
|
37
|
+
}
|
|
38
|
+
if (typeof value === "string") {
|
|
39
|
+
const trimmed = value.trim();
|
|
40
|
+
const parsed = parseFloat(trimmed);
|
|
41
|
+
if (!Number.isNaN(parsed)) {
|
|
42
|
+
ctx.flags.push({ flag: Flag.StringToNumber });
|
|
43
|
+
return success(parsed, ctx);
|
|
44
|
+
}
|
|
45
|
+
return failure(`Cannot parse "${trimmed}" as number`, ctx, "number", "string");
|
|
46
|
+
}
|
|
47
|
+
if (value === null || value === undefined) {
|
|
48
|
+
return failure("Expected number, got null/undefined", ctx, "number", describeType(value));
|
|
49
|
+
}
|
|
50
|
+
return failure(`Cannot coerce ${describeType(value)} to number`, ctx, "number", describeType(value));
|
|
51
|
+
}
|
|
52
|
+
/**
|
|
53
|
+
* When the schema expects an integer but LLM returns a float,
|
|
54
|
+
* rounding is more useful than failing. We track the precision loss.
|
|
55
|
+
*/
|
|
56
|
+
export function coerceInt(value, ctx) {
|
|
57
|
+
const numResult = coerceNumber(value, ctx);
|
|
58
|
+
if (!numResult.success) {
|
|
59
|
+
return numResult;
|
|
60
|
+
}
|
|
61
|
+
const num = numResult.value;
|
|
62
|
+
if (Number.isInteger(num)) {
|
|
63
|
+
return success(num, ctx);
|
|
64
|
+
}
|
|
65
|
+
const rounded = Math.round(num);
|
|
66
|
+
ctx.flags.push({ flag: Flag.FloatToInt, original: num, rounded });
|
|
67
|
+
return success(rounded, ctx);
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* LLMs return booleans in many forms: "true", "yes", "1", etc.
|
|
71
|
+
* We accept common truthy/falsy representations humans use.
|
|
72
|
+
*/
|
|
73
|
+
export function coerceBoolean(value, ctx) {
|
|
74
|
+
if (typeof value === "boolean") {
|
|
75
|
+
return success(value, ctx);
|
|
76
|
+
}
|
|
77
|
+
if (typeof value === "string") {
|
|
78
|
+
const lower = value.toLowerCase().trim();
|
|
79
|
+
// Common truthy strings across languages and conventions
|
|
80
|
+
if (lower === "true" || lower === "yes" || lower === "1" || lower === "on") {
|
|
81
|
+
ctx.flags.push({ flag: Flag.StringToBool });
|
|
82
|
+
return success(true, ctx);
|
|
83
|
+
}
|
|
84
|
+
if (lower === "false" || lower === "no" || lower === "0" || lower === "off") {
|
|
85
|
+
ctx.flags.push({ flag: Flag.StringToBool });
|
|
86
|
+
return success(false, ctx);
|
|
87
|
+
}
|
|
88
|
+
return failure(`Cannot parse "${value}" as boolean`, ctx, "boolean", "string");
|
|
89
|
+
}
|
|
90
|
+
// 1/0 are common boolean representations in APIs
|
|
91
|
+
if (typeof value === "number") {
|
|
92
|
+
if (value === 1) {
|
|
93
|
+
ctx.flags.push({ flag: Flag.StringToBool });
|
|
94
|
+
return success(true, ctx);
|
|
95
|
+
}
|
|
96
|
+
if (value === 0) {
|
|
97
|
+
ctx.flags.push({ flag: Flag.StringToBool });
|
|
98
|
+
return success(false, ctx);
|
|
99
|
+
}
|
|
100
|
+
return failure(`Cannot coerce number ${value} to boolean`, ctx, "boolean", "number");
|
|
101
|
+
}
|
|
102
|
+
if (value === null || value === undefined) {
|
|
103
|
+
return failure("Expected boolean, got null/undefined", ctx, "boolean", describeType(value));
|
|
104
|
+
}
|
|
105
|
+
return failure(`Cannot coerce ${describeType(value)} to boolean`, ctx, "boolean", describeType(value));
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* JSON has null but TypeScript often uses undefined.
|
|
109
|
+
* We treat them as interchangeable for flexibility.
|
|
110
|
+
*/
|
|
111
|
+
export function coerceNull(value, ctx) {
|
|
112
|
+
if (value === null) {
|
|
113
|
+
return success(null, ctx);
|
|
114
|
+
}
|
|
115
|
+
if (value === undefined) {
|
|
116
|
+
ctx.flags.push({ flag: Flag.NullToUndefined });
|
|
117
|
+
return success(null, ctx);
|
|
118
|
+
}
|
|
119
|
+
return failure(`Expected null, got ${describeType(value)}`, ctx, "null", describeType(value));
|
|
120
|
+
}
|
|
121
|
+
export function coerceUndefined(value, ctx) {
|
|
122
|
+
if (value === undefined) {
|
|
123
|
+
return success(undefined, ctx);
|
|
124
|
+
}
|
|
125
|
+
if (value === null) {
|
|
126
|
+
ctx.flags.push({ flag: Flag.NullToUndefined });
|
|
127
|
+
return success(undefined, ctx);
|
|
128
|
+
}
|
|
129
|
+
return failure(`Expected undefined, got ${describeType(value)}`, ctx, "undefined", describeType(value));
|
|
130
|
+
}
|
|
131
|
+
/**
|
|
132
|
+
* For z.literal(42), we first try exact match, then try coercing
|
|
133
|
+
* to the literal's type. So z.literal(42) accepts both 42 and "42".
|
|
134
|
+
*/
|
|
135
|
+
export function coerceLiteral(value, literal, ctx) {
|
|
136
|
+
if (value === literal) {
|
|
137
|
+
return success(literal, ctx);
|
|
138
|
+
}
|
|
139
|
+
// Try coercing to the literal's type, then check equality
|
|
140
|
+
if (typeof literal === "string") {
|
|
141
|
+
const result = coerceString(value, ctx);
|
|
142
|
+
if (result.success && result.value === literal) {
|
|
143
|
+
return success(literal, ctx);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
else if (typeof literal === "number") {
|
|
147
|
+
const result = coerceNumber(value, ctx);
|
|
148
|
+
if (result.success && result.value === literal) {
|
|
149
|
+
return success(literal, ctx);
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
else if (typeof literal === "boolean") {
|
|
153
|
+
const result = coerceBoolean(value, ctx);
|
|
154
|
+
if (result.success && result.value === literal) {
|
|
155
|
+
return success(literal, ctx);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
return failure(`Expected literal ${JSON.stringify(literal)}, got ${JSON.stringify(value)}`, ctx, JSON.stringify(literal), describeType(value));
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=primitive.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"primitive.js","sourceRoot":"","sources":["../../src/coercers/primitive.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;AACnC,OAAO,EAGL,OAAO,EACP,OAAO,EACP,YAAY,GACb,MAAM,aAAa,CAAC;AAErB;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,GAAkB;IAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,2DAA2D;IAC3D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;QAC9C,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;QAC5C,OAAO,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,GAAG,CAAC,CAAC;IACrC,CAAC;IAED,iFAAiF;IACjF,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,OAAO,CAAC,qCAAqC,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5F,CAAC;IAED,OAAO,OAAO,CACZ,iBAAiB,YAAY,CAAC,KAAK,CAAC,YAAY,EAChD,GAAG,EACH,QAAQ,EACR,YAAY,CAAC,KAAK,CAAC,CACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc,EAAE,GAAkB;IAC7D,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,2DAA2D;QAC3D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;YACxB,OAAO,OAAO,CAAC,SAAS,EAAE,GAAG,EAAE,QAAQ,EAAE,KAAK,CAAC,CAAC;QAClD,CAAC;QACD,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC;QAC7B,MAAM,MAAM,GAAG,UAAU,CAAC,OAAO,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,EAAE,CAAC;YAC1B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,cAAc,EAAE,CAAC,CAAC;YAC9C,OAAO,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;QAC9B,CAAC;QACD,OAAO,OAAO,CAAC,iBAAiB,OAAO,aAAa,EAAE,GAAG,EAAE,QAAQ,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,OAAO,CAAC,qCAAqC,EAAE,GAAG,EAAE,QAAQ,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAC5F,CAAC;IAED,OAAO,OAAO,CACZ,iBAAiB,YAAY,CAAC,KAAK,CAAC,YAAY,EAChD,GAAG,EACH,QAAQ,EACR,YAAY,CAAC,KAAK,CAAC,CACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,SAAS,CAAC,KAAc,EAAE,GAAkB;IAC1D,MAAM,SAAS,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,SAAS,CAAC,OAAO,EAAE,CAAC;QACvB,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,MAAM,GAAG,GAAG,SAAS,CAAC,KAAK,CAAC;IAC5B,IAAI,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;QAC1B,OAAO,OAAO,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IAChC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,EAAE,OAAO,EAAE,CAAC,CAAC;IAClE,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;AAC/B,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAc,EAAE,GAAkB;IAC9D,IAAI,OAAO,KAAK,KAAK,SAAS,EAAE,CAAC;QAC/B,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,MAAM,KAAK,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,CAAC;QAEzC,yDAAyD;QACzD,IAAI,KAAK,KAAK,MAAM,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC3E,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;YAC5C,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC5B,CAAC;QAED,IAAI,KAAK,KAAK,OAAO,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,GAAG,IAAI,KAAK,KAAK,KAAK,EAAE,CAAC;YAC5E,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;YAC5C,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC7B,CAAC;QAED,OAAO,OAAO,CAAC,iBAAiB,KAAK,cAAc,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACjF,CAAC;IAED,iDAAiD;IACjD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC9B,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;YAC5C,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;QAC5B,CAAC;QACD,IAAI,KAAK,KAAK,CAAC,EAAE,CAAC;YAChB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,YAAY,EAAE,CAAC,CAAC;YAC5C,OAAO,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC7B,CAAC;QACD,OAAO,OAAO,CAAC,wBAAwB,KAAK,aAAa,EAAE,GAAG,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;IACvF,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QAC1C,OAAO,OAAO,CAAC,sCAAsC,EAAE,GAAG,EAAE,SAAS,EAAE,YAAY,CAAC,KAAK,CAAC,CAAC,CAAC;IAC9F,CAAC;IAED,OAAO,OAAO,CACZ,iBAAiB,YAAY,CAAC,KAAK,CAAC,aAAa,EACjD,GAAG,EACH,SAAS,EACT,YAAY,CAAC,KAAK,CAAC,CACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,UAAU,CAAC,KAAc,EAAE,GAAkB;IAC3D,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/C,OAAO,OAAO,CAAC,IAAI,EAAE,GAAG,CAAC,CAAC;IAC5B,CAAC;IAED,OAAO,OAAO,CACZ,sBAAsB,YAAY,CAAC,KAAK,CAAC,EAAE,EAC3C,GAAG,EACH,MAAM,EACN,YAAY,CAAC,KAAK,CAAC,CACpB,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,KAAc,EAAE,GAAkB;IAChE,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;QACnB,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,eAAe,EAAE,CAAC,CAAC;QAC/C,OAAO,OAAO,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;IACjC,CAAC;IAED,OAAO,OAAO,CACZ,2BAA2B,YAAY,CAAC,KAAK,CAAC,EAAE,EAChD,GAAG,EACH,WAAW,EACX,YAAY,CAAC,KAAK,CAAC,CACpB,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,KAAc,EACd,OAAU,EACV,GAAkB;IAElB,IAAI,KAAK,KAAK,OAAO,EAAE,CAAC;QACtB,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;IAC/B,CAAC;IAED,0DAA0D;IAC1D,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAChC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC/C,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;SAAM,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QACvC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACxC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC/C,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;SAAM,IAAI,OAAO,OAAO,KAAK,SAAS,EAAE,CAAC;QACxC,MAAM,MAAM,GAAG,aAAa,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QACzC,IAAI,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,KAAK,OAAO,EAAE,CAAC;YAC/C,OAAO,OAAO,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC;QAC/B,CAAC;IACH,CAAC;IAED,OAAO,OAAO,CACZ,oBAAoB,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,SAAS,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,EAC3E,GAAG,EACH,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,EACvB,YAAY,CAAC,KAAK,CAAC,CACpB,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { type CoerceContext, type CoerceResult } from "../types.js";
|
|
2
|
+
export type Coercer<T> = (value: unknown, ctx: CoerceContext) => CoerceResult<T>;
|
|
3
|
+
/**
|
|
4
|
+
* For z.union([A, B, C]), we try each type in order and return the first success.
|
|
5
|
+
*
|
|
6
|
+
* Order matters! If you have z.union([z.string(), z.number()]), a number will
|
|
7
|
+
* become a string because string coercion accepts numbers. Put more specific
|
|
8
|
+
* types first if you want them to take priority.
|
|
9
|
+
*
|
|
10
|
+
* We use a temporary context for each attempt so failed attempts don't
|
|
11
|
+
* pollute the flags of the successful one.
|
|
12
|
+
*/
|
|
13
|
+
export declare function coerceUnion<T>(value: unknown, coercers: Coercer<T>[], ctx: CoerceContext): CoerceResult<T>;
|
|
14
|
+
/**
|
|
15
|
+
* For z.optional(T), both undefined and null become undefined.
|
|
16
|
+
* This bridges JSON's null with TypeScript's optional fields.
|
|
17
|
+
*/
|
|
18
|
+
export declare function coerceOptional<T>(value: unknown, innerCoercer: Coercer<T>, ctx: CoerceContext): CoerceResult<T | undefined>;
|
|
19
|
+
/**
|
|
20
|
+
* For z.nullable(T), both null and undefined become null.
|
|
21
|
+
* The inverse of optional - useful when the schema explicitly expects null.
|
|
22
|
+
*/
|
|
23
|
+
export declare function coerceNullable<T>(value: unknown, innerCoercer: Coercer<T>, ctx: CoerceContext): CoerceResult<T | null>;
|
|
24
|
+
/**
|
|
25
|
+
* For z.default(value), use the default when input is missing.
|
|
26
|
+
* Tracks when defaults are used so callers can distinguish explicit
|
|
27
|
+
* values from fallbacks.
|
|
28
|
+
*/
|
|
29
|
+
export declare function coerceDefault<T>(value: unknown, innerCoercer: Coercer<T>, defaultValue: T, ctx: CoerceContext): CoerceResult<T>;
|
|
30
|
+
/**
|
|
31
|
+
* For z.catch(value), return the catch value if coercion fails.
|
|
32
|
+
* Unlike default (which handles missing values), catch handles invalid values.
|
|
33
|
+
*/
|
|
34
|
+
export declare function coerceCatch<T>(value: unknown, innerCoercer: Coercer<T>, catchValue: T, ctx: CoerceContext): CoerceResult<T>;
|
|
35
|
+
//# sourceMappingURL=union.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"union.d.ts","sourceRoot":"","sources":["../../src/coercers/union.ts"],"names":[],"mappings":"AACA,OAAO,EACL,KAAK,aAAa,EAClB,KAAK,YAAY,EAMlB,MAAM,aAAa,CAAC;AAErB,MAAM,MAAM,OAAO,CAAC,CAAC,IAAI,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,aAAa,KAAK,YAAY,CAAC,CAAC,CAAC,CAAC;AAEjF;;;;;;;;;GASG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,OAAO,EACd,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,EAAE,EACtB,GAAG,EAAE,aAAa,GACjB,YAAY,CAAC,CAAC,CAAC,CAyBjB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,EACxB,GAAG,EAAE,aAAa,GACjB,YAAY,CAAC,CAAC,GAAG,SAAS,CAAC,CAY7B;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAAC,CAAC,EAC9B,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,EACxB,GAAG,EAAE,aAAa,GACjB,YAAY,CAAC,CAAC,GAAG,IAAI,CAAC,CAWxB;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,EAC7B,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,EACxB,YAAY,EAAE,CAAC,EACf,GAAG,EAAE,aAAa,GACjB,YAAY,CAAC,CAAC,CAAC,CAOjB;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,CAAC,EAC3B,KAAK,EAAE,OAAO,EACd,YAAY,EAAE,OAAO,CAAC,CAAC,CAAC,EACxB,UAAU,EAAE,CAAC,EACb,GAAG,EAAE,aAAa,GACjB,YAAY,CAAC,CAAC,CAAC,CASjB"}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import { Flag } from "../flags.js";
|
|
2
|
+
import { success, failure, createContext, describeType, } from "../types.js";
|
|
3
|
+
/**
|
|
4
|
+
* For z.union([A, B, C]), we try each type in order and return the first success.
|
|
5
|
+
*
|
|
6
|
+
* Order matters! If you have z.union([z.string(), z.number()]), a number will
|
|
7
|
+
* become a string because string coercion accepts numbers. Put more specific
|
|
8
|
+
* types first if you want them to take priority.
|
|
9
|
+
*
|
|
10
|
+
* We use a temporary context for each attempt so failed attempts don't
|
|
11
|
+
* pollute the flags of the successful one.
|
|
12
|
+
*/
|
|
13
|
+
export function coerceUnion(value, coercers, ctx) {
|
|
14
|
+
const errors = [];
|
|
15
|
+
for (const coercer of coercers) {
|
|
16
|
+
const tempCtx = createContext();
|
|
17
|
+
tempCtx.path = ctx.path;
|
|
18
|
+
const result = coercer(value, tempCtx);
|
|
19
|
+
if (result.success) {
|
|
20
|
+
// Only merge flags from the successful path
|
|
21
|
+
ctx.flags.push(...tempCtx.flags);
|
|
22
|
+
return success(result.value, ctx);
|
|
23
|
+
}
|
|
24
|
+
errors.push(result);
|
|
25
|
+
}
|
|
26
|
+
const expectedTypes = errors.map((e) => e.error.expected).join(" | ");
|
|
27
|
+
return failure(`Value does not match any union type`, ctx, expectedTypes, describeType(value));
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* For z.optional(T), both undefined and null become undefined.
|
|
31
|
+
* This bridges JSON's null with TypeScript's optional fields.
|
|
32
|
+
*/
|
|
33
|
+
export function coerceOptional(value, innerCoercer, ctx) {
|
|
34
|
+
if (value === undefined) {
|
|
35
|
+
return success(undefined, ctx);
|
|
36
|
+
}
|
|
37
|
+
// JSON has null, TypeScript has undefined - treat them the same for optional
|
|
38
|
+
if (value === null) {
|
|
39
|
+
ctx.flags.push({ flag: Flag.NullToUndefined });
|
|
40
|
+
return success(undefined, ctx);
|
|
41
|
+
}
|
|
42
|
+
return innerCoercer(value, ctx);
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* For z.nullable(T), both null and undefined become null.
|
|
46
|
+
* The inverse of optional - useful when the schema explicitly expects null.
|
|
47
|
+
*/
|
|
48
|
+
export function coerceNullable(value, innerCoercer, ctx) {
|
|
49
|
+
if (value === null) {
|
|
50
|
+
return success(null, ctx);
|
|
51
|
+
}
|
|
52
|
+
if (value === undefined) {
|
|
53
|
+
ctx.flags.push({ flag: Flag.NullToUndefined });
|
|
54
|
+
return success(null, ctx);
|
|
55
|
+
}
|
|
56
|
+
return innerCoercer(value, ctx);
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* For z.default(value), use the default when input is missing.
|
|
60
|
+
* Tracks when defaults are used so callers can distinguish explicit
|
|
61
|
+
* values from fallbacks.
|
|
62
|
+
*/
|
|
63
|
+
export function coerceDefault(value, innerCoercer, defaultValue, ctx) {
|
|
64
|
+
if (value === undefined || value === null) {
|
|
65
|
+
ctx.flags.push({ flag: Flag.DefaultUsed });
|
|
66
|
+
return success(defaultValue, ctx);
|
|
67
|
+
}
|
|
68
|
+
return innerCoercer(value, ctx);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* For z.catch(value), return the catch value if coercion fails.
|
|
72
|
+
* Unlike default (which handles missing values), catch handles invalid values.
|
|
73
|
+
*/
|
|
74
|
+
export function coerceCatch(value, innerCoercer, catchValue, ctx) {
|
|
75
|
+
const result = innerCoercer(value, ctx);
|
|
76
|
+
if (result.success) {
|
|
77
|
+
return result;
|
|
78
|
+
}
|
|
79
|
+
ctx.flags.push({ flag: Flag.DefaultUsed });
|
|
80
|
+
return success(catchValue, ctx);
|
|
81
|
+
}
|
|
82
|
+
//# sourceMappingURL=union.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"union.js","sourceRoot":"","sources":["../../src/coercers/union.ts"],"names":[],"mappings":"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"}
|
package/dist/flags.d.ts
ADDED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLMs often return data that doesn't exactly match the expected schema.
|
|
3
|
+
* Rather than failing, we coerce values to fit - but we track every
|
|
4
|
+
* transformation so callers can audit what changed and detect potential issues.
|
|
5
|
+
*/
|
|
6
|
+
export declare enum Flag {
|
|
7
|
+
StringToNumber = "string_to_number",
|
|
8
|
+
StringToBool = "string_to_bool",
|
|
9
|
+
NumberToString = "number_to_string",
|
|
10
|
+
BoolToString = "bool_to_string",
|
|
11
|
+
FloatToInt = "float_to_int",
|
|
12
|
+
IntToFloat = "int_to_float",
|
|
13
|
+
NullToUndefined = "null_to_undefined",
|
|
14
|
+
SingleToArray = "single_to_array",
|
|
15
|
+
ArrayToSingle = "array_to_single",
|
|
16
|
+
JsonRepaired = "json_repaired",
|
|
17
|
+
ExtractedFromMarkdown = "extracted_from_markdown",
|
|
18
|
+
ExtractedFromText = "extracted_from_text",
|
|
19
|
+
ExtraKeysIgnored = "extra_keys_ignored",
|
|
20
|
+
MissingOptionalKey = "missing_optional_key",
|
|
21
|
+
DefaultUsed = "default_used",
|
|
22
|
+
EnumCaseInsensitive = "enum_case_insensitive"
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Some flags benefit from additional context for debugging.
|
|
26
|
+
* ExtraKeysIgnored tells you which keys, FloatToInt shows the precision lost.
|
|
27
|
+
*/
|
|
28
|
+
export type FlagWithContext = {
|
|
29
|
+
flag: Flag.ExtraKeysIgnored;
|
|
30
|
+
keys: string[];
|
|
31
|
+
} | {
|
|
32
|
+
flag: Flag.FloatToInt;
|
|
33
|
+
original: number;
|
|
34
|
+
rounded: number;
|
|
35
|
+
} | {
|
|
36
|
+
flag: Flag.EnumCaseInsensitive;
|
|
37
|
+
input: string;
|
|
38
|
+
matched: string;
|
|
39
|
+
} | {
|
|
40
|
+
flag: Exclude<Flag, Flag.ExtraKeysIgnored | Flag.FloatToInt | Flag.EnumCaseInsensitive>;
|
|
41
|
+
};
|
|
42
|
+
export declare function flag(f: Flag): FlagWithContext;
|
|
43
|
+
export declare function flagValues(flags: FlagWithContext[]): Flag[];
|
|
44
|
+
//# sourceMappingURL=flags.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.d.ts","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,oBAAY,IAAI;IAGd,cAAc,qBAAqB;IACnC,YAAY,mBAAmB;IAC/B,cAAc,qBAAqB;IACnC,YAAY,mBAAmB;IAG/B,UAAU,iBAAiB;IAC3B,UAAU,iBAAiB;IAG3B,eAAe,sBAAsB;IAIrC,aAAa,oBAAoB;IACjC,aAAa,oBAAoB;IAGjC,YAAY,kBAAkB;IAG9B,qBAAqB,4BAA4B;IACjD,iBAAiB,wBAAwB;IAGzC,gBAAgB,uBAAuB;IACvC,kBAAkB,yBAAyB;IAG3C,WAAW,iBAAiB;IAG5B,mBAAmB,0BAA0B;CAC9C;AAED;;;GAGG;AACH,MAAM,MAAM,eAAe,GACvB;IAAE,IAAI,EAAE,IAAI,CAAC,gBAAgB,CAAC;IAAC,IAAI,EAAE,MAAM,EAAE,CAAA;CAAE,GAC/C;IAAE,IAAI,EAAE,IAAI,CAAC,UAAU,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAC5D;IAAE,IAAI,EAAE,IAAI,CAAC,mBAAmB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,MAAM,CAAA;CAAE,GAClE;IAAE,IAAI,EAAE,OAAO,CAAC,IAAI,EAAE,IAAI,CAAC,gBAAgB,GAAG,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC,mBAAmB,CAAC,CAAA;CAAE,CAAC;AAEhG,wBAAgB,IAAI,CAAC,CAAC,EAAE,IAAI,GAAG,eAAe,CAE7C;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,EAAE,GAAG,IAAI,EAAE,CAE3D"}
|
package/dist/flags.js
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LLMs often return data that doesn't exactly match the expected schema.
|
|
3
|
+
* Rather than failing, we coerce values to fit - but we track every
|
|
4
|
+
* transformation so callers can audit what changed and detect potential issues.
|
|
5
|
+
*/
|
|
6
|
+
export var Flag;
|
|
7
|
+
(function (Flag) {
|
|
8
|
+
// LLMs frequently return numbers as strings ("25" instead of 25)
|
|
9
|
+
// because they're generating text, not typed data
|
|
10
|
+
Flag["StringToNumber"] = "string_to_number";
|
|
11
|
+
Flag["StringToBool"] = "string_to_bool";
|
|
12
|
+
Flag["NumberToString"] = "number_to_string";
|
|
13
|
+
Flag["BoolToString"] = "bool_to_string";
|
|
14
|
+
// When schema expects int but LLM returns 3.7, we round rather than fail
|
|
15
|
+
Flag["FloatToInt"] = "float_to_int";
|
|
16
|
+
Flag["IntToFloat"] = "int_to_float";
|
|
17
|
+
// JSON has null, TypeScript has undefined - we bridge the gap
|
|
18
|
+
Flag["NullToUndefined"] = "null_to_undefined";
|
|
19
|
+
// LLMs sometimes return a single item when an array is expected,
|
|
20
|
+
// or vice versa - common when there's only one result
|
|
21
|
+
Flag["SingleToArray"] = "single_to_array";
|
|
22
|
+
Flag["ArrayToSingle"] = "array_to_single";
|
|
23
|
+
// The JSON parser had to fix syntax issues (trailing commas, unquoted keys, etc.)
|
|
24
|
+
Flag["JsonRepaired"] = "json_repaired";
|
|
25
|
+
// JSON was wrapped in markdown code blocks or surrounded by explanation text
|
|
26
|
+
Flag["ExtractedFromMarkdown"] = "extracted_from_markdown";
|
|
27
|
+
Flag["ExtractedFromText"] = "extracted_from_text";
|
|
28
|
+
// LLMs often add extra fields we didn't ask for (explanations, metadata)
|
|
29
|
+
Flag["ExtraKeysIgnored"] = "extra_keys_ignored";
|
|
30
|
+
Flag["MissingOptionalKey"] = "missing_optional_key";
|
|
31
|
+
// Value was missing/null so we used the schema's default
|
|
32
|
+
Flag["DefaultUsed"] = "default_used";
|
|
33
|
+
// LLM returned "RED" but schema expects "red" - close enough
|
|
34
|
+
Flag["EnumCaseInsensitive"] = "enum_case_insensitive";
|
|
35
|
+
})(Flag || (Flag = {}));
|
|
36
|
+
export function flag(f) {
|
|
37
|
+
return { flag: f };
|
|
38
|
+
}
|
|
39
|
+
export function flagValues(flags) {
|
|
40
|
+
return flags.map((f) => f.flag);
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=flags.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"flags.js","sourceRoot":"","sources":["../src/flags.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,CAAN,IAAY,IAoCX;AApCD,WAAY,IAAI;IACd,iEAAiE;IACjE,kDAAkD;IAClD,2CAAmC,CAAA;IACnC,uCAA+B,CAAA;IAC/B,2CAAmC,CAAA;IACnC,uCAA+B,CAAA;IAE/B,yEAAyE;IACzE,mCAA2B,CAAA;IAC3B,mCAA2B,CAAA;IAE3B,8DAA8D;IAC9D,6CAAqC,CAAA;IAErC,iEAAiE;IACjE,sDAAsD;IACtD,yCAAiC,CAAA;IACjC,yCAAiC,CAAA;IAEjC,kFAAkF;IAClF,sCAA8B,CAAA;IAE9B,6EAA6E;IAC7E,yDAAiD,CAAA;IACjD,iDAAyC,CAAA;IAEzC,yEAAyE;IACzE,+CAAuC,CAAA;IACvC,mDAA2C,CAAA;IAE3C,yDAAyD;IACzD,oCAA4B,CAAA;IAE5B,6DAA6D;IAC7D,qDAA6C,CAAA;AAC/C,CAAC,EApCW,IAAI,KAAJ,IAAI,QAoCf;AAYD,MAAM,UAAU,IAAI,CAAC,CAAO;IAC1B,OAAO,EAAE,IAAI,EAAE,CAAC,EAAqB,CAAC;AACxC,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,KAAwB;IACjD,OAAO,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { type CoerceResult } from "./types.js";
|
|
3
|
+
import { Flag, type FlagWithContext } from "./flags.js";
|
|
4
|
+
export { Flag, type FlagWithContext } from "./flags.js";
|
|
5
|
+
export { type CoerceResult, type CoerceSuccess, type CoerceFailure, type CoerceError } from "./types.js";
|
|
6
|
+
export { JsonParseError } from "./parse.js";
|
|
7
|
+
/**
|
|
8
|
+
* Parse result from the main parse function.
|
|
9
|
+
*/
|
|
10
|
+
export type ParseResult<T> = {
|
|
11
|
+
success: true;
|
|
12
|
+
data: T;
|
|
13
|
+
flags: FlagWithContext[];
|
|
14
|
+
} | {
|
|
15
|
+
success: false;
|
|
16
|
+
error: ParseError;
|
|
17
|
+
};
|
|
18
|
+
/**
|
|
19
|
+
* Error from parsing.
|
|
20
|
+
*/
|
|
21
|
+
export interface ParseError {
|
|
22
|
+
type: "json_parse_error" | "coercion_error";
|
|
23
|
+
message: string;
|
|
24
|
+
path?: (string | number)[];
|
|
25
|
+
expected?: string;
|
|
26
|
+
received?: string;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* Parse a string into a typed value using a Zod schema.
|
|
30
|
+
*
|
|
31
|
+
* This is the main entry point for the Schema-Aligned Parser.
|
|
32
|
+
* It combines flexible JSON parsing with schema-aligned coercion.
|
|
33
|
+
*
|
|
34
|
+
* @example
|
|
35
|
+
* ```ts
|
|
36
|
+
* const UserSchema = z.object({
|
|
37
|
+
* name: z.string(),
|
|
38
|
+
* age: z.number(),
|
|
39
|
+
* });
|
|
40
|
+
*
|
|
41
|
+
* // Handles malformed JSON
|
|
42
|
+
* const result = parse(UserSchema, `{name: 'John', age: "25",}`);
|
|
43
|
+
* // → { success: true, data: { name: "John", age: 25 }, flags: [...] }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function parse<T extends z.ZodTypeAny>(schema: T, input: string): ParseResult<z.infer<T>>;
|
|
47
|
+
/**
|
|
48
|
+
* Parse a string into a typed value, throwing on error.
|
|
49
|
+
*
|
|
50
|
+
* @throws {Error} If parsing or coercion fails
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseOrThrow<T extends z.ZodTypeAny>(schema: T, input: string): z.infer<T>;
|
|
53
|
+
/**
|
|
54
|
+
* Coerce an already-parsed value to match a schema.
|
|
55
|
+
*
|
|
56
|
+
* Use this when you already have a parsed JavaScript value
|
|
57
|
+
* and just need schema-aligned coercion.
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```ts
|
|
61
|
+
* const data = JSON.parse(rawJson);
|
|
62
|
+
* const result = coerce(UserSchema, data);
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export declare function coerce<T extends z.ZodTypeAny>(schema: T, value: unknown): CoerceResult<z.infer<T>>;
|
|
66
|
+
/**
|
|
67
|
+
* Coerce a value to match a schema, throwing on error.
|
|
68
|
+
*
|
|
69
|
+
* @throws {Error} If coercion fails
|
|
70
|
+
*/
|
|
71
|
+
export declare function coerceOrThrow<T extends z.ZodTypeAny>(schema: T, value: unknown): z.infer<T>;
|
|
72
|
+
/**
|
|
73
|
+
* Check if a parse result has any coercion flags.
|
|
74
|
+
* Useful for detecting when values were transformed.
|
|
75
|
+
*/
|
|
76
|
+
export declare function hasFlags(result: ParseResult<unknown>): boolean;
|
|
77
|
+
/**
|
|
78
|
+
* Get the flag types from a parse result.
|
|
79
|
+
*/
|
|
80
|
+
export declare function getFlags(result: ParseResult<unknown>): Flag[];
|
|
81
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAGxB,OAAO,EAAE,KAAK,YAAY,EAAiB,MAAM,YAAY,CAAC;AAC9D,OAAO,EAAE,IAAI,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAGxD,OAAO,EAAE,IAAI,EAAE,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AACxD,OAAO,EAAE,KAAK,YAAY,EAAE,KAAK,aAAa,EAAE,KAAK,aAAa,EAAE,KAAK,WAAW,EAAE,MAAM,YAAY,CAAC;AACzG,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAE5C;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,IACrB;IAAE,OAAO,EAAE,IAAI,CAAC;IAAC,IAAI,EAAE,CAAC,CAAC;IAAC,KAAK,EAAE,eAAe,EAAE,CAAA;CAAE,GACpD;IAAE,OAAO,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,UAAU,CAAA;CAAE,CAAC;AAE1C;;GAEG;AACH,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,kBAAkB,GAAG,gBAAgB,CAAC;IAC5C,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC3B,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAC1C,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,MAAM,GACZ,WAAW,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CA8CzB;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EACjD,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,MAAM,GACZ,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAYZ;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,MAAM,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAC3C,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,OAAO,GACb,YAAY,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAE1B;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAClD,MAAM,EAAE,CAAC,EACT,KAAK,EAAE,OAAO,GACb,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CASZ;AAED;;;GAGG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,OAAO,CAE9D;AAED;;GAEG;AACH,wBAAgB,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,OAAO,CAAC,GAAG,IAAI,EAAE,CAG7D"}
|