- 本文参加了由公众号@若川视野 发起的每周源码共读活动,点击了解详情一起参与。
- 第7期 | validate-npm-package-name 检测 npm 包是否符合标准
前言
你知道vue-create是如何检测包的规范性的吗?阅读过vue-cli源码 传送门 的童鞋可能不难发现起作用的就是validate-npm-package-name这个包,包关键源码只有100多行,下面就来一起学习探讨下~
收获清单
- 保姆级源码调试步骤
- 如何检测包名的规范性
环境准备
源码下载
这里装包时要注意看包版本号是否存在npm view ** versions,否则会装不成功
git clone https://github.com/npm/validate-npm-package-name
cd validate-npm-package-name
npm install
node环境
阅读源码前先从readme看使用方法再从package.json看执行命令、支持环境等,从package.json可以看出validate-npm-package-name支持的node环境如下,执行调试前记得先检查自己的node版本
开启调试
今天的源码从readme中也可以知道开启调试的命令,但更通用的是点击悬浮package.json的script脚本后出现的调试脚本按钮,开启调试前先找到测试文件test/index.js和主函数文件lib/index.js打好断点,基本原则是哪里不会点哪里,点到会为止~
调试截图
源码分析
引入依赖及定义全局变量
// 正则匹配scope库
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
// 列出node.js内置模块
var builtins = require('builtins')
// 黑名单
var blacklist = [
'node_modules',
'favicon.ico',
]
done方法输出结果
主要是通过操作对象属性来动态返回warning跟errors
var done = function (warnings, errors) {
var result = {
validForNewPackages: errors.length === 0 && warnings.length === 0,
validForOldPackages: errors.length === 0,
warnings: warnings,
errors: errors,
}
if (!result.warnings.length) {
delete result.warnings
}
if (!result.errors.length) {
delete result.errors
}
return result
}
如validate('node_modules'),会得到如下图结果:
validate函数
function validate (name) {
var warnings = []
var errors = []
...
// 代码有删减,删减部分主要判断name是否为空,以. _等非法字符开头等情况
// trim()主要是去首尾空格,这里是判断包名是否包含空格
if (name.trim() !== name) {
errors.push('name cannot contain leading or trailing spaces')
}
// No funny business
// 不能是node_modules和favicon.ico
blacklist.forEach(function (blacklistedName) {
if (name.toLowerCase() === blacklistedName) {
errors.push(blacklistedName + ' is a blacklisted name')
}
})
// Generate warnings for stuff that used to be allowed
// core module names like http, events, util, etc
// 利用builtins判断报名是否是nodejs内置模块名
builtins({ version: '*' }).forEach(function (builtin) {
if (name.toLowerCase() === builtin) {
warnings.push(builtin + ' is a core module name')
}
})
// 长度不能超过214个字符
if (name.length > 214) {
warnings.push('name can no longer contain more than 214 characters')
}
// mIxeD CaSe nAMEs
// 名称不能再包含大写字母
if (name.toLowerCase() !== name) {
warnings.push('name can no longer contain capital letters')
}
// 名称不能再包含特殊字符("~\'!()*")
if (/[~'!()*]/.test(name.split('/').slice(-1)[0])) {
warnings.push('name can no longer contain special characters ("~\'!()*")')
}
// 利用把字符串作为URI 组件进行编码判断作用域包名
if (encodeURIComponent(name) !== name) {
// Maybe it's a scoped package name, like @user/package
var nameMatch = name.match(scopedPackagePattern)
if (nameMatch) {
var user = nameMatch[1]
var pkg = nameMatch[2]
if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
return done(warnings, errors)
}
}
errors.push('name can only contain URL-friendly characters')
}
return done(warnings, errors)
}
总结
validate-npm-package-name主要是对包名的合法性进行检测,若非法就返回对应的错误,代码量少且易读性强,很适合刚开始阅读源码的童鞋。通过对源码的解读也了解到可以利用builtins读取nodejs的内置模块,同时对字符串的匹配正则表达式是不二之选,正则表达式可能可读性不想,因此文章的最后给大家推荐一个正则可视化工具!