Skip to content

Commit

Permalink
Issue 565 complexity reduction (#11)
Browse files Browse the repository at this point in the history
* refactor validation

fixes idrinth-api-bench/issues#565

* refactor validation

fixes idrinth-api-bench/issues#565

* fix merge

fixes idrinth-api-bench/issues#565

* fix merge

fixes idrinth-api-bench/issues#565
  • Loading branch information
Idrinth authored May 17, 2024
1 parent d775478 commit 4c35e9f
Show file tree
Hide file tree
Showing 11 changed files with 205 additions and 163 deletions.
4 changes: 2 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/node_modules
/coverage
/.idea
/node_modules
/src/locales
/coverage
151 changes: 4 additions & 147 deletions src/cli/check-routes.ts
Original file line number Diff line number Diff line change
@@ -1,166 +1,23 @@
/* eslint no-console: 0 */
import jobCreator from '../routes/job-creator.js';
import language, {
locale,
} from '../helper/language.js';
import {
DEFAULT_LANGUAGE,
ONE,
EMPTY,
FIRST_ARGUMENT,
} from '../constants.js';
import validateTasks from '../routes/validate-tasks.js';
import taskTypes from '../routes/task-types.js';
import Task from '../routes/task.js';
import Job from '../routes/job.js';
import taskType from '../routes/task-type.js';
import Request from '../routes/request.js';
import logSymbols from 'log-symbols';
import languageKey from '../locales/language-key.js';

const warn = (key: languageKey, ...argList: string[]) => {
console.warn(logSymbols.warning + ' ' + language(key, ...argList,),);
};
const error = (key: languageKey, ...argList: string[]) => {
console.error(logSymbols.error + ' ' + language(key, ...argList,),);
};

// eslint-disable-next-line complexity
const checkMiddleware = (type: 'pre'|'post', route: Task,) => {
if (typeof route[type] === 'undefined') {
return true;
}
const data = route[type];
delete route[type];
if (typeof data !== 'object' || ! Array.isArray(data,)) {
error(`invalid_${ type }_definition`, route.id,);
return false;
}
for (const middleware of data) {
if (typeof middleware !== 'string') {
error(`invalid_${ type }_definition`, route.id,);
return false;
}
}
return true;
};

// eslint-disable-next-line complexity
const checkRequest = (main: Request, id: string,): {
invalid: boolean,
risky: boolean,
} => {
const properties = [
{
name: 'method',
type: 'string',
required: true,
},
{
name: 'headers',
type: 'object',
required: false,
},
{
name: 'cookies',
type: 'object',
required: false,
},
{
name: 'body',
type: [
'string',
'object',
],
required: false,
},
{
name: 'autohandle',
type: 'string',
required: false,
},
{
name: 'url',
type: 'string',
required: true,
},
{
name: 'maxDuration',
type: 'number',
required: false,
},
];
let valid = true;
for (const property of properties) {
if (property.required && typeof main[property.name] === 'undefined') {
error('invalid_request_property', id, property.name,);
valid = false;
} else if (typeof main[property.name] !== property.type) {
error('invalid_request_property', id, property.name,);
valid = false;
delete main[property.name];
} else {
delete main[property.name];
}
}
if (Object.keys(main,).length === EMPTY) {
warn('invalid_request', id,);
return {
invalid: ! valid,
risky: true,
};
}
return {
invalid: ! valid,
risky: false,
};
};

// eslint-disable-next-line complexity
const checkType = (job: Job, type: taskType,) => {
if (typeof job[type] === 'undefined') {
return {
errors: 0,
warnings: 0,
};
}
let errors = 0;
let warnings = 0;
if (job[type].length > EMPTY) {
for (const route of job[type]) {
if (! checkMiddleware('pre', route,)) {
errors ++;
}
if (! checkMiddleware('post', route,)) {
errors ++;
}
const id = route.id;
delete route.id;
const result = checkRequest(route.main, id,);
if (result.invalid) {
errors ++;
}
if (result.risky) {
warnings ++;
}
delete route.main;
for (const key of Object.keys(route,)) {
warn('unknown_route_property', key, id,);
warnings ++;
}
}
}
return {
errors,
warnings,
};
};
import error from '../validation/error.js';
import checkType from '../validation/check-type.js';
import noDuplicateIds from '../validation/no-duplicate-ids.js';

// eslint-disable-next-line complexity
export default async(args: string[], cwd: string,): Promise<void> => {
await locale(args[FIRST_ARGUMENT] || DEFAULT_LANGUAGE,);
const job = await jobCreator(cwd,);
validateTasks(ONE, ONE, job.main,);
noDuplicateIds(job.main,);
let errors = 0;
let warnings = 0;
for (const type of taskTypes) {
Expand Down
2 changes: 1 addition & 1 deletion src/routes/middleware-loader.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,6 @@ const resolve = (path: string,): string => {
};
const load = async(path: string,): Promise<Middleware> => {
const req = cache[path] || (cache[path] = resolve(path,));
return new (await include(req,)) as Middleware;
return new (await include(req,))() as Middleware;
};
export default load;
16 changes: 4 additions & 12 deletions src/routes/validate-tasks.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,10 @@
import Task from './task.js';
import language from '../helper/language.js';
import language from './helper/language.js';
import {
EMPTY,
} from '../constants.js';
} from './constants.js';
import noDuplicateIds from './no-duplicate-ids.js';

const noDuplicateIDs = (tasks: Array<Task>,) => {
const ids: Array<string> = [];
for (const task of tasks) {
if (ids.includes(task.id,)) {
throw new Error(language('duplicate_task_id', task.id,),);
}
ids.push(task.id,);
}
};
const executableAmount = (
repetitions: number,
threads: number,
Expand All @@ -29,5 +21,5 @@ export default function validateTasks(
tasks: Array<Task>,
): void {
executableAmount(repetitions, threads, tasks,);
noDuplicateIDs(tasks,);
noDuplicateIds(tasks,);
}
23 changes: 23 additions & 0 deletions src/validation/check-middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import Task from '../task.js';
import error from './error.js';

const checkMiddleware = (type: 'pre' | 'post', route: Task,) => {
if (typeof route[type] === 'undefined') {
return true;
}
const data = route[type];
delete route[type];
if (typeof data !== 'object' || ! Array.isArray(data,)) {
error(`invalid_${ type }_definition`, route.id,);
return false;
}
for (const middleware of data) {
if (typeof middleware !== 'string') {
error(`invalid_${ type }_definition`, route.id,);
return false;
}
}
return true;
};

export default checkMiddleware;
89 changes: 89 additions & 0 deletions src/validation/check-request.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
import Request from '../request.js';
import error from './error.js';
import {
EMPTY,
} from '../constants.js';
import warn from './warn.js';

interface Property {
name: string;
type: string|string[];
required: boolean;
}

const properties: Property[] = [
{
name: 'method',
type: 'string',
required: true,
},
{
name: 'headers',
type: 'object',
required: false,
},
{
name: 'cookies',
type: 'object',
required: false,
},
{
name: 'body',
type: [
'string',
'object',
],
required: false,
},
{
name: 'autohandle',
type: 'string',
required: false,
},
{
name: 'url',
type: 'string',
required: true,
},
{
name: 'maxDuration',
type: 'number',
required: false,
},
];

const validateProperty = (property: Property, id: string, main: Request,) => {
if (property.required && typeof main[property.name] === 'undefined') {
error('invalid_request_property', id, property.name,);
return false;
}
const allowedTypes: string[] = Array.isArray(property.type,) ? property.type : [ property.type, ];

Check warning on line 60 in src/validation/check-request.ts

View workflow job for this annotation

GitHub Actions / lint

This line has a length of 100. Maximum allowed is 80
if (! allowedTypes.includes(typeof main[property.name],)) {
error('invalid_request_property', id, property.name,);
delete main[property.name];
return false;
}
delete main[property.name];
return true;
};
const checkRequest = (main: Request, id: string,): {
invalid: boolean,
risky: boolean,
} => {
let valid = true;
for (const property of properties) {
valid = validateProperty(property, id, main,) && valid;
}
if (Object.keys(main,).length !== EMPTY) {
warn('invalid_request', id,);
return {
invalid: ! valid,
risky: true,
};
}
return {
invalid: ! valid,
risky: false,
};
};
export default checkRequest;
49 changes: 49 additions & 0 deletions src/validation/check-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import Job from '../job.js';
import taskType from '../task-type.js';
import {
EMPTY,
} from '../constants.js';
import checkRequest from './check-request.js';
import warn from './warn.js';
import checkMiddleware from './check-middleware.js';

const checkType = (job: Job, type: taskType,) => {
if (typeof job[type] === 'undefined') {
return {
errors: 0,
warnings: 0,
};
}
let errors = 0;
let warnings = 0;
if (job[type].length > EMPTY) {
for (const route of job[type]) {
if (! checkMiddleware('pre', route,)) {
errors ++;
}
if (! checkMiddleware('post', route,)) {
errors ++;
}
const id = route.id;
delete route.id;
const result = checkRequest(route.main, id,);
if (result.invalid) {
errors ++;
}
if (result.risky) {
warnings ++;
}
delete route.main;
for (const key of Object.keys(route,)) {
warn('unknown_route_property', key, id,);
warnings ++;
}
}
}
return {
errors,
warnings,
};
};

export default checkType;
10 changes: 10 additions & 0 deletions src/validation/error.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
/* eslint no-console: 0 */
import language from '../helper/language.js';
import logSymbols from 'log-symbols';
import languageKey from '../locales/language-key.js';

const error = (key: languageKey, ...argList: string[]) => {
console.error(logSymbols.error + ' ' + language(key, ...argList,),);
};

export default error;
Loading

0 comments on commit 4c35e9f

Please sign in to comment.