"Fossies" - the Fresh Open Source Software Archive

Member "Atom/resources/app/apm/node_modules/read-installed/read-installed.js" (8 Mar 2017, 11682 Bytes) of archive /windows/misc/atom-windows.zip:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Javascript source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file.

    1 
    2 // Walk through the file-system "database" of installed
    3 // packages, and create a data object related to the
    4 // installed versions of each package.
    5 
    6 /*
    7 This will traverse through all node_modules folders,
    8 resolving the dependencies object to the object corresponding to
    9 the package that meets that dep, or just the version/range if
   10 unmet.
   11 
   12 Assuming that you had this folder structure:
   13 
   14 /path/to
   15 +-- package.json { name = "root" }
   16 `-- node_modules
   17     +-- foo {bar, baz, asdf}
   18     | +-- node_modules
   19     |   +-- bar { baz }
   20     |   `-- baz
   21     `-- asdf
   22 
   23 where "foo" depends on bar, baz, and asdf, bar depends on baz,
   24 and bar and baz are bundled with foo, whereas "asdf" is at
   25 the higher level (sibling to foo), you'd get this object structure:
   26 
   27 { <package.json data>
   28 , path: "/path/to"
   29 , parent: null
   30 , dependencies:
   31   { foo :
   32     { version: "1.2.3"
   33     , path: "/path/to/node_modules/foo"
   34     , parent: <Circular: root>
   35     , dependencies:
   36       { bar:
   37         { parent: <Circular: foo>
   38         , path: "/path/to/node_modules/foo/node_modules/bar"
   39         , version: "2.3.4"
   40         , dependencies: { baz: <Circular: foo.dependencies.baz> }
   41         }
   42       , baz: { ... }
   43       , asdf: <Circular: asdf>
   44       }
   45     }
   46   , asdf: { ... }
   47   }
   48 }
   49 
   50 Unmet deps are left as strings.
   51 Extraneous deps are marked with extraneous:true
   52 deps that don't meet a requirement are marked with invalid:true
   53 deps that don't meet a peer requirement are marked with peerInvalid:true
   54 
   55 to READ(packagefolder, parentobj, name, reqver)
   56 obj = read package.json
   57 installed = ./node_modules/*
   58 if parentobj is null, and no package.json
   59   obj = {dependencies:{<installed>:ANY}}
   60 deps = Object.keys(obj.dependencies)
   61 obj.path = packagefolder
   62 obj.parent = parentobj
   63 if name, && obj.name !== name, obj.invalid = true
   64 if reqver, && obj.version !satisfies reqver, obj.invalid = true
   65 if !reqver && parentobj, obj.extraneous = true
   66 for each folder in installed
   67   obj.dependencies[folder] = READ(packagefolder+node_modules+folder,
   68                                   obj, folder, obj.dependencies[folder])
   69 # walk tree to find unmet deps
   70 for each dep in obj.dependencies not in installed
   71   r = obj.parent
   72   while r
   73     if r.dependencies[dep]
   74       if r.dependencies[dep].verion !satisfies obj.dependencies[dep]
   75         WARN
   76         r.dependencies[dep].invalid = true
   77       obj.dependencies[dep] = r.dependencies[dep]
   78       r = null
   79     else r = r.parent
   80 return obj
   81 
   82 
   83 TODO:
   84 1. Find unmet deps in parent directories, searching as node does up
   85 as far as the left-most node_modules folder.
   86 2. Ignore anything in node_modules that isn't a package folder.
   87 
   88 */
   89 
   90 try {
   91   var fs = require("graceful-fs")
   92 } catch (er) {
   93   var fs = require("fs")
   94 }
   95 
   96 var path = require("path")
   97 var asyncMap = require("slide").asyncMap
   98 var semver = require("semver")
   99 var readJson = require("read-package-json")
  100 var url = require("url")
  101 var util = require("util")
  102 var extend = require("util-extend")
  103 
  104 var debug = require("debuglog")("read-installed")
  105 
  106 var readdir = require("readdir-scoped-modules")
  107 
  108 // Sentinel catch-all version constraint used when a dependency is not
  109 // listed in the package.json file.
  110 var ANY = {}
  111 
  112 module.exports = readInstalled
  113 
  114 function readInstalled (folder, opts, cb) {
  115   if (typeof opts === 'function') {
  116     cb = opts
  117     opts = {}
  118   } else {
  119     opts = extend({}, opts)
  120   }
  121 
  122   if (typeof opts.depth !== 'number')
  123     opts.depth = Infinity
  124 
  125   opts.depth = Math.max(0, opts.depth)
  126 
  127   if (typeof opts.log !== 'function')
  128     opts.log = function () {}
  129 
  130   opts.dev = !!opts.dev
  131   opts.realpathSeen = {}
  132   opts.findUnmetSeen = []
  133 
  134 
  135   readInstalled_(folder, null, null, null, 0, opts, function (er, obj) {
  136     if (er) return cb(er)
  137     // now obj has all the installed things, where they're installed
  138     // figure out the inheritance links, now that the object is built.
  139     resolveInheritance(obj, opts)
  140     obj.root = true
  141     unmarkExtraneous(obj, opts)
  142     cb(null, obj)
  143   })
  144 }
  145 
  146 function readInstalled_ (folder, parent, name, reqver, depth, opts, cb) {
  147   var installed
  148     , obj
  149     , real
  150     , link
  151     , realpathSeen = opts.realpathSeen
  152 
  153   readdir(path.resolve(folder, "node_modules"), function (er, i) {
  154     // error indicates that nothing is installed here
  155     if (er) i = []
  156     installed = i.filter(function (f) { return f.charAt(0) !== "." })
  157     next()
  158   })
  159 
  160   readJson(path.resolve(folder, "package.json"), function (er, data) {
  161     obj = copy(data)
  162 
  163     if (!parent) {
  164       obj = obj || true
  165       er = null
  166     }
  167     return next(er)
  168   })
  169 
  170   fs.lstat(folder, function (er, st) {
  171     if (er) {
  172       if (!parent) real = true
  173       return next(er)
  174     }
  175     fs.realpath(folder, function (er, rp) {
  176       debug("realpath(%j) = %j", folder, rp)
  177       real = rp
  178       if (st.isSymbolicLink()) link = rp
  179       next(er)
  180     })
  181   })
  182 
  183   var errState = null
  184     , called = false
  185   function next (er) {
  186     if (errState) return
  187     if (er) {
  188       errState = er
  189       return cb(null, [])
  190     }
  191     debug('next', installed, obj && typeof obj, name, real)
  192     if (!installed || !obj || !real || called) return
  193     called = true
  194     if (realpathSeen[real]) return cb(null, realpathSeen[real])
  195     if (obj === true) {
  196       obj = {dependencies:{}, path:folder}
  197       installed.forEach(function (i) { obj.dependencies[i] = ANY })
  198     }
  199     if (name && obj.name !== name) obj.invalid = true
  200     obj.realName = name || obj.name
  201     obj.dependencies = obj.dependencies || {}
  202 
  203     // At this point, figure out what dependencies we NEED to get met
  204     obj._dependencies = copy(obj.dependencies)
  205 
  206     if (reqver === ANY) {
  207       // We were unable to determine the required version of this
  208       // dependency from the package.json file, but we now know its actual
  209       // version, so treat that version as the required version to avoid
  210       // marking the dependency as invalid below. See #40.
  211       reqver = obj.version;
  212     }
  213 
  214     // "foo":"http://blah" and "foo":"latest" are always presumed valid
  215     if (reqver
  216         && semver.validRange(reqver, true)
  217         && !semver.satisfies(obj.version, reqver, true)) {
  218       obj.invalid = true
  219     }
  220 
  221     // Mark as extraneous at this point.
  222     // This will be un-marked in unmarkExtraneous, where we mark as
  223     // not-extraneous everything that is required in some way from
  224     // the root object.
  225     obj.extraneous = true
  226 
  227     obj.path = obj.path || folder
  228     obj.realPath = real
  229     obj.link = link
  230     if (parent && !obj.link) obj.parent = parent
  231     realpathSeen[real] = obj
  232     obj.depth = depth
  233     //if (depth >= opts.depth) return cb(null, obj)
  234     asyncMap(installed, function (pkg, cb) {
  235       var rv = obj.dependencies[pkg]
  236       if (!rv && obj.devDependencies && opts.dev)
  237         rv = obj.devDependencies[pkg]
  238 
  239       if (depth > opts.depth) {
  240         obj.dependencies = {}
  241         return cb(null, obj)
  242       }
  243 
  244       readInstalled_( path.resolve(folder, "node_modules/"+pkg)
  245                     , obj, pkg, obj.dependencies[pkg], depth + 1, opts
  246                     , cb )
  247 
  248     }, function (er, installedData) {
  249       if (er) return cb(er)
  250       installedData.forEach(function (dep) {
  251         obj.dependencies[dep.realName] = dep
  252       })
  253 
  254       // any strings here are unmet things.  however, if it's
  255       // optional, then that's fine, so just delete it.
  256       if (obj.optionalDependencies) {
  257         Object.keys(obj.optionalDependencies).forEach(function (dep) {
  258           if (typeof obj.dependencies[dep] === "string") {
  259             delete obj.dependencies[dep]
  260           }
  261         })
  262       }
  263       return cb(null, obj)
  264     })
  265   }
  266 }
  267 
  268 // starting from a root object, call findUnmet on each layer of children
  269 var riSeen = []
  270 function resolveInheritance (obj, opts) {
  271   if (typeof obj !== "object") return
  272   if (riSeen.indexOf(obj) !== -1) return
  273   riSeen.push(obj)
  274   if (typeof obj.dependencies !== "object") {
  275     obj.dependencies = {}
  276   }
  277   Object.keys(obj.dependencies).forEach(function (dep) {
  278     findUnmet(obj.dependencies[dep], opts)
  279   })
  280   Object.keys(obj.dependencies).forEach(function (dep) {
  281     if (typeof obj.dependencies[dep] === "object") {
  282       resolveInheritance(obj.dependencies[dep], opts)
  283     } else {
  284       debug("unmet dep! %s %s@%s", obj.name, dep, obj.dependencies[dep])
  285     }
  286   })
  287   findUnmet(obj, opts)
  288 }
  289 
  290 // find unmet deps by walking up the tree object.
  291 // No I/O
  292 function findUnmet (obj, opts) {
  293   var findUnmetSeen = opts.findUnmetSeen
  294   if (findUnmetSeen.indexOf(obj) !== -1) return
  295   findUnmetSeen.push(obj)
  296   debug("find unmet parent=%s obj=", obj.parent && obj.parent.name, obj.name || obj)
  297   var deps = obj.dependencies = obj.dependencies || {}
  298 
  299   debug(deps)
  300   Object.keys(deps)
  301     .filter(function (d) { return typeof deps[d] === "string" })
  302     .forEach(function (d) {
  303       var found = findDep(obj, d)
  304       debug("finding dep %j", d, found && found.name || found)
  305       // "foo":"http://blah" and "foo":"latest" are always presumed valid
  306       if (typeof deps[d] === "string" &&
  307           semver.validRange(deps[d], true) &&
  308           found &&
  309           !semver.satisfies(found.version, deps[d], true)) {
  310         // the bad thing will happen
  311         opts.log( "unmet dependency"
  312                 , obj.path + " requires "+d+"@'"+deps[d]
  313                 + "' but will load\n"
  314                 + found.path+",\nwhich is version "+found.version )
  315         found.invalid = true
  316       }
  317       if (found) {
  318         deps[d] = found
  319       }
  320     })
  321 
  322   var peerDeps = obj.peerDependencies = obj.peerDependencies || {}
  323   Object.keys(peerDeps).forEach(function (d) {
  324     var dependency
  325 
  326     if (!obj.parent) {
  327       dependency = obj.dependencies[d]
  328 
  329       // read it as a missing dep
  330       if (!dependency) {
  331         obj.dependencies[d] = peerDeps[d]
  332       }
  333     } else {
  334       var r = obj.parent
  335       while (r && !dependency) {
  336         dependency = r.dependencies && r.dependencies[d]
  337         r = r.link ? null : r.parent
  338       }
  339     }
  340 
  341     if (!dependency) {
  342       // mark as a missing dep!
  343       obj.dependencies[d] = peerDeps[d]
  344     } else if (!semver.satisfies(dependency.version, peerDeps[d], true)) {
  345       dependency.peerInvalid = true
  346     }
  347   })
  348 
  349   return obj
  350 }
  351 
  352 function unmarkExtraneous (obj, opts) {
  353   // Mark all non-required deps as extraneous.
  354   // start from the root object and mark as non-extraneous all modules
  355   // that haven't been previously flagged as extraneous then propagate
  356   // to all their dependencies
  357 
  358   obj.extraneous = false
  359 
  360   var deps = obj._dependencies || []
  361   if (opts.dev && obj.devDependencies && (obj.root || obj.link)) {
  362     Object.keys(obj.devDependencies).forEach(function (k) {
  363       deps[k] = obj.devDependencies[k]
  364     })
  365   }
  366 
  367   if (obj.peerDependencies) {
  368     Object.keys(obj.peerDependencies).forEach(function (k) {
  369       deps[k] = obj.peerDependencies[k]
  370     })
  371   }
  372 
  373   debug("not extraneous", obj._id, deps)
  374   Object.keys(deps).forEach(function (d) {
  375     var dep = findDep(obj, d)
  376     if (dep && dep.extraneous) {
  377       unmarkExtraneous(dep, opts)
  378     }
  379   })
  380 }
  381 
  382 // Find the one that will actually be loaded by require()
  383 // so we can make sure it's valid etc.
  384 function findDep (obj, d) {
  385   var r = obj
  386     , found = null
  387   while (r && !found) {
  388     // if r is a valid choice, then use that.
  389     // kinda weird if a pkg depends on itself, but after the first
  390     // iteration of this loop, it indicates a dep cycle.
  391     if (typeof r.dependencies[d] === "object") {
  392       found = r.dependencies[d]
  393     }
  394     if (!found && r.realName === d) found = r
  395     r = r.link ? null : r.parent
  396   }
  397   return found
  398 }
  399 
  400 function copy (obj) {
  401   if (!obj || typeof obj !== 'object') return obj
  402   if (Array.isArray(obj)) return obj.map(copy)
  403 
  404   var o = {}
  405   for (var i in obj) o[i] = copy(obj[i])
  406   return o
  407 }