今天学习validate-npm-package-name的源码,以下内容来自个人总结
为什么要读validate-npm-package-name的源码?
因为我们常用的脚手架都用到了这个包,这个包用于对我们创建的项目的名字有了一定的规范。没有规矩,难以成方圆嘛。
因为我自己的技术栈是react,所以我关注了create-react-app 中对这个包的应用
const validateProjectName = require('validate-npm-package-name');...function chaeckAppName(appName){// 通过 这个包的能力有针对性的校验名字const validationResult = validateProjectName(appName);// 源码中会返回一个validForNaePackages的boolean值,用于判断项目名是否通过了validationResult的校验if (!validationResult.validForNewPackages) {console.error(chalk.red(`Cannot create a project named ${chalk.green(`"${appName}"`)} because of npm naming restrictions:\n`));// 用于输出 validationResult 返回的所有错误信息(包括警告)[...(validationResult.errors || []),...(validationResult.warnings || []),].forEach(error => {console.error(chalk.red(` * ${error}`));});console.error(chalk.red('\nPlease choose a different project name.'));// 退出命令process.exit(1);}...其余代码...}
出处链接:这里
解析validate-npm-package-name包
// 启用严格模式'use strict'// 定义正则用于约束名字var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')// Node.js 提供的所有模块的名称列表。 可用于验证模块是否由第三方维护。var builtins = require('builtins')// 黑名单var blacklist = ['node_modules','favicon.ico']// 主要方法var validate = module.exports = function (name) {// 警告信息var warnings = []// 错误信息var errors = []// 输入名字不能为空if (name === null) {errors.push('name cannot be null')return done(warnings, errors)}// 输入名字不能是undefinedif (name === undefined) {errors.push('name cannot be undefined')return done(warnings, errors)}// 输入名字要为字符串,不能是数字?不知道这里是否进行了内置的转换 number=>stringif (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// 用于验证输入的名字是否与core module具有相同的名字,如果有就抛出对应名称的警告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 ("~\'!()*")')}// 包名不能包含non-url-safe字符// 关于encodeURIComponent不转义哪些字符if (encodeURIComponent(name) !== name) {// Maybe it's a scoped package name, like @user/packagevar 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// 调用公共方法,返回对应的warnings 和errorsvar 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.warningsif (!result.errors.length) delete result.errorsreturn result}
