Merge pull request #350 from strongloop/remove-app-boot
[2.0] Remove `app.boot`
This commit is contained in:
commit
9c32a0fb3b
|
@ -372,210 +372,9 @@ app.enableAuth = function() {
|
|||
this.isAuthEnabled = true;
|
||||
};
|
||||
|
||||
/**
|
||||
* Initialize an application from an options object or a set of JSON and JavaScript files.
|
||||
*
|
||||
* **Deprecated. Use the package
|
||||
* [loopback-boot](https://github.com/strongloop/loopback-boot) instead.**
|
||||
*
|
||||
* This function takes an optional argument that is either a string or an object.
|
||||
*
|
||||
* If the argument is a string, then it sets the application root directory based on the string value. Then it:
|
||||
* 1. Creates DataSources from the `datasources.json` file in the application root directory.
|
||||
* 2. Creates Models from the `models.json` file in the application root directory.
|
||||
*
|
||||
* If the argument is an object, then it looks for `model`, `dataSources`, and `appRootDir` properties of the object.
|
||||
* If the object has no `appRootDir` property then it sets the current working directory as the application root directory.
|
||||
* Then it:
|
||||
* 1. Creates DataSources from the `options.dataSources` object.
|
||||
* 2. Creates Models from the `options.models` object.
|
||||
*
|
||||
* In both cases, the function loads JavaScript files in the `/models` and `/boot` subdirectories of the application root directory with `require()`.
|
||||
*
|
||||
* **NOTE:** mixing `app.boot()` and `app.model(name, config)` in multiple
|
||||
* files may result in models being **undefined** due to race conditions.
|
||||
* To avoid this when using `app.boot()` make sure all models are passed as part of the `models` definition.
|
||||
*
|
||||
* Throws an error if the config object is not valid or if boot fails.
|
||||
*
|
||||
* <a name="model-definition"></a>
|
||||
* **Model Definitions**
|
||||
*
|
||||
* The following is example JSON for two `Model` definitions: "dealership" and "location".
|
||||
*
|
||||
* ```js
|
||||
* {
|
||||
* "dealership": {
|
||||
* // a reference, by name, to a dataSource definition
|
||||
* "dataSource": "my-db",
|
||||
* // the options passed to Model.extend(name, properties, options)
|
||||
* "options": {
|
||||
* "relations": {
|
||||
* "cars": {
|
||||
* "type": "hasMany",
|
||||
* "model": "Car",
|
||||
* "foreignKey": "dealerId"
|
||||
* }
|
||||
* }
|
||||
* },
|
||||
* // the properties passed to Model.extend(name, properties, options)
|
||||
* "properties": {
|
||||
* "id": {"id": true},
|
||||
* "name": "String",
|
||||
* "zip": "Number",
|
||||
* "address": "String"
|
||||
* }
|
||||
* },
|
||||
* "car": {
|
||||
* "dataSource": "my-db"
|
||||
* "properties": {
|
||||
* "id": {
|
||||
* "type": "String",
|
||||
* "required": true,
|
||||
* "id": true
|
||||
* },
|
||||
* "make": {
|
||||
* "type": "String",
|
||||
* "required": true
|
||||
* },
|
||||
* "model": {
|
||||
* "type": "String",
|
||||
* "required": true
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* }
|
||||
* ```
|
||||
* @options {String|Object} options Boot options; If String, this is the application root directory; if object, has below properties.
|
||||
* @property {String} appRootDir Directory to use when loading JSON and JavaScript files (optional). Defaults to the current directory (`process.cwd()`).
|
||||
* @property {Object} models Object containing `Model` definitions (optional).
|
||||
* @property {Object} dataSources Object containing `DataSource` definitions (optional).
|
||||
* @end
|
||||
*
|
||||
* @header app.boot([options])
|
||||
*/
|
||||
|
||||
app.boot = function(options) {
|
||||
options = options || {};
|
||||
|
||||
if(typeof options === 'string') {
|
||||
options = {appRootDir: options};
|
||||
}
|
||||
var app = this;
|
||||
var appRootDir = options.appRootDir = options.appRootDir || process.cwd();
|
||||
var ctx = {};
|
||||
var appConfig = options.app;
|
||||
var modelConfig = options.models;
|
||||
var dataSourceConfig = options.dataSources;
|
||||
|
||||
if(!appConfig) {
|
||||
appConfig = tryReadConfig(appRootDir, 'app') || {};
|
||||
}
|
||||
if(!modelConfig) {
|
||||
modelConfig = tryReadConfig(appRootDir, 'models') || {};
|
||||
}
|
||||
if(!dataSourceConfig) {
|
||||
dataSourceConfig = tryReadConfig(appRootDir, 'datasources') || {};
|
||||
}
|
||||
|
||||
assertIsValidConfig('app', appConfig);
|
||||
assertIsValidConfig('model', modelConfig);
|
||||
assertIsValidConfig('data source', dataSourceConfig);
|
||||
|
||||
appConfig.host =
|
||||
process.env.npm_config_host ||
|
||||
process.env.OPENSHIFT_SLS_IP ||
|
||||
process.env.OPENSHIFT_NODEJS_IP ||
|
||||
process.env.HOST ||
|
||||
appConfig.host ||
|
||||
process.env.npm_package_config_host ||
|
||||
app.get('host');
|
||||
|
||||
appConfig.port = _.find([
|
||||
process.env.npm_config_port,
|
||||
process.env.OPENSHIFT_SLS_PORT,
|
||||
process.env.OPENSHIFT_NODEJS_PORT,
|
||||
process.env.PORT,
|
||||
appConfig.port,
|
||||
process.env.npm_package_config_port,
|
||||
app.get('port'),
|
||||
3000
|
||||
], _.isFinite);
|
||||
|
||||
appConfig.restApiRoot =
|
||||
appConfig.restApiRoot ||
|
||||
app.get('restApiRoot') ||
|
||||
'/api';
|
||||
|
||||
if(appConfig.host !== undefined) {
|
||||
assert(typeof appConfig.host === 'string', 'app.host must be a string');
|
||||
app.set('host', appConfig.host);
|
||||
}
|
||||
|
||||
if(appConfig.port !== undefined) {
|
||||
var portType = typeof appConfig.port;
|
||||
assert(portType === 'string' || portType === 'number', 'app.port must be a string or number');
|
||||
app.set('port', appConfig.port);
|
||||
}
|
||||
|
||||
assert(appConfig.restApiRoot !== undefined, 'app.restApiRoot is required');
|
||||
assert(typeof appConfig.restApiRoot === 'string', 'app.restApiRoot must be a string');
|
||||
assert(/^\//.test(appConfig.restApiRoot), 'app.restApiRoot must start with "/"');
|
||||
app.set('restApiRoot', appConfig.restApiRoot);
|
||||
|
||||
for(var configKey in appConfig) {
|
||||
var cur = app.get(configKey);
|
||||
if(cur === undefined || cur === null) {
|
||||
app.set(configKey, appConfig[configKey]);
|
||||
}
|
||||
}
|
||||
|
||||
// instantiate data sources
|
||||
forEachKeyedObject(dataSourceConfig, function(key, obj) {
|
||||
app.dataSource(key, obj);
|
||||
});
|
||||
|
||||
// instantiate models
|
||||
forEachKeyedObject(modelConfig, function(key, obj) {
|
||||
app.model(key, obj);
|
||||
});
|
||||
|
||||
// try to attach models to dataSources by type
|
||||
try {
|
||||
registry.autoAttach();
|
||||
} catch(e) {
|
||||
if(e.name === 'AssertionError') {
|
||||
console.warn(e);
|
||||
} else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
// disable token requirement for swagger, if available
|
||||
var swagger = app.remotes().exports.swagger;
|
||||
var requireTokenForSwagger = appConfig.swagger
|
||||
&& appConfig.swagger.requireToken;
|
||||
if(swagger) {
|
||||
swagger.requireToken = requireTokenForSwagger || false;
|
||||
}
|
||||
|
||||
// require directories
|
||||
var requiredModels = requireDir(path.join(appRootDir, 'models'));
|
||||
var requiredBootScripts = requireDir(path.join(appRootDir, 'boot'));
|
||||
}
|
||||
|
||||
function assertIsValidConfig(name, config) {
|
||||
if(config) {
|
||||
assert(typeof config === 'object', name + ' config must be a valid JSON object');
|
||||
}
|
||||
}
|
||||
|
||||
function forEachKeyedObject(obj, fn) {
|
||||
if(typeof obj !== 'object') return;
|
||||
|
||||
Object.keys(obj).forEach(function(key) {
|
||||
fn(key, obj[key]);
|
||||
});
|
||||
throw new Error(
|
||||
'`app.boot` was removed, use the new module loopback-boot instead');
|
||||
}
|
||||
|
||||
function classify(str) {
|
||||
|
@ -628,85 +427,6 @@ function configureModel(ModelCtor, config, app) {
|
|||
registry.configureModel(ModelCtor, config);
|
||||
}
|
||||
|
||||
function requireDir(dir, basenames) {
|
||||
assert(dir, 'cannot require directory contents without directory name');
|
||||
|
||||
var requires = {};
|
||||
|
||||
if (arguments.length === 2) {
|
||||
// if basenames argument is passed, explicitly include those files
|
||||
basenames.forEach(function (basename) {
|
||||
var filepath = Path.resolve(Path.join(dir, basename));
|
||||
requires[basename] = tryRequire(filepath);
|
||||
});
|
||||
} else if (arguments.length === 1) {
|
||||
// if basenames arguments isn't passed, require all javascript
|
||||
// files (except for those prefixed with _) and all directories
|
||||
|
||||
var files = tryReadDir(dir);
|
||||
|
||||
// sort files in lowercase alpha for linux
|
||||
files.sort(function (a,b) {
|
||||
a = a.toLowerCase();
|
||||
b = b.toLowerCase();
|
||||
|
||||
if (a < b) {
|
||||
return -1;
|
||||
} else if (b < a) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
});
|
||||
|
||||
files.forEach(function (filename) {
|
||||
// ignore index.js and files prefixed with underscore
|
||||
if ((filename === 'index.js') || (filename[0] === '_')) { return; }
|
||||
|
||||
var filepath = path.resolve(path.join(dir, filename));
|
||||
var ext = path.extname(filename);
|
||||
var stats = fs.statSync(filepath);
|
||||
|
||||
// only require files supported by require.extensions (.txt .md etc.)
|
||||
if (stats.isFile() && !(ext in require.extensions)) { return; }
|
||||
|
||||
var basename = path.basename(filename, ext);
|
||||
|
||||
requires[basename] = tryRequire(filepath);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
return requires;
|
||||
};
|
||||
|
||||
function tryRequire(modulePath) {
|
||||
try {
|
||||
return require.apply(this, arguments);
|
||||
} catch(e) {
|
||||
console.error('failed to require "%s"', modulePath);
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
|
||||
function tryReadDir() {
|
||||
try {
|
||||
return fs.readdirSync.apply(fs, arguments);
|
||||
} catch(e) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
|
||||
function tryReadConfig(cwd, fileName) {
|
||||
try {
|
||||
return require(path.join(cwd, fileName + '.json'));
|
||||
} catch(e) {
|
||||
if(e.code !== "MODULE_NOT_FOUND") {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function clearHandlerCache(app) {
|
||||
app._handlers = undefined;
|
||||
}
|
||||
|
|
|
@ -57,6 +57,7 @@
|
|||
"strong-task-emitter": "0.0.x",
|
||||
"supertest": "~0.13.0",
|
||||
"chai": "~1.9.1",
|
||||
"loopback-boot": "1.x >=1.1",
|
||||
"loopback-testing": "~0.2.0",
|
||||
"browserify": "~4.1.6",
|
||||
"grunt": "~0.4.5",
|
||||
|
|
194
test/app.test.js
194
test/app.test.js
|
@ -86,15 +86,8 @@ describe('app', function() {
|
|||
|
||||
beforeEach(function() {
|
||||
app = loopback();
|
||||
app.boot({
|
||||
app: {port: 3000, host: '127.0.0.1'},
|
||||
// prevent loading of models.json, it is not available in the browser
|
||||
models: {},
|
||||
dataSources: {
|
||||
db: {
|
||||
connector: 'memory'
|
||||
}
|
||||
}
|
||||
app.dataSource('db', {
|
||||
connector: 'memory'
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -190,189 +183,6 @@ describe('app', function() {
|
|||
});
|
||||
});
|
||||
|
||||
describe.onServer('app.boot([options])', function () {
|
||||
beforeEach(function () {
|
||||
app.boot({
|
||||
app: {
|
||||
port: 3000,
|
||||
host: '127.0.0.1',
|
||||
restApiRoot: '/rest-api',
|
||||
foo: {bar: 'bat'},
|
||||
baz: true
|
||||
},
|
||||
models: {
|
||||
'foo-bar-bat-baz': {
|
||||
options: {
|
||||
plural: 'foo-bar-bat-bazzies'
|
||||
},
|
||||
dataSource: 'the-db'
|
||||
}
|
||||
},
|
||||
dataSources: {
|
||||
'the-db': {
|
||||
connector: 'memory'
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
it('should have port setting', function () {
|
||||
assert.equal(this.app.get('port'), 3000);
|
||||
});
|
||||
|
||||
it('should have host setting', function() {
|
||||
assert.equal(this.app.get('host'), '127.0.0.1');
|
||||
});
|
||||
|
||||
it('should have restApiRoot setting', function() {
|
||||
assert.equal(this.app.get('restApiRoot'), '/rest-api');
|
||||
});
|
||||
|
||||
it('should have other settings', function () {
|
||||
expect(this.app.get('foo')).to.eql({
|
||||
bar: 'bat'
|
||||
});
|
||||
expect(this.app.get('baz')).to.eql(true);
|
||||
});
|
||||
|
||||
describe('boot and models directories', function() {
|
||||
beforeEach(function() {
|
||||
var app = this.app = loopback();
|
||||
app.boot(SIMPLE_APP);
|
||||
});
|
||||
|
||||
it('should run all modules in the boot directory', function () {
|
||||
assert(process.loadedFooJS);
|
||||
delete process.loadedFooJS;
|
||||
});
|
||||
|
||||
it('should run all modules in the models directory', function () {
|
||||
assert(process.loadedBarJS);
|
||||
delete process.loadedBarJS;
|
||||
});
|
||||
});
|
||||
|
||||
describe('PaaS and npm env variables', function() {
|
||||
beforeEach(function() {
|
||||
this.boot = function () {
|
||||
var app = loopback();
|
||||
app.boot({
|
||||
app: {
|
||||
port: undefined,
|
||||
host: undefined
|
||||
}
|
||||
});
|
||||
return app;
|
||||
}
|
||||
});
|
||||
|
||||
it('should be honored', function() {
|
||||
var assertHonored = function (portKey, hostKey) {
|
||||
process.env[hostKey] = randomPort();
|
||||
process.env[portKey] = randomHost();
|
||||
var app = this.boot();
|
||||
assert.equal(app.get('port'), process.env[portKey]);
|
||||
assert.equal(app.get('host'), process.env[hostKey]);
|
||||
delete process.env[portKey];
|
||||
delete process.env[hostKey];
|
||||
}.bind(this);
|
||||
|
||||
assertHonored('OPENSHIFT_SLS_PORT', 'OPENSHIFT_NODEJS_IP');
|
||||
assertHonored('npm_config_port', 'npm_config_host');
|
||||
assertHonored('npm_package_config_port', 'npm_package_config_host');
|
||||
assertHonored('OPENSHIFT_SLS_PORT', 'OPENSHIFT_SLS_IP');
|
||||
assertHonored('PORT', 'HOST');
|
||||
});
|
||||
|
||||
it('should be honored in order', function() {
|
||||
process.env.npm_config_host = randomHost();
|
||||
process.env.OPENSHIFT_SLS_IP = randomHost();
|
||||
process.env.OPENSHIFT_NODEJS_IP = randomHost();
|
||||
process.env.HOST = randomHost();
|
||||
process.env.npm_package_config_host = randomHost();
|
||||
|
||||
var app = this.boot();
|
||||
assert.equal(app.get('host'), process.env.npm_config_host);
|
||||
|
||||
delete process.env.npm_config_host;
|
||||
delete process.env.OPENSHIFT_SLS_IP;
|
||||
delete process.env.OPENSHIFT_NODEJS_IP;
|
||||
delete process.env.HOST;
|
||||
delete process.env.npm_package_config_host;
|
||||
|
||||
process.env.npm_config_port = randomPort();
|
||||
process.env.OPENSHIFT_SLS_PORT = randomPort();
|
||||
process.env.OPENSHIFT_NODEJS_PORT = randomPort();
|
||||
process.env.PORT = randomPort();
|
||||
process.env.npm_package_config_port = randomPort();
|
||||
|
||||
var app = this.boot();
|
||||
assert.equal(app.get('host'), process.env.npm_config_host);
|
||||
assert.equal(app.get('port'), process.env.npm_config_port);
|
||||
|
||||
delete process.env.npm_config_port;
|
||||
delete process.env.OPENSHIFT_SLS_PORT;
|
||||
delete process.env.OPENSHIFT_NODEJS_PORT;
|
||||
delete process.env.PORT;
|
||||
delete process.env.npm_package_config_port;
|
||||
});
|
||||
|
||||
function randomHost() {
|
||||
return Math.random().toString().split('.')[1];
|
||||
}
|
||||
|
||||
function randomPort() {
|
||||
return Math.floor(Math.random() * 10000);
|
||||
}
|
||||
|
||||
it('should honor 0 for free port', function () {
|
||||
var app = loopback();
|
||||
app.boot({app: {port: 0}});
|
||||
assert.equal(app.get('port'), 0);
|
||||
});
|
||||
|
||||
it('should default to port 3000', function () {
|
||||
var app = loopback();
|
||||
app.boot({app: {port: undefined}});
|
||||
assert.equal(app.get('port'), 3000);
|
||||
});
|
||||
});
|
||||
|
||||
it('Instantiate models', function () {
|
||||
assert(app.models);
|
||||
assert(app.models.FooBarBatBaz);
|
||||
assert(app.models.fooBarBatBaz);
|
||||
assertValidDataSource(app.models.FooBarBatBaz.dataSource);
|
||||
assert.isFunc(app.models.FooBarBatBaz, 'find');
|
||||
assert.isFunc(app.models.FooBarBatBaz, 'create');
|
||||
});
|
||||
|
||||
it('Attach models to data sources', function () {
|
||||
assert.equal(app.models.FooBarBatBaz.dataSource, app.dataSources.theDb);
|
||||
});
|
||||
|
||||
it('Instantiate data sources', function () {
|
||||
assert(app.dataSources);
|
||||
assert(app.dataSources.theDb);
|
||||
assertValidDataSource(app.dataSources.theDb);
|
||||
assert(app.dataSources.TheDb);
|
||||
});
|
||||
});
|
||||
|
||||
describe.onServer('app.boot(appRootDir)', function () {
|
||||
it('Load config files', function () {
|
||||
var app = loopback();
|
||||
|
||||
app.boot(SIMPLE_APP);
|
||||
|
||||
assert(app.models.foo);
|
||||
assert(app.models.Foo);
|
||||
assert(app.models.Foo.dataSource);
|
||||
assert.isFunc(app.models.Foo, 'find');
|
||||
assert.isFunc(app.models.Foo, 'create');
|
||||
});
|
||||
});
|
||||
|
||||
describe.onServer('listen()', function() {
|
||||
it('starts http server', function(done) {
|
||||
var app = loopback();
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
var loopback = require('../../../');
|
||||
var boot = require('loopback-boot');
|
||||
var path = require('path');
|
||||
var app = module.exports = loopback();
|
||||
|
||||
app.boot(__dirname);
|
||||
boot(app, __dirname);
|
||||
|
||||
var apiPath = '/api';
|
||||
app.use(loopback.cookieParser('secret'));
|
||||
|
|
|
@ -1,8 +1,9 @@
|
|||
var loopback = require('../../../');
|
||||
var boot = require('loopback-boot');
|
||||
var path = require('path');
|
||||
var app = module.exports = loopback();
|
||||
|
||||
app.boot(__dirname);
|
||||
boot(app, __dirname);
|
||||
app.use(loopback.favicon());
|
||||
app.use(loopback.cookieParser({secret: app.get('cookieSecret')}));
|
||||
var apiPath = '/api';
|
||||
|
|
Loading…
Reference in New Issue