From d8b5633442f3a489ed937c71ade8145417583496 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste THERY Date: Mon, 24 Aug 2026 14:42:21 +0700 Subject: [PATCH] fix(core): support multi-document YAML ingestion Release highlights: - Index multi-document YAML streams without rejecting valid project files. Release details: - Parse YAML streams in order, omit null documents, and preserve parser errors. - Cover multi-document, single-document, empty-document, and invalid-stream regressions. Verification: - pnpm validate - Isolated rgr ingest and search reproduction for issue #159. Fixes #159 --- packages/ragmir-core/src/parsing.test.ts | 50 ++++++++++++++++++++++++ packages/ragmir-core/src/parsing.ts | 14 ++++++- 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/packages/ragmir-core/src/parsing.test.ts b/packages/ragmir-core/src/parsing.test.ts index 2dbfb0b..9177a45 100644 --- a/packages/ragmir-core/src/parsing.test.ts +++ b/packages/ragmir-core/src/parsing.test.ts @@ -38,6 +38,56 @@ describe("parseFile", () => { expect(parsed.text).not.toContain("hidden image") }) + it("should concatenate non-empty YAML documents in source order", async () => { + const root = await mkdtemp(path.join(os.tmpdir(), "ragmir-yaml-stream-")) + tempDirs.push(root) + const filePath = path.join(root, "context.yaml") + await writeFile( + filePath, + [ + "---", + 'project_context: "test"', + "quality_score: 5", + "---", + "---", + "# Title", + "", + "This is the body of the YAML document.", + ].join("\n"), + "utf8", + ) + + const parsed = await parseFile(sourceFile(root, filePath, ".yaml")) + + expect(parsed.text).toContain("project_context") + expect(parsed.text).toContain("quality_score: 5") + expect(parsed.text).toContain("This is the body of the YAML document.") + expect(parsed.text.indexOf("project_context")).toBeLessThan( + parsed.text.indexOf("This is the body of the YAML document."), + ) + expect(parsed.text).not.toMatch(/(^|\n)null($|\n)/u) + }) + + it("should preserve single-document YAML parsing", async () => { + const root = await mkdtemp(path.join(os.tmpdir(), "ragmir-yaml-single-")) + tempDirs.push(root) + const filePath = path.join(root, "context.yml") + await writeFile(filePath, "project: ragmir\nquality: 5\n", "utf8") + + const parsed = await parseFile(sourceFile(root, filePath, ".yml")) + + expect(parsed.text).toBe("project: ragmir\nquality: 5") + }) + + it("should reject invalid documents in a YAML stream", async () => { + const root = await mkdtemp(path.join(os.tmpdir(), "ragmir-yaml-invalid-")) + tempDirs.push(root) + const filePath = path.join(root, "invalid.yaml") + await writeFile(filePath, "---\nvalid: true\n---\nbroken: [\n", "utf8") + + await expect(parseFile(sourceFile(root, filePath, ".yaml"))).rejects.toThrow(/Flow sequence/iu) + }) + it("extracts text from docx files", async () => { const root = await mkdtemp(path.join(os.tmpdir(), "ragmir-docx-")) tempDirs.push(root) diff --git a/packages/ragmir-core/src/parsing.ts b/packages/ragmir-core/src/parsing.ts index e0d65b0..2be2cc2 100644 --- a/packages/ragmir-core/src/parsing.ts +++ b/packages/ragmir-core/src/parsing.ts @@ -118,7 +118,19 @@ export async function parseFile( } case ".yaml": case ".yml": { - text = YAML.stringify(YAML.parse(await readFile(file.absolutePath, "utf8"))) + const documents = YAML.parseAllDocuments(await readFile(file.absolutePath, "utf8")) + for (const document of documents) { + const [error] = document.errors + if (error) { + throw error + } + } + text = documents + .flatMap((document) => { + const value = document.toJS() + return value === null ? [] : [YAML.stringify(value)] + }) + .join("\n") break } case ".rtf":