1.学习目标
- 了解
validate-npm-package-name
- 它的作用和场景
2.资料准备
git clone https://github.com/npm/validate-npm-package-name.git
3 初识–README.md
3.1 什么是validate-npm-package-name?
- 检测 npm 包的名称是否符合标准
- 此包导出一个同步函数,该函数以字符串作为输入,并返回一个具有两个属性的对象:
validForNewPackages :: Boolean
validForOldPackages :: Boolean
3.2. Naming Rules(命名规则)
- 包名称长度应大于零
- 包名称中的所有字符必须为小写,即不允许使用大写或混合大写的名称
- 包名称可以由连字符组成
- 包名称不得包含任何非url安全字符(因为名称最终是url的一部分)
- 包名称不应以开头。或_
- 包名称不应包含任何前导或尾随空格
- 包名称不应包含以下任何字符:~)(’*
- 包名称不能与
node.js/io.js
核心模块或保留/黑名单名称相同。例如,以下名称无效:http
、流动、节点单元、图标文件 - 包名称长度不能超过214
3.3 例子
3.3.1 Valid Names(有效名称)
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
}
3.3.2 无效名称
validate("excited!")
validate(" leading-space:and:weirdchars")
// 无效 则返回如下对象
{
validForNewPackages: false,
validForOldPackages: false,
errors: [
'name cannot contain leading or trailing spaces',
'name can only contain URL-friendly characters'
]
}
4. 深入–源码阅读
'use strict'
// 惰性匹配-正则表达式 链接地址:jex.im/regulex/
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
// node 所有的node内置模块
var builtins = require('builtins')
// 黑名单
var blacklist = [
'node_modules',
'favicon.ico'
]
/**
* validate:验证函数
* name:包名
*/
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)
}
// 是否为string
if (typeof name !== 'string') {
errors.push('name must be a string')
return done(warnings, errors)
}
// 验证包名的长度不能为0
if (!name.length) {
errors.push('name length must be greater than zero')
}
// 验证包名是否以.开始
// .match(/^\./) 匹配除换行符 \n 之外的任何单字符。要匹配 . ,请使用 \.
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 核心模块名称,如http、events、util等
//包名不能是node.js/io.js 核心模块 或者保留的名称
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.
// 包名称长度不能超过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 ("~\'!()*")')
}
// 包名不得包含任何非 url 安全字符
// 关于encodeURIComponent不转义哪些字符
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
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]
//对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)
}
// scopedPackagePattern 暴露给外面使用,方便私域定制npm发布设置校验规则
validate.scopedPackagePattern = scopedPackagePattern
/**
* 结果返回函数
* @param {*} warnings 警告的数组
* @param {*} errors 错误的数组
* @returns
*/
var done = function (warnings, errors) {
var result = {
//一般用这个属性来判断一个包名是否合法
validForNewPackages: errors.length === 0 && warnings.length === 0,
//用于兼容最开始node package name 带来的遗留问题,比如报名不规范等
validForOldPackages: errors.length === 0,
warnings: warnings,
errors: errors
}
if (!result.warnings.length) delete result.warnings
if (!result.errors.length) delete result.errors
return result
}
5.总结
这一期简简单单,整整齐齐,可可爱爱