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-6 to 0.1.0-beta-60

framework/core/bodyParser.js

118

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 = null;
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

@@ -108,2 +136,12 @@ if (Type.isString(env.assetsPath)) {

}
// load config
if (Type.isString(env.config)) {
try {
di.load(envPath + '/' + env.config)(component, di, this);
} catch (e) {
throw new error.Exception('Initialize config: ' + envPath + '/' + env.config, e);
}
} else {
throw new error.DataError(env.config, 'Config file is not defined');
}
// if there is no logger init logger

@@ -115,6 +153,5 @@ if (!component.has('core/logger')) {

}
// add memory cache
if (!component.has('cache/memory')) {
component.set('cache/memory', {});
if (!component.has('storage/memory')) {
component.set('storage/memory', {});
}

@@ -129,6 +166,2 @@ // register router

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

@@ -138,12 +171,2 @@ if (!component.has('core/view')) {

}
// load config
if (Type.isString(env.config)) {
try {
di.load(envPath + '/' + env.config)(component, di);
} catch (e) {
throw new error.Exception('Initialize config: ' + envPath + '/' + env.config, e);
}
} else {
throw new error.DataError(env.config, 'Config file is not defined');
}
// http

@@ -161,6 +184,13 @@ if (!component.has('core/http')) {

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

@@ -170,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

@@ -180,7 +209,8 @@ server.on('close', function () {

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

@@ -196,2 +226,30 @@

* @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

@@ -198,0 +256,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'),

@@ -27,3 +29,4 @@ logger = component.get('core/logger'),

config: Type.OBJECT,
cache: Type.OBJECT
cache: Type.OBJECT,
regex: Type.REGEX
}, {

@@ -33,2 +36,3 @@ _construct: function Favicon_construct(config) {

path: '@{basePath}/storage/',
skip: false,
hook: '^\\/assets'

@@ -38,3 +42,4 @@ }, config);

logger.print('Assets.construct', config);
hook.set(new RegExp(this.config.hook), this.onRequest.bind(this));
this.regex = new RegExp(this.config.hook);
hook.set(this.regex, this.onRequest.bind(this));
},

@@ -52,8 +57,13 @@ /**

var maxAge = 60 * 60 * 24 * 30 * 12, // one year
filePath = this.config.path + api.parsedUrl.pathname,
mimeType,
file;
var url = api.parsedUrl.pathname,
maxAge = 60 * 60 * 24 * 30 * 12, // one year
filePath,
mimeType;
if (this.config.skip) {
url = url.replace(this.regex, '');
}
filePath = di.normalizePath(this.config.path + url);
mimeType = this.mimeType(filePath);

@@ -63,23 +73,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));
},

@@ -89,2 +115,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

@@ -106,4 +149,4 @@ *

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

@@ -110,0 +153,0 @@ });

@@ -66,2 +66,34 @@ "use strict";

* @author Igor Ivanovic
* @method Initialize#initOne
*
* @description
* Initialize
*/
checkDependency: function(component, components) {
var deps, depsName, depsConfig;
if (Type.assert(Type.STRING, component.name)) {
deps = this.getDependency(component.name);
if (Type.isArray(deps)) {
while (true) {
depsName = deps.shift();
if (!depsName) {
break;
}
if (!this.has(depsName)) {
if (!!components) {
depsConfig = this.find(depsName, components);
if (depsConfig) {
this.set(depsName, depsConfig);
break;
}
}
this.set(depsName, {});
}
}
}
}
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Initialize#components

@@ -73,3 +105,3 @@ *

init: function Component_init(components) {
var component, data, deps, depsName, depsConfig;
var component, data;
if (!Type.isArray(components)) {

@@ -79,3 +111,2 @@ throw new error.Exception('Component.init: components argument must be array type');

data = core.copy(components); // copy
while (true) {

@@ -86,23 +117,5 @@ component = data.shift();

}
if (Type.assert(Type.STRING, component.name)) {
deps = this.getDependency(component.name);
if (Type.isArray(deps)) {
while (true) {
depsName = deps.shift();
if (!depsName) {
break;
}
if (!this.has(depsName)) {
depsConfig = this.find(depsName, components);
if (depsConfig) {
this.set(depsName, depsConfig);
} else {
this.set(depsName, {});
}
}
}
}
if (!this.has(component.name)) {
this.set(component.name, component);
}
this.checkDependency(component, components);
if (!this.has(component.name)) {
this.set(component.name, component);
}

@@ -122,3 +135,5 @@ }

if (!this.has(name)) {
config.name = name;
try {
this.checkDependency(config);
if (!Type.isFunction(Func)) {

@@ -125,0 +140,0 @@ if (config.filePath) {

@@ -12,3 +12,3 @@ {

"core/logger",
"cache/memory",
"storage/memory",
"hooks/request"

@@ -18,3 +18,3 @@ ],

"core/logger",
"cache/memory",
"storage/memory",
"hooks/request"

@@ -27,3 +27,6 @@ ],

"core/logger"
],
"storage/session": [
"storage/memory"
]
}

@@ -5,4 +5,6 @@ "use strict";

Type = di.load('typejs'),
error = di.load('error'),
component = di.load('core/component'),
ControllerInterface = di.load('interface/controller'),
BodyParser = di.load('core/bodyParser'),
view = component.get('core/view'),

@@ -20,13 +22,137 @@ Controller;

*/
Controller = ControllerInterface.inherit({}, {
Controller = ControllerInterface.inherit({
__cookies__: Type.OBJECT
}, {
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#onEnd
* @method Controller#setStatusCode
* @param code {number}
* @description
* Set status code
*/
setStatusCode: function Controller_setStatusCode(code) {
this.__requestApi__.setStatusCode(code);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#stopChain
*
* @description
* On end
* Stop promise chain
*/
stopChain: function Controller_stopChain() {
return this.__requestApi__.stopPromiseChain();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#hasHeader
* @param key {string}
* @description
* has response header
*/
hasHeader: function Controller_hasHeader(key) {
return this.__requestApi__.hasHeader(key);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getRequestBody
*
* @description
* Get request body
*/
getRequestBody: function Controller_getRequestBody() {
return this.__requestApi__.getRequestBody();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getRequestHeader
* @param key {string}
* @description
* Get request header
*/
getRequestHeader: function Controller_getRequestHeader(key) {
return this.__requestApi__.getRequestHeader(key);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getHeaders
*
* @description
* Return response headers
*/
getHeaders: function Controller_getHeaders() {
return this.__requestApi__.getHeaders();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getMethod
*
* @description
* Return request method
*/
getMethod: function Controller_getMethod() {
return this.__requestApi__.getMethod();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getRequestHeaders
*
* @description
* Return request headers
*/
getRequestHeaders: function Controller_getRequestHeaders() {
return this.__requestApi__.getRequestHeaders();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#isHeaderCacheUnModified
*
* @description
* Check if cache is unmodified
*/
isHeaderCacheUnModified: function Controller_isHeaderCacheUnModified() {
return this.__requestApi__.isHeaderCacheUnModified();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#sendNoChange
*
* @description
* Send no change 304 response
*/
sendNoChange: function Controller_sendNoChange() {
return this.__requestApi__.sendNoChange();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getParsedUrl
*
* @description
* Return parsed url
*/
getParsedUrl: function Controller_getParsedUrl() {
return this.__requestApi__.parsedUrl;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#onEnd
* @param route {string}
* @param params {object}
* @description
* Create an url depends on route an parameters to router service
*/
createUrl: function Controller_createUrl(route, params) {
return this._request.createUrl(route, params);
return this.__requestApi__.createUrl(route, params);
},

@@ -37,8 +163,8 @@ /**

* @method Controller#onEnd
*
* @param callback {function}
* @description
* On end
* On end exec callback
*/
onEnd: function Controller_onEnd(callback) {
return this._request.onEnd(callback);
return this.__requestApi__.onEnd(callback);
},

@@ -49,3 +175,4 @@ /**

* @method Controller#addHeader
*
* @param key {string}
* @param value {string}
* @description

@@ -55,3 +182,3 @@ * Add header to request

addHeader: function Controller_addHeader(key, value) {
return this._request.addHeader(key, value);
return this.__requestApi__.addHeader(key, value);
},

@@ -62,3 +189,4 @@ /**

* @method Controller#forward
*
* @param route {string}
* @param params {object}
* @description

@@ -68,3 +196,3 @@ * Redirect to some url

forward: function Controller_forward(route, params) {
return this._request.forward(route, params);
return this.__requestApi__.forward(route, params);
},

@@ -74,4 +202,16 @@ /**

* @author Igor Ivanovic
* @method Controller#forwardUrl
* @param url {string}
* @description
* Redirect to some url
*/
forwardUrl: function Controller_forwardUrl(url) {
return this.__requestApi__.forwardUrl(url);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#redirect
*
* @param url {string}
* @param isTemp {boolean}
* @description

@@ -81,5 +221,4 @@ * Redirect to some url

redirect: function Controller_redirect(url, isTemp) {
return this._request.redirect(url, isTemp);
return this.__requestApi__.redirect(url, isTemp);
},
/**

@@ -89,3 +228,4 @@ * @since 0.0.1

* @method Controller#renderFile
*
* @param pathName {string}
* @param locals {object}
* @description

@@ -95,3 +235,3 @@ * Render file

renderFile: function Controller_renderFile(pathName, locals) {
return view.renderFile(pathName, locals);
return view.renderFile(pathName, locals, this.__config__.viewsPath);
},

@@ -102,3 +242,5 @@ /**

* @method Controller#render
*
* @param source {string}
* @param locals {object}
* @param escape {boolean}
* @description

@@ -113,5 +255,210 @@ * Render view

* @author Igor Ivanovic
* @method Controller#hasAction
* @method Controller#getActionName
*
* @description
* Get action name
* @return {string}
*/
getActionName: function Controller_getActionName() {
return this.__config__.action;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getControllerName
*
* @description
* Get controller name
* @return {string}
*/
getControllerName: function Controller_getControllerName() {
return this.__config__.controller;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getModuleName
*
* @description
* Get module name
* @return {string}
*/
getModuleName: function Controller_getModuleName() {
return this.__config__.module;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getSession
* @param key {string}
* @description
* Get session key
* @return {string}
*/
getSession: function Controller_getSession(key) {
var session = component.get('storage/session'),
session_id = this.getCookie(session.getCookieKey());
if (Type.isString(key)) {
return session.get(session_id + key);
}
throw new error.HttpError(500, {key: key, session_id: session_id}, 'Controller.getSession: key must be string type');
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#setSession key value
* @param key {string}
* @param value {object|mixed}
* @description
* Set session
* @return {string}
*/
setSession: function Controller_setSession(key, value) {
var session = component.get('storage/session'),
session_id = this.getCookie(session.getCookieKey());
if (!Type.isString(key)) {
throw new error.HttpError(500, {key: key, session_id: session_id}, 'Controller.getSession: key must be string type');
} else if (!session_id) {
session_id = this.__requestApi__.uuid() + '_' + (new Date).getTime();
this.setCookie(session.getCookieKey(), session_id, session.getExpiredTime());
}
session.set(session_id + key, value);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#removeSession
* @param key {string}
* @description
* Remove session key
* @return {string}
*/
removeSession: function Controller_removeSession(key) {
var session = component.get('storage/session'),
session_id = this.getCookie(session.getCookieKey());
if (Type.isString(key)) {
return session.remove(session_id + key);
}
throw new error.HttpError(500, {key: key, session_id: session_id}, 'Controller.removeSession: key must be string type');
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#setCookie
* @param key {string}
* @param value {string}
* @param expires {string|object|number}
* @param path {string}
* @param domain {string}
* @param isHttpOnly {boolean}
* @description
* Set cookie header
*/
setCookie: function Controller_setCookie(key, value, expires, path, domain, isHttpOnly) {
var cookie, date;
if (Type.isUndefined(key) || Type.isUndefined(value)) {
throw new error.HttpError(500, {
key: key,
value: value,
expires: expires,
path: path,
domain: domain,
isHttpOnly: isHttpOnly
}, 'Controller.setCookie: Key and Value must be provided!');
}
cookie = key + "=" + value;
if (!!expires) {
if (Type.isNumber(expires)) {
date = new Date();
date.setTime(date.getTime() + expires);
cookie += "; Expires=" + date.toGMTString();
} else if (Type.isString(expires)) {
cookie += "; Expires=" + expires;
} else if (Type.isDate(expires)) {
cookie += "; Expires=" + expires.toGMTString();
}
}
if (!!path) {
cookie += "; Path=" + path;
}
if (!!domain) {
cookie += "; Domain=" + domain;
}
if (!!isHttpOnly) {
cookie += "; HttpOnly";
}
this.addHeader('Set-cookie', cookie);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getCookies
*
* @description
* Parse cookies
* @return {object}
*/
getCookies: function Controller_getCookies() {
var data;
if (!!this.__cookies__) {
return this.__cookies__;
}
this.__cookies__ = {};
data = this.getRequestHeader('Cookie');
if (!!data) {
data.replace(/(\w+[^=]+)=([^;]+)/g, function (cookie, key, value) {
this.__cookies__[key] = value;
}.bind(this));
}
return this.__cookies__;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getCookie
* @param key {string}
* @description
* Get all cookies
* @return {null|string}
*/
getCookie: function Controller_getCookie(key) {
var cookies = this.getCookies();
if (cookies.hasOwnProperty(key)) {
return cookies[key];
}
return null;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#getParsedBody
*
* @description
* Parse body and return parsed object
* @return {object}
*/
getParsedBody: function Controller_getParsedBody() {
var parser = new BodyParser(
this.getRequestHeader('content-type'),
this.getRequestBody()
);
parser.parse();
return parser.getBody();
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Controller#hasAction
* @param name {string}
* @description
* Check if controller have action

@@ -127,3 +474,3 @@ * @return {boolean}

* @method Controller#getAction
*
* @param name {string}
* @description

@@ -130,0 +477,0 @@ * Get controller action

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

@@ -117,3 +147,3 @@ this.print('Publishing log write stream on port: ' + this.config.port);

date = new Date().toISOString();
logs += date + '\n';
logs += date + "\n";
try {

@@ -123,3 +153,3 @@ throw new Error();

url = core.trim(e.stack.split('\n').slice(3, 4).shift());
logs += url + '\n';
logs += url + "\n";
}

@@ -139,3 +169,3 @@ args.forEach(function (item) {

logs = logs.replace(/\\'/g, "'");
logs = logs.replace(/\\n/g, '\n');
logs = logs.replace(/\\n/g, "\n");
logs = logs.replace(/\\u001b/g, '\u001b');

@@ -149,2 +179,3 @@

try {
this.length += logs.length;
this.stream.write(logs);

@@ -151,0 +182,0 @@ } catch (e) {

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

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

@@ -40,6 +41,16 @@ router = component.get('core/router'),

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;

@@ -49,2 +60,5 @@ this.headers = {};

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

@@ -60,3 +74,3 @@ /**

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

@@ -108,5 +122,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

@@ -123,2 +163,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

@@ -186,4 +237,17 @@ *

addHeader: function Request_addHeader(key, value) {
var item;
if (Type.isString(key)) {
this.headers[key.toLowerCase()] = Type.isString(value) ? value : value.toString();
key = key.toLowerCase();
value = Type.isString(value) ? value : value.toString();
if (this.hasHeader(key) && !Type.isArray(this.headers[key])) {
item = this.getHeader(key);
this.headers[key] = [];
this.headers[key].push(item);
this.headers[key].push(value);
} else if (this.hasHeader(key) && Type.isArray(this.headers[key])) {
this.headers[key].push(value);
} else {
this.headers[key] = value;
}
} else {

@@ -199,2 +263,30 @@ throw new error.HttpError(500, {

* @author Igor Ivanovic
* @method Request#forwardUrl
*
* @description
* Forward to route
*/
forwardUrl: function Request_forwardUrl(url) {
var request;
if (this.url === url) {
throw new error.HttpError(500, {
url: url
}, 'Cannot forward to same url');
} else {
this.stopPromiseChain();
request = new Request({
request: this.request,
response: this.response,
isForwarded: true,
body: this.body
}, url);
logger.print('Request.forward.url', url);
return request.parse();
}
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Request#forward

@@ -216,8 +308,12 @@ *

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

@@ -238,2 +334,4 @@ return request.parse();

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

@@ -255,4 +353,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('');
},

@@ -280,2 +379,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())

@@ -285,10 +426,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
},

@@ -316,24 +462,58 @@ /**

* Handle error
* @return boolean
*/
_handleError: function Request_handleError(response) {
var request;
if (this.isRendered) {
// we have multiple recursion in parse for catching
return false;
}
// log error request
logger.print('Request.error', {
url: this.url,
status: this.statusCode,
id: this.id,
isRendered: this.isRendered,
content_type: this.getHeader('content-type')
}, response);
// 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 && !!router.getErrorRoute()) {
// return new request
request = new Request({
request: this.request,
response: this.response,
isForwarded: true,
body: this.body,
isERROR: true
}, router.createUrl(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);
}
this.isERROR = true;
return this._resolveRoute([router.getErrorRoute(), response]).then(null, this._handleError);
// 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);
}

@@ -348,26 +528,37 @@ },

* 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!');
}
}
logger.print('Request.render', {
url: this.url,
status: this.statusCode,
id: this.id,
isRendered: this.isRendered,
content_type: this.getHeader('content-type')
});
this.isRendered = true;
return true;
},

@@ -391,2 +582,3 @@

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

@@ -397,4 +589,8 @@ 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),
parsedUrl: core.copy(this.parsedUrl)
parsedUrl: core.copy(this.parsedUrl),
forwardUrl: this.forward.bind(this),
uuid: this._uuid.bind(this)
};

@@ -412,7 +608,11 @@ },

if (!promise) {
return new Promise(function(resolve, reject) {
return new Promise(function (resolve, reject) {
try {
resolve(next.apply(next, arguments));
} catch (e) {
reject(new error.HttpError(500, arguments, "Error on executing action", e));
if (e instanceof error.HttpError) {
reject(e);
} else {
reject(new error.HttpError(500, {}, "Error on executing action", e));
}
}

@@ -423,4 +623,7 @@ });

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

@@ -431,3 +634,7 @@ function _handler() {

} catch (e) {
throw new error.HttpError(500, arguments, "Error on executing action", e);
if (e instanceof error.HttpError) {
throw e;
} else {
throw new error.HttpError(500, {}, "Error on executing action", e);
}
}

@@ -439,3 +646,3 @@ }

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

@@ -445,10 +652,8 @@ * @description

*/
_handleRoute: function Request_handleRoute() {
var controllerToLoad = '@{controllersPath}/' + this.controller,
_handleController: function Request_handleController(controllersPath, viewsPath) {
var controllerToLoad = controllersPath + this.controller,
LoadedController,
controller,
action,
promise,
afterActionPromise = false,
afterEachPromise = false;
promise;

@@ -461,4 +666,13 @@ 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,
viewsPath: viewsPath
});
if (!(controller instanceof ControllerInterface)) {

@@ -504,7 +718,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));
}

@@ -514,8 +728,37 @@

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(path) {
var moduleToLoad = path + 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"');
}
return this._handleController(module.getControllersPath(), module.getViewsPath());
},
/**

@@ -529,7 +772,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();

@@ -544,3 +785,7 @@ this.params = routeRule.shift();

return this._handleRoute();
if (!!this.module) {
return this._handleModule(di.getAlias('modulesPath'));
}
return this._handleController(di.getAlias('controllersPath'), di.getAlias('viewsPath'));
}

@@ -547,0 +792,0 @@

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

routes: Type.ARRAY,
createUrlRgx: Type.REGEX,
config: Type.OBJECT

@@ -30,5 +31,13 @@ }, {

this.routes = [];
this.createUrlRgx = /\/\//g;
this.config = core.extend({
errorRoute: false
errorRoute: false,
errorUrl: '/error'
}, config);
// add error route so we can resolve it
this.add({
pattern: this.config.errorUrl,
route: this.config.errorRoute ? this.config.errorRoute : 'core/error',
method: ['GET', 'HEAD', 'POST', 'PUT', 'DELETE', 'TRACE', 'OPTIONS', 'CONNECT', 'PATCH']
});
},

@@ -72,3 +81,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');
}

@@ -78,8 +87,18 @@

this.routes.push(rule);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Router#normalizeUrl
*
* @description
* Create url
* @return {string}
*/
normalizeUrl: function Router_normalizeUrl(url) {
return url.replace(this.createUrlRgx, '/').replace(this.createUrlRgx, '/');
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method Router#createUrl

@@ -92,3 +111,3 @@ *

createUrl: function Router_createUrl(route, params) {
var i, len = this.routes.length, routeRule, url, anchor = '';
var routeRule, url, anchor = '', routes;

@@ -112,8 +131,9 @@ if (!Type.isString(route)) {

params = core.copy(params);
routes = this.routes.slice();
for (i = len - 1; i > -1; --i) {
routeRule = this.routes[i];
while (routes.length) {
routeRule = routes.shift();
url = routeRule.createUrl(route, params);
if (url) {
return '/' + url + anchor;
return this.normalizeUrl('/' + url + anchor);
}

@@ -127,3 +147,4 @@ }

}
return url + anchor;
return this.normalizeUrl(url + anchor);
},

@@ -139,17 +160,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 +230,3 @@ /**

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

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

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

@@ -222,0 +243,0 @@ });

@@ -12,4 +12,5 @@ "use strict";

ROUTE_MATCH = /<(\w+)>/ig,
PATTERN_CAPTURE_REGEX = /\(((\?P?<(\w+)>)((:?(\(([^\/]+)\)))?|([^\)]+))|([^\)]+))\)/g,
IS_NAMED = /\(\?P?<(\w+)>([^\)]+)\)/,
PATTERN_CAPTURE_REGEX = /\(\??P?(<(\w+)>)?([^\)]+\)?)\)?\)/g,
IS_NAMED = /<(\w+)>/,
IS_GROUP = /^\(([^\)]+)\)$/,
RouteRule;

@@ -43,2 +44,3 @@ /**

if (!config.pattern) {

@@ -75,6 +77,8 @@ throw new error.HttpError(500, config, 'RouteRule: rule object must have an pattern property');

if (Array.isArray(matches) && matches.length) {
matches.forEach(function (item) {
var esc, nPattern;
name = item[1];
nPattern = Type.isString(item[2]) ? item[2] : '[^\/]+';
nPattern = Type.isString(item[2]) ? item[2] : '([^\/]+)';
esc = {

@@ -85,2 +89,3 @@ key: '<' + name + '>',

escapePattern.push(esc);
if (this.find(this.routeParams, name)) {

@@ -91,3 +96,3 @@ escapeRule.push(esc);

key: name,
value: nPattern === '[^\/]+' ? '' : core.createRegex('^' + nPattern + '$')
value: nPattern === '([^\/]+)' ? '' : core.createRegex('^' + nPattern + '$')
});

@@ -315,2 +320,3 @@ }

var matches = core.match(PATTERN_CAPTURE_REGEX, re), newRegex = re;
if (matches.length) {

@@ -320,9 +326,18 @@ matches = matches.map(this.toObject);

var index = Object.keys(item).length - 3;
item.isNamed = IS_NAMED.test(item[0]);
item.isNamed = IS_NAMED.test(item[1]);
if (item.isNamed) {
item.pattern = '(' + item[index] + ')';
item.key = item[3];
if (IS_GROUP.test(item[index])) {
item.pattern = item[index];
} else {
item.pattern = '(' + item[index] + ')';
}
item.key = item[2];
newRegex = newRegex.replace(item[0], item.pattern);
} else {
item.pattern = item[0];
if (IS_GROUP.test(item[index])) {
item.pattern = item[index];
} else {
item.pattern = '(' + item[index] + ')';
}
item.key = null;

@@ -354,3 +369,2 @@ }

rgx = this.toRegex(rgx);
}

@@ -411,3 +425,3 @@ if (Type.isObject(rgx) && Type.isRegExp(rgx.regex)) {

str = str.trim();
if (strip) {
if (strip && str !== strip) {
str = str.replace(core.createRegex('^' + strip), '');

@@ -414,0 +428,0 @@ str = str.replace(core.createRegex(strip + '$'), '');

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

ViewInterface = di.load('interface/view'),
ModuleInterface = di.load('interface/module'),
swig = di.load('swig'),

@@ -27,3 +28,6 @@ error = di.load('error'),

swig: Type.OBJECT,
preloaded: Type.OBJECT
preloaded: Type.OBJECT,
paths: Type.ARRAY,
aliasRegex: Type.REGEX,
normalizers: Type.ARRAY
},

@@ -34,3 +38,6 @@ {

// extend
this.aliasRegex = /@{.*}/g;
this.preloaded = {};
this.paths = [];
this.normalizers = [];
this.config = core.extend({

@@ -44,12 +51,27 @@ cache: false,

cacheComponent: false,
themes: '@{appPath}/themes/',
views: '@{appPath}/views/',
suffix: '.twig',
theme: false
extensions: false,
defaultTheme: 'default',
themes: []
}, config);
this.normalizers.push(this.config.views);
di.setAlias('viewsPath', this.config.views);
di.setAlias('themesPath', this.config.themes);
if (Type.isArray(this.config.themes)) {
if (this.config.themes.indexOf(this.config.defaultTheme) === -1) {
this.config.themes.push(this.config.defaultTheme);
}
this.config.themes.forEach(function (name) {
this.paths.push(this.config.views + name + '/');
}.bind(this));
} else {
throw new error.HttpError(500, this.config, 'View.construct: themes are not array type');
}
this.setModulesViewsPath(di.getAlias('modulesPath'));
if (Type.assert(Type.STRING, this.config.suffix)) {

@@ -67,12 +89,21 @@ this.suffix = new RegExp(this.config.suffix + '$');

defaults = core.extend({}, this.config);
// don't use swig cache!
if (this.config.cache) {
this.preloadTemplates(di.getAlias('viewsPath'));
this.preloadTemplates(di.getAlias('themesPath'));
defaults.cache = {
get: this.getPreloaded.bind(this),
set: this.setPreloaded.bind(this)
};
}
defaults = core.extend({}, this.config);
// don't use swig cache!
defaults.cache = false;
this.swig = new swig.Swig(defaults);
if (this.config.extensions) {
di.load(this.config.extensions)(this, di);
}
if (this.config.cache) {
this.paths.forEach(this.preloadTemplates.bind(this));
}
logger.print("View.construct", this.config);

@@ -83,2 +114,48 @@ },

* @author Igor Ivanovic
* @method View#setModulesViewsPath
*
* @description
* Set modules path
*/
setModulesViewsPath: function View_setModulesViewsPath(dir) {
var list, name, moduleToLoad, LoadedModule, moduleInstance;
if (this.isDir(dir)) {
list = this.readDir(dir);
while (true) {
name = list.shift();
if (!name) {
break;
}
moduleToLoad = dir + '/' + name;
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');
}
moduleInstance = new LoadedModule(name);
if (!(moduleInstance instanceof ModuleInterface)) {
throw new error.HttpError(500, moduleInstance, 'Module must be instance of ModuleInterface "core/module"');
}
this.normalizers.push(moduleInstance.getViewsPath());
this.config.themes.forEach(function (name) {
this.paths.push(moduleInstance.getViewsPath() + name + '/');
}.bind(this));
}
}
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method View#setPreloaded

@@ -89,3 +166,3 @@ *

*/
setPreloaded: function (key, value) {
setPreloaded: function View_setPreloaded(key, value) {
logger.log('View.setPreloaded: ', key + '\n' + value);

@@ -101,5 +178,6 @@ this.preloaded[key] = value;

* Get preloaded template
* @return {string|boolean}
*/
getPreloaded: function (key) {
if (this.hasPreloaded(key)) {
getPreloaded: function View_getPreloaded(key) {
if (this.preloaded.hasOwnProperty(key)) {
return this.preloaded[key];

@@ -112,13 +190,16 @@ }

* @author Igor Ivanovic
* @method View#hasPreloaded
* @method View#isFile
*
* @description
* Check if have preloaded
* Is file
* @return {string|boolean}
*/
hasPreloaded: function (key) {
var isPreloaded = this.preloaded.hasOwnProperty(key);
if (!!this.config.cache && !isPreloaded) {
throw new error.DataError({key: key}, "ENOENT, no such file or directory");
isFile: function View_isFile(path) {
try {
path = di.normalizePath(path);
return fs.statSync(path).isFile();
} catch (e) {
logger.print('View.isFile path is not valid file', {path: path});
}
return isPreloaded;
return false;
},

@@ -128,34 +209,16 @@ /**

* @author Igor Ivanovic
* @method View#preloadTemplates
* @method View#isDir
*
* @description
* Preload all templates at bootstrap
* Is directory
* @return {string|boolean}
*/
preloadTemplates: function View_preloadTemplates(dir) {
var list, name;
if (isDir(dir)) {
list = readDir(dir);
while (true) {
name = list.shift();
if (!name) {
break;
}
this.preloadTemplates(di.normalizePath(dir + '/' + name));
}
} else if (isFile(dir) && this.suffix.test(dir)) {
this.setPreloaded(dir, di.readFileSync(dir));
}
function readDir(path) {
return fs.readdirSync(path);
}
function isDir(path) {
isDir: function View_isDir(path) {
try {
path = di.normalizePath(path);
return fs.statSync(path).isDirectory();
} catch (e) {
logger.print('View.isDir path is not valid path', {path: path});
}
function isFile(path) {
return fs.statSync(path).isFile();
}
return false;
},

@@ -165,15 +228,10 @@ /**

* @author Igor Ivanovic
* @method View#setThemesPath
* @method View#readDir
*
* @description
* Set theme path
* Read directory
*/
setTheme: function View_setTheme(name) {
if (Type.assert(Type.STRING, name)) {
this.config.theme = name;
} else if(Type.isNull(name)) {
this.config.theme = null;
} else {
throw new error.HttpError(500, {name: name}, "ViewLoader.setTheme: name must be string type");
}
readDir: function View_readDir(path) {
path = di.normalizePath(path);
return fs.readdirSync(path);
},

@@ -183,35 +241,28 @@ /**

* @author Igor Ivanovic
* @method View#getPath
* @method View#preloadTemplates
*
* @description
* Get path
* Preload all templates at bootstrap
*/
getPath: function View_getPath(skipTheme) {
var path = '@{viewsPath}/';
if (Type.isString(this.config.theme) && !skipTheme) {
path = '@{themesPath}/' + this.config.theme + '/';
preloadTemplates: function View_preloadTemplates(dir) {
var list, name;
if (this.isDir(dir)) {
list = this.readDir(dir);
while (true) {
name = list.shift();
if (!name) {
break;
}
this.preloadTemplates(di.normalizePath(dir + '/' + name));
}
} else if (this.isFile(dir) && this.suffix.test(dir)) {
this.setPreloaded(dir, this.swig.compileFile(dir));
}
return di.normalizePath(path);
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method View#normalizeResolveValue
*
* @description
* Normalize resolve value
* @return {string}
*/
normalizeResolveValue: function View_normalizeResolveValue(value) {
var theme = this.getPath(), view = this.getPath(true);
if (Type.isString(value) && value.match(theme)) {
return value.replace(theme, "").replace(this.suffix, "");
} else if (Type.isString(value) && value.match(view)) {
return value.replace(view, "").replace(this.suffix, "");
}
return value;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method View#resolve

@@ -223,20 +274,68 @@ *

*/
resolve: function View_resolve(to, from) {
return this.getPath() + this.normalizeResolveValue(to) + this.config.suffix;
},
/**
* @since 0.0.1
* @author Igor Ivanovic
* @method View#readTemplate
*
* @description
* Read template
* @return {string};
*/
readTemplate: function View_readTemplate(path) {
if (this.hasPreloaded(path)) {
return this.getPreloaded(path);
} else {
return di.readFileSync(path);
resolve: function View_resolve(toPath, fromPath) {
var file = di.normalizePath(toPath),
themes = this.config.themes.slice(),
theme,
re,
filePath,
normalizers = this.normalizers.slice(),
isNormalized = false,
path,
trace = [];
// file name normalizers
while (normalizers.length) {
path = di.normalizePath(normalizers.shift());
if (file.match(path)) {
file = file.replace(path, '').replace(this.suffix, '');
isNormalized = true;
break;
}
}
// try normalize fromPath
if (!isNormalized && !!fromPath) {
normalizers = this.normalizers.slice();
fromPath = di.normalizePath(fromPath);
// file name normalizers
while (normalizers.length) {
path = di.normalizePath(normalizers.shift());
if (fromPath.match(path)) {
isNormalized = true;
break;
}
}
}
// check themes
if (isNormalized) {
while (themes.length) {
theme = themes.shift();
re = new RegExp('^' + theme + '/');
file = file.replace(re, '');
filePath = di.normalizePath(path + theme + '/' + file + this.config.suffix);
if (this.isFile(filePath)) {
return filePath;
}
trace.push({
theme: theme,
path: path,
filePath: filePath
});
}
}
throw new error.HttpError(500, {
from: fromPath,
load: toPath,
filePath: filePath,
paths: this.paths,
isNormalized: isNormalized,
file: file,
path: path,
trace: trace,
themes: this.config.themes
}, "View.resolve: template don't exists");
},

@@ -252,13 +351,15 @@ /**

*/
load: function View_load(identifier, cb) {
load: function View_load(path, cb) {
var template = '';
try {
template = this.readTemplate(identifier);
template = di.readFileSync(path);
} catch (e) {
identifier = this.normalizeResolveValue(identifier);
identifier = this.getPath(true) + identifier + this.config.suffix;
template = this.readTemplate(identifier);
logger.print('ViewLoader.load.error', {
path: path,
cb: cb,
e: e
});
} finally {
logger.print('ViewLoader.load', {
identifier: identifier,
path: path,
template: template,

@@ -343,4 +444,7 @@ cb: cb

*/
renderFile: function View_renderFile(pathName, locals) {
return this.swig.renderFile(pathName, locals);
renderFile: function View_renderFile(templateName, locals, viewsPath) {
if (!viewsPath) {
viewsPath = di.getAlias('viewsPath');
}
return this.swig.renderFile(viewsPath + templateName, locals);
}

@@ -347,0 +451,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,4 +16,6 @@ {

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

@@ -25,3 +27,4 @@ "db/mongo": "@{framework}/db/mongo",

"interface/requestHooks": "@{framework}/interface/requestHooks",
"interface/cache": "@{framework}/interface/cache",
"interface/storage": "@{framework}/interface/storage",
"interface/controller": "@{framework}/interface/controller",

@@ -32,6 +35,8 @@ "interface/routeRule": "@{framework}/interface/routeRule",

"interface/view": "@{framework}/interface/view",
"interface/module": "@{framework}/interface/module",
"cache/memory": "@{framework}/cache/memory",
"storage/memory": "@{framework}/storage/memory",
"storage/session": "@{framework}/storage/session",
"typejs": "static-type-js"
}

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

ControllerInterface = Type.create({
_request: Type.OBJECT
__requestApi__: Type.OBJECT,
__config__: Type.OBJECT
}, {
_invoke: function ControllerInterface(request) {
this._request = request;
["has", "get", "redirect", "forward", "addHeader", "onEnd", "createUrl"].forEach(function (method) {
_invoke: function ControllerInterface(requestApi, config) {
this.__requestApi__ = requestApi;
this.__config__ = config;
[
"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');

@@ -25,4 +25,4 @@ "use strict";

"setLoader", "setFilter", "setTag", "setExtension",
"render", "renderFile", "setTheme", "getPath",
"normalizeResolveValue", "resolve", "load"
"render", "renderFile",
"resolve", "load"
].forEach(

@@ -29,0 +29,0 @@ function (method) {

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

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

@@ -23,9 +23,9 @@ "mongoose": "3.8.x",

"type": "git",
"url": "git://github.com/igorzg/node-mvc.git"
"url": "git://github.com/AdminJuwel191/node-mvc.git"
},
"bugs": {
"url": "https://github.com/igorzg/node-mvc/issues",
"url": "https://github.com/AdminJuwel191/node-mvc/issues",
"email": "igor.zg1987@gmail.com"
},
"homepage": "https://github.com/igorzg/node-mvc",
"homepage": "https://github.com/AdminJuwel191/node-mvc",
"author": {

@@ -36,2 +36,3 @@ "name": "Igor Ivanovic",

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

@@ -48,2 +49,2 @@ "framework",

"license": "MIT"
}
}

@@ -1,2 +0,3 @@

MVC JS [![Build Status](https://api.travis-ci.org/igorzg/node-mvc.svg?branch=master)](https://travis-ci.org/igorzg/node-mvc) beta
MVC JS [![Build Status](https://api.travis-ci.org/AdminJuwel191/node-mvc.svg?branch=master)](https://travis-ci.org/igorzg/node-mvc) beta
=====

@@ -6,2 +7,4 @@

Mvcjs is a first nodejs framework which supports modules as bundles!
Features

@@ -17,5 +20,8 @@ ====

8. Logger
9. Modules
[Demo application](https://github.com/igorzg/mvcjs-testapp)
[Docs and live app](http://mvcjs.igorivanovic.info)
Getting started

@@ -62,3 +68,2 @@ ====

"name": "core/view",
"themes": "@{appPath}/themes/",
"views": "@{appPath}/views/",

@@ -65,0 +70,0 @@ "theme": "default",

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