1
1
import fs from "mz/fs"
2
+ import fmt from "./fmt"
2
3
import glob from "glob"
4
+ import pretty from "prettyjson"
3
5
import chokidar from "chokidar"
4
6
import { join } from "path"
5
7
import { jsVariants } from "interpret"
@@ -15,6 +17,17 @@ export function error (...args) {
15
17
console . error . apply ( console , args )
16
18
}
17
19
20
+ /**
21
+ */
22
+ export function trace ( e ) {
23
+ error ( pretty . render ( e )
24
+ . replace ( / ( \s F u n c t i o n | \s O b j e c t ) \. / g, `${ fmt . blue ( "$1" ) } .` )
25
+ . replace ( / \( ( ~ ? \/ .* ) \) / g, `(${ fmt . gray ( "$1" ) } )` )
26
+ . replace ( / : ( [ 0 - 9 ] * ) : ( [ 0 - 9 ] * ) / g, ` ${ fmt . yellow ( "$1" ) } :${ fmt . yellow ( "$2" ) } ` )
27
+ . replace ( new RegExp ( process . env . HOME , "g" ) , "~" )
28
+ )
29
+ }
30
+
18
31
/**
19
32
Promisify an async function.
20
33
@param {Function } async function to promisify
@@ -27,18 +40,67 @@ export function defer (asyncFunc) {
27
40
}
28
41
29
42
/**
30
- Resolve the Flyfile path. Check the file extension for JavaScript variants.
43
+ Resolve the Flyfile path. Check the file extension and attempt to load
44
+ every possible JavaScript variant if `file` is a directory.
31
45
@param {String } file or path to the Flyfile
32
46
@param [{String}] Flyfile variant name
33
47
@return {String } path to the Flyfile
34
48
*/
35
- export function * resolve ( { file, name = "Flyfile" } ) {
49
+ export function * find ( { file, names = [ "Flyfile" , "Flypath" ] } ) {
36
50
const root = join ( process . cwd ( ) , file )
37
- const path = ( yield fs . stat ( file ) ) . isDirectory ( ) ? join ( root , name ) : root
38
- const mod = jsVariants [ `.${ path . split ( "." ) . slice ( 1 ) . join ( "." ) || "js" } ` ]
39
- if ( Array . isArray ( mod ) ) require ( mod [ 0 ] )
40
- else if ( mod ) require ( mod . module )
41
- return path
51
+ return hook ( require , ( yield fs . stat ( file ) ) . isDirectory ( )
52
+ ? yield resolve ( match (
53
+ names . concat ( names . map ( ( name ) => name . toLowerCase ( ) ) )
54
+ . map ( ( name ) => join ( root , name ) ) ,
55
+ Object . keys ( jsVariants )
56
+ ) )
57
+ : root )
58
+
59
+ /**
60
+ Add require hook so that subsequent calls to require transform the
61
+ JavaScript source variant (ES7, CoffeeScript, etc.) in the fly.
62
+ @param {Function } require function to load selected module
63
+ @param {String } path to Flyfile
64
+ @return {String } path to Flyfile
65
+ @private
66
+ */
67
+ function hook ( require , path ) {
68
+ const js = jsVariants [ `.${ path . split ( "." ) . slice ( 1 ) . join ( "." ) || "js" } ` ]
69
+ if ( Array . isArray ( js ) ) {
70
+ ( function reduce ( modules ) {
71
+ if ( modules . length === 0 ) return
72
+ try { require ( modules [ 0 ] . module ) }
73
+ catch ( _ ) { reduce ( modules . slice ( 1 ) ) }
74
+ } ( js ) )
75
+ } else if ( js ) require ( js . module )
76
+ return path
77
+ }
78
+
79
+ /**
80
+ Resolve to the first existing file in paths.
81
+ @param {Array:String } list of paths to search
82
+ @return {String } path of an existing file
83
+ @private
84
+ */
85
+ function * resolve ( paths ) {
86
+ if ( paths . length === 0 ) throw { code : "ENOENT" }
87
+ try {
88
+ if ( yield fs . stat ( paths [ 0 ] ) ) return paths [ 0 ]
89
+ } catch ( e ) { return yield resolve ( paths . slice ( 1 ) ) }
90
+ }
91
+
92
+ /**
93
+ Match files and extensions.
94
+ @param {Array:String } List of files to match
95
+ @param {Array:String } List of extensions to match
96
+ @return {Array } Product of matched files * extensions
97
+ @private
98
+ */
99
+ function match ( files , exts ) {
100
+ return files . length === 1
101
+ ? exts . map ( ( ext ) => `${ files [ 0 ] } ${ ext } ` )
102
+ : match ( [ files [ 0 ] ] , exts ) . concat ( match ( files . slice ( 1 ) , exts ) )
103
+ }
42
104
}
43
105
44
106
/**
@@ -76,21 +138,29 @@ export function expand (pattern, handler) {
76
138
} )
77
139
}
78
140
141
+ /**
142
+ Flattens a nested array recursively.
143
+ @return [[a],[b],[c]] -> [a,b,c]
144
+ */
145
+ export function flatten ( array ) {
146
+ return array . reduce ( ( flat , next ) =>
147
+ flat . concat ( Array . isArray ( next ) ? flatten ( next ) : next ) , [ ] )
148
+ }
149
+
79
150
/**
80
151
Wrapper for chokidar.watch. Array of globs are flattened.
81
152
@param {Array:String } globs
82
153
@param {...String } tasks Tasks to run
83
154
@return {chokidar.FSWatcher }
84
155
*/
85
156
export function watch ( globs , opts ) {
86
- return chokidar . watch (
87
- ( function flatten ( array ) {
88
- return array . reduce ( ( flat , next ) =>
89
- flat . concat ( Array . isArray ( next ) ? flatten ( next ) : next ) , [ ] )
90
- } ( [ globs ] ) ) , opts )
157
+ return chokidar . watch ( flatten ( [ globs ] ) , opts )
91
158
}
92
159
93
- /** Wrapper for update-notifier */
160
+ /**
161
+ Wrapper for update-notifier.
162
+ @param {Array } options
163
+ */
94
164
export function notifyUpdates ( options ) {
95
165
updateNotifier ( options ) . notify ( )
96
166
}
0 commit comments