k-skill-rhwp 实战指南:用 Node CLI 与 WASM 实现 HWP 5.x 文档的插入、替换、表格与渲染
k-skill-rhwp 实战指南用 Node CLI 与 WASM 实现 HWP 5.x 文档的插入、替换、表格与渲染【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill本指南以 k-skill 仓库中的packages/k-skill-rhwp包为主体讲解如何在 Node.js 18 环境下通过k-skill-rhwp命令与 Node API 对 HWP 5.x 文档进行安全的往返编辑round-trip safe editing。该包封装了上游rhwp/coreRust WebAssemblyMIT的编辑能力为仓库中的rhwp-edit技能提供编辑引擎读完本文你将掌握 10 个 CLI 子命令的用法、JSON 输出契约、search/replace-all的作用域与 Unicode 安全语义以及 WASM 惰性初始化的底层原理。项目定位三个技能各司其职k-skill-rhwp不是孤立的工具而是 k-skill 仓库中 HWP 处理技能矩阵的编辑引擎。根据 README 与 CHANGELOG 的说明仓库按职责做了如下切分技能 / 包职责底层技术rhwp-edit技能 k-skill-rhwp 包本文主角HWP 5.x 的编辑插入/删除文本、全局替换、建表、写单元格、渲染页面rhwp/coreWASMNode 侧 CLIrhwp-advanced技能调试上游 rhwp Rust CLI 的高级命令export-svg --debug-overlay、dump、ir-diff、thumbnail、convert本包不封装这些命令上游 Rust CLIhwp技能HWP 的读取/转换.hwp→ Markdown / JSON / 表单字段提取kordoc 方案也就是说需要把 HWP 转成 Markdown 或提取表单字段时用 hwp/SKILL.md需要深入调试文档内部 IR 时用 rhwp-advanced/SKILL.md而要在正文中做机械化编辑补日期、换年份、填表格时本包是唯一入口其对应技能文档见 rhwp-edit/SKILL.md。从源码结构看k-skill-rhwp定位为纯编辑型editing-only工具不覆盖读取/转换能力。安装与快速开始包以 npm 包形式发布Node 引擎要求18见 package.json无需安装 Rust 工具链随包分发的 WASM 完成全部工作。# 作为项目依赖安装 npm install k-skill-rhwp # 或一次性运行不落地安装 npx --yes k-skill-rhwp --help安装后会提供k-skill-rhwp可执行文件bin字段指向 bin/k-skill-rhwp.js。该入口通过 src/cli.js 的main()分发命令参数解析支持--flag value、--flagvalue、布尔 flag 与--分隔符测试见 test/cli.test.js 的parseArgs用例。先验证安装并快速走通新建空白文档 → 查看结构k-skill-rhwp create-blank blank.hwp k-skill-rhwp info blank.hwpinfo输出示例结构以仓库实现为准{ sourceFormat: hwp, pageCount: 1, sectionCount: 1, sections: [ { sectionIndex: 0, paragraphCount: 1, paragraphs: [ { paragraphIndex: 0, length: 0 } ] } ], documentInfo: {} }CLI 子命令全景README 将 10 个子命令分为四组完整命令如下带[ ]的参数为可选默认值以代码注释标注命令细节与 src/cli.js 中USAGE一致元数据 / 结构k-skill-rhwp info input.hwp k-skill-rhwp list-paragraphs input.hwp [--section N] # section 默认 0 k-skill-rhwp search input.hwp --query TEXT [--from-section N] [--from-paragraph N] [--from-char N] [--case-sensitive]正文编辑k-skill-rhwp insert-text input output --section N --paragraph N --offset N --text TEXT k-skill-rhwp delete-text input output --section N --paragraph N --offset N --count N k-skill-rhwp replace-all input output --query TEXT --replacement TEXT [--case-sensitive]表格k-skill-rhwp create-table input output --section N --paragraph N --offset N --rows N --cols N k-skill-rhwp set-cell-text input output --section N --parent-paragraph N --control N --cell N --text TEXT [--cell-paragraph N] [--no-replace]渲染 / 创建k-skill-rhwp create-blank output.hwp k-skill-rhwp render input.hwp [--page N] [--format svg|html] # page 默认 0format 默认 svg全局选项还包括--jsoninfo/list/search默认即为 JSON 输出、--help/-h、--version/-v。参数校验规则来自 CLI 实现数值型参数--section、--paragraph、--offset、--count、--rows、--cols、--from-*、--page、--cell等必须是非负整数否则报must be a non-negative integer见requireFlag/optionalNumbersrc/cli.js必填参数缺失时报missing required --xxx并以退出码 1 结束--text在insertText中必须为非空字符串--count必须为正整数src/index.js。编辑命令的输出契约永不覆盖输入README 强调一个安全设计每个编辑子命令都写出全新的 HWP 文件绝不覆盖输入文件。这在 src/index.js 中由writeHwp()落实——编辑在内存中的HwpDocument对象上进行随后doc.exportHwp()产出字节写入output路径src/index.js。成功时每个编辑命令都会打印一段 JSON 摘要包含字段含义ok是否成功truecharOffset/paraIdx/controlIdx等编辑后光标/锚点位置依命令不同bytesWritten写出的字节数outputPath解析后的输出文件绝对路径replace-all额外返回count替换次数。bytesWritten与outputPath由writeHwp统一注入其他字段来自上游返回src/index.js。测试也验证了这一点insertText后在info中能读到段落长度等于插入文本长度且 SHA-1 校验输入输出字节必然不同test/index.test.js 的 round-trip 用例。典型正文编辑示例# 在第 1 个 section、第 1 个段落开头插入标题 k-skill-rhwp insert-text draft.hwp titled.hwp \ --section 0 --paragraph 0 --offset 0 --text 2026년 신청서 # 删除第 3 个段落开头 10 个字符 k-skill-rhwp delete-text draft.hwp cleaned.hwp \ --section 0 --paragraph 2 --offset 0 --count 10 # 全文把 2025 替换成 2026 k-skill-rhwp replace-all draft.hwp next-year.hwp --query 2025 --replacement 2026search 与 replace-all 的作用域语义README 明确search和replace-all只扫描正文段落body paragraphs。表格单元格内的文字、页眉/页脚、脚注不会被扫描。这与上游rhwp/core的searchText作用域一致src/index.js 直接透传上游doc.searchText。因此对单元格文字的正确姿势是先用info或list-paragraphs定位表格所在段落与控制对象再用set-cell-text写入。create-table成功返回的paraIdx与controlIdx正是后续set-cell-text所需的--parent-paragraph与--control取值——测试 test/index.test.js 的setCellText fills a cell after creating a table完整演示了这条建表 → 取索引 → 填单元格链路。替换文本的换行禁令replace-all拒绝任何包含换行或段落分隔符\n、\r、U2028、U2029的--replacement因为那会把一个段落劈成两个实现见 src/index.js 的正则[\n\r\u2028\u2029]。需要多段落结果时应拆成多次insert-text调用。对应测试replaceAll rejects replacement containing newlines断言了该拒绝行为。非重叠替换语义避免无限循环replace-all使用非重叠non-overlapping语义所有匹配位置基于替换执行前的原始文本一次性计算然后从后往前逐个执行src/index.js 中先findAllMatchOffsets收集全部偏移再倒序replaceText。因此--query a --replacement aa作用于aaa时先对原文算出 3 个匹配位置替换后得到aaaaaa而不会因为新生成的a被反复匹配而陷入死循环。测试replaceAll handles replacement containing the query without infinite loop正是这一行为的回归保障断言 count 为 3、结果长度为 6。replace-all 的 Unicode 大小写折叠安全护栏默认情况下不带--case-sensitivereplace-all采用不区分大小写匹配实现依赖String.prototype.toLowerCase()。该实现假设小写化不改变 UTF-16 长度这样在 lowercased 草堆中算出的偏移才能安全套用到原文。但有少量 Unicode 字符破坏这一不变式最典型的是土耳其语İU0130它小写后变成iU0069 组合上点U0307UTF-16 长度从 1 变成 2导致其后所有偏移逐字漂移、悄悄损坏文档。README 给出了具体的防护行为当查询串或任意段落包含此类字符时replace-all拒绝执行退出码 1并输出错误信息case-insensitive matching is unsafe because case folding changes the UTF-16 length解决方式改带--case-sensitive重跑或先把输入规范化ASCII、韩文Hangul以及常见 HWP 场景如2025 → 2026不受影响。这一保护在 src/index.js 的findAllMatchOffsets中实现小写化后先比对hay.length ! text.length || needle.length ! query.length一旦不等立即抛错。测试 test/index.test.js 用一组针对性用例锁定了行为默认大小写不敏感匹配遇到ABCİABCİXYZ时拒绝执行且不写出任何输出文件改为caseSensitive: true后正常替换两处İ并保留X防止偏移漂移损坏。同时还有回归用例确认 ASCII/韩文混合场景hello WORLD 안녕 HELLO的大小写不敏感替换不受影响。Node API 编程方式除 CLI 外包还以 CommonJS 模块导出编程 APImain指向 src/index.js。README 的核心示例const { insertText, createTable, setCellText, getDocumentInfo } require(k-skill-rhwp); await insertText({ input: ./draft.hwp, output: ./draft-with-title.hwp, section: 0, paragraph: 0, offset: 0, text: 2026년 신청서 }); console.log(await getDocumentInfo(./draft-with-title.hwp));导出的全部函数见 src/index.js函数对应 CLI说明getDocumentInfo(filePath)info文档元数据 各 section/段落长度listParagraphs(filePath, sectionIndex)list-paragraphs指定 section 的段落长度列表searchText({ input, query, fromSection, fromParagraph, fromChar, forward, caseSensitive })search前向/后向搜索正文insertText({ input, output, section, paragraph, offset, text })insert-text插入文本deleteText({ input, output, section, paragraph, offset, count })delete-text删除文本replaceAll({ input, output, query, replacement, caseSensitive })replace-all全局替换createTable({ input, output, section, paragraph, offset, rows, cols })create-table创建表格setCellText({ input, output, section, parentParagraph, control, cell, cellParagraph, text, replace })set-cell-text写单元格replace对应--no-replace的反向开关createBlank(outputPath)create-blank新建空白文档renderPage(filePath, pageIndex, format)render渲染页面为 SVG/HTML每个 API 在finally中都会调用doc.free()释放 WASM 内存如 src/index.js长时间批量处理时不会累积泄漏。setCellText 的替换语义setCellText默认replace: true会先读取目标单元格指定段落的长度若大于 0 则先deleteTextInCell清空再insertTextInCell写入src/index.js。传--no-replace即 API 中replace: false则跳过清空步骤直接在单元格段落开头追加。WASM 初始化原理与 measureTextWidth 垫片每次进程首次调用任意函数时模块会惰性加载并初始化rhwp/coreWASMsrc/wasm-init.js。README 提到两个关键点其实现细节如下WASM 需要globalThis.measureTextWidth(font, text)回调做文本布局断行、两端对齐。浏览器端标准实现依赖canvas2D context而无头 Node 没有 canvas。本包在首次使用时自动安装确定性近似垫片src/wasm-init.js从字体字符串解析px字号默认 12CJK/全角字符U1100–UFFDC 区间含韩文按整字宽 ≈ 字号计算拉丁/数字/标点按 0.55 × 字号计算。这对往返编辑与冒烟测试足够精确但不适合追求像素级渲染的用途。若你已有基于 node-canvas 的高精度实现只需在首次调用前自行设置globalThis.measureTextWidth垫片检测到已有函数便不会覆盖返回false。默认init(undefined)路径假设import.meta.url与fetch()在 Node 中都无法指向本地文件系统的 WASM 文件。本包通过require.resolve(rhwp/core/rhwp_bg.wasm)定位随包分发的二进制用fs.readFileSync读出字节后显式init({ module_or_path: wasmBytes })完全避免网络 I/Osrc/wasm-init.js。子路径解析方式使其在 workspace、全局链接、hoistednode_modules场景下都能工作。模块无副作用getRhwpCore()多次调用返回同一个 PromiseWASM 每个进程只初始化一次。测试installMeasureTextWidthShim installs a deterministic shim only once与resolveRhwpWasmPath resolves the shipped rhwp/core wasm binary断言 wasm 文件大于 1 MB分别锁定了这两条行为。已知限制与适用边界README 明确列出三条限制使用前请对照HWPX 往返被上游禁用rhwp #196HWPX 输入可以接受但输出始终写为 HWP 5.x 二进制rhwp v0.7.x 处于 beta复杂表格、图片、图表或表单域在往返时偶有保真度损失非平凡编辑后建议用info和视觉渲染render验证结果Windows 安全模块、Hancom GUI 自动化、rhwp convert之外的只读分发文档不在本包范围内。测试与验证方法包内置了基于 Node 内置node:test的测试套件见 package.json 的scripts.test与scripts.lint。在包目录下执行npm test # 运行 node --test npm run lint # 对所有 src/test/bin 文件做 node --check 语法检查测试覆盖了值得关注的行为可作为你集成时的行为契约参考test/index.test.js空文本insertText、非正整数deleteText/createTable的入参校验replace-all的等长/加长/缩短替换、空替换删除、零匹配、大小写敏感开关、换行拒绝、Unicode 漂移拒绝含不写输出文件的断言create-blank → insert-text → info的 CLI 端到端往返test/cli.test.js缺失必填 flag 时 stderr 提示与退出码 1。小结k-skill-rhwp把 Rust WASM 的 HWP 编辑能力收敛为 Node 生态中一套小而稳的 CLI API安全的新文件输出契约、正文范围的搜索替换、非重叠替换语义、Unicode 大小写折叠护栏以及无 canvas 环境的自动布局垫片使其特别适合在无头服务器上由 Agent 批量执行 HWP 文档的机械化编辑。结合仓库内 rhwp-edit/SKILL.md、rhwp-advanced/SKILL.md 与 hwp/SKILL.md 三个技能即可组成覆盖编辑—调试—读取/转换的完整 HWP 自动化链路。包的源码、测试与版本历史可继续在仓库内查看src/cli.js、src/index.js、src/wasm-init.js、test/index.test.js 与 CHANGELOG.md。【免费下载链接】k-skill한국인을 위한 스킬 모음집 - 에이전트를 한국인으로项目地址: https://gitcode.com/GitHub_Trending/ks/k-skill创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考