Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
284 changes: 2 additions & 282 deletions lib/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Loading