Concepts

js.spec has two main concepts: Predicates and specs. However this distinction is rather technical and should not matter in practice as they can be used interchangeably.

tl;dr

  • Predicates
    • Smallest building block for schemas
    • Functions any → boolean
    • Users should implement custom predicates if built-ins are insufficient
  • Specs
    • Powerful way to compose predicates
    • Users should not implement custom spec types (ie. something you would use instead of spec.map)

Predicates

Predicates are check functions that take input data and return a boolean. For instance the predicate isString would return true iff the provided parameter is a string and could be implemented like this:

function isString(data) {
  return typeof data === 'string';
}

Now with a naive approach that could be it: If you would want to check for an even number between 0 and 100, you'd need to write a predicate for that. This doesn't scale, which is (also) why there are specifications.

Specs

Specs are somewhat like predicates. They can also check for validity, but more. To add to the confusion, every predicate can be used as spec (will be automatically converted).

What are the powerful features?

Composability

You can define how an address looks in your system, e.g. a map with keys country, zipcode and street:

const classic_address = spec.map("classic address", {
  country: spec.string,
  zipcode: spec.string,
  street: spec.string
})

...and use that when you define a person!

const person = spec.map("person", {
  name: spec.map("name", {
    first: spec.string,
    last: spec.string
  }),
  address: classic_address
})

Support for alternatives

Sometimes you want your data to match one of many alternatives. For instance there are countries that use more than zip code and street, so for sake of argument you could add GPS as a universal alternative.

const gps_address = spec.map("gps", {
  lat: spec.number,
  lon: spec.number
})

const address = spec.or("address", {
  gps: gps_address,
  simple: classic_address
})

Reverse match

Consider the address example from above: At some point you will want to know which type of address you are working with. Maybe you want to plot your users on a map and need to convert simple addresses to GPS coordinates first. You can do that with specifications:

conform(address, { lat: 13, lon: 55 })
// ['gps', { lat: 13, lon: 55 }]

Introspection

Get metadata about a specification, e.g. type and configuration (🚧 WIP).

results matching ""

    No results matching ""