npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

@o-galaxy/guardian

v1.1.1

Published

Guardian - Validation Module.

Downloads

8

Readme

Guardian

Validation Module - Follow the Builder pattern.

  • Provide an easy validation layers building api.
  • Support sync & async validation as one.
  • Provide a custom (sync & async) validation method registry, for global app usage.
  • Support a reduction of a validation stack to an express/connect middleware.
  • Support typescript from the box.
  • Provide OR relation in the validation stack.
  • No dependencies.

Example

// validation-registry.ts

import { CustomRegistryContext } from 'guardian/core/custom-registry';


CustomRegistryContext.registerCustomFunction(
    'start-with-X', 
    function(name: string) { 
        const prefix = this.args[0]; // dynamically bound context
        return name.startsWith(prefix);
    }
)

import { Guardian } from 'guardian'

import { NotNull, NotUndefined, Gt, RunCustom } from 'guardian/core/layer-operators';


// instantiate an Guardian object to build the validation layers on top.
const guardian = new Guardian(); 


// stacking up the layers

guardian.on({ 
    path: ['data.address', 'name'], 
    errorMessage: 'name & address are required' 
}).add([
    NotNull(), 
    NotUndefined()
]);


guardian.on({ 
    path: 'name', 
    errorMessage: 'name must start with B' 
}).add([
    RunCustom('start-with-X', 'B')
]);


guardian.on({ 
    path: 'data.list[$]',         
    errorMessage: 'all items in list are required',
    each: true 
}).add([
    NotNull()
]);


guardian.on({ 
    path: 'data.items[-1].num',   
    errorMessage: 'last item must be greater than 5', 
}).add([
    Gt(5)
]);


// compile the target object
guardian.compile({ 
    name: 'Bob', 
    data: { 
        address: 'home', 
        list: [2, null], 
        items: [
            {num: 2}, 
            {num: null}, 
            {num: 6}, 
            {num: 8}, 
            {num: 10}]
    } 
});


// exec the validations
guardian.run().then(errors => {
    console.log(errors);
});

// Output : 

[
  {
    "message": "name & address are required",
    "target": null,
    "path": "data.address",
    "layerKey": 1
  },
  {
    "message": "all items in list are required",
    "target": [
      2,
      null
    ],
    "path": "data.list[$]",
    "layerKey": 3
  }
]

Stack Summary

guardian.stackSummary()

// Output : 

┌─────────┬───────┬───────────────────────────────┬────────────────────────────┬─────┐
│ (index) │ Layer │             Name              │            Path            │ Key │
├─────────┼───────┼───────────────────────────────┼────────────────────────────┼─────┤
│    0    │   1   │ [ 'NotNull', 'NotUndefined' ] │ [ 'data.address', 'name' ] │  1  │
│    1    │   2   │      [ 'start-with-X' ]       │           'name'           │  2  │
│    2    │   3   │         [ 'NotNull' ]         │       'data.list[$]'       │  3  │
│    3    │   4   │           [ 'Gt' ]            │    'data.items[-1].num'    │  4  │
└─────────┴───────┴───────────────────────────────┴────────────────────────────┴─────┘

API

class Guardian

By using a Guardian object a stack of validation layers can be built to validate a single object target.

const guardian = new Guardian()

Method

guardian.on()

on(options: GuardianOptions): LayerAttacher;
on(path: Array<string>): LayerAttacher;
on(path: string): LayerAttacher;

A factory method for LayerAttacher object, with on method you're setting the configuration for the validation layer you're about to create.

GuardianOptions reference

  • Example :
guardian.on({ 
    path: 'data.list[$]',         
    errorMessage: 'all items in list are required',
    each: true 
}).add([
    NotNull()
]);

guardian.orReduction()

orReduction(...keys: Array<string>): void

By providing the layers keys, orReduction will reduce the referenced layers to a single layer, that resolve to true if at least on of the referenced layers resolved to true.

  • Example :

const guardian = new Guardian();

guardian.on({ 
    path: 'name', 
    errorMessage: 'name must start with B.' 
}).add([
    RunCustom('start-with-X', 'B')
]);

guardian.on({ 
    path: 'data.age',         
    errorMessage: 'age is required & must be greater than 20.'
}).add([
    NotNull(),
    Gt(20)
]);

guardian.on({ 
    path: 'data.list[$]',         
    errorMessage: 'all items in list are required',
    each: true 
}).add([
    NotNull()
]);

// before orReduction --> 1 & 2 & 3

guardian.orReduction('1', '3');

// after orReduction --> (1 || 3) & 2

guardian.compile({ 
    name: 'Bob', 
    data: { 
        age: 25,
        list: [2, null]
    }
});

console.log('summary:');
guardian.stackSummary();

guardian.run().then(errors => {
    console.log('result:');
    console.log(JSON.stringify(errors, undefined, 2));
});

// Output :
summary:
┌─────────┬────────┬─────────────────────┬────────────────┬─────┐
│ (index) │ Layer  │        Name         │      Path      │ Key │
├─────────┼────────┼─────────────────────┼────────────────┼─────┤
│    0    │ 'OR/1' │ [ 'start-with-X' ]  │     'name'     │  1  │
│    1    │ 'OR/1' │    [ 'NotNull' ]    │ 'data.list[$]' │  3  │
│    2    │   1    │ [ 'NotNull', 'Gt' ] │   'data.age'   │  2  │
└─────────┴────────┴─────────────────────┴────────────────┴─────┘
result:
[]

guardian.compile()

compile(target: any): void

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

guardian.run()

run(): Promise<Array<any>

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

guardian.disable()

disable(layerKey: number|string): void

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

guardian.stackSummary()

stackSummary(prettyPrint: boolean): void 
stackSummary(): Array<any> 

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

guardian.toMiddleware()

toMiddleware(target?: Function ): e.RequestHandler
toMiddleware(target?: string ): e.RequestHandler

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

  • Example :
const guardian = new Guardian();

guardian.on({ 
    path: 'email', 
    errorMessage: 'email field is required.'
}).add([
    NotUndefined(),
    NotNull(),
    NotEmpty()
])

// the root object will be {req, res}
const logisterValidator = guardian.toMiddleware('req.body');

const app = express();
app.post('/login', logisterValidator, (req, res, next) => {
    // request pass all validations ...
});

Interfaces

GuardianOptions

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

interface GuardianOptions {
    layerKey?: string | number;
    optional?: boolean;
    errorMessage?: string;
    each?: boolean;
    disabled?: boolean
    path: string | Array<string>;
}

class LayerAttacher

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

const layerAttacher = guardian.on(...);

Method

layerAttacher.add()

add(operations: LayerOperation): void
add(operations: Array<LayerOperation>): void

define a single validation layer with one or more layer-operations. where each operation holds the actual validation logic.

LayerOperation reference

Interfaces

LayerOperation

Lorem Ipsum is simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s, when an unknown printer took.

interface LayerOperation {
    (options: Partial<GuardianOptions>): SequentialLayer
}