Skip to content

Commit

Permalink
feat(typegen): also search for queries in app and sanity folders (#6475)
Browse files Browse the repository at this point in the history
* feat(typegen): also search for queries in app and sanity folders

* feat(typegen): format generated types with prettier
  • Loading branch information
sgulseth authored and rexxars committed Apr 26, 2024
1 parent f6af636 commit 03cbb12
Show file tree
Hide file tree
Showing 7 changed files with 117 additions and 15 deletions.
2 changes: 1 addition & 1 deletion packages/@sanity/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@
"groq-js": "^1.7.0",
"node-machine-id": "^1.1.12",
"pkg-dir": "^5.0.0",
"prettier": "^3.2.5",
"semver": "^7.3.5",
"silver-fleece": "1.1.0",
"validate-npm-package-name": "^3.0.0"
Expand Down Expand Up @@ -120,7 +121,6 @@
"p-filter": "^2.1.0",
"p-timeout": "^4.0.0",
"preferred-pm": "^3.0.3",
"prettier": "^3.2.5",
"promise-props-recursive": "^2.0.2",
"recast": "^0.23.6",
"resolve-from": "^5.0.0",
Expand Down
15 changes: 11 additions & 4 deletions packages/@sanity/cli/src/actions/typegen/generateAction.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {dirname, join} from 'node:path'
import {Worker} from 'node:worker_threads'

import {readConfig} from '@sanity/codegen'
import prettier from 'prettier'

import {type CliCommandArguments, type CliCommandContext} from '../../types'
import {getCliWorkerPath} from '../../util/cliWorker'
Expand Down Expand Up @@ -56,6 +57,15 @@ export default async function typegenGenerateAction(
}
throw err
}

const outputPath = join(process.cwd(), codegenConfig.generates)
const outputDir = dirname(outputPath)
await mkdir(outputDir, {recursive: true})

const prettierConfig = await prettier.resolveConfig(outputPath).catch((err) => {
output.warn(`Failed to load prettier config: ${err.message}`)
return null
})
const workerPath = await getCliWorkerPath('typegenGenerate')

const spinner = output.spinner({}).start('Generating types')
Expand All @@ -65,15 +75,12 @@ export default async function typegenGenerateAction(
workDir,
schemaPath: codegenConfig.schema,
searchPath: codegenConfig.path,
prettierConfig,
} satisfies TypegenGenerateTypesWorkerData,
// eslint-disable-next-line no-process-env
env: process.env,
})

const outputPath = join(process.cwd(), codegenConfig.generates)
const outputDir = dirname(outputPath)
await mkdir(outputDir, {recursive: true})

const typeFile = await open(
outputPath,
// eslint-disable-next-line no-bitwise
Expand Down
32 changes: 27 additions & 5 deletions packages/@sanity/cli/src/workers/typegenGenerate.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,17 @@ import {
} from '@sanity/codegen'
import createDebug from 'debug'
import {typeEvaluate, type TypeNode} from 'groq-js'
import {format as prettierFormat, type Options as PrettierOptions} from 'prettier'

const $info = createDebug('sanity:codegen:generate:info')
const $warn = createDebug('sanity:codegen:generate:warn')

export interface TypegenGenerateTypesWorkerData {
workDir: string
workspaceName?: string
schemaPath: string
searchPath: string | string[]
prettierConfig: PrettierOptions | null
}

export type TypegenGenerateTypesWorkerMessage =
Expand Down Expand Up @@ -57,14 +60,30 @@ const opts = _workerData as TypegenGenerateTypesWorkerData

registerBabel()

function maybeFormatCode(code: string, prettierConfig: PrettierOptions | null): Promise<string> {
if (!prettierConfig) {
return Promise.resolve(code)
}

try {
return prettierFormat(code, {
...prettierConfig,
parser: 'typescript' as const,
})
} catch (err) {
$warn(`Error formatting: ${err.message}`)
}
return Promise.resolve(code)
}

async function main() {
const schema = await readSchema(opts.schemaPath)

const typeGenerator = new TypeGenerator(schema)
const schemaTypes = [
typeGenerator.generateSchemaTypes(),
TypeGenerator.generateKnownTypes(),
].join('\n')
const schemaTypes = await maybeFormatCode(
[typeGenerator.generateSchemaTypes(), TypeGenerator.generateKnownTypes()].join('\n'),
opts.prettierConfig,
)
const resolver = getResolver()

parentPort?.postMessage({
Expand Down Expand Up @@ -103,7 +122,10 @@ async function main() {
const ast = safeParseQuery(query)
const queryTypes = typeEvaluate(ast, schema)

const type = typeGenerator.generateTypeNodeTypes(`${queryName}Result`, queryTypes)
const type = await maybeFormatCode(
typeGenerator.generateTypeNodeTypes(`${queryName}Result`, queryTypes),
opts.prettierConfig,
)

const queryTypeStats = walkAndCountQueryTypeNodeStats(queryTypes)
fileQueryTypes.push({
Expand Down
44 changes: 44 additions & 0 deletions packages/@sanity/cli/test/__snapshots__/typegen.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`CLI: \`sanity typegen\` sanity typegen generate: formats code 1`] = `
"/**
* ---------------------------------------------------------------------------------
* This file has been generated by Sanity TypeGen.
* Command: \`sanity typegen generate\`
*
* Any modifications made directly to this file will be overwritten the next time
* the TypeScript definitions are generated. Please make changes to the Sanity
* schema definitions and/or GROQ queries if you need to update these types.
*
* For more information on how to use Sanity TypeGen, visit the official documentation:
* https://www.sanity.io/docs/sanity-typegen
* ---------------------------------------------------------------------------------
*/
// Source: schema.json
export type Person = {
_id: string;
_type: 'person';
_createdAt: string;
_updatedAt: string;
_rev: string;
name?: string;
slug?: Slug;
};
export type Slug = {
_type: 'slug';
current?: string;
source?: string;
};
export declare const internalGroqTypeReferenceTo: unique symbol;
// Source: ./src/queries.ts
// Variable: PAGE_QUERY
// Query: *[_type == \\"page\\" && slug.current == $slug][0]
export type PAGE_QUERYResult = null;
"
`;
24 changes: 23 additions & 1 deletion packages/@sanity/cli/test/typegen.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
import {readFile, writeFile} from 'node:fs/promises'

import {expect, test} from '@jest/globals'

import {describeCliTest} from './shared/describe'
import {runSanityCmdCommand} from './shared/environment'
import {runSanityCmdCommand, studiosPath} from './shared/environment'

describeCliTest('CLI: `sanity typegen`', () => {
test('sanity typegen generate: missing schema, default path', async () => {
Expand Down Expand Up @@ -47,4 +49,24 @@ describeCliTest('CLI: `sanity typegen`', () => {
'Generated TypeScript types for 2 schema types and 1 GROQ queries in 1 file',
)
})

test('sanity typegen generate: formats code', async () => {
// Write a prettier config to the output folder, with single quotes. The defeault is double quotes.
await writeFile(`${studiosPath}/v3/out/.prettierrc`, '{\n "singleQuote": true\n}\n')
const result = await runSanityCmdCommand('v3', [
'typegen',
'generate',
'--config-path',
'working-typegen.json',
])

expect(result.code).toBe(0)
expect(result.stderr).toContain(
'Generated TypeScript types for 2 schema types and 1 GROQ queries in 1 file',
)

const types = await readFile(`${studiosPath}/v3/out/types.ts`)
expect(types.toString()).toContain(`'person'`)
expect(types.toString()).toMatchSnapshot()
})
})
9 changes: 8 additions & 1 deletion packages/@sanity/codegen/src/readConfig.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,14 @@ import * as json5 from 'json5'
import * as z from 'zod'

export const configDefintion = z.object({
path: z.string().or(z.array(z.string())).default('./src/**/*.{ts,tsx,js,jsx,mjs,cjs}'),
path: z
.string()
.or(z.array(z.string()))
.default([
'./src/**/*.{ts,tsx,js,jsx,mjs,cjs}',
'./app/**/*.{ts,tsx,js,jsx,mjs,cjs}',
'./sanity/**/*.{ts,tsx,js,jsx,mjs,cjs}',
]),
schema: z.string().default('./schema.json'),
generates: z.string().default('./sanity.types.ts'),
})
Expand Down
6 changes: 3 additions & 3 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 03cbb12

Please sign in to comment.