简介
validate-npm-package-name,顾名思义,主要是用来校验包名是否符合规范。传入一个字符串,返回一个包含
以下两个属性的一个对象。
validForNewPackages :: Boolean
validForOldPackages :: Boolean
用法
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
}
源码分析
现在进入源码部分,我们可以看到package.json中包含了一些依赖
package.json
{
...
"dependencies": {
"builtins": "^1.0.3"
},
"devDependencies": {
"standard": "^8.6.0",
"tap": "^10.0.0"
},
"scripts": {
"cov:test": "TAP_FLAGS='--cov' npm run test:code",
"test:code": "tap ${TAP_FLAGS:-'--'} test/*.js",
"test:style": "standard",
"test": "npm run test:code && npm run test:style"
},
...
}
builtins是获取Node的内置模块,例如可以用以下代码获取Node中模块的信息
const m = require('module');
console.log(m);
红框内的就是内置模块的数据,内置模块允许修改,但是不支持新增,可参照Node.js的内置模块说明
standard是JavaScript代码规范,自带linter 和代码修正,可以参考StandardJs中文
tap是NodeJs的一个测试框架,支持覆盖测试等,并且拥有美观的测试输出,Node Tap
所以
npm run test
主要是执行了tap和standard的操作
index.js
代码里的正则可视图
/^(?:@([^/]+?)[/])?([^/]+?)$/
其他部分的直接贴注释:
'use strict'
// 包匹配的正则
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
// 获取NodeJs的内置模块
var builtins = require('builtins')
// 黑明单列表,name不允许存在在黑名单中
var blacklist = [
'node_modules',
'favicon.ico'
]
var validate = module.exports = function (name) {
// 保存警告
var warnings = []
// 保存错误
var errors = []
// 不允许为null
if (name === null) {
errors.push('name cannot be null')
return done(warnings, errors)
}
// 不允许为undefined
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
builtins.forEach(function (builtin) {
if (name.toLowerCase() === builtin) {
warnings.push(builtin + ' is a core module name')
}
})
// 长度不能超过214
// really-long-package-names-------------------------------such--length-----many---wow
// the thisisareallyreallylongpackagenameitshouldpublishdowenowhavealimittothelengthofpackagenames-poch.
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 ("~\'!()*")')
}
// 合法的url字符
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.scopedPackagePattern = scopedPackagePattern
// 处理的函数
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
}
总结
1.了解了builtins,standard,tap
2.复习了正则