Skip to content
This repository has been archived by the owner on Mar 26, 2024. It is now read-only.

Commit

Permalink
refactor: cli improvements; updated docs (#278)
Browse files Browse the repository at this point in the history
Co-authored-by: Rico Kahler <[email protected]>
  • Loading branch information
ricokahler and Rico Kahler authored Jan 20, 2023
1 parent c1ead4f commit 7135904
Show file tree
Hide file tree
Showing 17 changed files with 219 additions and 192 deletions.
144 changes: 65 additions & 79 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,110 +23,96 @@ yarn add --dev sanity-codegen@alpha
At the root of your sanity project, run:

```
npx sanity-codegen extractor
npx sanity-codegen codegen
```

This command will locate your schema, generate TypeScript types, and write them to `schema.d.ts`.
This command will locate your schema, generate TypeScript types, and write them to `sanity-codegen.d.ts`.

[You can also create a configuration file and see other options here.](./packages/cli)

### Using the types
## Type usage

In the project that will use the types, install the package `@sanity-codegen/types@alpha`
### Schema types

```
npm i --save-dev @sanity-codegen/types@alpha
The `sanity-codegen.d.ts` file that was generated will add ambient types to your project. Access them via `Sanity.Schema.YourType`

```js
interface Props {
book: Sanity.Schema.Book; // no import needed. just use it
}

function yourFunction({ book }: Props) {
//
}
```

or
### Query types

First install the typed client:

```
yarn add --dev @sanity-codegen/types@alpha
npm i @sanity-codegen/client
```

From there, include the types file generated from the CLI at the root of your repo. This will create ambient types that you can use in any file without importing them.
#### Configure the client

### Schema Codegen Options
After that's done, you can create your configured client file.

If you want your type to be marked as required instead of optional, add `codegen: { required: true }` to your schema fields:
In a file called, `client.ts`, import your favorite Sanity client (both [`@sanity/client`](https://www.sanity.io/docs/js-client) and [`picosanity`](https://github.com/rexxars/picosanity) will work).

```ts
export default {
name: 'myDocument',
type: 'document',
fields: [
{
name: 'aRequiredField',
type: 'string',
// 👇👇👇
codegen: { required: true },
validation: (Rule) => Rule.required(),
// 👆👆👆
},
],
};
```
// client.ts

This will tell the codegen to remove the optional `?` modifier on the field.
import SanityClient from '@sanity/client';
// or use the smaller `picosanity` client
// import SanityClient from 'picosanity';

> **NOTE:** Drafts that are run through the document may have incorrect types. Be aware of this when using preview mode.
import { wrapClient, groq } from '@sanity-codegen/client';

## Usage with first-party client (`@sanity/codegen`)
// 1. configure your favorite sanity client
const sanityClient = new SanityClient({
// ...
});

For more stable usage, you can use the generated types with the first party javascript client [`@sanity/client`](https://www.sanity.io/docs/js-client) (or the tiny alternative [`picosanity`](https://github.com/rexxars/picosanity)).
// 2. wrap that client with `wrapClient`. this will return a configure function
const configureClient = wrapClient(picoSanity);

Query for documents like normal but use the generated types to create the correct type for your query.
// 3. call this configure function passing in the type argument
// `Sanity.Query.Map` from the GROQ codegen output.
const sanity = configureClient<Sanity.Query.Map>();

```ts
import sanityClient from '@sanity/client';
import groq from 'groq';

const client = sanityClient({
projectId: 'your-project-id',
dataset: 'bikeshop',
token: 'sanity-auth-token', // or leave blank to be anonymous user
useCdn: true, // `false` if you want to ensure fresh data
});
export { sanity, groq };
```

// Step 1: write a query
const query = groq`
*[_type == 'blogPost'] {
// pick the title
title,
// then a full expansion of the author
author -> { ... },
}
`;

// Step 2: create a type for your query's result composed from the codegen types.
//
// Refer to Typescript's utility types for useful type helpers:
// https://www.typescriptlang.org/docs/handbook/utility-types.html#picktype-keys
//
// And also intersections:
// https://www.typescriptlang.org/docs/handbook/unions-and-intersections.html#intersection-types
type QueryResult = Array<
Omit<Pick<Sanity.Schema.BlogPost, 'title'>, 'author'> & {
author: Sanity.Schema.Author;
}
>;

async function main() {
// Step 3: add the `QueryResult` as the type parameter as well as the query
const results = await client.fetch<QueryResult>(query);

const first = results[0];

console.log(first.title); // "Title"
console.log(first.author); // { name: 'Example', bio: '...' }
#### Using the typed client

```ts
// some-example.ts

// 1. import the client configured from the previous step
import { sanity, groq } from '../client';

export async function someFunction() {
// 1. use the added `query` method.
// pass in a _query key_ followed by a template
// literal with the `groq` tag
const bookAuthors = await sanity.query(
'BookAuthors',
groq`
*[_type == 'books'].author
`,
);

// 2. ensure the codegen re-runs.
// this is easiest via the CLI

// 3. that's it. `bookAuthors` is now typed
return bookAuthors;
}

main().catch((e) => {
console.error(e);
process.exit(1);
});
// Extra note: if ever need to reference the type of a query again,
// you can do so via `Sanity.Query.{QueryKey}`
type ExampleType = Sanity.Query.BookAuthors;
```

## API/Programatic Usage

[See the `@sanity-codegen/extractor` package.](./packages/extractor)
Note: you'll have to re-run the codegen every time you update your schema or your queries.
21 changes: 13 additions & 8 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,21 +26,21 @@ const config: SanityCodegenConfig = {
* function that returns a list of paths to specify the source files you want
* to generate types from.
*
* If `groqCodegenInclude` is provided as a function then `groqCodegenExclude`
* If `include` is provided as a function then `exclude`
* will not be used.
*/
groqCodegenInclude: ['./src/**/*.{js,jsx,ts,tsx}'],
// include: ['./src/**/*.{js,jsx,ts,tsx}'],
/**
* Specify a glob (powered by
* [`globby`](https://github.com/sindresorhus/globby)) or a list of globs to
* specify which source files you want to exclude from type generation.
*/
groqCodegenExclude: ['**/*.test.{js,ts,tsx}', '**/node_modules'],
// exclude: ['**/*.test.{js,ts,tsx}', '**/node_modules'],
/**
* Optionally provide a destination path to the resulting sanity groq types.
* The default value is `query-types.d.ts`.
*/
// typesOutputPath: './query-types.d.ts',
// output: './query-types.d.ts',
/**
* Optionally provide a path to a .babelrc file. This will be passed into the
* babel options of the schema executor.
Expand Down Expand Up @@ -98,14 +98,16 @@ export default config;
```

<!-- toc -->
* [@sanity-codegen/cli](#sanity-codegencli)
* [Usage](#usage)
* [Commands](#commands)

- [@sanity-codegen/cli](#sanity-codegencli)
- [Usage](#usage)
- [Commands](#commands)
<!-- tocstop -->

# Usage

<!-- usage -->

```sh-session
$ npm install -g @sanity-codegen/cli
$ sanity-codegen COMMAND
Expand All @@ -117,12 +119,14 @@ USAGE
$ sanity-codegen COMMAND
...
```

<!-- usagestop -->

# Commands

<!-- commands -->
* [`sanity-codegen help [COMMAND]`](#sanity-codegen-help-command)

- [`sanity-codegen help [COMMAND]`](#sanity-codegen-help-command)

## `sanity-codegen help [COMMAND]`

Expand All @@ -140,4 +144,5 @@ OPTIONS
```

_See code: [@oclif/plugin-help](https://github.com/oclif/plugin-help/blob/v3.2.18/src/commands/help.ts)_

<!-- commandsstop -->
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ const config: SanityCodegenConfig = {
],
},
]),
groqCodegenInclude: '**/*.{js,ts,tsx}',
include: '**/*.{js,ts,tsx}',
};

export default config;
14 changes: 8 additions & 6 deletions packages/cli/src/commands/codegen.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,15 +38,17 @@ describe('codegen command', () => {
.map((message: string) => message.replace(/:\s[\w/\\.-]+/g, ' <PATH>')),
).toMatchInlineSnapshot(`
[
"Starting codegen…",
"Using sanity-codegen config found at <PATH>",
"Generating types from your schema…",
"Converted 1 schema definition to TypeScript",
"Converting queries to typescript…",
"Plucking queries from files…",
"Finding files to extract queries from…",
"Found 2 candidate files from \`groqCodegenInclude\` and \`groqCodegenExclude\`",
"Found 2 candidate files",
"Extracting queries… 50% (1/2)",
"Extracting queries… 100% (2/2)",
"Found 1 query from 2 files.",
"Converting queries to typescript…",
"Converted 2 queries to TypeScript",
"Writing query types output…",
"Wrote query types output to <PATH>",
Expand All @@ -73,13 +75,13 @@ describe('codegen command', () => {
}
namespace Sanity.Query {
type QueryKey = (string | null)[];
}
namespace Sanity.Query {
type QueryKeys = {
type Map = {
QueryKey: Sanity.Query.QueryKey;
};
}
namespace Sanity.Query {
type QueryKey = (string | null)[];
}
",
]
`);
Expand Down
Loading

1 comment on commit 7135904

@vercel
Copy link

@vercel vercel bot commented on 7135904 Jan 20, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.