UNPKG

3.91 kBJavaScriptView Raw
1'use strict';
2
3var findex = require('findex')
4 , fs = require('fs')
5 , path = require('path')
6 , log = require('./log')
7 , packDox = require('./dox/pack')
8 , requireLike = require('require-like')
9 , findParentDir = require('find-parent-dir')
10 , xtend = require('util')._extend
11 , colors = require('ansicolors')
12 , wire = require('./wire')
13 , indexedDirs = {}
14 , indexes = {}
15
16function indexDirectory(dir, dirFilter, cb) {
17 if (indexedDirs[dir]) return;
18 indexedDirs[dir] = true;
19
20 findex.fork({ root: dir, directoryFilter: dirFilter, debug: false }, function (err, indexes_) {
21 if (err) {
22 log.error(err);
23 cb();
24 }
25
26 indexedDirs = indexes_.indexedDirs
27 .reduce(function (acc, x) {
28 acc[x] = true;
29 return acc;
30 }, indexedDirs);
31
32 indexes = xtend(indexes, indexes_);
33 indexes.find = findex.find.bind(indexes);
34
35 cb();
36 });
37}
38
39// on first the first run we don't want to include the module's dependencies
40var firstFilter = [ '!.git', '!.svn', '!test', '!tests', '!node_modules' ];
41
42// on the second run we start inside the package's node_modules dir and will include all node_modules below as well
43var secondFilter = firstFilter.slice(0, -1);
44
45/**
46 * Returns custom require which does the following:
47 * - adjusts require to work relative to the given requirePath
48 * - ensures that required modules are never cached in order to pick up changes made to the required module (if uncached is set)
49 * - indexes all functions of the required module first and of all its dependencies second
50 * - the indexing step is performed on a forked process in order to not interfer with the main process, the repl itself
51 *
52 * @name exports
53 * @function
54 * @param requirePath {String} the path to which the require should be relative (i.e. the file from which the require is called)
55 * @param uncached {Boolean} if true the module cache will be cleared before each require
56 * @return {Function} adjusted require that behaves and has side effects as explained
57 */
58var go = module.exports = function (requirePath, uncached) {
59 var reqlike = requireLike(requirePath, uncached);
60
61 function wrap (request) {
62 var mdl = reqlike(request);
63 var from = reqlike.resolve(request);
64 var fromdir = path.dirname(from);
65
66 findParentDir(from, 'package.json', function (err, packagedir) {
67 if (err) return log.error(err);
68
69 // now we now the packagedir and can attach dox that print readme
70 packDox(mdl, request, packagedir);
71
72 // first indexing run only handles functions of the required module itself
73 indexDirectory(fromdir, firstFilter, function () {
74 log.sillyln('updated', fromdir);
75 wire.emit('findex-first-pass', requirePath);
76
77 // now lets take care of all functions found in the dependencies of the module
78 var dependencies = path.join(fromdir, 'node_modules');
79 fs.exists(dependencies, function (exists) {
80 if (!exists) return;
81 indexDirectory(dependencies, secondFilter, function () {
82 wire.emit('findex-second-pass', requirePath);
83 log.sillyln('updated %s dependencies', fromdir);
84 });
85 });
86 });
87
88 });
89
90 return mdl;
91 }
92 wrap.resolve = reqlike.resolve.bind(reqlike);
93 return wrap;
94}
95
96// TODO: the approach may not be ideal because:
97// - npm places common dependencies in a sibling directory instead of nested (especially when npm dedupe is used)
98// - therefore we may not find those when indexing contained node_modules
99// - two alternatives:
100// 1. require everything that is a dir level above (excluding node_modules)
101// 2. look for dependencies in package.json, require.resolve them and index the containing directory
102
103go.find = function (fn) { return indexes.find ? indexes.find(fn) : []; };
104go.indexes = indexes;