Comparing version 0.1.0-beta-1 to 0.1.0-beta-10
@@ -64,2 +64,5 @@ "use strict"; | ||
envPath = di.dirname(filePath); | ||
// set env path | ||
di.setAlias('envPath', envPath); | ||
@@ -131,5 +134,5 @@ // load config | ||
try { | ||
di.load('@{appPath}/' + env.config)(component, di); | ||
di.load(envPath + '/' + env.config)(component, di); | ||
} catch (e) { | ||
throw new error.Exception('Initialize config', e); | ||
throw new error.Exception('Initialize config: ' + envPath + '/' + env.config, e); | ||
} | ||
@@ -136,0 +139,0 @@ } else { |
@@ -20,5 +20,94 @@ "use strict"; | ||
Controller = ControllerInterface.inherit({}, { | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#hasHeader | ||
* | ||
* @description | ||
* has response header | ||
*/ | ||
hasHeader: function Controller_hasHeader(key) { | ||
return this._request.hasHeader(key); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#getRequestHeader | ||
* | ||
* @description | ||
* Get request header | ||
*/ | ||
getRequestHeader: function Controller_getRequestHeader(key) { | ||
return this._request.getRequestHeader(key); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#getHeaders | ||
* | ||
* @description | ||
* Return response headers | ||
*/ | ||
getHeaders: function Controller_getHeaders() { | ||
return this._request.getHeaders(); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#getMethod | ||
* | ||
* @description | ||
* Return request method | ||
*/ | ||
getMethod: function Controller_getMethod() { | ||
return this._request.getMethod(); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#getRequestHeaders | ||
* | ||
* @description | ||
* Return request headers | ||
*/ | ||
getRequestHeaders: function Controller_getRequestHeaders() { | ||
return this._request.getRequestHeaders(); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#isHeaderCacheUnModified | ||
* | ||
* @description | ||
* Check if cache is unmodified | ||
*/ | ||
isHeaderCacheUnModified: function Controller_isHeaderCacheUnModified() { | ||
return this._request.isHeaderCacheUnModified(); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#sendNoChange | ||
* | ||
* @description | ||
* Send no change 304 response | ||
*/ | ||
sendNoChange: function Controller_sendNoChange() { | ||
return this._request.sendNoChange(); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#getParsedUrl | ||
* | ||
* @description | ||
* Return parsed url | ||
*/ | ||
getParsedUrl: function Controller_getParsedUrl() { | ||
return this._request.parsedUrl; | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method Controller#onEnd | ||
@@ -76,3 +165,2 @@ * | ||
}, | ||
/** | ||
@@ -79,0 +167,0 @@ * @since 0.0.1 |
@@ -30,2 +30,3 @@ "use strict"; | ||
config: Type.OBJECT, | ||
length: Type.NUMBER, | ||
hooks: Type.ARRAY | ||
@@ -36,4 +37,4 @@ }, | ||
var file; | ||
this.stream = null; | ||
this.server = null; | ||
this.length = 0; | ||
this.stream = this.server = null; | ||
this.hooks = []; | ||
@@ -45,2 +46,3 @@ this.config = core.extend({ | ||
console: false, | ||
readLength: 20000, | ||
port: 9001, | ||
@@ -55,8 +57,36 @@ file: "server.log", | ||
if (this.config.publish) { | ||
this.server = http.createServer(); | ||
this.server.on('request', function (request, response) { | ||
var read = fs.readFileSync(file); | ||
response.writeHead(200, {'Content-type': 'text/plain', 'Content-Length': read.length}); | ||
response.end(read); | ||
}); | ||
var len = this.length, | ||
start = len - this.config.readLength, | ||
blen = 0, | ||
buffer, | ||
blenMessage; | ||
if (start < 0) { | ||
start = 0; | ||
blen = 1000; | ||
} else { | ||
blen = len - start; | ||
} | ||
blenMessage = 'LAST '+ blen + ' BYTES:\n\n'; | ||
buffer = new Buffer(blen + blenMessage.length, 'utf8'); | ||
fs.open(file, 'r', 755, function(status, fd) { | ||
fs.read(fd, buffer, 0, blen, start, function(err) { | ||
if (err) { | ||
var errorMessage = 'Error reading logger buffer'; | ||
response.writeHead(200, {'Content-type': 'text/plain', 'Content-Length': errorMessage.length}); | ||
response.end(errorMessage); | ||
} else { | ||
response.writeHead(200, {'Content-type': 'text/plain', 'Content-Length': buffer.length}); | ||
response.write(blenMessage); | ||
response.end(buffer); | ||
} | ||
}); | ||
}); | ||
}.bind(this)); | ||
this.server.listen(this.config.port); | ||
@@ -146,2 +176,3 @@ this.print('Publishing log write stream on port: ' + this.config.port); | ||
try { | ||
this.length += logs.length; | ||
this.stream.write(logs); | ||
@@ -148,0 +179,0 @@ } catch (e) { |
@@ -305,11 +305,4 @@ "use strict"; | ||
_handleError: function Request_handleError(response) { | ||
var Controller, | ||
errorRoute = router.getErrorRoute(), | ||
errorController = '@{controllersPath}/' + errorRoute.shift(), | ||
errorAction = errorRoute.shift(); | ||
if (response instanceof Error && !this.isERROR && di.exists(di.normalizePath(errorController) + '.js')) { | ||
if (response instanceof Error && !this.isERROR && !!router.getErrorRoute()) { | ||
if (response.code) { | ||
@@ -320,24 +313,4 @@ this.statusCode = response.code; | ||
} | ||
try { | ||
Controller = di.load(errorController); | ||
errorController = new Controller(); | ||
if (errorController.has('action_' + errorAction)) { | ||
response = errorController.get('action_' + errorAction)(response); | ||
if (response.trace) { | ||
this._render(response.trace); | ||
} else if (response.stack) { | ||
this._render(response.stack); | ||
} else { | ||
this._render(util.inspect(response)); | ||
} | ||
} else { | ||
throw new error.HttpError(500, {errorAction: errorAction}, "No error action defined at error controller"); | ||
} | ||
} catch (e) { | ||
this.isERROR = true; | ||
throw new error.HttpError(500, {}, "Error on executing error action", e); | ||
} | ||
this.isERROR = true; | ||
return this._resolveRoute([router.getErrorRoute(), response]).then(null, this._handleError); | ||
} else if (response.trace) { | ||
@@ -434,3 +407,3 @@ this.addHeader('Content-Type', 'text/plain'); | ||
return promise.then(function (data) { | ||
return Promise.resolve(_handler(data)); | ||
return _handler(data); | ||
}, this._handleError.bind(this)); | ||
@@ -459,5 +432,3 @@ | ||
action, | ||
promise, | ||
afterActionPromise = false, | ||
afterEachPromise = false; | ||
promise; | ||
@@ -512,7 +483,7 @@ try { | ||
if (controller.has('after_' + this.action)) { | ||
afterActionPromise = this._chain(promise, controller.get('after_' + this.action).bind(controller, this.params)); | ||
promise = this._chain(promise, controller.get('after_' + this.action).bind(controller, this.params)); | ||
} | ||
if (controller.has("afterEach")) { | ||
afterEachPromise = this._chain(promise, controller.afterEach.bind(controller, this.action, this.params)); | ||
promise = this._chain(promise, controller.afterEach.bind(controller, this.action, this.params)); | ||
} | ||
@@ -522,6 +493,3 @@ | ||
return Promise.all([afterActionPromise, afterEachPromise]).then(function (data) { | ||
logger.print('afterActionPromise, afterEachPromise', data); | ||
return promise; | ||
}); | ||
return promise; | ||
}, | ||
@@ -528,0 +496,0 @@ |
@@ -30,8 +30,4 @@ "use strict"; | ||
this.config = core.extend({ | ||
errorRoute: "error/index" | ||
errorRoute: false | ||
}, config); | ||
if (!Type.assert(Type.STRING, this.config.errorRoute)) { | ||
throw new error.DataError(this.config, 'Router.construct: errorRoute must be string type'); | ||
} | ||
}, | ||
@@ -48,3 +44,3 @@ /** | ||
getErrorRoute: function Router_getErrorRoute() { | ||
return this.config.errorRoute.split('/').splice(0, 2); | ||
return this.config.errorRoute; | ||
}, | ||
@@ -81,3 +77,2 @@ /** | ||
this.routes.push(rule); | ||
}, | ||
@@ -139,17 +134,25 @@ | ||
parseRequest: function Router_parseRequest(method, parsedUrl) { | ||
var i, len = this.routes.length, routeRule, route = []; | ||
var all = []; | ||
for (i = len - 1; i > -1; --i) { | ||
routeRule = this.routes[i]; | ||
route = routeRule.parseRequest(method, parsedUrl); | ||
if (Type.isArray(route) && route.length) { | ||
break; | ||
this.routes.forEach(function (routeRule) { | ||
all.push( | ||
new Promise(function (resolve, reject) { | ||
try { | ||
resolve(routeRule.parseRequest(method, parsedUrl)) | ||
} catch (e) { | ||
reject(e); | ||
} | ||
}) | ||
); | ||
}); | ||
return Promise.all(all).then(function (data) { | ||
var route; | ||
while (data.length) { | ||
route = data.shift(); | ||
if (Type.isArray(route) && route.length === 2) { | ||
return route; | ||
} | ||
} | ||
} | ||
if (!Type.isArray(route)) { | ||
route = []; | ||
} | ||
logger.print('Router.parseRequest', route); | ||
return route; | ||
return []; | ||
}); | ||
}, | ||
@@ -201,3 +204,3 @@ /** | ||
return new Promise(handlePromise.bind(this)) | ||
return this.parseRequest(method, parsedUrl) | ||
.then(function (routeRule) { | ||
@@ -212,10 +215,2 @@ if (Type.isArray(routeRule) && routeRule.length === 2) { | ||
}); | ||
function handlePromise(resolve, reject) { | ||
try { | ||
resolve(this.parseRequest(method, parsedUrl)); | ||
} catch (e) { | ||
reject(e); | ||
} | ||
} | ||
} | ||
@@ -222,0 +217,0 @@ }); |
@@ -8,3 +8,3 @@ "use strict"; | ||
var fs = require('fs'); | ||
var INVALID_ALIAS_VALUE = /[\\?%*:|"<>.\s]/ig; | ||
var INVALID_ALIAS_VALUE = /[\\?%*:|"<>\s]/ig; | ||
var error; | ||
@@ -74,3 +74,3 @@ /** | ||
error = this.load('error'); | ||
throw new error.Exception('DI.setAlias: Invalid alias value, chars \'\\?%*:|"<>.\' and spaces are not allowed. KEY: ' + key); | ||
throw new error.Exception('DI.setAlias: Invalid alias value, chars \'\\?%*:|"<>.\' and spaces are not allowed. KEY: ' + key + ', VAL:' + value); | ||
} else { | ||
@@ -164,2 +164,13 @@ this.aliases[key] = this.normalizePath(value); | ||
* @author Igor Ivanovic | ||
* @method DI#dirname | ||
* | ||
* @description | ||
* Get dir of file | ||
*/ | ||
dirname: function DI_dirname(name) { | ||
return path.dirname(name); | ||
}, | ||
/** | ||
* @since 0.0.1 | ||
* @author Igor Ivanovic | ||
* @method DI#getPath | ||
@@ -166,0 +177,0 @@ * |
@@ -23,3 +23,9 @@ "use strict"; | ||
this._request = request; | ||
["has", "get", "redirect", "forward", "addHeader", "onEnd", "createUrl"].forEach(function (method) { | ||
[ | ||
"has", "get", "redirect", | ||
"forward", "addHeader", "onEnd", | ||
"createUrl", "hasHeader", "getRequestHeader", | ||
"getHeaders", "getMethod", "getRequestHeaders", | ||
"isHeaderCacheUnModified", "sendNoChange", "getParsedUrl" | ||
].forEach(function (method) { | ||
if (!(method in this)) { | ||
@@ -26,0 +32,0 @@ throw new error.DataError({method: method}, 'ControllerInterface: missing method in Controller object'); |
@@ -5,3 +5,3 @@ { | ||
"description": "Powerful lightweight mvc framework for nodejs", | ||
"version": "0.1.0-beta-1", | ||
"version": "0.1.0-beta-10", | ||
"dependencies" : { | ||
@@ -8,0 +8,0 @@ "mongoose": "3.8.x", |
119
README.md
@@ -1,2 +0,119 @@ | ||
mvcjs [![Build Status](https://api.travis-ci.org/igorzg/node-mvc.svg?branch=master)](https://travis-ci.org/igorzg/node-mvc) | ||
MVC JS [![Build Status](https://api.travis-ci.org/igorzg/node-mvc.svg?branch=master)](https://travis-ci.org/igorzg/node-mvc) beta | ||
===== | ||
Powerful lightweight mvc framework for nodejs inspired by [Yii](http://www.yiiframework.com/) | ||
Features | ||
==== | ||
1. Fully extensible | ||
2. TDD driven | ||
3. Type checking at runtime | ||
4. Custom DI | ||
5. Component based | ||
6. Twig (swigjs) templating engine | ||
7. Dynamic routing | ||
8. Logger | ||
[Demo application](https://github.com/igorzg/mvcjs-testapp) | ||
Getting started | ||
==== | ||
npm install mvcjs | ||
index.js | ||
```javascript | ||
var di = require('mvcjs'); | ||
var framework = di.load('bootstrap'); | ||
framework.setBasePath(__dirname); | ||
framework.init('app/', 'env.json'); | ||
``` | ||
app/env.json | ||
```json | ||
{ | ||
"aliases": [ | ||
{ | ||
"key": "assetsPath", | ||
"value": "@{basePath}/assets" | ||
} | ||
], | ||
"components": [ | ||
{ | ||
"name": "core/logger", | ||
"enabled": true, | ||
"write": true, | ||
"publish": true, | ||
"console": true, | ||
"port": 9001, | ||
"file": "server.log" | ||
}, | ||
{ | ||
"name": "core/router", | ||
"errorRoute": "core/error" | ||
}, | ||
{ | ||
"name": "core/favicon", | ||
"path": "@{basePath}/favicon.ico" | ||
}, | ||
{ | ||
"name": "core/view", | ||
"themes": "@{appPath}/themes/", | ||
"views": "@{appPath}/views/", | ||
"theme": "default", | ||
"cache": true | ||
}, | ||
{ | ||
"name": "core/assets", | ||
"path": "@{basePath}/storage/", | ||
"hook": "^\\/assets" | ||
}, | ||
{ | ||
"name": "db/mongo", | ||
"connection": "mongodb://localhost/testdb" | ||
} | ||
], | ||
"config": "config-test.js", | ||
"assetsPath": "@{assetsPath}", | ||
"port": 9000 | ||
} | ||
``` | ||
app/config-test.js | ||
```javascript | ||
module.exports = function (componet, di) { | ||
"use strict"; | ||
var viewLoader, router, | ||
logger = componet.get('core/logger'), | ||
loggerModel = di.load('@{modelsPath}/logger'); | ||
viewLoader = componet.get('core/view'); | ||
viewLoader.setTheme('home'); | ||
// bind logger hook | ||
logger.addHook(loggerModel.save.bind(loggerModel)); | ||
router = componet.get('core/router'); | ||
router.add([ | ||
{ | ||
pattern: 'home/<action>', | ||
route: 'home/<action>' | ||
}, | ||
{ | ||
pattern: 'posts/<action:(create|update|delete)>', | ||
route: 'posts/<action>', | ||
method: ['GET', 'POST'] | ||
}, | ||
{ | ||
pattern: 'user/<id:(\\d+)>', | ||
route: 'user/view' | ||
} | ||
]); | ||
router.add({ | ||
pattern: '/', | ||
route: 'home/index' | ||
}); | ||
}; | ||
``` | ||
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
107128
3411
120