pax_global_header00006660000000000000000000000064130504333450014512gustar00rootroot0000000000000052 comment=ddf73c79e920b59413485ca2ae50a38552156d62 validate-npm-package-name-3.0.0/000077500000000000000000000000001305043334500164025ustar00rootroot00000000000000validate-npm-package-name-3.0.0/.gitignore000066400000000000000000000000151305043334500203660ustar00rootroot00000000000000node_modules validate-npm-package-name-3.0.0/.travis.yml000066400000000000000000000001021305043334500205040ustar00rootroot00000000000000sudo: false language: node_js node_js: - '0.10' - '4' - '6' validate-npm-package-name-3.0.0/LICENSE000066400000000000000000000013301305043334500174040ustar00rootroot00000000000000Copyright (c) 2015, npm, Inc Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. validate-npm-package-name-3.0.0/README.md000066400000000000000000000056121305043334500176650ustar00rootroot00000000000000# validate-npm-package-name Give me a string and I'll tell you if it's a valid `npm` package name. This package exports a single synchronous function that takes a `string` as input and returns an object with two properties: - `validForNewPackages` :: `Boolean` - `validForOldPackages` :: `Boolean` ## Contents - [Naming rules](#naming-rules) - [Examples](#examples) + [Valid Names](#valid-names) + [Invalid Names](#invalid-names) - [Legacy Names](#legacy-names) - [Tests](#tests) - [License](#license) ## Naming Rules Below is a list of rules that valid `npm` package name should conform to. - package name length should be greater than zero - all the characters in the package name must be lowercase i.e., no uppercase or mixed case names are allowed - package name *can* consist of hyphens - package name must *not* contain any non-url-safe characters (since name ends up being part of a URL) - package name should not start with `.` or `_` - package name should *not* contain any leading or trailing spaces - package name should *not* contain any of the following characters: `~)('!*` - package name *cannot* be the same as a node.js/io.js core module nor a reserved/blacklisted name. For example, the following names are invalid: + http + stream + node_modules + favicon.ico - package name length cannot exceed 214 ## Examples ### Valid Names ```js var validate = require("validate-npm-package-name") validate("some-package") validate("example.com") validate("under_score") validate("123numeric") validate("excited!") validate("@npm/thingy") validate("@jane/foo.js") ``` All of the above names are valid, so you'll get this object back: ```js { validForNewPackages: true, validForOldPackages: true } ``` ### Invalid Names ```js validate(" leading-space:and:weirdchars") ``` That was never a valid package name, so you get this: ```js { validForNewPackages: false, validForOldPackages: false, errors: [ 'name cannot contain leading or trailing spaces', 'name can only contain URL-friendly characters' ] } ``` ## Legacy Names In the old days of npm, package names were wild. They could have capital letters in them. They could be really long. They could be the name of an existing module in node core. If you give this function a package name that **used to be valid**, you'll see a change in the value of `validForNewPackages` property, and a warnings array will be present: ```js validate("eLaBorAtE-paCkAgE-with-mixed-case-and-more-than-214-characters-----------------------------------------------------------------------------------------------------------------------------------------------------------") ``` returns: ```js { validForNewPackages: false, validForOldPackages: true, warnings: [ "name can no longer contain capital letters", "name can no longer contain more than 214 characters" ] } ``` ## Tests ```sh npm install npm test ``` ## License ISC validate-npm-package-name-3.0.0/index.js000066400000000000000000000054311305043334500200520ustar00rootroot00000000000000'use strict' var scopedPackagePattern = new RegExp('^(?:@([^/]+?)[/])?([^/]+?)$') 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) } 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 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') } 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 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') } return done(warnings, errors) } validate.scopedPackagePattern = scopedPackagePattern var done = function (warnings, errors) { var result = { 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 } validate-npm-package-name-3.0.0/package.json000066400000000000000000000016371305043334500206770ustar00rootroot00000000000000{ "name": "validate-npm-package-name", "version": "3.0.0", "description": "Give me a string and I'll tell you if it's a valid npm package name", "main": "index.js", "directories": { "test": "test" }, "dependencies": { "builtins": "^1.0.3" }, "devDependencies": { "standard": "^8.6.0", "tap": "^10.0.0" }, "scripts": { "cov:test": "TAP_FLAGS='--cov' npm run test:code", "test:code": "tap ${TAP_FLAGS:-'--'} test/*.js", "test:style": "standard", "test": "npm run test:code && npm run test:style" }, "repository": { "type": "git", "url": "https://github.com/npm/validate-npm-package-name" }, "keywords": [ "npm", "package", "names", "validation" ], "author": "zeke", "license": "ISC", "bugs": { "url": "https://github.com/npm/validate-npm-package-name/issues" }, "homepage": "https://github.com/npm/validate-npm-package-name" } validate-npm-package-name-3.0.0/test/000077500000000000000000000000001305043334500173615ustar00rootroot00000000000000validate-npm-package-name-3.0.0/test/index.js000066400000000000000000000075751305043334500210440ustar00rootroot00000000000000'use strict' var validate = require('..') var test = require('tap').test test('validate-npm-package-name', function (t) { // Traditional t.deepEqual(validate('some-package'), {validForNewPackages: true, validForOldPackages: true}) t.deepEqual(validate('example.com'), {validForNewPackages: true, validForOldPackages: true}) t.deepEqual(validate('under_score'), {validForNewPackages: true, validForOldPackages: true}) t.deepEqual(validate('period.js'), {validForNewPackages: true, validForOldPackages: true}) t.deepEqual(validate('123numeric'), {validForNewPackages: true, validForOldPackages: true}) t.deepEqual(validate('crazy!'), { validForNewPackages: false, validForOldPackages: true, warnings: ['name can no longer contain special characters ("~\'!()*")'] }) // Scoped (npm 2+) t.deepEqual(validate('@npm/thingy'), {validForNewPackages: true, validForOldPackages: true}) t.deepEqual(validate('@npm-zors/money!time.js'), { validForNewPackages: false, validForOldPackages: true, warnings: ['name can no longer contain special characters ("~\'!()*")'] }) // Invalid t.deepEqual(validate(''), { validForNewPackages: false, validForOldPackages: false, errors: ['name length must be greater than zero']}) t.deepEqual(validate(''), { validForNewPackages: false, validForOldPackages: false, errors: ['name length must be greater than zero']}) t.deepEqual(validate('.start-with-period'), { validForNewPackages: false, validForOldPackages: false, errors: ['name cannot start with a period']}) t.deepEqual(validate('_start-with-underscore'), { validForNewPackages: false, validForOldPackages: false, errors: ['name cannot start with an underscore']}) t.deepEqual(validate('contain:colons'), { validForNewPackages: false, validForOldPackages: false, errors: ['name can only contain URL-friendly characters']}) t.deepEqual(validate(' leading-space'), { validForNewPackages: false, validForOldPackages: false, errors: ['name cannot contain leading or trailing spaces', 'name can only contain URL-friendly characters']}) t.deepEqual(validate('trailing-space '), { validForNewPackages: false, validForOldPackages: false, errors: ['name cannot contain leading or trailing spaces', 'name can only contain URL-friendly characters']}) t.deepEqual(validate('s/l/a/s/h/e/s'), { validForNewPackages: false, validForOldPackages: false, errors: ['name can only contain URL-friendly characters']}) t.deepEqual(validate('node_modules'), { validForNewPackages: false, validForOldPackages: false, errors: ['node_modules is a blacklisted name']}) t.deepEqual(validate('favicon.ico'), { validForNewPackages: false, validForOldPackages: false, errors: ['favicon.ico is a blacklisted name']}) // Node/IO Core t.deepEqual(validate('http'), { validForNewPackages: false, validForOldPackages: true, warnings: ['http is a core module name']}) // Long Package Names t.deepEqual(validate('ifyouwanttogetthesumoftwonumberswherethosetwonumbersarechosenbyfindingthelargestoftwooutofthreenumbersandsquaringthemwhichismultiplyingthembyitselfthenyoushouldinputthreenumbersintothisfunctionanditwilldothatforyou-'), { validForNewPackages: false, validForOldPackages: true, warnings: ['name can no longer contain more than 214 characters'] }) t.deepEqual(validate('ifyouwanttogetthesumoftwonumberswherethosetwonumbersarechosenbyfindingthelargestoftwooutofthreenumbersandsquaringthemwhichismultiplyingthembyitselfthenyoushouldinputthreenumbersintothisfunctionanditwilldothatforyou'), { validForNewPackages: true, validForOldPackages: true }) // Legacy Mixed-Case t.deepEqual(validate('CAPITAL-LETTERS'), { validForNewPackages: false, validForOldPackages: true, warnings: ['name can no longer contain capital letters']}) t.end() })