译:我在 4.5 小时内使用 Codex CLI 和 GPT-5.2 将 JustHTML 从 Python 移植到了 JavaScript
原文: https://simonwillison.net/2025/Dec/15/porting-justhtml/
作者: Simon Willison
译者: Gemini 3 Pro High
2025年12月15日
我昨天写了关于 JustHTML 的文章——这是 Emil Stenström 的项目,旨在利用运行于全面的 html5lib-tests 测试库之上的编码代理,构建一个新的、符合标准的纯 Python 代码 HTML5 解析器。昨晚,纯粹出于好奇,我决定尝试使用 Codex CLI 和 GPT-5.2,以尽可能少的精力将 JustHTML 从 Python 移植到 JavaScript。结果超出了我的预期。
简述
我构建了 simonw/justjshtml,这是一个 JavaScript 中的无依赖 HTML5 解析库,它通过了 html5lib-tests 套件中的 9,200 项测试,并模仿了 Emil 的 JustHTML 库的 API 设计。
这只用了两个初始提示和一些微小的后续跟进。在 Codex CLI 中运行的 GPT-5.2 不间断地运行了几个小时,消耗了 1,464,295 个输入 token,97,122,176 个缓存输入 token 和 625,563 个输出 token,最终生成了 9,000 行经过充分测试的 JavaScript 代码,共计 43 次提交。
从项目构思到完成库的时间:大约 4 小时,在此期间我还和家人一起购买并装饰了圣诞树,并观看了最新的《利刃出鞘》(Knives Out) 电影。
一些背景
十年前 HTML5 规范最重要的贡献之一是它精确地规定了应如何解析无效 HTML。世界上充满了无效文档,拥有涵盖这些情况的规范意味着浏览器可以用相同的方式处理它们——在构建解析软件时不再需要担心“未定义行为”。
不出所料,这些无效解析规则相当复杂!Simon Pieters 的免费在线书籍 HTML 解析器的特质 (Idiosyncrasies of the HTML parser) 深入探讨了这一主题,特别是 第 3 章:HTML 解析器。
Python 的 html5lib 项目启动了 html5lib-tests 仓库,其中包含一组独立于实现的测试。此后,这些测试已成为 HTML5 解析器互操作性测试的黄金标准,并被诸如 Servo 之类的项目所使用,Servo 使用它们来帮助构建 html5ever,这是一个用 Rust 编写的“高性能浏览器级 HTML5 解析器”。
Emil Stenström 的 JustHTML 项目是一个纯 Python 实现的 HTML5 解析器,通过了完整的 html5lib-tests 套件。Emil 花了几个月时间将其作为一个副业项目,特意选择了一个拥有全面现有测试套件的问题,以看看利用编码代理能走多远。
有一次,他让代理根据对 Rust html5ever 库的仔细检查来重写它。我不知道这其中有多少是直接翻译,有多少是灵感借鉴(这里是 Emil 对此的评论)——他的项目总共有 1,215 次提交,所以看起来包含了大量的迭代,而不仅仅是直接移植。
我的项目就是一个直接移植。我指示 Codex CLI 构建 Emil 的 Python 代码的 JavaScript 版本。
详细过程
我从一些准备工作开始。我检出了两个仓库,并为新项目创建了一个空的第三个目录:
cd ~/dev
git clone https://github.com/EmilStenstrom/justhtml
git clone https://github.com/html5lib/html5lib-tests
mkdir justjshtml
cd justjshtml
然后我像这样为 GPT-5.2 启动了 Codex CLI:
codex --yolo -m gpt-5.2
那个 --yolo 标志是 --dangerously-bypass-approvals-and-sandbox(危险地绕过批准和沙箱)的快捷方式,正如听起来那样危险。
我的第一个提示告诉 Codex 检查现有代码,并使用它为新的 JavaScript 库构建规范:
We are going to create a JavaScript port of ~/dev/justhtml - an HTML parsing library that passes the full ~/dev/html5lib-tests test suite. It is going to have a similar API to the Python library but in JavaScript. It will have no dependencies other than raw JavaScript, hence it will work great in the browser and node.js and other environments. Start by reading ~/dev/justhtml and designing the user-facing API for the new library - create a spec.md containing your plan.
我们将创建 ~/dev/justhtml 的 JavaScript 移植版 - 这是一个通过完整 ~/dev/html5lib-tests 测试套件的 HTML 解析库。它将拥有与 Python 库类似的 API,但是是 JavaScript 版本的。除了原生 JavaScript 外它没有任何依赖,因此它将在浏览器、node.js 和其他环境中运行良好。首先阅读 ~/dev/justhtml 并为新库设计面向用户的 API - 创建一个包含你计划的 spec.md。
我审查了规范,其中包括一组建议的里程碑,并告诉它再添加一个:
Add an early step to the roadmap that involves an initial version that parses a simple example document that is valid and returns the right results. Then add and commit the spec.md file.
在路线图中添加一个早期步骤,涉及解析一个简单有效示例文档并返回正确结果的初始版本。然后添加并提交 spec.md 文件。
这是生成的 spec.md 文件。我对该初始版本的请求变成了“里程碑 0.5”,如下所示:
里程碑 0.5 — 端到端冒烟解析(单个有效文档)
- 实现最小的端到端切片,以便公共 API 尽早真实可用:
new JustHTML(\"<html><head></head><body><p>Hello</p></body></html>\")返回具有预期标签结构和文本节点的树。- 对于此有效输入,
doc.toText()返回\"Hello\"且doc.errors为空。- 添加
scripts/smoke.js(无依赖),运行该示例并断言预期的结构/输出。- 门控:
node scripts/smoke.js通过。
然后我告诉它:
实现里程碑 0.5
然后它就开始工作了。生成的代码似乎可以工作,所以我说:
Configure GitHub Actions test.yml to run that on every commit, then commit and push
配置 GitHub Actions test.yml 以在每次提交时运行它,然后提交并推送
此时我运行了 git init 并为该项目创建了一个私有 GitHub 仓库,并设置本地目录以推送到该远程仓库。
这是那次初始推送。然后我告诉它:
OK do the rest, commit and push often
好的,做剩下的部分,经常提交和推送
这就差不多了!
我将笔记本电脑设置为不休眠,让它自行运行,而我们去买圣诞树了。“经常提交和推送”意味着我可以通过刷新 GitHub 上的提交日志在手机上监控其进度。
我是在我的每月 20 美元的 ChatGPT Plus 账户上运行此操作的,该账户对 Codex CLI 有五小时的 token 限额窗口。这在下午 6:35 用完了,Codex 暂停了,所以我等到下午 7:14 的重置点,然后输入:
继续
晚上 9:30,它宣布完成,并显示以下摘要消息:
• What’s Done
- html5lib-tests now run in CI and pass: tokenizer 6810/6810, tree 1770/1782
(12 skipped: #script-on), serializer 230/230, encoding 82/83 (1 skipped:
scripted) (.github/workflows/test.yml:1).
- Public API expanded: stream() (src/stream.js:1), CSS selectors query()/\n matches() (src/selector.js:1), and toMarkdown() (src/markdown.js:1), all
exported via src/index.js:1.
- Added no-deps unit scripts for selectors/stream/markdown (scripts/run-\n selector-tests.js:1, scripts/run-stream-tests.js:1, scripts/run-markdown-\n tests.js:1) and wired them into CI.
- Fixed TreeBuilder so <br> no longer closes <p> (src/treebuilder.js:647).
作为最后的润色,我让它添加了一个 playground 界面,这样我就可以在浏览器中试用新库。我提示道:
Add a playground.html in the top level folder which loads the necessary ES modules from ./src/… and implements the exact same functionality as seen on https://tools.simonwillison.net/justhtml but using the JavaScript library instead of Pyodide
在顶层文件夹中添加一个 playground.html,从 ./src/… 加载必要的 ES 模块,并实现与 https://tools.simonwillison.net/justhtml 上完全相同的功能,但使用 JavaScript 库而不是 Pyodide
它使用 curl 获取了我现有的 JustHTML playground 页面(在此处描述),并构建了一个新的 playground.html 文件,改为加载新的 JavaScript 代码。这工作得完美。
我为我仍然私有的仓库启用了 GitHub Pages,这意味着我可以通过此 URL 访问新的 playground:
https://simonw.github.io/justjshtml/playground.html

现在它只需要一些文档:
Add a comprehensive README with full usage instructions including attribution plus how this was built plus how to use in in HTML plus how to use it in Node.js
添加一个全面的 README,包含完整的使用说明,包括归属、它是如何构建的、如何在 HTML 中使用它以及如何在 Node.js 中使用它
你可以在这里阅读结果。
现在我们总共用了八个提示,运行了四个多小时,而且我已经装饰了圣诞树并在 Netflix 上观看了《死人复活》(Wake Up Dead Man)。
根据 Codex CLI:
Token 使用情况:总计=2,089,858 输入=1,464,295 (+ 97,122,176 缓存) 输出=625,563 (推理 437,010)
我的 llm-prices.com 计算器 估计,如果我按 API 价格支付这些 token,费用为 29.41 美元,但它们包含在我的每月 20 美元的 ChatGPT Plus 订阅中,因此对我来说实际额外费用为零。
我们能从中学到什么?
我分享这个项目是因为我认为它展示了 2025 年 12 月 LLM 状态的许多有趣之处。
- 前沿 LLM 确实可以在最少的监督下执行复杂的、耗时数小时的任务,并进行数百次工具调用。我为此使用了 GPT-5.2,但我没有理由相信 Claude Opus 4.5 或 Gemini 3 Pro 无法实现同样的事情——我没有尝试的唯一原因是我不想在更多的运行上再消耗 4 个小时的时间和数百万个 token。
- 如果你能将问题简化为一个健壮的测试套件,你就可以放心地让编码代理循环在上面运行,并高度确信它最终会成功。几个月前我称之为设计代理循环。我认为这是释放 LLM 处理复杂任务潜力的关键技能。
- 通过编码代理将整个开源库从一种语言移植到另一种语言效果极佳。
- 代码如此便宜,几乎是免费的。有效的代码仍然有成本,但既然编码代理可以在进行过程中检查其工作,这种成本已经大幅下降。
- 我们甚至还没有开始探讨这种开发风格的礼仪和伦理。在看电影的同时,在几个小时内大量生产像这样的库的直接移植版,是否负责任和得体?需要什么才能让这样构建的代码在生产中被信任?
最后,我提出一些开放性问题:
- 这个库是否构成对 Rust 库或 Python 库版权的法律侵犯?
- 即使这是合法的,以这种方式构建库是否合乎道德?
- 这种开发形式是否会伤害开源生态系统?
- 鉴于大部分工作是由 LLM 产生的,我甚至可以主张对此拥有版权吗?
- 发布以这种方式构建的软件库是否负责任?
- 如果由专家团队在几个月内手工制作,这个库会好多少?