diff --git a/packages/cli/src/commands/diff.ts b/packages/cli/src/commands/diff.ts index 7aefd7b8f6..188bd7aa31 100644 --- a/packages/cli/src/commands/diff.ts +++ b/packages/cli/src/commands/diff.ts @@ -2,6 +2,7 @@ import { existsSync, promises as fs } from "fs" import path from "path" import { Config, getConfig } from "@/src/utils/get-config" import { handleError } from "@/src/utils/handle-error" +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" import { fetchTree, @@ -13,7 +14,6 @@ import { registryIndexSchema } from "@/src/utils/registry/schema" import { transform } from "@/src/utils/transformers" import { Command } from "commander" import { diffLines, type Change } from "diff" -import { green, red } from "kleur/colors" import { z } from "zod" const updateOptionsSchema = z.object({ @@ -50,7 +50,7 @@ export const diff = new Command() const config = await getConfig(cwd) if (!config) { logger.warn( - `Configuration is missing. Please run ${green( + `Configuration is missing. Please run ${highlighter.success( `init` )} to create a components.json file.` ) @@ -107,7 +107,9 @@ export const diff = new Command() } } logger.break() - logger.info(`Run ${green(`diff `)} to see the changes.`) + logger.info( + `Run ${highlighter.success(`diff `)} to see the changes.` + ) process.exit(0) } @@ -118,7 +120,9 @@ export const diff = new Command() if (!component) { logger.error( - `The component ${green(options.component)} does not exist.` + `The component ${highlighter.success( + options.component + )} does not exist.` ) process.exit(1) } @@ -200,10 +204,10 @@ async function printDiff(diff: Change[]) { diff.forEach((part) => { if (part) { if (part.added) { - return process.stdout.write(green(part.value)) + return process.stdout.write(highlighter.success(part.value)) } if (part.removed) { - return process.stdout.write(red(part.value)) + return process.stdout.write(highlighter.error(part.value)) } return process.stdout.write(part.value) diff --git a/packages/cli/src/commands/init.ts b/packages/cli/src/commands/init.ts index 7454af3d7b..be2687eaef 100644 --- a/packages/cli/src/commands/init.ts +++ b/packages/cli/src/commands/init.ts @@ -14,10 +14,10 @@ import { } from "@/src/utils/get-config" import { getProjectConfig } from "@/src/utils/get-project-info" import { handleError } from "@/src/utils/handle-error" +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" import { getRegistryBaseColors, getRegistryStyles } from "@/src/utils/registry" import { Command } from "commander" -import { cyan, green } from "kleur/colors" import ora from "ora" import prompts from "prompts" import { z } from "zod" @@ -57,7 +57,7 @@ export const init = new Command() const { proceed } = await prompts({ type: "confirm", name: "proceed", - message: `Write configuration to ${cyan( + message: `Write configuration to ${highlighter.info( "components.json" )}. Proceed?`, initial: true, @@ -85,8 +85,8 @@ export const init = new Command() }) logger.info("") - logger.info( - `${green( + logger.log( + `${highlighter.success( "Success!" )} Project initialization completed.\nYou may now add components.` ) @@ -108,7 +108,9 @@ async function promptForConfig(defaultConfig: Config | null = null) { { type: "toggle", name: "typescript", - message: `Would you like to use ${cyan("TypeScript")} (recommended)?`, + message: `Would you like to use ${highlighter.info( + "TypeScript" + )} (recommended)?`, initial: defaultConfig?.tsx ?? true, active: "yes", inactive: "no", @@ -116,7 +118,7 @@ async function promptForConfig(defaultConfig: Config | null = null) { { type: "select", name: "style", - message: `Which ${cyan("style")} would you like to use?`, + message: `Which ${highlighter.info("style")} would you like to use?`, choices: styles.map((style) => ({ title: style.label, value: style.name, @@ -125,7 +127,7 @@ async function promptForConfig(defaultConfig: Config | null = null) { { type: "select", name: "tailwindBaseColor", - message: `Which color would you like to use as the ${cyan( + message: `Which color would you like to use as the ${highlighter.info( "base color" )}?`, choices: baseColors.map((color) => ({ @@ -136,13 +138,15 @@ async function promptForConfig(defaultConfig: Config | null = null) { { type: "text", name: "tailwindCss", - message: `Where is your ${cyan("global CSS")} file?`, + message: `Where is your ${highlighter.info("global CSS")} file?`, initial: defaultConfig?.tailwind.css ?? DEFAULT_TAILWIND_CSS, }, { type: "toggle", name: "tailwindCssVariables", - message: `Would you like to use ${cyan("CSS variables")} for theming?`, + message: `Would you like to use ${highlighter.info( + "CSS variables" + )} for theming?`, initial: defaultConfig?.tailwind.cssVariables ?? true, active: "yes", inactive: "no", @@ -150,7 +154,7 @@ async function promptForConfig(defaultConfig: Config | null = null) { { type: "text", name: "tailwindPrefix", - message: `Are you using a custom ${cyan( + message: `Are you using a custom ${highlighter.info( "tailwind prefix eg. tw-" )}? (Leave blank if not)`, initial: "", @@ -158,25 +162,29 @@ async function promptForConfig(defaultConfig: Config | null = null) { { type: "text", name: "tailwindConfig", - message: `Where is your ${cyan("tailwind.config.js")} located?`, + message: `Where is your ${highlighter.info( + "tailwind.config.js" + )} located?`, initial: defaultConfig?.tailwind.config ?? DEFAULT_TAILWIND_CONFIG, }, { type: "text", name: "components", - message: `Configure the import alias for ${cyan("components")}:`, + message: `Configure the import alias for ${highlighter.info( + "components" + )}:`, initial: defaultConfig?.aliases["components"] ?? DEFAULT_COMPONENTS, }, { type: "text", name: "utils", - message: `Configure the import alias for ${cyan("utils")}:`, + message: `Configure the import alias for ${highlighter.info("utils")}:`, initial: defaultConfig?.aliases["utils"] ?? DEFAULT_UTILS, }, { type: "toggle", name: "rsc", - message: `Are you using ${cyan("React Server Components")}?`, + message: `Are you using ${highlighter.info("React Server Components")}?`, initial: defaultConfig?.rsc ?? true, active: "yes", inactive: "no", @@ -223,7 +231,7 @@ async function promptForMinimalConfig( { type: "select", name: "style", - message: `Which ${cyan("style")} would you like to use?`, + message: `Which ${highlighter.info("style")} would you like to use?`, choices: styles.map((style) => ({ title: style.label, value: style.name, @@ -233,7 +241,7 @@ async function promptForMinimalConfig( { type: "select", name: "tailwindBaseColor", - message: `Which color would you like to use as the ${cyan( + message: `Which color would you like to use as the ${highlighter.info( "base color" )}?`, choices: baseColors.map((color) => ({ @@ -244,7 +252,9 @@ async function promptForMinimalConfig( { type: "toggle", name: "tailwindCssVariables", - message: `Would you like to use ${cyan("CSS variables")} for theming?`, + message: `Would you like to use ${highlighter.info( + "CSS variables" + )} for theming?`, initial: defaultConfig?.tailwind.cssVariables, active: "yes", inactive: "no", diff --git a/packages/cli/src/preflights/preflight-add.ts b/packages/cli/src/preflights/preflight-add.ts index acec601b88..75d15a6542 100644 --- a/packages/cli/src/preflights/preflight-add.ts +++ b/packages/cli/src/preflights/preflight-add.ts @@ -2,9 +2,9 @@ import path from "path" import { addOptionsSchema } from "@/src/commands/add" import * as ERRORS from "@/src/utils/errors" import { getConfig } from "@/src/utils/get-config" +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" import fs from "fs-extra" -import { cyan } from "kleur/colors" import ora from "ora" import { z } from "zod" @@ -13,7 +13,7 @@ export async function preFlightAdd(options: z.infer) { let projectSpinner if (options.verbose) { - logger.info("") + logger.break() projectSpinner = ora(`Preflight checks.`).start() } @@ -39,27 +39,35 @@ export async function preFlightAdd(options: z.infer) { if (Object.keys(errors).length > 0) { projectSpinner?.fail() - logger.info("") + logger.break() if (errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT]) { - logger.error(`The path ${cyan(options.cwd)} does not exist or is empty.`) + logger.error( + `The path ${highlighter.info(options.cwd)} does not exist or is empty.` + ) } if (errors[ERRORS.MISSING_CONFIG]) { logger.error( - `A ${cyan("components.json")} file was not found at ${cyan( - options.cwd - )}.\nBefore you can add components, you must create a ${cyan( + `A ${highlighter.info( "components.json" - )} file by running the ${cyan("init")} command.` + )} file was not found at ${highlighter.info( + options.cwd + )}.\nBefore you can add components, you must create a ${highlighter.info( + "components.json" + )} file by running the ${highlighter.info("init")} command.` ) logger.error( - `Learn more at ${cyan("https://ui.shadcn.com/docs/components-json")}.` + `Learn more at ${highlighter.info( + "https://ui.shadcn.com/docs/components-json" + )}.` ) } else if (errors[ERRORS.FAILED_CONFIG_READ]) { - logger.error(`Failed to read the ${cyan("components.json")} file.`) + logger.error( + `Failed to read the ${highlighter.info("components.json")} file.` + ) } - logger.info("") + logger.break() process.exit(1) } diff --git a/packages/cli/src/preflights/preflight-init.ts b/packages/cli/src/preflights/preflight-init.ts index d9b823b736..560f0b49b0 100644 --- a/packages/cli/src/preflights/preflight-init.ts +++ b/packages/cli/src/preflights/preflight-init.ts @@ -2,16 +2,16 @@ import path from "path" import { initOptionsSchema } from "@/src/commands/init" import * as ERRORS from "@/src/utils/errors" import { getProjectInfo } from "@/src/utils/get-project-info" +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" import fs from "fs-extra" -import { cyan } from "kleur/colors" import ora from "ora" import { z } from "zod" export async function preFlightInit( options: z.infer ) { - logger.info("") + logger.break() const errors: Record = {} // Ensure target directory exists. @@ -24,7 +24,6 @@ export async function preFlightInit( errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT] = true } - // Check for existing components.json file. if ( fs.existsSync(path.resolve(options.cwd, "components.json")) && !options.force @@ -35,48 +34,57 @@ export async function preFlightInit( if (Object.keys(errors).length > 0) { projectSpinner?.fail() - logger.info("") + logger.break() if (errors[ERRORS.MISSING_DIR_OR_EMPTY_PROJECT]) { - logger.error(`The path ${cyan(options.cwd)} does not exist or is empty.`) + logger.error( + `The path ${highlighter.info(options.cwd)} does not exist or is empty.` + ) } if (errors[ERRORS.EXISTING_CONFIG]) { logger.error( - `A ${cyan("components.json")} file already exists at ${cyan( - options.cwd - )}.\nTo start over, remove the ${cyan( + `A ${highlighter.info( "components.json" - )} file and run ${cyan("init")} again.` + )} file already exists at ${highlighter.info( + options.cwd + )}.\nTo start over, remove the ${highlighter.info( + "components.json" + )} file and run ${highlighter.info("init")} again.` ) } - logger.info("") + logger.break() process.exit(1) } projectSpinner?.succeed() - const projectInfo = await getProjectInfo(options.cwd) - const frameworkSpinner = ora(`Verifying framework.`).start() - if (projectInfo?.framework.name === "manual") { + const projectInfo = await getProjectInfo(options.cwd) + if (!projectInfo || projectInfo?.framework.name === "manual") { errors[ERRORS.UNSUPPORTED_FRAMEWORK] = true frameworkSpinner?.fail() - logger.info("") - logger.error( - `We could not detect a supported framework at ${cyan(options.cwd)}.\n` + - `Visit ${cyan( - projectInfo?.framework.links.installation - )} to manually configure your project.\nOnce configured, you can use the cli to add components.` - ) - logger.info("") + logger.break() + if (projectInfo?.framework.links.installation) { + logger.error( + `We could not detect a supported framework at ${highlighter.info( + options.cwd + )}.\n` + + `Visit ${highlighter.info( + projectInfo?.framework.links.installation + )} to manually configure your project.\nOnce configured, you can use the cli to add components.` + ) + } + logger.break() process.exit(1) - } else { - frameworkSpinner?.succeed( - `Verifying framework: ${projectInfo?.framework.label}.` - ) } + frameworkSpinner?.succeed( + `Verifying framework. Found ${highlighter.info( + projectInfo.framework.label + )}.` + ) + const tailwindSpinner = ora(`Validating Tailwind CSS.`).start() if (!projectInfo?.tailwindConfigFile || !projectInfo?.tailwindCssFile) { errors[ERRORS.TAILWIND_NOT_CONFIGURED] = true @@ -95,30 +103,32 @@ export async function preFlightInit( if (Object.keys(errors).length > 0) { if (errors[ERRORS.TAILWIND_NOT_CONFIGURED]) { - logger.info("") + logger.break() logger.error( `Tailwind CSS is not configured. Install Tailwind CSS then run init again.` ) if (projectInfo?.framework.links.tailwind) { logger.error( - `Visit ${cyan(projectInfo?.framework.links.tailwind)} to get started.` + `Visit ${highlighter.info( + projectInfo?.framework.links.tailwind + )} to get started.` ) } } if (errors[ERRORS.IMPORT_ALIAS_MISSING]) { - logger.info("") + logger.break() logger.error(`No import alias found in your tsconfig.json file.`) if (projectInfo?.framework.links.installation) { logger.error( - `Visit ${cyan( + `Visit ${highlighter.info( projectInfo?.framework.links.installation )} to learn how to set an import alias.` ) } } - logger.info("") + logger.break() process.exit(1) } diff --git a/packages/cli/src/utils/add-components.ts b/packages/cli/src/utils/add-components.ts index 74c732d6c8..b686b2cd64 100644 --- a/packages/cli/src/utils/add-components.ts +++ b/packages/cli/src/utils/add-components.ts @@ -1,10 +1,10 @@ import { type Config } from "@/src/utils/get-config" import { handleError } from "@/src/utils/handle-error" import { registryResolveItemsTree } from "@/src/utils/registry" +import { updateCssVars } from "@/src/utils/updaters/update-css-vars" import { updateDependencies } from "@/src/utils/updaters/update-dependencies" import { updateFiles } from "@/src/utils/updaters/update-files" import { updateTailwindConfig } from "@/src/utils/updaters/update-tailwind-config" -import { updateTailwindCss } from "@/src/utils/updaters/update-tailwind-css" import ora from "ora" export async function addComponents( @@ -26,7 +26,7 @@ export async function addComponents( registrySpinner?.succeed() await updateTailwindConfig(tree.tailwind?.config, config) - await updateTailwindCss(tree.cssVars, config) + await updateCssVars(tree.cssVars, config) await updateDependencies(tree.dependencies, config) await updateFiles(tree.files, config, { diff --git a/packages/cli/src/utils/handle-error.ts b/packages/cli/src/utils/handle-error.ts index 0d5d4c521b..9791835773 100644 --- a/packages/cli/src/utils/handle-error.ts +++ b/packages/cli/src/utils/handle-error.ts @@ -1,5 +1,5 @@ +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" -import { cyan } from "kleur/colors" import { z } from "zod" export function handleError(error: unknown) { @@ -10,7 +10,7 @@ export function handleError(error: unknown) { logger.error("") if (typeof error === "string") { logger.error(error) - logger.error("\n") + logger.break() process.exit(1) } @@ -18,18 +18,18 @@ export function handleError(error: unknown) { console.log(error.issues) logger.error("Validation failed:") for (const [key, value] of Object.entries(error.flatten().fieldErrors)) { - logger.error(`- ${cyan(key)}: ${value}`) + logger.error(`- ${highlighter.info(key)}: ${value}`) } - logger.error("\n") + logger.break() process.exit(1) } if (error instanceof Error) { logger.error(error.message) - logger.error("\n") + logger.break() process.exit(1) } - logger.error("\n") + logger.break() process.exit(1) } diff --git a/packages/cli/src/utils/highlighter.ts b/packages/cli/src/utils/highlighter.ts new file mode 100644 index 0000000000..2d0ea9800b --- /dev/null +++ b/packages/cli/src/utils/highlighter.ts @@ -0,0 +1,8 @@ +import { cyan, green, red, yellow } from "kleur/colors" + +export const highlighter = { + error: red, + warn: yellow, + info: cyan, + success: green, +} diff --git a/packages/cli/src/utils/logger.ts b/packages/cli/src/utils/logger.ts index 88b1498a50..7d698796c7 100644 --- a/packages/cli/src/utils/logger.ts +++ b/packages/cli/src/utils/logger.ts @@ -1,17 +1,17 @@ -import { cyan, green, red, yellow } from "kleur/colors" +import { highlighter } from "@/src/utils/highlighter" export const logger = { error(...args: unknown[]) { - console.log(red(args.join(" "))) + console.log(highlighter.error(args.join(" "))) }, warn(...args: unknown[]) { - console.log(yellow(args.join(" "))) + console.log(highlighter.warn(args.join(" "))) }, info(...args: unknown[]) { - console.log(cyan(args.join(" "))) + console.log(highlighter.info(args.join(" "))) }, success(...args: unknown[]) { - console.log(green(args.join(" "))) + console.log(highlighter.success(args.join(" "))) }, log(...args: unknown[]) { console.log(args.join(" ")) diff --git a/packages/cli/src/utils/registry/index.ts b/packages/cli/src/utils/registry/index.ts index 533b00db96..cca45d1744 100644 --- a/packages/cli/src/utils/registry/index.ts +++ b/packages/cli/src/utils/registry/index.ts @@ -1,6 +1,7 @@ import path from "path" import { Config } from "@/src/utils/get-config" import { handleError } from "@/src/utils/handle-error" +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" import { registryBaseColorSchema, @@ -13,7 +14,6 @@ import { import { buildTailwindThemeColorsFromCssVars } from "@/src/utils/updaters/update-tailwind-config" import deepmerge from "deepmerge" import { HttpsProxyAgent } from "https-proxy-agent" -import { cyan } from "kleur/colors" import fetch from "node-fetch" import { z } from "zod" @@ -174,7 +174,9 @@ async function fetchRegistry(paths: string[]) { 500: "Internal server error", } const message = errorMessages[response.status] || response.statusText - throw new Error(`Failed to fetch from ${cyan(url)}. ${message}`) + throw new Error( + `Failed to fetch from ${highlighter.info(url)}. ${message}` + ) } return response.json() diff --git a/packages/cli/src/utils/updaters/update-tailwind-css.ts b/packages/cli/src/utils/updaters/update-css-vars.ts similarity index 88% rename from packages/cli/src/utils/updaters/update-tailwind-css.ts rename to packages/cli/src/utils/updaters/update-css-vars.ts index 74aca450ca..fc119bcf13 100644 --- a/packages/cli/src/utils/updaters/update-tailwind-css.ts +++ b/packages/cli/src/utils/updaters/update-css-vars.ts @@ -1,8 +1,8 @@ import { promises as fs } from "fs" import path from "path" import { Config } from "@/src/utils/get-config" +import { highlighter } from "@/src/utils/highlighter" import { registryItemCssVarsSchema } from "@/src/utils/registry/schema" -import { cyan } from "kleur/colors" import ora from "ora" import postcss from "postcss" import AtRule from "postcss/lib/at-rule" @@ -10,24 +10,29 @@ import Root from "postcss/lib/root" import Rule from "postcss/lib/rule" import { z } from "zod" -export async function updateTailwindCss( +export async function updateCssVars( cssVars: z.infer | undefined, config: Config ) { - if (!cssVars || !Object.keys(cssVars).length) { + if ( + !cssVars || + !Object.keys(cssVars).length || + !config.resolvedPaths.tailwindCss + ) { return } - console.log(cssVars) - - const tailwindCssFileRelativePath = path.relative( + const cssFilepath = config.resolvedPaths.tailwindCss + const cssFilepathRelative = path.relative( config.resolvedPaths.cwd, - config.resolvedPaths.tailwindCss + cssFilepath ) - const spinner = ora(`Updating ${cyan(tailwindCssFileRelativePath)}`).start() - const raw = await fs.readFile(config.resolvedPaths.tailwindCss, "utf8") + const spinner = ora( + `Updating ${highlighter.info(cssFilepathRelative)}` + ).start() + const raw = await fs.readFile(cssFilepath, "utf8") let output = await transformTailwindCss(raw, cssVars) - await fs.writeFile(config.resolvedPaths.tailwindCss, output, "utf8") + await fs.writeFile(cssFilepath, output, "utf8") spinner.succeed() } @@ -140,7 +145,6 @@ function updateCssVarsPlugin( } } -// Function to add or update variables for a given selector function addOrUpdateVars( baseLayer: AtRule, selector: string, diff --git a/packages/cli/src/utils/updaters/update-dependencies.ts b/packages/cli/src/utils/updaters/update-dependencies.ts index 0c89ae35ef..46266c07af 100644 --- a/packages/cli/src/utils/updaters/update-dependencies.ts +++ b/packages/cli/src/utils/updaters/update-dependencies.ts @@ -1,8 +1,8 @@ import { Config } from "@/src/utils/get-config" import { getPackageManager } from "@/src/utils/get-package-manager" +import { highlighter } from "@/src/utils/highlighter" import { RegistryItem } from "@/src/utils/registry/schema" import { execa } from "execa" -import { cyan } from "kleur/colors" import ora from "ora" export async function updateDependencies( @@ -14,7 +14,7 @@ export async function updateDependencies( } const dependenciesSpinner = ora( - `Installing ${dependencies.map((d) => cyan(d)).join(", ")}.` + `Installing ${dependencies.map((d) => highlighter.info(d)).join(", ")}.` )?.start() const packageManager = await getPackageManager(config.resolvedPaths.cwd) diff --git a/packages/cli/src/utils/updaters/update-files.ts b/packages/cli/src/utils/updaters/update-files.ts index aa2f3f636b..8a7fbc5c27 100644 --- a/packages/cli/src/utils/updaters/update-files.ts +++ b/packages/cli/src/utils/updaters/update-files.ts @@ -1,6 +1,7 @@ import { existsSync, promises as fs } from "fs" import path, { basename } from "path" import { Config } from "@/src/utils/get-config" +import { highlighter } from "@/src/utils/highlighter" import { logger } from "@/src/utils/logger" import { getRegistryBaseColor, @@ -12,7 +13,6 @@ import { transformCssVars } from "@/src/utils/transformers/transform-css-vars" import { transformImport } from "@/src/utils/transformers/transform-import" import { transformRsc } from "@/src/utils/transformers/transform-rsc" import { transformTwPrefixes } from "@/src/utils/transformers/transform-tw-prefix" -import { cyan } from "kleur/colors" import ora from "ora" import prompts from "prompts" @@ -52,7 +52,7 @@ export async function updateFiles( const { overwrite } = await prompts({ type: "confirm", name: "overwrite", - message: `The file ${cyan( + message: `The file ${highlighter.info( fileName )} already exists. Would you like to overwrite?`, initial: false, diff --git a/packages/cli/src/utils/updaters/update-tailwind-config.ts b/packages/cli/src/utils/updaters/update-tailwind-config.ts index fff503acdf..835897c5fa 100644 --- a/packages/cli/src/utils/updaters/update-tailwind-config.ts +++ b/packages/cli/src/utils/updaters/update-tailwind-config.ts @@ -2,10 +2,9 @@ import { promises as fs } from "fs" import { tmpdir } from "os" import path from "path" import { Config } from "@/src/utils/get-config" -import { logger } from "@/src/utils/logger" +import { highlighter } from "@/src/utils/highlighter" import { registryItemTailwindSchema } from "@/src/utils/registry/schema" import deepmerge from "deepmerge" -import { cyan } from "kleur/colors" import ora from "ora" import objectToString from "stringify-object" import { type Config as TailwindConfig } from "tailwindcss" @@ -39,7 +38,9 @@ export async function updateTailwindConfig( config.resolvedPaths.cwd, config.resolvedPaths.tailwindConfig ) - const spinner = ora(`Updating ${cyan(tailwindFileRelativePath)}`).start() + const spinner = ora( + `Updating ${highlighter.info(tailwindFileRelativePath)}` + ).start() const raw = await fs.readFile(config.resolvedPaths.tailwindConfig, "utf8") const output = await transformTailwindConfig(raw, tailwindConfig, config) await fs.writeFile(config.resolvedPaths.tailwindConfig, output, "utf8")