Skip to content

Commit 2a3291c

Browse files
committed
Merge pull request #62 from angularity/feature/bower-overrides
feature/bower overrides, bugfix/nested-dependencies
2 parents 7225f38 + 16f533a commit 2a3291c

File tree

6 files changed

+216
-207
lines changed

6 files changed

+216
-207
lines changed

lib/build/browserify.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -341,10 +341,10 @@ function printMessages(messages) {
341341
if (messages.length > 0) {
342342

343343
// push the buffer to stdout in a single block
344-
var width = Number(80) || 0;
345-
var hr = new Array(width + 1); // this is a good trick to repeat a character N times
346-
var start = (width > 0) ? (hr.join('\u25BC') + '\n') : '';
347-
var stop = (width > 0) ? (hr.join('\u25B2') + '\n') : '';
344+
var WIDTH = 80;
345+
var hr = new Array(WIDTH + 1); // this is a good trick to repeat a character N times
346+
var start = (WIDTH > 0) ? (hr.join('\u25BC') + '\n') : '';
347+
var stop = (WIDTH > 0) ? (hr.join('\u25B2') + '\n') : '';
348348
var message = messages
349349
.map(groupByFilename)
350350
.join('');

lib/config/streams.js

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
'use strict';
22

3-
var gulp = require('gulp'),
4-
path = require('path'),
5-
slash = require('gulp-slash'),
6-
bowerDir = require('bower-directory');
3+
var gulp = require('gulp'),
4+
path = require('path'),
5+
slash = require('gulp-slash'),
6+
bowerDir = require('bower-directory');
77

88
var bowerFiles = require('../inject/bower-files'),
99
libGlobber = require('./lib-globber');
@@ -18,7 +18,12 @@ var NODE = 'node_modules',
1818
RELEASE_VENDOR = 'app-release/vendor',
1919
ROUTES = ['', BOWER, BUILD].reduce(mapRoutes, {});
2020

21-
var getLocalLibGlob = libGlobber(NODE, BOWER, APP, GENERATED);
21+
var getLocalLibGlob = libGlobber(NODE, BOWER, APP, GENERATED),
22+
testDependencies = bowerFiles({
23+
pattern: 'js',
24+
context: 'build',
25+
dev : true
26+
});
2227

2328
function mapRoutes(result, path) {
2429
result['/' + slash(path)] = path; // result['/<path>'] = <path>
@@ -45,11 +50,6 @@ function htmlApp(opts) {
4550
return gulp.src([APP + '/**/*.html', '!**/assets/**'], opts);
4651
}
4752

48-
function testDependencies(opts) {
49-
return bowerFiles(80)
50-
.src('js', opts);
51-
}
52-
5353
module.exports = {
5454
NODE : NODE,
5555
BOWER : BOWER,

lib/inject/bower-files.js

Lines changed: 152 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -11,176 +11,183 @@ var combined = require('combined-stream'),
1111
fs = require('fs');
1212

1313
/**
14-
* Retrieve version details of bower files as a stream
15-
* @param {boolean} useComment Determines whether the output is wrapped in a comment
16-
* @param {boolean} includeDev Determines whether dev dependencies are included
17-
* @returns {stream.Readable} A readable stream containing only the manifest file
14+
* Create a gulp.src() method that emits the bower main files and optional version manifest.
15+
* @param {{pattern:string, base:boolean, manifest:boolean, dev:boolean}} Options
1816
*/
19-
function json(includeDev) {
20-
function read(filename) {
21-
try {
22-
return fs.existsSync(filename) && require(path.resolve(filename));
23-
} catch(error) {
24-
gutil.log('Error parsing bower.json at ' + filename);
25-
}
26-
}
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'));
32-
}
33-
return result;
34-
}
35-
36-
/**
37-
* Retrieve version details of bower files as a stream
38-
* @param {boolean} useComment Determines whether the output is wrapped in a comment
39-
* @param {boolean} includeDev Determines whether dev dependencies are included
40-
* @returns {stream.Readable} A readable stream containing only the manifest file
41-
*/
42-
function manifest(useComment, includeDev) {
43-
var bower = json(includeDev);
44-
var versions = { };
45-
for (var key in bower) {
46-
versions[key] = bower[key].version;
47-
}
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 }, [
52-
new gutil.File({
53-
cwd: cwd,
54-
base: cwd,
55-
path: path.join(cwd, 'manifest.json'),
56-
contents: new Buffer(commented)
57-
})
58-
]);
59-
}
60-
61-
module.exports = function () {
62-
var before = [ ];
63-
var after = [ ];
17+
module.exports = function create(options) {
18+
defaults(options, {
19+
pattern : '*',
20+
base : false,
21+
manifest: false,
22+
dev : false
23+
});
6424

6525
/**
66-
* @param {string|RegExp} pattern Matches the extension of bower files
67-
* @param {object?} options Options for <code>gulp.src()</code> stream
26+
* Get a gulp.src() stream for the bower main files.
27+
* @param {object} options Options for <code>gulp.src()</code> stream
6828
*/
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-
}
29+
return function src(gulpSrcOptions) {
9630

9731
// create result list
98-
// the parsed content will be sorted by extension
99-
var parsed = json(options.dev);
100-
var bowerPackages = [ ];
32+
var parsed = json(options.dev, options.context),
33+
manifestFile = !!options.manifest && manifest((options.manifest === 'comment'), options.dev),
34+
bowerPackages = [];
10135
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);
36+
var config = parsed[packageName],
37+
list = []
38+
.concat(config.main)
39+
.filter(Boolean)
40+
.map(toAbsoluteForPackage(packageName))
41+
.filter(testExtension);
42+
if (list.length) {
43+
var base = list.reduce(greatestCommonBase, null);
44+
bowerPackages.push({
45+
name : packageName,
46+
options: defaults({base: base || options.base}, gulpSrcOptions), // use our base over that given
47+
list : list
48+
});
11449
}
11550
}
116-
var value = before.concat(bowerPackages).concat(after);
117-
var prepend = options.manifest && manifest(options.manifest === 'comment', options.dev);
11851

119-
// represent list as a readable stream
52+
// represent list as a readable stream, even if empty
12053
var stream;
121-
if (!value.length) {
12254

123-
// degenerate stream
124-
stream = spigot({ objectMode: true }, [ ]);
125-
stream._read = function () { };
55+
// degenerate stream
56+
if (!bowerPackages.length) {
57+
stream = spigot({objectMode: true}, []);
58+
stream._read = function () {
59+
};
12660
stream.push(null);
127-
128-
} else {
129-
130-
// combination of source streams with specific base path for each package
61+
}
62+
// combination of source streams with specific base path for each package
63+
else {
13164
stream = combined.create();
132-
if (prepend) {
133-
stream.append(prepend);
65+
if (manifestFile) {
66+
stream.append(manifestFile);
13467
}
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-
});
68+
bowerPackages.reduce(eachPackage, stream);
14669
}
14770

14871
// add the list to the stream as a sidecar
149-
stream.list = flatten(value);
72+
stream.list = flatten(bowerPackages);
15073

15174
// complete
15275
return stream;
153-
}
76+
};
15477

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-
};
78+
function greatestCommonBase(candidate, absolute) {
79+
if (candidate) {
80+
var i = 0;
81+
while (candidate[i] === absolute[i]) {
82+
i++;
83+
}
84+
return candidate.slice(0, i);
85+
} else if (options.base === true) {
86+
return path.dirname(absolute);
87+
} else {
88+
return null;
89+
}
16490
}
16591

166-
// complete
167-
var self = {
92+
function eachPackage(stream, bowerPackage) {
93+
return stream.append(
94+
gulp.src(bowerPackage.list, bowerPackage.options)
95+
.pipe(through.obj(transform))
96+
);
16897

169-
/**
170-
* Append any number of additional file paths to be used in any file lists that follow
171-
*/
172-
prepend: add(before),
98+
function transform(file, encoding, done) {
99+
/* jshint validthis:true */
100+
if ((options.base === true) && (bowerPackage.name)) {
101+
file.path = path.join(file.base, bowerPackage.name, file.relative);
102+
}
103+
this.push(file);
104+
done();
105+
}
106+
}
173107

174-
/**
175-
* Append any number of additional file paths to be used in any file lists that follow
176-
*/
177-
append: add(after),
108+
function testExtension(filename) {
109+
var pattern = options.pattern,
110+
ext = path.extname(filename).slice(1);
111+
return (
112+
((typeof pattern === 'string') && (pattern.split('|').indexOf(ext) >= 0)) ||
113+
((typeof pattern === 'object') && ('test' in pattern) && pattern.test(ext)) ||
114+
(pattern === '*')
115+
);
116+
}
117+
};
178118

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
119+
function toAbsoluteForPackage(packageName) {
120+
return function toAbsolute(relative) {
121+
return path.resolve(path.join('bower_components', packageName, ''), relative);
184122
};
185-
return self;
186-
};
123+
}
124+
125+
/**
126+
* Retrieve version details of bower files as a stream.
127+
* @param {boolean} includeDev Determines whether dev dependencies are included
128+
* @param {string} context Key used to determine overrides
129+
* @returns {stream.Readable} A readable stream containing only the manifest file
130+
*/
131+
function json(includeDev, context) {
132+
var root = read('bower.json'),
133+
packages = reduceJsonToPackages(root, includeDev);
134+
return processOverrides(packages, root.overrides);
135+
136+
function read(filename) {
137+
try {
138+
return fs.existsSync(filename) && require(path.resolve(filename));
139+
} catch (error) {
140+
gutil.log('Error parsing bower.json at ' + filename);
141+
}
142+
}
143+
144+
function reduceJsonToPackages(json, includeDev) {
145+
var isValid = (json && (typeof json === 'object')),
146+
dependencies = isValid && defaults(json.dependencies, includeDev && json.devDependencies) || {};
147+
return Object.keys(dependencies)
148+
.reduce(reduceDependencies, {});
149+
150+
function reduceDependencies(result, packageName) {
151+
var contents = read(path.join('bower_components', packageName, 'bower.json'));
152+
defaults(result, reduceJsonToPackages(contents, false)); // current items' dependencies precede the current item
153+
result[packageName] = contents;
154+
return result;
155+
}
156+
}
157+
158+
function processOverrides(packages, overrides) {
159+
return overrides ? Object.keys(packages).reduce(reducePackages, {}) : packages;
160+
161+
function reducePackages(result, packageName) {
162+
var item = packages[packageName],
163+
override = context && overrides[packageName + '.' + context] || overrides[packageName];
164+
result[packageName] = defaults({}, override, item);
165+
return result;
166+
}
167+
}
168+
}
169+
170+
/**
171+
* Retrieve version details of bower files as a stream.
172+
* @param {boolean} useComment Determines whether the output is wrapped in a comment
173+
* @param {boolean} includeDev Determines whether dev dependencies are included
174+
* @returns {stream.Readable} A readable stream containing only the manifest file
175+
*/
176+
function manifest(useComment, includeDev) {
177+
var bower = json(includeDev),
178+
versions = {};
179+
for (var key in bower) {
180+
versions[key] = bower[key].version;
181+
}
182+
var text = JSON.stringify(versions, null, 2),
183+
commented = (useComment) ? ['/*', text, '*/'].join('\n') : text,
184+
cwd = process.cwd();
185+
return spigot({objectMode: true}, [
186+
new gutil.File({
187+
cwd : cwd,
188+
base : cwd,
189+
path : path.join(cwd, 'manifest.json'),
190+
contents: new Buffer(commented)
191+
})
192+
]);
193+
}

0 commit comments

Comments
 (0)