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

@fefeding/jdoc

v0.1.1

Published

文档解析与生成统一库:支持 PPTX / DOCX / XLSX / PDF 的解析与生成,纯 TypeScript,浏览器与 Node.js 双端可用

Readme

@fefeding/jdoc

文档解析与生成统一库:PPTX / DOCX / XLSX / PDF / Markdown / TXT 多格式一套 API,浏览器与 Node.js 双端可用。

特性

  • 一套命名,四种格式 — 解析统一为 xxxToYyy(input, options),生成统一为 jsonToXxx(doc, options)
  • 入参无门槛 — ArrayBuffer / TypedArray / Buffer / Blob / File / base64 / data URL 直接传,不用自己转换
  • 出参统一 — 所有生成函数一律返回 Uint8Array,可直接 new Blob([bytes]) 或写入文件系统
  • JSON 即契约 — 解析结果可直接回传给生成函数,支持「解析 → 改 → 生成」往返
  • 自带 HTML 渲染 — DOCX / XLSX 解析结果可直接渲染成带内联样式的 HTML
  • 零框架依赖 — 纯 TypeScript,同时输出 ESM / CJS / 浏览器产物

安装

npm install @fefeding/jdoc

快速开始

解析

import { docxToHtml, xlsxToJson, pptxToStandard, pdfToText, detectFormat } from '@fefeding/jdoc';

// 直接把 File / Blob 丢进去,不用 arrayBuffer()
const html = await docxToHtml(file);                 // DOCX -> HTML
const { sheets } = await xlsxToJson(file);           // XLSX -> 工作簿结构
const doc = await pptxToStandard(file);              // PPTX -> 标准文档结构
const text = await pdfToText(file);                  // PDF -> 全文

console.log(await detectFormat(file));               // 'docx' | 'xlsx' | 'pptx' | 'pdf'

生成

import { jsonToDocx, jsonToXlsx, jsonToPptx, jsonToPdf } from '@fefeding/jdoc';

const docx = await jsonToDocx([
  { type: 'heading', level: 1, text: '周报' },
  { type: 'paragraph', text: '本周完成 A、B 两个模块。' },
  { type: 'table', header: true, rows: [['模块', '进度'], ['A', '100%']] }
]);

const xlsx = await jsonToXlsx([
  { name: '订单', rows: [['姓名', '金额'], ['张三', 1200]] }
]);

const pdf = await jsonToPdf({
  metadata: { title: '报告' },
  elements: [
    { type: 'heading', level: 1, text: '季度报告' },
    { type: 'text', text: '正文内容……' },
    { type: 'table', header: true, rows: [['项', '值'], ['营收', '1200']] }
  ]
});

const pptx = await jsonToPptx({
  slides: [{ elements: [{ type: 'text', text: 'Hello', x: 50, y: 50, width: 200, height: 40 }] }]
});

// 浏览器:触发下载
const url = URL.createObjectURL(new Blob([docx], { type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document' }));
const a = Object.assign(document.createElement('a'), { href: url, download: 'report.docx' });
a.click();
URL.revokeObjectURL(url);

API 一览

通用

| 函数 | 说明 | | --- | --- | | detectFormat(input) | 按魔数与 ZIP 内部结构识别格式,返回 'docx' \| 'xlsx' \| 'pptx' \| 'pdf' \| null | | JdocError | 统一错误类型,带 format / code / cause | | toUint8Array(input) / toArrayBuffer(input) / bytesToBase64(bytes) | 入参与编码工具 | | parseXml(xml) / findAll / findFirst / attr / textOf | 零依赖 XML 解析工具 |

二进制资源(图片等)

文档里的图片等二进制内容统一抽象为资源(asset):一份字节 + 位置锚点。 解析时用 assets 选项决定给不给独立资源表,生成时用引用写回。

| 模式 | 文档结构里 | assets | 适用场景 | | --- | --- | --- | --- | | inline(DOCX/XLSX/PPTX 默认) | data URL | 无 | 浏览器直接显示,保持既有行为 | | extract | { assetId } 引用 | 有 | 后台存储 / 另存为,JSON 体积小 | | both(PPTX 默认) | data URL + assetId | 有 | 前端显示与后端取字节并行 | | ignore(PDF 默认) | — | 无 | 完全丢弃 |

各格式的默认与能力:

| 格式 | 默认 | 可提取 | 锚点 kind | | --- | --- | --- | --- | | DOCX | inline | 块内图片 | block(表格内为 cells[r][c] 路径) | | XLSX | ignore | 单元格锚定图片 | cell(如 Sheet1!B3) | | PPTX | both | 元素图片(含形状填充) | slide(第几张幻灯片) | | PDF | ignore | 附件 + 页面图像 | other(附件)、page(页码) |

PDF 的页面图像需走一遍渲染指令,代价较高(上百页文档明显变慢),因此默认不提取; 附件提取很廉价,显式开启 assets: 'extract' 即可一并拿到。

// 解析:抽出资源,块上只留引用(DOCX / XLSX / PPTX 同理)
const parsed = await docxToJson(file, { assets: 'extract' });
// const sheet   = await xlsxToJson(file, { assets: 'extract' });  // 单元格图片
// const deck    = await pptxToStandard(file, { assets: 'extract' }); // 幻灯片图片
// const pdf     = await pdfToJson(file, { assets: 'extract' });    // 附件 + 页面图像
parsed.assets[0];
// {
//   id: 'docx-0001',
//   name: 'docx-0001.png',
//   mime: 'image/png',
//   data: Uint8Array,
//   part: 'word/media/image1.png',   // 容器内原始部件路径
//   anchor: { scope: 'docx', kind: 'block', index: 1, path: 'blocks[1]', label: '第 2 个块' }
// }

// 同一份字节,按端取最合适的形式
assetToDataUrl(asset)      // data:image/png;base64,…      浏览器直接 <img src>
assetToBlob(asset)         // Blob                         浏览器预览 / 下载
assetToBase64(asset)       // base64                       存库字段
assetToArrayBuffer(asset)  // ArrayBuffer                  底层库 / postMessage
assetToNodeStream(asset)   // Node Readable                后台直接 pipe 落盘或转存对象存储
assetToWebStream(asset)    // ReadableStream               fetch / Response

// 生成:按引用写回,往返不必搬运 base64
const bytes = await jsonToDocx(parsed, { assets: parsed.assets });

四种格式的引用写法一致,图片字段给 { assetId } 或直接给资源对象即可:

jsonToDocx({ blocks: [{ type: 'image', src: { assetId: 'docx-0001' } }] }, { assets });
jsonToXlsx({ sheets: [{ name: 'S', rows: [['x', { image: { assetId: 'xlsx-0001' } }]] }] }, { assets });
jsonToPptx({ slides: [{ elements: [{ type: 'image', data: { assetId: 'pptx-0001' } }] }] }, { assets });
jsonToPdf({ elements: [{ type: 'image', src: { assetId: 'pdf-0001' } }] }, { assets });
  • 资源表也可直接挂在文档规格上({ assets, blocks/elements/slides }),无需再传选项
  • 资源缺失时 DOCX 降级为占位段落、PDF 跳过该图,均不中断整篇生成
  • PPTX 的 extract 模式元素上只留 assetId,生成时自动还原成 data URL

资源是纯数据(不含方法),可直接 JSON.stringify 落库;字节单独取用。 同一张图在文档里出现多次只存一份字节,块共享同一个 assetId。 anchor 让「资源 ↔ 文档位置」双向可查——既能由块找图片,也能由图片反查它在第几个块 / 哪张表哪格。

文档一体保存

解析结果与资源可打成自包含的 bundle(ZIP),解压即可还原,任意机器可编辑:

const zip = await packDocument({
    format: 'docx',
    name: '技术协议',
    document: parsed,
    assets: parsed.assets,
    original: file   // 可选:一并保留原始文件
});
// 技术协议.jdbundle
// ├── manifest.json      格式、名称、资源清单(含位置锚点)
// ├── 技术协议.docx        原始文档
// ├── document.json      解析出的结构,可回传给 jsonToDocx
// └── assets/docx-0001.png

const restored = await unpackDocument(zip);      // 解包还原结构与字节
await listBundleAssets(zip);                     // 只列资源与其在文档中的位置
await isDocumentBundle(bytes);                   // 判断是否为 bundle,避免误判普通文档

// Node 端也能直接落成一个文件夹(便于人工查看与二次加工)
await writeDocumentBundle(bundle, 'out/技术协议');

DOCX

| 函数 | 返回 | | --- | --- | | docxToJson(input, options?) | { metadata, blocks, messages, text },assets: 'extract' 时另含 assets | | docxToHtml(input, options?) | 上述字段 + html(含默认样式表) | | docxToText(input) | string | | jsonToDocx(doc \| blocks, options?) | Uint8Array | | blocksToHtml(doc \| blocks, options?) | string(不生成文件直接渲染) |

支持的块类型:heading / paragraph / list / table / image / quote / code / hr / pageBreak。 文本支持 bold italic underline strike subscript superscript color size font highlight link。

XLSX

| 函数 | 返回 | | --- | --- | | xlsxToJson(input, options?) | { metadata, sheets, messages },assets: 'extract' 时另含 assets | | xlsxToHtml(input, options?) | 上述字段 + html | | xlsxToMatrix(input, sheetName?) | { headers, rows },适合直接喂图表库 | | jsonToXlsx(workbook \| sheets, options?) | Uint8Array | | sheetsToHtml(workbook \| sheets, options?) | string |

单元格支持三种写法,从简到繁:

rows: [
  ['简写:直接写值'],
  [{ 1: '对象式:列号或 A1 记号做键' }, { C2: 'C 列' }],
  [{ value: 1200, style: { numFmt: '#,##0.00', align: 'right' } }],
  [{ formula: 'B2*2', result: 2401 }],
  [{ value: '链接', hyperlink: 'https://example.com' }]
]

样式支持:font(含 bold / color / size / name)、fill、align、valign、wrapText、numFmt、border。

PDF

| 函数 | 返回 | | --- | --- | | pdfToJson(input, options?) | { metadata, pageCount, pages, messages },assets 选项开启时另含 assets | | pdfToText(input, options?) | string(按页用空行分隔) | | pdfInfo(input) | { metadata, pageCount, pages, messages },不提取正文,最快 | | jsonToPdf(spec, options?) | Uint8Array | | pdfPageToPng(input, page?, scale?) | Uint8Array(PNG,需 @napi-rs/canvas,仅 Node) |

支持的元素类型:text / heading / image / line / rect / table / pageBreak。 坐标采用顶部原点(与 HTML 一致),只需给出距左边距 / 距顶边距的距离。

编辑既有 PDF

editPdf(input, spec) 在既有 PDF 上追加内容并保存:原文件的对象结构、内容流、矢量图形与 内嵌字体全部原样保留,只往页面内容流末尾追加绘制指令。另有 mergePdfs(inputs) 与 splitPdf(input, { from, to })。

const bytes = await editPdf(file, {
  overlays: [
    [{ type: 'rect', x: 40, y: 60, width: 200, height: 18, fill: '#ffe08a', opacity: 0.5 }],
    [{ type: 'text', x: 40, y: 120, text: 'Approved', size: 14, color: '#334155' }]
  ],
  rotate: [{ page: 0, degrees: 90 }],
  removePages: [4],
  pageOrder: [2, 0, 1]
});

overlays 以下标(0 起)对应页序,同页内按数组顺序叠放;removePages 与 pageOrder 都作用 于最终页集合(先删后重排)。页面管理在叠加绘制之前完成,因此叠加坐标始终对应调整后的页面。 中文需通过 spec.fonts 内嵌中文字体,约束与 jsonToPdf 相同。

这是扁平化叠加而非批注:内容被画进页面内容流,之后无法再单独移除——与「盖章后导出」的 常见预期一致。

PPTX

| 函数 | 返回 | | --- | --- | | pptxToHtml(input, options?) | 幻灯片 HTML | | pptxToJson(input, options?) | 结构化解析结果 | | pptxToStandard(input, options?) | 标准文档结构(与 jsonToPptx 同源,可往返) | | pptxToFiles(input) | 内部文件清单与内容 | | jsonToPptx(doc, options?) | Uint8Array | | PPTXComposer | 链式构建,save() 返回 Uint8Array | | editPptx(input) | 增删页 / 改元数据 |

Markdown / 纯文本

| 函数 | 返回 | | --- | --- | | markdownToHtml(input, options?) | { html, text, metadata, messages },HTML 已按白名单清洗 | | markdownToText(input, options?) | 去标记后的纯文本 | | textToHtml(input, options?) | { html, text, messages },纯文本转义后包在 <pre> 里 | | textToText(input) | 原文(UTF-8 解码,去 BOM) |

const { html, metadata } = await markdownToHtml(bytes);
container.innerHTML = html;              // 自带 .jdoc-md 作用域样式,可用 includeStyle: false 关闭
console.log(metadata?.headings);          // 标题大纲

公式与流程图

解析时把 Mermaid 图表与数学公式识别成语义容器(同时保留源码作降级显示):

| 语法 | 产出 | | --- | --- | | ```mermaid 围栏 | <pre class="jdoc-mermaid" data-diagram="mermaid"> | | ```math / ```tex / ```latex 围栏 | <pre class="jdoc-math-block" data-tex="…"> | | $$…$$、\[…\] | <pre class="jdoc-math-block" data-tex="…"> | | $…$、\(…\) | <code class="jdoc-math-inline" data-tex="…"> |

浏览器端调用 renderMarkdownExtras() 才会真正渲染(Mermaid / KaTeX 都是动态 import,不渲染不加载):

await renderMarkdownExtras(container);   // → { math: n, diagrams: n }

宿主需要提供 KaTeX 样式表(含 fonts/*.woff2)公式才美观;渲染失败会自动回退到显示源码。 用 { math: false, diagrams: false } 可完全关闭这两类语法。

markdownToHtml 默认允许 Markdown 内嵌的原始 HTML,但会移除 script / iframe / 事件属性与 javascript: 等危险协议;传 { allowHtml: false } 可让原始 HTML 全部按纯文本转义。

环境要求

| 场景 | 说明 | | --- | --- | | Node.js >= 18 | 直接可用,PDF 解析无需额外配置 | | 浏览器 | 需使用打包器(Vite / Webpack / Rollup);纯 ESM CDN 直接引入时,exceljs 需改用其 UMD 产物 | | PDF 解析 | pdfjs-dist 为可选依赖,未安装时仅 pdfTo* 报错,其余功能不受影响:npm i pdfjs-dist | | PDF 页面渲染 | Node 端另需 npm i @napi-rs/canvas | | 生成含中文的 PDF | 需内嵌中文 TTF/OTF(PDF 标准字体不含 CJK 字形) |

// 生成中文 PDF:把字体字节交给 fonts.regular
import fs from 'node:fs';
const bytes = await jsonToPdf({
  fonts: { regular: fs.readFileSync('./SourceHanSans-Regular.ttf') },
  elements: [{ type: 'text', text: '中文内容' }]
});

已知限制

  • PDF 只做解析文本与页面信息,不做版面分析、表格结构化或图片提取。
  • DOCX 不还原分栏、页眉页脚、脚注、批注与修订;文本框、SmartArt 等浮动对象会被忽略。
  • XLSX 不保留数据透视表、图表、条件格式与批注(批注需显式开启 includeNotes)。
  • PPTX 由 @fefeding/ppt-parser 提供,其保真度以该库为准(形状、图表、SmartArt 渲染与往返)。

技能(Skills)

本仓库在 skills/ 下随库提供一组 agent 技能:按能力各一个包,每个含一份 SKILL.md,说明何时使用、精确的 API、可运行示例与常见坑。其包模型与 work-space 技能存储一致(SKILL.md + 可选资源),AI 助手可按需加载。

| 技能 | 覆盖 | | --- | --- | | docx | 解析 / 生成 / 往返编辑 DOCX | | xlsx | 解析 / 生成表格、单元格、样式、公式 | | pptx | 渲染 / 生成 / 编辑演示文稿 | | pdf | 解析文本、生成、栅格化 PNG、扁平化叠加 | | markdown | Markdown / 纯文本 → HTML,Mermaid + KaTeX | | convert | 一条命令在 docx / pdf / md / html 间互转 | | assets | 二进制资源提取、按端取用、按引用写回 | | bundle | 把「文档 + 资源」打包 / 解包成自包含 .jdbundle |

开发

npm install
npm run test:run      # 运行测试
npm run type-check    # 类型检查
npm run build         # 构建 ESM / CJS / browser + .d.ts

License

MIT