Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issue 565 complexity reduction #11

Merged
merged 6 commits into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from 3 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
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
159 changes: 7 additions & 152 deletions src/cli/check-routes.ts
Original file line number Diff line number Diff line change
@@ -1,166 +1,21 @@
/* eslint no-console: 0 */
import jobCreator from '../routes/job-creator.js';
import language, {
locale,
} from '../helper/language.js';
import jobCreator from '../helper/job-creator.js';
import language, {locale,} from '../helper/language.js';

Check warning on line 2 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

Expected a line break after this opening brace

Check warning on line 2 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

A space is required after '{'

Check warning on line 2 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

Expected a line break before this closing brace

Check warning on line 2 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

A space is required before '}'
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
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 taskTypes from '../task-types.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";

Check warning on line 10 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

Strings must use singlequote
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
import checkType from "../validation/check-type.js";

Check warning on line 11 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

Strings must use singlequote
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
import noDuplicateIds from "../no-duplicate-ids.js";

Check warning on line 12 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

Strings must use singlequote
Idrinth marked this conversation as resolved.
Show resolved Hide resolved

// 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 All @@ -175,6 +30,6 @@
error('validation_warnings', `${ warnings }`,);
}
if (warnings === EMPTY && errors === EMPTY) {
console.log(logSymbols.success + ' ' + language('no_errors_warnings',),);

Check warning on line 33 in src/cli/check-routes.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected console statement
}
};
13 changes: 13 additions & 0 deletions src/no-duplicate-ids.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import Task from "./task.js";

Check warning on line 1 in src/no-duplicate-ids.ts

View workflow job for this annotation

GitHub Actions / lint

Strings must use singlequote
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
import language from "./helper/language.js";

const noDuplicateIds = (tasks: Array<Task>,) => {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
const ids: Array<string> = [];
for (const task of tasks) {
if (ids.includes(task.id,)) {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
throw new Error(language('duplicate_task_id', task.id,),);
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
}
ids.push(task.id,);
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
}
};
export default noDuplicateIds;
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';
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
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,);
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
}
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';
Idrinth marked this conversation as resolved.
Show resolved Hide resolved

const checkMiddleware = (type: 'pre' | 'post', route: Task,) => {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
if (typeof route[type] === 'undefined') {
return true;
}
const data = route[type];
delete route[type];
if (typeof data !== 'object' || !Array.isArray(data,)) {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
error(`invalid_${type}_definition`, route.id,);
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
return false;
}
for (const middleware of data) {
if (typeof middleware !== 'string') {
error(`invalid_${type}_definition`, route.id,);
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
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];
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) {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
warn('invalid_request', id,);
return {
invalid: !valid,
risky: true,
};
}
return {
invalid: !valid,
risky: false,
};
};
export default checkRequest;
47 changes: 47 additions & 0 deletions src/validation/check-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
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,) => {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
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,)) {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
errors++;
}
if (!checkMiddleware('post', route,)) {
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
errors++;
}
const id = route.id;
delete route.id;
const result = checkRequest(route.main, id,);
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
if (result.invalid) {
errors++;
}
if (result.risky) {
warnings++;
}
delete route.main;
for (const key of Object.keys(route,)) {
warn('unknown_route_property', key, id,);
Idrinth marked this conversation as resolved.
Show resolved Hide resolved
warnings++;
}
}
}
return {
errors,
warnings,
};
};

export default checkType;
Loading
Loading