@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
package/dist/index.js
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { parseJson, JsonParseError } from "./parse.js";
|
|
2
|
+
import { coerceToSchema } from "./coerce.js";
|
|
3
|
+
import { createContext } from "./types.js";
|
|
4
|
+
// Re-export types and utilities
|
|
5
|
+
export { Flag } from "./flags.js";
|
|
6
|
+
export { JsonParseError } from "./parse.js";
|
|
7
|
+
/**
|
|
8
|
+
* Parse a string into a typed value using a Zod schema.
|
|
9
|
+
*
|
|
10
|
+
* This is the main entry point for the Schema-Aligned Parser.
|
|
11
|
+
* It combines flexible JSON parsing with schema-aligned coercion.
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* ```ts
|
|
15
|
+
* const UserSchema = z.object({
|
|
16
|
+
* name: z.string(),
|
|
17
|
+
* age: z.number(),
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // Handles malformed JSON
|
|
21
|
+
* const result = parse(UserSchema, `{name: 'John', age: "25",}`);
|
|
22
|
+
* // → { success: true, data: { name: "John", age: 25 }, flags: [...] }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export function parse(schema, input) {
|
|
26
|
+
// Phase 1: Flexible JSON parsing
|
|
27
|
+
let parsed;
|
|
28
|
+
let parseFlags = [];
|
|
29
|
+
try {
|
|
30
|
+
const parseResult = parseJson(input);
|
|
31
|
+
parsed = parseResult.value;
|
|
32
|
+
parseFlags = parseResult.flags;
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
if (e instanceof JsonParseError) {
|
|
36
|
+
return {
|
|
37
|
+
success: false,
|
|
38
|
+
error: {
|
|
39
|
+
type: "json_parse_error",
|
|
40
|
+
message: e.message,
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
throw e;
|
|
45
|
+
}
|
|
46
|
+
// Phase 2: Schema-aligned coercion
|
|
47
|
+
const ctx = createContext();
|
|
48
|
+
ctx.flags.push(...parseFlags);
|
|
49
|
+
const result = coerceToSchema(schema, parsed, ctx);
|
|
50
|
+
if (result.success) {
|
|
51
|
+
return {
|
|
52
|
+
success: true,
|
|
53
|
+
data: result.value,
|
|
54
|
+
flags: result.flags,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
return {
|
|
58
|
+
success: false,
|
|
59
|
+
error: {
|
|
60
|
+
type: "coercion_error",
|
|
61
|
+
message: result.error.message,
|
|
62
|
+
path: result.error.path,
|
|
63
|
+
expected: result.error.expected,
|
|
64
|
+
received: result.error.received,
|
|
65
|
+
},
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Parse a string into a typed value, throwing on error.
|
|
70
|
+
*
|
|
71
|
+
* @throws {Error} If parsing or coercion fails
|
|
72
|
+
*/
|
|
73
|
+
export function parseOrThrow(schema, input) {
|
|
74
|
+
const result = parse(schema, input);
|
|
75
|
+
if (!result.success) {
|
|
76
|
+
const error = result.error;
|
|
77
|
+
const path = error.path?.join(".") ?? "";
|
|
78
|
+
throw new Error(`Parse error${path ? ` at ${path}` : ""}: ${error.message}`);
|
|
79
|
+
}
|
|
80
|
+
return result.data;
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Coerce an already-parsed value to match a schema.
|
|
84
|
+
*
|
|
85
|
+
* Use this when you already have a parsed JavaScript value
|
|
86
|
+
* and just need schema-aligned coercion.
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* ```ts
|
|
90
|
+
* const data = JSON.parse(rawJson);
|
|
91
|
+
* const result = coerce(UserSchema, data);
|
|
92
|
+
* ```
|
|
93
|
+
*/
|
|
94
|
+
export function coerce(schema, value) {
|
|
95
|
+
return coerceToSchema(schema, value);
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* Coerce a value to match a schema, throwing on error.
|
|
99
|
+
*
|
|
100
|
+
* @throws {Error} If coercion fails
|
|
101
|
+
*/
|
|
102
|
+
export function coerceOrThrow(schema, value) {
|
|
103
|
+
const result = coerce(schema, value);
|
|
104
|
+
if (!result.success) {
|
|
105
|
+
const path = result.error.path.join(".") || "<root>";
|
|
106
|
+
throw new Error(`Coercion error at ${path}: ${result.error.message}`);
|
|
107
|
+
}
|
|
108
|
+
return result.value;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Check if a parse result has any coercion flags.
|
|
112
|
+
* Useful for detecting when values were transformed.
|
|
113
|
+
*/
|
|
114
|
+
export function hasFlags(result) {
|
|
115
|
+
return result.success && result.flags.length > 0;
|
|
116
|
+
}
|
|
117
|
+
/**
|
|
118
|
+
* Get the flag types from a parse result.
|
|
119
|
+
*/
|
|
120
|
+
export function getFlags(result) {
|
|
121
|
+
if (!result.success)
|
|
122
|
+
return [];
|
|
123
|
+
return result.flags.map((f) => f.flag);
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/parse.d.ts
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type FlagWithContext } from "./flags.js";
|
|
2
|
+
export interface ParseResult {
|
|
3
|
+
value: unknown;
|
|
4
|
+
flags: FlagWithContext[];
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* LLM outputs are notoriously messy - they wrap JSON in markdown, add
|
|
8
|
+
* explanatory text, use single quotes, leave trailing commas, etc.
|
|
9
|
+
*
|
|
10
|
+
* We try progressively more aggressive strategies to extract valid JSON,
|
|
11
|
+
* preferring minimal intervention (so we try JSON.parse first before repair).
|
|
12
|
+
*/
|
|
13
|
+
export declare function parseJson(input: string): ParseResult;
|
|
14
|
+
export declare class JsonParseError extends Error {
|
|
15
|
+
constructor(message: string);
|
|
16
|
+
}
|
|
17
|
+
//# sourceMappingURL=parse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AACA,OAAO,EAAc,KAAK,eAAe,EAAE,MAAM,YAAY,CAAC;AAE9D,MAAM,WAAW,WAAW;IAC1B,KAAK,EAAE,OAAO,CAAC;IACf,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;;;;;GAMG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,MAAM,GAAG,WAAW,CAuDpD;AA2FD,qBAAa,cAAe,SAAQ,KAAK;gBAC3B,OAAO,EAAE,MAAM;CAI5B"}
|
package/dist/parse.js
ADDED
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { jsonrepair } from "jsonrepair";
|
|
2
|
+
import { Flag, flag } from "./flags.js";
|
|
3
|
+
/**
|
|
4
|
+
* LLM outputs are notoriously messy - they wrap JSON in markdown, add
|
|
5
|
+
* explanatory text, use single quotes, leave trailing commas, etc.
|
|
6
|
+
*
|
|
7
|
+
* We try progressively more aggressive strategies to extract valid JSON,
|
|
8
|
+
* preferring minimal intervention (so we try JSON.parse first before repair).
|
|
9
|
+
*/
|
|
10
|
+
export function parseJson(input) {
|
|
11
|
+
const trimmed = input.trim();
|
|
12
|
+
const flags = [];
|
|
13
|
+
// Fast path: if it's already valid JSON, don't waste time on extraction/repair
|
|
14
|
+
try {
|
|
15
|
+
return { value: JSON.parse(trimmed), flags };
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
// Expected for most LLM outputs - continue to extraction strategies
|
|
19
|
+
}
|
|
20
|
+
// LLMs love wrapping responses in ```json blocks, especially ChatGPT
|
|
21
|
+
const markdownResult = extractFromMarkdown(trimmed);
|
|
22
|
+
if (markdownResult !== null) {
|
|
23
|
+
flags.push(flag(Flag.ExtractedFromMarkdown));
|
|
24
|
+
try {
|
|
25
|
+
return { value: JSON.parse(markdownResult), flags };
|
|
26
|
+
}
|
|
27
|
+
catch {
|
|
28
|
+
// The extracted content might still have syntax issues
|
|
29
|
+
try {
|
|
30
|
+
const repaired = jsonrepair(markdownResult);
|
|
31
|
+
flags.push(flag(Flag.JsonRepaired));
|
|
32
|
+
return { value: JSON.parse(repaired), flags };
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
// Markdown extraction didn't help, try other strategies
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
// LLMs often prefix JSON with "Here's the result:" or similar
|
|
40
|
+
const extracted = extractJsonFromText(trimmed);
|
|
41
|
+
if (extracted !== null && extracted !== trimmed) {
|
|
42
|
+
flags.push(flag(Flag.ExtractedFromText));
|
|
43
|
+
try {
|
|
44
|
+
return { value: JSON.parse(extracted), flags };
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
try {
|
|
48
|
+
const repaired = jsonrepair(extracted);
|
|
49
|
+
flags.push(flag(Flag.JsonRepaired));
|
|
50
|
+
return { value: JSON.parse(repaired), flags };
|
|
51
|
+
}
|
|
52
|
+
catch {
|
|
53
|
+
// Extraction didn't help, try repairing the whole thing
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
// Last resort: let jsonrepair try to fix whatever syntax issues exist
|
|
58
|
+
// (trailing commas, unquoted keys, single quotes, comments, etc.)
|
|
59
|
+
try {
|
|
60
|
+
const repaired = jsonrepair(trimmed);
|
|
61
|
+
flags.push(flag(Flag.JsonRepaired));
|
|
62
|
+
return { value: JSON.parse(repaired), flags };
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
throw new JsonParseError(`Failed to parse JSON: ${trimmed.slice(0, 100)}...`);
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* ChatGPT and Claude often wrap JSON in markdown code blocks.
|
|
70
|
+
* We extract the content between the backticks.
|
|
71
|
+
*/
|
|
72
|
+
function extractFromMarkdown(input) {
|
|
73
|
+
const codeBlockMatch = input.match(/```(?:json)?\s*\n?([\s\S]*?)\n?```/);
|
|
74
|
+
if (codeBlockMatch?.[1]) {
|
|
75
|
+
return codeBlockMatch[1].trim();
|
|
76
|
+
}
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* LLMs often add context around JSON: "Here's your data: {...} Let me know if..."
|
|
81
|
+
* We find balanced braces/brackets to extract just the JSON portion.
|
|
82
|
+
*
|
|
83
|
+
* Uses a simple state machine to handle strings (so braces inside strings
|
|
84
|
+
* don't confuse the matching) and escape sequences.
|
|
85
|
+
*/
|
|
86
|
+
function extractJsonFromText(input) {
|
|
87
|
+
const objectStart = input.indexOf("{");
|
|
88
|
+
const arrayStart = input.indexOf("[");
|
|
89
|
+
let start;
|
|
90
|
+
let openChar;
|
|
91
|
+
let closeChar;
|
|
92
|
+
if (objectStart === -1 && arrayStart === -1) {
|
|
93
|
+
return null;
|
|
94
|
+
}
|
|
95
|
+
else if (objectStart === -1) {
|
|
96
|
+
start = arrayStart;
|
|
97
|
+
openChar = "[";
|
|
98
|
+
closeChar = "]";
|
|
99
|
+
}
|
|
100
|
+
else if (arrayStart === -1) {
|
|
101
|
+
start = objectStart;
|
|
102
|
+
openChar = "{";
|
|
103
|
+
closeChar = "}";
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
// Use whichever structure appears first in the text
|
|
107
|
+
if (objectStart < arrayStart) {
|
|
108
|
+
start = objectStart;
|
|
109
|
+
openChar = "{";
|
|
110
|
+
closeChar = "}";
|
|
111
|
+
}
|
|
112
|
+
else {
|
|
113
|
+
start = arrayStart;
|
|
114
|
+
openChar = "[";
|
|
115
|
+
closeChar = "]";
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// Track nesting depth, ignoring braces inside strings
|
|
119
|
+
let depth = 0;
|
|
120
|
+
let inString = false;
|
|
121
|
+
let escapeNext = false;
|
|
122
|
+
for (let i = start; i < input.length; i++) {
|
|
123
|
+
const char = input[i];
|
|
124
|
+
if (escapeNext) {
|
|
125
|
+
escapeNext = false;
|
|
126
|
+
continue;
|
|
127
|
+
}
|
|
128
|
+
if (char === "\\") {
|
|
129
|
+
escapeNext = true;
|
|
130
|
+
continue;
|
|
131
|
+
}
|
|
132
|
+
if (char === '"') {
|
|
133
|
+
inString = !inString;
|
|
134
|
+
continue;
|
|
135
|
+
}
|
|
136
|
+
if (inString)
|
|
137
|
+
continue;
|
|
138
|
+
if (char === openChar) {
|
|
139
|
+
depth++;
|
|
140
|
+
}
|
|
141
|
+
else if (char === closeChar) {
|
|
142
|
+
depth--;
|
|
143
|
+
if (depth === 0) {
|
|
144
|
+
return input.slice(start, i + 1);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// Unclosed JSON - return what we have, jsonrepair might fix it
|
|
149
|
+
return input.slice(start);
|
|
150
|
+
}
|
|
151
|
+
export class JsonParseError extends Error {
|
|
152
|
+
constructor(message) {
|
|
153
|
+
super(message);
|
|
154
|
+
this.name = "JsonParseError";
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
//# sourceMappingURL=parse.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { FlagWithContext } from "./flags.js";
|
|
3
|
+
/**
|
|
4
|
+
* Result of successful coercion, including the value and any transformation flags.
|
|
5
|
+
*/
|
|
6
|
+
export interface CoerceSuccess<T> {
|
|
7
|
+
success: true;
|
|
8
|
+
value: T;
|
|
9
|
+
flags: FlagWithContext[];
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Result of failed coercion, including error details.
|
|
13
|
+
*/
|
|
14
|
+
export interface CoerceFailure {
|
|
15
|
+
success: false;
|
|
16
|
+
error: CoerceError;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Combined result type for coercion.
|
|
20
|
+
*/
|
|
21
|
+
export type CoerceResult<T> = CoerceSuccess<T> | CoerceFailure;
|
|
22
|
+
/**
|
|
23
|
+
* Error that occurred during coercion.
|
|
24
|
+
*/
|
|
25
|
+
export interface CoerceError {
|
|
26
|
+
message: string;
|
|
27
|
+
path: (string | number)[];
|
|
28
|
+
expected: string;
|
|
29
|
+
received: string;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Context passed through the coercion process.
|
|
33
|
+
*/
|
|
34
|
+
export interface CoerceContext {
|
|
35
|
+
/** Current path in the object (for error messages) */
|
|
36
|
+
path: (string | number)[];
|
|
37
|
+
/** Accumulated flags */
|
|
38
|
+
flags: FlagWithContext[];
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Create a new coercion context.
|
|
42
|
+
*/
|
|
43
|
+
export declare function createContext(): CoerceContext;
|
|
44
|
+
/**
|
|
45
|
+
* Create a child context with an extended path.
|
|
46
|
+
*/
|
|
47
|
+
export declare function childContext(ctx: CoerceContext, segment: string | number): CoerceContext;
|
|
48
|
+
/**
|
|
49
|
+
* Create a success result.
|
|
50
|
+
*/
|
|
51
|
+
export declare function success<T>(value: T, ctx: CoerceContext): CoerceSuccess<T>;
|
|
52
|
+
/**
|
|
53
|
+
* Create a failure result.
|
|
54
|
+
*/
|
|
55
|
+
export declare function failure(message: string, ctx: CoerceContext, expected: string, received: string): CoerceFailure;
|
|
56
|
+
/**
|
|
57
|
+
* Type helper to extract the inferred type from a Zod schema.
|
|
58
|
+
*/
|
|
59
|
+
export type InferSchema<T extends z.ZodTypeAny> = z.infer<T>;
|
|
60
|
+
/**
|
|
61
|
+
* Get a human-readable type description for an unknown value.
|
|
62
|
+
*/
|
|
63
|
+
export declare function describeType(value: unknown): string;
|
|
64
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAElD;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC;IAC9B,OAAO,EAAE,IAAI,CAAC;IACd,KAAK,EAAE,CAAC,CAAC;IACT,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,WAAW,CAAC;CACpB;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,CAAC,CAAC,IAAI,aAAa,CAAC,CAAC,CAAC,GAAG,aAAa,CAAC;AAE/D;;GAEG;AACH,MAAM,WAAW,WAAW;IAC1B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC1B,QAAQ,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,MAAM,WAAW,aAAa;IAC5B,sDAAsD;IACtD,IAAI,EAAE,CAAC,MAAM,GAAG,MAAM,CAAC,EAAE,CAAC;IAC1B,wBAAwB;IACxB,KAAK,EAAE,eAAe,EAAE,CAAC;CAC1B;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,aAAa,CAE7C;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,GAAG,aAAa,CAKxF;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,EAAE,GAAG,EAAE,aAAa,GAAG,aAAa,CAAC,CAAC,CAAC,CAEzE;AAED;;GAEG;AACH,wBAAgB,OAAO,CACrB,OAAO,EAAE,MAAM,EACf,GAAG,EAAE,aAAa,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,GACf,aAAa,CAUf;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AAE7D;;GAEG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAKnD"}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Create a new coercion context.
|
|
3
|
+
*/
|
|
4
|
+
export function createContext() {
|
|
5
|
+
return { path: [], flags: [] };
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Create a child context with an extended path.
|
|
9
|
+
*/
|
|
10
|
+
export function childContext(ctx, segment) {
|
|
11
|
+
return {
|
|
12
|
+
path: [...ctx.path, segment],
|
|
13
|
+
flags: ctx.flags, // Share flags array
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Create a success result.
|
|
18
|
+
*/
|
|
19
|
+
export function success(value, ctx) {
|
|
20
|
+
return { success: true, value, flags: ctx.flags };
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Create a failure result.
|
|
24
|
+
*/
|
|
25
|
+
export function failure(message, ctx, expected, received) {
|
|
26
|
+
return {
|
|
27
|
+
success: false,
|
|
28
|
+
error: {
|
|
29
|
+
message,
|
|
30
|
+
path: ctx.path,
|
|
31
|
+
expected,
|
|
32
|
+
received,
|
|
33
|
+
},
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Get a human-readable type description for an unknown value.
|
|
38
|
+
*/
|
|
39
|
+
export function describeType(value) {
|
|
40
|
+
if (value === null)
|
|
41
|
+
return "null";
|
|
42
|
+
if (value === undefined)
|
|
43
|
+
return "undefined";
|
|
44
|
+
if (Array.isArray(value))
|
|
45
|
+
return "array";
|
|
46
|
+
return typeof value;
|
|
47
|
+
}
|
|
48
|
+
//# sourceMappingURL=types.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AA6CA;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,OAAO,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,CAAC;AACjC,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,GAAkB,EAAE,OAAwB;IACvE,OAAO;QACL,IAAI,EAAE,CAAC,GAAG,GAAG,CAAC,IAAI,EAAE,OAAO,CAAC;QAC5B,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,oBAAoB;KACvC,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CAAI,KAAQ,EAAE,GAAkB;IACrD,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,GAAG,CAAC,KAAK,EAAE,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,OAAO,CACrB,OAAe,EACf,GAAkB,EAClB,QAAgB,EAChB,QAAgB;IAEhB,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE;YACL,OAAO;YACP,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,QAAQ;YACR,QAAQ;SACT;KACF,CAAC;AACJ,CAAC;AAOD;;GAEG;AACH,MAAM,UAAU,YAAY,CAAC,KAAc;IACzC,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IAClC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,WAAW,CAAC;IAC5C,IAAI,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAAE,OAAO,OAAO,CAAC;IACzC,OAAO,OAAO,KAAK,CAAC;AACtB,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@hoangvu12/yomi",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Yomi (読み) - Flexible JSON parser that interprets LLM output to match Zod schemas",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"types": "./dist/index.d.ts"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"lint": "eslint src --ext .ts",
|
|
17
|
+
"typecheck": "tsc --noEmit",
|
|
18
|
+
"test": "vitest",
|
|
19
|
+
"prepublishOnly": "bun run build"
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"json",
|
|
23
|
+
"parser",
|
|
24
|
+
"llm",
|
|
25
|
+
"zod",
|
|
26
|
+
"coerce",
|
|
27
|
+
"schema",
|
|
28
|
+
"ai",
|
|
29
|
+
"openai",
|
|
30
|
+
"anthropic",
|
|
31
|
+
"structured-output"
|
|
32
|
+
],
|
|
33
|
+
"author": "hoangvu12",
|
|
34
|
+
"repository": {
|
|
35
|
+
"type": "git",
|
|
36
|
+
"url": "git+https://github.com/hoangvu12/yomi.git"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://github.com/hoangvu12/yomi#readme",
|
|
39
|
+
"bugs": {
|
|
40
|
+
"url": "https://github.com/hoangvu12/yomi/issues"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"jsonrepair": "^3.8.0"
|
|
44
|
+
},
|
|
45
|
+
"peerDependencies": {
|
|
46
|
+
"zod": "^3.20.0"
|
|
47
|
+
},
|
|
48
|
+
"devDependencies": {
|
|
49
|
+
"@types/node": "^20.10.0",
|
|
50
|
+
"typescript": "^5.3.0",
|
|
51
|
+
"vitest": "^2.0.0",
|
|
52
|
+
"eslint": "^8.56.0",
|
|
53
|
+
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
|
54
|
+
"@typescript-eslint/parser": "^6.0.0",
|
|
55
|
+
"zod": "^3.23.8"
|
|
56
|
+
},
|
|
57
|
+
"files": [
|
|
58
|
+
"dist"
|
|
59
|
+
],
|
|
60
|
+
"license": "MIT"
|
|
61
|
+
}
|