1. 前言
1.1 环境
- 操作系统: macOS 11.5.2
- 浏览器: Chrome 94.0.4606.81
validate-npm-package-name 3.0.0
1.2 阅读该文章可以get以下知识点
-
2. 开始
2.1 如何使用
```javascript 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”)
// All of the above names are valid, so you’ll get this object back: // 如果校验通过,返回下面的对象 { validForNewPackages: true, validForOldPackages: true }
// 非法名称 validate(“excited!”) validate(“ leading-space:and:weirdchars”)
// That was never a valid package name, so you get this: // 名称有问题,返回下面的报错信息 { validForNewPackages: false, validForOldPackages: false, errors: [ ‘name cannot contain leading or trailing spaces’, ‘name can only contain URL-friendly characters’ ] }
<a name="fYtTV"></a>
## 2.2 源码
```javascript
// 作用域正则,例如@vue/component,会被match拆分成vue和component
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
// 返回node内置模块列表[
'assert',
'buffer',
'child_process',
'cluster',
'console',
'constants',
'crypto',
'dgram',
'dns',
'domain',
'events',
'fs',
'http',
'https',
'module',
'net',
'os',
'path',
'punycode',
'querystring',
'readline',
'repl',
'stream',
'string_decoder',
'sys',
'timers',
'tls',
'tty',
'url',
'util',
'vm',
'zlib'
]
// 里面就是一个json文件,所以不与安装的node程序有关
var builtins = require('builtins')
// 黑名单,不管node_modules和ico文件
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)
}
// 上面的三个判断都直接return
// 空字符串
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内置模块命名
builtins.forEach(function (builtin) {
if (name.toLowerCase() === builtin) {
warnings.push(builtin + ' is a core module name')
}
})
// 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 ("~\'!()*")')
}
// ;/?:@&=+$,# 这些用于分隔 URI 组件的标点符号,会被转义,如%26等等,目前大部分scope的包都是以@开头
if (encodeURIComponent(name) !== name) {
// Maybe it's a scoped package name, like @user/package
var nameMatch = name.match(scopedPackagePattern)
if (nameMatch) {
// 前面是作用域user
var user = nameMatch[1]
// 后面是具体的包 package
var pkg = nameMatch[2]
// 相等直接返回
if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
return done(warnings, errors)
}
}
// 不相等抛出错误
errors.push('name can only contain URL-friendly characters')
}
// 最后都到了done函数
return done(warnings, errors)
}
validate.scopedPackagePattern = scopedPackagePattern
// 清洗数据,将不存在的warngings和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
}
3. 总结
源码很短就100行左右,主要用来校验npm包名是否符合标准,主要校验以下几种情况,是不合法的
- 直接返回的情况
- undefined
- null
- 不是字符串类型
放入警告和错误列表的情况