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

json-predicate

v0.9.5

Published

Javascript implementation of JSON predicate (by Snell)

Downloads

2,305

Readme

json-predicate

npm version Build Status Dependencies Dev Dependencies

Version History

Check/Test/Validate if a block of JSON meets criteria defined by another block of JSON. This is a javascript implementation of the JSON Predicate (Snell) spec.

One likely use of this would be for passing data validations from the back-end to the front-end in a programmatic way. If your back-end is validating incoming data on an API, then it may be useful to send those same validations to the front-end so forms can be checked proactively for the user. The JSON Predicate spec defines the interchange, and this library takes care of reading those validations on the front-end. Now you just need a way to have your back-end serialize out your validations in the JSON predicate format. (Good luck with that!)

Please note that this library does not deal directly with JSON strings, themselves. Instead, it is assumed that the JSON has already been parsed into regular Javascript objects/arrays/expressions.

Given that this library deals with Javascript data (and not the actual JSON strings), it adds a few extra capabilities when it comes to type checking and regular expression matching.

Installation

node:

$ npm install json-predicate

Usage

var jsonPredicate = require('json-predicate');
var jsonTest = jsonPredicate.test;

var passesPredicate = jsonTest(inputData, predicate);
// --> True/False

Operations

contains

Check if the string at path includes the provided substring. Add ignore_case: true to make the check case-insensitive.

var data = {
  a: {
    b: 'Smart People on Ice!'
  }
};

var predicate = {
  op: 'contains',
  path: '/a/b',
  value: 'People'
}

jsonTest(data, predicate); // true

predicate = {
  op: 'contains',
  path: '/a/b',
  value: 'sMaRt PeOpLe',
  ignore_case: true
};

jsonTest(data, predicate); // true

defined

Check if the key at path exists (is not undefined).

var data = {
  a: {
    b: 'You\'ve seen him too?',
    c: null
  }
};

var predicate = {
  op: 'defined',
  path: '/a/b'
}
jsonTest(data, predicate); // true

var predicate = {
  op: 'defined',
  path: '/a/c'
}
jsonTest(data, predicate); // true

predicate = {
  op: 'defined',
  path: '/a/z'
}
jsonTest(data, predicate); // false

ends

Check if the string at path ends with the provided substring. Add ignore_case: true to make the check case-insensitive.

var data = {
  a: {
    b: 'Smart People on Ice!'
  }
};

var predicate = {
  op: 'ends',
  path: '/a/b',
  value: ' Ice!'
}

jsonTest(data, predicate); // true

predicate = {
  op: 'ends',
  path: '/a/b',
  value: 'On ICE!',
  ignore_case: true
};

jsonTest(data, predicate); // true

in

Check if the value at path is included in the provided value array. Compares objects deeply (using lodash _.isEqual under the hood). ignore_case:true can be passed to allow mismatched strings.

  var data = {
    firstName: 'Mitch',
    lastName: 'Taylor'
  }

  var predicate = {
    op: 'in',
    path: '/firstName',
    value: ['chris', 'mitch', 'kent', 'jordan'],
    ignore_case: true
  }

  jsonTest(data, predicate); // true

  var data = {
    title: 'Everything',
    host: {
      firstName: 'Jerry',
      lastName: 'Hathaway'
    }
  };

  var predicate = {
    op: 'in',
    path: '/host',
    value: [
      {firstName: 'Jerry', lastName: 'Hathaway'},
      {firstName: 'Albert', lastName: 'Einstein'}
    ]
  }

  jsonTest(data, predicate); // true

less

Check if the numeric value at path is less than the provided value. Returns false if either the value at path or the predicate value is non-numeric.

  var data = {
    a: 1984
  }

  var predicate = {
    op: 'less',
    path: '/a',
    value: 1985
  }

  jsonTest(data, predicate); // true

matches

Check if the string value at path satisfies the provided regex. The predicate value can be given directly as a regex, or as a string to be turned into a regex. ignore_case:true can also be added to the predicate to make the regex test case-insensitive.

  var data = {
    laser: {
      e: '1x10^6J/l' // "... That's hotter than the sun!"
    }
  }

  var predicate = {
    op: 'matches',
    path: '/laser/e',
    value: '[1-9x^]*J\/l' // pass regex as string
  }

  jsonTest(data, predicate); // true

  var predicate = {
    op: 'matches',
    path: '/laser/e',
    value: /[1-9x^]*J\/l/ // or pass regex directly
  }

  jsonTest(data, predicate); // true

more

Check if the numeric value at path is more than the provided value. Returns false if either the value at path or the predicate value is non-numeric.

  var data = {
    a: 1984
  }

  var predicate = {
    op: 'more',
    path: '/a',
    value: 1983
  }

  jsonTest(data, predicate); // true

starts

Check if the string at path starts with the provided substring. Add ignore_case: true to make the check case-insensitive.

var data = {
  a: {
    b: 'Smart People on Ice!'
  }
};

var predicate = {
  op: 'starts',
  path: '/a/b',
  value: 'Smart People'
}

jsonTest(data, predicate); // true

predicate = {
  op: 'starts',
  path: '/a/b',
  value: 'sMaRt',
  ignore_case: true
};

jsonTest(data, predicate); // true

test

Check if the value at path is equal to the provided value. Compares objects deeply (using lodash _.isEqual under the hood). ignore_case:true can be passed to allow mismatched strings.


  // Match strings:
  var data = {
    firstName: 'Mitch',
    lastName: 'Taylor'
  }

  var predicate = {
    op: 'test',
    path: '/firstName',
    value: 'mitch',
    ignore_case: true
  }

  jsonTest(data, predicate); // true

  // Match objects:
  var data = {
    title: 'Everything',
    host: {
      firstName: 'Jerry',
      lastName: 'Hathaway'
    }
  };

  var predicate = {
    op: 'test',
    path: '/host',
    value: {firstName: 'Jerry', lastName: 'Hathaway'}
  }

  jsonTest(data, predicate); // true

  // Match numbers:
  var data = {
    laser: {
      wavelength: 600,
      unit: 'nm'
    }
  }

  var predicate = {
    op: 'test',
    path: '/laser/wavelength',
    value: 600
  }

  jsonTest(data, predicate); // true

type

Check if the key at path is of the type given in the predicate value. Types can be:

  • number
  • string
  • boolean
  • object
  • array
  • null
  • undefined
  • date (A string conforming to RFC3339 'full-date' spec)
  • date-time (A string conforming to RFC3339 'date-time' spec)
  • time (A string conforming to RFC3339 'full-time' spec)
  • lang (A string conforming to RFC4646 'Language-Tag' spec)
  • lang-range (A string conforming to RFC4647 'language-range')
  • iri (A string conforming to RFC3987 'IRI-reference' spec)
  • absolute-iri (A string conforming to RFC3987 'IRI' spec)

Note: date, date-time, time string matching is based on the following regular expressions. They may not exactly match the RFC specs. I invite pull requests or recommendations for libraries to depend on.

  • date: /^\d{4}-\d{2}-\d{2}$/
  • date-time: /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?((?:[\+\-]\d{2}:\d{2})|Z)$/
  • time: /^\d{2}:\d{2}:\d{2}(?:\.\d{1,3})?((?:[\+\-]\d{2}:\d{2})|Z)$/

Note: lang and lang-range string matching is based on the following regular expressions. They may not exactly match RFC specs. I invite pull requests or recommendations for libraries to depend on.

  • lang: /^[a-z]{2,3}(?:-[A-Z]{2,3}(?:-[a-zA-Z]{4})?)?$/
  • lang-range: /^\*|[A-Z]{1,8}(?:-[\*A-Za-z0-9]{1,8})?$/

Note: iri and absolute-iri string matching is based on the valid-url library. With validUrl.isUri() being used for 'iri' type, and validUrl.isWebUri() being used for 'absolute-iri'. This is almost certainly not the correct behavior with respect to RFC3987 and the JSON-predicate spec. In invite pull requests or recommendations to improve this.

var data = {
  num: 23,
  str: "little pickles",
  bool: true,
  obj: { firstName: "Lazlo", lastName: "Hollyfeld" },
  arr: ['tracking system', 'large spinning mirror'],
  nil: null,
  d: '1985-08-07',
  dt: '1985-08-07T19:00:00Z',
  t: '19:00:00-05:00',
  l: 'en-US',
  lr: 'CH-*',
  iri: 'https://github.com/MalcolmDwyer/json-predicate#type',
  absIri: 'https://github.com/MalcolmDwyer/json-predicate'
}

jsonTest(data, {op:'type', path:'/num',       value:'number'});       // true
jsonTest(data, {op:'type', path:'/str',       value:'string'});       // true
jsonTest(data, {op:'type', path:'/bool',      value:'boolean'});      // true
jsonTest(data, {op:'type', path:'/obj',       value:'object'});       // true
jsonTest(data, {op:'type', path:'/arr',       value:'array'});        // true
jsonTest(data, {op:'type', path:'/nil',       value:'null'});         // true
jsonTest(data, {op:'type', path:'/not_a_key', value:'undefined'});    // true
jsonTest(data, {op:'type', path:'/d',         value:'date'});         // true
jsonTest(data, {op:'type', path:'/dt',        value:'date-time'});    // true
jsonTest(data, {op:'type', path:'/t',         value:'time'});         // true
jsonTest(data, {op:'type', path:'/l',         value:'lang'});         // true
jsonTest(data, {op:'type', path:'/lr',        value:'lang-range'});   // true
jsonTest(data, {op:'type', path:'/iri',       value:'iri'});          // true
jsonTest(data, {op:'type', path:'/absIri',    value:'absolute-iri'}); // true

undefined

Check if the key at path does not exist (is undefined).

var data = {
  a: {
    b: 'You\'ve seen him too?',
    c: null
  }
};

predicate = {
  op: 'undefined',
  path: '/a/z'
}
jsonTest(data, predicate); // true

var predicate = {
  op: 'undefined',
  path: '/a/b'
}
jsonTest(data, predicate); // false

var predicate = {
  op: 'undefined',
  path: '/a/c'
}
jsonTest(data, predicate); // false

contained

Note: This operation is not included in the Snell json-predicate spec. If you are sharing predicates with other implementations, you should avoid using this op.

Check if the key at path (which must be an array) contains the value given. (Inverse of in, which has the array in the predicate and the single value in the data). Can compare strings, numbers, shallow and deep objects. Operation honors the ignore_case parameter when comparing string values.

var data = {
  a: {
    b: [1983, 1984, 1985]
  }
}

var predicate = {
  op: 'contained',
  path: '/a/b',
  value: 1984
}

jsonTest(data, predicate); // true

intersects

Note: This operation is not included in the Snell json-predicate spec. If you are sharing predicates with other implementations, you should avoid using this op.

Check if the key at path (which must be an array) has any matching values in common with the provided array data (which also must be an array). As long as one or more elements in the two arrays match (numeric, string, shallow or deep object comparisons, etc.), then the test will return true. If either value is not an array, or if no array elements are found in common, then it returns false. Operation honors the ignore_case parameter for string comparisons.

var data = {
  a: {
    b: [1983, 1984, 1985]
  }
}

var predicate = {
  op: 'contained',
  path: '/a/b',
  value: [1984, 1988, 1992]
}

jsonTest(data, predicate); // true

and

Check if two or more sub-predicates are true.

var data = {
  a: {
    b: 'Much further, much faster!',
    c: 'I don\'t know; I found it in one of the labs.'
  }
}

predicate = {
  op: 'and',
  apply: [
    {
      op: 'contains',
      path: '/a/b',
      value: 'faster!'
    },
    {
      op: 'contains',
      path: '/a/c',
      value: 'labs'
    }
  ]
}
jsonTest(data, predicate); // true

Paths can also be defined in layers:

var data = {
  a: {
    b: 'Much further, much faster!',
    c: 'I don\'t know; I found it in one of the labs.'
  }
}

predicate = {
  op: 'and',
  path: '/a',
  apply: [
    {
      op: 'contains',
      path: '/b',
      value: 'faster!'
    },
    {
      op: 'contains',
      path: '/c',
      value: 'labs'
    }
  ]
}
jsonTest(data, predicate); // true

or

Check if any of two or more sub-predicates are true.

var data = {
  a: {
    b: 'Much further, much faster!',
    c: 'I don\'t know; I found it in one of the labs.'
  }
}

predicate = {
  op: 'or',
  apply: [
    {
      op: 'contains',
      path: '/a/b',
      value: 'faster!' // true
    },
    {
      op: 'contains',
      path: '/a/c',
      value: 'Get out, Lightman!' // false
    }
  ]
}
jsonTest(data, predicate); // true

predicate = {
  op: 'or',
  apply: [
    {
      op: 'contains',
      path: '/a/b',
      value: 'Protovision, I have you now!' // false
    },
    {
      op: 'contains',
      path: '/a/c',
      value: 'Get out, Lightman!' // false
    }
  ]
}
jsonTest(data, predicate); // false

Paths can also be defined in layers:

var data = {
  a: {
    b: 'Much further, much faster!',
    c: 'I don\'t know; I found it in one of the labs.'
  }
}

predicate = {
  op: 'or',
  path: '/a',
  apply: [
    {
      op: 'contains',
      path: '/b',
      value: 'faster!' // true
    },
    {
      op: 'contains',
      path: '/c',
      value: 'Mr. Potatohead!' // false
    }
  ]
}
jsonTest(data, predicate); // true

not

Check if two or more sub-predicates are all false. Equivalent to a logical NOR operation.

var data = {
  a: {
    b: 'Much further, much faster!',
    c: 'I don\'t know; I found it in one of the labs.'
  }
}

predicate = {
  op: 'not',
  apply: [
    {
      op: 'contains',
      path: '/a/b',
      value: 'Joshua, what are you doing?' // false
    },
    {
      op: 'contains',
      path: '/a/c',
      value: 'Hi, Lightman!' // false
    }
  ]
}
jsonTest(data, predicate); // true

Paths can also be defined in layers:

var data = {
  a: {
    b: 'Much further, much faster!',
    c: 'I don\'t know; I found it in one of the labs.'
  }
}

predicate = {
  op: 'not',
  path: '/a',
  apply: [
    {
      op: 'contains',
      path: '/b',
      value: 'Joshua, what are you doing?' // false
    },
    {
      op: 'contains',
      path: '/c',
      value: 'Hi, Lightman!' // false
    }
  ]
}
jsonTest(data, predicate); // true