| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418 | 
							- 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 fixer = module.exports = {
 
-   // default warning function
 
-   warn: function() {},
 
-   fixRepositoryField: function(data) {
 
-     if (data.repositories) {
 
-       this.warn("repositories");
 
-       data.repository = data.repositories[0]
 
-     }
 
-     if (!data.repository) return this.warn("missingRepository")
 
-     if (typeof data.repository === "string") {
 
-       data.repository = {
 
-         type: "git",
 
-         url: data.repository
 
-       }
 
-     }
 
-     var r = data.repository.url || ""
 
-     if (r) {
 
-       var hosted = hostedGitInfo.fromUrl(r)
 
-       if (hosted) {
 
-         r = data.repository.url
 
-           = hosted.getDefaultRepresentation() == "shortcut" ? hosted.https() : hosted.toString()
 
-       }
 
-     }
 
-     if (r.match(/github.com\/[^\/]+\/[^\/]+\.git\.git$/)) {
 
-       this.warn("brokenGitUrl", r)
 
-     }
 
-   }
 
- , fixTypos: function(data) {
 
-     Object.keys(typos.topLevel).forEach(function (d) {
 
-       if (data.hasOwnProperty(d)) {
 
-         this.warn("typo", d, typos.topLevel[d])
 
-       }
 
-     }, this)
 
-   }
 
- , fixScriptsField: function(data) {
 
-     if (!data.scripts) return
 
-     if (typeof data.scripts !== "object") {
 
-       this.warn("nonObjectScripts")
 
-       delete data.scripts
 
-       return
 
-     }
 
-     Object.keys(data.scripts).forEach(function (k) {
 
-       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)
 
-   }
 
- , fixFilesField: function(data) {
 
-     var files = data.files
 
-     if (files && !Array.isArray(files)) {
 
-       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)
 
-           return false
 
-         } else {
 
-           return true
 
-         }
 
-       }, this)
 
-     }
 
-   }
 
- , fixBinField: function(data) {
 
-     if (!data.bin) return;
 
-     if (typeof data.bin === "string") {
 
-       var b = {}
 
-       var match
 
-       if (match = data.name.match(/^@[^/]+[/](.*)$/)) {
 
-         b[match[1]] = data.bin
 
-       } else {
 
-         b[data.name] = data.bin
 
-       }
 
-       data.bin = b
 
-     }
 
-   }
 
- , fixManField: function(data) {
 
-     if (!data.man) return;
 
-     if (typeof data.man === "string") {
 
-       data.man = [ data.man ]
 
-     }
 
-   }
 
- , fixBundleDependenciesField: function(data) {
 
-     var bdd = "bundledDependencies"
 
-     var bd = "bundleDependencies"
 
-     if (data[bdd] && !data[bd]) {
 
-       data[bd] = data[bdd]
 
-       delete data[bdd]
 
-     }
 
-     if (data[bd] && !Array.isArray(data[bd])) {
 
-       this.warn("nonArrayBundleDependencies")
 
-       delete data[bd]
 
-     } else if (data[bd]) {
 
-       data[bd] = data[bd].filter(function(bd) {
 
-         if (!bd || typeof bd !== 'string') {
 
-           this.warn("nonStringBundleDependency", bd)
 
-           return false
 
-         } else {
 
-           if (!data.dependencies) {
 
-             data.dependencies = {}
 
-           }
 
-           if (!data.dependencies.hasOwnProperty(bd)) {
 
-             this.warn("nonDependencyBundleDependency", bd)
 
-             data.dependencies[bd] = "*"
 
-           }
 
-           return true
 
-         }
 
-       }, this)
 
-     }
 
-   }
 
- , 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("nonObjectDependencies", deps)
 
-         delete data[deps]
 
-         return
 
-       }
 
-       Object.keys(data[deps]).forEach(function (d) {
 
-         var r = data[deps][d]
 
-         if (typeof r !== 'string') {
 
-           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()
 
-       }, this)
 
-     }, this)
 
-   }
 
- , fixModulesField: function (data) {
 
-     if (data.modules) {
 
-       this.warn("deprecatedModules")
 
-       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("nonArrayKeywords")
 
-     } else if (data.keywords) {
 
-       data.keywords = data.keywords.filter(function(kw) {
 
-         if (typeof kw !== "string" || !kw) {
 
-           this.warn("nonStringKeyword");
 
-           return false
 
-         } else {
 
-           return true
 
-         }
 
-       }, this)
 
-     }
 
-   }
 
- , 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) {
 
-       data.version = ""
 
-       return true
 
-     }
 
-     if (!semver.valid(data.version, loose)) {
 
-       throw new Error('Invalid version: "'+ data.version + '"')
 
-     }
 
-     data.version = semver.clean(data.version, loose)
 
-     return true
 
-   }
 
- , 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 = {}
 
-     var strict = options.strict
 
-     if (!data.name && !strict) {
 
-       data.name = ""
 
-       return
 
-     }
 
-     if (typeof data.name !== "string") {
 
-       throw new Error("name field must be a string.")
 
-     }
 
-     if (!strict)
 
-       data.name = data.name.trim()
 
-     ensureValidName(data.name, strict, options.allowLegacyCase)
 
-     if (isBuiltinModule(data.name))
 
-       this.warn("conflictingName", data.name)
 
-   }
 
- , fixDescriptionField: function (data) {
 
-     if (data.description && typeof data.description !== 'string') {
 
-       this.warn("nonStringDescription")
 
-       delete 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")
 
-   }
 
- , fixReadmeField: function (data) {
 
-     if (!data.readme) {
 
-       this.warn("missingReadme")
 
-       data.readme = "ERROR: No README data found!"
 
-     }
 
-   }
 
- , fixBugsField: function(data) {
 
-     if (!data.bugs && data.repository && data.repository.url) {
 
-       var hosted = hostedGitInfo.fromUrl(data.repository.url)
 
-       if(hosted && hosted.bugs()) {
 
-         data.bugs = {url: hosted.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)
 
-           data.bugs = {url: data.bugs}
 
-         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)
 
-             data.bugs.url = oldBugs.url
 
-           else
 
-             this.warn("nonUrlBugsUrlField")
 
-         }
 
-         if(oldBugs.email) {
 
-           if(typeof(oldBugs.email) == "string" && emailRe.test(oldBugs.email))
 
-             data.bugs.email = oldBugs.email
 
-           else
 
-             this.warn("nonEmailBugsEmailField")
 
-         }
 
-       }
 
-       if(!data.bugs.email && !data.bugs.url) {
 
-         delete data.bugs
 
-         this.warn("emptyNormalizedBugs")
 
-       }
 
-     }
 
-   }
 
- , 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 (!data.homepage) return
 
-     if(typeof data.homepage !== "string") {
 
-       this.warn("nonUrlHomepage")
 
-       return delete data.homepage
 
-     }
 
-     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")
 
-       }
 
-     }
 
-   }
 
- }
 
- function isValidScopedPackageName(spec) {
 
-   if (spec.charAt(0) !== '@') return false
 
-   var rest = spec.slice(1).split('/')
 
-   if (rest.length !== 2) return false
 
-   return rest[0] && rest[1] &&
 
-     rest[0] === encodeURIComponent(rest[0]) &&
 
-     rest[1] === encodeURIComponent(rest[1])
 
- }
 
- function isCorrectlyEncodedName(spec) {
 
-   return !spec.match(/[\/@\s\+%:]/) &&
 
-     spec === encodeURIComponent(spec)
 
- }
 
- function ensureValidName (name, strict, allowLegacyCase) {
 
-   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))
 
-   }
 
- }
 
- function modifyPeople (data, fn) {
 
-   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)
 
-   })
 
-   return data
 
- }
 
- function unParsePerson (person) {
 
-   if (typeof person === "string") return person
 
-   var name = person.name || ""
 
-   var u = person.url || person.web
 
-   var url = u ? (" ("+u+")") : ""
 
-   var e = person.email || person.mail
 
-   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(/\(([^\)]+)\)/)
 
-   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];
 
-   return obj
 
- }
 
- function addOptionalDepsToDeps (data, warn) {
 
-   var o = data.optionalDependencies
 
-   if (!o) return;
 
-   var d = data.dependencies || {}
 
-   Object.keys(o).forEach(function (k) {
 
-     d[k] = o[k]
 
-   })
 
-   data.dependencies = d
 
- }
 
- function depObjectify (deps, type, warn) {
 
-   if (!deps) return {}
 
-   if (typeof deps === "string") {
 
-     deps = deps.trim().split(/[\n\r\s\t ,]+/)
 
-   }
 
-   if (!Array.isArray(deps)) return deps
 
-   warn("deprecatedArrayDependencies", type)
 
-   var o = {}
 
-   deps.filter(function (d) {
 
-     return typeof d === "string"
 
-   }).forEach(function(d) {
 
-     d = d.trim().split(/(:?[@\s><=])/)
 
-     var dn = d.shift()
 
-     var dv = d.join("")
 
-     dv = dv.trim()
 
-     dv = dv.replace(/^@/, "")
 
-     o[dn] = dv
 
-   })
 
-   return o
 
- }
 
- function objectifyDeps (data, warn) {
 
-   depTypes.forEach(function (type) {
 
-     if (!data[type]) return;
 
-     data[type] = depObjectify(data[type], type, warn)
 
-   })
 
- }
 
- function bugsTypos(bugs, warn) {
 
-   if (!bugs) return
 
-   Object.keys(bugs).forEach(function (k) {
 
-     if (typos.bugs[k]) {
 
-       warn("typo", k, typos.bugs[k], "bugs")
 
-       bugs[typos.bugs[k]] = bugs[k]
 
-       delete bugs[k]
 
-     }
 
-   })
 
- }
 
 
  |