Socket
Socket
Sign inDemoInstall

normalize-package-data

Package Overview
Dependencies
12
Maintainers
7
Versions
60
Alerts
File Explorer

Advanced tools

Install Socket

Detect and block malicious and high-risk dependencies

Install

Comparing version 3.0.2 to 3.0.3

16

lib/extract_description.js

@@ -5,11 +5,19 @@ module.exports = extractDescription

function extractDescription (d) {
if (!d) return;
if (d === "ERROR: No README data found!") return;
if (!d) {
return
}
if (d === 'ERROR: No README data found!') {
return
}
// the first block of text before the first heading
// that isn't the first line heading
d = d.trim().split('\n')
for (var s = 0; d[s] && d[s].trim().match(/^(#|$)/); s ++);
for (var s = 0; d[s] && d[s].trim().match(/^(#|$)/); s++) {
;
}
var l = d.length
for (var e = s + 1; e < l && d[e].trim(); e ++);
for (var e = s + 1; e < l && d[e].trim(); e++) {
;
}
return d.slice(s, e).join(' ').trim()
}

@@ -1,27 +0,30 @@

var semver = require("semver")
var validateLicense = require('validate-npm-package-license');
var hostedGitInfo = require("hosted-git-info")
var isBuiltinModule = require("resolve").isCore
var depTypes = ["dependencies","devDependencies","optionalDependencies"]
var extractDescription = require("./extract_description")
var url = require("url")
var typos = require("./typos.json")
var isValidSemver = require('semver/functions/valid')
var cleanSemver = require('semver/functions/clean')
var validateLicense = require('validate-npm-package-license')
var hostedGitInfo = require('hosted-git-info')
var isBuiltinModule = require('is-core-module')
var depTypes = ['dependencies', 'devDependencies', 'optionalDependencies']
var extractDescription = require('./extract_description')
var url = require('url')
var typos = require('./typos.json')
var fixer = module.exports = {
module.exports = {
// default warning function
warn: function() {},
warn: function () {},
fixRepositoryField: function(data) {
fixRepositoryField: function (data) {
if (data.repositories) {
this.warn("repositories");
this.warn('repositories')
data.repository = data.repositories[0]
}
if (!data.repository) return this.warn("missingRepository")
if (typeof data.repository === "string") {
if (!data.repository) {
return this.warn('missingRepository')
}
if (typeof data.repository === 'string') {
data.repository = {
type: "git",
url: data.repository
type: 'git',
url: data.repository,
}
}
var r = data.repository.url || ""
var r = data.repository.url || ''
if (r) {

@@ -31,23 +34,25 @@ var hosted = hostedGitInfo.fromUrl(r)

r = data.repository.url
= hosted.getDefaultRepresentation() == "shortcut" ? hosted.https() : hosted.toString()
= hosted.getDefaultRepresentation() === 'shortcut' ? hosted.https() : hosted.toString()
}
}
if (r.match(/github.com\/[^\/]+\/[^\/]+\.git\.git$/)) {
this.warn("brokenGitUrl", r)
if (r.match(/github.com\/[^/]+\/[^/]+\.git\.git$/)) {
this.warn('brokenGitUrl', r)
}
}
},
, fixTypos: function(data) {
fixTypos: function (data) {
Object.keys(typos.topLevel).forEach(function (d) {
if (data.hasOwnProperty(d)) {
this.warn("typo", d, typos.topLevel[d])
if (Object.prototype.hasOwnProperty.call(data, d)) {
this.warn('typo', d, typos.topLevel[d])
}
}, this)
}
},
, fixScriptsField: function(data) {
if (!data.scripts) return
if (typeof data.scripts !== "object") {
this.warn("nonObjectScripts")
fixScriptsField: function (data) {
if (!data.scripts) {
return
}
if (typeof data.scripts !== 'object') {
this.warn('nonObjectScripts')
delete data.scripts

@@ -57,20 +62,20 @@ return

Object.keys(data.scripts).forEach(function (k) {
if (typeof data.scripts[k] !== "string") {
this.warn("nonStringScript")
if (typeof data.scripts[k] !== 'string') {
this.warn('nonStringScript')
delete data.scripts[k]
} else if (typos.script[k] && !data.scripts[typos.script[k]]) {
this.warn("typo", k, typos.script[k], "scripts")
this.warn('typo', k, typos.script[k], 'scripts')
}
}, this)
}
},
, fixFilesField: function(data) {
fixFilesField: function (data) {
var files = data.files
if (files && !Array.isArray(files)) {
this.warn("nonArrayFiles")
this.warn('nonArrayFiles')
delete data.files
} else if (data.files) {
data.files = data.files.filter(function(file) {
if (!file || typeof file !== "string") {
this.warn("invalidFilename", file)
data.files = data.files.filter(function (file) {
if (!file || typeof file !== 'string') {
this.warn('invalidFilename', file)
return false

@@ -82,7 +87,9 @@ } else {

}
}
},
, fixBinField: function(data) {
if (!data.bin) return;
if (typeof data.bin === "string") {
fixBinField: function (data) {
if (!data.bin) {
return
}
if (typeof data.bin === 'string') {
var b = {}

@@ -97,13 +104,15 @@ var match

}
}
},
, fixManField: function(data) {
if (!data.man) return;
if (typeof data.man === "string") {
data.man = [ data.man ]
fixManField: function (data) {
if (!data.man) {
return
}
}
, fixBundleDependenciesField: function(data) {
var bdd = "bundledDependencies"
var bd = "bundleDependencies"
if (typeof data.man === 'string') {
data.man = [data.man]
}
},
fixBundleDependenciesField: function (data) {
var bdd = 'bundledDependencies'
var bd = 'bundleDependencies'
if (data[bdd] && !data[bd]) {

@@ -114,8 +123,8 @@ data[bd] = data[bdd]

if (data[bd] && !Array.isArray(data[bd])) {
this.warn("nonArrayBundleDependencies")
this.warn('nonArrayBundleDependencies')
delete data[bd]
} else if (data[bd]) {
data[bd] = data[bd].filter(function(bd) {
data[bd] = data[bd].filter(function (bd) {
if (!bd || typeof bd !== 'string') {
this.warn("nonStringBundleDependency", bd)
this.warn('nonStringBundleDependency', bd)
return false

@@ -126,5 +135,5 @@ } else {

}
if (!data.dependencies.hasOwnProperty(bd)) {
this.warn("nonDependencyBundleDependency", bd)
data.dependencies[bd] = "*"
if (Object.prototype.hasOwnProperty.call(data.dependencies, bd)) {
this.warn('nonDependencyBundleDependency', bd)
data.dependencies[bd] = '*'
}

@@ -135,6 +144,5 @@ return true

}
}
},
, fixDependencies: function(data, strict) {
var loose = !strict
fixDependencies: function (data, strict) {
objectifyDeps(data, this.warn)

@@ -144,6 +152,8 @@ addOptionalDepsToDeps(data, this.warn)

;['dependencies','devDependencies'].forEach(function(deps) {
if (!(deps in data)) return
if (!data[deps] || typeof data[deps] !== "object") {
this.warn("nonObjectDependencies", deps)
;['dependencies', 'devDependencies'].forEach(function (deps) {
if (!(deps in data)) {
return
}
if (!data[deps] || typeof data[deps] !== 'object') {
this.warn('nonObjectDependencies', deps)
delete data[deps]

@@ -155,20 +165,22 @@ return

if (typeof r !== 'string') {
this.warn("nonStringDependency", d, JSON.stringify(r))
this.warn('nonStringDependency', d, JSON.stringify(r))
delete data[deps][d]
}
var hosted = hostedGitInfo.fromUrl(data[deps][d])
if (hosted) data[deps][d] = hosted.toString()
if (hosted) {
data[deps][d] = hosted.toString()
}
}, this)
}, this)
}
},
, fixModulesField: function (data) {
fixModulesField: function (data) {
if (data.modules) {
this.warn("deprecatedModules")
this.warn('deprecatedModules')
delete data.modules
}
}
},
, fixKeywordsField: function (data) {
if (typeof data.keywords === "string") {
fixKeywordsField: function (data) {
if (typeof data.keywords === 'string') {
data.keywords = data.keywords.split(/,\s+/)

@@ -178,7 +190,7 @@ }

delete data.keywords
this.warn("nonArrayKeywords")
this.warn('nonArrayKeywords')
} else if (data.keywords) {
data.keywords = data.keywords.filter(function(kw) {
if (typeof kw !== "string" || !kw) {
this.warn("nonStringKeyword");
data.keywords = data.keywords.filter(function (kw) {
if (typeof kw !== 'string' || !kw) {
this.warn('nonStringKeyword')
return false

@@ -190,5 +202,5 @@ } else {

}
}
},
, fixVersionField: function(data, strict) {
fixVersionField: function (data, strict) {
// allow "loose" semver 1.0 versions in non-strict mode

@@ -198,134 +210,155 @@ // enforce strict semver 2.0 compliance in strict mode

if (!data.version) {
data.version = ""
data.version = ''
return true
}
if (!semver.valid(data.version, loose)) {
throw new Error('Invalid version: "'+ data.version + '"')
if (!isValidSemver(data.version, loose)) {
throw new Error('Invalid version: "' + data.version + '"')
}
data.version = semver.clean(data.version, loose)
data.version = cleanSemver(data.version, loose)
return true
}
},
, fixPeople: function(data) {
fixPeople: function (data) {
modifyPeople(data, unParsePerson)
modifyPeople(data, parsePerson)
}
},
, fixNameField: function(data, options) {
if (typeof options === "boolean") options = {strict: options}
else if (typeof options === "undefined") options = {}
fixNameField: function (data, options) {
if (typeof options === 'boolean') {
options = {strict: options}
} else if (typeof options === 'undefined') {
options = {}
}
var strict = options.strict
if (!data.name && !strict) {
data.name = ""
data.name = ''
return
}
if (typeof data.name !== "string") {
throw new Error("name field must be a string.")
if (typeof data.name !== 'string') {
throw new Error('name field must be a string.')
}
if (!strict)
if (!strict) {
data.name = data.name.trim()
}
ensureValidName(data.name, strict, options.allowLegacyCase)
if (isBuiltinModule(data.name))
this.warn("conflictingName", data.name)
}
if (isBuiltinModule(data.name)) {
this.warn('conflictingName', data.name)
}
},
, fixDescriptionField: function (data) {
fixDescriptionField: function (data) {
if (data.description && typeof data.description !== 'string') {
this.warn("nonStringDescription")
this.warn('nonStringDescription')
delete data.description
}
if (data.readme && !data.description)
if (data.readme && !data.description) {
data.description = extractDescription(data.readme)
if(data.description === undefined) delete data.description;
if (!data.description) this.warn("missingDescription")
}
}
if (data.description === undefined) {
delete data.description
}
if (!data.description) {
this.warn('missingDescription')
}
},
, fixReadmeField: function (data) {
fixReadmeField: function (data) {
if (!data.readme) {
this.warn("missingReadme")
data.readme = "ERROR: No README data found!"
this.warn('missingReadme')
data.readme = 'ERROR: No README data found!'
}
}
},
, fixBugsField: function(data) {
fixBugsField: function (data) {
if (!data.bugs && data.repository && data.repository.url) {
var hosted = hostedGitInfo.fromUrl(data.repository.url)
if(hosted && hosted.bugs()) {
if (hosted && hosted.bugs()) {
data.bugs = {url: hosted.bugs()}
}
}
else if(data.bugs) {
} else if (data.bugs) {
var emailRe = /^.+@.*\..+$/
if(typeof data.bugs == "string") {
if(emailRe.test(data.bugs))
data.bugs = {email:data.bugs}
else if(url.parse(data.bugs).protocol)
if (typeof data.bugs === 'string') {
if (emailRe.test(data.bugs)) {
data.bugs = {email: data.bugs}
/* eslint-disable-next-line node/no-deprecated-api */
} else if (url.parse(data.bugs).protocol) {
data.bugs = {url: data.bugs}
else
this.warn("nonEmailUrlBugsString")
}
else {
} else {
this.warn('nonEmailUrlBugsString')
}
} else {
bugsTypos(data.bugs, this.warn)
var oldBugs = data.bugs
data.bugs = {}
if(oldBugs.url) {
if(typeof(oldBugs.url) == "string" && url.parse(oldBugs.url).protocol)
if (oldBugs.url) {
/* eslint-disable-next-line node/no-deprecated-api */
if (typeof (oldBugs.url) === 'string' && url.parse(oldBugs.url).protocol) {
data.bugs.url = oldBugs.url
else
this.warn("nonUrlBugsUrlField")
} else {
this.warn('nonUrlBugsUrlField')
}
}
if(oldBugs.email) {
if(typeof(oldBugs.email) == "string" && emailRe.test(oldBugs.email))
if (oldBugs.email) {
if (typeof (oldBugs.email) === 'string' && emailRe.test(oldBugs.email)) {
data.bugs.email = oldBugs.email
else
this.warn("nonEmailBugsEmailField")
} else {
this.warn('nonEmailBugsEmailField')
}
}
}
if(!data.bugs.email && !data.bugs.url) {
if (!data.bugs.email && !data.bugs.url) {
delete data.bugs
this.warn("emptyNormalizedBugs")
this.warn('emptyNormalizedBugs')
}
}
}
},
, fixHomepageField: function(data) {
fixHomepageField: function (data) {
if (!data.homepage && data.repository && data.repository.url) {
var hosted = hostedGitInfo.fromUrl(data.repository.url)
if (hosted && hosted.docs()) data.homepage = hosted.docs()
if (hosted && hosted.docs()) {
data.homepage = hosted.docs()
}
}
if (!data.homepage) return
if (!data.homepage) {
return
}
if(typeof data.homepage !== "string") {
this.warn("nonUrlHomepage")
if (typeof data.homepage !== 'string') {
this.warn('nonUrlHomepage')
return delete data.homepage
}
if(!url.parse(data.homepage).protocol) {
data.homepage = "http://" + data.homepage
/* eslint-disable-next-line node/no-deprecated-api */
if (!url.parse(data.homepage).protocol) {
data.homepage = 'http://' + data.homepage
}
}
},
, fixLicenseField: function(data) {
if (!data.license) {
return this.warn("missingLicense")
} else{
if (
typeof(data.license) !== 'string' ||
data.license.length < 1 ||
data.license.trim() === ''
) {
this.warn("invalidLicense")
} else {
if (!validateLicense(data.license).validForNewPackages)
this.warn("invalidLicense")
}
fixLicenseField: function (data) {
const license = data.license || data.licence
if (!license) {
return this.warn('missingLicense')
}
}
if (
typeof (license) !== 'string' ||
license.length < 1 ||
license.trim() === ''
) {
return this.warn('invalidLicense')
}
if (!validateLicense(license).validForNewPackages) {
return this.warn('invalidLicense')
}
},
}
function isValidScopedPackageName(spec) {
if (spec.charAt(0) !== '@') return false
function isValidScopedPackageName (spec) {
if (spec.charAt(0) !== '@') {
return false
}
var rest = spec.slice(1).split('/')
if (rest.length !== 2) return false
if (rest.length !== 2) {
return false
}

@@ -337,4 +370,4 @@ return rest[0] && rest[1] &&

function isCorrectlyEncodedName(spec) {
return !spec.match(/[\/@\s\+%:]/) &&
function isCorrectlyEncodedName (spec) {
return !spec.match(/[/@\s+%:]/) &&
spec === encodeURIComponent(spec)

@@ -344,8 +377,8 @@ }

function ensureValidName (name, strict, allowLegacyCase) {
if (name.charAt(0) === "." ||
if (name.charAt(0) === '.' ||
!(isValidScopedPackageName(name) || isCorrectlyEncodedName(name)) ||
(strict && (!allowLegacyCase) && name !== name.toLowerCase()) ||
name.toLowerCase() === "node_modules" ||
name.toLowerCase() === "favicon.ico") {
throw new Error("Invalid name: " + JSON.stringify(name))
name.toLowerCase() === 'node_modules' ||
name.toLowerCase() === 'favicon.ico') {
throw new Error('Invalid name: ' + JSON.stringify(name))
}

@@ -355,5 +388,8 @@ }

function modifyPeople (data, fn) {
if (data.author) data.author = fn(data.author)
;["maintainers", "contributors"].forEach(function (set) {
if (!Array.isArray(data[set])) return;
if (data.author) {
data.author = fn(data.author)
}['maintainers', 'contributors'].forEach(function (set) {
if (!Array.isArray(data[set])) {
return
}
data[set] = data[set].map(fn)

@@ -365,20 +401,30 @@ })

function unParsePerson (person) {
if (typeof person === "string") return person
var name = person.name || ""
if (typeof person === 'string') {
return person
}
var name = person.name || ''
var u = person.url || person.web
var url = u ? (" ("+u+")") : ""
var url = u ? (' (' + u + ')') : ''
var e = person.email || person.mail
var email = e ? (" <"+e+">") : ""
return name+email+url
var email = e ? (' <' + e + '>') : ''
return name + email + url
}
function parsePerson (person) {
if (typeof person !== "string") return person
var name = person.match(/^([^\(<]+)/)
var url = person.match(/\(([^\)]+)\)/)
if (typeof person !== 'string') {
return person
}
var name = person.match(/^([^(<]+)/)
var url = person.match(/\(([^)]+)\)/)
var email = person.match(/<([^>]+)>/)
var obj = {}
if (name && name[0].trim()) obj.name = name[0].trim()
if (email) obj.email = email[1];
if (url) obj.url = url[1];
if (name && name[0].trim()) {
obj.name = name[0].trim()
}
if (email) {
obj.email = email[1]
}
if (url) {
obj.url = url[1]
}
return obj

@@ -389,3 +435,5 @@ }

var o = data.optionalDependencies
if (!o) return;
if (!o) {
return
}
var d = data.dependencies || {}

@@ -399,17 +447,21 @@ Object.keys(o).forEach(function (k) {

function depObjectify (deps, type, warn) {
if (!deps) return {}
if (typeof deps === "string") {
if (!deps) {
return {}
}
if (typeof deps === 'string') {
deps = deps.trim().split(/[\n\r\s\t ,]+/)
}
if (!Array.isArray(deps)) return deps
warn("deprecatedArrayDependencies", type)
if (!Array.isArray(deps)) {
return deps
}
warn('deprecatedArrayDependencies', type)
var o = {}
deps.filter(function (d) {
return typeof d === "string"
}).forEach(function(d) {
return typeof d === 'string'
}).forEach(function (d) {
d = d.trim().split(/(:?[@\s><=])/)
var dn = d.shift()
var dv = d.join("")
var dv = d.join('')
dv = dv.trim()
dv = dv.replace(/^@/, "")
dv = dv.replace(/^@/, '')
o[dn] = dv

@@ -422,3 +474,5 @@ })

depTypes.forEach(function (type) {
if (!data[type]) return;
if (!data[type]) {
return
}
data[type] = depObjectify(data[type], type, warn)

@@ -428,7 +482,9 @@ })

function bugsTypos(bugs, warn) {
if (!bugs) return
function bugsTypos (bugs, warn) {
if (!bugs) {
return
}
Object.keys(bugs).forEach(function (k) {
if (typos.bugs[k]) {
warn("typo", k, typos.bugs[k], "bugs")
warn('typo', k, typos.bugs[k], 'bugs')
bugs[typos.bugs[k]] = bugs[k]

@@ -435,0 +491,0 @@ delete bugs[k]

@@ -1,11 +0,10 @@

var util = require("util")
var messages = require("./warning_messages.json")
var util = require('util')
var messages = require('./warning_messages.json')
module.exports = function() {
module.exports = function () {
var args = Array.prototype.slice.call(arguments, 0)
var warningName = args.shift()
if (warningName == "typo") {
return makeTypoWarning.apply(null,args)
}
else {
if (warningName === 'typo') {
return makeTypoWarning.apply(null, args)
} else {
var msgTemplate = messages[warningName] ? messages[warningName] : warningName + ": '%s'"

@@ -12,0 +11,0 @@ args.unshift(msgTemplate)

module.exports = normalize
var fixer = require("./fixer")
var fixer = require('./fixer')
normalize.fixer = fixer
var makeWarning = require("./make_warning")
var makeWarning = require('./make_warning')
var fieldsToFix = ['name','version','description','repository','modules','scripts'
,'files','bin','man','bugs','keywords','readme','homepage','license']
var otherThingsToFix = ['dependencies','people', 'typos']
var fieldsToFix = ['name', 'version', 'description', 'repository', 'modules', 'scripts',
'files', 'bin', 'man', 'bugs', 'keywords', 'readme', 'homepage', 'license']
var otherThingsToFix = ['dependencies', 'people', 'typos']
var thingsToFix = fieldsToFix.map(function(fieldName) {
return ucFirst(fieldName) + "Field"
var thingsToFix = fieldsToFix.map(function (fieldName) {
return ucFirst(fieldName) + 'Field'
})

@@ -21,20 +21,29 @@ // two ways to do this in CoffeeScript on only one line, sub-70 chars:

function normalize (data, warn, strict) {
if(warn === true) warn = null, strict = true
if(!strict) strict = false
if(!warn || data.private) warn = function(msg) { /* noop */ }
if (warn === true) {
warn = null
strict = true
}
if (!strict) {
strict = false
}
if (!warn || data.private) {
warn = function (msg) { /* noop */ }
}
if (data.scripts &&
data.scripts.install === "node-gyp rebuild" &&
data.scripts.install === 'node-gyp rebuild' &&
!data.scripts.preinstall) {
data.gypfile = true
}
fixer.warn = function() { warn(makeWarning.apply(null, arguments)) }
thingsToFix.forEach(function(thingName) {
fixer["fix" + ucFirst(thingName)](data, strict)
fixer.warn = function () {
warn(makeWarning.apply(null, arguments))
}
thingsToFix.forEach(function (thingName) {
fixer['fix' + ucFirst(thingName)](data, strict)
})
data._id = data.name + "@" + data.version
data._id = data.name + '@' + data.version
}
function ucFirst (string) {
return string.charAt(0).toUpperCase() + string.slice(1);
return string.charAt(0).toUpperCase() + string.slice(1)
}
var util = require('util')
module.exports = function() {
module.exports = function () {
var args = Array.prototype.slice.call(arguments, 0)
args.forEach(function(arg) {
if (!arg) throw new TypeError('Bad arguments.')
args.forEach(function (arg) {
if (!arg) {
throw new TypeError('Bad arguments.')
}
})
return util.format.apply(null, arguments)
}
{
"name": "normalize-package-data",
"version": "3.0.2",
"version": "3.0.3",
"author": "Meryn Stol <merynstol@gmail.com>",

@@ -16,7 +16,12 @@ "description": "Normalizes data that can be found in package.json files.",

"preversion": "npm test",
"test": "tap test/*.js"
"test": "tap test/*.js --branches 85 --functions 90 --lines 85 --statements 85",
"npmclilint": "npmcli-lint",
"lint": "npm run npmclilint -- \"lib/**/*.*js\" \"test/**/*.*js\"",
"lintfix": "npm run lint -- --fix",
"posttest": "npm run lint --",
"postsnap": "npm run lintfix --"
},
"dependencies": {
"hosted-git-info": "^4.0.1",
"resolve": "^1.20.0",
"is-core-module": "^2.5.0",
"semver": "^7.3.4",

@@ -26,3 +31,4 @@ "validate-npm-package-license": "^3.0.1"

"devDependencies": {
"tap": "^14.11.0"
"@npmcli/lint": "^1.0.2",
"tap": "^15.0.9"
},

@@ -29,0 +35,0 @@ "files": [

@@ -99,3 +99,3 @@ # normalize-package-data

The `license` field should be a valid *SPDX license expression* or one of the special values allowed by [validate-npm-package-license](https://npmjs.com/package/validate-npm-package-license). See [documentation for the license field in package.json](https://docs.npmjs.com/files/package.json#license).
The `license`/`licence` field should be a valid *SPDX license expression* or one of the special values allowed by [validate-npm-package-license](https://npmjs.com/package/validate-npm-package-license). See [documentation for the license field in package.json](https://docs.npmjs.com/files/package.json#license).

@@ -108,3 +108,3 @@ ## Credits

normalize-package-data is released under the [BSD 2-Clause License](http://opensource.org/licenses/MIT).
Copyright (c) 2013 Meryn Stol
normalize-package-data is released under the [BSD 2-Clause License](https://opensource.org/licenses/BSD-2-Clause).
Copyright (c) 2013 Meryn Stol

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

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

Packages

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc