Skip to content

Commit 232beb9

Browse files
author
benholloway
committed
fixed bower not including/injecting nested dependencies
1 parent ff46296 commit 232beb9

File tree

4 files changed

+151
-167
lines changed

4 files changed

+151
-167
lines changed

lib/config/streams.js

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -46,8 +46,7 @@ function htmlApp(opts) {
4646
}
4747

4848
function testDependencies(opts) {
49-
return bowerFiles(80)
50-
.src('js', opts);
49+
return bowerFiles('js', opts);
5150
}
5251

5352
module.exports = {

lib/inject/bower-files.js

Lines changed: 126 additions & 144 deletions
Original file line numberDiff line numberDiff line change
@@ -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
*/
19119
function 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
*/
42151
function 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+
}

tasks/html.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ function setUpTaskHtml(context) {
5151
.pipe(injectAdjacent('js|css', {
5252
name: 'inject'
5353
}))
54-
.pipe(inject(bowerFiles().src('js|css', {read: false}), {
54+
.pipe(inject(bowerFiles('js|css', {read: false}), {
5555
name: 'bower'
5656
}))
5757
.pipe(gulp.dest(streams.BUILD));

0 commit comments

Comments
 (0)