Nanoscale Parts Manufacturing

    ajv-dates
    TypeScript icon, indicating that this package has built-in type declarations

    1.1.0 • Public • Published

    ajv-dates

    npm version Coverage Status Build Status Bundle Phobia

    What's this?

    Good date validation has been conspicuously missing from the JSON schema spec. ajv-dates adds a few (configurable) keywords to ajv to make date validation a snap.

    Getting Started

    npm install ajv-dates
    # or
    yarn add ajv-dates

    Usage

    import Ajv from 'ajv';
    import dates from 'ajv-dates';
    
    const instance = dates(new Ajv());
    
    const validator = instance.compile({
        type: 'string',
        isAfter: Date.UTC(2021, 12, 31)
    });
    
    console.log(validator('2022-01-01').errors)
    // null, no errors!
    
    console.log(validator('2021-01-01').errors)
    /*
    
          [
            {
              message: 'Date must be after 1643587200000',
              instancePath: '',
              schemaPath: '#/isAfter'
            }
          ]
    
    */

    Keywords

    isAfter

    isAfter accepts a single argument that is, or can be parsed into a Date or unix timestamp:

    instance.validate({
        type: 'string',
        isAfter: Date.now()
    })

    isBefore

    isBefore accepts a single argument that is, or can be parsed into a Date or unix timestamp:

    instance.validate({
        type: 'string',
        isAfter: Date.now()
    })

    isBetween

    isBetween accepts a tuple of two values that are, or can be parsed into, Dates or unix timestamps:

    instance.validate({
        type: 'string',
        isBetween: [Date.now()-86400, Date.now()+86400]
    })

    isWeekday

    isWeekday accepts a boolean:

    instance.validate({
        type: 'string',
        isWeekday: true
    })

    isWeekend

    isWeekend accepts a boolean:

    instance.validate({
        type: 'string',
        isWeekend: false
    })

    Bonus Keywords: times

    If you supply a parser you can also take advantage of our time keywords:

    import Ajv from 'ajv';
    import { date, times } from 'ajv-dates';
    import { parseDate } from 'chrono-node';
    
    const options = { parser: parseDate }
    const instance = times(dates(new Ajv(),options),options)

    isTimeAfter

    instance.validate({
        type: 'string',
        isTimeAfter: '7:00pm',
    }, '6:30pm');
    
    // Error: Time must be after 7:00pm

    isTimeBefore

    instance.validate({
        type: 'string',
        isTimeBefore: '6:00pm',
    }, '6:30pm');
    
    // Error: Time must be before 6:00pm

    isTimeBetween

    instance.validate({
        type: 'string',
        isTimeBetween: ['7:00pm','10:00pm'],
    }, '6:30pm');
    
    // Error: Time must be between 7:00pm and 10:00pm

    API

    This library exports a default function that accepts an AJV instance and options.

    Options

    type Options = {
      parser?: (val: any) => Date | number;
      keywordMap?: KeywordMap;
    };

    parser = (val) => new Date(val)

    The parser accepts any value and tries to parse it to a Date (or a unix timestamp). It is used to parse both the subject being evaluated and the arguments given to the keyword. As shown below, the ability to specify a parser allows some really great features to be unlocked.

    keywordMap = Partial<Record<Keyword,string>>

    Don't like the keywords? Configure your own using the keyword map:

    const instance = dates(
        new Ajv(),
        { 
            keywordMap: { 
                isAfter: 'isDateAfter' 
            }
        }
    )
    
    instance.validate({
        type: 'string',
        isDateAfter: Date.now()
    }, '2021-12-31')

    Parser

    Even with ajv-formats, there's still something missing with date validation - the difficulty to encode "now", for validation purposes, in a schema. Fortunately, by using a smart date parser that can parse natural language relative strings into timestamps, you can now encode relative date logic into your schemas.

    Two great options (tested with ajv-dates) are:

    import Ajv from 'ajv';
    import dates from 'ajv-dates';
    
    import { Date as SDate } from 'sugar-date'
    import { parseDate } from 'chrono-node';
    
    // sugardate
    const instance = dates(new Ajv(), { parser: SDate.create })
    
    // chrono
    const instance = dates(new Ajv(), { parser: parseDate })

    Here's what the super power looks like:

    const schema = {
        type: 'string',
        isAfter: '30 days ago'
    }
    
    const instance = dates(new Ajv(), { parser: /* your chosen natural language date parser */ })
    const today = (new Date()).toISOString();
    
    instance.validate(
        {
            type: 'string',
            isAfter: '2 weeks ago'
        }, 
        today
    );
    console.log(instance.errors); // null
    
    instance.validate(
        {
            type: 'string',
            isAfter: '2 weeks from now'
        }, 
        today
    );
    
    console.log(instance.errors);
    /*
    
    [
        {
            message: 'Date must be after 2 weeks from now',
            instancePath: '',
            schemaPath: '#/isAfter'
        }
    ]
    
    */

    License

    MIT

    Contributing

    Grab an issue, PRs welcome!

    Install

    npm i ajv-dates

    DownloadsWeekly Downloads

    280

    Version

    1.1.0

    License

    ISC

    Unpacked Size

    19.5 kB

    Total Files

    14

    Last publish

    Collaborators

    • akmjenkins