@chakra-ui/cli
Version:
Generate theme typings for autocomplete
117 lines (105 loc) • 4.48 kB
JavaScript
import { pretty } from './pretty.js';
import { capitalize, isBooleanValue, unionType } from './shared.js';
async function generateRecipe(sys, strict = true) {
const theme = sys._config.theme ?? {};
const sysRecipes = theme.recipes ?? {};
const sysSlotRecipes = theme.slotRecipes ?? {};
const recipes = Object.keys(sysRecipes).map((key) => {
const recipe = sysRecipes[key];
const variantKeyMap = sys.cva(recipe).variantMap;
const upperName = capitalize(key);
const str = `
export interface ${upperName}Variant {
${Object.keys(variantKeyMap).map((key2) => {
const def = Reflect.get(recipe.defaultVariants ?? {}, key2);
const jsDoc = def ? `/** @default ${JSON.stringify(def)} */
` : "";
const values = variantKeyMap[key2];
if (values.every(isBooleanValue)) {
return `${jsDoc}${key2}?: boolean | undefined`;
}
return `${jsDoc}${key2}?: ${unionType(values)} | undefined`;
}).join("\n")}
}
export type ${upperName}VariantProps = {
[K in keyof ${upperName}Variant]?: ConditionalValue<${upperName}Variant[K]> | undefined
}
export type ${upperName}VariantMap = {
[K in keyof ${upperName}Variant]: Array<${upperName}Variant[K]>
}
`;
return str;
});
const recipeKeys = Object.keys(sysRecipes);
const recipeRecord = `
export interface ConfigRecipes {
${recipeKeys.length ? Object.keys(sysRecipes).map((key) => {
const upperName = capitalize(key);
return `${key}: SystemRecipeFn<${upperName}VariantProps, ${upperName}VariantMap>`;
}).join("\n") : "[key: string]: SystemRecipeFn<any>"}
}
`;
const recipeResult = [recipes.join("\n"), recipeRecord].join("\n");
const slotRecipeKeys = Object.keys(sysSlotRecipes);
const slotRecipes = slotRecipeKeys.map((key) => {
const recipe = sysSlotRecipes[key];
const variantKeyMap = sys.sva(recipe).variantMap;
const upperName = capitalize(key);
const str = `
// ${upperName}
export type ${upperName}Slot = ${unionType(recipe.slots ?? [])}
export interface ${upperName}Variant {
${Object.keys(variantKeyMap).map((key2) => {
const def = Reflect.get(recipe.defaultVariants ?? {}, key2);
const jsDoc = def ? `/** @default ${JSON.stringify(def)} */
` : "";
const values = variantKeyMap[key2];
if (values.every(isBooleanValue)) {
return `${jsDoc}${key2}?: boolean | undefined`;
}
return `${jsDoc}${key2}?: ${unionType(values, !strict)} | undefined`;
}).join("\n")}
}
export type ${upperName}VariantProps = {
[K in keyof ${upperName}Variant]?: ConditionalValue<${upperName}Variant[K]> | undefined
}
export type ${upperName}VariantMap = {
[K in keyof ${upperName}Variant]: Array<${upperName}Variant[K]>
}
`;
return str;
});
const slotRecipeRecord = `
export interface ConfigSlotRecipes {
${slotRecipeKeys.length ? slotRecipeKeys.map((key) => {
const upperName = capitalize(key);
return `${key}: SystemSlotRecipeFn<${upperName}Slot, ${upperName}VariantProps, ${upperName}VariantMap>`;
}).join("\n") : "[key: string]: SystemSlotRecipeFn<string, any>"}
}
export interface ConfigRecipeSlots {
${slotRecipeKeys.length ? slotRecipeKeys.map((key) => `${key}: ${capitalize(key)}Slot`).join("\n") : "[key: string]: string"}
}
`;
const slotRecipeResult = [slotRecipes.join("\n"), slotRecipeRecord].join("\n");
return pretty(
[
'import type { RecipeDefinition, SlotRecipeDefinition, SystemRecipeFn, SystemSlotRecipeFn } from "../recipe.types"',
'import type { ConditionalValue } from "../css.types"',
recipeResult,
slotRecipeResult,
`
export type SlotRecipeRecord<T, K> = T extends keyof ConfigRecipeSlots
? Record<ConfigRecipeSlots[T], K>
: Record<string, K>
export type SlotRecipeProps<T> = T extends keyof ConfigSlotRecipes
? ConfigSlotRecipes[T]["__type"] & { recipe?: SlotRecipeDefinition | undefined }
: { recipe?: SlotRecipeDefinition | undefined }
export type RecipeProps<T> = T extends keyof ConfigRecipes
? ConfigRecipes[T]["__type"] & { recipe?: RecipeDefinition | undefined }
: { recipe?: RecipeDefinition | undefined }
`
].join("\n")
);
}
export { generateRecipe };
;