今天学习validate-npm-package-name的源码,以下内容来自个人总结

为什么要读validate-npm-package-name的源码?

因为我们常用的脚手架都用到了这个包,这个包用于对我们创建的项目的名字有了一定的规范。没有规矩,难以成方圆嘛。
因为我自己的技术栈是react,所以我关注了create-react-app 中对这个包的应用

  1. const validateProjectName = require('validate-npm-package-name');
  2. ...
  3. function chaeckAppName(appName){
  4. // 通过 这个包的能力有针对性的校验名字
  5. const validationResult = validateProjectName(appName);
  6. // 源码中会返回一个validForNaePackages的boolean值,用于判断项目名是否通过了validationResult的校验
  7. if (!validationResult.validForNewPackages) {
  8. console.error(
  9. chalk.red(
  10. `Cannot create a project named ${chalk.green(
  11. `"${appName}"`
  12. )} because of npm naming restrictions:\n`
  13. )
  14. );
  15. // 用于输出 validationResult 返回的所有错误信息(包括警告)
  16. [
  17. ...(validationResult.errors || []),
  18. ...(validationResult.warnings || []),
  19. ].forEach(error => {
  20. console.error(chalk.red(` * ${error}`));
  21. });
  22. console.error(chalk.red('\nPlease choose a different project name.'));
  23. // 退出命令
  24. process.exit(1);
  25. }
  26. ...
  27. 其余代码
  28. ...
  29. }

出处链接:这里

解析validate-npm-package-name包

  1. // 启用严格模式
  2. 'use strict'
  3. // 定义正则用于约束名字
  4. var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
  5. // Node.js 提供的所有模块的名称列表。 可用于验证模块是否由第三方维护。
  6. var builtins = require('builtins')
  7. // 黑名单
  8. var blacklist = [
  9. 'node_modules',
  10. 'favicon.ico'
  11. ]
  12. // 主要方法
  13. var validate = module.exports = function (name) {
  14. // 警告信息
  15. var warnings = []
  16. // 错误信息
  17. var errors = []
  18. // 输入名字不能为空
  19. if (name === null) {
  20. errors.push('name cannot be null')
  21. return done(warnings, errors)
  22. }
  23. // 输入名字不能是undefined
  24. if (name === undefined) {
  25. errors.push('name cannot be undefined')
  26. return done(warnings, errors)
  27. }
  28. // 输入名字要为字符串,不能是数字?不知道这里是否进行了内置的转换 number=>string
  29. if (typeof name !== 'string') {
  30. errors.push('name must be a string')
  31. return done(warnings, errors)
  32. }
  33. // 输入的名字必须要有长度
  34. if (!name.length) {
  35. errors.push('name length must be greater than zero')
  36. }
  37. // 输入的名字不能以点开头
  38. if (name.match(/^\./)) {
  39. errors.push('name cannot start with a period')
  40. }
  41. // 输入的名字不能以下划线开始
  42. if (name.match(/^_/)) {
  43. errors.push('name cannot start with an underscore')
  44. }
  45. // 输入的名字不能以空格结尾
  46. if (name.trim() !== name) {
  47. errors.push('name cannot contain leading or trailing spaces')
  48. }
  49. // No funny business
  50. // 不允许用户使用这些名字命名
  51. blacklist.forEach(function (blacklistedName) {
  52. if (name.toLowerCase() === blacklistedName) {
  53. errors.push(blacklistedName + ' is a blacklisted name')
  54. }
  55. })
  56. // Generate warnings for stuff that used to be allowed
  57. // core module names like http, events, util, etc
  58. // 用于验证输入的名字是否与core module具有相同的名字,如果有就抛出对应名称的警告
  59. builtins.forEach(function (builtin) {
  60. if (name.toLowerCase() === builtin) {
  61. warnings.push(builtin + ' is a core module name')
  62. }
  63. })
  64. // really-long-package-names-------------------------------such--length-----many---wow
  65. // the thisisareallyreallylongpackagenameitshouldpublishdowenowhavealimittothelengthofpackagenames-poch.
  66. // 规定输入名字的最大长度为214字符
  67. if (name.length > 214) {
  68. warnings.push('name can no longer contain more than 214 characters')
  69. }
  70. // mIxeD CaSe nAMEs
  71. // 不允许输入的名字包含大写字母
  72. if (name.toLowerCase() !== name) {
  73. warnings.push('name can no longer contain capital letters')
  74. }
  75. // 不允许输入的名字包含 ~ ' !()* 等符号
  76. if (/[~'!()*]/.test(name.split('/').slice(-1)[0])) {
  77. warnings.push('name can no longer contain special characters ("~\'!()*")')
  78. }
  79. // 包名不能包含non-url-safe字符
  80. // 关于encodeURIComponent不转义哪些字符
  81. if (encodeURIComponent(name) !== name) {
  82. // Maybe it's a scoped package name, like @user/package
  83. var nameMatch = name.match(scopedPackagePattern)
  84. if (nameMatch) {
  85. var user = nameMatch[1]
  86. var pkg = nameMatch[2]
  87. if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
  88. return done(warnings, errors)
  89. }
  90. }
  91. errors.push('name can only contain URL-friendly characters')
  92. }
  93. return done(warnings, errors)
  94. }
  95. validate.scopedPackagePattern = scopedPackagePattern
  96. // 调用公共方法,返回对应的warnings 和errors
  97. var done = function (warnings, errors) {
  98. var result = {
  99. // 我们一般用该属性来判断一个包名是否合法
  100. validForNewPackages: errors.length === 0 && warnings.length === 0,
  101. // 这个属性是用于兼容最开始node package name带来的遗留问题,那个时候有些包名不规范
  102. validForOldPackages: errors.length === 0,
  103. warnings: warnings,
  104. errors: errors
  105. }
  106. if (!result.warnings.length) delete result.warnings
  107. if (!result.errors.length) delete result.errors
  108. return result
  109. }

出处:validate-npm-package-name