@@ -10,27 +10,136 @@ var combined = require('combined-stream'),
1010 path = require ( 'path' ) ,
1111 fs = require ( 'fs' ) ;
1212
13+ /**
14+ * @param {string|RegExp } pattern Matches the extension of bower files
15+ * @param {object? } options Options for <code>gulp.src()</code> stream
16+ */
17+ module . exports = function src ( pattern , options ) {
18+ options = options || { } ;
19+
20+ // create result list
21+ // the parsed content will be sorted by extension
22+ var parsed = json ( options . dev ) ,
23+ manifestFile = ! ! options . manifest && manifest ( options . manifest === 'comment' , options . dev ) ,
24+ bowerPackages = [ ] ;
25+ for ( var packageName in parsed ) {
26+ var config = parsed [ packageName ] ,
27+ list = [ ]
28+ . concat ( config . main )
29+ . filter ( Boolean )
30+ . map ( toAbsoluteForPackage ( packageName ) )
31+ . filter ( testExtension ) ;
32+ if ( list . length ) {
33+ var base = list . reduce ( greatestCommonBase , null ) ;
34+ bowerPackages . push ( {
35+ name : packageName ,
36+ options : defaults ( { base : base || options . base } , options ) , // use our base over that given
37+ list : list
38+ } ) ;
39+ }
40+ }
41+
42+ // represent list as a readable stream, even if empty
43+ var stream ;
44+
45+ // degenerate stream
46+ if ( ! bowerPackages . length ) {
47+ stream = spigot ( { objectMode : true } , [ ] ) ;
48+ stream . _read = function ( ) {
49+ } ;
50+ stream . push ( null ) ;
51+ }
52+ // combination of source streams with specific base path for each package
53+ else {
54+ stream = combined . create ( ) ;
55+ if ( manifestFile ) {
56+ stream . append ( manifestFile ) ;
57+ }
58+ bowerPackages . reduce ( eachPackage , stream ) ;
59+ }
60+
61+ // add the list to the stream as a sidecar
62+ stream . list = flatten ( bowerPackages ) ;
63+
64+ // complete
65+ return stream ;
66+
67+ function greatestCommonBase ( candidate , absolute ) {
68+ if ( candidate ) {
69+ var i = 0 ;
70+ while ( candidate [ i ] === absolute [ i ] ) {
71+ i ++ ;
72+ }
73+ return candidate . slice ( 0 , i ) ;
74+ } else if ( options . base === true ) {
75+ return path . dirname ( absolute ) ;
76+ } else {
77+ return null ;
78+ }
79+ }
80+
81+ function eachPackage ( stream , bowerPackage ) {
82+ return stream . append (
83+ gulp . src ( bowerPackage . list , bowerPackage . options )
84+ . pipe ( through . obj ( transform ) )
85+ ) ;
86+
87+ function transform ( file , encoding , done ) {
88+ /* jshint validthis:true */
89+ if ( ( options . base === true ) && ( bowerPackage . name ) ) {
90+ file . path = path . join ( file . base , bowerPackage . name , file . relative ) ;
91+ }
92+ this . push ( file ) ;
93+ done ( ) ;
94+ }
95+ }
96+
97+ function testExtension ( filename ) {
98+ var ext = path . extname ( filename ) . slice ( 1 ) ;
99+ return (
100+ ( ( typeof pattern === 'string' ) && ( pattern . split ( '|' ) . indexOf ( ext ) >= 0 ) ) ||
101+ ( ( typeof pattern === 'object' ) && ( 'test' in pattern ) && pattern . test ( ext ) ) ||
102+ ( pattern === '*' )
103+ ) ;
104+ }
105+ } ;
106+
107+ function toAbsoluteForPackage ( packageName ) {
108+ return function toAbsolute ( relative ) {
109+ return path . resolve ( path . join ( 'bower_components' , packageName , '' ) , relative ) ;
110+ } ;
111+ }
112+
13113/**
14114 * Retrieve version details of bower files as a stream
15115 * @param {boolean } useComment Determines whether the output is wrapped in a comment
16116 * @param {boolean } includeDev Determines whether dev dependencies are included
17117 * @returns {stream.Readable } A readable stream containing only the manifest file
18118 */
19119function json ( includeDev ) {
120+ return processBowerJson ( read ( 'bower.json' ) , includeDev ) ;
121+
20122 function read ( filename ) {
21123 try {
22124 return fs . existsSync ( filename ) && require ( path . resolve ( filename ) ) ;
23- } catch ( error ) {
125+ } catch ( error ) {
24126 gutil . log ( 'Error parsing bower.json at ' + filename ) ;
25127 }
26128 }
27- var bower = read ( 'bower.json' ) ;
28- var deps = bower ? defaults ( bower . dependencies , ( includeDev && bower . devDependencies ) ) : { } ;
29- var result = { } ;
30- for ( var key in deps ) {
31- result [ key ] = read ( path . join ( 'bower_components' , key , 'bower.json' ) ) ;
129+
130+ function processBowerJson ( json , includeDev ) {
131+ var isValid = ( json && ( typeof json === 'object' ) ) ,
132+ dependencies = isValid && defaults ( json . dependencies , includeDev && json . devDependencies ) || { } ;
133+ return Object . keys ( dependencies )
134+ . reduce ( reduceDeps , { } ) ;
135+ }
136+
137+ function reduceDeps ( result , key ) {
138+ var contents = read ( path . join ( 'bower_components' , key , 'bower.json' ) ) ;
139+ defaults ( result , processBowerJson ( contents , false ) ) ; // current items' dependencies precede the current item
140+ result [ key ] = contents ;
141+ return result ;
32142 }
33- return result ;
34143}
35144
36145/**
@@ -40,147 +149,20 @@ function json(includeDev) {
40149 * @returns {stream.Readable } A readable stream containing only the manifest file
41150 */
42151function manifest ( useComment , includeDev ) {
43- var bower = json ( includeDev ) ;
44- var versions = { } ;
152+ var bower = json ( includeDev ) ,
153+ versions = { } ;
45154 for ( var key in bower ) {
46155 versions [ key ] = bower [ key ] . version ;
47156 }
48- var text = JSON . stringify ( versions , null , 2 ) ;
49- var commented = ( useComment ) ? [ '/*' , text , '*/' ] . join ( '\n' ) : text ;
50- var cwd = process . cwd ( ) ;
51- return spigot ( { objectMode : true } , [
157+ var text = JSON . stringify ( versions , null , 2 ) ,
158+ commented = ( useComment ) ? [ '/*' , text , '*/' ] . join ( '\n' ) : text ,
159+ cwd = process . cwd ( ) ;
160+ return spigot ( { objectMode : true } , [
52161 new gutil . File ( {
53- cwd : cwd ,
54- base : cwd ,
55- path : path . join ( cwd , 'manifest.json' ) ,
162+ cwd : cwd ,
163+ base : cwd ,
164+ path : path . join ( cwd , 'manifest.json' ) ,
56165 contents : new Buffer ( commented )
57166 } )
58167 ] ) ;
59- }
60-
61- module . exports = function ( ) {
62- var before = [ ] ;
63- var after = [ ] ;
64-
65- /**
66- * @param {string|RegExp } pattern Matches the extension of bower files
67- * @param {object? } options Options for <code>gulp.src()</code> stream
68- */
69- function src ( pattern , options ) {
70- options = options || { } ;
71-
72- function testExtension ( filename ) {
73- var ext = path . extname ( filename ) . slice ( 1 ) ;
74- return (
75- ( ( typeof pattern === 'string' ) && ( pattern . split ( '|' ) . indexOf ( ext ) >= 0 ) ) ||
76- ( ( typeof pattern === 'object' ) && ( 'test' in pattern ) && pattern . test ( ext ) ) ||
77- ( pattern === '*' )
78- ) ;
79- }
80-
81- function toAbsolute ( relative ) {
82- return path . resolve ( path . join ( 'bower_components' , packageName , '' ) , relative ) ;
83- }
84-
85- function greatestCommonBase ( absolute ) {
86- if ( base ) {
87- var i = 0 ;
88- while ( base [ i ] === absolute [ i ] ) {
89- i ++ ;
90- }
91- base = base . slice ( 0 , i ) ;
92- } else if ( options . base === true ) {
93- base = path . dirname ( absolute ) ;
94- }
95- }
96-
97- // create result list
98- // the parsed content will be sorted by extension
99- var parsed = json ( options . dev ) ;
100- var bowerPackages = [ ] ;
101- for ( var packageName in parsed ) {
102- var config = parsed [ packageName ] ;
103- var bowerPackage = [ ]
104- . concat ( config . main )
105- . filter ( Boolean )
106- . map ( toAbsolute )
107- . filter ( testExtension ) ;
108- if ( bowerPackage . length ) {
109- var base = null ;
110- bowerPackage . forEach ( greatestCommonBase ) ;
111- bowerPackage . options = defaults ( { base : base || options . base } , options ) ; // use our base over that given
112- bowerPackage . name = packageName ;
113- bowerPackages . push ( bowerPackage ) ;
114- }
115- }
116- var value = before . concat ( bowerPackages ) . concat ( after ) ;
117- var prepend = options . manifest && manifest ( options . manifest === 'comment' , options . dev ) ;
118-
119- // represent list as a readable stream
120- var stream ;
121- if ( ! value . length ) {
122-
123- // degenerate stream
124- stream = spigot ( { objectMode : true } , [ ] ) ;
125- stream . _read = function ( ) { } ;
126- stream . push ( null ) ;
127-
128- } else {
129-
130- // combination of source streams with specific base path for each package
131- stream = combined . create ( ) ;
132- if ( prepend ) {
133- stream . append ( prepend ) ;
134- }
135- value . forEach ( function ( bowerPackage ) {
136- var src = gulp . src ( bowerPackage . concat ( ) , bowerPackage . options )
137- . pipe ( through . obj ( function ( file , encoding , done ) {
138- if ( ( options . base === true ) && ( bowerPackage . name ) ) {
139- file . path = path . join ( file . base , bowerPackage . name , file . relative ) ;
140- }
141- this . push ( file ) ;
142- done ( ) ;
143- } ) ) ;
144- stream . append ( src ) ;
145- } ) ;
146- }
147-
148- // add the list to the stream as a sidecar
149- stream . list = flatten ( value ) ;
150-
151- // complete
152- return stream ;
153- }
154-
155- function add ( array ) {
156- return function ( ) {
157- Array . prototype . slice . call ( arguments ) . forEach ( function ( arg ) {
158- if ( ( typeof arg === 'string' ) && fs . existsSync ( arg ) ) {
159- array . push ( arg ) ;
160- }
161- } ) ;
162- return self ;
163- } ;
164- }
165-
166- // complete
167- var self = {
168-
169- /**
170- * Append any number of additional file paths to be used in any file lists that follow
171- */
172- prepend : add ( before ) ,
173-
174- /**
175- * Append any number of additional file paths to be used in any file lists that follow
176- */
177- append : add ( after ) ,
178-
179- /**
180- * Retrieve all or some bower files as listed in the package <code>main</code> parameter
181- * @param {object } Options for the stream
182- */
183- src : src
184- } ;
185- return self ;
186- } ;
168+ }
0 commit comments