Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'develop'

  • Loading branch information...
commit de7553f342d8452cb5d8ce74e33d18a62a66d4b4 2 parents b4f731d + 8782b39
@aljimenez aljimenez authored
View
1  .travis.yml
@@ -1,7 +1,6 @@
language: node_js
node_js:
- "0.10"
- - "0.8"
env:
- "testtype=unit"
- "testtype=func"
View
29 HISTORY.md
@@ -1,3 +1,32 @@
+version 0.9.6
+=============
+
+Features
+--------
+
+* Clearer and more specific error messages regarding invalid mojits and exceptions.
+* Routes.json now accepts an annotations object (see [express annotations](https://github.com/yahoo/express-annotations#express-annotations)). Also the "client" annotation can be used to specify whether to expose the route to the client; by default, routes are exposed to the client.
+
+Ex. routes.json:
+
+```js
+...
+"route": {
+ "verbs": ["get"],
+ "path": "/path",
+ "call": "spec.action",
+ "annotations": {
+ "client": false
+ }
+}
+...
+```
+
+Bug Fixes
+---------
+
+* Catching any uncaught exception during binder execution. This prevents binder errors from interfering with other binders and the mojito client.
+
version 0.9.5
=============
View
2  lib/app/addons/ac/deploy.server.js
@@ -69,7 +69,7 @@ YUI.add('mojito-deploy-addon', function (Y, NAME) {
initializer, // script for YUI initialization
pathToRoot,
pageData = this.adapter && this.adapter.page && this.adapter.page.data,
- pageRoutes = this.adapter && this.adapter.page && this.adapter.page.routes,
+ pageRoutes = this.adapter && this.adapter.page && this.adapter.page.clientRoutes,
updateLoaderCount = store._updateLoaderCount,
loaderRess,
lang = this.ac.context.lang;
View
5 lib/app/addons/rs/yui.js
@@ -600,6 +600,11 @@ YUI.add('addon-rs-yui', function(Y, NAME) {
var store = this.get('host');
this._captureYUIModuleDetails(res);
+
+ if (!res.yui) {
+ // Do not add YUI resources that failed while capturing details.
+ return new Y.Do.Halt();
+ }
},
View
3  lib/app/autoload/action-context.common.js
@@ -322,7 +322,8 @@ YUI.add('mojito-action-context', function(Y, NAME) {
actionFunction = '__call';
} else {
// If there is still no joy then die
- error = new Error("No method '" + command.action + "' on controller type '" + command.instance.type + "'");
+ error = new Error('Action "' + this.action + '" not defined by the controller named "'
+ + this.instance.controller + '" of the "' + this.type + '" mojit.');
error.code = 404;
throw error;
}
View
26 lib/app/autoload/dispatch.server.js
@@ -72,11 +72,8 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
store: this.store
});
} catch (e) {
- Y.log('Error from dispatch on instance \'' +
- (command.instance.id || '@' + command.instance.type) +
- '\':', 'error', NAME);
- Y.log(e.message, 'error', NAME);
- Y.log(e.stack, 'error', NAME);
+ Y.log('Error dispatching \'' +
+ (command.instance.id || '@' + command.instance.type) + '\': \n' + e.stack, 'error', NAME);
adapter.error(e);
}
// HookSystem::StartBlock
@@ -137,35 +134,36 @@ YUI.add('mojito-dispatcher', function (Y, NAME) {
store.expandInstance(command.instance, command.context,
function (err, instance) {
+ var errorMessage;
// HookSystem::StartBlock
Y.mojito.hooks.hook('dispatch', adapter.hook, 'end', command);
// HookSystem::EndBlock
if (err || !instance || !instance.controller) {
-
- adapter.error(new Error('Cannot expand instance [' + (command.instance.base || '@' +
- command.instance.type) + '], or instance.controller is undefined'));
+ errorMessage = 'Error expanding instance for "' +
+ (command.instance.id || command.instance.base || command.instance.type) + '"';
+ Y.log(errorMessage + (err ? ': \n' + err.stack :
+ instance && !instance.controller ? ': no valid controller found in the "' + instance.type + '" mojit' : ''), 'error', NAME);
+ adapter.error(new Error(errorMessage));
return;
-
}
// We replace the given instance with the expanded instance.
command.instance = instance;
if (!Y.mojito.controllers[instance.controller]) {
+ errorMessage = 'Invalid controller, named "' + instance.controller + '", in the "' + command.instance.type + '" mojit';
// the controller was not found, we should halt
- adapter.error(new Error('Invalid controller name [' +
- command.instance.controller + '] for mojit [' +
- command.instance.type + '].'));
+ Y.log(errorMessage + '. The controller does not define its actions under Y.namespace(\'mojito.controllers\')[\'' +
+ instance.controller + '\']', 'error', NAME);
+ adapter.error(new Error(errorMessage));
} else {
// dispatching AC
my._createActionContext(command, adapter);
}
-
});
}
-
};
}, '0.1.0', {requires: [
View
19 lib/app/autoload/mojito-client.client.js
@@ -137,7 +137,11 @@ YUI.add('mojito-client', function(Y, NAME) {
if (Y.Lang.isFunction(binder.bind)) {
// Pass the "node" to the bind method
- binder.bind(node, element);
+ try {
+ binder.bind(node, element);
+ } catch (e) {
+ Y.log(e.stack || e.message, 'error', NAME);
+ }
}
// all automatic event delegation
if (Y.Lang.isFunction(binder.handleClick)) {
@@ -641,11 +645,14 @@ YUI.add('mojito-client', function(Y, NAME) {
});
if (Y.Lang.isFunction(binder.init)) {
- binder.init(mojitProxy);
+ try {
+ binder.init(mojitProxy);
+ } catch (e) {
+ Y.log(e.stack || e.message, 'error', NAME);
+ }
}
onBinderComplete();
-
});
}, this);
@@ -1018,7 +1025,11 @@ YUI.add('mojito-client', function(Y, NAME) {
if (Y.Lang.isFunction(childBinder.onRefreshView)) {
childBinder.onRefreshView(childNode, childElement);
} else if (Y.Lang.isFunction(childBinder.bind)) {
- childBinder.bind(childNode, childElement);
+ try {
+ childBinder.bind(childNode, childElement);
+ } catch (e) {
+ Y.log(e.stack || e.message, 'error', NAME);
+ }
}
});
View
18 lib/app/autoload/store.server.js
@@ -586,6 +586,10 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
spec.config = {};
}
+ if (!spec.type) {
+ return cb(new Error('Instance is missing a mojit type.'));
+ }
+
// type details
try {
typeDetails = this.getMojitTypeDetails(env, ctx, spec.type);
@@ -656,9 +660,9 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
posl = this.selector.getPOSLFromContext(ctx, true);
}
- // if lazyLangs is on then determine the closetLang for this mojit and add the corresponding lang resources
+ // if lazyLangs is on then determine the closestLang for this mojit and add the corresponding lang resources
// if they havent been added already.
- if (this.lazyLangs) {
+ if (this._unloadedLangs[mojitType]) {
closestLang = Y.mojito.util.findClosestLang(ctx.lang, this._unloadedLangs[mojitType]);
newModules = this._loadMojitLangs(mojitType, closestLang) || newModules;
}
@@ -1532,7 +1536,7 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
* You most often don't want to call this directly, but instead to hook
* into it using the AOP mechanism of `Y.Plugin.Base`:
*
- * this.beforeHostMethod('parseResourceVersion', this._myParseResource, this);
+ * this.beforeHostMethod('addResourceVersion', this._myAddResourceVersion, this);
*
* @method addResourceVersion
* @param {object} res the resource version
@@ -1648,6 +1652,10 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
ress = this._mojitRVs[type];
+ if (!ress) {
+ throw new Error('Cannot find the "' + type + '" mojit. Make sure "' + type + '" exists in the application.');
+ }
+
this._mojitDetails[type] = {};
for (r = 0; r < ress.length; r++) {
@@ -2166,7 +2174,9 @@ YUI.add('mojito-resource-store', function(Y, NAME) {
this.yui._processResources(ress);
// Add new static details.
- this.getURLDetails(ress, this._staticDetails);
+ if (this._staticDetails) {
+ this.getURLDetails(ress, this._staticDetails);
+ }
},
View
2  lib/app/middleware/mojito-parser-body.js
@@ -17,4 +17,4 @@
Export a function which can create a body parser.
@return {Object} The newly constructed body parser.
**/
-module.exports = require('express').bodyParser;
+module.exports = require('express').bodyParser;
View
8 lib/dispatcher.js
@@ -107,7 +107,7 @@ module.exports = {
The `command` should be attached to the request.
@protected
- @method handleRequest
+ @method handleRequest
@param {http.ServerRequest} req
@param {Object} req.command the mojito command to be executed
@param {http.ServerResponse} res
@@ -135,7 +135,7 @@ module.exports = {
outputHandler.setLogger({ log: Y.log });
- // storing the static app config as well as contextualized
+ // storing the static app config as well as contextualized
// app config per request
outputHandler.page.staticAppConfig = appConfig;
outputHandler.page.appConfig = store.getAppConfig(context);
@@ -143,9 +143,13 @@ module.exports = {
// - routes are not contextualized anymore
if (!CACHE.routes) {
CACHE.routes = app.getRouteMap();
+ CACHE.clientRoutes = app.getRouteMap({
+ client: true
+ });
}
outputHandler.page.routes = CACHE.routes;
+ outputHandler.page.clientRoutes = CACHE.clientRoutes;
// HookSystem::StartBlock
// enabling perf group
View
4 lib/mojito.js
@@ -72,6 +72,7 @@ function Mojito(app, options) {
this._config = {};
this._options = options || {};
this._options.context = this._options.context || {};
+ this._options.root = this._options.root || process.cwd();
this._options.mojitoRoot = __dirname;
app.mojito = this;
@@ -96,7 +97,6 @@ Mojito.prototype._init = function () {
var app = this._app,
options = this._options,
context = options.context,
- appRoot = process.cwd(),
store; // reference to resource store
if (!app.mojito) {
@@ -105,8 +105,6 @@ Mojito.prototype._init = function () {
context.runtime = 'server';
- options.root = appRoot;
-
store = libstore.createStore(options);
this._configureAppInstance(app, store, options);
View
2  lib/output-handler.server.js
@@ -54,7 +54,7 @@ OutputHandler.prototype = {
size,
memDebug = {};
- this.logger.log('done', 'info', NAME);
+ this.logger.log('done', 'mojito', NAME);
this._readMeta(meta);
this._writeHeaders();
if (!data ||
View
10 lib/router.js
@@ -18,7 +18,7 @@ Example usage:
app = express();
- app.use(mojito.middleware());
+ app.use(mojito.middleware());
...
// or specify app specific paths (preferred)
app.mojito.attachRoutes(libpath.join(__dirname, 'config', 'routes.json'));
@@ -70,7 +70,7 @@ function readConfigYCB(fullPath) {
/**
Normalizes the `routes.json` configuration.
-@param {String} name
+@param {String} name
@param {Object} route the route object from `routes.json`
@return {Object} normalized route object
**/
@@ -162,6 +162,12 @@ module.exports = {
function registerRoutes(routes) {
Object.keys(routes).forEach(function (name) {
var route = routes[name];
+ route.annotations = route.annotations || {};
+ // By default the "client" annotation is considered true, unless specified as false.
+ // This means that routes are exposed to the client unless the "client" annotation
+ // is set to false.
+ route.annotations.client = route.annotations.client !== false;
+ app.annotate(route.path, route.annotations);
Object.keys(route.verbs).forEach(function (verb) {
debug('[%s %s] installing handler', route.call, route.path);
verb = verb.toLowerCase();
View
2  package.json
@@ -1,6 +1,6 @@
{
"name": "mojito",
- "version": "0.9.5",
+ "version": "0.9.6",
"description": "Mojito provides an architecture, components and tools for developers to build complex web applications faster.",
"author": "Drew Folta <folta@yahoo-inc.com>",
"contributors": [
View
2  tests/unit/lib/app/addons/ac/test-deploy.server.js
@@ -20,7 +20,7 @@ YUI().use('mojito-deploy-addon', 'test', 'json-parse', function(Y) {
setUp: function() {
addon = new Y.mojito.addons.ac.deploy(
{instance: {}}, // command
- {page: { routes: { 'get': { } } } } // adapter
+ {page: { clientRoutes: { 'get': { } } } } // adapter
);
addon.ac = {
http: {
View
3  tests/unit/lib/app/autoload/test-action-context.common.js
@@ -745,6 +745,7 @@ YUI().use('mojito-action-context', 'test', function (Y) {
instance: {
id: 'id',
type: 'TypeGeneral',
+ controller: 'GeneralController',
acAddons: [],
views: {}
}
@@ -764,7 +765,7 @@ YUI().use('mojito-action-context', 'test', function (Y) {
error = err;
}
A.isNotUndefined(error);
- A.areSame("No method 'index' on controller type 'TypeGeneral'", error.message.toString());
+ A.areSame('Action "index" not defined by the controller named "GeneralController" of the "TypeGeneral" mojit.', error.message.toString());
},
'test controller __call': function() {
View
3  tests/unit/lib/test-router.js
@@ -69,7 +69,8 @@ YUI().use('test', function (Y) {
// mock expect 'routes01.json'
root: ''
}
- }
+ },
+ annotate: function () {}
};
router._app = app;
},
Please sign in to comment.
Something went wrong with that request. Please try again.