Merge pull request #658 from rhalff:master

Fix basic jshint errors

Close #658
This commit is contained in:
Miroslav Bajtoš 2014-10-22 18:48:12 +02:00
commit 97a8c3acb2
13 changed files with 182 additions and 173 deletions

View File

@ -5,8 +5,10 @@
"indent": 2, "indent": 2,
"undef": true, "undef": true,
"quotmark": "single", "quotmark": "single",
"maxlen": 80, "maxlen": 150,
"trailing": true, "trailing": true,
"newcap": true, "newcap": true,
"nonew": true "nonew": true,
"laxcomma": true,
"laxbreak": true
} }

View File

@ -30,8 +30,11 @@ module.exports = function(grunt) {
gruntfile: { gruntfile: {
src: 'Gruntfile.js' src: 'Gruntfile.js'
}, },
lib_test: { lib: {
src: ['lib/**/*.js', 'test/**/*.js'] src: ['lib/**/*.js']
},
test: {
src: ['test/**/*.js']
} }
}, },
watch: { watch: {
@ -39,9 +42,13 @@ module.exports = function(grunt) {
files: '<%= jshint.gruntfile.src %>', files: '<%= jshint.gruntfile.src %>',
tasks: ['jshint:gruntfile'] tasks: ['jshint:gruntfile']
}, },
lib_test: { lib: {
files: '<%= jshint.lib_test.src %>', files: ['<%= jshint.lib.src %>'],
tasks: ['jshint:lib_test'] tasks: ['jshint:lib']
},
test: {
files: ['<%= jshint.test.src %>'],
tasks: ['jshint:test']
} }
}, },
browserify: { browserify: {
@ -104,7 +111,7 @@ module.exports = function(grunt) {
// list of files to exclude // list of files to exclude
exclude: [ exclude: [
], ],
// test results reporter to use // test results reporter to use

View File

@ -39,15 +39,15 @@ function AccessContext(context) {
this.sharedMethod = context.sharedMethod; this.sharedMethod = context.sharedMethod;
this.sharedClass = this.sharedMethod && this.sharedMethod.sharedClass; this.sharedClass = this.sharedMethod && this.sharedMethod.sharedClass;
if(this.sharedMethod) { if(this.sharedMethod) {
this.methodNames = this.sharedMethod.aliases.concat([this.sharedMethod.name]); this.methodNames = this.sharedMethod.aliases.concat([this.sharedMethod.name]);
} else { } else {
this.methodNames = []; this.methodNames = [];
} }
if(this.sharedMethod) { if(this.sharedMethod) {
this.accessType = this.model._getAccessTypeForMethod(this.sharedMethod); this.accessType = this.model._getAccessTypeForMethod(this.sharedMethod);
} }
this.accessType = context.accessType || AccessContext.ALL; this.accessType = context.accessType || AccessContext.ALL;
assert(loopback.AccessToken, assert(loopback.AccessToken,
'AccessToken model must be defined before AccessContext model'); 'AccessToken model must be defined before AccessContext model');
@ -157,9 +157,9 @@ AccessContext.prototype.debug = function() {
if(debug.enabled) { if(debug.enabled) {
debug('---AccessContext---'); debug('---AccessContext---');
if(this.principals && this.principals.length) { if(this.principals && this.principals.length) {
debug('principals:') debug('principals:');
this.principals.forEach(function(principal) { this.principals.forEach(function(principal) {
debug('principal: %j', principal) debug('principal: %j', principal);
}); });
} else { } else {
debug('principals: %j', this.principals); debug('principals: %j', this.principals);
@ -170,14 +170,14 @@ AccessContext.prototype.debug = function() {
debug('method %s', this.method); debug('method %s', this.method);
debug('accessType %s', this.accessType); debug('accessType %s', this.accessType);
if(this.accessToken) { if(this.accessToken) {
debug('accessToken:') debug('accessToken:');
debug(' id %j', this.accessToken.id); debug(' id %j', this.accessToken.id);
debug(' ttl %j', this.accessToken.ttl); debug(' ttl %j', this.accessToken.ttl);
} }
debug('getUserId() %s', this.getUserId()); debug('getUserId() %s', this.getUserId());
debug('isAuthenticated() %s', this.isAuthenticated()); debug('isAuthenticated() %s', this.isAuthenticated());
} }
} };
/** /**
* This class represents the abstract notion of a principal, which can be used * This class represents the abstract notion of a principal, which can be used
@ -273,17 +273,17 @@ AccessRequest.prototype.exactlyMatches = function(acl) {
} }
return false; return false;
} };
/** /**
* Is the request for access allowed? * Is the request for access allowed?
* *
* @returns {Boolean} * @returns {Boolean}
*/ */
AccessRequest.prototype.isAllowed = function() { AccessRequest.prototype.isAllowed = function() {
return this.permission !== loopback.ACL.DENY; return this.permission !== loopback.ACL.DENY;
} };
AccessRequest.prototype.debug = function() { AccessRequest.prototype.debug = function() {
if(debug.enabled) { if(debug.enabled) {
@ -295,7 +295,7 @@ AccessRequest.prototype.debug = function() {
debug(' isWildcard() %s', this.isWildcard()); debug(' isWildcard() %s', this.isWildcard());
debug(' isAllowed() %s', this.isAllowed()); debug(' isAllowed() %s', this.isAllowed());
} }
} };
module.exports.AccessContext = AccessContext; module.exports.AccessContext = AccessContext;
module.exports.Principal = Principal; module.exports.Principal = Principal;

View File

@ -14,22 +14,22 @@ var DataSource = require('loopback-datasource-juggler').DataSource
/** /**
* The `App` object represents a Loopback application. * The `App` object represents a Loopback application.
* *
* The App object extends [Express](http://expressjs.com/api.html#express) and * The App object extends [Express](http://expressjs.com/api.html#express) and
* supports Express middleware. See * supports Express middleware. See
* [Express documentation](http://expressjs.com/) for details. * [Express documentation](http://expressjs.com/) for details.
* *
* ```js * ```js
* var loopback = require('loopback'); * var loopback = require('loopback');
* var app = loopback(); * var app = loopback();
* *
* app.get('/', function(req, res){ * app.get('/', function(req, res){
* res.send('hello world'); * res.send('hello world');
* }); * });
* *
* app.listen(3000); * app.listen(3000);
* ``` * ```
* *
* @class LoopBackApplication * @class LoopBackApplication
* @header var app = loopback() * @header var app = loopback()
*/ */
@ -59,10 +59,10 @@ app.remotes = function () {
if(this.get) { if(this.get) {
options = this.get('remoting'); options = this.get('remoting');
} }
return (this._remotes = RemoteObjects.create(options)); return (this._remotes = RemoteObjects.create(options));
} }
} };
/*! /*!
* Remove a route by reference. * Remove a route by reference.
@ -76,7 +76,7 @@ app.disuse = function (route) {
} }
} }
} }
} };
/** /**
* Attach a model to the app. The `Model` will be available on the * Attach a model to the app. The `Model` will be available on the
@ -92,7 +92,7 @@ app.disuse = function (route) {
* var User = loopback.User; * var User = loopback.User;
* app.model(User, { dataSource: 'db' }); * app.model(User, { dataSource: 'db' });
*``` *```
* *
* @param {Object|String} Model The model to attach. * @param {Object|String} Model The model to attach.
* @options {Object} config The model's configuration. * @options {Object} config The model's configuration.
* @property {String|DataSource} dataSource The `DataSource` to which to attach the model. * @property {String|DataSource} dataSource The `DataSource` to which to attach the model.
@ -207,7 +207,7 @@ app.model = function (Model, config) {
app.models = function () { app.models = function () {
return this._models || (this._models = []); return this._models || (this._models = []);
} };
/** /**
* Define a DataSource. * Define a DataSource.
@ -221,7 +221,7 @@ app.dataSource = function (name, config) {
this.dataSources[classify(name)] = this.dataSources[classify(name)] =
this.dataSources[camelize(name)] = ds; this.dataSources[camelize(name)] = ds;
return ds; return ds;
} };
/** /**
* Register a connector. * Register a connector.
@ -254,30 +254,30 @@ app.remoteObjects = function () {
this.remotes().classes().forEach(function(sharedClass) { this.remotes().classes().forEach(function(sharedClass) {
result[sharedClass.name] = sharedClass.ctor; result[sharedClass.name] = sharedClass.ctor;
}); });
return result; return result;
} };
/*! /*!
* Get a handler of the specified type from the handler cache. * Get a handler of the specified type from the handler cache.
* @triggers `mounted` events on shared class constructors (models) * @triggers `mounted` events on shared class constructors (models)
*/ */
app.handler = function (type, options) { app.handler = function (type, options) {
var handlers = this._handlers || (this._handlers = {}); var handlers = this._handlers || (this._handlers = {});
if(handlers[type]) { if(handlers[type]) {
return handlers[type]; return handlers[type];
} }
var remotes = this.remotes(); var remotes = this.remotes();
var handler = this._handlers[type] = remotes.handler(type, options); var handler = this._handlers[type] = remotes.handler(type, options);
remotes.classes().forEach(function(sharedClass) { remotes.classes().forEach(function(sharedClass) {
sharedClass.ctor.emit('mounted', app, sharedClass, remotes); sharedClass.ctor.emit('mounted', app, sharedClass, remotes);
}); });
return handler; return handler;
} };
/** /**
* An object to store dataSource instances. * An object to store dataSource instances.
@ -342,7 +342,7 @@ app.enableAuth = function() {
app.boot = function(options) { app.boot = function(options) {
throw new Error( throw new Error(
'`app.boot` was removed, use the new module loopback-boot instead'); '`app.boot` was removed, use the new module loopback-boot instead');
} };
function classify(str) { function classify(str) {
return stringUtils.classify(str); return stringUtils.classify(str);
@ -355,7 +355,7 @@ function camelize(str) {
function dataSourcesFromConfig(config, connectorRegistry) { function dataSourcesFromConfig(config, connectorRegistry) {
var connectorPath; var connectorPath;
assert(typeof config === 'object', assert(typeof config === 'object',
'cannont create data source without config object'); 'cannont create data source without config object');
if(typeof config.connector === 'string') { if(typeof config.connector === 'string') {
@ -459,7 +459,7 @@ app.listen = function(cb) {
}); });
var useAppConfig = var useAppConfig =
arguments.length == 0 || arguments.length === 0 ||
(arguments.length == 1 && typeof arguments[0] == 'function'); (arguments.length == 1 && typeof arguments[0] == 'function');
if (useAppConfig) { if (useAppConfig) {
@ -469,4 +469,4 @@ app.listen = function(cb) {
} }
return server; return server;
} };

View File

@ -7,13 +7,13 @@ module.exports = Connector;
/** /**
* Module dependencies. * Module dependencies.
*/ */
var EventEmitter = require('events').EventEmitter var EventEmitter = require('events').EventEmitter
, debug = require('debug')('connector') , debug = require('debug')('connector')
, util = require('util') , util = require('util')
, inherits = util.inherits , inherits = util.inherits
, assert = require('assert'); , assert = require('assert');
/** /**
* Create a new `Connector` with the given `options`. * Create a new `Connector` with the given `options`.
* *
@ -24,7 +24,7 @@ var EventEmitter = require('events').EventEmitter
function Connector(options) { function Connector(options) {
EventEmitter.apply(this, arguments); EventEmitter.apply(this, arguments);
this.options = options; this.options = options;
debug('created with options', options); debug('created with options', options);
} }
@ -43,12 +43,12 @@ Connector._createJDBAdapter = function (jdbModule) {
jdbModule.initialize(fauxSchema, function () { jdbModule.initialize(fauxSchema, function () {
// connected // connected
}); });
} };
/*! /*!
* Add default crud operations from a JugglingDB adapter. * Add default crud operations from a JugglingDB adapter.
*/ */
Connector.prototype._addCrudOperationsFromJDBAdapter = function (connector) { Connector.prototype._addCrudOperationsFromJDBAdapter = function (connector) {
} };

View File

@ -5,7 +5,7 @@
var mailer = require('nodemailer') var mailer = require('nodemailer')
, assert = require('assert') , assert = require('assert')
, debug = require('debug')('loopback:connector:mail') , debug = require('debug')('loopback:connector:mail')
, loopback = require('../loopback') , loopback = require('../loopback');
/** /**
* Export the MailConnector class. * Export the MailConnector class.
@ -44,7 +44,7 @@ function MailConnector(settings) {
MailConnector.initialize = function(dataSource, callback) { MailConnector.initialize = function(dataSource, callback) {
dataSource.connector = new MailConnector(dataSource.settings); dataSource.connector = new MailConnector(dataSource.settings);
callback(); callback();
} };
MailConnector.prototype.DataAccessObject = Mailer; MailConnector.prototype.DataAccessObject = Mailer;
@ -86,7 +86,7 @@ MailConnector.prototype.setupTransport = function(setting) {
connector.transportsIndex[setting.type] = transport; connector.transportsIndex[setting.type] = transport;
connector.transports.push(transport); connector.transports.push(transport);
} };
function Mailer() { function Mailer() {
@ -101,7 +101,7 @@ function Mailer() {
MailConnector.prototype.transportForName = function(name) { MailConnector.prototype.transportForName = function(name) {
return this.transportsIndex[name]; return this.transportsIndex[name];
} };
/** /**
* Get the default transport. * Get the default transport.
@ -111,7 +111,7 @@ MailConnector.prototype.transportForName = function(name) {
MailConnector.prototype.defaultTransport = function() { MailConnector.prototype.defaultTransport = function() {
return this.transports[0] || this.stubTransport; return this.transports[0] || this.stubTransport;
} };
/** /**
* Send an email with the given `options`. * Send an email with the given `options`.
@ -166,7 +166,7 @@ Mailer.send = function (options, fn) {
fn(null, options); fn(null, options);
}); });
} }
} };
/** /**
* Send an email instance using `modelInstance.send()`. * Send an email instance using `modelInstance.send()`.
@ -174,7 +174,7 @@ Mailer.send = function (options, fn) {
Mailer.prototype.send = function (fn) { Mailer.prototype.send = function (fn) {
this.constructor.send(this, fn); this.constructor.send(this, fn);
} };
/** /**
* Access the node mailer object. * Access the node mailer object.

View File

@ -7,14 +7,14 @@ module.exports = Memory;
/** /**
* Module dependencies. * Module dependencies.
*/ */
var Connector = require('./base-connector') var Connector = require('./base-connector')
, debug = require('debug')('memory') , debug = require('debug')('memory')
, util = require('util') , util = require('util')
, inherits = util.inherits , inherits = util.inherits
, assert = require('assert') , assert = require('assert')
, JdbMemory = require('loopback-datasource-juggler/lib/connectors/memory'); , JdbMemory = require('loopback-datasource-juggler/lib/connectors/memory');
/** /**
* Create a new `Memory` connector with the given `options`. * Create a new `Memory` connector with the given `options`.
* *

View File

@ -20,20 +20,20 @@ function createMiddlewareNotInstalled(memberName, moduleName) {
} }
var middlewareModules = { var middlewareModules = {
"compress": "compression", 'compress': 'compression',
"timeout": "connect-timeout", 'timeout': 'connect-timeout',
"cookieParser": "cookie-parser", 'cookieParser': 'cookie-parser',
"cookieSession": "cookie-session", 'cookieSession': 'cookie-session',
"csrf": "csurf", 'csrf': 'csurf',
"errorHandler": "errorhandler", 'errorHandler': 'errorhandler',
"session": "express-session", 'session': 'express-session',
"methodOverride": "method-override", 'methodOverride': 'method-override',
"logger": "morgan", 'logger': 'morgan',
"responseTime": "response-time", 'responseTime': 'response-time',
"favicon": "serve-favicon", 'favicon': 'serve-favicon',
"directory": "serve-index", 'directory': 'serve-index',
// "static": "serve-static", // 'static': 'serve-static',
"vhost": "vhost" 'vhost': 'vhost'
}; };
middlewares.bodyParser = safeRequire('body-parser'); middlewares.bodyParser = safeRequire('body-parser');

View File

@ -14,7 +14,7 @@ module.exports = status;
* "uptime": 9.394 * "uptime": 9.394
* } * }
* ``` * ```
* *
* @header loopback.status() * @header loopback.status()
*/ */
function status() { function status() {
@ -25,6 +25,6 @@ function status() {
started: started, started: started,
uptime: (Date.now() - Number(started)) / 1000 uptime: (Date.now() - Number(started)) / 1000
}); });
} };
} }

View File

@ -11,22 +11,22 @@ var assert = require('assert');
module.exports = token; module.exports = token;
/** /**
* Check for an access token in cookies, headers, and query string parameters. * Check for an access token in cookies, headers, and query string parameters.
* This function always checks for the following: * This function always checks for the following:
* *
* - `access_token` (params only) * - `access_token` (params only)
* - `X-Access-Token` (headers only) * - `X-Access-Token` (headers only)
* - `authorization` (headers and cookies) * - `authorization` (headers and cookies)
* *
* It checks for these values in cookies, headers, and query string parameters _in addition_ to the items * It checks for these values in cookies, headers, and query string parameters _in addition_ to the items
* specified in the options parameter. * specified in the options parameter.
* *
* **NOTE:** This function only checks for [signed cookies](http://expressjs.com/api.html#req.signedCookies). * **NOTE:** This function only checks for [signed cookies](http://expressjs.com/api.html#req.signedCookies).
* *
* The following example illustrates how to check for an `accessToken` in a custom cookie, query string parameter * The following example illustrates how to check for an `accessToken` in a custom cookie, query string parameter
* and header called `foo-auth`. * and header called `foo-auth`.
* *
* ```js * ```js
* app.use(loopback.token({ * app.use(loopback.token({
* cookies: ['foo-auth'], * cookies: ['foo-auth'],
@ -47,13 +47,13 @@ function token(options) {
options = options || {}; options = options || {};
var TokenModel = options.model || loopback.AccessToken; var TokenModel = options.model || loopback.AccessToken;
assert(TokenModel, 'loopback.token() middleware requires a AccessToken model'); assert(TokenModel, 'loopback.token() middleware requires a AccessToken model');
return function (req, res, next) { return function (req, res, next) {
if (req.accessToken !== undefined) return next(); if (req.accessToken !== undefined) return next();
TokenModel.findForRequest(req, options, function(err, token) { TokenModel.findForRequest(req, options, function(err, token) {
req.accessToken = token || null; req.accessToken = token || null;
next(err); next(err);
}); });
} };
} }

View File

@ -15,5 +15,5 @@ function urlNotFound() {
var error = new Error('Cannot ' + req.method + ' ' + req.url); var error = new Error('Cannot ' + req.method + ' ' + req.url);
error.status = 404; error.status = 404;
next(error); next(error);
} };
} }

View File

@ -9,7 +9,7 @@ var extend = require('util')._extend;
var stringUtils = require('underscore.string'); var stringUtils = require('underscore.string');
/** /**
* The base class for **all models**. * The base class for **all models**.
* *
* **Inheriting from `Model`** * **Inheriting from `Model`**
* *
@ -18,7 +18,7 @@ var stringUtils = require('underscore.string');
* var options = {...}; * var options = {...};
* var MyModel = loopback.Model.extend('MyModel', properties, options); * var MyModel = loopback.Model.extend('MyModel', properties, options);
* ``` * ```
* *
* **Options** * **Options**
* *
* - `trackChanges` - If true, changes to the model will be tracked. **Required * - `trackChanges` - If true, changes to the model will be tracked. **Required
@ -27,7 +27,7 @@ var stringUtils = require('underscore.string');
* **Events** * **Events**
* *
* #### Event: `changed` * #### Event: `changed`
* *
* Emitted after a model has been successfully created, saved, or updated. * Emitted after a model has been successfully created, saved, or updated.
* Argument: `inst`, model instance, object * Argument: `inst`, model instance, object
* *
@ -37,10 +37,10 @@ var stringUtils = require('underscore.string');
* // => model with id 1 has been changed * // => model with id 1 has been changed
* }); * });
* ``` * ```
* *
* #### Event: `deleted` * #### Event: `deleted`
* *
* Emitted after an individual model has been deleted. * Emitted after an individual model has been deleted.
* Argument: `id`, model ID (number). * Argument: `id`, model ID (number).
* *
* ```js * ```js
@ -51,7 +51,7 @@ var stringUtils = require('underscore.string');
* ``` * ```
* *
* #### Event: `deletedAll` * #### Event: `deletedAll`
* *
* Emitted after an individual model has been deleted. * Emitted after an individual model has been deleted.
* Argument: `where` (optional), where filter, JSON object. * Argument: `where` (optional), where filter, JSON object.
* *
@ -65,27 +65,27 @@ var stringUtils = require('underscore.string');
* } * }
* }); * });
* ``` * ```
* *
* #### Event: `attached` * #### Event: `attached`
* *
* Emitted after a `Model` has been attached to an `app`. * Emitted after a `Model` has been attached to an `app`.
* *
* #### Event: `dataSourceAttached` * #### Event: `dataSourceAttached`
* *
* Emitted after a `Model` has been attached to a `DataSource`. * Emitted after a `Model` has been attached to a `DataSource`.
* *
* #### Event: set * #### Event: set
* *
* Emitted when model property is set. * Emitted when model property is set.
* Argument: `inst`, model instance, object * Argument: `inst`, model instance, object
* *
* ```js * ```js
* MyModel.on('set', function(inst) { * MyModel.on('set', function(inst) {
* console.log('model with id %s has been changed', inst.id); * console.log('model with id %s has been changed', inst.id);
* // => model with id 1 has been changed * // => model with id 1 has been changed
* }); * });
* ``` * ```
* *
* @param {Object} data * @param {Object} data
* @property {String} modelName The name of the model. Static property. * @property {String} modelName The name of the model. Static property.
* @property {DataSource} dataSource Data source to which the model is connected, if any. Static property. * @property {DataSource} dataSource Data source to which the model is connected, if any. Static property.
@ -128,7 +128,7 @@ Model.setup = function () {
id = null; id = null;
} else if (typeof id === 'function') { } else if (typeof id === 'function') {
fn = id; fn = id;
if(typeof data !== 'object') { if(typeof data !== 'object') {
id = data; id = data;
data = null; data = null;
@ -136,7 +136,7 @@ Model.setup = function () {
id = null; id = null;
} }
} }
if(id && data) { if(id && data) {
var model = new ModelCtor(data); var model = new ModelCtor(data);
model.id = id; model.id = id;
@ -152,14 +152,14 @@ Model.setup = function () {
} else { } else {
err = new Error('could not find a model with id ' + id); err = new Error('could not find a model with id ' + id);
err.statusCode = 404; err.statusCode = 404;
fn(err); fn(err);
} }
}); });
} else { } else {
fn(new Error('must specify an id or data')); fn(new Error('must specify an id or data'));
} }
} };
var idDesc = ModelCtor.modelName + ' id'; var idDesc = ModelCtor.modelName + ' id';
ModelCtor.sharedCtor.accepts = [ ModelCtor.sharedCtor.accepts = [
@ -171,7 +171,7 @@ Model.setup = function () {
ModelCtor.sharedCtor.http = [ ModelCtor.sharedCtor.http = [
{path: '/:id'} {path: '/:id'}
]; ];
ModelCtor.sharedCtor.returns = {root: true}; ModelCtor.sharedCtor.returns = {root: true};
// before remote hook // before remote hook
@ -190,7 +190,7 @@ Model.setup = function () {
}); });
} }
}; };
// after remote hook // after remote hook
ModelCtor.afterRemote = function (name, fn) { ModelCtor.afterRemote = function (name, fn) {
var self = this; var self = this;
@ -280,7 +280,7 @@ Model.checkAccess = function(token, modelId, sharedMethod, ctx, callback) {
callback = ctx; callback = ctx;
ctx = {}; ctx = {};
} }
aclModel.checkAccessForContext({ aclModel.checkAccessForContext({
accessToken: token, accessToken: token,
model: this, model: this,
@ -308,7 +308,7 @@ Model._getAccessTypeForMethod = function(method) {
method = {name: method}; method = {name: method};
} }
assert( assert(
typeof method === 'object', typeof method === 'object',
'method is a required argument and must be a RemoteMethod object' 'method is a required argument and must be a RemoteMethod object'
); );
@ -340,7 +340,7 @@ Model._getAccessTypeForMethod = function(method) {
default: default:
return ACL.EXECUTE; return ACL.EXECUTE;
} }
} };
/** /**
* Get the `Application` the Model is attached to. * Get the `Application` the Model is attached to.
@ -361,7 +361,7 @@ Model.getApp = function(callback) {
callback(null, Model.app); callback(null, Model.app);
}); });
} }
} };
/** /**
* Enable remote invocation for the method with the given name. * Enable remote invocation for the method with the given name.
@ -382,7 +382,7 @@ Model.remoteMethod = function(name, options) {
options.isStatic = true; options.isStatic = true;
} }
this.sharedClass.defineMethod(name, options); this.sharedClass.defineMethod(name, options);
} };
/** /**
* Disable remote invocation for the method with the given name. * Disable remote invocation for the method with the given name.
@ -395,7 +395,7 @@ Model.remoteMethod = function(name, options) {
Model.disableRemoteMethod = function(name, isStatic) { Model.disableRemoteMethod = function(name, isStatic) {
this.sharedClass.disableMethod(name, isStatic || false); this.sharedClass.disableMethod(name, isStatic || false);
} };
Model.belongsToRemoting = function(relationName, relation, define) { Model.belongsToRemoting = function(relationName, relation, define) {
var modelName = relation.modelTo && relation.modelTo.modelName; var modelName = relation.modelTo && relation.modelTo.modelName;
@ -409,7 +409,7 @@ Model.belongsToRemoting = function(relationName, relation, define) {
description: 'Fetches belongsTo relation ' + relationName, description: 'Fetches belongsTo relation ' + relationName,
returns: {arg: relationName, type: modelName, root: true} returns: {arg: relationName, type: modelName, root: true}
}, fn); }, fn);
} };
Model.hasOneRemoting = function(relationName, relation, define) { Model.hasOneRemoting = function(relationName, relation, define) {
var fn = this.prototype[relationName]; var fn = this.prototype[relationName];
@ -421,22 +421,22 @@ Model.hasOneRemoting = function(relationName, relation, define) {
description: 'Fetches hasOne relation ' + relationName, description: 'Fetches hasOne relation ' + relationName,
returns: {arg: relationName, type: relation.modelTo.modelName, root: true} returns: {arg: relationName, type: relation.modelTo.modelName, root: true}
}, fn); }, fn);
} };
Model.hasManyRemoting = function (relationName, relation, define) { Model.hasManyRemoting = function (relationName, relation, define) {
var pathName = (relation.options.http && relation.options.http.path) || relationName; var pathName = (relation.options.http && relation.options.http.path) || relationName;
var toModelName = relation.modelTo.modelName; var toModelName = relation.modelTo.modelName;
function convertNullToNotFoundError(ctx, cb) { function convertNullToNotFoundError(ctx, cb) {
if (ctx.result !== null) return cb(); if (ctx.result !== null) return cb();
var fk = ctx.getArgByName('fk'); var fk = ctx.getArgByName('fk');
var msg = 'Unknown "' + toModelName + '" id "' + fk + '".'; var msg = 'Unknown "' + toModelName + '" id "' + fk + '".';
var error = new Error(msg); var error = new Error(msg);
error.statusCode = error.status = 404; error.statusCode = error.status = 404;
cb(error); cb(error);
} }
var findByIdFunc = this.prototype['__findById__' + relationName]; var findByIdFunc = this.prototype['__findById__' + relationName];
define('__findById__' + relationName, { define('__findById__' + relationName, {
isStatic: false, isStatic: false,
@ -568,9 +568,9 @@ Model.scopeRemoting = function(scopeName, scope, define) {
http: {verb: 'get', path: '/' + pathName + '/count'}, http: {verb: 'get', path: '/' + pathName + '/count'},
accepts: {arg: 'where', type: 'object', description: 'Criteria to match model instances'}, accepts: {arg: 'where', type: 'object', description: 'Criteria to match model instances'},
description: 'Counts ' + scopeName + ' of ' + this.modelName + '.', description: 'Counts ' + scopeName + ' of ' + this.modelName + '.',
returns: {arg: 'count', type: 'number'} returns: {arg: 'count', type: 'number'}
}); });
}; };
Model.nestRemoting = function(relationName, options, cb) { Model.nestRemoting = function(relationName, options, cb) {
@ -579,7 +579,7 @@ Model.nestRemoting = function(relationName, options, cb) {
options = {}; options = {};
} }
options = options || {}; options = options || {};
var regExp = /^__([^_]+)__([^_]+)$/; var regExp = /^__([^_]+)__([^_]+)$/;
var relation = this.relations[relationName]; var relation = this.relations[relationName];
if (relation && relation.modelTo && relation.modelTo.sharedClass) { if (relation && relation.modelTo && relation.modelTo.sharedClass) {
@ -587,17 +587,17 @@ Model.nestRemoting = function(relationName, options, cb) {
var sharedClass = this.sharedClass; var sharedClass = this.sharedClass;
var sharedToClass = relation.modelTo.sharedClass; var sharedToClass = relation.modelTo.sharedClass;
var toModelName = relation.modelTo.modelName; var toModelName = relation.modelTo.modelName;
var pathName = options.pathName || relation.options.path || relationName; var pathName = options.pathName || relation.options.path || relationName;
var paramName = options.paramName || 'nk'; var paramName = options.paramName || 'nk';
var http = [].concat(sharedToClass.http || [])[0]; var http = [].concat(sharedToClass.http || [])[0];
if (relation.multiple) { if (relation.multiple) {
var httpPath = pathName + '/:' + paramName; var httpPath = pathName + '/:' + paramName;
var acceptArgs = [ var acceptArgs = [
{ {
arg: paramName, type: 'any', http: { source: 'path' }, arg: paramName, type: 'any', http: { source: 'path' },
description: 'Foreign key for ' + relation.name, description: 'Foreign key for ' + relation.name,
required: true required: true
} }
@ -606,7 +606,7 @@ Model.nestRemoting = function(relationName, options, cb) {
var httpPath = pathName; var httpPath = pathName;
var acceptArgs = []; var acceptArgs = [];
} }
// A method should return the method name to use, if it is to be // A method should return the method name to use, if it is to be
// included as a nested method - a falsy return value will skip. // included as a nested method - a falsy return value will skip.
var filter = cb || options.filterMethod || function(method, relation) { var filter = cb || options.filterMethod || function(method, relation) {
@ -615,31 +615,31 @@ Model.nestRemoting = function(relationName, options, cb) {
return '__' + matches[1] + '__' + relation.name + '__' + matches[2]; return '__' + matches[1] + '__' + relation.name + '__' + matches[2];
} }
}; };
sharedToClass.methods().forEach(function(method) { sharedToClass.methods().forEach(function(method) {
var methodName; var methodName;
if (!method.isStatic && (methodName = filter(method, relation))) { if (!method.isStatic && (methodName = filter(method, relation))) {
var prefix = relation.multiple ? '__findById__' : '__get__'; var prefix = relation.multiple ? '__findById__' : '__get__';
var getterName = options.getterName || (prefix + relationName); var getterName = options.getterName || (prefix + relationName);
var getterFn = relation.modelFrom.prototype[getterName]; var getterFn = relation.modelFrom.prototype[getterName];
if (typeof getterFn !== 'function') { if (typeof getterFn !== 'function') {
throw new Error('Invalid remote method: `' + getterName + '`'); throw new Error('Invalid remote method: `' + getterName + '`');
} }
var nestedFn = relation.modelTo.prototype[method.name]; var nestedFn = relation.modelTo.prototype[method.name];
if (typeof nestedFn !== 'function') { if (typeof nestedFn !== 'function') {
throw new Error('Invalid remote method: `' + method.name + '`'); throw new Error('Invalid remote method: `' + method.name + '`');
} }
var opts = {}; var opts = {};
opts.accepts = acceptArgs.concat(method.accepts || []); opts.accepts = acceptArgs.concat(method.accepts || []);
opts.returns = [].concat(method.returns || []); opts.returns = [].concat(method.returns || []);
opts.description = method.description; opts.description = method.description;
opts.rest = extend({}, method.rest || {}); opts.rest = extend({}, method.rest || {});
opts.rest.delegateTo = method.name; opts.rest.delegateTo = method.name;
opts.http = []; opts.http = [];
var routes = [].concat(method.http || []); var routes = [].concat(method.http || []);
routes.forEach(function(route) { routes.forEach(function(route) {
@ -649,7 +649,7 @@ Model.nestRemoting = function(relationName, options, cb) {
opts.http.push(copy); opts.http.push(copy);
} }
}); });
if (relation.multiple) { if (relation.multiple) {
sharedClass.defineMethod(methodName, opts, function(fkId) { sharedClass.defineMethod(methodName, opts, function(fkId) {
var args = Array.prototype.slice.call(arguments, 1); var args = Array.prototype.slice.call(arguments, 1);
@ -681,17 +681,17 @@ Model.nestRemoting = function(relationName, options, cb) {
} }
} }
}); });
if (options.hooks === false) return; // don't inherit before/after hooks if (options.hooks === false) return; // don't inherit before/after hooks
self.once('mounted', function(app, sc, remotes) { self.once('mounted', function(app, sc, remotes) {
var listenerTree = extend({}, remotes.listenerTree || {}); var listenerTree = extend({}, remotes.listenerTree || {});
listenerTree.before = listenerTree.before || {}; listenerTree.before = listenerTree.before || {};
listenerTree.after = listenerTree.after || {}; listenerTree.after = listenerTree.after || {};
var beforeListeners = remotes.listenerTree.before[toModelName] || {}; var beforeListeners = remotes.listenerTree.before[toModelName] || {};
var afterListeners = remotes.listenerTree.after[toModelName] || {}; var afterListeners = remotes.listenerTree.after[toModelName] || {};
sharedClass.methods().forEach(function(method) { sharedClass.methods().forEach(function(method) {
var delegateTo = method.rest && method.rest.delegateTo; var delegateTo = method.rest && method.rest.delegateTo;
if (delegateTo) { if (delegateTo) {
@ -711,7 +711,7 @@ Model.nestRemoting = function(relationName, options, cb) {
} }
}); });
}); });
} else { } else {
throw new Error('Relation `' + relationName + '` does not exist for model `' + this.modelName + '`'); throw new Error('Relation `' + relationName + '` does not exist for model `' + this.modelName + '`');
} }

View File

@ -43,9 +43,9 @@ PersistedModel.setup = function setupPersistedModel() {
PersistedModel.enableChangeTracking(); PersistedModel.enableChangeTracking();
}); });
} }
PersistedModel.setupRemoting(); PersistedModel.setupRemoting();
} };
/*! /*!
* Throw an error telling the user that the method is not available and why. * Throw an error telling the user that the method is not available and why.
@ -260,7 +260,7 @@ PersistedModel.destroyById = function deleteById(id, cb) {
/** /**
* Alias for destroyById. * Alias for destroyById.
*/ */
PersistedModel.removeById = PersistedModel.destroyById PersistedModel.removeById = PersistedModel.destroyById;
/** /**
* Alias for destroyById. * Alias for destroyById.
@ -338,7 +338,7 @@ PersistedModel.prototype.save = function (options, callback) {
// then save // then save
function save() { function save() {
inst.trigger('save', function (saveDone) { inst.trigger('save', function (saveDone) {
inst.trigger('update', function (updateDone) { inst.trigger('update', function (updateDone) {
Model.upsert(inst, function(err) { Model.upsert(inst, function(err) {
inst._initProperties(data); inst._initProperties(data);
updateDone.call(inst, function () { updateDone.call(inst, function () {
@ -430,7 +430,7 @@ PersistedModel.prototype.reload = function reload(callback) {
PersistedModel.prototype.setId = function(val) { PersistedModel.prototype.setId = function(val) {
var ds = this.getDataSource(); var ds = this.getDataSource();
this[this.getIdName()] = val; this[this.getIdName()] = val;
} };
/** /**
* Get the `id` value for the `PersistedModel`. * Get the `id` value for the `PersistedModel`.
@ -442,7 +442,7 @@ PersistedModel.prototype.getId = function() {
var data = this.toObject(); var data = this.toObject();
if(!data) return; if(!data) return;
return data[this.getIdName()]; return data[this.getIdName()];
} };
/** /**
* Get the id property name of the constructor. * Get the id property name of the constructor.
@ -452,7 +452,7 @@ PersistedModel.prototype.getId = function() {
PersistedModel.prototype.getIdName = function() { PersistedModel.prototype.getIdName = function() {
return this.constructor.getIdName(); return this.constructor.getIdName();
} };
/** /**
* Get the id property name of the constructor. * Get the id property name of the constructor.
@ -469,7 +469,7 @@ PersistedModel.getIdName = function() {
} else { } else {
return 'id'; return 'id';
} }
} };
PersistedModel.setupRemoting = function() { PersistedModel.setupRemoting = function() {
var PersistedModel = this; var PersistedModel = this;
@ -597,7 +597,7 @@ PersistedModel.setupRemoting = function() {
{arg: 'since', type: 'number', description: 'Find deltas since this checkpoint'}, {arg: 'since', type: 'number', description: 'Find deltas since this checkpoint'},
{arg: 'remoteChanges', type: 'array', description: 'an array of change objects', {arg: 'remoteChanges', type: 'array', description: 'an array of change objects',
http: {source: 'body'}} http: {source: 'body'}}
], ],
returns: {arg: 'result', type: 'object', root: true}, returns: {arg: 'result', type: 'object', root: true},
http: {verb: 'post', path: '/diff'} http: {verb: 'post', path: '/diff'}
}); });
@ -612,7 +612,7 @@ PersistedModel.setupRemoting = function() {
returns: {arg: 'changes', type: 'array', root: true}, returns: {arg: 'changes', type: 'array', root: true},
http: {verb: 'get', path: '/changes'} http: {verb: 'get', path: '/changes'}
}); });
setRemoting(PersistedModel, 'checkpoint', { setRemoting(PersistedModel, 'checkpoint', {
description: 'Create a checkpoint.', description: 'Create a checkpoint.',
returns: {arg: 'checkpoint', type: 'object', root: true}, returns: {arg: 'checkpoint', type: 'object', root: true},
@ -649,22 +649,22 @@ PersistedModel.setupRemoting = function() {
http: {verb: 'post', path: '/:id/rectify-change'} http: {verb: 'post', path: '/:id/rectify-change'}
}); });
} }
} };
/** /**
* Get a set of deltas and conflicts since the given checkpoint. * Get a set of deltas and conflicts since the given checkpoint.
* *
* See `Change.diff()` for details. * See `Change.diff()` for details.
* *
* @param {Number} since Find deltas since this checkpoint * @param {Number} since Find deltas since this checkpoint
* @param {Array} remoteChanges An array of change objects * @param {Array} remoteChanges An array of change objects
* @param {Function} callback * @param {Function} callback
*/ */
PersistedModel.diff = function(since, remoteChanges, callback) { PersistedModel.diff = function(since, remoteChanges, callback) {
var Change = this.getChangeModel(); var Change = this.getChangeModel();
Change.diff(this.modelName, since, remoteChanges, callback); Change.diff(this.modelName, since, remoteChanges, callback);
} };
/** /**
* Get the changes to a model since a given checkpoint. Provide a filter object * Get the changes to a model since a given checkpoint. Provide a filter object
@ -720,11 +720,11 @@ PersistedModel.changes = function(since, filter, callback) {
})); }));
}); });
}); });
} };
/** /**
* Create a checkpoint. * Create a checkpoint.
* *
* @param {Function} callback * @param {Function} callback
*/ */
@ -736,11 +736,11 @@ PersistedModel.checkpoint = function(cb) {
sourceId: sourceId sourceId: sourceId
}, cb); }, cb);
}); });
} };
/** /**
* Get the current checkpoint id. * Get the current checkpoint id.
* *
* @callback {Function} callback * @callback {Function} callback
* @param {Error} err * @param {Error} err
* @param {Number} currentCheckpointId * @param {Number} currentCheckpointId
@ -750,7 +750,7 @@ PersistedModel.checkpoint = function(cb) {
PersistedModel.currentCheckpoint = function(cb) { PersistedModel.currentCheckpoint = function(cb) {
var Checkpoint = this.getChangeModel().getCheckpointModel(); var Checkpoint = this.getChangeModel().getCheckpointModel();
Checkpoint.current(cb); Checkpoint.current(cb);
} };
/** /**
* Replicate changes since the given checkpoint to the given target model. * Replicate changes since the given checkpoint to the given target model.
@ -793,7 +793,7 @@ PersistedModel.replicate = function(since, targetModel, options, callback) {
callback = callback || function defaultReplicationCallback(err) { callback = callback || function defaultReplicationCallback(err) {
if(err) throw err; if(err) throw err;
} };
var tasks = [ var tasks = [
getSourceChanges, getSourceChanges,
@ -848,13 +848,13 @@ PersistedModel.replicate = function(since, targetModel, options, callback) {
callback && callback(null, conflicts); callback && callback(null, conflicts);
} }
} };
/** /**
* Create an update list (for `Model.bulkUpdate()`) from a delta list * Create an update list (for `Model.bulkUpdate()`) from a delta list
* (result of `Change.diff()`). * (result of `Change.diff()`).
* *
* @param {Array} deltas * @param {Array} deltas
* @param {Function} callback * @param {Function} callback
*/ */
@ -899,13 +899,13 @@ PersistedModel.createUpdates = function(deltas, cb) {
if(err) return cb(err); if(err) return cb(err);
cb(null, updates); cb(null, updates);
}); });
} };
/** /**
* Apply an update list. * Apply an update list.
* *
* **Note: this is not atomic** * **Note: this is not atomic**
* *
* @param {Array} updates An updates list (usually from Model.createUpdates()) * @param {Array} updates An updates list (usually from Model.createUpdates())
* @param {Function} callback * @param {Function} callback
*/ */
@ -937,11 +937,11 @@ PersistedModel.bulkUpdate = function(updates, callback) {
}); });
async.parallel(tasks, callback); async.parallel(tasks, callback);
} };
/** /**
* Get the `Change` model. * Get the `Change` model.
* *
* @throws {Error} Throws an error if the change model is not correctly setup. * @throws {Error} Throws an error if the change model is not correctly setup.
* @return {Change} * @return {Change}
*/ */
@ -953,11 +953,11 @@ PersistedModel.getChangeModel = function() {
assert(isSetup, 'Cannot get a setup Change model'); assert(isSetup, 'Cannot get a setup Change model');
return changeModel; return changeModel;
} };
/** /**
* Get the source identifier for this model / dataSource. * Get the source identifier for this model / dataSource.
* *
* @callback {Function} callback * @callback {Function} callback
* @param {Error} err * @param {Error} err
* @param {String} sourceId * @param {String} sourceId
@ -969,12 +969,12 @@ PersistedModel.getSourceId = function(cb) {
this.once('dataSourceAttached', this.getSourceId.bind(this, cb)); this.once('dataSourceAttached', this.getSourceId.bind(this, cb));
} }
assert( assert(
dataSource.connector.name, dataSource.connector.name,
'Model.getSourceId: cannot get id without dataSource.connector.name' 'Model.getSourceId: cannot get id without dataSource.connector.name'
); );
var id = [dataSource.connector.name, this.modelName].join('-'); var id = [dataSource.connector.name, this.modelName].join('-');
cb(null, id); cb(null, id);
} };
/** /**
* Enable the tracking of changes made to the model. Usually for replication. * Enable the tracking of changes made to the model. Usually for replication.
@ -993,11 +993,11 @@ PersistedModel.enableChangeTracking = function() {
Model.afterSave = function afterSave(next) { Model.afterSave = function afterSave(next) {
Model.rectifyChange(this.getId(), next); Model.rectifyChange(this.getId(), next);
} };
Model.afterDestroy = function afterDestroy(next) { Model.afterDestroy = function afterDestroy(next) {
Model.rectifyChange(this.getId(), next); Model.rectifyChange(this.getId(), next);
} };
Model.on('deletedAll', cleanup); Model.on('deletedAll', cleanup);
@ -1017,7 +1017,7 @@ PersistedModel.enableChangeTracking = function() {
}); });
} }
} }
} };
PersistedModel._defineChangeModel = function() { PersistedModel._defineChangeModel = function() {
var BaseChangeModel = registry.getModel('Change'); var BaseChangeModel = registry.getModel('Change');
@ -1030,11 +1030,11 @@ PersistedModel._defineChangeModel = function() {
trackModel: this trackModel: this
} }
); );
} };
PersistedModel.rectifyAllChanges = function(callback) { PersistedModel.rectifyAllChanges = function(callback) {
this.getChangeModel().rectifyAll(callback); this.getChangeModel().rectifyAll(callback);
} };
/** /**
* Handle a change error. Override this method in a subclassing model to customize * Handle a change error. Override this method in a subclassing model to customize
@ -1048,7 +1048,7 @@ PersistedModel.handleChangeError = function(err) {
console.error(Model.modelName + ' Change Tracking Error:'); console.error(Model.modelName + ' Change Tracking Error:');
console.error(err); console.error(err);
} }
} };
/** /**
* Tell loopback that a change to the model with the given id has occurred. * Tell loopback that a change to the model with the given id has occurred.
@ -1061,6 +1061,6 @@ PersistedModel.handleChangeError = function(err) {
PersistedModel.rectifyChange = function(id, callback) { PersistedModel.rectifyChange = function(id, callback) {
var Change = this.getChangeModel(); var Change = this.getChangeModel();
Change.rectifyModelChanges(this.modelName, [id], callback); Change.rectifyModelChanges(this.modelName, [id], callback);
} };
PersistedModel.setup(); PersistedModel.setup();