8 Commits

Author SHA1 Message Date
philkunz d53fe44766 3.0.1 2024-05-30 18:57:11 +02:00
philkunz 993c4e07bc fix(core): update 2024-05-30 18:57:10 +02:00
philkunz 8329bb902f 3.0.0 2024-05-30 18:53:53 +02:00
philkunz 7acda53d57 BREAKING CHANGE(api): changed API to be more concise 2024-05-30 18:53:52 +02:00
philkunz 50789d4416 2.0.4 2024-05-30 17:53:34 +02:00
philkunz d79d93ad30 fix(core): update 2024-05-30 17:53:33 +02:00
philkunz c9bd9dbe02 2.0.3 2024-05-30 16:57:18 +02:00
philkunz 1cf88b5aad fix(core): update 2024-05-30 16:57:18 +02:00
10 changed files with 214 additions and 32 deletions
+5 -2
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"
]
}
},
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "@push.rocks/smartguard",
"version": "2.0.2",
"version": "3.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@push.rocks/smartguard",
"version": "2.0.2",
"version": "3.0.1",
"license": "MIT",
"dependencies": {
"@push.rocks/smartpromise": "^3.0.2",
+6 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@push.rocks/smartguard",
"version": "2.0.2",
"version": "3.0.1",
"private": false,
"description": "A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.",
"main": "dist_ts/index.js",
@@ -48,12 +48,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"
],
"homepage": "https://code.foss.global/push.rocks/smartguard",
"repository": {
+152 -2
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.
+1 -1
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,
+1 -1
View File
@@ -3,6 +3,6 @@
*/
export const commitinfo = {
name: '@push.rocks/smartguard',
version: '2.0.2',
version: '3.0.1',
description: 'A TypeScript library for creating and managing validation guards, aiding in data validation and security checks.'
}
+5 -9
View File
@@ -2,17 +2,13 @@ import * as plugins from './smartguard.plugins.js';
import { Guard } from './smartguard.classes.guard.js';
import { GuardSet } from './smartguard.classes.guardset.js';
export * from './smartguard.classes.guard.js';
export * from './smartguard.classes.guardset.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) {
const result = await guardSet.allGuardsPass(dataArg);
if (!result) {
return;
throw new Error('Guard failed');
}
}
done.resolve();
await done.promise;
return;
return ;
};
+1 -1
View File
@@ -12,7 +12,7 @@ export class Guard<T> {
* executes the guard against a data argument;
* @param dataArg
*/
public async executeGuardWithData(dataArg: T) {
public async exec(dataArg: T) {
const result = await this.guardFunction(dataArg);
return result;
}
+38 -10
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 execAllWithData(dataArg: T) {
const resultPromises: Array<Promise<boolean>> = [];
for (const guard of this.guards) {
const resultPromise = guard.executeGuardWithData(dataArg);
resultPromises.push(resultPromise);
const guardResultPromise = guard.exec(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.execAllWithData(dataArg);
return results.every(result => result);
}
/**
* checks if any guard passes
* @param dataArg
*/
public async anyGuardsPass(dataArg: T): Promise<boolean> {
const results = await this.execAllWithData(dataArg);
return results.some(result => result);
}
}
+2
View File
@@ -1,4 +1,6 @@
// @push.rocks scope
import * as smartpromise from '@push.rocks/smartpromise';
// pushrocks scope
export { smartpromise };