11var path = require ( 'path' ) ,
22 fs = require ( './fs' ) ,
3- PromiseConstructor ,
3+ PromiseConstructor = typeof Promise === 'undefined' ? require ( 'promise' ) : Promise ,
44 AbstractFileManager = require ( "../less/environment/abstract-file-manager.js" ) ;
55
6- try {
7- PromiseConstructor = typeof Promise === 'undefined' ? require ( 'promise' ) : Promise ;
8- } catch ( e ) {
9- }
10-
116var FileManager = function ( ) {
7+ this . files = { } ;
128} ;
139
1410FileManager . prototype = new AbstractFileManager ( ) ;
@@ -20,46 +16,85 @@ FileManager.prototype.supportsSync = function(filename, currentDirectory, option
2016 return true ;
2117} ;
2218
23- FileManager . prototype . loadFile = function ( filename , currentDirectory , options , environment , callback ) {
19+ FileManager . prototype . loadFile = function ( filename , currentDirectory , options , environment ) {
20+
21+ // TODO refactor so isn't cut and paste between loadFileSync
2422 var fullFilename ,
2523 data ,
2624 isAbsoluteFilename = this . isPathAbsolute ( filename ) ,
27- filenamesTried = [ ] ;
25+ filenamesTried = [ ] ,
26+ self = this ,
27+ prefix = filename . slice ( 0 , 1 ) ,
28+ explicit = prefix === "." || prefix === "/" ;
2829
2930 options = options || { } ;
3031
31- if ( options . syncImport || ! PromiseConstructor ) {
32- data = this . loadFileSync ( filename , currentDirectory , options , environment , 'utf-8' ) ;
33- callback ( data . error , data ) ;
34- return ;
35- }
32+ var paths = isAbsoluteFilename ? [ '' ] : [ currentDirectory ] ;
3633
37- var paths = isAbsoluteFilename ? [ "" ] : [ currentDirectory ] ;
3834 if ( options . paths ) { paths . push . apply ( paths , options . paths ) ; }
35+
36+ // Search node_modules
37+ if ( ! explicit ) { paths . push . apply ( paths , this . modulePaths ) ; }
38+
3939 if ( ! isAbsoluteFilename && paths . indexOf ( '.' ) === - 1 ) { paths . push ( '.' ) ; }
4040
41+ var prefixes = options . prefixes || [ '' ] ;
42+ var fileParts = this . extractUrlParts ( filename ) ;
43+
4144 // promise is guaranteed to be asyncronous
4245 // which helps as it allows the file handle
4346 // to be closed before it continues with the next file
4447 return new PromiseConstructor ( function ( fulfill , reject ) {
48+ if ( options . syncImport ) {
49+ data = this . loadFileSync ( filename , currentDirectory , options , environment , 'utf-8' ) ;
50+ if ( data . error ) {
51+ reject ( data . error ) ;
52+ }
53+ else {
54+ fulfill ( data ) ;
55+ }
56+ return ;
57+ }
4558 ( function tryPathIndex ( i ) {
4659 if ( i < paths . length ) {
47- fullFilename = filename ;
48- if ( paths [ i ] ) {
49- fullFilename = path . join ( paths [ i ] , fullFilename ) ;
50- }
51- fs . stat ( fullFilename , function ( err ) {
52- if ( err ) {
53- filenamesTried . push ( fullFilename ) ;
54- tryPathIndex ( i + 1 ) ;
55- } else {
56- fs . readFile ( fullFilename , 'utf-8' , function ( e , data ) {
57- if ( e ) { reject ( e ) ; return ; }
60+ ( function tryPrefix ( j ) {
61+ if ( j < prefixes . length ) {
62+
63+ fullFilename = fileParts . rawPath + prefixes [ j ] + fileParts . filename ;
64+
65+ if ( paths [ i ] ) {
66+ fullFilename = path . join ( paths [ i ] , fullFilename ) ;
67+ }
68+ if ( paths [ i ] . indexOf ( 'node_modules' ) > - 1 ) {
69+ try {
70+ fullFilename = require . resolve ( fullFilename ) ;
71+ }
72+ catch ( e ) { }
73+ }
74+ else {
75+ fullFilename = options . ext ? self . tryAppendExtension ( fullFilename , options . ext ) : fullFilename ;
76+ }
77+
78+ if ( self . files [ fullFilename ] ) {
79+ fulfill ( { contents : self . files [ fullFilename ] , filename : fullFilename } ) ;
80+ }
81+ else {
82+
83+ fs . readFile ( fullFilename , 'utf-8' , function ( e , data ) {
84+ if ( e ) {
85+ filenamesTried . push ( fullFilename ) ;
86+ return tryPrefix ( j + 1 ) ;
87+ }
88+ self . files [ fullFilename ] = data ;
89+ fulfill ( { contents : data , filename : fullFilename } ) ;
90+ } ) ;
91+ }
5892
59- fulfill ( { contents : data , filename : fullFilename } ) ;
60- } ) ;
6193 }
62- } ) ;
94+ else {
95+ tryPathIndex ( i + 1 ) ;
96+ }
97+ } ) ( 0 ) ;
6398 } else {
6499 reject ( { type : 'File' , message : "'" + filename + "' wasn't found. Tried - " + filenamesTried . join ( "," ) } ) ;
65100 }
@@ -79,26 +114,39 @@ FileManager.prototype.loadFileSync = function(filename, currentDirectory, option
79114 paths . push ( '.' ) ;
80115 }
81116
82- var err , result ;
117+ var prefixes = options . prefixes || [ '' ] ;
118+ var fileParts = this . extractUrlParts ( filename ) ;
119+
120+ var err , result , breakAll = false ;
83121 for ( var i = 0 ; i < paths . length ; i ++ ) {
84- try {
85- fullFilename = filename ;
86- if ( paths [ i ] ) {
87- fullFilename = path . join ( paths [ i ] , fullFilename ) ;
122+ for ( var j = 0 ; j < prefixes . length ; j ++ ) {
123+ try {
124+ fullFilename = fileParts . rawPath + prefixes [ j ] + fileParts . filename ;
125+ if ( paths [ i ] ) {
126+ fullFilename = path . join ( paths [ i ] , fullFilename ) ;
127+ }
128+ filenamesTried . push ( fullFilename ) ;
129+ fs . statSync ( fullFilename ) ;
130+ breakAll = true ;
131+ break ;
132+ } catch ( e ) {
133+ fullFilename = null ;
88134 }
89- filenamesTried . push ( fullFilename ) ;
90- fs . statSync ( fullFilename ) ;
91- break ;
92- } catch ( e ) {
93- fullFilename = null ;
94135 }
136+ if ( breakAll ) { break ; }
95137 }
96138
97139 if ( ! fullFilename ) {
98140 err = { type : 'File' , message : "'" + filename + "' wasn't found. Tried - " + filenamesTried . join ( "," ) } ;
99141 result = { error : err } ;
100142 } else {
101- data = fs . readFileSync ( fullFilename , encoding ) ;
143+ if ( this . files [ fullFilename ] ) {
144+ data = this . files [ fullFilename ] ;
145+ }
146+ else {
147+ data = fs . readFileSync ( fullFilename , encoding ) ;
148+ this . files [ fullFilename ] = data ;
149+ }
102150 result = { contents : data , filename : fullFilename } ;
103151 }
104152
0 commit comments