npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@shadow-garden/bapbong-docx

v0.20.0

Published

bapbong — DOCX (OOXML) import / export

Readme

@shadow-garden/bapbong-docx

DOCX (OOXML) import and export. Unzips a .docx, parses word/document.xml and friends, and maps the property cascade (docDefaults → table style → paragraph style → character style → inline) into the model schema — then writes it back.

  • Scope: scope:io
  • Depends on: @shadow-garden/bapbong-model, @shadow-garden/bapbong-contracts, jszip

What it covers

  • Paragraphs, runs and marks (bold/italic/underline/strike, color, highlight, super/subscript), multilevel lists (numbering.xml), tables (borders, shading, vAlign, merged cells), inline images, hyperlinks.
  • Table styles, including w:tblStylePr conditional formatting — first/last row, first/last column, row and column banding, corner cells — across all four channels (w:pPr, w:rPr, w:tcPr, cell borders), gated by w:tblLook.
  • Page geometry from sectPr, multi-column sections, headers/footers (default / first / even), footnotes/endnotes, track-changes runs.
  • Comments: comments.xml (range marks) + threaded/resolved metadata from commentsExtended.xml (w15 paraIdParentparentId, w15:done → resolved).

Public API

import { importDocx } from '@shadow-garden/bapbong-docx';

const {
  doc,
  headers,
  footers,
  footnotes,
  comments,
  page,
  titlePg,
  evenAndOdd,
} = await importDocx(fileBytes); // DocxInput = ArrayBuffer | Uint8Array | Blob
import { exportDocx } from '@shadow-garden/bapbong-docx';

const bytes = await exportDocx(doc, { carry: raw }); // `raw` from importDocx

exportDocx round-trips the document; passing the importer's raw package back lets unmodelled parts and properties survive the save verbatim.

Word vs the standard

Fidelity means matching Word, which is not always the same as matching ISO/IEC 29500. Where the two disagree this converter follows Word and cites the source at the call site. The ones that shaped it most:

| Behaviour | Source | | ----------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------ | | w:tblStylePr type="wholeTable" is discarded — "Word does not apply and discards on save any properties within" it | MS-OI29500 §17.18.89(a) | | Toggle properties (w:b, w:i, …) do not toggle between style layers; Word "resets the value … to the value specified" | MS-OI29500 §2.1.258 | | A missing w:tblLook means the bitmask 0x04A0, not 0x0000; and w:val is read only when none of the six attributes is present | MS-OI29500 §17.4.55 | | tblStyleRowBandSize/ColBandSize default to 0 (the standard says 1), and 0 means no banding at all | MS-OI29500 §2.1.251 | | Conditional formats apply bands → first/last column → first/last row → corners (the standard orders it differently) | MS-OI29500 §2.1.250 | | Auto paragraph spacing is 14pt (280 twips), and only between two neighbouring paragraphs — never at a cell's edges or between items of one list | Word help; Aspose.Words; LibreOffice |

The 14pt is not a guess: Aspose.Words and Word's own help both name it, and LibreOffice's writerfilter/DomainMapper.cxx hardcodes default_spacing = 280 twips for the same setting. One MS Q&A answer describes it as 1em instead — three sources against one, and no document in the corpus can referee it.

Row and column banding excludes the header row (and the first column) from the count. That rule is in no document we could find; it was settled by diffing our computation against all 268 w:cnfStyle strings Word itself wrote into a styled 39-row table.

Erratum. Commit 6d2c3ec ("a table style's w:pPr reaches the paragraphs inside the table") states in its message that many real table styles keep their pPr inside tblStylePr type="wholeTable", and that the commit therefore does not reach them. That is wrong: Word ignores that branch entirely (first row above), so whole-table formatting only ever lives at the style's own w:pPr/w:rPr/w:tblPr — which that commit does read. The message is left as written; this is the correction.

Build / test

pnpm nx build @shadow-garden/bapbong-docx
pnpm nx test  @shadow-garden/bapbong-docx