refactor: extract repeated code block detection logic into method

- Extract isInsideCodeBlock() method from DirectiveStreamingParser
- Replace duplicate code in onopentag and onclosetag handlers
- Add comprehensive test coverage for the extracted logic
- Improve code maintainability and follow DRY principle
This commit is contained in:
Steven T. Cramer 2025-06-16 22:51:19 +07:00
parent b879dd21b6
commit e7289bdc33
2 changed files with 46 additions and 10 deletions

View file

@ -27,11 +27,7 @@ export class DirectiveStreamingParser {
parser.onopentag = (node: sax.Tag) => {
// Check if we're inside a code block (either global or within tool parameters)
const insideCodeBlock =
context.codeBlockState === CodeBlockState.INSIDE ||
(activeHandler &&
"isInsideParameterCodeBlock" in activeHandler &&
(activeHandler as any).isInsideParameterCodeBlock())
const insideCodeBlock = this.isInsideCodeBlock(context, activeHandler)
// Check if we're inside a tool parameter (but not at the parameter level itself)
const insideToolParameter =
@ -65,11 +61,7 @@ export class DirectiveStreamingParser {
parser.onclosetag = (tagName: string) => {
// Check if we're inside a code block (either global or within tool parameters)
const insideCodeBlock =
context.codeBlockState === CodeBlockState.INSIDE ||
(activeHandler &&
"isInsideParameterCodeBlock" in activeHandler &&
(activeHandler as any).isInsideParameterCodeBlock())
const insideCodeBlock = this.isInsideCodeBlock(context, activeHandler)
// Check if we're inside a tool parameter (but not at the parameter level itself)
const insideToolParameter =
@ -130,6 +122,18 @@ export class DirectiveStreamingParser {
return context.contentBlocks
}
/**
* Check if we're inside a code block (either global or within tool parameters)
*/
private static isInsideCodeBlock(context: ParseContext, activeHandler: any): boolean {
return (
context.codeBlockState === CodeBlockState.INSIDE ||
(activeHandler &&
"isInsideParameterCodeBlock" in activeHandler &&
(activeHandler as any).isInsideParameterCodeBlock())
)
}
/**
* Convert SAX node attributes to string representation
*/

View file

@ -297,4 +297,36 @@ I've provided an example of the XML format for the log_message directive.</resul
const logMessages = result.filter((r) => r.type === "log_message")
expect(logMessages).toHaveLength(0)
})
test("should correctly identify code block contexts in various scenarios", () => {
// Test that the extracted isInsideCodeBlock logic works correctly
// by testing scenarios that depend on this logic
// Test 1: Code block should prevent directive parsing
const codeBlockInput = "Text ```\n<log_message><message>Should not parse</message></log_message>\n``` end"
const codeBlockResult = DirectiveStreamingParser.parse(codeBlockInput)
expect(codeBlockResult).toHaveLength(1)
expect(codeBlockResult[0].type).toBe("text")
expect((codeBlockResult[0] as any).content).toContain("<log_message>")
// Test 2: Tool parameter code block should prevent directive parsing
const toolParamCodeBlockInput =
"<attempt_completion><result>```\n<log_message><message>Should not parse</message></log_message>\n```</result></attempt_completion>"
const toolParamResult = DirectiveStreamingParser.parse(toolParamCodeBlockInput)
expect(toolParamResult).toHaveLength(1)
expect(toolParamResult[0].type).toBe("tool_use")
expect((toolParamResult[0] as any).name).toBe("attempt_completion")
expect((toolParamResult[0] as any).params.result).toContain("<log_message>")
// Ensure no separate log_message directive was created
const logMessages = toolParamResult.filter((r) => r.type === "log_message")
expect(logMessages).toHaveLength(0)
// Test 3: Normal directive parsing outside code blocks should still work
const normalInput = "<log_message><message>Should parse normally</message><level>info</level></log_message>"
const normalResult = DirectiveStreamingParser.parse(normalInput)
expect(normalResult).toHaveLength(1)
expect(normalResult[0].type).toBe("log_message")
expect((normalResult[0] as any).message).toBe("Should parse normally")
})
})