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

schema-select

v1.1.0

Published

Provides utility classes for selecting and enforcing a particular data type schema

Downloads

145

Readme

Schema Select

This library provides a framework for setting the schema of selected value, applying the effects of said schema to that value, and checking which schema if any already applies. This is intended as a generic library for value editors where you want the users to be able to select a particular value type and have it applied.

Quickstart

Installation

You can install this library through npm like so:

$ npm install --save schema-select

Option Factories

The meat of this library is the SchemaOptionsFactory class. It's composed of three major elements: a label factory, an enforcer factory, and an optional schema splitter. These are used in turn by the options factory's process function to extract a list of labeled schema enforcers. Here's a run down of how that works:

  • The splitter breaks the schema down into a list of potential subschema branches. This allows handling schema with multiple valid variants, such as a JSON schema using the "anyOf" keyword.
  • The label factory generates a label string for each of those subschemas.
  • The enforcer factory generatea a SchemaEnforcer for each subschema.

These combine to produce an array of LabeledValue items, each having a label string and a schema enforcer value. Said schema enforcers have a reference to the associated subschema and a validate function. They may also have an optional coerce function.

The validate function evaluates it's first parameter and returns a validation response based on whether the value matches the subschema. The form this response takes varies by enforcer type, defaulting to a boolean.

Similarly, the coerce function return a value the meets the schema's criteria, adhering as closely as possible to the first parameter without violating the schema's constraints.

JSON Schema Options

For an example of how this all comes together, see the JSONSchemaOptionsFactory. That support JSON Schema values and comes prebuilt with all 3 subelements. As such you can use it right out of the box like so:

import { JSONSchemaOptionsFactory } from "schema-select"

const optionsFactory = new JSONSchemaOptionsFactory()
const options = optionsFactory.process(true)

Doing so will give you a list of options for the array, object, boolean, string, number, integer, and null types. It return those options rather than a single any type due to using a JSONSchemaSplitter, which assumes by default that users will want to be able to force a particular valid subtype.

Note that default enforcer factory is a minimalist one that currently only supports the type and const keywords, with enums handled by the splitter. However, you can expand on or replace that enforcer as needed.

Replacing the Enforcer Factor

When creating the JSON schema factory, you can pass in a custom enforcer factory as the first parameter. Said factory must have the following type of process function:

(value: FlagOrObject) => SchemaEnforcer<FlagOrObject, ErrorLog<Partial<KeywordError>>>

That means the process function must accept a boolean or object as it's first parameter and return a schema enforcer as it's result. Said enforcer must have a schema and validate property and may have a coerce function as noted above. That validate function must return an object with an errors array. The errors in that array may have the following properties:

  • keyword - name of the keyword rule violated
  • value - value associated with the above keyword in the source schema
  • target - value that failed validation
  • priority - importance of this error relative to any others
  • coerce - callback to generate a version of the provided value that would pass validation

This means you can plug your favorite JSON schema validation libary into a JSONSchemaOptionsFactory, provided you wrap it in an enforcer factory that follows the above rules.

Should you want to plug those into such a factory without those restrictions, simply create a SchemaOptionsFactory and pass in your custom enforcer factory like so:

import { SchemaOptionsFactory, JSONSchemaLabeler, JSONSchemaSplitter } from "schema-select"

const optionsFactory = new SchemaOptionsFactory(
  {
    process: (schema: any) => {
      return {
        schema,
        validate: (value: any) => Boolean(value)
      }
    }
  },
  new JSONSchemaLabeler(),
  new JSONSchemaSplitter()
)

Just plug your libary of choice into the above process callback and you're good to go.

Adding Keyword Rules

You can add an additional keyword to schema parsing by adding a rule to the enforcer factory's keyword handler, like so:

const enforcerFactory = optionsFactory.enforcerFactory as JSONSchemaEnforcerFactory
enforcerFactory.keywordHandler.rules.push(
  {
    keyword: 'not',
    getEnforcerFor: (source: Record<string, any>) => {
      if ('not' in source) {
        const enforcer = enforcerFactory.process(source.not)
        return {
          schema: source,
          validate: (value) => {
            const result = enforcer.validate(value)
            return result.errors.length <= 0
              ? {
                errors: [
                  {
                    keyword: 'not',
                    value: source.not,
                    target: value
                  }
                ]
              }
              : { errors: [] }
          }
        }
      }
    }
  }
)

Option Parsers

As of version 1.1.0 I've added the SchemaOptionsParser class. This combines an options factory with a validation parser to let you find the most appropriate subschema for a given value, like so:

import { JSONSchemaOptionsParser } from "schema-select"

const parser = new JSONSchemaOptionsParser()
const options = parser.getOptionsFor({
  oneOf: [
    { type: 'boolean' },
    { type: 'number' }
  ]
})
const match = parser.getMostValidOption(options, 1)

The above uses a subclass that starts with a JSONSchemaOptionsFactory and KeywordErrorLogValidationParser. As with the JSONSchemaOptionsFactory you may pass in a custom enforcer factory to plug in your library of choice.

To support these option parsers, validation parsers now have a rateValidity function that convert a validation value to a number. The above KeywordErrorLogValidationParser uses the highest priority error to determine this.