1
1
'use strict' ;
2
2
3
- var fs = require ( 'fs' ) ,
4
- path = require ( 'path' ) ;
3
+ var fs = require ( 'fs' ) ,
4
+ path = require ( 'path' ) ,
5
+ defaults = require ( 'lodash.defaults' ) ;
5
6
6
- module . exports = {
7
- absolute : absolute ,
8
- base : base
9
- } ;
7
+ var PACKAGE_NAME = require ( '../package.json' ) . name ;
10
8
11
9
/**
12
- * Search for the relative file reference from the <code>startPath</code> up to the process
13
- * working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
14
- * @param {string } startPath The location of the uri declaration and the place to start the search from
15
- * @param {string } uri The content of the url() statement, expected to be a relative file path
16
- * @param {string } [limit] Optional directory to limit the search to
17
- * @returns {string|null } <code>null</code> where not found else the absolute path to the file
10
+ * Factory for find-file with the given <code>options</code> hash.
11
+ * @param {{debug: boolean} } [opt] Optional options hash
18
12
*/
19
- function absolute ( startPath , uri , limit ) {
20
- var basePath = base ( startPath , uri , limit ) ;
21
- return ! ! basePath && path . resolve ( basePath , uri ) || null ;
22
- }
13
+ function findFile ( opt ) {
14
+ var options = defaults ( opt , {
15
+ debug : false
16
+ } ) ;
17
+ return {
18
+ absolute : absolute ,
19
+ base : base
20
+ } ;
23
21
24
- /**
25
- * Search for the relative file reference from the <code>startPath</code> up to the process
26
- * working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
27
- * @param {string } startPath The location of the uri declaration and the place to start the search from
28
- * @param {string } uri The content of the url() statement, expected to be a relative file path
29
- * @param {string } [limit] Optional directory to limit the search to
30
- * @returns {string|null } <code>null</code> where not found else the base path upon which the uri may be resolved
31
- */
32
- function base ( startPath , uri , limit ) {
33
-
34
- // ensure we have some limit to the search
35
- limit = limit && path . resolve ( limit ) || process . cwd ( ) ;
36
-
37
- // ignore data uris and ensure we are at a valid start path
38
- var absoluteStart = ! ( / ^ d a t a \: / . test ( uri ) ) && path . resolve ( startPath ) ;
39
- if ( absoluteStart ) {
40
-
41
- // find path to the root, stopping at cwd, package.json or bower.json
42
- var pathToRoot = [ ] ;
43
- var isWorking ;
44
- do {
45
- pathToRoot . push ( absoluteStart ) ;
46
- isWorking = testWithinLimit ( absoluteStart ) && testNotPackage ( absoluteStart ) ;
47
- absoluteStart = path . resolve ( absoluteStart , '..' ) ;
48
- } while ( isWorking ) ;
49
-
50
- // start a queue with the path to the root
51
- var queue = pathToRoot . concat ( ) ;
52
-
53
- // process the queue until empty
54
- // the queue pattern ensures that we favour paths closest the the start path
55
- while ( queue . length ) {
56
-
57
- // shift the first item off the queue, consider it the base for our relative uri
58
- var basePath = queue . shift ( ) ;
59
- var fullPath = path . resolve ( basePath , uri ) ;
60
-
61
- // file exists so convert to a dataURI and end
62
- if ( fs . existsSync ( fullPath ) ) {
63
- return basePath ;
64
- }
65
- // enqueue subdirectories that are not packages and are not in the root path
66
- else {
67
- enqueue ( queue , basePath ) ;
68
- }
69
- }
22
+ /**
23
+ * Search for the relative file reference from the <code>startPath</code> up to the process
24
+ * working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
25
+ * @param {string } startPath The location of the uri declaration and the place to start the search from
26
+ * @param {string } uri The content of the url() statement, expected to be a relative file path
27
+ * @param {string } [limit] Optional directory to limit the search to
28
+ * @returns {string|null } <code>null</code> where not found else the absolute path to the file
29
+ */
30
+ function absolute ( startPath , uri , limit ) {
31
+ var basePath = base ( startPath , uri , limit ) ;
32
+ return ! ! basePath && path . resolve ( basePath , uri ) || null ;
70
33
}
71
34
72
- // ignored or not found
73
- return null ;
74
-
75
35
/**
76
- * Enqueue subdirectories that are not packages and are not in the root path
77
- * @param {Array } queue The queue to add to
78
- * @param {string } basePath The path to consider
36
+ * Search for the relative file reference from the <code>startPath</code> up to the process
37
+ * working directory, avoiding any other directories with a <code>package.json</code> or <code>bower.json</code>.
38
+ * @param {string } startPath The location of the uri declaration and the place to start the search from
39
+ * @param {string } uri The content of the url() statement, expected to be a relative file path
40
+ * @param {string } [limit] Optional directory to limit the search to
41
+ * @returns {string|null } <code>null</code> where not found else the base path upon which the uri may be resolved
79
42
*/
80
- function enqueue ( queue , basePath ) {
81
- fs . readdirSync ( basePath )
82
- . filter ( function notHidden ( filename ) {
83
- return ( filename . charAt ( 0 ) !== '.' ) ;
84
- } )
85
- . map ( function toAbsolute ( filename ) {
86
- return path . join ( basePath , filename ) ;
87
- } )
88
- . filter ( function directoriesOnly ( absolutePath ) {
89
- return fs . existsSync ( absolutePath ) && fs . statSync ( absolutePath ) . isDirectory ( ) ;
90
- } )
91
- . filter ( function notInRootPath ( absolutePath ) {
92
- return ( pathToRoot . indexOf ( absolutePath ) < 0 ) ;
93
- } )
94
- . filter ( testNotPackage )
95
- . forEach ( function enqueue ( absolutePath ) {
96
- queue . push ( absolutePath ) ;
97
- } ) ;
43
+ function base ( startPath , uri , limit ) {
44
+ var messages = [ ] ;
45
+
46
+ // ensure we have some limit to the search
47
+ limit = limit && path . resolve ( limit ) || process . cwd ( ) ;
48
+
49
+ // ignore data uris and ensure we are at a valid start path
50
+ var absoluteStart = ! ( / ^ d a t a \: / . test ( uri ) ) && path . resolve ( startPath ) ;
51
+ if ( absoluteStart ) {
52
+
53
+ // find path to the root, stopping at cwd, package.json or bower.json
54
+ var pathToRoot = [ ] ;
55
+ var isWorking ;
56
+ do {
57
+ pathToRoot . push ( absoluteStart ) ;
58
+ isWorking = testWithinLimit ( absoluteStart ) && testNotPackage ( absoluteStart ) ;
59
+ absoluteStart = path . resolve ( absoluteStart , '..' ) ;
60
+ } while ( isWorking ) ;
61
+
62
+ // start a queue with the path to the root
63
+ var queue = pathToRoot . concat ( ) ;
64
+
65
+ // process the queue until empty
66
+ // the queue pattern ensures that we favour paths closest the the start path
67
+ while ( queue . length ) {
68
+
69
+ // shift the first item off the queue, consider it the base for our relative uri
70
+ var basePath = queue . shift ( ) ;
71
+ var fullPath = path . resolve ( basePath , uri ) ;
72
+ messages . push ( basePath ) ;
73
+
74
+ // file exists so convert to a dataURI and end
75
+ if ( fs . existsSync ( fullPath ) ) {
76
+ flushMessages ( 'FOUND' ) ;
77
+ return basePath ;
78
+ }
79
+ // enqueue subdirectories that are not packages and are not in the root path
80
+ else {
81
+ enqueue ( queue , basePath ) ;
82
+ }
83
+ }
84
+
85
+ // not found
86
+ flushMessages ( 'NOT FOUND' ) ;
87
+ return null ;
88
+ }
89
+ // ignored
90
+ else {
91
+ flushMessages ( 'IGNORED' ) ;
92
+ return null ;
93
+ }
94
+
95
+ /**
96
+ * Enqueue subdirectories that are not packages and are not in the root path
97
+ * @param {Array } queue The queue to add to
98
+ * @param {string } basePath The path to consider
99
+ */
100
+ function enqueue ( queue , basePath ) {
101
+ fs . readdirSync ( basePath )
102
+ . filter ( function notHidden ( filename ) {
103
+ return ( filename . charAt ( 0 ) !== '.' ) ;
104
+ } )
105
+ . map ( function toAbsolute ( filename ) {
106
+ return path . join ( basePath , filename ) ;
107
+ } )
108
+ . filter ( function directoriesOnly ( absolutePath ) {
109
+ return fs . existsSync ( absolutePath ) && fs . statSync ( absolutePath ) . isDirectory ( ) ;
110
+ } )
111
+ . filter ( function notInRootPath ( absolutePath ) {
112
+ return ( pathToRoot . indexOf ( absolutePath ) < 0 ) ;
113
+ } )
114
+ . filter ( testNotPackage )
115
+ . forEach ( function enqueue ( absolutePath ) {
116
+ queue . push ( absolutePath ) ;
117
+ } ) ;
118
+ }
119
+
120
+ /**
121
+ * Test whether the given directory is above but not equal to any of the project root directories.
122
+ * @param {string } absolutePath An absolute path
123
+ * @returns {boolean } True where a package.json or bower.json exists, else False
124
+ */
125
+ function testWithinLimit ( absolutePath ) {
126
+ var relative = path . relative ( limit , absolutePath ) ;
127
+ return ! ! relative && ( relative . slice ( 0 , 2 ) !== '..' ) ;
128
+ }
129
+
130
+ /**
131
+ * Print verbose debug info where <code>options.debug</code> is in effect.
132
+ * @param {string } result Final text to append to the message
133
+ */
134
+ function flushMessages ( result ) {
135
+ if ( options . debug ) {
136
+ var text = [ '\n' + PACKAGE_NAME + ': ' + uri ]
137
+ . concat ( messages )
138
+ . concat ( result )
139
+ . join ( '\n ' ) ;
140
+ console . log ( text ) ;
141
+ }
142
+ }
98
143
}
99
144
100
145
/**
101
- * Test whether the given directory is above but not equal to any of the project root directories .
146
+ * Test whether the given directory is the root of its own package .
102
147
* @param {string } absolutePath An absolute path
103
148
* @returns {boolean } True where a package.json or bower.json exists, else False
104
149
*/
105
- function testWithinLimit ( absolutePath ) {
106
- var relative = path . relative ( limit , absolutePath ) ;
107
- return ! ! relative && ( relative . slice ( 0 , 2 ) !== '..' ) ;
150
+ function testNotPackage ( absolutePath ) {
151
+ return [ 'package.json' , 'bower.json' ] . every ( function fileFound ( file ) {
152
+ return ! fs . existsSync ( path . resolve ( absolutePath , file ) ) ;
153
+ } ) ;
108
154
}
109
155
}
110
156
111
- /**
112
- * Test whether the given directory is the root of its own package.
113
- * @param {string } absolutePath An absolute path
114
- * @returns {boolean } True where a package.json or bower.json exists, else False
115
- */
116
- function testNotPackage ( absolutePath ) {
117
- return [ 'package.json' , 'bower.json' ] . every ( function fileFound ( file ) {
118
- return ! fs . existsSync ( path . resolve ( absolutePath , file ) ) ;
119
- } ) ;
120
- }
157
+ module . exports = findFile ;
0 commit comments