Skip to content

A schema first GROQ query generator with custom type resolver.

Notifications You must be signed in to change notification settings

niklas-may/sanity-generator

Repository files navigation

Test and Publish npm

Sanity Generator

Sanity Generator aims to simplify the process of defining schemas and queries when working with Sanity CMS.

It is built on the premise, that for most use cases, the shape of your query can be very similar to the shape of your document schema. Moreover, it assumes that if you need to reshape a specific field type, you probably would like to do this on all occurrences of that type throughout all queries.

Certainly, this can be done with simple exporting, importing, and composing of template literals. But this is quite repetitive and error-prone. Sanity Generator is a CLI tool that aims to automate this while still providing all the flexiblities of GROQ.

Disclaimer: This is still Beta. Use with caution

Basic Usage

Install from npm:

npm install --save-dev sanity-generator 

or

yarn add --dev sanity-generator 

Create a config file:

npx sanity-generator init

Customize the config:

// sanity-generator.config.ts
export default createConfig({
  schemas: {
    // All sanity document schemas you want to query go here.
    // The object key is for later referencing.
    page: pageSchema,
  },
  resolvers: {
    // All field types you want to apply a custom GROQ query go here.
    // The object key must match a field type.
    localeString: (name: string) => /* groq */ `
      "${name}": coalesce(${name}[$lang], ${name}.en)
    `,
  },
  queries: {
    // Every property in here will be exported as a GROQ query. 
    // The function receives a single argument that is an object with 
    // all processed schemas. Here you can get the projection with 
    // all resolvers applied, and for convenience also the schema name.
    getPages: ({ schemas }) => /* groq */ `
        *[_type == "${schemas.page.name}"] {
          ${schemas.page.projection}
        }
      `,
  },
});

Write the queries and resolver to disk:

npx sanity-generator generate

Filehandling and Limitations

Sanity Generator uses ts-node and if present the tsconfig.json from the present working directory to transpile all of you configs TypeScript dependencies. However, this might not be enough if your schemas depend on files that need a special loader like CSS files. For these scenarios you might need to transpile the schemas before using them with the generator.

Programatic Use

For szenarios as described before or more custom implementation, you can import the core functions into your node.js app.

import { createConfig, generate } from "sanity-generator";

const config = createConfig({
  // ...config
})

generate(...config)

How it works

Sanity Generator simply traverses all branches of the document schema. If a branch holds no types that have a corresponding resolver, it uses the spread operator (...). If a branch holds a type that should be resolved differently, it writes the corresponding projections just as far as needed.

Here is an example with the same query, without and with a custom resolver. (Both with option inlineResolver: true)

// Generated query with no resolver
export const getPages = /* groq */ `
*[_type == "page"] {
    ...
}
`
// Same query, with resolver
export const getPages = /* groq */  `
*[_type == "page"] {
  ...,
  "seoTitle": coalesce(seoTitle[$lang], seoTitle.en),
  sections[] {
    ...,
    slides[] {
      ...,
      "title": coalesce(title[$lang], title.en)
    }
  }
}
`

Options

CLI

npx sanity-generator

or

npx sg
Command Option Description
generate Run the generator assuming the config is here: ~/sanity-generator.config.ts
generate --config -c Specify a path to the config file
init Create a default config

Config

The module exports a createConfig function to provide better type support for the configuration object.

Property Default Description
schemas {} See basic usage
resolvers {} See basic usage
queries {} See basic usage
outPath './sanity-generator` Path to the destination folder for the queries
inlineResolvers false By default, resolvers are imported as a function into the final query. Setting this to false, will inline the resolvers as a string into the query.

ToDos

  • Example for programatic use in monorepo (PRs welcome)

Roadmap

  • Auto type generation for the queries.
  • Local resolvers for inline objects (objects that are not imported directly to the schema)