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

@danifoldi/spartan-schema

v2.1.0

Published

A fork of spartan-schema with some new features

Downloads

13

Readme

Spartan Schema

This is a fork of spartan-schema, with changes that better suit my workflow, and added features that I felt like were missing.

An ultra-minimal, Typescript-compatible alternative to JSON Schema, designed as part of Osmosis.

Spartan Schema is...

  • Clear: Spartan Schemas are singificantly simpler than comparable JSON schemas. Here's a schema that will match objects like { name: { first: "Al", last: "Yankovic" }, age: 62 }:

    {
      "schema": {
        "name": {
          "first": "string",
          "middle": ["optional", "string"],
          "last": "string"
        },
        "age": "integer"
      }
    }
  • Compatible: Spartan Schema includes binary and date types, for languages like YAML and MessagePack that support more data types than JSON. The parser expects a JavaScript object, which can be parsed from any JSON-like format, or written directly in JS/TS source.

  • Minimal: The entire specification fits on a single page. Spartan Schema can describe itself in 20 lines of YAML:

    spartan: 1
    let:
      EnumValue: [oneof, null, boolean, number, string]
      Type:
      - oneof
      - [enum, null, 'null', boolean, integer, float, number, string, date, binary]
      - [array, [enum, enum], [ref, EnumValue], [ref, EnumValue]]
      - [array, [enum, oneof], [ref, Type], [ref, Type]]
      - [array, [enum, tuple], [ref, Type], [ref, Type]]
      - [array, [enum, array], [ref, Type], [ref, Type]]
      - [tuple, [enum, dictionary], [ref, Type]]
      - [tuple, [enum, ref], string]
      - - dictionary
        - - oneof
          - [tuple, [enum, optional], [ref, Type]]
          - [ref, Type]
    schema:
      spartan: [optional, [enum, 1]]
      let: [optional, [dictionary, [ref, Type]]]
      schema: [ref, Type]
  • Statically typed: Spartan Schema uses Typescript 4.1 recursive conditional types to convert schemas into Typescript type definitions. A schema written directly in source code can be a single source of truth for both compile-time and runtime typechecking.

    import { matchesSchema } from 'spartan-schema';
    
    // Schemas should be defined with 'as const', for typechecking.
    const personSchema = {
      schema: {
        name: {
          first: 'string',
          middle: ['optional', 'string'],
          last: 'string'
        },
        age: 'integer'
      }
    } as const;
    
    const isPerson = matchesSchema(personSchema);
    
    function loadPerson(json: string) {
      const data = JSON.parse(json);
      if (!isPerson(data)) {
        throw new Error("JSON data does not match schema");
      }
    
      // The type of `data` is now:
      //
      // { name: { first: string, middle?: string, last: string }, age: number }
      //
      // This type was derived from `personSchema`!
    
      console.log(`Hello, ${data.name.first} ${data.name.last}!`);
    }

Usage

You can install the package with npm i @danifoldi/spartan-schema.

import {
  Schema,
  matchesSchema
} from 'spartan-schema';

The Schema Language

The Root Object

The root of a Spartan Schema is an object. This object must contain a "schema" property, and may optionally contain "spartan" and "let" properties. Other properties are allowed, and will be ignored.

  • "schema": The schema itself. A single schema type.
  • "let": An object whose values are schema types. Its properties are defined as reference types, which can be accessed with the "ref" directive type.
    • For example, { "let": { "Foo": "string" }, "schema": ["ref", "Foo"] } is equivalent to { "schema": "string" }.
  • "spartan": The Spartan Schema major version of this schema. If present, it must be 1.

Schema Types

  • Primitive types: "string", "integer", "float", "number", "binary", "date", "boolean", null.
    • "float" is an alias for "number".
    • "null" can also be written as the literal value null.
    • `"string(min,max)" is a string with length at least min, and at most max (inclusive).
    • `"number(min,max)" is a number greater than or equal to min, and less than or equal to max.
    • `"integer(min,max)" is an integer greater than or equal to min, and less than or equal to max.
    • `"float(min,max)" is a float greater than or equal to min, and less than or equal to max.
  • Object type: An object whose keys are schema types. Matches an object with all of the included keys, if those keys' values match their schema types.
    • Unspecified keys are allowed, and will not be checked.
    • Keys are required by default. To make a key optional, use the directive type "optional": { "optionalKey": ["optional", <value type>] }
  • Directive types: Arrays whose first element is a string. The string is the name of the directive, and the rest of the array is the directive's arguments.
    • "enum" takes an argument list of primitive values (strings, numbers, true, false, null) and matches only those exact values.
    • "oneof" takes an argument list of schema types and matches anything that matches at least one of those types.
    • "tuple" takes an argument list of schema types and matches an array with that exact length, with each element matching the argument at the same index.
    • "array" takes an argument list of schema types.
      • If it has one argument, it matches an array of any length whose elements all match that argument.
      • If it has more than one argument, it behaves like "tuple" with a variable-length suffix: given N arguments, "array" matches an array with at least N - 1 elements, where each of these elements matches the argument of the same index, followed by 0 or more additional elements which match the last argument.
    • "dictionary" takes one schema type argument, and matches an object whose values all match this argument.
    • "ref" takes one string argument. Its argument must be a key in the root object's "let" property. A "ref" is substituted with the value of the "let" property that it names.
      • Recursion is allowed, and "ref"s can be used inside of "let" to create infinite types.
    • "optional" is only allowed as a value of an object type. It takes one schema type argument. It makes its key in the object type optional, with its argument as the value type.

Comparison to JSON Schema

Spartan Schema is much less verbose than JSON Schema, but has more limited features.

(Examples taken from https://json-schema.org/learn/miscellaneous-examples.html)

{
  "$id": "https://example.com/person.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "title": "Person",
  "type": "object",
  "properties": {
    "firstName": {
      "type": "string",
      "description": "The person's first name."
    },
    "lastName": {
      "type": "string",
      "description": "The person's last name."
    },
    "age": {
      "description": "Age in years.",
      "type": "integer",
      "minimum": 0
    }
  }
}
{
  "schema": {
    "firstName": "string",
    "lastName": "string",
    "age": "integer"
  }
}

This schema is much shorter, but does not include names, URLs, or field descriptions, and cannot specify a minimum for age.

{
  "$id": "https://example.com/arrays.schema.json",
  "$schema": "https://json-schema.org/draft/2020-12/schema",
  "type": "object",
  "properties": {
    "fruits": {
      "type": "array",
      "items": {
        "type": "string"
      }
    },
    "vegetables": {
      "type": "array",
      "items": { "$ref": "#/$defs/veggie" }
    }
  },
  "$defs": {
    "veggie": {
      "type": "object",
      "required": [ "veggieName", "veggieLike" ],
      "properties": {
        "veggieName": {
          "type": "string",
          "description": "The name of the vegetable."
        },
        "veggieLike": {
          "type": "boolean",
          "description": "Do I like this vegetable?"
        }
      }
    }
  }
}
{
  "let": {
    "Veggie": {
      "veggieName": "string",
      "veggieLike": "boolean"
    }
  },
  "schema": {
    "fruits": ["array", "string"],
    "vegetables": ["array", ["ref", "Veggie"]]
  }
}

Spartan Schema supports references, using "let" and "ref". All fields are required unless marked "optional".

API

Spartan Schema defines only a few functions that operate on schema objects. A schema object is made up of plain JavaScript objects and arrays that match the Spartan Schema spec.

type Schema

The type of valid Spartan Schemas.

When writing schemas directly in Typescript code, you should not use this type; instead, use as const and let Typescript infer the exact type of the schema.

type MatchesSchema<S extends Schema>

Given a type S that describes the exact shape of a Schema, MatchesSchema<S> is the type of values that match that schema.

For example, MatchesSchema<{ schema: { foo: "string" } }> is { foo: string }.

MatchesSchema is a complex recursive type, and can easily cause the Typescript compiler to fail with a "Type instantiation is excessively deep and possibly infinite" error. It should only be used on schema types that are 100% statically known.

type PathArray

type PathArray = readonly (string | number)[]

A path to a specific location in a JSON document.

function isSchema(schema, errors?)

A type predicate that checks whether schema is a valid Spartan Schema.

errors is a mutable array of { message, location } pairs; if it is present and isSchema returns false, it will be populated with a list of parsing errors.

function matchesSchema(schema)(value)

A curried function that checks whether value matches schema and returns a boolean.

If schema is statically known at typechecking type (defined with as const), then the function returned by matchesSchema(schema) will be a type predicate.

function zeroValue(schema)

Returns the zero value of this schema's root type.

| Type | Zero value | | -------------- | --------------------------------------------- | | null | null | | boolean | false | | integer, float | 0 | | string | "" | | binary | 0-length Uint8Array | | date | new Date(0) (Jan 1, 1970) | | object | object populated with properties' zero values | | oneof | zero value of first type | | enum | first enum value | | array | [] | | tuple | array populated with elements' zero values | | dictionary | {} |

This function typechecks the schema it receives. If it is passed a known schema type S (defined as const in a Typescript file), then its return type will be MatchesSchema<S>.

May throw an exception if the schema type is infinitely recursive.

License

Copyright © 2021-2022 Adam Nelson Portions Copyright © 2022 Dániel Földi

Spartan Schema is distributed under the Blue Oak Model License. It is a MIT/BSD-style license, but with some clarifying improvements around patents, attribution, and multiple contributors.