Skip to content

Commit d4be30d

Browse files
committed
refactor: extract shared parser runtime to core-parser.ts
Both parser.ts and beta-parser.ts contained an identical parseOutputFormat implementation (18 lines each): resolve the format object, check for json_schema type, call format.parse() or JSON.parse(), throw AnthropicError on failure. Extract that shared runtime to src/lib/core-parser.ts as parseAccumulatedFormat(format, content). Both parsers now import and delegate to it, removing the AnthropicError import from each. The type-level logic (conditional types, getOutputFormat, deprecated output_format shim, .parsed getter) stays file-local — it is intentionally different between the stable and beta paths and has zero runtime cost. Behaviour preserved exactly: same error message, same fallback to JSON.parse, same null return when format is absent or non-json_schema.
1 parent 872b623 commit d4be30d

File tree

3 files changed

+40
-30
lines changed

3 files changed

+40
-30
lines changed

src/lib/beta-parser.ts

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Logger } from '../client';
2-
import { AnthropicError } from '../core/error';
2+
import { parseAccumulatedFormat } from './core-parser';
33
import {
44
BetaContentBlock,
55
BetaJSONOutputFormat,
@@ -10,6 +10,7 @@ import {
1010
} from '../resources/beta/messages/messages';
1111

1212
import { Simplify } from './type-utils';
13+
1314
type AutoParseableBetaOutputConfig = Omit<BetaOutputConfig, 'format'> & {
1415
format?: BetaJSONOutputFormat | AutoParseableBetaOutputFormat<any> | null;
1516
};
@@ -129,18 +130,8 @@ function parseBetaOutputFormat<Params extends BetaParseableMessageCreateParams>(
129130
params: Params,
130131
content: string,
131132
): ExtractParsedContentFromBetaParams<Params> | null {
132-
const outputFormat = getOutputFormat(params);
133-
if (outputFormat?.type !== 'json_schema') {
134-
return null;
135-
}
136-
137-
try {
138-
if ('parse' in outputFormat) {
139-
return outputFormat.parse(content);
140-
}
141-
142-
return JSON.parse(content);
143-
} catch (error) {
144-
throw new AnthropicError(`Failed to parse structured output: ${error}`);
145-
}
133+
return parseAccumulatedFormat(
134+
getOutputFormat(params),
135+
content,
136+
) as ExtractParsedContentFromBetaParams<Params> | null;
146137
}

src/lib/core-parser.ts

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import { AnthropicError } from '../core/error';
2+
3+
/**
4+
* Shared parse-step runtime used by both parser.ts (stable) and beta-parser.ts.
5+
*
6+
* Accepts the resolved format object (already extracted from params by the
7+
* caller's getOutputFormat) and the accumulated text content. Returns the
8+
* parsed value, or null when the format is absent or non-parseable.
9+
*
10+
* Throws AnthropicError if the format is json_schema but parsing fails —
11+
* same behaviour that lived in each parser previously.
12+
*/
13+
export function parseAccumulatedFormat(
14+
format: { type: string; parse?: (content: string) => unknown } | null | undefined,
15+
content: string,
16+
): unknown | null {
17+
if (format?.type !== 'json_schema') {
18+
return null;
19+
}
20+
21+
try {
22+
if ('parse' in (format as object)) {
23+
return (format as { parse: (c: string) => unknown }).parse(content);
24+
}
25+
return JSON.parse(content);
26+
} catch (error) {
27+
throw new AnthropicError(`Failed to parse structured output: ${error}`);
28+
}
29+
}

src/lib/parser.ts

Lines changed: 5 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import type { Logger } from '../client';
2-
import { AnthropicError } from '../core/error';
2+
import { parseAccumulatedFormat } from './core-parser';
33
import {
44
ContentBlock,
55
JSONOutputFormat,
@@ -107,18 +107,8 @@ function parseOutputFormat<Params extends ParseableMessageCreateParams>(
107107
params: Params,
108108
content: string,
109109
): ExtractParsedContentFromParams<Params> | null {
110-
const outputFormat = getOutputFormat(params);
111-
if (outputFormat?.type !== 'json_schema') {
112-
return null;
113-
}
114-
115-
try {
116-
if ('parse' in outputFormat) {
117-
return outputFormat.parse(content);
118-
}
119-
120-
return JSON.parse(content);
121-
} catch (error) {
122-
throw new AnthropicError(`Failed to parse structured output: ${error}`);
123-
}
110+
return parseAccumulatedFormat(
111+
getOutputFormat(params),
112+
content,
113+
) as ExtractParsedContentFromParams<Params> | null;
124114
}

0 commit comments

Comments
 (0)