Skip to content

Commit

Permalink
types(groq-builder): added ts-simplify-sanity-schema`
Browse files Browse the repository at this point in the history
  • Loading branch information
scottrippey committed Oct 5, 2023
1 parent 934e5b1 commit b5a855c
Show file tree
Hide file tree
Showing 3 changed files with 81 additions and 48 deletions.
27 changes: 27 additions & 0 deletions packages/ts-simplify/bin/ts-simplify-sanity-schema.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { compileTypes, simplifyTypes } from "../src/simplify-types";
import { unindent } from "../src/utils/unindent";

declare const process: { argv: string[] };
const [_, __, sanityConfig, outputFile] = process.argv;
const outputText = compileSanityTypes({ sanityConfigFile: sanityConfig });
console.log(outputText);

function compileSanityTypes(config: { sanityConfigFile: string }) {
return compileTypes({
sourceFile: config.sanityConfigFile,
transform({}) {
return unindent(`
import sanityConfig from './${config.sanityConfigFile}';
import { InferSchemaValues } from '@sanity-typed/types';
type SimplifyDeep<T> = T extends object
? T extends infer O
? { [K in keyof O]: SimplifyDeep<O[K]> }
: never
: T;
export type SanitySchema = SimplifyDeep<InferSchemaValues<typeof sanityConfig>>;
`);
},
});
}
97 changes: 49 additions & 48 deletions packages/ts-simplify/src/simplify-types.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import debug from "debug";
import { Project, TypeFormatFlags } from "ts-morph";
import { Project, SourceFile, TypeAliasDeclaration, TypeFormatFlags } from "ts-morph";
import { unindent } from "./utils/unindent";

namespace logger {
const base = debug("ts-simplify");
Expand All @@ -9,6 +10,40 @@ namespace logger {
}

export function simplifyTypes(config: { sourceFile: string }) {
return compileTypes({
sourceFile: config.sourceFile,
transform({ sourceFile }) {
const sourceTypes = sourceFile.getTypeAliases().filter((t) => t.isExported());

logger.info(`Source file exports ${sourceTypes.length} types: ${sourceTypes.map((t) => t.getName()).join(", ")}`);

return unindent(`
import * as SOURCES from './${config.sourceFile}';
type SimplifyDeep<T> = T extends object
? T extends infer O
? { [K in keyof O]: SimplifyDeep<O[K]> }
: never
: T;
${sourceTypes
.map((type) => {
const name = type.getName();
return unindent(`
export type ${name} = SimplifyDeep<SOURCES.${name}>;
`);
})
.join("")}
`);
},
});
}

export type CompileConfig = {
sourceFile: string;
transform: (info: { sourceFile: SourceFile }) => string;
};
export function compileTypes(config: CompileConfig) {
const project = new Project({
tsConfigFilePath: "tsconfig.json",
skipAddingFilesFromTsConfig: true,
Expand All @@ -17,52 +52,25 @@ export function simplifyTypes(config: { sourceFile: string }) {

const sourceFile = project.addSourceFileAtPath(config.sourceFile);

const sourceTypes = sourceFile.getTypeAliases().filter((type) => type.isExported());

logger.info(`Source file exports ${sourceTypes.length} types: ${sourceTypes.map((t) => t.getName()).join(", ")}`);

const simplifiedFile = project.createSourceFile(
"./virtual/simplified.ts",
unindent(`
import * as SOURCES from '../${config.sourceFile}';
const transformedText = config.transform({ sourceFile });
const transformedFile = project.createSourceFile("./transformed.ts", transformedText);
const outputFile = project.createSourceFile("./output.ts");

type SimplifyDeep<T> = T extends object
? T extends infer O
? { [K in keyof O]: SimplifyDeep<O[K]> }
: never
: T;
${sourceTypes
.map((type) => {
const name = type.getName();
return unindent(`
export type ${name} = SimplifyDeep<SOURCES.${name}>;
`);
})
.join("")}
`)
);

const outputFile = project.createSourceFile(
"./virtual/output.ts",
`
// Generated by ts-simplify
`,
{ overwrite: true }
const transformedTypes = transformedFile.getTypeAliases().filter((type) => type.isExported());
logger.info(
`Creating ${transformedTypes.length} output types: ${transformedTypes.map((t) => t.getName()).join(", ")}`
);

const simplifiedTypes = simplifiedFile.getTypeAliases().filter((type) => type.isExported());
for (const simplifiedType of simplifiedTypes) {
const expandedType = simplifiedType
for (const transformedType of transformedTypes) {
const compiledType = transformedType
.getType()
.getText(undefined, TypeFormatFlags.UseAliasDefinedOutsideCurrentScope | TypeFormatFlags.NoTruncation);

outputFile.addTypeAlias({
name: simplifiedType.getName(),
isExported: simplifiedType.isExported(),
isDefaultExport: simplifiedType.isDefaultExport(),
hasDeclareKeyword: simplifiedType.hasDeclareKeyword(),
type: expandedType,
name: transformedType.getName(),
isExported: transformedType.isExported(),
isDefaultExport: transformedType.isDefaultExport(),
hasDeclareKeyword: transformedType.hasDeclareKeyword(),
type: compiledType,
});
}

Expand All @@ -71,12 +79,5 @@ export function simplifyTypes(config: { sourceFile: string }) {
// Original source: ${config.sourceFile}
${outputFile.getText()}
`);

return outputText;
}

function unindent(str: string) {
const lines = str.split("\n");
const indent = lines[1].match(/^\s*/)![0];
return lines.map((line) => line.replace(indent, "")).join("\n");
}
5 changes: 5 additions & 0 deletions packages/ts-simplify/src/utils/unindent.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
export function unindent(str: string) {
const lines = str.split("\n");
const indent = lines[1].match(/^\s*/)![0];
return lines.map((line) => line.replace(indent, "")).join("\n");
}

0 comments on commit b5a855c

Please sign in to comment.