Skip to content

v7.5.1

Latest

Choose a tag to compare

@github-actions github-actions released this 30 Jul 20:59

v7.5.1: 🛡️ Corrupt Files Fail Loudly, Real-World Archives Detect Correctly & Webpack-Safe Bundles

I am pleased to announce the release of officeParser v7.5.1! This patch release closes three reported issues around one theme: trusting the file in front of us less, and telling you more. Unreadable input now fails with typed errors instead of parsing as an empty document, type detection reads the archive's own declaration when magic-byte sniffing gives up, and the browser bundles no longer break webpack builds.

Thanks to @benhid, @SteveNewhouse and @ayazaurie, whose reports drove this release.

Warning

Behavior changes

  • Corrupt input throws; it no longer parses as an empty document. Data that is not a ZIP archive, an archive cut off in transfer (or carrying data after its end-of-archive record), and a readable ZIP missing the part its format requires (word/document.xml, xl/workbook.xml, ppt/presentation.xml, ODF content.xml, the EPUB OPF) now reject with ZIP_NO_ENTRIES_FOUND, ZIP_TRUNCATED and REQUIRED_PART_MISSING respectively. An empty result therefore means the document really is empty. If you relied on unreadable files resolving quietly, catch and branch on error.officeIssue.code.
  • DOCX headers, footers and comments now appear in output. They were documented but never extracted, so ast.auxiliary.headers / .footers were always empty and comments never reached the AST. Documents that have them will now produce them; ignoreHeadersAndFooters and ignoreComments restore the old shape if you want it.
  • Config objects are no longer shared with the library. Reusing one config across calls previously leaked each parse's warnings into earlier, already-returned ast.warnings arrays, and generation could silently rewrite htmlConfig.containerWidth on your own object. Resolution now copies; callbacks and abortSignal keep their identity.

🌟 Key Highlights

1. Corrupt, Truncated and Mislabeled Files Fail Loudly (#107)

Since the 7.3.0 streaming ZIP rewrite, a corrupt buffer resolved into an empty AST with no warnings, indistinguishable from a genuinely empty document. Three distinct failure modes are now typed rejections, and every thrown error carries its structured issue so you branch on a stable code instead of matching message text:

try {
    const ast = await parseOffice(buffer, { fileType: 'docx' });
} catch (err) {
    switch (err.officeIssue?.code) {
        case 'ZIP_NO_ENTRIES_FOUND':  // not a ZIP archive at all
        case 'ZIP_TRUNCATED':         // cut off in transfer, entries incomplete
        case 'REQUIRED_PART_MISSING': // readable ZIP, but not the format it claims
            console.error('Unusable file:', err.officeIssue.message);
            break;
        default:
            throw err;
    }
}

The OfficeError type is exported for TypeScript users. Files that are legitimately empty still parse and now say so: a chartsheet-only workbook emits NO_WORKSHEETS_FOUND and a zero-slide deck emits NO_SLIDES_FOUND through onWarning / ast.warnings, so an empty result is never silent in either direction. Two ODF gaps closed alongside: a valid .ods/.odp without a mimetype entry was walked as a text document and came back empty (it now falls back to your fileType or the extension), and a missing root content.xml can no longer silently promote an embedded Object N/content.xml chart to the document body.

2. Type Detection Reads the Archive's Own Declaration (#82)

Passing a bare Buffer relied entirely on magic-byte sniffing, which walks a ZIP under fixed budgets: at most 1024 entries, and roughly 1 MiB of scanning when entry sizes are deferred to trailing data descriptors (general-purpose flag bit 3, what streaming ZIP writers produce). A valid PPTX whose [Content_Types].xml sat beyond either budget was reported as generic zip, so parseOffice threw "Sorry, OfficeParser currently supports docx, pptx, xlsx... add support for zip files" for a perfectly good document. Both layouts occur in the wild, and every ZIP-backed format was affected, in Node and in the browser.

When sniffing is inconclusive, the archive is now opened with officeParser's own reader, which has neither budget, and the format is taken from [Content_Types].xml or the ODF/EPUB mimetype entry. Detection inflates at most 4 MiB regardless of your decompression limits, a correct fileType hint skips the archive scan entirely and remains the fastest path, and a bare zip sniff is no longer misreported as a BUFFER_TYPE_MISMATCH against your own hint.

3. Webpack-Compatible Browser Bundles (#108)

One dynamic import inside the bundles escaped the build's webpackIgnore annotations, because the annotator treated an interpolated template literal as a static string. Webpack does not skip a specifier it cannot resolve: it builds a context module over the whole directory, so consumers ended up bundling all of dist/, Node-only files included, and their builds failed on child_process. The annotator was rewritten around a shared, tested classifier, child_process and url now resolve to browser stubs, and a webpack 5 build of the ESM and slim ESM bundles is warning-free. Shipping checks now scan every bundle so this class of regression cannot ship again.


🔧 Also Fixed

  • DOCX headers, footers and comments were never extracted. The parse code existed but the parts were missing from the archive extraction filter, so it could never run. Part names now also match past header9.xml, which documents with several sections reach.
  • PPTX document-property parts were parsed as slide candidates. docProps/app.xml and custom.xml are now skipped in the slide loop on identity, closing the same phantom-slide trap that ppt/presentation.xml needed.
  • Typed errors were reported twice, with a doubled [OfficeParser]: prefix and their code flattened to FILE_CORRUPTED by the wrapping layer. Errors now pass through once, intact.
  • Archive extraction errors ignored outputErrorToConsole and onWarning, always writing to the console. They now report through your handlers like every other issue.
  • Memory: the Word, Excel and PowerPoint parsers each kept the full XML source of every extracted part in a write-only buffer under includeRawContent. Dropped; serialized ASTs are byte-identical.

🛠 Getting Started

npm install officeparser@7.5.1

🔗 Full Changelog: View v7.5.1 details
🔗 Documentation & Visualizer: officeparser.harshankur.com