validate-npm-package-name
git clone https://github.com/npm/validate-npm-package-name.git
validForNewPackages :: Boolean validForOldPackages :: Boolean
node.js/io.js
核心模块或保留/黑名单名称相同。例如,以下名称无效:http
、流动、节点单元、图标文件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") // 无效 则返回如下对象 { validForNewPackages: false, validForOldPackages: false, errors: [ 'name cannot contain leading or trailing spaces', 'name can only contain URL-friendly characters' ] }
'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 }
这一期简简单单,整整齐齐,可可爱爱