From 2ab21be452167031e154b578062851e38ab88496 Mon Sep 17 00:00:00 2001 From: ddbaron Date: Fri, 14 Aug 2026 20:16:52 -0500 Subject: [PATCH 1/2] fix(reader): resolve officeparser interop exports --- AGENTS.md | 1 + .../Pesticide Application Records.docx | Bin 0 -> 15467 bytes src/registry.ts | 57 ++++++++++++++++-- test/read-rich-document.test.ts | 48 ++++++++++++++- 4 files changed, 100 insertions(+), 6 deletions(-) create mode 100644 docs/maint-div/Pesticide Application Records.docx diff --git a/AGENTS.md b/AGENTS.md index 672ee9e..8f9e1ed 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -7,6 +7,7 @@ This file is the project's committed home for project-intrinsic agent knowledge: ## Project notes - The published package entry point and OpenCode tool registration live in `src/index.ts`; the reader, safety checks, format registry, and media extraction are split across `src/`. +- `src/registry.ts` resolves `officeparser` through named, default, and top-level exports because OpenCode's Bun loader can leave the named `OfficeParser` binding undefined even for version 7.5.1. - Run `npm run check && npm test` for the local typecheck and executable fixture suite. The DOCX, ODT, and PPTX fixtures are generated as real ZIP archives by `test/fixtures.ts`. ## Maintaining this file diff --git a/docs/maint-div/Pesticide Application Records.docx b/docs/maint-div/Pesticide Application Records.docx new file mode 100644 index 0000000000000000000000000000000000000000..fa0c5dcb0d86514926d2b7afd579b15fec4924a4 GIT binary patch literal 15467 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 GuKo`T71C+| literal 0 HcmV?d00001 diff --git a/src/registry.ts b/src/registry.ts index d9cafd4..8e7128f 100644 --- a/src/registry.ts +++ b/src/registry.ts @@ -1,13 +1,62 @@ -import { OfficeParser } from "officeparser"; +import * as officeParser from "officeparser"; import type { OfficeParserConfig, SupportedFileType } from "officeparser"; import type { RichDocumentFormat } from "./types.ts"; -function officeFormat(parserType: SupportedFileType): RichDocumentFormat { +type ParseOffice = RichDocumentFormat["parse"]; + +interface OfficeParserModuleValue { + OfficeParser?: unknown; + default?: unknown; + parseOffice?: unknown; +} + +interface ResolvedParser { + parseOffice: ParseOffice; + receiver: unknown; +} + +function moduleValue(value: unknown): OfficeParserModuleValue | undefined { + if ((typeof value !== "object" && typeof value !== "function") || value === null) return undefined; + return value as OfficeParserModuleValue; +} + +// Bun's CJS interop can leave the named OfficeParser binding undefined while +// retaining the default class and top-level parseOffice export. +function resolveOfficeParser(value: unknown, seen = new Set()): ResolvedParser | undefined { + const candidate = moduleValue(value); + if (!candidate) return undefined; + + const reference = value as object; + if (seen.has(reference)) return undefined; + seen.add(reference); + + for (const nested of [candidate.OfficeParser, candidate.default]) { + const resolved = resolveOfficeParser(nested, seen); + if (resolved) return resolved; + } + + if (typeof candidate.parseOffice === "function") { + return { parseOffice: candidate.parseOffice as ParseOffice, receiver: value }; + } + return undefined; +} + +function parserFor(module: unknown): ResolvedParser { + const parser = resolveOfficeParser(module); + if (!parser) throw new TypeError("officeparser does not expose a parseOffice function"); + return parser; +} + +export function createOfficeFormat( + parserType: SupportedFileType, + parserModule: unknown = officeParser, +): RichDocumentFormat { return { extension: `.${parserType}`, parserType, parse(input: Uint8Array, config: OfficeParserConfig) { - return OfficeParser.parseOffice(input, { ...config, fileType: parserType }); + const parser = parserFor(parserModule); + return parser.parseOffice.call(parser.receiver, input, { ...config, fileType: parserType }); }, }; } @@ -20,7 +69,7 @@ function officeFormat(parserType: SupportedFileType): RichDocumentFormat { export const formatRegistry: ReadonlyMap = new Map( ["docx", "odt", "pptx"].map((format) => { const parserType = format as SupportedFileType; - return [`.${format}`, officeFormat(parserType)] as const; + return [`.${format}`, createOfficeFormat(parserType)] as const; }), ); diff --git a/test/read-rich-document.test.ts b/test/read-rich-document.test.ts index 37f1dec..6358ff3 100644 --- a/test/read-rich-document.test.ts +++ b/test/read-rich-document.test.ts @@ -2,18 +2,24 @@ import assert from "node:assert/strict"; import { after, before, describe, it } from "node:test"; import { mkdir, readFile, realpath, rm, stat, symlink, writeFile } from "node:fs/promises"; import { basename, dirname, join, relative } from "node:path"; -import type { OfficeParserAST } from "officeparser"; +import { fileURLToPath } from "node:url"; +import type { OfficeParserAST, OfficeParserConfig } from "officeparser"; import { RichDocumentReaderPlugin } from "../src/index.ts"; import { READER_LIMITS } from "../src/limits.ts"; import { readRichDocument } from "../src/reader.ts"; +import { createOfficeFormat } from "../src/registry.ts"; import { createFixtures } from "./fixtures.ts"; let fixtures: Awaited>; const extractedDirectories = new Set(); function context() { + return projectContext(fixtures.root); +} + +function projectContext(projectRoot: string) { const abort = new AbortController(); - return { directory: fixtures.root, worktree: fixtures.root, abort: abort.signal }; + return { directory: projectRoot, worktree: projectRoot, abort: abort.signal }; } function rememberExtraction(result: { metadata?: { media?: Array<{ temporaryPath: string }> } }) { @@ -40,6 +46,44 @@ describe("plugin registration", () => { }); describe("read_rich_document", () => { + it("resolves named, default, and top-level officeparser exports", async () => { + const ast = {} as OfficeParserAST; + const calls: OfficeParserConfig[] = []; + const parseOffice = async (_input: Uint8Array, config: OfficeParserConfig) => { + calls.push(config); + return ast; + }; + const namedParser = { parseOffice }; + const defaultParser = Object.assign(function OfficeParser() {}, { parseOffice }); + + for (const parserModule of [ + { OfficeParser: namedParser }, + { default: defaultParser }, + { parseOffice }, + { OfficeParser: undefined, default: defaultParser, parseOffice }, + ]) { + const format = createOfficeFormat("docx", parserModule); + assert.equal(await format.parse(new Uint8Array(), {}), ast); + } + + assert.deepEqual(calls.map(({ fileType }) => fileType), ["docx", "docx", "docx", "docx"]); + }); + + it("reads the supplied pesticide records DOCX with content and metadata", async () => { + const sourcePath = "docs/maint-div/Pesticide Application Records.docx"; + const projectRoot = dirname(dirname(fileURLToPath(import.meta.url))); + assert.equal((await stat(join(projectRoot, sourcePath))).isFile(), true); + + const result = await readRichDocument({ path: sourcePath }, projectContext(projectRoot)); + + assert.match(result.output, /Pesticide Application Records/); + assert.match(result.output, /Applicators Name/); + assert.ok(result.metadata); + assert.equal(result.metadata.format, "docx"); + assert.equal(result.metadata.sourcePath, sourcePath); + assert.deepEqual(result.metadata.media, []); + }); + it("extracts DOCX structure, media, and section association without default attachments", async () => { const result = await readRichDocument({ path: "structure.docx" }, context()); rememberExtraction(result); From 4abf29047f0a9348d6b8e4c2cfd66556cea93d26 Mon Sep 17 00:00:00 2001 From: ddbaron Date: Fri, 14 Aug 2026 20:20:01 -0500 Subject: [PATCH 2/2] chore: remove captain smoke fixture --- .../Pesticide Application Records.docx | Bin 15467 -> 0 bytes test/read-rich-document.test.ts | 10 +++++++--- 2 files changed, 7 insertions(+), 3 deletions(-) delete mode 100644 docs/maint-div/Pesticide Application Records.docx diff --git a/docs/maint-div/Pesticide Application Records.docx b/docs/maint-div/Pesticide Application Records.docx deleted file mode 100644 index fa0c5dcb0d86514926d2b7afd579b15fec4924a4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 15467 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 GuKo`T71C+| diff --git a/test/read-rich-document.test.ts b/test/read-rich-document.test.ts index 6358ff3..3c73c5b 100644 --- a/test/read-rich-document.test.ts +++ b/test/read-rich-document.test.ts @@ -2,7 +2,6 @@ import assert from "node:assert/strict"; import { after, before, describe, it } from "node:test"; import { mkdir, readFile, realpath, rm, stat, symlink, writeFile } from "node:fs/promises"; import { basename, dirname, join, relative } from "node:path"; -import { fileURLToPath } from "node:url"; import type { OfficeParserAST, OfficeParserConfig } from "officeparser"; import { RichDocumentReaderPlugin } from "../src/index.ts"; import { READER_LIMITS } from "../src/limits.ts"; @@ -69,9 +68,14 @@ describe("read_rich_document", () => { assert.deepEqual(calls.map(({ fileType }) => fileType), ["docx", "docx", "docx", "docx"]); }); - it("reads the supplied pesticide records DOCX with content and metadata", async () => { + it("reads the supplied pesticide records DOCX with content and metadata", async (t) => { + const projectRoot = process.env.OPENCODE_RICH_DOCUMENT_SMOKE_ROOT; + if (!projectRoot) { + t.skip("set OPENCODE_RICH_DOCUMENT_SMOKE_ROOT to run the external supplied-document smoke test"); + return; + } + const sourcePath = "docs/maint-div/Pesticide Application Records.docx"; - const projectRoot = dirname(dirname(fileURLToPath(import.meta.url))); assert.equal((await stat(join(projectRoot, sourcePath))).isFile(), true); const result = await readRichDocument({ path: sourcePath }, projectContext(projectRoot));