|  | var fs = require ('graceful-fs') | 
|  | var dz = require ('dezalgo') | 
|  | var once = require ('once') | 
|  | var path = require ('path') | 
|  | var debug = require ('debuglog') ('rds') | 
|  |  | 
|  | module . exports = readdir | 
|  | readdir.sync = readdirSync | 
|  |  | 
|  | function readdir (dir, cb) { | 
|  | fs . readdir (dir, function (er, kids) { | 
|  | if (er) | 
|  | return cb (er) | 
|  |  | 
|  | debug ('dir=%j, kids=%j', dir, kids) | 
|  | readScopes (dir, kids, function (er, data) { | 
|  | if (er) | 
|  | return cb (er) | 
|  |  | 
|  | // Sort for bonus consistency points | 
|  | data = data . sort (function (a, b) { | 
|  | return a > b ? 1 : -1 | 
|  | }) | 
|  |  | 
|  | return cb (null, data) | 
|  | }) | 
|  | }) | 
|  | } | 
|  |  | 
|  | function readdirSync (dir) { | 
|  | var kids = fs . readdirSync (dir) | 
|  | debug ('dir=%j, kids=%j', dir, kids) | 
|  | var data =  readScopesSync (dir, kids) | 
|  | // Sort for bonus consistency points | 
|  | data = data . sort (function (a, b) { | 
|  | return a > b ? 1 : -1 | 
|  | }) | 
|  |  | 
|  | return data | 
|  | } | 
|  |  | 
|  | // Turn [ 'a', '@scope' ] into | 
|  | // ['a', '@scope/foo', '@scope/bar'] | 
|  | function readScopes (root, kids, cb) { | 
|  | var scopes = kids . filter (function (kid) { | 
|  | return kid . charAt (0) === '@' | 
|  | }) | 
|  |  | 
|  | kids = kids . filter (function (kid) { | 
|  | return kid . charAt (0) !== '@' | 
|  | }) | 
|  |  | 
|  | debug ('scopes=%j', scopes) | 
|  |  | 
|  | if (scopes . length === 0) | 
|  | dz (cb) (null, kids) // prevent maybe-sync zalgo release | 
|  |  | 
|  | cb = once (cb) | 
|  | var l = scopes . length | 
|  | scopes . forEach (function (scope) { | 
|  | var scopedir = path . resolve (root, scope) | 
|  | debug ('root=%j scope=%j scopedir=%j', root, scope, scopedir) | 
|  | fs . readdir (scopedir, then . bind (null, scope)) | 
|  | }) | 
|  |  | 
|  | function then (scope, er, scopekids) { | 
|  | if (er) | 
|  | return cb (er) | 
|  |  | 
|  | // XXX: Not sure how old this node bug is. Maybe superstition? | 
|  | scopekids = scopekids . filter (function (scopekid) { | 
|  | return !(scopekid === '.' || scopekid === '..' || !scopekid) | 
|  | }) | 
|  |  | 
|  | kids . push . apply (kids, scopekids . map (function (scopekid) { | 
|  | return scope + '/' + scopekid | 
|  | })) | 
|  |  | 
|  | debug ('scope=%j scopekids=%j kids=%j', scope, scopekids, kids) | 
|  |  | 
|  | if (--l === 0) | 
|  | cb (null, kids) | 
|  | } | 
|  | } | 
|  |  | 
|  | function readScopesSync (root, kids) { | 
|  | var scopes = kids . filter (function (kid) { | 
|  | return kid . charAt (0) === '@' | 
|  | }) | 
|  |  | 
|  | kids = kids . filter (function (kid) { | 
|  | return kid . charAt (0) !== '@' | 
|  | }) | 
|  |  | 
|  | debug ('scopes=%j', scopes) | 
|  |  | 
|  | if (scopes . length === 0) | 
|  | return kids | 
|  |  | 
|  | var l = scopes . length | 
|  | scopes . forEach (function (scope) { | 
|  | var scopedir = path . resolve (root, scope) | 
|  | debug ('root=%j scope=%j scopedir=%j', root, scope, scopedir) | 
|  | then (scope, fs . readdirSync (scopedir)) | 
|  | }) | 
|  |  | 
|  | function then (scope, scopekids) { | 
|  | // XXX: Not sure how old this node bug is. Maybe superstition? | 
|  | scopekids = scopekids . filter (function (scopekid) { | 
|  | return !(scopekid === '.' || scopekid === '..' || !scopekid) | 
|  | }) | 
|  |  | 
|  | kids . push . apply (kids, scopekids . map (function (scopekid) { | 
|  | return scope + '/' + scopekid | 
|  | })) | 
|  |  | 
|  | debug ('scope=%j scopekids=%j kids=%j', scope, scopekids, kids) | 
|  | } | 
|  |  | 
|  | return kids | 
|  | } |