源码阅读系列1:validate-npm-package-name 检测 npm 包是否符合标准

132 阅读1分钟

参加若川源码共读活动

源码地址:github.com/npm/validat…

1. 介绍

输入一个字符串,检验这个字符串是否是一个有效的npm包名 此包导出一个同步的方法,这个方法接受一个字符串并返回一个至少拥有两个属性的对象:

  • validForNewPackages :: Boolean
  • validForOldPackages :: Boolean

2. 源码

源码很短,比较容易懂。

// 核心模块名称:builtins.json
[
  "assert",
  "buffer",
  "child_process",
  "cluster",
  "console",
  "constants",
  "crypto",
  "dgram",
  "dns",
  "domain",
  "events",
  "fs",
  "http",
  "https",
  "module",
  "net",
  "os",
  "path",
  "process",
  "punycode",
  "querystring",
  "readline",
  "repl",
  "stream",
  "string_decoder",
  "timers",
  "tls",
  "tty",
  "url",
  "util",
  "v8",
  "vm",
  "zlib"
]

'use strict'
// 作用域包名正则检测,如@user/package
var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$')
// 核心模块名称
var builtins = require('builtins')
// 黑名单列表
var blacklist = [
  'node_modules',
  'favicon.ico'
]

核心源码比较简单,只记录部分

if (/[~'!()*]/.test(name.split('/').slice(-1)[0])) {
    warnings.push('name can no longer contain special characters ("~\'!()*")')
}

此处用到了slice(-1)。 slice() 方法是从已有的数组中返回选定的元素,不会改变原始数组,只是浅拷贝了原数组中的部分元素。 -1,则表示数组的倒数一项,-2,倒数两项,以此类推。

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]
      if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) {
        return done(warnings, errors)
      }
    }

    errors.push('name can only contain URL-friendly characters')
  }

此处主要就是encodeURIComponent,详情可见 developer.mozilla.org/zh-CN/docs/…