@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.
Files changed (42) hide show
  1. package/README.md +191 -0
  2. package/dist/coerce.d.ts +8 -0
  3. package/dist/coerce.d.ts.map +1 -0
  4. package/dist/coerce.js +207 -0
  5. package/dist/coerce.js.map +1 -0
  6. package/dist/coercers/array.d.ts +20 -0
  7. package/dist/coercers/array.d.ts.map +1 -0
  8. package/dist/coercers/array.js +77 -0
  9. package/dist/coercers/array.js.map +1 -0
  10. package/dist/coercers/enum.d.ts +12 -0
  11. package/dist/coercers/enum.d.ts.map +1 -0
  12. package/dist/coercers/enum.js +62 -0
  13. package/dist/coercers/enum.js.map +1 -0
  14. package/dist/coercers/object.d.ts +23 -0
  15. package/dist/coercers/object.d.ts.map +1 -0
  16. package/dist/coercers/object.js +75 -0
  17. package/dist/coercers/object.js.map +1 -0
  18. package/dist/coercers/primitive.d.ts +33 -0
  19. package/dist/coercers/primitive.d.ts.map +1 -0
  20. package/dist/coercers/primitive.js +160 -0
  21. package/dist/coercers/primitive.js.map +1 -0
  22. package/dist/coercers/union.d.ts +35 -0
  23. package/dist/coercers/union.d.ts.map +1 -0
  24. package/dist/coercers/union.js +82 -0
  25. package/dist/coercers/union.js.map +1 -0
  26. package/dist/flags.d.ts +44 -0
  27. package/dist/flags.d.ts.map +1 -0
  28. package/dist/flags.js +42 -0
  29. package/dist/flags.js.map +1 -0
  30. package/dist/index.d.ts +81 -0
  31. package/dist/index.d.ts.map +1 -0
  32. package/dist/index.js +125 -0
  33. package/dist/index.js.map +1 -0
  34. package/dist/parse.d.ts +17 -0
  35. package/dist/parse.d.ts.map +1 -0
  36. package/dist/parse.js +157 -0
  37. package/dist/parse.js.map +1 -0
  38. package/dist/types.d.ts +64 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +48 -0
  41. package/dist/types.js.map +1 -0
  42. 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":"AACA,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AACvD,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAqB,aAAa,EAAE,MAAM,YAAY,CAAC;AAG9D,gCAAgC;AAChC,OAAO,EAAE,IAAI,EAAwB,MAAM,YAAY,CAAC;AAExD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAoB5C;;;;;;;;;;;;;;;;;GAiBG;AACH,MAAM,UAAU,KAAK,CACnB,MAAS,EACT,KAAa;IAEb,iCAAiC;IACjC,IAAI,MAAe,CAAC;IACpB,IAAI,UAAU,GAAsB,EAAE,CAAC;IAEvC,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,SAAS,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,GAAG,WAAW,CAAC,KAAK,CAAC;QAC3B,UAAU,GAAG,WAAW,CAAC,KAAK,CAAC;IACjC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,IAAI,CAAC,YAAY,cAAc,EAAE,CAAC;YAChC,OAAO;gBACL,OAAO,EAAE,KAAK;gBACd,KAAK,EAAE;oBACL,IAAI,EAAE,kBAAkB;oBACxB,OAAO,EAAE,CAAC,CAAC,OAAO;iBACnB;aACF,CAAC;QACJ,CAAC;QACD,MAAM,CAAC,CAAC;IACV,CAAC;IAED,mCAAmC;IACnC,MAAM,GAAG,GAAG,aAAa,EAAE,CAAC;IAC5B,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,CAAC,CAAC;IAE9B,MAAM,MAAM,GAAG,cAAc,CAAC,MAAM,EAAE,MAAM,EAAE,GAAG,CAAC,CAAC;IAEnD,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QACnB,OAAO;YACL,OAAO,EAAE,IAAI;YACb,IAAI,EAAE,MAAM,CAAC,KAAK;YAClB,KAAK,EAAE,MAAM,CAAC,KAAK;SACpB,CAAC;IACJ,CAAC;IAED,OAAO;QACL,OAAO,EAAE,KAAK;QACd,KAAK,EAAE;YACL,IAAI,EAAE,gBAAgB;YACtB,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO;YAC7B,IAAI,EAAE,MAAM,CAAC,KAAK,CAAC,IAAI;YACvB,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;YAC/B,QAAQ,EAAE,MAAM,CAAC,KAAK,CAAC,QAAQ;SAChC;KACF,CAAC;AACJ,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAC1B,MAAS,EACT,KAAa;IAEb,MAAM,MAAM,GAAG,KAAK,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAEpC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;QACzC,MAAM,IAAI,KAAK,CACb,cAAc,IAAI,CAAC,CAAC,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,KAAK,KAAK,CAAC,OAAO,EAAE,CAC5D,CAAC;IACJ,CAAC;IAED,OAAO,MAAM,CAAC,IAAI,CAAC;AACrB,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,UAAU,MAAM,CACpB,MAAS,EACT,KAAc;IAEd,OAAO,cAAc,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;AACvC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAC3B,MAAS,EACT,KAAc;IAEd,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;IAErC,IAAI,CAAC,MAAM,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,IAAI,GAAG,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,QAAQ,CAAC;QACrD,MAAM,IAAI,KAAK,CAAC,qBAAqB,IAAI,KAAK,MAAM,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,MAAM,CAAC,KAAK,CAAC;AACtB,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,QAAQ,CAAC,MAA4B;IACnD,OAAO,MAAM,CAAC,OAAO,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC;AACnD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,QAAQ,CAAC,MAA4B;IACnD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,EAAE,CAAC;IAC/B,OAAO,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;AACzC,CAAC"}
@@ -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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"}
@@ -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
+ }