Skip to content
This repository was archived by the owner on Jan 7, 2022. It is now read-only.

Commit db70482

Browse files
committed
Handle Node and Link objects properly
1 parent 10d6f6d commit db70482

File tree

2 files changed

+91
-20
lines changed

2 files changed

+91
-20
lines changed

README.md

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,10 @@ rpt('/path/to/pkg/root', function (er, data) {
1111
// data is a structure like:
1212
// {
1313
// package: <package.json data, or null>
14-
// children: [ <more things like this, inside node_modules> ]
15-
// path: <real path where package lives>
14+
// children: [ <more things like this> ]
15+
// path: <path loaded>
16+
// realpath: <the real path on disk>
17+
// target: <if a Link, then this is the actual Node>
1618
// }
1719
})
1820
```
@@ -25,3 +27,20 @@ anything else.
2527

2628
Just follows the links in the `node_modules` heirarchy and reads the
2729
package.json files it finds therein.
30+
31+
## Symbolic Links
32+
33+
When there are symlinks to packages in the `node_modules` hierarchy, a
34+
`Link` object will be created, with a `target` that is a `Node`
35+
object.
36+
37+
For the most part, you can treat `Link` objects just the same as
38+
`Node` objects. But if your tree-walking program needs to treat
39+
symlinks differently from normal folders, then make sure to check the
40+
object.
41+
42+
In a given `read-package-tree` run, a specific `path` will always
43+
correspond to a single object, and a specific `realpath` will always
44+
correspond to a single `Node` object. This means that you may not be
45+
able to pass the resulting data object to `JSON.stringify`, because it
46+
may contain cycles.

rpt.js

Lines changed: 70 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,33 +14,81 @@ function dpath (p) {
1414

1515
module . exports = rpt
1616

17-
function Node (package, path) {
17+
rpt . Node = Node
18+
rpt . Link = Link
19+
20+
var ID = 0
21+
function Node (package, path, cache) {
22+
if (cache [path])
23+
return cache [path]
24+
1825
if (! (this instanceof Node))
19-
return new Node (package, path)
26+
return new Node (package, path, cache)
27+
28+
cache [path] = this
2029

21-
debug ('Node', dpath (path), package && package . _id)
30+
debug (this . constructor . name, dpath (path), package && package . _id)
31+
32+
this . id = ID ++
2233
this . package = package
2334
this . path = path
35+
this . realpath = path
2436
this . children = []
2537
}
2638
Node . prototype . package = null
2739
Node . prototype . path = ''
40+
Node . prototype . realpath = ''
2841
Node . prototype . children = null
2942

30-
function loadNode (p, cb) {
43+
44+
45+
function Link (package, path, realpath, cache) {
46+
if (cache [path])
47+
return cache [path]
48+
49+
if (! (this instanceof Link))
50+
return new Link (package, path, realpath)
51+
52+
cache [path] = this
53+
54+
debug (this . constructor . name, dpath (path), package && package . _id)
55+
56+
this . id = ID ++
57+
this . path = path
58+
this . realpath = realpath
59+
this . package = package
60+
this . target = new Node (package, realpath, cache)
61+
this . children = this . target . children
62+
}
63+
Link . prototype = Object . create (Node . prototype, {
64+
constructor : { value : Link }
65+
})
66+
Link . prototype . target = null
67+
Link . prototype . realpath = ''
68+
69+
70+
71+
function loadNode (p, cache, cb) {
3172
debug ('loadNode', dpath (p))
3273
fs . realpath (p, function (er, real) {
3374
if (er)
3475
return cb (er)
3576
debug ('realpath p=%j real=%j', dpath (p), dpath (real))
3677
var pj = path . resolve (real, 'package.json')
3778
rpj (pj, function (er, package) {
38-
cb (er, new Node (package || null, real))
79+
package = package || null
80+
var n
81+
if (p === real)
82+
n = new Node (package, real, cache)
83+
else
84+
n = new Link (package, p, real, cache)
85+
86+
cb (er, n)
3987
})
4088
})
4189
}
4290

43-
function loadChildren (node, cb) {
91+
function loadChildren (node, cache, cb) {
4492
debug ('loadChildren', dpath(node . path))
4593
// don't let it be called more than once
4694
cb = once (cb)
@@ -60,7 +108,7 @@ function loadChildren (node, cb) {
60108

61109
kids . forEach (function (kid) {
62110
var p = path . resolve (nm, kid)
63-
loadNode (p, then)
111+
loadNode (p, cache, then)
64112
})
65113

66114
function then (er, kid) {
@@ -83,28 +131,30 @@ function sortChildren (node) {
83131
})
84132
}
85133

86-
function loadTree (node, cb, did) {
87-
did = did || Object . create (null)
88-
debug ('loadTree', dpath (node . path), !! did [ node . path ])
89-
if (did [ node . path ])
134+
function loadTree (node, did, cache, cb) {
135+
debug ('loadTree', dpath (node . path), !! cache [ node . path ])
136+
137+
if (did [ node . realpath ]) {
90138
return dz (cb) (null, node)
139+
}
91140

92-
did [ node . path ] = true
141+
did [ node . realpath ] = true
93142

94143
cb = once (cb)
95-
loadChildren (node, function (er, node) {
144+
loadChildren (node, cache, function (er, node) {
96145
if (er)
97146
return cb (er)
98147

99148
var kids = node . children . filter (function (kid) {
100-
return ! did [ kid . path ]
149+
return !did [ kid . realpath ]
101150
})
151+
102152
var l = kids . length
103153
if (l === 0)
104154
return cb (null, node)
105155

106-
kids . forEach (function (kid) {
107-
loadTree (kid, then, did)
156+
kids . forEach (function (kid, index) {
157+
loadTree (kid, did, cache, then)
108158
})
109159

110160
function then (er, kid) {
@@ -118,11 +168,13 @@ function loadTree (node, cb, did) {
118168
}
119169

120170
function rpt (root, cb) {
171+
root = path . resolve (root)
121172
debug ('rpt', dpath (root))
122-
loadNode (root, function (er, node) {
173+
var cache = Object . create (null)
174+
loadNode (root, cache, function (er, node) {
123175
// if there's an error, it's fine, as long as we got a node
124176
if (!node)
125177
return cb (er)
126-
loadTree (node, cb)
178+
loadTree (node, {}, cache, cb)
127179
})
128180
}

0 commit comments

Comments
 (0)