Tidy up the iteration per review comment

This commit is contained in:
Raymond Feng 2016-05-31 16:43:58 -07:00 committed by David Cheung
parent 5a92f3eeb1
commit c000435be9
10 changed files with 119 additions and 124 deletions

63
lib/bootstrapper.js vendored
View File

@ -144,6 +144,37 @@ Bootstrapper.prototype.addPhases = function(phases) {
return this.phases;
};
function pluginIteratorFactory(context, phase) {
return function(plugin, done) {
var result;
if (typeof plugin.handler[phase] !== 'function') {
debug('Skipping %s.%s', plugin.handler.name, phase);
return done();
}
debug('Invoking %s.%s', plugin.handler.name, phase);
try {
if (plugin.handler[phase].length === 2) {
plugin.handler[phase](context, done);
} else {
result = plugin.handler[phase](context);
if (typeof Promise !== 'undefined') {
Promise.resolve(result).then(function(value) {
done(null, value);
}).catch(function(err) {
debug('Unable to invoke %s.%s()', plugin.name, phase, err);
done(err);
});
} else {
done(null, result);
}
}
} catch (err) {
debug('Unable to invoke %s.%s()', plugin.name, phase, err);
done(err);
}
};
}
/**
* Invoke the plugins phase by phase with the given context
* @param {Object} context Context object
@ -168,37 +199,9 @@ Bootstrapper.prototype.run = function(context, done) {
var phases = context.phases || this.phases;
var bootPlugins = this.getExtensions('/boot');
async.eachSeries(phases, function(phase, cb1) {
async.eachSeries(phases, function(phase, done) {
debug('Phase %s', phase);
async.eachSeries(bootPlugins, function(plugin, cb2) {
var result;
if (typeof plugin.handler[phase] === 'function') {
debug('Invoking %s.%s', plugin.handler.name, phase);
try {
if (plugin.handler[phase].length === 2) {
plugin.handler[phase](context, cb2);
} else {
result = plugin.handler[phase](context);
if (typeof Promise !== 'undefined') {
Promise.resolve(result).then(function(value) {
cb2(null, value);
}).catch(function(err) {
debug(err);
cb2(err);
});
} else {
cb2(null, result);
}
}
} catch (err) {
debug(err);
cb2(err);
}
} else {
debug('Skipping %s.%s', plugin.handler.name, phase);
return cb2();
}
}, cb1);
async.eachSeries(bootPlugins, pluginIteratorFactory(context, phase), done);
}, function(err) {
return done(err, context);
});

View File

@ -15,6 +15,7 @@ var g = require('strong-globalize')();
* @param {Object} bundler A browserify object created by `browserify()`.
*/
module.exports = function addInstructionsToBrowserify(context, bundler) {
addPlugins(bundler);
// bundlePluginScripts(context, bundler);
bundleModelScripts(context, bundler);
bundleMixinScripts(context, bundler);
@ -23,6 +24,15 @@ module.exports = function addInstructionsToBrowserify(context, bundler) {
bundleInstructions(context, bundler);
};
function addPlugins(bundler) {
var dir = path.join(__dirname, './plugins');
var files = fs.readdirSync(dir);
files.forEach(function(f) {
bundler.require(path.join(dir, f),
{ expose: './plugins/' + path.basename(f, '.js') });
});
}
function bundleOtherScripts(context, bundler) {
var list = context.instructions.bootScripts;
addScriptsToBundle('boot', list, bundler);

View File

@ -38,8 +38,6 @@ PluginScript.prototype.load = function(context) {
pluginScripts = pluginScripts.concat(utils.findScripts(envdir));
});
// de-dedup boot scripts -ERS
// https://github.com/strongloop/loopback-boot/issues/64
pluginScripts = _.uniq(pluginScripts);
debug('Plugin scripts: %j', pluginScripts);
this.configure(context, pluginScripts);

View File

@ -19,24 +19,8 @@ function Application(options) {
util.inherits(Application, PluginBase);
function patchAppLoopback(app) {
if (app.loopback) return;
// app.loopback was introduced in 1.9.0
// patch the app object to make loopback-boot work with older versions too
try {
app.loopback = require('loopback');
} catch (err) {
if (err.code === 'MODULE_NOT_FOUND') {
console.error(
'When using loopback-boot with loopback <1.9, ' +
'the loopback module must be available for `require(\'loopback\')`.');
}
throw err;
}
}
function assertLoopBackVersion(app) {
var RANGE = '1.x || 2.x || ^3.0.0-alpha';
var RANGE = '2.x || ^3.0.0-alpha';
var loopback = app.loopback;
// remove any pre-release tag from the version string,
@ -130,8 +114,6 @@ function applyAppConfig(app, appConfig) {
Application.prototype.starting = function(context) {
var app = context.app;
app.booting = true;
patchAppLoopback(app);
assertLoopBackVersion(app);
var appConfig = context.instructions.application;

View File

@ -25,24 +25,25 @@
"license": "MIT",
"dependencies": {
"async": "^1.5.2",
"bluebird": "^3.3.5",
"bluebird": "^3.4.0",
"commondir": "1.0.1",
"debug": "^2.2.0",
"lodash": "^4.11.1",
"lodash": "^4.13.1",
"semver": "^5.1.0",
"strong-globalize": "^2.6.2",
"toposort": "^0.2.12"
"toposort": "^1.0.0"
},
"devDependencies": {
"browserify": "^4.2.3",
"eslint": "^2.5.3",
"eslint-config-loopback": "^1.0.0",
"chai": "^3.5.0",
"coffee-script": "^1.10.0",
"coffeeify": "^2.0.1",
"fs-extra": "^0.28.0",
"loopback": "^2.27.0",
"mocha": "^2.4.5",
"dirty-chai": "^1.2.2",
"eslint": "^2.11.1",
"eslint-config-loopback": "^1.0.0",
"fs-extra": "^0.30.0",
"loopback": "^2.28.0",
"mocha": "^2.5.3",
"supertest": "^1.2.0"
}
}

View File

@ -1,6 +1,11 @@
var path = require('path');
var loopback = require('loopback');
var expect = require('chai').expect;
var chai = require('chai');
var dirtyChai = require('dirty-chai');
var expect = chai.expect;
chai.use(dirtyChai);
var Bootstrapper = require('../lib/bootstrapper').Bootstrapper;
describe('Bootstrapper', function() {
@ -25,12 +30,12 @@ describe('Bootstrapper', function() {
bootstrapper.run(context, function(err) {
if (err) return done(err);
expect(context.configurations.application).to.be.object;
expect(context.configurations.bootScripts).to.be.object;
expect(context.configurations.middleware).to.be.object;
expect(context.configurations.models).to.be.object;
expect(context.configurations.application).to.be.an('object');
expect(context.configurations.bootScripts).to.be.an('array');
expect(context.configurations.middleware).to.be.an('object');
expect(context.configurations.models).to.be.an('object');
expect(context.configurations.tracker).to.eql('load');
expect(context.instructions).to.be.undefined;
expect(context.instructions).to.be.undefined();
expect(process.bootFlags.length).to.eql(0);
done();
});
@ -51,11 +56,11 @@ describe('Bootstrapper', function() {
bootstrapper.run(context, function(err) {
if (err) return done(err);
expect(context.configurations.application).to.be.object;
expect(context.configurations.middleware).to.be.undefined;
expect(context.configurations.models).to.be.undefined;
expect(context.configurations.bootScripts).to.be.object;
expect(context.instructions.application).to.be.object;
expect(context.configurations.application).to.be.an('object');
expect(context.configurations.middleware).to.be.undefined();
expect(context.configurations.models).to.be.undefined();
expect(context.configurations.bootScripts).to.be.an('array');
expect(context.instructions.application).to.be.an('object');
expect(context.instructions.tracker).to.eql('compile');
expect(context.executions.tracker).to.eql('start');
expect(process.bootFlags).to.eql(['barLoaded',

View File

@ -60,22 +60,12 @@ describe('browser support for multiple apps', function() {
});
});
function addPlugins(b) {
var files = fs.readdirSync(path.join(__dirname, '../lib/plugins'));
files.forEach(function(f) {
b.require('../../lib/plugins/' + f,
{ expose: './plugins/' + path.basename(f, '.js') });
});
}
function browserifyTestApps(apps, next) {
var b = browserify({
debug: true,
basedir: path.resolve(__dirname, './fixtures'),
});
addPlugins(b);
var bundles = [];
for (var i in apps) {
var appDir = apps[i].appDir;

View File

@ -14,21 +14,12 @@ var vm = require('vm');
var createBrowserLikeContext = require('./helpers/browser').createContext;
var printContextLogs = require('./helpers/browser').printContextLogs;
function addPlugins(b) {
var files = fs.readdirSync(path.join(__dirname, '../lib/plugins'));
files.forEach(function(f) {
b.require('../../../lib/plugins/' + f,
{ expose: './plugins/' + path.basename(f, '.js') });
});
}
var compileStrategies = {
'default': function(appDir) {
var b = browserify({
basedir: appDir,
debug: true,
});
addPlugins(b);
b.require('./app.js', { expose: 'browser-app' });
return b;
},
@ -39,7 +30,6 @@ var compileStrategies = {
extensions: ['.coffee'],
debug: true,
});
addPlugins(b);
b.transform('coffeeify');
b.require('./app.coffee', { expose: 'browser-app' });

View File

@ -19,7 +19,11 @@ describe('compiler', function() {
beforeEach(sandbox.reset);
beforeEach(appdir.init);
function expectToThrow(err, done, options) {
function expectCompileToThrow(err, options, done) {
if (typeof options === 'function') {
done = options;
options = undefined;
}
boot.compile(options || appdir.PATH, function(err) {
expect(function() {
if (err) throw err;
@ -28,7 +32,11 @@ describe('compiler', function() {
});
}
function expectToNotThrow(done, options) {
function expectCompileToNotThrow(options, done) {
if (typeof options === 'function') {
done = options;
options = undefined;
}
boot.compile(options || appdir.PATH, function(err) {
expect(function() {
if (err) throw err;
@ -570,7 +578,8 @@ describe('compiler', function() {
},
});
expectToThrow(/array values of different length.*nest\.array/, done);
expectCompileToThrow(/array values of different length.*nest\.array/,
done);
});
it('refuses to merge Array of different length in Array', function(done) {
@ -582,7 +591,7 @@ describe('compiler', function() {
key: [['value']],
});
expectToThrow(/array values of different length.*key\[0\]/, done);
expectCompileToThrow(/array values of different length.*key\[0\]/, done);
});
it('returns full key of an incorrect Array value', function(done) {
@ -602,7 +611,8 @@ describe('compiler', function() {
],
});
expectToThrow(/array values of different length.*toplevel\[0\]\.nested/,
expectCompileToThrow(
/array values of different length.*toplevel\[0\]\.nested/,
done);
});
@ -614,7 +624,7 @@ describe('compiler', function() {
key: {},
});
expectToThrow(/incompatible types.*key/, done);
expectCompileToThrow(/incompatible types.*key/, done);
});
it('refuses to merge incompatible array items', function(done) {
@ -625,7 +635,7 @@ describe('compiler', function() {
key: [{}],
});
expectToThrow(/incompatible types.*key\[0\]/, done);
expectCompileToThrow(/incompatible types.*key\[0\]/, done);
});
it('merges app configs from multiple files', function(done) {
@ -977,7 +987,7 @@ describe('compiler', function() {
foo: { properties: { name: 'string' }},
});
expectToThrow(/unsupported 1\.x format/, done);
expectCompileToThrow(/unsupported 1\.x format/, done);
});
it('throws when model-config.json contains 1.x `options.base`',
@ -986,7 +996,7 @@ describe('compiler', function() {
Customer: { options: { base: 'User' }},
});
expectToThrow(/unsupported 1\.x format/, done);
expectCompileToThrow(/unsupported 1\.x format/, done);
});
it('loads models from `./models`', function(done) {
@ -1341,7 +1351,7 @@ describe('compiler', function() {
base: 'Car',
});
expectToThrow(/cyclic dependency/i, done);
expectCompileToThrow(/cyclic dependency/i, done);
});
it('uses file name as default value for model name', function(done) {
@ -1841,8 +1851,8 @@ describe('compiler', function() {
it('throws error for invalid normalization format', function(done) {
options.normalization = 'invalidFormat';
expectToThrow(/Invalid normalization format - "invalidFormat"/,
done, options);
expectCompileToThrow(/Invalid normalization format - "invalidFormat"/,
options, done);
});
});
@ -1985,7 +1995,7 @@ describe('compiler', function() {
},
});
expectToThrow(/path-does-not-exist/, done);
expectCompileToThrow(/path-does-not-exist/, done);
});
it('does not fail when an optional middleware cannot be resolved',
@ -1998,7 +2008,7 @@ describe('compiler', function() {
},
});
expectToNotThrow(done);
expectCompileToNotThrow(done);
});
it('fails when a module middleware fragment cannot be resolved',
@ -2009,7 +2019,7 @@ describe('compiler', function() {
},
});
expectToThrow(/path-does-not-exist/, done);
expectCompileToThrow(/path-does-not-exist/, done);
});
it('does not fail when an optional middleware fragment cannot be resolved',
@ -2022,7 +2032,7 @@ describe('compiler', function() {
},
});
expectToNotThrow(done);
expectCompileToNotThrow(done);
});
it('resolves paths relatively to appRootDir', function(done) {
@ -2778,7 +2788,8 @@ describe('compiler', function() {
});
appdir.writeConfigFileSync('./my-component/component.js', '');
expectToThrow('Cannot resolve path \"my-component/component.js\"',
expectCompileToThrow(
'Cannot resolve path \"my-component/component.js\"',
done);
});

View File

@ -8,7 +8,12 @@ var boot = require('../');
var path = require('path');
var loopback = require('loopback');
var assert = require('assert');
var expect = require('chai').expect;
var chai = require('chai');
var dirtyChai = require('dirty-chai');
var expect = chai.expect;
chai.use(dirtyChai);
var fs = require('fs-extra');
var sandbox = require('./helpers/sandbox');
var appdir = require('./helpers/appdir');
@ -62,13 +67,13 @@ describe('executor', function() {
describe('when booting', function() {
it('should set the `booting` flag during execution', function(done) {
expect(app.booting).to.be.undefined;
expect(app.booting).to.be.undefined();
simpleAppInstructions(function(err, context) {
if (err) return done(err);
boot.execute(app, context.instructions, function(err) {
expect(err).to.not.exist;
expect(process.bootingFlagSet).to.be.true;
expect(app.booting).to.be.false;
expect(process.bootingFlagSet).to.be.true();
expect(app.booting).to.be.false();
done();
});
});
@ -410,16 +415,16 @@ describe('executor', function() {
});
it('should honor host and port', function(done) {
function assertHonored(portKey, hostKey, done) {
function assertHonored(portKey, hostKey, cb) {
process.env[hostKey] = randomPort();
process.env[portKey] = randomHost();
bootWithDefaults(function(err) {
if (err) return done(err);
if (err) return cb(err);
assert.equal(app.get('port'), process.env[portKey], portKey);
assert.equal(app.get('host'), process.env[hostKey], hostKey);
delete process.env[portKey];
delete process.env[hostKey];
done();
cb();
});
}
@ -430,8 +435,8 @@ describe('executor', function() {
{ port: 'OPENSHIFT_SLS_PORT', host: 'OPENSHIFT_SLS_IP' },
{ port: 'VCAP_APP_PORT', host: 'VCAP_APP_HOST' },
{ port: 'PORT', host: 'HOST' },
], function(config, done) {
assertHonored(config.port, config.host, done);
], function(config, cb) {
assertHonored(config.port, config.host, cb);
}, done);
});
@ -656,8 +661,8 @@ describe('executor', function() {
supertest(app)
.get('/')
.end(function(err, res) {
expect(err).to.be.null;
expect(res.body.path).to.be.undefined;
expect(err).to.be.null();
expect(res.body.path).to.be.undefined();
cb();
});
}, cb);
@ -675,7 +680,7 @@ describe('executor', function() {
supertest(app)
.get('/')
.end(function(err, res) {
expect(err).to.be.null;
expect(err).to.be.null();
done();
});
});
@ -833,7 +838,7 @@ describe('executor', function() {
boot.execute(app, someInstructions({ bootScripts: [file] }),
function(err) {
if (err) return done(err);
expect(app.fnCalled, 'exported fn was called').to.be.true;
expect(app.fnCalled, 'exported fn was called').to.be.true();
done();
});
});
@ -1023,12 +1028,12 @@ describe('executor', function() {
describe('when booting with env', function() {
it('should set the `booting` flag during execution', function(done) {
expect(app.booting).to.be.undefined;
expect(app.booting).to.be.undefined();
envAppInstructions(function(err, context) {
if (err) return done(err);
boot.execute(app, context.instructions, function(err) {
if (err) return done(err);
expect(app.booting).to.be.false;
expect(app.booting).to.be.false();
expect(process.bootFlags).to.not.have.property('barLoadedInTest');
done();
});
@ -1156,8 +1161,8 @@ describe('executor', function() {
var bootInstructions = { dataSources: datasource };
boot.execute(app, someInstructions(bootInstructions), function() {
expect(app.get('DYNAMIC_HOST')).to.be.undefined;
expect(app.datasources.mydb.settings.host).to.be.undefined;
expect(app.get('DYNAMIC_HOST')).to.be.undefined();
expect(app.datasources.mydb.settings.host).to.be.undefined();
done();
});
});