validate-npm-package-name 检测 npm 包是否符合标准

393 阅读2分钟

validate-npm-package-name 这个包主要介绍了合格的包名应该符合哪些规则,才可以通过正确的包名去创建项目,如我们常用的vue-cli创建项目等等都是使用了这些校验规则。

通过源码地址、拉取源码

  • npm install

  • npm run test

01.png

将源码包跑起来,可以看到在test目录index入口文件下的测试用例均能够passed

源码分析

根目录下的index入口文件,导出一个validate函数(10 ~ 91 行)

/**

  • name 传入的包名

*/

var validate = module.exports = function (name) {

    //todos...
}

var validate = module.exports = function (name) {

    //默认输出的错误信息

    var warnings = []

    var errors = []

    //不能为null

    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)

    }

    //必须存在长度

    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

    (不能是node的内置模块,如http,events, util等等)

    builtins.forEach(function (builtin) {

        //builtins是一个node的内置模块包

        if (name.toLowerCase() === builtin) {

            warnings.push(builtin + ' is a core module name')

        }

    })

    //包名不能太长

    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 ("~\'!()*")')

    }

    //不能包含中文

    if (encodeURIComponent(name) !== name) {

        // Maybe it's a scoped package name, like @user/package

        //类似包名 @package/user

        var nameMatch = name.match(scopedPackagePattern)

        if (nameMatch) {

            var user = nameMatch[1]//package

            var pkg = nameMatch[2]//user

            //对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)

 }

//校验后均会执行的方法

/**

  • @param {*} warnings 警告的数组

  • @param {*} errors 错误的数组

  • @returns

*/

var done = function (warnings, errors) {

    var result = {

        //如果没有警告和错误 为true

        validForNewPackages: errors.length === 0 && warnings.length === 0,

        //只需要没有错误就行

        validForOldPackages: errors.length === 0,

        warnings: warnings,

        errors: errors

    }

    //删除对应的对象

    if (!result.warnings.length) delete result.warnings

    if (!result.errors.length) delete result.errors

    //返回整个校验后的对象

    return result

}

源码阅读收获

通过这期的源码阅读,细致了解到了npm包命名的规范以及源码实现思路,进一步理解了包名的校验规则。