03 / 真实软件包案例 / 阅读约 7 分钟

slugify:为什么 URL 里还有“!”?

“Déjà Vu!” 变成了“deja-vu!”,但你想要的是“deja-vu”。用 REA 分析这个 JavaScript 软件包,找到控制标点的设置,再验证结果。

本页内容
slugify 1.6.6 / MITREA 6.4.0验证于 2026 年 10 月 12 日

直接看答案

lower: true 只会把大写字母改成小写。再加上 strict: true 就能同时移除标点。这是需要开启的选项,并非库本身的错误。

可用配置
slugify("Déjà Vu!", { lower: true, strict: true })
// → "deja-vu"

01. 我们想要的 URL

slug 是 URL 末尾便于阅读的一段,例如 deja-vu (完整 URL 为 example.com/posts/deja-vu)。本示例使用真实的 slugify 1.6.6 npm 发布版本。下方结果来自在本地运行该版本。

试试下方标题,再开启 移除标点 看看差别。

试用真实软件包 slugify 1.6.6
生成的 URL
example.com/posts/deja-vu!

还有“!”?请开启 移除标点。

JavaScript 选项{ lower: true, strict: false }

在浏览器本地运行,不上传任何内容。REA 的使用见文字教程。

下面是同样的 JavaScript 对比:

软件包的实际行为
slugify("Déjà Vu!")
// → "Deja-Vu!"

slugify("Déjà Vu!", { lower: true })
// → "deja-vu!"

重音符号消失了,感叹号却还在。我们用 REA 定位软件包入口文件,读取过滤代码,并查明哪个选项会移除感叹号。你可以按下方步骤复现。

02. 下载软件包,用 REA 分析

我们下载了固定版本的 npm tarball,解压时没有安装或运行软件包。以下准备命令需要 shell 中有 tar:

终端
mkdir rea-slugify-case
cd rea-slugify-case
npm pack slugify@1.6.6
tar -xzf slugify-1.6.6.tgz

随后,我们对解压后的 package 目录运行 REA 的 JavaScript 应用分析器:

如果更习惯使用编程智能体,请替换路径并粘贴这段提示词:

复制到编程智能体
使用 REA 分析 /absolute/path/to/rea-slugify-case/package。我用 slugify 生成文章 URL。为什么 slugify('Déjà Vu!', { lower: true }) 会保留感叹号?找到入口文件,展示允许保留它的代码,并指出移除它的选项。不要修改软件包。

也可以直接在终端收集分析结果:

终端
npx -y rea-agents@6.4.0 analyze-javascript-application ./package --json > analysis.json

REA 将软件包识别为 slugify,版本为 1.6.6,入口为 ./slugify.js。报告记录了三个相关文件,解析失败数为零;同时将整体图覆盖范围标记为 partial(部分覆盖),我们在发布的摘要中保留了这一点。

这是可读的 JavaScript 发行包。REA 提供了文件清单和分析上下文,随后通过源码检查和直接验证确认行为,未涉及原生代码反编译。

03. 找到移除标点的选项

在发布包的 slugify.js中,第 33–42 行完成字符串规范化、语言或字符映射替换,以及字符过滤。默认过滤规则明确允许感叹号。

slugify.js · 第 41–47 行
// remove not allowed characters
.replace(options.remove || /[^\w\s$*_+~.()'"!\-:@]+/g, '')
}, '');

if (options.strict) {
  slug = slug.replace(/[^A-Za-z0-9\s]/g, '');
}

strict 分支随后执行,移除字母、数字和空白以外的字符。小写转换是第 57–58 行的独立操作。由此可以提出一个可测试的预测:

预测
slugify("Déjà Vu!", { lower: true, strict: true })
// should return "deja-vu"

同一文件也解释了为什么多个空格合并成一个分隔符,为什么 & 变成 and,以及为什么德语设置会改变 Ä 变为 AE。

04. 在真实软件包上运行验证

我们对未经修改的 1.6.6 版本执行了八项断言,包括最初的问题和几个相关行为。

8 / 8
验证通过。

原始软件包 · Node.js 22.23.1 · macOS arm64

输入选项实际结果
Déjà Vu!默认Deja-Vu!
Déjà Vu!lowerdeja-vu!
Déjà Vu!lower + strictdeja-vu
hello world(两侧有空格)默认hello-world
Rock & Roll默认Rock-and-Roll
Äpfel德语设置 + loweraepfel
空字符串默认空字符串
42(数字)默认抛出“string argument expected”错误

查看已记录的验证结果,或使用上方交互演示。演示在浏览器中运行同一固定版本的软件包。

05. 我们测试了什么

对于这个版本和这些输入,源码与实际输出一致。如果想得到 deja-vu,请同时使用 lower: true 和 strict: true。

注意验证范围。 八项验证不能覆盖所有 Unicode 或语言设置行为。REA 的关系图并不完整;图中缺少某个关系,并不能证明关系不存在。我们没有重建原生二进制文件,也没有恢复无法获取的源码。

发布包中的源码可读,因此直接检查源码也是可行方法。这个案例演示完整的分析习惯:确认分析对象,检查一条规则,再对照原始实现验证结论。

06. 下载并运行这个示例

下载小型复现资料包,其中包含固定版本的依赖、全部八项断言,以及收集 REA 证据的步骤。

下载复现资料包

在解压后的资料包中执行
npm install --ignore-scripts
node verify.mjs

断言脚本会打印每项结果,任一验证失败时以错误退出。只有到这一步,Node.js 才会执行 npm 软件包;此前 REA 的静态分析不会执行它。

试试另一篇教程查明应用把导出文件保存在哪里。

证据: REA 分析摘要 · 验证结果 · 已分析的源码 · MIT 许可证。软件包由 simov 和贡献者开发。分析和运行验证于 2026 年 10 月 12 日在本地完成。公开摘要已省略本地文件系统路径。

第一次使用这个工具? REA 是什么? · 我们如何核查教程