New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

mvcjs

Package Overview
Dependencies
Maintainers
1
Versions
123
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

mvcjs - npm Package Compare versions

Comparing version 0.1.0-beta-3 to 0.1.0-beta-30

framework/core/module.js

96

framework/bootstrap.js

@@ -10,3 +10,2 @@ "use strict";

ENV_END_PATTERN = new RegExp('.*\\.json$'),
DEFAULT_SERVER_PORT = 8080,
Bootstrap;

@@ -16,3 +15,8 @@

Bootstrap = Type.create({
initalized: Type.BOOLEAN
initalized: Type.BOOLEAN,
listenPort: Type.NUMBER,
listenHost: Type.STRING,
controllersPath: Type.STRING,
modulesPath: Type.STRING,
modelsPath: Type.STRING
}, {

@@ -31,2 +35,7 @@ /**

this.initalized = false;
this.listenPort = 8080;
this.listenHost = "127.0.0.1";
this.controllersPath = '@{appPath}/controllers/';
this.modulesPath = '@{appPath}/modules/';
this.modelsPath = '@{appPath}/models/';
},

@@ -82,2 +91,9 @@ /**

}
if (Type.isNumber(env.port)) {
this.setListenPort(env.port);
}
if (Type.isString(env.host)) {
this.setListenHost(env.host);
}
// set aliases

@@ -93,8 +109,20 @@ if (Type.isArray(env.aliases)) {

if (!di.hasAlias('controllersPath')) {
di.setAlias('controllersPath', '@{appPath}/controllers/');
di.setAlias('controllersPath', this.controllersPath);
} else {
this.controllersPath = di.getAlias('controllersPath');
}
// if there is no modules path
if (!di.hasAlias('modulesPath')) {
di.setAlias('modulesPath', this.modulesPath);
} else {
this.modulesPath = di.getAlias('modulesPath');
}
// if there is no models path
if (!di.hasAlias('modelsPath')) {
di.setAlias('modelsPath', '@{appPath}/models/');
di.setAlias('modelsPath', this.modelsPath);
} else {
this.modelsPath = di.getAlias('modelsPath');
}
// assets path

@@ -127,6 +155,3 @@ if (Type.isString(env.assetsPath)) {

}
// set favicon path
if (!component.has('core/favicon')) {
component.set('core/favicon', {});
}
// set view component

@@ -139,3 +164,3 @@ if (!component.has('core/view')) {

try {
di.load(envPath + '/' + env.config)(component, di);
di.load(envPath + '/' + env.config)(component, di, this);
} catch (e) {

@@ -159,6 +184,13 @@ throw new error.Exception('Initialize config: ' + envPath + '/' + env.config, e);

logger.print('Create new request', request.url);
// set paths on each request
di.setAlias('controllersPath', this.controllersPath);
di.setAlias('modulesPath', this.modulesPath);
di.setAlias('modelsPath', this.modelsPath);
// new request
var nRequest = new Request({
request: request,
response: response
response: response,
encoding: server.getEncoding()
}, request.url);

@@ -168,6 +200,5 @@ /// parse request

// on end destory
request.on('end', function () {
nRequest.destroy();
});
});
nRequest.onEnd(nRequest.destroy.bind(nRequest));
}.bind(this));
// server close event

@@ -178,9 +209,4 @@ server.on('close', function () {

});
// this must be last !! in config order
if (Type.isNumber(env.port)) {
server.listen(env.port);
} else {
server.listen(DEFAULT_SERVER_PORT);
}
// this must be last !
server.listen(this.listenPort, this.listenHost);
// logger

@@ -194,2 +220,30 @@ logger.print(env);

* @author Igor Ivanovic
* @method Bootstrap#setListenHost
*
* @description
* Set listen host
*/
setListenHost: function Bootstrap_setListenHost(host) {
if (Type.isString(host)) {
this.listenHost = host;
}
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Bootstrap#setListenPort
*
* @description
* Set listen port
*/
setListenPort: function Bootstrap_setListenPort(port) {
if (Type.isNumber(port)) {
this.listenPort = port;
} else {
this.listenPort = parseInt(port);
}
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Bootstrap#setBasePath

@@ -196,0 +250,0 @@ *

@@ -132,3 +132,64 @@ "use strict";

}
/**
* @since 0.0.1
* @author Igor Ivanovic
* @function compare
*
* @description
* Compare object a with b
*/
function compare(a, b) {
if (Type.isString(a)) {
return a === b;
} else if (Type.isNumber(a)) {
if (isNaN(a) || isNaN(b)) {
return isNaN(a) === isNaN(b);
}
return a === b;
} else if (Type.isBoolean(a)) {
return a === b;
} else if (Type.isDate(a) && Type.isDate(b)) {
return a.getTime() === b.getTime();
} else if (Type.isRegExp(a) && Type.isRegExp(b)) {
return a.source === b.source;
} else if (Type.isArray(a) && Type.isArray(b)) {
// check references first
if (a === b) {
return true;
}
return a.every(function (item, index) {
try {
return compare(item, b[index]);
} catch (e) {
throw e;
}
});
} else if (Type.isObject(a) && Type.isObject(b)) {
var equal = [];
// check references first
if (a === b) {
return true;
}
try {
for (var key in a) {
equal.push(compare(a[key], b[key]));
}
} catch (e) {
throw e;
}
return equal.every(function (item) {
return item === true;
});
/// compare undefined and nulls and nans
} else if (a === b) {
return true;
}
return false;
}
/**
* Export functions

@@ -144,3 +205,4 @@ * @type {{isBoolean: isBoolean, isUndefined: isUndefined, isDefined: isDefined, isObject: isObject, isString: isString, isNumber: isNumber, isDate: isDate, isArray: isArray, isFunction: isFunction, isRegExp: isRegExp, isConstructor: isConstructor, copy: copy, trim: trim, throwError: throwError}}

createRegex: createRegex,
toObject: toObject
toObject: toObject,
compare: compare
};

@@ -8,2 +8,4 @@ "use strict";

mime = di.load('mime-types'),
fs = di.load('fs'),
Promise = di.load('promise'),
component = di.load('core/component'),

@@ -50,5 +52,4 @@ logger = component.get('core/logger'),

var maxAge = 60 * 60 * 24 * 30 * 12, // one year
filePath = this.config.path + api.parsedUrl.pathname,
mimeType,
file;
filePath = di.normalizePath(this.config.path + api.parsedUrl.pathname),
mimeType;

@@ -60,23 +61,39 @@

logger.print('MimeType', mimeType, filePath);
return false;
return this.handleError(function() {
new error.HttpError(500, {path: filePath}, 'Invalid mime type');
});
}
file = this.readFile(filePath);
if (api.getMethod() !== 'GET') {
return this.handleError(function() {
new error.HttpError(500, {path: filePath}, 'Assets are accessible only via GET request');
});
}
return new Promise(function (resolve, reject) {
api.addHeader('Content-Type', mimeType);
api.addHeader('Cache-Control', 'public, max-age=' + ~~(maxAge));
api.addHeader('ETag', etag(file));
this.readFile(filePath, function (err, file) {
if (err) {
try {
new error.HttpError(500, {path: filePath}, 'No file found', err);
} catch (e) {
return reject(e);
}
}
if (api.getMethod() !== 'GET') {
throw new error.HttpError(500, {path: filePath}, 'Assets are accessible only via GET request');
} else if (api.isHeaderCacheUnModified()) {
api.sendNoChange();
}
api.addHeader('Content-Type', mimeType);
api.addHeader('Cache-Control', 'public, max-age=' + ~~(maxAge));
api.addHeader('ETag', etag(file));
logger.print('MimeType', mimeType, filePath);
if (api.isHeaderCacheUnModified()) {
return resolve(api.sendNoChange());
}
return file;
logger.print('MimeType', mimeType, filePath);
resolve(file);
});
}.bind(this));
},

@@ -86,2 +103,19 @@ /**

* @author Igor Ivanovic
* @method Favicon#handleError
*
* @description
* Handle error response
*/
handleError: function Assets_handleError(callback) {
return new Promise(function (resolve, reject) {
try {
callback();
} catch (e) {
reject(e);
}
});
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Favicon#mimeType

@@ -103,4 +137,4 @@ *

*/
readFile: function Assets_readFile(filePath) {
return di.readFileSync(filePath);
readFile: function Assets_readFile() {
return fs.readFile.apply(fs, arguments);
}

@@ -107,0 +141,0 @@ });

@@ -23,2 +23,123 @@ "use strict";

* @author Igor Ivanovic
* @method Controller#setStatusCode
*
* @description
* Set status code
*/
setStatusCode: function Controller_setStatusCode(code) {
this._request.setStatusCode(code);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#stopChain
*
* @description
* Stop promise chain
*/
stopChain: function Controller_stopChain() {
return this._request.stopPromiseChain();
},
/**
* @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#getRequestBody
*
* @description
* Get request body
*/
getRequestBody: function Controller_getRequestBody() {
return this._request.getRequestBody();
},
/**
* @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 +197,2 @@ *

},
/**

@@ -103,2 +223,38 @@ * @since 0.0.1

* @author Igor Ivanovic
* @method Controller#getActionName
*
* @description
* Get action name
* @return {string}
*/
getActionName: function Controller_getActionName() {
return this._routeInfo.action;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getControllerName
*
* @description
* Get controller name
* @return {string}
*/
getControllerName: function Controller_getControllerName() {
return this._routeInfo.controller;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getModuleName
*
* @description
* Get module name
* @return {string}
*/
getModuleName: function Controller_getModuleName() {
return this._routeInfo.module;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#hasAction

@@ -105,0 +261,0 @@ *

@@ -5,2 +5,3 @@ "use strict";

HttpServiceInterface = di.load('interface/http'),
core = di.load('core'),
http = di.load('http'),

@@ -20,10 +21,27 @@ HttpService;

HttpService = HttpServiceInterface.inherit({
server: Type.OBJECT
server: Type.OBJECT,
config: Type.OBJECT
}, {
_construct: function HttpService() {
_construct: function HttpService(config) {
this.config = {
encoding: 'utf8'
};
core.extend(this.config, config);
this.server = http.createServer();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method HttpService#getEncoding
*
* @description
* Return encoding
*/
getEncoding: function HttpService_getEncoding() {
return this.config.encoding;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method HttpService#on

@@ -30,0 +48,0 @@ *

@@ -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) {

@@ -5,2 +5,3 @@ "use strict";

ControllerInterface = di.load('interface/controller'),
ModuleInterface = di.load('interface/module'),
component = di.load('core/component'),

@@ -10,2 +11,3 @@ router = component.get('core/router'),

logger = component.get('core/logger'),
view = component.get('core/view'),
URLParser = di.load('url'),

@@ -41,6 +43,16 @@ Type = di.load('typejs'),

isRendered: Type.BOOLEAN,
isERROR: Type.BOOLEAN
isERROR: Type.BOOLEAN,
isPromiseChainStopped: Type.BOOLEAN,
isForwarded: Type.BOOLEAN,
encoding: Type.STRING,
body: Type.STRING,
id: Type.STRING
}, {
_construct: function Request(config, url) {
this.isForwarded = false;
this.body = '';
this.isERROR = false;
// body and isForwarded can be overriden
core.extend(this, config);
this.statusCode = 200;

@@ -50,2 +62,6 @@ this.headers = {};

this.parsedUrl = URLParser.parse(this.url, true);
this.isPromiseChainStopped = false;
this.isRendered = false;
this.id = this._uuid();
view.setPaths();
},

@@ -61,3 +77,3 @@ /**

onEnd: function Request_onEnd(callback) {
this.request.on('end', callback);
this.request.on('destory', callback);
},

@@ -109,5 +125,31 @@ /**

},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#setStatusCode
*
* @description
* HTTP status code
*/
setStatusCode: function Request_setStatusCode(code) {
if (!Type.isNumber(code)) {
throw new error.HttpError(500, {code: code}, "Status code must be number type");
}
this.statusCode = code;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#stopPromiseChain
*
* @description
* Stop promise chain
*/
stopPromiseChain: function Request_stopPromiseChain() {
this.isPromiseChainStopped = true;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#getHeaders

@@ -124,2 +166,13 @@ *

* @author Igor Ivanovic
* @method Request#getRequestBody
*
* @description
* Return body data
*/
getRequestBody: function Request_getRequestBody() {
return this.body;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#getRequestHeaders

@@ -215,5 +268,9 @@ *

this.stopPromiseChain();
request = new Request({
request: this.request,
response: this.response
response: this.response,
isForwarded: true,
body: this.body
}, router.createUrl(route, params));

@@ -237,2 +294,3 @@

this.addHeader('Location', url);
this.stopPromiseChain();
if (Type.isBoolean(isTemp) && !!isTemp) {

@@ -254,4 +312,5 @@ this.response.writeHead(302, this.headers);

sendNoChange: function () {
this.response.writeHead(304, this.headers);
this.response.end();
this.stopPromiseChain();
this.setStatusCode(304);
this._render('');
},

@@ -279,2 +338,44 @@ /**

if (this.isForwarded) {
return this._process().then(
this.request.emit.bind(this.request, 'destory'),
this.request.emit.bind(this.request, 'destory')
); // emit destroy on error and resolve
}
this.request.setEncoding(this.encoding);
this.request.on('data', function (body) {
this.body += body;
}.bind(this));
return new Promise(this.request.on.bind(this.request, 'end'))
.then(this._process.bind(this))
.then(
this.request.emit.bind(this.request, 'destory'),
this.request.emit.bind(this.request, 'destory')
); // emit destroy on error and resolve
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#_uuid
*
* @description
* Generate uuid
*/
_uuid: function () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#_process
*
* @description
* Process request
*/
_process: function () {
return hooks.process(this._getApi())

@@ -284,10 +385,15 @@ .then(function handleHooks(data) {

return data;
} else if (this.isPromiseChainStopped) {
return false;
}
return router
.process(this.request.method, this.parsedUrl) // find route
.then(this._resolveRoute.bind(this), this._handleError.bind(this)); // resolve route chain
.then(this._resolveRoute.bind(this)); // resolve route chain
}.bind(this), this._handleError.bind(this))
.then(this._render.bind(this), this._handleError.bind(this)) // render chain
.then(this._render.bind(this), this._handleError.bind(this)); // render error thrown in render function
}.bind(this)) // handle hook chain
.then(this._render.bind(this)) // resolve route chain
.catch(this._handleError.bind(this)) // catch hook error
.then(this._render.bind(this)) // render hook error
.catch(this._handleError.bind(this)) // catch render error
.then(this._render.bind(this)); // resolve render error
},

@@ -315,51 +421,50 @@ /**

* Handle error
* @return boolean
*/
_handleError: function Request_handleError(response) {
var Controller,
errorRoute = router.getErrorRoute(),
errorController = '@{controllersPath}/' + errorRoute.shift(),
errorAction = errorRoute.shift();
var request;
if (this.isRendered) {
// we have multiple recursion in parse for catching
return false;
}
// set status codes
if (response.code) {
this.setStatusCode(response.code);
} else {
this.setStatusCode(500);
}
// stop current chain!!!
this.stopPromiseChain();
if (response instanceof Error && !this.isERROR && di.exists(di.normalizePath(errorController) + '.js')) {
if (response instanceof Error && !this.isERROR && !!router.getErrorRoute()) {
// return new request
request = new Request({
request: this.request,
response: this.response,
isForwarded: true,
body: this.body,
isERROR: true
}, router.getErrorRoute());
// pass exception response over parsed url query as query parameter
request.parsedUrl.query.exception = response;
// set status codes for new request
if (response.code) {
this.statusCode = response.code;
request.setStatusCode(response.code);
} else {
this.statusCode = 500;
request.setStatusCode(500);
}
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);
}
// return parsed request
return request.parse();
} else if (response.trace) {
this.addHeader('Content-Type', 'text/plain');
this._render(response.trace);
return this._render(response.trace);
} else if (response.stack) {
this.addHeader('Content-Type', 'text/plain');
this._render(response.stack);
return this._render(response.stack);
} else if (this.isERROR) {
this.addHeader('Content-Type', 'text/plain');
this._render(util.inspect(response));
return this._render(util.inspect(response));
} else {
this._render(response);
return this._render(response);
}

@@ -374,26 +479,35 @@ },

* End request
* @return boolean
*/
_render: function Request__render(response) {
if (!this.isRendered) {
if (this.isRendered) {
return false;
}
logger.print('Request.render', response);
this._checkContentType('text/html');
this._checkContentType('text/html');
this.response.writeHead(this.statusCode, this.headers);
this.response.writeHead(this.statusCode, this.headers);
if (Type.isString(response)) {
this.addHeader('Content-Length', response.length);
this.response.end(response);
} else if (response instanceof Buffer) {
this.addHeader('Content-Length', response.length);
this.response.end(response);
} else if (!response) {
throw new error.HttpError(500, {}, 'No data to render');
} else {
throw new error.HttpError(500, {}, 'Invalid response type, string or buffer is required!');
}
if (Type.isString(response)) {
this.addHeader('Content-Length', response.length);
this.response.end(response);
} else if (response instanceof Buffer) {
this.addHeader('Content-Length', response.length);
this.response.end(response);
} else if (!response) {
throw new error.HttpError(500, {}, 'No data to render');
} else {
throw new error.HttpError(500, {}, 'Invalid response type, string or buffer is required!');
}
if ((response instanceof Error) || this.isERROR || this.statusCode === 500) {
logger.print('Request.error', this.statusCode, this.id, this.getHeader('content-type'), response);
} else {
logger.print('Request.render', this.statusCode, this.id, this.getHeader('content-type'));
}
this.isRendered = true;
return true;
},

@@ -417,2 +531,3 @@

getMethod: this.getMethod.bind(this),
getRequestBody: this.getRequestBody.bind(this),
getRequestHeaders: this.getRequestHeaders.bind(this),

@@ -423,2 +538,4 @@ getRequestHeader: this.getRequestHeader.bind(this),

sendNoChange: this.sendNoChange.bind(this),
stopPromiseChain: this.stopPromiseChain.bind(this),
setStatusCode: this.setStatusCode.bind(this),
createUrl: router.createUrl.bind(router),

@@ -438,3 +555,3 @@ parsedUrl: core.copy(this.parsedUrl)

if (!promise) {
return new Promise(function(resolve, reject) {
return new Promise(function (resolve, reject) {
try {

@@ -449,4 +566,7 @@ resolve(next.apply(next, arguments));

return promise.then(function (data) {
return Promise.resolve(_handler(data));
}, this._handleError.bind(this));
if (!!this.isPromiseChainStopped) {
return promise;
}
return _handler(data);
}.bind(this), this._handleError.bind(this));

@@ -464,3 +584,3 @@ function _handler() {

* @author Igor Ivanovic
* @method Request#_handleRoute
* @method Request#_handleController
*

@@ -470,3 +590,3 @@ * @description

*/
_handleRoute: function Request_handleRoute() {
_handleController: function Request_handleController() {
var controllerToLoad = '@{controllersPath}/' + this.controller,

@@ -476,5 +596,3 @@ LoadedController,

action,
promise,
afterActionPromise = false,
afterEachPromise = false;
promise;

@@ -487,4 +605,12 @@ try {

controller = new LoadedController(this._getApi());
if (!Type.assert(Type.FUNCTION, LoadedController)) {
throw new error.HttpError(500, {path: controllerToLoad}, 'Controller must be function type');
}
controller = new LoadedController(this._getApi(), {
controller: this.controller,
action: this.action,
module: this.module
});
if (!(controller instanceof ControllerInterface)) {

@@ -530,7 +656,7 @@ throw new error.HttpError(500, controller, 'Controller must be instance of ControllerInterface "core/controller"');

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));
}

@@ -540,8 +666,40 @@

return Promise.all([afterActionPromise, afterEachPromise]).then(function (data) {
logger.print('afterActionPromise, afterEachPromise', data);
return promise;
});
return promise;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#_handleModule
*
* @description
* Handle module
* @return {object} Promise
*/
_handleModule: function Request__handleModule() {
var moduleToLoad = '@{modulesPath}/' + this.module,
LoadedModule,
module;
try {
LoadedModule = di.load(moduleToLoad);
} catch (e) {
throw new error.HttpError(500, {path: moduleToLoad}, 'Missing module', e);
}
if (!Type.assert(Type.FUNCTION, LoadedModule)) {
throw new error.HttpError(500, {path: moduleToLoad}, 'Module must be function type');
}
module = new LoadedModule(this.module);
if (!(module instanceof ModuleInterface)) {
throw new error.HttpError(500, module, 'Module must be instance of ModuleInterface "core/module"');
}
module.setControllersPath();
module.setViewsPath();
module.setThemesPath();
return this._handleController();
},
/**

@@ -555,7 +713,5 @@ * @since 0.0.1

* @return {object} Promise
* @todo implement modules
*/
_resolveRoute: function Request__resolveRoute(routeRule) {
var route;
this.statusCode = 200;
this.route = routeRule.shift();

@@ -570,3 +726,7 @@ this.params = routeRule.shift();

return this._handleRoute();
if (!!this.module) {
return this._handleModule();
}
return this._handleController();
}

@@ -573,0 +733,0 @@

@@ -30,8 +30,10 @@ "use strict";

this.config = core.extend({
errorRoute: "error/index"
errorRoute: false,
errorUrl: '/error'
}, config);
if (!Type.assert(Type.STRING, this.config.errorRoute)) {
throw new error.DataError(this.config, 'Router.construct: errorRoute must be string type');
}
// add error route so we can resolve it
this.add({
pattern: this.config.errorUrl,
route: this.config.errorRoute ? this.config.errorRoute : 'core/error'
});
},

@@ -48,3 +50,3 @@ /**

getErrorRoute: function Router_getErrorRoute() {
return this.config.errorRoute.split('/').splice(0, 2);
return this.config.errorRoute;
},

@@ -76,3 +78,3 @@ /**

if (!(rule instanceof RouteRuleInterface)) {
throw new error.HttpError(500, {rule: rule}, 'Router.add: rule must be instance of RouteRuleInterface');
throw new error.HttpError(500, {rule: rule, route: route}, 'Router.add: rule must be instance of RouteRuleInterface');
}

@@ -82,3 +84,2 @@

this.routes.push(rule);
},

@@ -140,17 +141,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 [];
});
},

@@ -202,3 +211,3 @@ /**

return new Promise(handlePromise.bind(this))
return this.parseRequest(method, parsedUrl)
.then(function (routeRule) {

@@ -213,10 +222,2 @@ if (Type.isArray(routeRule) && routeRule.length === 2) {

});
function handlePromise(resolve, reject) {
try {
resolve(this.parseRequest(method, parsedUrl));
} catch (e) {
reject(e);
}
}
}

@@ -223,0 +224,0 @@ });

@@ -64,4 +64,3 @@ "use strict";

if (this.config.cache) {
this.preloadTemplates(di.getAlias('viewsPath'));
this.preloadTemplates(di.getAlias('themesPath'));
this.preloadTemplates(di.getAlias('appPath'));
}

@@ -324,2 +323,24 @@

* @author Igor Ivanovic
* @method View#setPaths
*
* @description
* Set default paths
* @return {string}
*/
setPaths: function View_setPaths(themesPath, viewsPath) {
if (Type.isString(themesPath) && !!themesPath) {
di.setAlias('themesPath', themesPath);
} else {
di.setAlias('themesPath', this.config.themes);
}
if (Type.isString(viewsPath) && !!viewsPath) {
di.setAlias('viewsPath', viewsPath);
} else {
di.setAlias('viewsPath', this.config.views);
}
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method View#renderFile

@@ -326,0 +347,0 @@ *

@@ -87,6 +87,10 @@ "use strict";

normalizePath: function DI_normalizePath(value) {
Object.keys(this.aliases).forEach(function (key) {
value = value.replace('@{' + key + '}', this.aliases[key]);
}.bind(this));
return path.normalize(value);
if (Type.isString(value)) {
Object.keys(this.aliases).forEach(function (key) {
value = value.replace('@{' + key + '}', this.aliases[key]);
}.bind(this));
return path.normalize(value);
} else {
throw new error.DataError({value: value}, 'DI.normalizePath: value is not string');
}
},

@@ -127,2 +131,18 @@ /**

* @author Igor Ivanovic
* @method DI#refereshNodeModuleCache
*
* @description
* Reset file cache
*/
refereshNodeModuleCache: function DI_refereshNodeModuleCache(file) {
var path = this.getFilePath(file),
key = require.resolve(path + '.js');
// because all modules in node are cached while executing tests we want to delete cached version
delete require.cache[key];
return path;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method DI#mockLoad

@@ -144,8 +164,4 @@ *

if (Type.isString(file)) {
// get file
path = this.getFilePath(file);
// because all modules in node are cached while executing tests we want to delete cached version
delete require.cache[require.resolve(path + '.js')];
// do require
return require(path);
return require(this.refereshNodeModuleCache(file));

@@ -152,0 +168,0 @@ } else if (Type.isFunction(file)) {

@@ -16,2 +16,3 @@ {

"core/controller": "@{framework}/core/controller",
"core/module": "@{framework}/core/module",
"core/routeRule": "@{framework}/core/routeRule",

@@ -31,2 +32,3 @@ "core/view": "@{framework}/core/view",

"interface/view": "@{framework}/interface/view",
"interface/module": "@{framework}/interface/module",

@@ -33,0 +35,0 @@ "cache/memory": "@{framework}/cache/memory",

@@ -19,7 +19,20 @@ "use strict";

ControllerInterface = Type.create({
_request: Type.OBJECT
_request: Type.OBJECT,
_routeInfo: Type.OBJECT
}, {
_invoke: function ControllerInterface(request) {
_invoke: function ControllerInterface(request, routeInfo) {
this._request = request;
["has", "get", "redirect", "forward", "addHeader", "onEnd", "createUrl"].forEach(function (method) {
this._routeInfo = routeInfo;
[
"has", "get", "redirect",
"forward", "addHeader", "onEnd",
"createUrl", "hasHeader", "getRequestHeader",
"getHeaders", "getMethod", "getRequestHeaders",
"isHeaderCacheUnModified", "sendNoChange", "getParsedUrl",
"stopChain", "render", "renderFile", "setStatusCode",
"getRequestBody",
"getActionName",
"getControllerName",
"getModuleName"
].forEach(function (method) {
if (!(method in this)) {

@@ -26,0 +39,0 @@ throw new error.DataError({method: method}, 'ControllerInterface: missing method in Controller object');

@@ -22,3 +22,3 @@ "use strict";

_invoke: function HttpServiceInterface() {
["on", "listen", "close", "setTimeout"].forEach(function (method) {
["on", "listen", "close", "setTimeout", "getEncoding"].forEach(function (method) {
if (!(method in this)) {

@@ -25,0 +25,0 @@ throw new error.DataError({method: method}, 'HttpServiceInterface: missing method in HttpService object');

@@ -5,3 +5,3 @@ {

"description": "Powerful lightweight mvc framework for nodejs",
"version": "0.1.0-beta-3",
"version": "0.1.0-beta-30",
"dependencies" : {

@@ -35,2 +35,3 @@ "mongoose": "3.8.x",

"keywords": [
"node",
"mvcjs",

@@ -37,0 +38,0 @@ "framework",

@@ -1,2 +0,124 @@

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/)
Mvcjs is a first nodejs framework which supports modules as bundles!
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
9. Modules
[Demo application](https://github.com/igorzg/mvcjs-testapp)
[Docs and live app](http://mvcjs.igorivanovic.info)
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'
});
};
```
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc