@balderdash/sails-edge
Version:
API-driven framework for building realtime apps, using MVC conventions (based on Express and Socket.io)
139 lines (113 loc) • 3.96 kB
JavaScript
/**
* Module dependencies.
*/
var _ = require('lodash');
// NOTE:
// Since controllers load blueprint actions by default anyways, this route syntax handler
// can be replaced with `{action: 'find'}, {action: 'create'}, ...` etc.
/**
* Expose route parser.
* @type {Function}
*/
module.exports = function (sails) {
return interpretRouteSyntax;
/**
* interpretRouteSyntax
*
* "Teach" router to understand direct references to blueprints
* as a target to sails.router.bind()
* (i.e. in the `routes.js` file)
*
* @param {[type]} route [description]
* @return {[type]} [description]
* @api private
*/
function interpretRouteSyntax (route) {
var target = route.target,
path = route.path,
verb = route.verb,
options = route.options;
// Support referencing blueprints in explicit routes
// (`{ blueprint: 'create' }` et. al.)
if (
_.isObject(target) &&
!_.isFunction(target) &&
!_.isArray(target) &&
_.isString(target.blueprint)) {
// On a match, merge leftover items in the target object into route options:
options = _.merge(options, _.omit(target, 'blueprint'));
return bindBlueprintAction(path, target.blueprint, verb, options);
}
// Ignore unknown route syntax
// If it needs to be understood by another hook, the hook would have also received
// the typeUnknown event, so we're done.
return;
}
/**
* Bind explicit route to a blueprint action.
*
* @param {[type]} path [description]
* @param {[type]} blueprintActionID [description]
* @param {[type]} verb [description]
* @param {[type]} options [description]
* @return {[type]} [description]
* @api private
*/
function bindBlueprintAction ( path, blueprintActionID, verb, options ) {
// Look up appropriate blueprint action and make sure it exists
var blueprint = sails.middleware.blueprints[blueprintActionID];
// If a 'blueprint' was specified, but it doesn't exist, warn the user and ignore it.
if ( ! ( blueprint && _.isFunction(blueprint) )) {
sails.log.error(
blueprintActionID,
':: Ignoring attempt to bind route (' + path + ') to unknown blueprint action (`'+blueprintActionID+'`).'
);
return;
}
// If a model wasn't provided with the options, try and guess it
if (!options.model) {
var matches = path.match(/^\/(\w+).*$/);
if (matches && matches[1] && sails.models[matches[1]]) {
options.model = matches[1];
}
else {
sails.log.error(
blueprintActionID,
':: Ignoring attempt to bind route (' + path + ') to blueprint action (`'+blueprintActionID+'`), but no valid model was specified and we couldn\'t guess one based on the path.'
);
return;
}
}
// If associations weren't provided with the options, try and get them
if (!options.associations) {
options = _.merge({ associations: _.cloneDeep(sails.models[options.model].associations) }, options);
}
// Otherwise make sure it's an array of strings of valid association aliases
else {
options.associations = options.associations.map(function(alias) {
if (typeof(alias) != 'string') {
sails.log.error(
blueprintActionID,
':: Ignoring invalid association option for '+path+'.'
);
return;
}
var association;
if (!(association = _.findWhere(sails.models[options.model].associations, {alias: alias}))) {
sails.log.error(
blueprintActionID,
':: Ignoring invalid association option `'+alias+'` for '+path+'.'
);
return;
}
return association;
});
}
// If "populate" wasn't provided in the options, use the default
if (typeof (options.populate) == 'undefined') {
options.populate = sails.config.blueprints.populate;
}
sails.router.bind(path, blueprint, verb, options);
return;
}
};