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

plumier

Package Overview
Dependencies
Maintainers
1
Versions
652
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

plumier - npm Package Compare versions

Comparing version 0.1.0-alpha.b123904d to 0.1.0-alpha.caa0578b

lib/common.d.ts

32

lib/application.d.ts

@@ -0,3 +1,6 @@

/// <reference types="koa__cors" />
import Cors from "@koa/cors";
import Koa, { Context } from "koa";
import { ActionResult, Application, Configuration, Facility, Invocation, KoaMiddleware, PlumierApplication, PlumierConfiguration, Middleware } from "./framework";
import { ActionResult, Application, BodyParserOption, Configuration, Facility, Invocation, KoaMiddleware, Middleware, PlumierApplication, PlumierConfiguration, RouteInfo } from "./core";
export declare function extractDecorators(route: RouteInfo): Middleware[];
export declare class MiddlewareInvocation implements Invocation {

@@ -16,2 +19,29 @@ private middleware;

export declare function pipe(middleware: Middleware[], context: Context, invocation: Invocation): Invocation;
/**
* Preset configuration for building web api. This facility contains:
*
* body parser: koa-bodyparser
*
* cors: @koa/cors
*/
export declare class WebApiFacility implements Facility {
private opt?;
constructor(opt?: {
bodyParser?: BodyParserOption | undefined;
cors?: Cors.Options | undefined;
} | undefined);
setup(app: Readonly<PlumierApplication>): Promise<void>;
}
/**
* Preset configuration for building restful style api. This facility contains:
*
* body parser: koa-bodyparser
*
* cors: @koa/cors
*
* default response status: { get: 200, post: 201, put: 204, delete: 204 }
*/
export declare class RestfulApiFacility extends WebApiFacility {
setup(app: Readonly<PlumierApplication>): Promise<void>;
}
export declare class Plumier implements PlumierApplication {

@@ -18,0 +48,0 @@ readonly config: Readonly<PlumierConfiguration>;

151

lib/application.js
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const cors_1 = tslib_1.__importDefault(require("@koa/cors"));
const debug_1 = tslib_1.__importDefault(require("debug"));
const fs_1 = require("fs");
const koa_1 = tslib_1.__importDefault(require("koa"));
const path_1 = require("path");
const util_1 = require("util");
const koa_bodyparser_1 = tslib_1.__importDefault(require("koa-bodyparser"));
const tsval_1 = require("tsval");
const binder_1 = require("./binder");
const framework_1 = require("./framework");
const common_1 = require("./common");
const core_1 = require("./core");
const router_1 = require("./router");
const log = debug_1.default("plum:app");
/* ------------------------------------------------------------------------------- */
/* ----------------------------------- HELPERS ----------------------------------- */
/* ------------------------------------------------------------------------------- */
function extractDecorators(route) {
const classDecorator = route.controller.decorators.filter(x => x.name == "Middleware");
const methodDecorator = route.action.decorators.filter(x => x.name == "Middleware");
const extract = (d) => d.map(x => x.value).reduce((a, b) => a.concat(b), []);
return extract(classDecorator)
.concat(extract(methodDecorator))
.reverse();
}
exports.extractDecorators = extractDecorators;
/* ------------------------------------------------------------------------------- */
/* ------------------------------- INVOCATIONS ----------------------------------- */

@@ -40,19 +54,19 @@ /* ------------------------------------------------------------------------------- */

const validate = (value, i) => config.validator(value, param(i));
const issues = parameters.map((value, index) => ({ parameter: param(index).name, issues: validate(value, index) }))
.filter(x => Boolean(x.issues));
log(`[Action Invocation] Validation result ${framework_1.b(util_1.inspect(issues, false, null))}`);
const issues = parameters.map((value, index) => validate(value, index))
.reduce((a, b) => a.concat(b), []);
log(`[Action Invocation] Validation result ${common_1.b(issues)}`);
if (issues.length > 0)
return new framework_1.ActionResult(issues, 400);
throw new core_1.ValidationError(issues);
}
const result = controller[route.action.name].apply(controller, parameters);
const awaitedResult = await Promise.resolve(result);
const status = config.responseStatus && config.responseStatus[route.method] || 200;
if (result instanceof framework_1.ActionResult) {
result.status = result.status || status;
log(`[Action Invocation] Method: ${framework_1.b(route.method)} Status config: ${framework_1.b(util_1.inspect(config.responseStatus, false, null))} Status: ${framework_1.b(result.status)} `);
return Promise.resolve(result);
if (awaitedResult instanceof core_1.ActionResult) {
awaitedResult.status = awaitedResult.status || status;
log(`[Action Invocation] ActionResult value - Method: ${common_1.b(route.method)} Status config: ${common_1.b(config.responseStatus)} Status: ${common_1.b(result.status)} `);
return awaitedResult;
}
else {
const awaitedResult = await Promise.resolve(result);
log(`[Action Invocation] Method: ${route.method} Status config: ${framework_1.b(util_1.inspect(config.responseStatus, false, null))} Status: ${framework_1.b(status)} `);
return new framework_1.ActionResult(awaitedResult, status);
log(`[Action Invocation] Raw value - Method: ${route.method} Status config: ${common_1.b(config.responseStatus)} Status: ${common_1.b(status)} `);
return new core_1.ActionResult(awaitedResult, status);
}

@@ -62,5 +76,2 @@ }

exports.ActionInvocation = ActionInvocation;
/* ------------------------------------------------------------------------------- */
/* ------------------------- MIDDLEWARE PIPELINE --------------------------------- */
/* ------------------------------------------------------------------------------- */
function pipe(middleware, context, invocation) {

@@ -71,27 +82,77 @@ return middleware.reverse().reduce((prev, cur) => new MiddlewareInvocation(cur, context, prev), invocation);

/* ------------------------------------------------------------------------------- */
/* --------------------------- REQUEST HANDLER ----------------------------------- */
/* -------------------------------- FACITLITIES ---------------------------------- */
/* ------------------------------------------------------------------------------- */
class ValidationMiddleware {
async execute(invocation) {
try {
return await invocation.proceed();
}
catch (e) {
if (e instanceof core_1.ValidationError) {
return new core_1.ActionResult(e.issues, 400);
}
else
throw e;
}
}
}
/**
* Preset configuration for building web api. This facility contains:
*
* body parser: koa-bodyparser
*
* cors: @koa/cors
*/
class WebApiFacility {
constructor(opt) {
this.opt = opt;
}
async setup(app) {
app.koa.use(koa_bodyparser_1.default(this.opt && this.opt.bodyParser));
app.koa.use(cors_1.default(this.opt && this.opt.cors));
app.set({
validator: (value, meta) => {
const decorators = meta.decorators.filter((x) => x.type === "ValidatorDecorator");
log(`[Validator] Validating ${common_1.b(value)} metadata: ${common_1.b(meta)}`);
return tsval_1.validate(value, decorators, [meta.name])
.map(x => ({ messages: x.messages, path: x.path }));
}
});
app.use(new ValidationMiddleware());
}
}
exports.WebApiFacility = WebApiFacility;
/**
* Preset configuration for building restful style api. This facility contains:
*
* body parser: koa-bodyparser
*
* cors: @koa/cors
*
* default response status: { get: 200, post: 201, put: 204, delete: 204 }
*/
class RestfulApiFacility extends WebApiFacility {
async setup(app) {
super.setup(app);
app.set({ responseStatus: { post: 201, put: 204, delete: 204 } });
}
}
exports.RestfulApiFacility = RestfulApiFacility;
/* ------------------------------------------------------------------------------- */
/* --------------------------- MAIN APPLICATION ---------------------------------- */
/* ------------------------------------------------------------------------------- */
async function requestHandler(ctx) {
const controllerMiddleware = router_1.extractDecorators(ctx.route);
const controllerMiddleware = extractDecorators(ctx.route);
const pipeline = pipe(controllerMiddleware, ctx, new ActionInvocation(ctx));
const result = await pipeline.proceed();
result.execute(ctx);
log(`[Request Handler] ${framework_1.b(ctx.path)} -> ${framework_1.b(ctx.route.controller.name)}.${framework_1.b(ctx.route.action.name)}`);
log(`[Request Handler] Request Query: ${framework_1.b(util_1.inspect(ctx.query, false, null))}`);
log(`[Request Handler] Request Header: ${framework_1.b(util_1.inspect(ctx.headers, false, null))}`);
log(`[Request Handler] Request Body: ${framework_1.b(util_1.inspect(result.body, false, null))}`);
log(`[Request Handler] ${common_1.b(ctx.path)} -> ${common_1.b(ctx.route.controller.name)}.${common_1.b(ctx.route.action.name)}`);
log(`[Request Handler] Request Query: ${common_1.b(ctx.query)}`);
log(`[Request Handler] Request Header: ${common_1.b(ctx.headers)}`);
log(`[Request Handler] Request Body: ${common_1.b(result.body)}`);
}
/* ------------------------------------------------------------------------------- */
/* --------------------------- MAIN APPLICATION ---------------------------------- */
/* ------------------------------------------------------------------------------- */
class Plumier {
constructor() {
this.koa = new koa_1.default();
this.config = {
mode: "debug",
middleware: [],
facilities: [],
controller: path_1.join(process.cwd(), "./controller"),
dependencyResolver: new framework_1.DefaultDependencyResolver()
};
this.config = Object.assign({}, core_1.DefaultConfiguration, { middleware: [], facilities: [] });
}

@@ -103,3 +164,3 @@ use(option) {

else {
this.koa.use(framework_1.MiddlewareUtil.toKoa(option));
this.koa.use(core_1.MiddlewareUtil.toKoa(option));
}

@@ -109,3 +170,3 @@ return this;

set(config) {
if (framework_1.hasKeyOf(config, "setup"))
if (common_1.hasKeyOf(config, "setup"))
this.config.facilities.push(config);

@@ -121,12 +182,26 @@ else

if (!fs_1.existsSync(this.config.controller))
throw new Error(framework_1.StringUtil.format(framework_1.errorMessage.ControllerPathNotFound, this.config.controller));
routes = await router_1.transformModule(this.config.controller);
throw new Error(core_1.errorMessage.ControllerPathNotFound.format(this.config.controller));
routes = await router_1.transformModule(this.config.controller, [this.config.fileExtension]);
}
else {
else if (Array.isArray(this.config.controller)) {
routes = this.config.controller.map(x => router_1.transformController(x))
.reduce((a, b) => a.concat(b), []);
}
else {
routes = router_1.transformController(this.config.controller);
}
if (this.config.mode === "debug")
router_1.printAnalysis(router_1.analyzeRoutes(routes));
await Promise.all(this.config.facilities.map(x => x.setup(this)));
this.koa.use(async (ctx, next) => {
try {
await next();
}
catch (e) {
if (e instanceof core_1.HttpStatusError)
ctx.throw(e.status, e);
else
ctx.throw(500, e);
}
});
this.koa.use(router_1.router(routes, this.config, requestHandler));

@@ -133,0 +208,0 @@ return this.koa;

/// <reference types="koa-bodyparser" />
import { Request } from "koa";
import { Class, TypeConverter, ValueConverter } from "./framework";
import { FunctionReflection } from "tinspector";
export declare function booleanConverter(value: any): boolean;
export declare function dateConverter(value: any): Date;
export declare function defaultModelConverter(value: any, type: Class, converters: Map<Function, ValueConverter>): any;
export declare function defaultArrayConverter(value: any[], type: Class, converters: Map<Function, ValueConverter>): any;
export declare function flattenConverters(converters: [Function, ValueConverter][]): Map<Function, ValueConverter>;
export declare const DefaultConverterList: [Function, ValueConverter][];
export declare function convert(value: any, type: Class | undefined, converters: Map<Function, ValueConverter>): any;
export declare function bindParameter(request: Request, action: FunctionReflection, converter?: TypeConverter): any[];
import { Class, ParameterProperties, TypeConverter, ValueConverter } from "./core";
export declare function flattenConverters(converters: TypeConverter[]): Map<Function, ValueConverter>;
export declare function booleanConverter(rawValue: any, prop: ParameterProperties & {
parameterType: Class;
}): boolean;
export declare function numberConverter(rawValue: any, prop: ParameterProperties & {
parameterType: Class;
}): number;
export declare function dateConverter(rawValue: any, prop: ParameterProperties & {
parameterType: Class;
}): Date;
export declare function defaultModelConverter(value: any, prop: ParameterProperties & {
parameterType: Class;
}): any;
export declare function defaultArrayConverter(value: any[], prop: ParameterProperties & {
parameterType: Class;
}): any;
export declare const DefaultConverterList: TypeConverter[];
export declare function convert(value: any, prop: ParameterProperties): any;
export declare function bindParameter(request: Request, action: FunctionReflection, converter?: TypeConverter[]): any[];

@@ -5,64 +5,147 @@ "use strict";

const debug_1 = tslib_1.__importDefault(require("debug"));
const util_1 = require("util");
const framework_1 = require("./framework");
const tinspector_1 = require("tinspector");
const common_1 = require("./common");
const core_1 = require("./core");
const log = debug_1.default("plum:binder");
function getArrayDecorator(decorators) {
return decorators.find((x) => x.type == "ParameterBinding" && x.name == "Array");
}
function createConversionError(value, prop) {
const decorator = getArrayDecorator(prop.decorators);
const type = decorator ? `Array<${decorator.typeAnnotation.name}>` : prop.parameterType.name;
log(`[Converter] Unable to convert ${common_1.b(value)} into ${common_1.b(type)}`);
return new core_1.ConversionError({ path: prop.path, type, value }, core_1.errorMessage.UnableToConvertValue.format(value, type, prop.path.join("->")));
}
function flattenConverters(converters) {
return converters.reduce((a, b) => { a.set(b.type, b.converter); return a; }, new Map());
}
exports.flattenConverters = flattenConverters;
//some object can't simply convertible to string https://github.com/emberjs/ember.js/issues/14922#issuecomment-278986178
function safeToString(value) {
try {
return value.toString();
}
catch (e) {
return "[object Object]";
}
}
/* ------------------------------------------------------------------------------- */
/* -------------------------------- HELPER --------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------------------------------------------------------- */
/* ------------------------------- CONVERTER ------------------------------------- */
/* ------------------------------------------------------------------------------- */
function booleanConverter(value) {
return ["on", "true", "1", "yes"].some(x => value.toLocaleLowerCase() == x);
function booleanConverter(rawValue, prop) {
const value = safeToString(rawValue);
const list = {
on: true, true: true, "1": true, yes: true,
off: false, false: false, "0": false, no: false
};
const result = list[value.toLowerCase()];
log(`[Boolean Converter] Raw: ${common_1.b(value)} Value: ${common_1.b(result)}`);
if (result === undefined)
throw createConversionError(value, prop);
return result;
}
exports.booleanConverter = booleanConverter;
function dateConverter(value) {
return new Date(value);
function numberConverter(rawValue, prop) {
const value = safeToString(rawValue);
const result = Number(value);
if (isNaN(result) || value === "")
throw createConversionError(value, prop);
log(`[Number Converter] Raw: ${common_1.b(value)} Value: ${common_1.b(result)}`);
return result;
}
exports.numberConverter = numberConverter;
function dateConverter(rawValue, prop) {
const value = safeToString(rawValue);
const result = new Date(value);
if (isNaN(result.getTime()) || value === "")
throw createConversionError(value, prop);
log(`[Date Converter] Raw: ${common_1.b(value)} Value: ${common_1.b(result)}`);
return result;
}
exports.dateConverter = dateConverter;
function defaultModelConverter(value, type, converters) {
const getType = (par) => {
const decorator = par.decorators.find((x) => x.type == "ParameterBinding" && x.name == "Array");
log(`[Model Converter] Constructor parameter ${par.name} decorator ${util_1.inspect(par.decorators, false, null)}`);
if (decorator)
return decorator.typeAnnotation;
function defaultModelConverter(value, prop) {
//--- helper functions
const isConvertibleToObject = (value) => {
if (typeof value == "boolean" ||
typeof value == "number" ||
typeof value == "string")
return false;
else
return par.typeAnnotation;
return true;
};
log(`[Model Converter] converting ${framework_1.b(util_1.inspect(value, false, null))} to ${framework_1.b(type.name)} `);
const reflection = tinspector_1.reflect(type);
log(`[Model Converter] model info ${framework_1.b(util_1.inspect(reflection.ctorParameters))} `);
//---
//if the value already instance of the type then return immediately
//this is possible when using decorator binding such as @bind.request("req")
if (value instanceof prop.parameterType)
return value;
//get reflection metadata of the class
const reflection = tinspector_1.reflect(prop.parameterType);
//check if the value is possible to convert to model
if (!isConvertibleToObject(value))
throw createConversionError(value, prop);
log(`[Model Converter] converting ${common_1.b(value)} to ${common_1.b(prop.parameterType.name)}{${common_1.b(reflection.ctorParameters.map(x => x.name).join(", "))}}`);
//sanitize excess property to prevent object having properties that doesn't match with declaration
//traverse through the object properties and convert to appropriate property's type
const sanitized = reflection.ctorParameters.map(x => ({
name: x.name,
value: convert(value[x.name], getType(x), converters)
value: convert(value[x.name], {
parameterType: x.typeAnnotation,
path: prop.path.concat(x.name),
decorators: x.decorators,
converters: prop.converters
})
})).reduce((a, b) => { a[b.name] = b.value; return a; }, {});
log(`[Model Converter] Sanitized value ${framework_1.b(util_1.inspect(sanitized, false, null))}`);
return Object.assign(new type(), sanitized);
log(`[Model Converter] Sanitized value ${common_1.b(sanitized)}`);
//crete new instance of the type and assigned the sanitized values
try {
return Object.assign(new prop.parameterType(), sanitized);
}
catch (e) {
const message = core_1.errorMessage.UnableToInstantiateModel.format(prop.parameterType.name);
if (e instanceof Error) {
e.message = message + "\n" + e.message;
throw e;
}
else
throw new Error(message);
}
}
exports.defaultModelConverter = defaultModelConverter;
function defaultArrayConverter(value, type, converters) {
log(`[Array Converter] converting ${framework_1.b(util_1.inspect(value, false, null))} to Array<${type.name}>`);
return value.map(x => convert(x, type, converters));
function defaultArrayConverter(value, prop) {
const decorator = getArrayDecorator(prop.decorators);
if (!Array.isArray(value))
throw createConversionError(value, prop);
log(`[Array Converter] converting ${common_1.b(value)} to Array<${decorator.typeAnnotation.name}>`);
return value.map(((x, i) => convert(x, {
path: prop.path.concat(i.toString()),
converters: prop.converters,
decorators: [],
parameterType: decorator.typeAnnotation
})));
}
exports.defaultArrayConverter = defaultArrayConverter;
function flattenConverters(converters) {
return converters.reduce((a, b) => { a.set(b[0], b[1]); return a; }, new Map());
}
exports.flattenConverters = flattenConverters;
exports.DefaultConverterList = [
[Number, Number],
[Date, dateConverter],
[Boolean, booleanConverter]
{ type: Number, converter: numberConverter },
{ type: Date, converter: dateConverter },
{ type: Boolean, converter: booleanConverter }
];
function convert(value, type, converters) {
if (!type)
function convert(value, prop) {
if (value === null || value === undefined)
return undefined;
if (!prop.parameterType)
return value;
if (Array.isArray(value))
return defaultArrayConverter(value, type, converters);
else if (converters.has(type))
return converters.get(type)(value, type, converters);
log(`[Converter] Path: ${common_1.b(prop.path.join("->"))} ` +
`Source Type: ${common_1.b(typeof value)} ` +
`Target Type:${common_1.b(prop.parameterType.name)} ` +
`Decorators: ${common_1.b(prop.decorators.map(x => x.name).join(", "))} ` +
`Value: ${common_1.b(value)}`);
//check if the parameter contains @bind.array()
if (Boolean(getArrayDecorator(prop.decorators)))
return defaultArrayConverter(value, Object.assign({}, prop, { parameterType: prop.parameterType }));
//check if parameter is native value that has default converter (Number, Date, Boolean) or if user provided converter
else if (prop.converters.has(prop.parameterType))
return prop.converters.get(prop.parameterType)(value, Object.assign({}, prop, { parameterType: prop.parameterType }));
//if type of model and has no converter, use DefaultObject converter
else if (framework_1.isCustomClass(type))
return defaultModelConverter(value, type, converters);
else if (common_1.isCustomClass(prop.parameterType))
return defaultModelConverter(value, Object.assign({}, prop, { parameterType: prop.parameterType }));
//no converter, return the value

@@ -74,3 +157,3 @@ else

/* ------------------------------------------------------------------------------- */
/* ----------------------------- MODEL BINDER ------------------------------------ */
/* ----------------------------- BINDER FUNCTIONS -------------------------------- */
/* ------------------------------------------------------------------------------- */

@@ -80,10 +163,8 @@ function bindModel(action, request, par, converter) {

return;
if (!framework_1.isCustomClass(par.typeAnnotation))
if (!common_1.isCustomClass(par.typeAnnotation))
return;
log(`[Model Binder] Action: ${framework_1.b(action.name)} Parameter: ${framework_1.b(par.name)} Parameter Type: ${framework_1.b(par.typeAnnotation.name)}`);
log(`[Model Binder] Action: ${common_1.b(action.name)} Parameter: ${common_1.b(par.name)} Parameter Type: ${common_1.b(par.typeAnnotation.name)}`);
log(`[Model Binder] Request Body: ${common_1.b(request.body)}`);
return converter(request.body);
}
/* ------------------------------------------------------------------------------- */
/* ------------------------ DECORATOR PARAMETER BINDER --------------------------- */
/* ------------------------------------------------------------------------------- */
function bindDecorator(action, request, par, converter) {

@@ -93,38 +174,33 @@ const decorator = par.decorators.find((x) => x.type == "ParameterBinding");

return;
log(`[Decorator Binder] Action: ${framework_1.b(action.name)} Parameter: ${framework_1.b(par.name)} Decorator: ${framework_1.b(decorator.name)} Part: ${framework_1.b(decorator.part)}`);
log(`[Decorator Binder] Action: ${common_1.b(action.name)} Parameter: ${common_1.b(par.name)} Decorator: ${common_1.b(decorator.name)} Part: ${common_1.b(decorator.part)}`);
const getDataOrPart = (data) => decorator.part ? data && data[decorator.part] : data;
switch (decorator.name) {
case "Body":
return decorator.part ? request.body && request.body[decorator.part] : request.body;
return converter(getDataOrPart(request.body));
case "Query":
return decorator.part ? request.query && request.query[decorator.part] : request.query;
return converter(getDataOrPart(request.query));
case "Header":
return decorator.part ? request.headers && request.headers[decorator.part] : request.headers;
return converter(getDataOrPart(request.headers));
case "Request":
return decorator.part ? request[decorator.part] : request;
return converter(getDataOrPart(request));
}
}
/* ------------------------------------------------------------------------------- */
/* --------------------------- ARRAY PARAMETER BINDER ---------------------------- */
/* ------------------------------------------------------------------------------- */
function bindArrayDecorator(action, request, par, converter) {
const decorator = par.decorators.find((x) => x.type == "ParameterBinding" && x.name == "Array");
const decorator = getArrayDecorator(par.decorators);
if (!decorator)
return;
log(`[Array Binder] Action: ${framework_1.b(action.name)} Parameter: ${framework_1.b(par.name)} Type: ${framework_1.b(decorator.typeAnnotation.name)}`);
log(`[Array Binder] Action: ${common_1.b(action.name)} Parameter: ${common_1.b(par.name)} Type: ${common_1.b(decorator.typeAnnotation.name)}`);
return converter(request.body, decorator.typeAnnotation);
}
/* ------------------------------------------------------------------------------- */
/* -------------------------- REGULAR PARAMETER BINDER --------------------------- */
/* ------------------------------------------------------------------------------- */
function bindRegular(action, request, par, converter) {
log(`[Regular Binder] Action: ${framework_1.b(action.name)} Parameter: ${framework_1.b(par.name)} Value: ${framework_1.b(request.query[par.name])}`);
log(`[Regular Binder] Action: ${common_1.b(action.name)} Parameter: ${common_1.b(par.name)} Value: ${common_1.b(request.query[par.name])}`);
return converter(request.query[par.name.toLowerCase()]);
}
/* ------------------------------------------------------------------------------- */
/* -------------------------- MAIN PARAMETER BINDER --------------------------- */
/* ------------------------------------------------------------------------------- */
function bindParameter(request, action, converter) {
const mergedConverters = flattenConverters(exports.DefaultConverterList.concat(converter || []));
return action.parameters.map(x => {
const converter = (result, type) => convert(result, type || x.typeAnnotation, mergedConverters);
return action.parameters.map(((x, i) => {
const converter = (result, type) => convert(result, {
path: [x.name], parameterType: type || x.typeAnnotation,
converters: mergedConverters, decorators: x.decorators
});
return bindArrayDecorator(action, request, x, converter) ||

@@ -134,4 +210,4 @@ bindDecorator(action, request, x, converter) ||

bindRegular(action, request, x, converter);
});
}));
}
exports.bindParameter = bindParameter;

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

export { ActionResult, Application, bind, Configuration, DependencyResolver, Facility, HeaderPart, HttpMethod, HttpStatusError, Invocation, KoaMiddleware, middleware, Middleware, model, PlumierApplication, PlumierConfiguration, RequestPart, route, RouteInfo, TypeConverter, WebApiFacility } from "./framework";
export { Plumier } from "./application";
export { ActionResult, Application, bind, Configuration, DependencyResolver, Facility, HeaderPart, HttpMethod, HttpStatusError, Invocation, KoaMiddleware, middleware, Middleware, model, PlumierApplication, PlumierConfiguration, RequestPart, route, RouteInfo, TypeConverter, } from "./core";
export { Plumier, WebApiFacility, RestfulApiFacility } from "./application";
export { val } from "tsval";
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var framework_1 = require("./framework");
exports.ActionResult = framework_1.ActionResult;
exports.bind = framework_1.bind;
exports.HttpStatusError = framework_1.HttpStatusError;
exports.middleware = framework_1.middleware;
exports.model = framework_1.model;
exports.route = framework_1.route;
exports.WebApiFacility = framework_1.WebApiFacility;
var core_1 = require("./core");
exports.ActionResult = core_1.ActionResult;
exports.bind = core_1.bind;
exports.HttpStatusError = core_1.HttpStatusError;
exports.middleware = core_1.middleware;
exports.model = core_1.model;
exports.route = core_1.route;
var application_1 = require("./application");
exports.Plumier = application_1.Plumier;
exports.WebApiFacility = application_1.WebApiFacility;
exports.RestfulApiFacility = application_1.RestfulApiFacility;
var tsval_1 = require("tsval");
exports.val = tsval_1.val;
import { Context } from "koa";
import { RouteInfo, Class, Configuration, Middleware } from "./framework";
import { ClassReflection } from "tinspector";
import { Class, Configuration, RouteInfo } from "./core";
interface Issue {

@@ -14,5 +14,4 @@ type: "error" | "warning" | "success";

export declare function getControllerRoute(controller: ClassReflection): string;
export declare function extractDecorators(route: RouteInfo): Middleware[];
export declare function transformController(object: ClassReflection | Class): RouteInfo[];
export declare function transformModule(path: string, extensions?: string[]): Promise<RouteInfo[]>;
export declare function transformModule(path: string, extensions: string[]): Promise<RouteInfo[]>;
export declare function router(infos: RouteInfo[], config: Configuration, handler: (ctx: Context) => Promise<void>): (ctx: Context, next: () => Promise<void>) => Promise<void>;

@@ -19,0 +18,0 @@ export declare function analyzeRoutes(routes: RouteInfo[]): TestResult[];

"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const tslib_1 = require("tslib");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const debug_1 = tslib_1.__importDefault(require("debug"));

@@ -8,6 +9,5 @@ const Fs = tslib_1.__importStar(require("fs"));

const path_to_regexp_1 = tslib_1.__importDefault(require("path-to-regexp"));
const framework_1 = require("./framework");
const tinspector_1 = require("tinspector");
const util_1 = require("util");
const chalk_1 = tslib_1.__importDefault(require("chalk"));
const common_1 = require("./common");
const core_1 = require("./core");
const log = debug_1.default("plum:router");

@@ -26,16 +26,6 @@ /* ------------------------------------------------------------------------------- */

exports.getControllerRoute = getControllerRoute;
function extractDecorators(route) {
const classDecorator = route.controller.decorators.filter(x => x.name == "Middleware");
const methodDecorator = route.action.decorators.filter(x => x.name == "Middleware");
const extract = (d) => d.map(x => x.value).reduce((a, b) => a.concat(b), []);
return extract(classDecorator)
.concat(extract(methodDecorator))
.reverse();
}
exports.extractDecorators = extractDecorators;
function getActionName(route) {
return `${route.controller.name}.${route.action.name}(${route.action.parameters.map(x => x.name).join(", ")})`;
}
function resolvePath(path, extensions) {
const ext = extensions || [".js"];
function resolvePath(path, ext) {
//resolve provided path directory or file

@@ -121,2 +111,3 @@ if (Fs.lstatSync(path).isDirectory()) {

const match = regexp.exec(ctx.path);
log(`[Router] Route: ${common_1.b(route.method)} ${common_1.b(route.url)} Ctx Path: ${common_1.b(ctx.method)} ${common_1.b(ctx.path)} Match: ${common_1.b(match)}`);
return { keys, match, method: route.method.toUpperCase(), route };

@@ -129,3 +120,3 @@ }

if (match) {
log(`[Router] Match route ${framework_1.b(match.route.method)} ${framework_1.b(match.route.url)} with ${framework_1.b(ctx.method)} ${framework_1.b(ctx.path)}`);
log(`[Router] Match route ${common_1.b(match.route.method)} ${common_1.b(match.route.url)} with ${common_1.b(ctx.method)} ${common_1.b(ctx.path)}`);
//assign config and route to context

@@ -138,3 +129,3 @@ Object.assign(ctx, { config, route: match.route });

}, {});
log(`[Router] Extracted parameter from url ${framework_1.b(util_1.inspect(query, false, null))}`);
log(`[Router] Extracted parameter from url ${common_1.b(query)}`);
Object.assign(ctx.query, query);

@@ -144,3 +135,3 @@ await handler(ctx);

else {
log(`[Router] Not route match ${framework_1.b(ctx.method)} ${framework_1.b(ctx.url)}`);
log(`[Router] Not route match ${common_1.b(ctx.method)} ${common_1.b(ctx.url)}`);
await next();

@@ -156,3 +147,3 @@ }

function getModelsInParameters(par) {
return par.filter(x => x.typeAnnotation && framework_1.isCustomClass(x.typeAnnotation))
return par.filter(x => x.typeAnnotation && common_1.isCustomClass(x.typeAnnotation))
.map(x => tinspector_1.reflect(x.typeAnnotation));

@@ -185,3 +176,3 @@ }

type: "error",
message: framework_1.StringUtil.format(framework_1.errorMessage.RouteDoesNotHaveBackingParam, missing.join(", "))
message: core_1.errorMessage.RouteDoesNotHaveBackingParam.format(missing.join(", "))
};

@@ -198,3 +189,3 @@ }

type: "warning",
message: framework_1.errorMessage.ActionDoesNotHaveTypeInfo
message: core_1.errorMessage.ActionDoesNotHaveTypeInfo
};

@@ -210,3 +201,3 @@ }

type: "error",
message: framework_1.errorMessage.MultipleDecoratorNotSupported
message: core_1.errorMessage.MultipleDecoratorNotSupported
};

@@ -222,3 +213,3 @@ }

type: "error",
message: framework_1.StringUtil.format(framework_1.errorMessage.DuplicateRouteFound, dup.map(x => getActionName(x)).join(" "))
message: core_1.errorMessage.DuplicateRouteFound.format(dup.map(x => getActionName(x)).join(" "))
};

@@ -236,6 +227,6 @@ }

if (noTypeInfo.length > 0) {
log(`[Analyzer] Model without type information ${framework_1.b(noTypeInfo.map(x => x.name).join(", "))}`);
log(`[Analyzer] Model without type information ${common_1.b(noTypeInfo.map(x => x.name).join(", "))}`);
return {
type: "warning",
message: framework_1.StringUtil.format(framework_1.errorMessage.ModelWithoutTypeInformation, noTypeInfo.map(x => x.name).join(", "))
message: core_1.errorMessage.ModelWithoutTypeInformation.format(noTypeInfo.map(x => x.name).join(", "))
};

@@ -253,3 +244,3 @@ }

type: "warning",
message: framework_1.StringUtil.format(framework_1.errorMessage.ArrayWithoutTypeInformation, array.map(x => x.name).join(", "))
message: core_1.errorMessage.ArrayWithoutTypeInformation.format(array.map(x => x.name).join(", "))
};

@@ -278,3 +269,3 @@ }

const data = results.map(x => {
const method = framework_1.StringUtil.padRight(x.route.method.toUpperCase(), 5);
const method = x.route.method.toUpperCase();
const action = getActionName(x.route);

@@ -285,9 +276,9 @@ const issues = x.issues.map(issue => ` - ${issue.type} ${issue.message}`);

data.forEach((x, i) => {
const action = framework_1.StringUtil.padRight(x.action, Math.max(...data.map(x => x.action.length)));
const method = framework_1.StringUtil.padRight(x.method, Math.max(...data.map(x => x.method.length)));
const url = framework_1.StringUtil.padRight(x.url, Math.max(...data.map(x => x.url.length)));
const action = x.action.padEnd(Math.max(...data.map(x => x.action.length)));
const method = x.method.padEnd(Math.max(...data.map(x => x.method.length)));
//const url = x.url.padEnd(Math.max(...data.map(x => x.url.length)))
const issueColor = (issue) => issue.startsWith(" - warning") ? chalk_1.default.yellow(issue) : chalk_1.default.red(issue);
const color = x.issues.length == 0 ? (x) => x :
x.issues.some(x => x.startsWith(" - warning")) ? chalk_1.default.yellow : chalk_1.default.red;
console.log(color(`${i + 1}. ${action} -> ${method} ${url}`));
console.log(color(`${i + 1}. ${action} -> ${method} ${x.url}`));
x.issues.forEach(issue => console.log(issueColor(issue)));

@@ -294,0 +285,0 @@ });

{
"name": "plumier",
"version": "0.1.0-alpha.b123904d",
"version": "0.1.0-alpha.caa0578b",
"description": "Pleasant TypeScript Web Api Framework",

@@ -17,4 +17,4 @@ "main": "lib/index.js",

"compile": "tsc -p tsconfig.build.json",
"package-prod": "node ../../.script/modify-package.js production",
"package-dev": "node ../../.script/modify-package.js"
"package-prod": "node ../../.script/modify-package production",
"package-dev": "node ../../.script/modify-package"
},

@@ -36,5 +36,5 @@ "author": "Ketut Sandiarsa",

"path-to-regexp": "^2.2.1",
"tinspector": "1.4.0-alpha.b123904d",
"tinspector": "1.4.0-alpha.caa0578b",
"tslib": "^1.9.2",
"validator": "^10.4.0"
"validatorts": "^0.1.0"
},

@@ -44,3 +44,2 @@ "devDependencies": {

"benalu": "^2.0.0-beta-1",
"edit-json-file": "^1.0.8",
"supertest": "^3.1.0"

@@ -47,0 +46,0 @@ },

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