0.1.3 • Published 3 years ago

sanity-schema-builder v0.1.3

Weekly downloads
-
License
MIT
Repository
github
Last release
3 years ago

Sanity Schema Builder lets you write schema programmatically. You can use it for defining specific fields within your existing schema, or for generating entire document definitions. It's like the official Structure Builder, but for schema.

Writing complex schema can often involve a lot of repetition. The Sanity Schema Builder API exposes convenient methods that allow you to quickly define documents, fields, block text, previews, orderings, et al. It's written in TypeScript, so you can benefit from automatic suggestions as you write.

TL;DR

Do this...

import { SchemaBuilder } from 'sanity-schema-builder';
import { OkHandIcon } from '@sanity/icons';
const S = new SchemaBuilder();

export default S.doc('person')
  .icon(OkHandIcon)
  .fields([S.str('firstName'), S.str('lastName'), S.num('age')])
  .generate();

Instead of this...

import { OkHandIcon } from '@sanity/icons';

export default {
  type: 'document',
  name: 'person',
  title: 'Person',
  icon: OkHandIcon,
  fields: [
    {
      type: 'string',
      name: 'firstName',
      title: 'First Name',
    },
    {
      type: 'string',
      name: 'lastName',
      title: 'Last Name',
    },
    {
      type: 'number',
      name: 'age',
      title: 'Age',
    },
  ],
};

Install

$ npm i sanity-schema-builder # or yarn add sanity-schema-builder

Usage

import { SchemaBuilder } from 'sanity-schema-builder';

const S = new SchemaBuilder();

export default S.document('person')
  /* Go wild here */
  .generate();

Detailed example

The SchemaBuilder class aims to make it slightly easier for you to write your schema. It offers chainable and nestable methods as shorthand alternatives to defining longer form schema objects. Each time you would normally define a new object, you can instead use a method.

Below is an example of a document schema with multiple fields of different types, each with their own properties and options, as well as a custom preview and orderings. Of course there are many more methods available, see the "Available Schema Types" section.

const document = S.document('person') // Create a new document
  .fields([ // Add some fields to the document
    S.string('firstName'), // A basic string with the name 'firstName'. A title of 'First Name' will be generated.
    S.string('lastName', 'Family Name'), // Define the title explicitly
    S.str('nickname') // Use the "str" shorthand alias
      .title('Also known as...'),  // Set the title using a method
    S.number('age')
      .description('Will be kept secret.'), // Add a description (a generic field property)
    S.geopoint('location')
      .readOnly()
      .hidden(), // Chain multiple properties
    S.array('pets').of([ // Create an array of objects
      S.object('pet').fields([ // Each object may have an array of fields
        S.string('species')
          .list(['Dog', 'Cat', 'Axolotl']) // Add a field specific option
          .layout('radio'), // Chain multiple options
        S.image('photo')
          .options({ hotspot: true, storeOriginalFilename: true }), // Set options explicitly
      ]),
    ]),
    S.reference('memberOf')
      .to(['team', 'group']) // Define an array of references
      .add('department'), // Or add references individually
    S.field('table', 'measurements'), // Define a custom field of type 'table'
    S.slug('handle')
      .validation(Rule => Rule.required()), // Use validation
  ])
  .icon(SomeImportedIcon) // Define an icon used by the studio for this document type
  .preview(
    S.preview() // Use a nested preview method
      .select('firstName').select('lastName').select('alias', 'nickname') // Chain selections
      .prepare((selection) => ({ // Use a prepare function
        title: `${firstName} ${lastName}`,
        subtitle: selection.alias,
      }));
  )
  .orderings([ // Use an array of nested orderings
    S.ordering('age').by('age', 'desc'),
    S.ordering('name').by('lastName', 'asc').by('firstName', 'asc'), // Add multiple sorts
  ])
  .generate(); // IMPORTANT! Don't forget to actually generate the schema

You don't have to just generate documents in this way. For example, you may want to generate a reusable field:

const field = S.obj('metadata')
  .fields([
    S.str('title'),
    S.str('description'),
    S.url('canonical'),
    S.img('image'),
  ])
  .generate();

Available Schema Types

Sanity Schema Builder supports all of the standard schema types listed in the official documentation. These types are all available as methods on a SchemaBuilder class instance, as well as via their alias. e.g. S.string() or S.str().

TypeAliasDescription
arrayarrAn array of other types.
blocksAn array of block content (and other types).
booleanboolEither true or false.
dateAn ISO-8601 formatted string containing date.
datetimedtAn ISO-8601 formatted string UTC containing date and time.
documentdocThe base schema type for Sanity Studio.
fileAn object with a reference to a file asset.
geopointgeoAn object signifying a global latitude/longitude/altitude coordinate.
imageimgAn object with a reference to an image asset.
numbernumA number.
objectobjFor defining custom types that contain other fields.
referencerefA reference to another document.
slugA slug, typically for URLs.
stringstrA string, or selectable list of strings.
textA basic multi-line string.
urlA string representing a URL.

In addition, the following methods and aliases are available for more specific or nested functionality:

TypeAliasDescription
fieldfLow-level method for specifying custom field types.
fieldsetfsetFor defining fieldsets inside documents and objects.
orderingsortFor defining sort orders.
previewviewFor defining previews.
generateGenerates the schema. All schema type chains must end with this method.

Predefined fields

You can pass the schema builder predefined fields which you can then reference as strings when adding sub-fields to objects or other object-like fields. These can be generated using the Schema builder or written manually.

Predefined fields can be passed to the SchemaBuilder constructor, or added after initialization using the define method.

// Pass in via the constructor
const S = new SchemaBuilder({
  title: {
    type: 'string',
    name: 'title',
    title: 'Title',
  },
});
// Or using the define method
S.define('name', S.str('name').generate());
// Create an array of predefined fields
const someArray = S.arr().of(['title', 'name']);

Contributing

Contributions are welcome, some ideas of things to help with:

  • Specific documentation for each class method.
  • Some types could be improved, check @TODO comments in the source code.
  • Test coverage could be expanded, especially for some of the higher-order methods.

License

MIT

0.1.3

3 years ago

0.1.2

3 years ago

0.1.1

3 years ago

0.1.0

3 years ago