Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 1 addition & 15 deletions dist/lib/core/controller/controller.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,6 @@ class ControllerCollection {
}
DispatchController(controllerName, actionName, idString, search, dispatch) {
return __awaiter(this, void 0, void 0, function* () {
let searchGroup = new Map();
if (search && search.length > 2) {
if (!SearchRegex.test(search))
console.error('search not valid:', search);
else {
let all = search.match(SearchRegex)[1];
all.split('&').forEach(query => {
let match = query.match(QueryRegex);
if (match && match.length === 3) {
searchGroup.set(match[1], match[2]);
}
});
}
}
const __innerOperations = () => __awaiter(this, void 0, void 0, function* () {
if (this.Has(controllerName)) {
let controller = this.Controllers[controllerName].Controller;
Expand Down Expand Up @@ -95,7 +81,7 @@ class ControllerCollection {
}
};
try {
context = yield controller[action](dispatch.Request, shResponse, dispatch.Method, idString, searchGroup);
context = yield controller[action](dispatch.Request, shResponse, dispatch.Method, idString, search);
}
catch (e) {
if (e.message.match(/.*not.*define/i))
Expand Down
1 change: 1 addition & 0 deletions dist/lib/core/error/error.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ export declare enum CompileTimeError {
SH010101 = 65793,
SH010102 = 65794,
SH010103 = 65795,
SH010201 = 66049,
}
export declare enum RuntimeError {
SH020101 = 131329,
Expand Down
2 changes: 2 additions & 0 deletions dist/lib/core/error/error.js
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,7 @@ var CompileTimeError;
CompileTimeError[CompileTimeError["SH010101"] = 65793] = "SH010101";
CompileTimeError[CompileTimeError["SH010102"] = 65794] = "SH010102";
CompileTimeError[CompileTimeError["SH010103"] = 65795] = "SH010103";
CompileTimeError[CompileTimeError["SH010201"] = 66049] = "SH010201";
})(CompileTimeError = exports.CompileTimeError || (exports.CompileTimeError = {}));
;
var RuntimeError;
Expand All @@ -187,6 +188,7 @@ const ErrorTemplate = {
SH010101: "Controller '$${0}' is not a valid controller.",
SH010102: "Controller path '$${0}' does not exist on '$${1}'.",
SH010103: "Unresolved controller file.",
SH010201: "Invalid route rule: $${0}. The possible reason is:$${1}",
SH020101: "Controller '$${0}' not registered.",
SH020102: "Default router not found.",
SH020201: "View file '$${0}' does not exist on '$${1}'.",
Expand Down
3 changes: 3 additions & 0 deletions dist/lib/route/route.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,13 @@ export declare class Route {
private Rule;
private Default;
private IgnoredRules;
private RulePrefix;
constructor();
MapRoute(routeName: string, routeRule: string, defaultValue: RouteValue): void;
IgnoreRoute(routes: (string | RegExp)[]): void;
private ValidateRule(input);
private Ignored(p);
RunRoutev1(path: string): RouteValue;
RunRoute(path: string): RouteValue;
static GetRoute(): Route;
}
Expand Down
83 changes: 81 additions & 2 deletions dist/lib/route/route.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const error_1 = require("../core/error/error");
const ControllerRegexp = /^\/((?:(?:\.[a-z\d_-])|(?:[a-z]))[a-z\d_-][a-z\d_.-]+)/;
const ActionRegexp = /^\/((?:(?:[a-z_])|(?:[a-z]))[a-z\d_.-]+)/;
const IdRegexp = /^\/((?:\d+\.?\d*)|(?:0x[a-f\d]+)|(?:[01]+b)|(?:\d+e[+-]?\d+))$/i;
class Route {
constructor() {
this.Name = 'default';
this.Rule = '{controller}/{action}/{id}';
this.Rule = '/{controller}/{action}/{id}';
this.Default = {
Controller: 'home',
Action: 'index',
Expand All @@ -13,6 +17,12 @@ class Route {
}
MapRoute(routeName, routeRule, defaultValue) {
this.Name = routeName;
if (!routeRule.startsWith('/'))
routeRule = '/' + routeRule;
if (!this.ValidateRule(routeRule)) {
this.Rule = routeRule;
this.RulePrefix = routeRule.slice(0, routeRule.indexOf('/{controller}'));
}
this.Rule = routeRule;
this.Default = {
Controller: (defaultValue && defaultValue.Controller) ? defaultValue.Controller : 'home',
Expand Down Expand Up @@ -43,6 +53,15 @@ class Route {
throw new Error('Should be either string or RegExp object.');
});
}
ValidateRule(input) {
if (!input.includes('/{controller}/{action}'))
throw new Error(error_1.ErrorManager.RenderError(error_1.CompileTimeError.SH010201, input, 'controller and action fields are required'));
if (!input.match(/^[a-z\d._{}\/-]+$/i))
throw new Error(error_1.ErrorManager.RenderError(error_1.CompileTimeError.SH010201, input, 'there are some invalid characters.'));
if (!input.endsWith('}/') && !input.endsWith('}'))
throw new Error(error_1.ErrorManager.RenderError(error_1.CompileTimeError.SH010201, input, 'invalid rule ending'));
return true;
}
Ignored(p) {
if (!p)
return true;
Expand All @@ -64,7 +83,7 @@ class Route {
});
return ignored;
}
RunRoute(path) {
RunRoutev1(path) {
if (!path)
path = '';
if (path.startsWith('/'))
Expand Down Expand Up @@ -116,6 +135,66 @@ class Route {
};
return result;
}
RunRoute(path) {
if (!path || path.length === 0)
path = '/';
else if (!path.startsWith('/'))
path = '/' + path;
if (path.startsWith(this.RulePrefix))
path = path.replace(this.RulePrefix, '');
else if (this.RulePrefix && path !== '/')
return void 0;
let params = null;
if (path.includes('?')) {
let temp = {};
try {
let paramstr = path.slice(path.indexOf('?') + 1);
paramstr.split('&').forEach(ele => {
let key = ele.slice(0, ele.indexOf('='));
let value = ele.slice(ele.indexOf('=') + 1);
Object.defineProperty(temp, key, { value: value, writable: false });
});
}
catch (err) { }
params = temp;
path = path.slice(0, path.indexOf('?'));
}
let result = {};
result.Search = params;
let ctrlr_match = path.match(ControllerRegexp);
if (!ctrlr_match || ctrlr_match.length !== 2) {
if (path === '/') {
result = {
Controller: this.Default.Controller,
Action: this.Default.Action,
Id: this.Default.Id,
Search: params
};
}
else
return void 0;
}
else {
result.Controller = ctrlr_match[1];
path = path.replace('/' + result.Controller, '');
}
let act_match = path.match(ActionRegexp);
if (!act_match || act_match.length !== 2) {
result.Action = this.Default.Action;
}
else {
result.Action = act_match[1];
path = path.replace('/' + result.Action, '');
}
let id_match = path.match(IdRegexp);
if (!id_match || id_match.length !== 2) {
result.Id = this.Default.Id;
}
else {
result.Id = id_match[1];
}
return result;
}
static GetRoute() {
return Route.Instance;
}
Expand Down
8 changes: 8 additions & 0 deletions doc/Errors.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ Category | Type | Unique | Cause
01 | 01 | 01 | [Controller name not valid](#sh010101)
01 | 01 | 02 | [Controller path not valid](#sh010102)
01 | 01 | 03 | [Controller cannot be resolved](#sh010103)
01 | 02 | 01 | [Route rule not valid](#sh010201)
02 | 01 | 01 | [Controller not registered](#sh020101)
02 | 01 | 02 | [Default controller not found](#sh020102)
02 | 07 | 01 | [AppStart method not found](#sh020701)
Expand Down Expand Up @@ -80,6 +81,13 @@ A controller path does not match any files in the content directory. Check the g

The controller file is not able to be resolved. May be you used a `const controller = ...` expression?

#### SH010201

<span id='sh010201'></span>
***Invalid route rule detected***

The custom route rule defined in serverhubinstance.Run() method is not supported.

## Runtime Errors (RTE) (SH02____)

There are five types of runtime errors:
Expand Down
37 changes: 12 additions & 25 deletions lib/core/controller/controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,30 +23,30 @@ const QueryRegex = /((?:(?:[-a-z\d$_.+!*'(),]|(?:%[\da-f]{2}))|[;:@])+)=((?:(?:[
*/
class ControllerCollection {
private Controllers = {};
public Add(bundle: ControllerBundle): void {
public Add (bundle: ControllerBundle): void {
this.Controllers[bundle.Name] = bundle;
}
public Remove(controllerName: string): ControllerBundle {
public Remove (controllerName: string): ControllerBundle {
if (this.Controllers.hasOwnProperty(controllerName)) {
let bundle = this.Controllers[controllerName];
delete this.Controllers[controllerName];
return bundle;
}
return void 0;
}
public Has(controllerName: string): boolean {
public Has (controllerName: string): boolean {
if (this.Controllers.hasOwnProperty(controllerName)) {
return true;
}
return false;
}

public HasAction(controllerName: string, actionName: string): boolean {
public HasAction (controllerName: string, actionName: string): boolean {
actionName = actionName.toLowerCase();
return (this.Controllers.hasOwnProperty(controllerName) && this.Controllers[controllerName].Controller.hasOwnProperty(actionName));
}

public async DispatchController(controllerName: string, actionName: string, idString: string, search: string, dispatch: ControllDispatch): Promise<boolean> {
public async DispatchController (controllerName: string, actionName: string, idString: string, search: string, dispatch: ControllDispatch): Promise<boolean> {
/* handling search
*
* According to RFC 1738 (https://tools.ietf.org/html/rfc1738):
Expand All @@ -69,20 +69,7 @@ class ControllerCollection {
* hex = digit | "A" | "B" | "C" | "D" | "E" | "F" |
* "a" | "b" | "c" | "d" | "e" | "f"
*/
let searchGroup = new Map<string, string>();
if (search && search.length > 2) {
if (!SearchRegex.test(search))
console.error('search not valid:', search);
else {
let all = search.match(SearchRegex)[1];
all.split('&').forEach(query => {
let match = query.match(QueryRegex);
if (match && match.length === 3) {
searchGroup.set(match[1], match[2]);
}
})
}
}


const __innerOperations = async () => {
if (this.Has(controllerName)) {
Expand Down Expand Up @@ -129,7 +116,7 @@ class ControllerCollection {
}
};
try {
context = await controller[action](dispatch.Request, shResponse, dispatch.Method, idString, searchGroup);
context = await controller[action](dispatch.Request, shResponse, dispatch.Method, idString, search);
} catch (e) {
if ((e as Error).message.match(/.*not.*define/i))
console.error('Undefined reference. Did you missed a "this" reference while using controller scope variables?')
Expand Down Expand Up @@ -168,19 +155,19 @@ export class Controller {
* Register a new controller
* @param controller Controller file name
*/
public static Register(controller: string) {
public static Register (controller: string) {
Controller.Collection.Add(Register(controller));
}

public static RegisterM(controller: string) {
public static RegisterM (controller: string) {
Controller.Collection.Add(RegisterM(controller));
}

/**
* Unregister a controller (not frequently used)
* @param controllerName Controller file name
*/
public static Unregister(controllerName: string) {
public static Unregister (controllerName: string) {
Controller.Collection.Remove(controllerName);
}

Expand All @@ -191,15 +178,15 @@ export class Controller {
* @param request HTTP request info
* @param response Server response
*/
public static async Dispatch(method: string, route: RouteValue, request: IncomingMessage, response: ServerResponse): Promise<boolean> {
public static async Dispatch (method: string, route: RouteValue, request: IncomingMessage, response: ServerResponse): Promise<boolean> {
return Controller.Collection.DispatchController(route.Controller, route.Action, route.Id, route.Search, {
Method: method,
Request: request,
Response: response
} as ControllDispatch).then(() => true).catch(() => false);
}

public static Dispatchable(controllerName: string, actionName: string): boolean {
public static Dispatchable (controllerName: string, actionName: string): boolean {
return Controller.Collection.HasAction(controllerName, actionName);
}
}
Expand Down
8 changes: 5 additions & 3 deletions lib/core/error/error.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@

import { GlobalEnvironmentVariables } from "../global";
export class ErrorManager {
public static RenderError(errorEnum: CompileTimeError | RuntimeError, ...params): string {
public static RenderError (errorEnum: CompileTimeError | RuntimeError, ...params): string {
if (errorEnum === void 0)
throw new Error('SH000000: Fatal error, code not correct');
if (CompileTimeError[errorEnum] !== void 0) {
Expand All @@ -27,7 +27,7 @@ export class ErrorManager {
return RuntimeError[errorEnum] + ': ' + errortemplate;
} else throw new Error('ErrorManager cannot determine your error');
}
public static RenderErrorAsHTML(error: Error): string {
public static RenderErrorAsHTML (error: Error): string {
if (!(error instanceof Error))
throw new Error('Error not defined');
let stack = '';
Expand Down Expand Up @@ -167,7 +167,8 @@ export enum CompileTimeError {
// - controller
SH010101 = 0x010101,
SH010102 = 0x010102,
SH010103 = 0x010103
SH010103 = 0x010103,
SH010201 = 0x010201
// TODO
};

Expand Down Expand Up @@ -196,6 +197,7 @@ const ErrorTemplate = {
SH010101: "Controller '$${0}' is not a valid controller.", // 0:controllerName.ext, .ext is expected to be .js, see doc/Errors.md.
SH010102: "Controller path '$${0}' does not exist on '$${1}'.", // 0:controllerName.js; 1: controllerPath, see global['EnvironmentVariables'].
SH010103: "Unresolved controller file.",
SH010201: "Invalid route rule: $${0}. The possible reason is:$${1}", // 0: route rule string. 1: reason.
SH020101: "Controller '$${0}' not registered.", // 0: controllerName.
SH020102: "Default router not found.",
SH020201: "View file '$${0}' does not exist on '$${1}'.", // 0:viewFileName.js; 1: viewPath, see global['EnvironmentVariables'].
Expand Down
Loading