每天一个npm包:validate-npm-package-name
前端三元同学
共 5887字,需浏览 12分钟
· 2021-06-21
“ 当你热爱生活,你才会变得快乐。”
validate-npm-package-name这个包相信大家都不陌生,存在于大多数CLI脚手架类工具中被使用。比如在create-react-app[1]中。
function checkAppName(appName) {
const validationResult = validateProjectName(appName);
// 根据validForNewPackages字段判断是否是合法的包名
if (!validationResult.validForNewPackages) {
console.error(
chalk.red(
`Cannot create a project named ${chalk.green(
`"${appName}"`
)} because of npm naming restrictions:\n`
)
);
// 打印错误、警告
[
...(validationResult.errors || []),
...(validationResult.warnings || []),
].forEach(error => {
console.error(chalk.red(` * ${error}`));
});
console.error(chalk.red('\nPlease choose a different project name.'));
// 退出进程
process.exit(1);
}
...
}
那么接下来跟我一起翻一番源码吧。
由于源码不多,直接就贴注释了,通过源码可以学习到一个合格的包名应该符合哪些规则,以及里面有一小段代码还是挺有意思的。
builtins模块
'use strict'
var semver = require('semver')
module.exports = function (version) {
// 获取node版本
version = version || process.version
var coreModules = [
'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'
]
if (semver.lt(version, '6.0.0')) coreModules.push('freelist')
if (semver.gte(version, '1.0.0')) coreModules.push('v8')
if (semver.gte(version, '1.1.0')) coreModules.push('process')
if (semver.gte(version, '8.1.0')) coreModules.push('async_hooks')
if (semver.gte(version, '8.4.0')) coreModules.push('http2')
if (semver.gte(version, '8.5.0')) coreModules.push('perf_hooks')
return coreModules
}
validate-npm-package-name
'use strict'
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
// 这个包是包括node内置 module的列表
var builtins = require('builtins')
// 保留名(黑名单)
var blacklist = [
'node_modules',
'favicon.ico'
]
var validate = module.exports = function (name) {
// 警告:用于表示过去package name允许、如今不允许的兼容error
var warnings = []
// 存储不符号合格的包名的规则
var errors = []
// 校验格式
if (name === null) {
errors.push('name cannot be null')
return done(warnings, errors)
}
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)
}
// 校验包名长度必须大于0
if (!name.length) {
errors.push('name length must be greater than zero')
}
// 校验包名不能以.开头
if (name.match(/^\./)) {
errors.push('name cannot start with a period')
}
// 校验包名不能以_开头、这里复习了下match用法
// '.'.match(/^_/) === null
if (name.match(/^_/)) {
errors.push('name cannot start with an underscore')
}
// 校验包名不能包含任何的前导、后导空格
if (name.trim() !== name) {
errors.push('name cannot contain leading or trailing spaces')
}
// 校验包名不能为保留字
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 内置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.
// 校验包名最大长度
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')
}
// 校验包名不能包含特殊字段 ~'!()*
// name.split('/').slice(-1)[0] => 获取包名、之所以要这样处理是因为
// name.split('/') 处理 npm package scope场景
// slice(-1)[0] 保证永远截取包名正确
// 'koa'.split('/').slice(-1)[0] // 'koa'
// '@babel/core'.split('/').slice(-1)[0] // 'core'
// /[~'!()*]/.test('@babel/core'.split('/').slice(-1)) // false
// /[~'!()*]/.test('@babel/co*re'.split('/').slice(-1)) // true
if (/[~'!()*]/.test(name.split('/').slice(-1)[0])) {
warnings.push('name can no longer contain special characters ("~\'!()*")')
}
// 包名不能包含non-url-safe字符
// 关于encodeURIComponent不转义哪些字符
// https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
if (encodeURIComponent(name) !== name) {
// 这里主要处理 scope package name 比如 @babel/core
var nameMatch = name.match(scopedPackagePattern)
if (nameMatch) {
var user = nameMatch[1] // 比如 bebel
var pkg = nameMatch[2] // 比如得到 core
// 如果没有异常 直接返回
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
// 返回结果的util方法
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
}
好了,今天就到这结束了,下期见。
References
[1]
create-react-app: https://link.zhihu.com/?target=https%3A//github.com/facebook/create-react-app/blob/2d1829eaf6ff1308da00720fa9984620dd0fb296/packages/create-react-app/createReactApp.js%23L850
结尾
如果觉得这篇文章还不错,来个分享、点赞、在看三连吧,让更多小伙伴看到~
评论
一个朋友
一个朋友,在深圳奋斗7年,和女友在去年合力在龙华买了一套房,总价600万,首付3成。但就在昨天,他们崩溃了。深圳推出可售型人才住房,就在他们新房附近,同样面积,总价不到400万,售价近乎腰斩。他们想不明白,同样是深圳人,买房人为什么都要被当成炒房客对待?二手房冰封,卖不出,新房不断打着,像极了上世纪
嵌入式Linux
0
真高!比亚迪员工爆料比亚迪在越南的薪资水平:基本工资480万,全勤奖35万,交通补助20万,餐补110万,每周6天,每天10小时
上一篇:某大公司为逼迫员工离职,竟然把他的工位安排到厕所旁,没想到他直接开始记录领导的如厕时间,还发到公司大群...对此,你怎么看?--完--PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。全文完,感谢你的耐心阅读。如果你还想看到我的文章,请一定给本
开发者全社区
0
老爸嘲讽我了,写破代码一年就挣十几万,他在工地带50个工人,一个月光人头费就3万,让我滚回去跟他干!
点击上方 "大数据肌肉猿"关注, 星标一起成长点击下方链接,进入高质量学习交流群今日更新| 1052个转型案例分享-大数据交流群来自:网络,侵删有个网友的父亲是做工程的,天天就嘲笑他,说他天天写着破代码有啥用,一年就拿个十多万的死工资,然后告诉他自己在工地里面带了50个工人,一个月能抽三万
程序源代码
0
测试新人,如何快速上手一个陌生的系统!
大家好,我是狂师!作为刚入行不久的测试新人,面对一个陌生的系统时,可能会感到有些手足无措。面对一个全新的系统系统,如何快速上手并展开有效的测试工作是一个重要的挑战。本文将探讨测试新人如何通过一系列步骤和策略,快速熟悉并掌握新系统的测试要点,从而提高测试效率和质量。本文旨在为测试新手提供一份指导,帮助
测试开发技术
0
Windows格式化对话框是一个使用了30年的 “临时解决方案”
戴夫-普卢默(Dave Plummer)是微软的资深工程师,曾创造了任务管理器、Windows 弹球、原生 ZIP 支持(微软出钱买断该功能后,他用这笔钱购买了一辆红色克尔维特)等传奇。近日他在自己的 X 账户上分享了创建 "格式化" 对话框的故事 —— 称其是一个使用了长达 30 年的 “临时解决
开源Linux
0
一个神奇的 Linux命令——type
转自:科学随想录在Linux系统中,了解命令的类型、位置和完整路径对于系统管理和开发非常重要。type命令是一个强大而实用的工具,能够帮助我们查看给定命令的类型、位置和完整路径。在本文中,我们将深入探索type命令的用法和功能,并提供详细的代码示例和输出,以帮助读者全面了解该命令。第一部分:type
开源Linux
0
有意思!一个关于 Spring 历史的在线小游戏
发现 Spring One 的官网上有个好玩的彩蛋,分享给大家!进到Spring One的官网,可以看到右下角有个类似马里奥游戏中的金币图标。点击该金币之后,会打开一个新的页面,进入下面这样一个名为:The History Of Spring 的在线小游戏你可以使用上下左右的方向键来控制Spring
公众号程序猿DD
1
【Python】coverage,一个有趣的 Python 库!
大家好,今天为大家分享一个有趣的 Python 库 - coveragepy。Github地址:https://github.com/nedbat/coveragepy在软件开发中,测试是确保代码质量和稳定性的关键步骤之一。而代码覆盖率则是衡量测试覆盖代码的程度的重要指标之一。Python cove
机器学习初学者
0