Socket
Socket
Sign inDemoInstall

normalize-package-data

Package Overview
Dependencies
Maintainers
1
Versions
60
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

normalize-package-data - npm Package Compare versions

Comparing version 0.1.7 to 0.2.0

test/strict.js

145

lib/fixer.js

@@ -6,4 +6,8 @@ var semver = require("semver")

var url = require("url")
var typos = require("./typos")
var fixer = module.exports = {
// default warning function
warn: function() {},
fixRepositoryField: function(data) {

@@ -15,3 +19,3 @@ if (data.repositories) {

}
if (!data.repository) return;
if (!data.repository) return this.warn('No repository field.')
if (typeof data.repository === "string") {

@@ -36,2 +40,26 @@ data.repository = {

, fixTypos: function(data) {
Object.keys(typos.topLevel).forEach(function (d) {
if (data.hasOwnProperty(d)) {
this.warn(makeTypoWarning(d, typos.topLevel[d]))
}
}, this)
}
, fixScriptsField: function(data) {
if (!data.scripts) return
if (typeof data.scripts !== "object") {
this.warn("scripts must be an object")
delete data.scripts
}
Object.keys(data.scripts).forEach(function (k) {
if (typeof data.scripts[k] !== "string") {
this.warn("script values must be string commands")
delete data.scripts[k]
} else if (typos.script[k]) {
this.warn(makeTypoWarning(k, typos.script[k], "scripts"))
}
}, this)
}
, fixFilesField: function(data) {

@@ -42,2 +70,11 @@ var files = data.files

delete data.files
} else if (data.files) {
data.files = data.files.filter(function(file) {
if (!file || typeof file !== "string") {
this.warn("Invalid filename in 'files' list: " + file)
return false
} else {
return true
}
}, this)
}

@@ -68,17 +105,71 @@ }

}
if (data[bd] && !Array.isArray(data[bd])) {
this.warn("Invalid 'bundleDependencies' list. " +
"Must be array of package names")
delete data[bd]
} else if (data[bd]) {
data[bd] = data[bd].filter(function(bd) {
if (!bd || typeof bd !== 'string') {
this.warn("Invalid bundleDependencies member: " + bd)
return false
} else {
return true
}
}, this)
}
}
, fixDependencies: function(data) {
, fixDependencies: function(data, strict) {
var loose = !strict
objectifyDeps(data, this.warn)
addOptionalDepsToDeps(data, this.warn)
this.fixBundleDependenciesField(data)
;['dependencies','devDependencies'].forEach(function(deps) {
if (!(deps in data)) return
if (!data[deps] || typeof data[deps] !== "object") {
this.warn(deps + " field must be an object")
delete data[deps]
return
}
Object.keys(data[deps]).forEach(function (d) {
var r = data[deps][d]
if (typeof r !== 'string') {
this.warn('Invalid dependency: ' + d + ' ' + JSON.stringify(r))
delete data[deps][d]
}
}, this)
}, this)
}
, fixKeywordsField: function (data, warn) {
, fixModulesField: function (data) {
if (data.modules) {
this.warn("modules field is deprecated")
delete data.modules
}
}
, fixKeywordsField: function (data) {
if (typeof data.keywords === "string") {
data.keywords = data.keywords.split(/,\s+/)
}
if (data.keywords && !Array.isArray(data.keywords)) {
delete data.keywords
this.warn("keywords should be an array of strings")
} else if (data.keywords) {
data.keywords = data.keywords.filter(function(kw) {
if (typeof kw !== "string" || !kw) {
this.warn("keywords should be an array of strings");
return false
} else {
return true
}
}, this)
}
}
, fixVersionField: function(data) {
, fixVersionField: function(data, strict) {
// allow "loose" semver 1.0 versions in non-strict mode
// enforce strict semver 2.0 compliance in strict mode
var loose = !strict
if (!data.version) {

@@ -88,6 +179,6 @@ data.version = ""

}
if (!semver.valid(data.version)) {
throw new Error("invalid version: "+ data.version)
if (!semver.valid(data.version, loose)) {
throw new Error('Invalid version: "'+ data.version + '"')
}
data.version = semver.clean(data.version)
data.version = semver.clean(data.version, loose)
return true

@@ -101,6 +192,6 @@ }

, fixNameField: function(data) {
if (!data.name) {
, fixNameField: function(data, strict) {
if (!data.name && !strict) {
data.name = ""
return true
return
}

@@ -110,4 +201,5 @@ if (typeof data.name !== "string") {

}
data.name = data.name.trim()
ensureValidName(data.name)
if (!strict)
data.name = data.name.trim()
ensureValidName(data.name, strict)
}

@@ -123,6 +215,10 @@

data.description = extractDescription(data.readme)
if (!data.description) this.warn('No description')
}
, fixReadmeField: function (data) {
if (!data.readme) data.readme = "ERROR: No README data found!"
if (!data.readme) {
this.warn("No README data")
data.readme = "ERROR: No README data found!"
}
}

@@ -151,2 +247,3 @@

else {
bugsTypos(data.bugs, this.warn)
var oldBugs = data.bugs

@@ -187,6 +284,7 @@ data.bugs = {}

function ensureValidName (name) {
function ensureValidName (name, strict) {
if (name.charAt(0) === "." ||
name.match(/[\/@\s\+%:]/) ||
name !== encodeURIComponent(name) ||
(strict && name !== name.toLowerCase()) ||
name.toLowerCase() === "node_modules" ||

@@ -265,1 +363,20 @@ name.toLowerCase() === "favicon.ico") {

}
function bugsTypos(bugs, warn) {
if (!bugs) return
Object.keys(bugs).forEach(function (k) {
if (typos.bugs[k]) {
warn(makeTypoWarning(k, typos.bugs[k], "bugs"))
bugs[typos.bugs[k]] = bugs[k]
delete bugs[k]
}
})
}
function makeTypoWarning (providedName, probableName, field) {
if (field) {
providedName = field + "['" + providedName + "']"
probableName = field + "['" + probableName + "']"
}
return providedName + " should probably be " + probableName + "."
}

14

lib/normalize.js
module.exports = normalize
var isValid = require("./is_valid")
var fixer = require("./fixer")
var fieldsToFix = ['name','version','description','repository'
var fieldsToFix = ['name','version','description','repository','modules','scripts'
,'files','bin','man','bugs','keywords','readme','homepage']
var otherThingsToFix = ['dependencies','people']
var otherThingsToFix = ['dependencies','people', 'typos']

@@ -18,5 +17,7 @@ var thingsToFix = fieldsToFix.map(function(fieldName) {

function normalize (data, warn) {
function normalize (data, warn, strict) {
if(warn === true) warn = null, strict = true
if(!strict) strict = false
if(!warn) warn = function(msg) { /* noop */ }
isValid(data, warn) // don't care if it's valid, we'll make it valid
if (data.scripts &&

@@ -29,6 +30,5 @@ data.scripts.install === "node-gyp rebuild" &&

thingsToFix.forEach(function(thingName) {
fixer["fix" + ucFirst(thingName)](data)
fixer["fix" + ucFirst(thingName)](data, strict)
})
data._id = data.name + "@" + data.version
if (data.modules) delete data.modules // modules field is deprecated
}

@@ -35,0 +35,0 @@

@@ -20,5 +20,6 @@ {

,"publicationConfig": "publishConfig"
,"script": "scripts"
},
"bugs": { "web": "url", "name": "url" },
"script": { "server": "start", "tests": "test" }
}
}
{
"name": "normalize-package-data",
"version": "0.1.7",
"version": "0.2.0",
"author": "Meryn Stol <merynstol@gmail.com>",

@@ -15,3 +15,3 @@ "description": "Normalizes data that can be found in package.json files.",

"dependencies": {
"semver": "1.x",
"semver": "2",
"github-url-from-git": "~1.1.1"

@@ -18,0 +18,0 @@ },

@@ -50,3 +50,7 @@ var tap = require("tap")

t.same(packageData, expect)
t.same(warnings, ["No repository field.","No readme data."])
t.same(warnings, [
"No description",
"No repository field.",
"No README data"
])
t.end()

@@ -77,10 +81,11 @@ })

var expect =
[ 'No repository field.',
'No readme data.',
'bugs.url field must be a string url. Deleted.',
'bugs.email field must be a string email. Deleted.',
'Normalized value of bugs field is an empty object. Deleted.',
'Bug string field must be url, email, or {email,url}',
'Normalized value of bugs field is an empty object. Deleted.',
'homepage field must be a string url. Deleted.' ]
[ "No description",
"No repository field.",
"bugs.url field must be a string url. Deleted.",
"bugs.email field must be a string email. Deleted.",
"Normalized value of bugs field is an empty object. Deleted.",
"No README data",
"Bug string field must be url, email, or {email,url}",
"Normalized value of bugs field is an empty object. Deleted.",
"homepage field must be a string url. Deleted." ]
t.same(warnings, expect)

@@ -103,5 +108,6 @@ t.end()

var expect =
[ 'No repository field.',
'No readme data.',
'homepage field must start with a protocol.' ]
[ "No description",
"No repository field.",
"No README data",
"homepage field must start with a protocol." ]
t.same(warnings, expect)

@@ -122,2 +128,9 @@ t.same(a.homepage, 'http://example.org')

tap.test("singularize repositories", function(t) {
var d = {repositories:["git@gist.github.com:123456.git"]}
normalize(d)
t.same(d.repository, { type: 'git', url: 'git@gist.github.com:123456.git' })
t.end()
});
tap.test('no new globals', function(t) {

@@ -127,8 +140,1 @@ t.same(Object.keys(global), globals)

})
tap.test("singularize repositories", function(t) {
d = {repositories:["git@gist.github.com:123456.git"]}
normalize(d)
t.same(d.repository, { type: 'git', url: 'git@gist.github.com:123456.git' })
t.end()
});

@@ -12,3 +12,4 @@ var test = require('tap').test

var expect =
[ 'dependancies should probably be dependencies.',
[ 'No repository field.',
'dependancies should probably be dependencies.',
'dependecies should probably be dependencies.',

@@ -29,10 +30,3 @@ 'depdenencies should probably be dependencies.',

'contributers should probably be contributors.',
'publicationConfig should probably be publishConfig.',
'No repository field.',
'No repository field.',
'No readme data.',
'bugs.url field must be a string url. Deleted.',
'Normalized value of bugs field is an empty object. Deleted.',
'No repository field.',
'No readme data.' ]
'publicationConfig should probably be publishConfig.' ]

@@ -60,2 +54,14 @@ normalize({"dependancies": "dependencies"

t.same(warnings, expect)
warnings.length = 0
var expect =
[ 'No description',
'No repository field.',
'bugs[\'web\'] should probably be bugs[\'url\'].',
'bugs[\'name\'] should probably be bugs[\'url\'].',
'bugs.url field must be a string url. Deleted.',
'Normalized value of bugs field is an empty object. Deleted.',
"No README data" ]
normalize({name:"name"

@@ -65,7 +71,32 @@ ,version:"1.2.5"

t.same(warnings, expect)
warnings.length = 0
var expect =
[ 'No description',
'No repository field.',
"No README data",
'script should probably be scripts.' ]
normalize({name:"name"
,version:"1.2.5"
,script:{server:"start",tests:"test"}}, warn)
t.same(warnings, expect)
warnings.length = 0
expect =
[ 'No description',
'No repository field.',
'scripts[\'server\'] should probably be scripts[\'start\'].',
'scripts[\'tests\'] should probably be scripts[\'test\'].',
"No README data" ]
normalize({name:"name"
,version:"1.2.5"
,scripts:{server:"start",tests:"test"}}, warn)
t.same(warnings, expect)
t.end();
})
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc