fix(core): update

This commit is contained in:
Philipp Kunz 2024-05-30 16:57:18 +02:00
parent f02d175a2a
commit 1cf88b5aad
7 changed files with 208 additions and 29 deletions

View File

@ -17,12 +17,15 @@
"nodejs",
"express",
"middleware",
"data validation",
"security",
"input validation",
"API",
"data validation",
"custom validation",
"composite validation"
"composite validation",
"form validation",
"server-side validation",
"backend validation"
]
}
},

View File

@ -48,16 +48,19 @@
"nodejs",
"express",
"middleware",
"data validation",
"security",
"input validation",
"API",
"data validation",
"custom validation",
"composite validation"
"composite validation",
"form validation",
"server-side validation",
"backend validation"
],
"homepage": "https://code.foss.global/push.rocks/smartguard",
"repository": {
"type": "git",
"url": "https://code.foss.global/push.rocks/smartguard.git"
}
}
}

154
readme.md
View File

@ -1,5 +1,5 @@
# @push.rocks/smartguard
A library for creating and managing validation guards.
A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.
## Install
@ -255,7 +255,157 @@ console.log(userProfileValidationResults.every(result => result)); // true if us
In this example, we created a nested guard structure to validate a user profile object that includes address information. Each nested object is validated individually using its specific guards.
### Summary
### Dynamic Guards
There can be situations when you need to create guards dynamically based on some conditions or input. `@push.rocks/smartguard` allows you to create and use such dynamic guards effortlessly.
```typescript
import { Guard, GuardSet } from '@push.rocks/smartguard';
const createDynamicGuard = (minLength: number) => new Guard<string>(async (data) => {
return data.length >= minLength;
});
const flexibleLengthGuardSet = (length: number) => new GuardSet<string>([createDynamicGuard(length)]);
const dynamicGuard = flexibleLengthGuardSet(5);
const isValid = await dynamicGuard.executeGuardsWithData('Hello, world!');
console.log(isValid.every(result => result)); // true because the length of 'Hello, world!' is more than 5
```
In the example above, we created a dynamic guard based on a minimum length and then evaluated some data against it.
### Validating Complex Data Structures
There can often be a need to validate complex data structures with nested arrays or objects. Using a combination of `Guard` and `GuardSet`, you can effectively handle validations of such complex structures.
```typescript
interface BlogPost {
title: string;
content: string;
tags: string[];
author: {
name: string;
email: string;
};
}
const isStringGuard = new Guard<string>(async (data) => {
return typeof data === 'string';
});
const isNonEmptyStringGuard = new Guard<string>(async (data) => {
return await isStringGuard.executeGuardWithData(data) && data.trim().length > 0;
});
const isStringArrayGuard = new Guard<string[]>(async (data) => {
return Array.isArray(data) && data.every(item => typeof item === 'string');
});
const isEmailGuard = new Guard<string>(async (data) => {
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
return typeof data === 'string' && emailRegex.test(data);
});
const isAuthorGuardSet = new GuardSet<BlogPost['author']>([
new Guard(async (data) => await isNonEmptyStringGuard.executeGuardWithData(data.name)),
new Guard(async (data) => await isEmailGuard.executeGuardWithData(data.email))
]);
const isBlogPostGuardSet = new GuardSet<BlogPost>([
new Guard(async (data) => await isNonEmptyStringGuard.executeGuardWithData(data.title)),
new Guard(async (data) => await isNonEmptyStringGuard.executeGuardWithData(data.content)),
new Guard(async (data) => await isStringArrayGuard.executeGuardWithData(data.tags)),
new Guard(async (data) => await isAuthorGuardSet.executeGuardsWithData(data.author).then(results => results.every(result => result)))
]);
const blogPost: BlogPost = {
title: 'Introduction to Smart Guard',
content: 'Smart Guard is a TypeScript library for creating and managing validation guards...',
tags: ['typescript', 'validation', 'library'],
author: {
name: 'John Doe',
email: 'johndoe@example.com'
}
};
const blogPostValidationResults = await isBlogPostGuardSet.executeGuardsWithData(blogPost);
console.log(blogPostValidationResults.every(result => result)); // true if the blog post is valid
```
In this example, we created different guards to validate various parts of a complex `BlogPost` object. Notice how we used nested `GuardSet` instances to validate the `author` object.
### Asynchronous Validations
`@push.rocks/smartguard` supports asynchronous guard functions, making it possible to perform validations that involve network requests or other asynchronous operations.
```typescript
import { Guard } from '@push.rocks/smartguard';
import { smartrequest } from '@push.rocks/smartrequest';
const isApiKeyValidGuard = new Guard<string>(async (apiKey) => {
const response = await smartrequest.request(`https://api.example.com/validate?key=${apiKey}`, { method: 'GET' });
return response.status === 200;
});
const apiKey = 'some-api-key';
const isApiKeyValid = await isApiKeyValidGuard.executeGuardWithData(apiKey);
console.log(isApiKeyValid); // true if the API key is valid
```
In this example, the guard performs an asynchronous API request to validate an API key.
### Default Error Handling
When using `@push.rocks/smartguard`, you can take advantage of built-in error handling mechanisms. If a guard fails, it throws an error that you can catch and handle accordingly.
```typescript
import { Guard, passGuardsOrReject } from '@push.rocks/smartguard';
const isNonEmptyStringGuard = new Guard<string>(async (data) => {
return typeof data === 'string' && data.trim().length > 0;
});
const validateInput = async (input: string) => {
try {
await passGuardsOrReject(input, [isNonEmptyStringGuard]);
console.log('Input is valid');
} catch (error) {
console.error('Validation failed:', error.message);
}
};
await validateInput(''); // Will print "Validation failed: Guard failed"
await validateInput('Valid input'); // Will print "Input is valid"
```
In this example, we use the `passGuardsOrReject` function to validate an input. If the input is invalid, `passGuardsOrReject` throws an error that is caught and handled in the `catch` block.
### Extending Guard Functionalities
Sometimes, you may need to extend or customize the functionalities of a guard to suit specific requirements. `@push.rocks/smartguard` allows you to extend the `Guard` class to create specialized guards.
```typescript
import { Guard } from '@push.rocks/smartguard';
class MinLengthGuard extends Guard<string> {
constructor(private minLength: number) {
super(async (data) => {
return typeof data === 'string' && data.length >= this.minLength;
});
}
}
const minLengthGuard = new MinLengthGuard(10);
const isLongEnough = await minLengthGuard.executeGuardWithData('Hello, world!');
console.log(isLongEnough); // true because the length of 'Hello, world!' is more than 10
```
In this example, we create a `MinLengthGuard` class that extends `Guard` and validates a string based on its minimum length.
### Conclusion
`@push.rocks/smartguard` provides a powerful framework for creating and managing validation guards in JavaScript and TypeScript applications. The library's flexibility allows it to handle simple boolean checks, asynchronous operations, integration with external APIs, and complex composite validations. Its use of `Guard` and `GuardSet` classes ensures that validations are both modular and reusable.

View File

@ -33,7 +33,7 @@ tap.test('should be able to create smartguards for a request', async () => {
smartexpressInstance.addRoute(
'/testroute',
new typedserver.servertools.Handler('ALL', async (req, res) => {
await smartguard.passGuards(
await smartguard.passGuardsOrReject(
{
req,
res,

View File

@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartguard',
version: '2.0.2',
version: '2.0.3',
description: 'A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.'
}

View File

@ -3,16 +3,11 @@ import { Guard } from './smartguard.classes.guard.js';
import { GuardSet } from './smartguard.classes.guardset.js';
export * from './smartguard.classes.guard.js';
export const passGuards = async <T>(dataArg: T, guards: Array<Guard<T>>) => {
const done = plugins.smartpromise.defer();
export const passGuardsOrReject = async <T>(dataArg: T, guards: Array<Guard<T>>) => {
const guardSet = new GuardSet<T>(guards);
const results = await guardSet.executeGuardsWithData(dataArg);
for (const result of results) {
if (!result) {
return;
}
const result = await guardSet.allGuardsPass(dataArg);
if (!result) {
throw new Error('Guard failed');
}
done.resolve();
await done.promise;
return;
return ;
};

View File

@ -1,23 +1,51 @@
import * as plugins from './smartguard.plugins.js';
import { Guard } from './smartguard.classes.guard.js';
import { Guard, type TGuardFunction } from './smartguard.classes.guard.js';
/**
* a guardSet is a set of guards that need to be fulfilled
* Extended GuardSet that inherits from Guard
* and provides additional functionalities.
*/
export class GuardSet<T> {
export class GuardSet<T> extends Guard<T> {
public guards: Array<Guard<T>>;
public passed: boolean;
constructor(guardsArrayArg: Array<Guard<T>>) {
this.guards = guardsArrayArg;
constructor(guardArray: Array<Guard<T>> = []) {
super(async (dataArg: T) => {
return this.allGuardsPass(dataArg);
})
this.guards = guardArray;
}
public async executeGuardsWithData(dataArg: T) {
/**
* executes all guards in all guardSets against a data argument
* @param dataArg
*/
public async executeAllGuardsWithData(dataArg: T) {
const resultPromises: Array<Promise<boolean>> = [];
for (const guard of this.guards) {
const resultPromise = guard.executeGuardWithData(dataArg);
resultPromises.push(resultPromise);
const guardResultPromise = guard.executeGuardWithData(dataArg);
resultPromises.push(guardResultPromise);
}
const results = Promise.all(resultPromises);
const results = await Promise.all(resultPromises);
return results;
}
/**
* checks if all guards pass
* @param dataArg
*/
public async allGuardsPass(dataArg: T): Promise<boolean> {
const results = await this.executeAllGuardsWithData(dataArg);
return results.every(result => result);
}
/**
* checks if any guard passes
* @param dataArg
*/
public async anyGuardsPass(dataArg: T): Promise<boolean> {
const results = await this.executeAllGuardsWithData(dataArg);
return results.some(result => result);
}
}