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

feat(v1): generate identifiers #299

Open
wants to merge 5 commits into
base: alpha
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packages/cli/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,14 @@ const config: SanityCodegenConfig = {
* prevent naming collisions.
*/
// generateTypeName: undefined,
/**
* Optionally provide a function that generates the typescript workspace
* identifier from the schema type name.
*
* Please note that this identifier is used for the generated typescript
* file, so the returned value should be a valid typescript identifier.
*/
// generateWorkspaceName: undefined,
/**
* This option is fed directly to prettier `resolveConfig`
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,17 @@ const config: SanityCodegenConfig = {
{ name: 'author', type: 'string' },
],
},
{
name: 'foo',
type: 'document',
fields: [{ name: 'myStr', type: 'string' }],
},
],
}),
],
include: '**/*.{js,ts,tsx}',
generateWorkspaceName: (name) => `Overriden${name}`,
generateTypeName: (name) => (name === 'Foo' ? 'Bar' : name),
};

export default config;
21 changes: 15 additions & 6 deletions packages/cli/src/commands/codegen.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,8 @@ describe('codegen command', () => {
[
"Starting codegen…",
"Using sanity-codegen config found at <PATH>",
"[default] Generating types for workspace \`default\`",
"[default] Converted 1 schema definition to TypeScript",
"[default] Generating types for workspace \`default\` as \`OverridenDefault\`",
"[default] Converted 2 schema definitions to TypeScript",
"[default] Plucking queries from files…",
"[default] Finding files to extract queries from…",
"[default] Found 2 candidate files",
Expand All @@ -63,15 +63,24 @@ describe('codegen command', () => {
[
"/// <reference types="@sanity-codegen/types" />

namespace Sanity.Default.Client {
namespace Sanity.OverridenDefault.Client {
type Config = {
QueryKey: Sanity.Default.Query.QueryKey;
QueryKey: Sanity.OverridenDefault.Query.QueryKey;
};
}
namespace Sanity.Default.Query {
namespace Sanity.OverridenDefault.Query {
type QueryKey = (string | null)[];
}
namespace Sanity.Default.Schema {
namespace Sanity.OverridenDefault.Schema {
type Bar =
| {
_id: string;
_type: "foo";
myStr?: string;
}
| undefined;
}
namespace Sanity.OverridenDefault.Schema {
type Book =
| {
_id: string;
Expand Down
2 changes: 2 additions & 0 deletions packages/cli/src/commands/codegen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,8 @@ export default class GroqCodegen extends Command {
babelOptions,
prettierResolveConfigOptions: config?.prettierResolveConfigOptions,
prettierResolveConfigPath: config?.prettierResolveConfigPath,
generateTypeName: config?.generateTypeName,
generateWorkspaceName: config?.generateWorkspaceName,
root,
normalizedSchemas,
logger,
Expand Down
5 changes: 2 additions & 3 deletions packages/core/src/generate-query-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,16 +13,15 @@ interface GenerateQueryTypesOptions {
* optionally override the default logger (e.g. to silence it, etc)
*/
logger?: Sanity.Codegen.Logger;
workspaceIdentifier?: string;
}

export function generateQueryTypes({
normalizedSchema,
extractedQueries,
workspaceIdentifier = defaultGenerateTypeName(normalizedSchema.name),
...options
}: GenerateQueryTypesOptions) {
// TODO: allow customizing this?
const workspaceIdentifier = defaultGenerateTypeName(normalizedSchema.name);

const { logger = simpleLogger } = options;
const queries = extractedQueries
.map(({ queryKey, query }) => {
Expand Down
15 changes: 10 additions & 5 deletions packages/core/src/generate-schema-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,17 +2,19 @@ import * as t from '@babel/types';
import { defaultGenerateTypeName } from './default-generate-type-name';
import { transformSchemaNodeToStructure } from './transform-schema-to-structure';
import { transformStructureToTs } from './transform-structure-to-ts';
import { GenerateTypesOptions } from './generate-types';

interface GenerateSchemaTypesOptions {
normalizedSchema: Sanity.SchemaDef.Schema;
workspaceIdentifier?: string;
generateTypeName?: GenerateTypesOptions['generateTypeName'];
}

export function generateSchemaTypes({
normalizedSchema,
workspaceIdentifier = defaultGenerateTypeName(normalizedSchema.name),
generateTypeName = (typeName) => typeName,
}: GenerateSchemaTypesOptions) {
// TODO: allow customizing this?
const workspaceIdentifier = defaultGenerateTypeName(normalizedSchema.name);

const topLevelSchemaNodes = [
...normalizedSchema.documents,
...normalizedSchema.registeredTypes,
Expand All @@ -24,8 +26,11 @@ export function generateSchemaTypes({
normalizedSchema,
});

// TODO: allow customizing this?
const identifier = defaultGenerateTypeName(node.name);
const identifier = generateTypeName(defaultGenerateTypeName(node.name), {
node,
nodes: topLevelSchemaNodes,
normalizedSchema,
});

const { tsType, declarations, substitutions } = transformStructureToTs({
structure,
Expand Down
60 changes: 31 additions & 29 deletions packages/core/src/generate-types.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,8 @@ describe('generateTypes', () => {
name: 'additionalWorkspace',
}),
],
generateWorkspaceName: (name) => `Overriden${name}`,
generateTypeName: (name) => (name === 'Foo' ? 'Bar' : name),
logger: {
debug: jest.fn(),
error: jest.fn(),
Expand All @@ -141,76 +143,76 @@ describe('generateTypes', () => {
expect(result).toMatchInlineSnapshot(`
"/// <reference types="@sanity-codegen/types" />

namespace Sanity.AdditionalWorkspace.Client {
namespace Sanity.OverridenAdditionalWorkspace.Client {
type Config = {
BookAuthorUsesDefaultAlias: Sanity.AdditionalWorkspace.Query.BookAuthorUsesDefaultAlias;
BookTitlesUsesDefaultExport: Sanity.AdditionalWorkspace.Query.BookTitlesUsesDefaultExport;
AllBooksUsesDefaultReexport: Sanity.AdditionalWorkspace.Query.AllBooksUsesDefaultReexport;
AllBooksUsesNamedDeclaredExport: Sanity.AdditionalWorkspace.Query.AllBooksUsesNamedDeclaredExport;
AllBooksUsesNameSpecifiedExport: Sanity.AdditionalWorkspace.Query.AllBooksUsesNameSpecifiedExport;
ImportStarExportStar: Sanity.AdditionalWorkspace.Query.ImportStarExportStar;
BookAuthorUsesDefaultAlias: Sanity.OverridenAdditionalWorkspace.Query.BookAuthorUsesDefaultAlias;
BookTitlesUsesDefaultExport: Sanity.OverridenAdditionalWorkspace.Query.BookTitlesUsesDefaultExport;
AllBooksUsesDefaultReexport: Sanity.OverridenAdditionalWorkspace.Query.AllBooksUsesDefaultReexport;
AllBooksUsesNamedDeclaredExport: Sanity.OverridenAdditionalWorkspace.Query.AllBooksUsesNamedDeclaredExport;
AllBooksUsesNameSpecifiedExport: Sanity.OverridenAdditionalWorkspace.Query.AllBooksUsesNameSpecifiedExport;
ImportStarExportStar: Sanity.OverridenAdditionalWorkspace.Query.ImportStarExportStar;
};
}
namespace Sanity.AdditionalWorkspace.Query {
namespace Sanity.OverridenAdditionalWorkspace.Query {
type AllBooksUsesDefaultReexport =
Sanity.AdditionalWorkspace.Query.BookTitlesUsesDefaultExport;
Sanity.OverridenAdditionalWorkspace.Query.BookTitlesUsesDefaultExport;
}
namespace Sanity.AdditionalWorkspace.Query {
namespace Sanity.OverridenAdditionalWorkspace.Query {
type AllBooksUsesNamedDeclaredExport = {
authorName: unknown;
title: unknown;
}[];
}
namespace Sanity.AdditionalWorkspace.Query {
namespace Sanity.OverridenAdditionalWorkspace.Query {
type AllBooksUsesNameSpecifiedExport =
Sanity.AdditionalWorkspace.Query.AllBooksUsesNamedDeclaredExport;
Sanity.OverridenAdditionalWorkspace.Query.AllBooksUsesNamedDeclaredExport;
}
namespace Sanity.AdditionalWorkspace.Query {
namespace Sanity.OverridenAdditionalWorkspace.Query {
type BookAuthorUsesDefaultAlias = unknown;
}
namespace Sanity.AdditionalWorkspace.Query {
namespace Sanity.OverridenAdditionalWorkspace.Query {
type BookTitlesUsesDefaultExport = unknown[];
}
namespace Sanity.AdditionalWorkspace.Query {
namespace Sanity.OverridenAdditionalWorkspace.Query {
type ImportStarExportStar =
Sanity.AdditionalWorkspace.Query.AllBooksUsesNamedDeclaredExport;
Sanity.OverridenAdditionalWorkspace.Query.AllBooksUsesNamedDeclaredExport;
}
namespace Sanity.AdditionalWorkspace.Schema {
type Foo =
namespace Sanity.OverridenAdditionalWorkspace.Schema {
type Bar =
| {
_id: string;
_type: "foo";
myStr?: string;
}
| undefined;
}
namespace Sanity.Default.Query {
namespace Sanity.OverridenDefault.Query {
type AllBooksUsesDefaultReexport =
Sanity.Default.Query.BookTitlesUsesDefaultExport;
Sanity.OverridenDefault.Query.BookTitlesUsesDefaultExport;
}
namespace Sanity.Default.Query {
namespace Sanity.OverridenDefault.Query {
type AllBooksUsesNamedDeclaredExport = {
authorName: string | null;
title: string | null;
}[];
}
namespace Sanity.Default.Query {
namespace Sanity.OverridenDefault.Query {
type AllBooksUsesNameSpecifiedExport =
Sanity.Default.Query.AllBooksUsesNamedDeclaredExport;
Sanity.OverridenDefault.Query.AllBooksUsesNamedDeclaredExport;
}
namespace Sanity.Default.Query {
namespace Sanity.OverridenDefault.Query {
type BookAuthorUsesDefaultAlias = {
name?: string;
} | null;
}
namespace Sanity.Default.Query {
namespace Sanity.OverridenDefault.Query {
type BookTitlesUsesDefaultExport = (string | null)[];
}
namespace Sanity.Default.Query {
namespace Sanity.OverridenDefault.Query {
type ImportStarExportStar =
Sanity.Default.Query.AllBooksUsesNamedDeclaredExport;
Sanity.OverridenDefault.Query.AllBooksUsesNamedDeclaredExport;
}
namespace Sanity.Default.Schema {
namespace Sanity.OverridenDefault.Schema {
type Blocks =
| {
_key: string;
Expand All @@ -226,7 +228,7 @@ describe('generateTypes', () => {
}[]
| undefined;
}
namespace Sanity.Default.Schema {
namespace Sanity.OverridenDefault.Schema {
type Book =
| {
_id: string;
Expand Down
53 changes: 51 additions & 2 deletions packages/core/src/generate-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import {
import { simpleLogger } from './utils';
import { generateQueryTypes } from './generate-query-types';
import { generateSchemaTypes } from './generate-schema-types';
import { defaultGenerateTypeName } from './default-generate-type-name';

const logLevels: Sanity.Codegen.LogLevel[] = [
'success',
Expand Down Expand Up @@ -42,6 +43,39 @@ export interface GenerateTypesOptions extends PluckGroqFromFilesOptions {
* workspace that mirrors another one in schema (e.g. for staging env)
*/
ignoreSchemas?: string[];

root?: string;
/**
* Function that generates the typescript type identifier from the node name.
*
* @param typeName The generated type name from the node name
*/
generateTypeName?: (
typeName: string,
context: {
normalizedSchema: Sanity.SchemaDef.Schema;
node:
| Sanity.SchemaDef.DocumentNode
| Sanity.SchemaDef.RegisteredSchemaNode;
nodes: (
| Sanity.SchemaDef.DocumentNode
| Sanity.SchemaDef.RegisteredSchemaNode
)[];
},
) => string;
/**
* Function that generates the typescript workspace identifier from the schema
* name.
*
* @param typeName The generated workspace name from the schema name
*/
generateWorkspaceName?: (
typeName: string,
context: {
normalizedSchemas: Sanity.SchemaDef.Schema[];
normalizedSchema: Sanity.SchemaDef.Schema;
},
) => string;
}

/**
Expand All @@ -56,6 +90,8 @@ export async function generateTypes({
prettierResolveConfigPath,
normalizedSchemas,
ignoreSchemas = [],
generateTypeName,
generateWorkspaceName = (typeName) => typeName,
...pluckOptions
}: GenerateTypesOptions) {
const { logger = simpleLogger } = pluckOptions;
Expand Down Expand Up @@ -83,11 +119,23 @@ export async function generateTypes({
{ ...logger },
);

const workspaceIdentifier = generateWorkspaceName(
defaultGenerateTypeName(normalizedSchema.name),
{
normalizedSchemas: filteredSchemas,
normalizedSchema,
},
);

wrappedLogger.verbose(
`Generating types for workspace \`${normalizedSchema.name}\``,
`Generating types for workspace \`${normalizedSchema.name}\` as \`${workspaceIdentifier}\``,
);

const schemaTypes = generateSchemaTypes({ normalizedSchema });
const schemaTypes = generateSchemaTypes({
normalizedSchema,
workspaceIdentifier,
generateTypeName,
});
const schemaCount = Object.keys(schemaTypes.declarations).length;

wrappedLogger[schemaCount ? 'success' : 'warn'](
Expand All @@ -114,6 +162,7 @@ export async function generateTypes({
normalizedSchema,
substitutions: schemaTypes.substitutions,
extractedQueries,
workspaceIdentifier,
});
const queryCount = Object.keys(queryTypes.declarations).length;

Expand Down