源码分析 - validate-npm-package-name
从包名的描述中,我们可以知道该包是用于验证 npm package name 是否合法。
示例
先看官方给的例子:
// 正确的命名
var validate = require('validate-npm-package-name')
validate('some-package')
validate('example.com')
validate('under_score')
validate('123numeric')
validate('@npm/thingy')
validate('@jane/foo.js')
// 以上的结果都为
/*
{
validForNewPackages: true,
validForOldPackages: true
}
*/
// 错误的命名
validate('excited!')
// validate(' leading-space:and:weirdchars')
validate(
'eLaBorAtE-paCkAgE-with-mixed-case-and-more-than-214-characters-----------------------------------------------------------------------------------------------------------------------------------------------------------',
)
/*
{
validForNewPackages: false,
validForOldPackages: false,
errors: [
'name cannot contain leading or trailing spaces',
'name can only contain URL-friendly characters'
]
}
{
validForNewPackages: false,
validForOldPackages: true,
warnings: [
"name can no longer contain capital letters",
"name can no longer contain more than 214 characters"
]
}
*/
从示例中我们可以知道, validate 函数并不是简单的返回一个 boolean,它返回一个对象包含
- 对于旧版 package name 的验证。(validForOldPackages)
- 对于新版 package name 的验证。(validForNewPackages)
- 警告 / 错误的提示信息。
项目分析
该项目的源码也就 100 多行,里面涉及大量的字符串和正则的比较,这里不会逐行去分析这些比较。 更多地关注项目的结构。
'use strict'
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
var builtins = require('builtins')
var blacklist = [
/* ... */
]
var validate = (module.exports = function (name) {
var warnings = []
var errors = []
return done(warnings, errors)
})
validate.scopedPackagePattern = scopedPackagePattern
var done = function (warnings, errors) {
var result = {
/* ... */
}
return result
}
里面两个核心函数 validate 和 done 的结合可谓巧妙。
核心函数
var validate = (module.exports = function (name) {
var warnings = []
var errors = []
// statements
return done(warnings, 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
}
done 函数是对输出结果进行格式化,validate 函数对输入的 name 进行一系列的验证后,将验证过程中的警告和错误推入数组中。
需要注意的是验证的先后顺序。
学习心得
事实上,我们可以将该库进行抽象,实现自己的验证库:
export function validate(somethingShouldBeValidate) {
const warnings = []
const errors = []
// do validate
return done(warnings, errors)
}
function done(warnings, errors) {
const result = {
isSuccess: errors.length === 0 && warnings.length === 0,
isWarning: warnings.length !== 0,
isError: errors.length !== 0,
warnings,
errors,
}
return result
}
验证逻辑和输出结果可以根据项目的要求而定。