validate-npm-package-name 这个包主要介绍了合格的包名应该符合哪些规则,才可以通过正确的包名去创建项目,如我们常用的vue-cli创建项目等等都是使用了这些校验规则。
- 源码地址: github.com/npm/validat…
- 《JavaScript 正则表达式迷你书》学习:juejin.cn/post/684490…
通过源码地址、拉取源码
-
npm install
-
npm run test
将源码包跑起来,可以看到在test目录index入口文件下的测试用例均能够passed
源码分析
根目录下的index入口文件,导出一个validate函数(10 ~ 91 行)
/**
- name 传入的包名
*/
var validate = module.exports = function (name) {
//todos...
}
var validate = module.exports = function (name) {
//默认输出的错误信息
var warnings = []
var errors = []
//不能为null
if (name === null) {
errors.push('name cannot be null')
return done(warnings, errors)
}
//不能为空
if (name === undefined) {
errors.push('name cannot be undefined')
return done(warnings, errors)
}
//必须是个字符串
if (typeof name !== 'string') {
errors.push('name must be a string')
return done(warnings, errors)
}
//必须存在长度
if (!name.length) {
errors.push('name length must be greater than zero')
}
//不能以点开头
if (name.match(/^\./)) {
errors.push('name cannot start with a period')
}
//不能以下划线开头
if (name.match(/^_/)) {
errors.push('name cannot start with an underscore')
}
//不能含有空格尾随
if (name.trim() !== name) {
errors.push('name cannot contain leading or trailing spaces')
}
// No funny business (不能大小写乱写)
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
(不能是node的内置模块,如http,events, util等等)
builtins.forEach(function (builtin) {
//builtins是一个node的内置模块包
if (name.toLowerCase() === builtin) {
warnings.push(builtin + ' is a core module name')
}
})
//包名不能太长
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 ("~\'!()*")')
}
//不能包含中文
if (encodeURIComponent(name) !== name) {
// Maybe it's a scoped package name, like @user/package
//类似包名 @package/user
var nameMatch = name.match(scopedPackagePattern)
if (nameMatch) {
var user = nameMatch[1]//package
var pkg = nameMatch[2]//user
//对user和pkg分别进行校验
if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
return done(warnings, errors)
}
}
errors.push('name can only contain URL-friendly characters')
}
return done(warnings, errors)
}
//校验后均会执行的方法
/**
-
@param {*} warnings 警告的数组
-
@param {*} errors 错误的数组
-
@returns
*/
var done = function (warnings, errors) {
var result = {
//如果没有警告和错误 为true
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
}
源码阅读收获
通过这期的源码阅读,细致了解到了npm包命名的规范以及源码实现思路,进一步理解了包名的校验规则。