validate-npm-package-name
Advanced tools
Comparing version 1.2.0 to 2.0.0
62
index.js
var scopedPackagePattern = new RegExp("^(?:@([^/]+?)[/])?([^/]+?)$"); | ||
var builtins = require("builtins") | ||
var blacklist = [ | ||
@@ -7,15 +8,10 @@ "node_modules", | ||
var validate = module.exports = function(name, options) { | ||
var validate = module.exports = function(name) { | ||
var warnings = [] | ||
var errors = [] | ||
if (!options) { | ||
options = { | ||
allowMixedCase: false | ||
} | ||
} | ||
if (name === null) { | ||
errors.push("name cannot be null") | ||
return done(errors) | ||
return done(warnings, errors) | ||
} | ||
@@ -25,3 +21,3 @@ | ||
errors.push("name cannot be undefined") | ||
return done(errors) | ||
return done(warnings, errors) | ||
} | ||
@@ -31,3 +27,3 @@ | ||
errors.push("name must be a string") | ||
return done(errors) | ||
return done(warnings, errors) | ||
} | ||
@@ -47,6 +43,2 @@ | ||
if (name.length > 50) { | ||
errors.push("name cannot be longer than 50 characters") | ||
} | ||
if (name.trim() !== name) { | ||
@@ -56,6 +48,3 @@ errors.push("name cannot contain leading or trailing spaces") | ||
if (name.toLowerCase() !== name && !options.allowMixedCase) { | ||
errors.push("name must be lowercase") | ||
} | ||
// No funny business | ||
blacklist.forEach(function(blacklistedName){ | ||
@@ -67,2 +56,21 @@ if (name.toLowerCase() === blacklistedName) { | ||
// 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 | ||
if (name.length > 50) { | ||
warnings.push("name can no longer contain more than 50 characters") | ||
} | ||
// mIxeD CaSe nAMEs | ||
if (name.toLowerCase() !== name) { | ||
warnings.push("name can no longer contain capital letters") | ||
} | ||
if (encodeURIComponent(name) !== name) { | ||
@@ -76,3 +84,3 @@ | ||
if (encodeURIComponent(user) === user && encodeURIComponent(pkg) === pkg) { | ||
return done(errors) | ||
return done(warnings, errors) | ||
} | ||
@@ -84,3 +92,3 @@ } | ||
return done(errors) | ||
return done(warnings, errors) | ||
@@ -91,8 +99,12 @@ } | ||
var done = function (errors) { | ||
if (errors.length) { | ||
return {valid: false, errors: errors} | ||
} else { | ||
return {valid: true} | ||
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 | ||
} |
{ | ||
"name": "validate-npm-package-name", | ||
"version": "1.2.0", | ||
"version": "2.0.0", | ||
"description": "Give me a string and I'll tell you if it's a valid npm package name", | ||
@@ -9,3 +9,5 @@ "main": "index.js", | ||
}, | ||
"dependencies": {}, | ||
"dependencies": { | ||
"builtins": "0.0.7" | ||
}, | ||
"devDependencies": { | ||
@@ -12,0 +14,0 @@ "tap": "^0.4.13" |
@@ -1,39 +0,77 @@ | ||
# validate-npm-package-name | ||
# validate-npm-package-name | ||
Give me a string and I'll tell you if it's a valid npm package name | ||
Give me a string and I'll tell you if it's a valid npm package name. | ||
## Installation | ||
This package exports a single synchronous function that takes a string as | ||
input and returns an object: | ||
Download node at [nodejs.org](http://nodejs.org) and install it, if you haven't already. | ||
### Valid Names | ||
```sh | ||
npm install validate-npm-package-name --save | ||
```js | ||
var validate = require("validate-npm-package-name") | ||
validate("some-package") | ||
validate("example.com") | ||
validate("under_score") | ||
validate("123numeric") | ||
validate("crazy!") | ||
validate("@npm/thingy") | ||
validate("@jane/foo.js") | ||
``` | ||
## Usage | ||
All of the above names are valid, so you'll get this object back: | ||
```js | ||
var valid = require("validate-npm-package-name") | ||
{ | ||
validForNewPackages: true, | ||
validForOldPackages: true | ||
} | ||
``` | ||
validate("some-package") // => {valid: true} | ||
validate("example.com") // => {valid: true} | ||
validate("under_score") // => {valid: true} | ||
validate("123numeric") // => {valid: true} | ||
validate("crazy!") // => {valid: true} | ||
validate("@npm/thingy") // => {valid: true} | ||
validate("@jane/foo.js") // => {valid: true} | ||
### Invalid Names | ||
validate("") // => {valid: false, errors:["name length must be greater than zero"]} | ||
validate("ca$h") // => {valid: false, errors:["name can only contain URL-friendly characters"]} | ||
validate("_flodash") // => {valid: false, errors:["name cannot start with an underscore"]} | ||
validate("CAPITALS") // => {valid: false, errors:["name must be lowercase"]} | ||
```js | ||
validate(" leading-space:and:weirdchars") | ||
``` | ||
// Nowadays, package names have to be lowercase | ||
// To validate older packages, do this: | ||
That was never a valid package name, so you get this: | ||
validate("CAPITALS", | ||
{allowMixedCase: true}) // => {valid: true} | ||
```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("cRaZY-paCkAgE-with-mixed-case-and-more-than-fifty-characters") | ||
``` | ||
returns: | ||
```js | ||
{ | ||
validForNewPackages: false, | ||
validForOldPackages: true, | ||
warnings: [ | ||
"name can no longer contain capital letters", | ||
"name can no longer contain more than 50 characters" | ||
] | ||
} | ||
``` | ||
## Tests | ||
@@ -46,15 +84,4 @@ | ||
## Dependencies | ||
None | ||
## Dev Dependencies | ||
- [tap](https://github.com/isaacs/node-tap): A Test-Anything-Protocol library | ||
## License | ||
ISC | ||
_Generated by [package-json-to-readme](https://github.com/zeke/package-json-to-readme)_ |
@@ -1,2 +0,2 @@ | ||
var valid = require("..") | ||
var validate = require("..") | ||
var test = require("tap").test | ||
@@ -7,67 +7,92 @@ var path = require("path") | ||
test("validate-npm-package-name", function (t) { | ||
t.deepEqual(valid("some-package"), {valid: true}) | ||
t.deepEqual(valid("example.com"), {valid: true}) | ||
t.deepEqual(valid("under_score"), {valid: true}) | ||
t.deepEqual(valid("period.js"), {valid: true}) | ||
t.deepEqual(valid("123numeric"), {valid: true}) | ||
t.deepEqual(valid("crazy!"), {valid: true}) | ||
t.deepEqual(valid("@npm/thingy"), {valid: true}) | ||
t.deepEqual(valid("@npm-zors/money!time.js"), {valid: true}) | ||
t.deepEqual(valid(""), { | ||
valid: false, | ||
// 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: true, validForOldPackages: true}) | ||
// Scoped (npm 2+) | ||
t.deepEqual(validate("@npm/thingy"), {validForNewPackages: true, validForOldPackages: true}) | ||
t.deepEqual(validate("@npm-zors/money!time.js"), {validForNewPackages: true, validForOldPackages: true}) | ||
// Invalid | ||
t.deepEqual(validate(""), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["name length must be greater than zero"]}) | ||
t.deepEqual(valid(""), { | ||
valid: false, | ||
t.deepEqual(validate(""), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["name length must be greater than zero"]}) | ||
t.deepEqual(valid(".start-with-period"), { | ||
valid: false, | ||
t.deepEqual(validate(".start-with-period"), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["name cannot start with a period"]}) | ||
t.deepEqual(valid("_start-with-underscore"), { | ||
valid: false, | ||
t.deepEqual(validate("_start-with-underscore"), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["name cannot start with an underscore"]}) | ||
t.deepEqual(valid("contain:colons"), { | ||
valid: false, | ||
t.deepEqual(validate("contain:colons"), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["name can only contain URL-friendly characters"]}) | ||
t.deepEqual(valid("1234567890123456789012345678901234567890-more-than-fifty"), { | ||
valid: false, | ||
errors: ["name cannot be longer than 50 characters"]}) | ||
t.deepEqual(valid(" leading-space"), { | ||
valid: false, | ||
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(valid("trailing-space "), { | ||
valid: false, | ||
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(valid("s/l/a/s/h/e/s"), { | ||
valid: false, | ||
t.deepEqual(validate("s/l/a/s/h/e/s"), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["name can only contain URL-friendly characters"]}) | ||
t.deepEqual(valid("node_modules"), { | ||
valid: false, | ||
t.deepEqual(validate("node_modules"), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["node_modules is a blacklisted name"]}) | ||
t.deepEqual(valid("favicon.ico"), { | ||
valid: false, | ||
t.deepEqual(validate("favicon.ico"), { | ||
validForNewPackages: false, | ||
validForOldPackages: false, | ||
errors: ["favicon.ico is a blacklisted name"]}) | ||
// Legacy Mixed-Case | ||
// Node/IO Core | ||
t.deepEqual(valid("CAPITAL-LETTERS", {allowMixedCase: true}), {valid: true}) | ||
t.deepEqual(validate("http"), { | ||
validForNewPackages: false, | ||
validForOldPackages: true, | ||
warnings: ["http is a core module name"]}) | ||
t.deepEqual(valid("CAPITAL-LETTERS"), { | ||
valid: false, | ||
errors: ["name must be lowercase"]}) | ||
// Long Package Names | ||
t.deepEqual(validate("1234567890123456789012345678901234567890-more-than-fifty"), { | ||
validForNewPackages: false, | ||
validForOldPackages: true, | ||
warnings: ["name can no longer contain more than 50 characters"] | ||
}) | ||
// Legacy Mixed-Case | ||
t.deepEqual(validate("CAPITAL-LETTERS"), { | ||
validForNewPackages: false, | ||
validForOldPackages: true, | ||
warnings: ["name can no longer contain capital letters"]}) | ||
t.end() | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
8313
154
87
1
5
+ Addedbuiltins@0.0.7
+ Addedbuiltins@0.0.7(transitive)