UNPKG

shadcn-vue

Version:
3,993 lines 127 kB
#!/usr/bin/env node

// src/commands/init.ts
import { promises as fs9 } from "node:fs";

// src/utils/errors.ts
var MISSING_DIR_OR_EMPTY_PROJECT = "1";
var MISSING_CONFIG = "3";
var TAILWIND_NOT_CONFIGURED = "5";
var IMPORT_ALIAS_MISSING = "6";
var UNSUPPORTED_FRAMEWORK = "7";
var BUILD_MISSING_REGISTRY_FILE = "13";

// src/utils/frameworks.ts
var FRAMEWORKS = {
  vite: {
    name: "vite",
    label: "Vite",
    links: {
      installation: "https://shadcn-vue.com/docs/installation/vite",
      tailwind: "https://tailwindcss.com/docs/guides/vite"
    }
  },
  nuxt: {
    name: "nuxt",
    label: "Nuxt",
    links: {
      installation: "https://shadcn-vue.com/docs/installation/nuxt",
      tailwind: "https://tailwindcss.com/docs/guides/nuxtjs"
    }
  },
  astro: {
    name: "astro",
    label: "Astro",
    links: {
      installation: "https://shadcn-vue.com/docs/installation/astro",
      tailwind: "https://tailwindcss.com/docs/guides/astro"
    }
  },
  laravel: {
    name: "laravel",
    label: "Laravel",
    links: {
      installation: "https://shadcn-vue.com/docs/installation/laravel",
      tailwind: "https://tailwindcss.com/docs/guides/laravel"
    }
  },
  manual: {
    name: "manual",
    label: "Manual",
    links: {
      installation: "https://shadcn-vue.com/docs/installation/manual",
      tailwind: "https://tailwindcss.com/docs/installation"
    }
  }
};

// src/utils/resolve-import.ts
import { createPathsMatcher } from "get-tsconfig";
function resolveImport(importPath, config) {
  const matcher = createPathsMatcher(config);
  if (matcher === null) {
    return;
  }
  const paths = matcher(importPath);
  return paths[0];
}

// src/utils/get-config.ts
import { cosmiconfig } from "cosmiconfig";
import { getTsconfig } from "get-tsconfig";
import path from "pathe";
import { z } from "zod";

// src/utils/highlighter.ts
import { colors } from "consola/utils";
var highlighter = {
  error: colors.red,
  warn: colors.yellow,
  info: colors.cyan,
  success: colors.green
};

// src/utils/get-config.ts
var TAILWIND_CSS_PATH = {
  nuxt: "assets/css/tailwind.css",
  vite: "src/assets/index.css",
  laravel: "resources/css/app.css",
  astro: "src/styles/globals.css"
};
var DEFAULT_COMPONENTS = "@/components";
var DEFAULT_UTILS = "@/lib/utils";
var DEFAULT_TAILWIND_CSS = TAILWIND_CSS_PATH.nuxt;
var DEFAULT_TAILWIND_CONFIG = "tailwind.config.js";
var explorer = cosmiconfig("components", {
  searchPlaces: ["components.json"]
});
var rawConfigSchema = z.object({
  $schema: z.string().optional(),
  style: z.string(),
  typescript: z.boolean().default(true),
  tailwind: z.object({
    config: z.string().optional(),
    css: z.string(),
    baseColor: z.string(),
    cssVariables: z.boolean().default(true),
    prefix: z.string().default("").optional()
  }),
  aliases: z.object({
    components: z.string(),
    composables: z.string().optional(),
    utils: z.string(),
    ui: z.string().optional(),
    lib: z.string().optional()
  }),
  iconLibrary: z.string().optional()
}).strict();
var configSchema = rawConfigSchema.extend({
  resolvedPaths: z.object({
    cwd: z.string(),
    tailwindConfig: z.string(),
    tailwindCss: z.string(),
    utils: z.string(),
    components: z.string(),
    composables: z.string(),
    lib: z.string(),
    ui: z.string()
  })
});
async function getConfig(cwd) {
  const config = await getRawConfig(cwd);
  if (!config) {
    return null;
  }
  if (!config.iconLibrary) {
    config.iconLibrary = config.style === "new-york" ? "radix" : "lucide";
  }
  return await resolveConfigPaths(cwd, config);
}
function getTSConfig(cwd, tsconfigName) {
  const parsedConfig = getTsconfig(path.resolve(cwd, "package.json"), tsconfigName);
  if (parsedConfig === null) {
    throw new Error(
      `Failed to find ${highlighter.info(tsconfigName)}`
    );
  }
  return parsedConfig;
}
async function resolveConfigPaths(cwd, config) {
  const tsconfigType = config.typescript ? "tsconfig.json" : "jsconfig.json";
  const tsConfig = getTSConfig(cwd, tsconfigType);
  return configSchema.parse({
    ...config,
    resolvedPaths: {
      cwd,
      tailwindConfig: config.tailwind.config ? path.resolve(cwd, config.tailwind.config) : "",
      tailwindCss: path.resolve(cwd, config.tailwind.css),
      utils: await resolveImport(config.aliases.utils, tsConfig),
      components: await resolveImport(config.aliases.components, tsConfig),
      ui: config.aliases.ui ? await resolveImport(config.aliases.ui, tsConfig) : path.resolve(
        await resolveImport(config.aliases.components, tsConfig) ?? cwd,
        "ui"
      ),
      // TODO: Make this configurable.
      // For now, we assume the lib and hooks directories are one level up from the components directory.
      lib: config.aliases.lib ? await resolveImport(config.aliases.lib, tsConfig) : path.resolve(
        await resolveImport(config.aliases.utils, tsConfig) ?? cwd,
        ".."
      ),
      composables: config.aliases.composables ? await resolveImport(config.aliases.composables, tsConfig) : path.resolve(
        await resolveImport(config.aliases.components, tsConfig) ?? cwd,
        "..",
        "composables"
      )
    }
  });
}
async function getRawConfig(cwd) {
  try {
    const configResult = await explorer.search(cwd);
    if (!configResult) {
      return null;
    }
    return rawConfigSchema.parse(configResult.config);
  } catch (error) {
    throw new Error(`Invalid configuration found in ${cwd}/components.json.`);
  }
}
async function getTargetStyleFromConfig(cwd, fallback) {
  const projectInfo = await getProjectInfo(cwd);
  return projectInfo?.tailwindVersion === "v4" ? "new-york-v4" : fallback;
}

// src/utils/get-package-info.ts
import fs from "fs-extra";
import path2 from "pathe";
function getPackageInfo(cwd = "", shouldThrow = true) {
  const packageJsonPath = path2.join(cwd, "package.json");
  return fs.readJSONSync(packageJsonPath, {
    throws: shouldThrow
  });
}

// src/utils/get-project-info.ts
import fs2 from "fs-extra";
import { parseTsconfig } from "get-tsconfig";
import path3 from "pathe";
import { glob } from "tinyglobby";
import { z as z2 } from "zod";
var PROJECT_SHARED_IGNORE = [
  "**/node_modules/**",
  ".nuxt",
  "public",
  "dist",
  "build"
];
var TS_CONFIG_SCHEMA = z2.object({
  compilerOptions: z2.object({
    paths: z2.record(z2.string().or(z2.array(z2.string())))
  })
});
async function getProjectInfo(cwd) {
  const [
    configFiles,
    typescript,
    tailwindConfigFile,
    tailwindCssFile,
    tailwindVersion,
    aliasPrefix,
    packageJson
  ] = await Promise.all([
    glob("**/{nuxt,vite,astro}.config.*|composer.json", {
      cwd,
      deep: 3,
      ignore: PROJECT_SHARED_IGNORE
    }),
    isTypeScriptProject(cwd),
    getTailwindConfigFile(cwd),
    getTailwindCssFile(cwd),
    getTailwindVersion(cwd),
    getTsConfigAliasPrefix(cwd),
    getPackageInfo(cwd, false)
  ]);
  const type = {
    framework: FRAMEWORKS.manual,
    typescript,
    tailwindConfigFile,
    tailwindCssFile,
    tailwindVersion,
    aliasPrefix
  };
  if (configFiles.find((file) => file.startsWith("nuxt.config."))?.length) {
    type.framework = FRAMEWORKS.nuxt;
    return type;
  }
  if (configFiles.find((file) => file.startsWith("astro.config."))?.length) {
    type.framework = FRAMEWORKS.astro;
    return type;
  }
  if (configFiles.find((file) => file.startsWith("composer.json"))?.length) {
    type.framework = FRAMEWORKS.laravel;
    return type;
  }
  if (configFiles.find((file) => file.startsWith("vite.config."))?.length) {
    type.framework = FRAMEWORKS.vite;
    return type;
  }
  return type;
}
async function getTailwindVersion(cwd) {
  const [packageInfo, config] = await Promise.all([
    getPackageInfo(cwd),
    getConfig(cwd)
  ]);
  if (config?.tailwind?.config === "") {
    return "v4";
  }
  if (!packageInfo?.dependencies?.tailwindcss && !packageInfo?.devDependencies?.tailwindcss) {
    return null;
  }
  if (/^(?:\^|~)?3(?:\.\d+)*(?:-.*)?$/.test(
    packageInfo?.dependencies?.tailwindcss || packageInfo?.devDependencies?.tailwindcss || ""
  )) {
    return "v3";
  }
  return "v4";
}
async function getTailwindCssFile(cwd) {
  const [files, tailwindVersion] = await Promise.all([
    glob(["**/*.css", "**/*.scss"], {
      cwd,
      deep: 5,
      ignore: PROJECT_SHARED_IGNORE
    }),
    getTailwindVersion(cwd)
  ]);
  if (!files.length) {
    return null;
  }
  const needle = tailwindVersion === "v4" ? `@import "tailwindcss"` : "@tailwind base";
  for (const file of files) {
    const contents = await fs2.readFile(path3.resolve(cwd, file), "utf8");
    if (contents.includes(`@import "tailwindcss"`) || contents.includes(`@import 'tailwindcss'`) || contents.includes(`@tailwind base`)) {
      return file;
    }
  }
  return null;
}
async function getTailwindConfigFile(cwd) {
  const files = await glob("tailwind.config.*", {
    cwd,
    deep: 3,
    ignore: PROJECT_SHARED_IGNORE
  });
  if (!files.length) {
    return null;
  }
  return files[0];
}
async function getTsConfigAliasPrefix(cwd) {
  const isTypescript = await isTypeScriptProject(cwd);
  const tsconfigType = isTypescript ? "tsconfig.json" : "jsconfig.json";
  const tsConfig = getTSConfig(cwd, tsconfigType);
  const parsedTsConfig = parseTsconfig(tsConfig.path);
  const aliasPaths = parsedTsConfig.compilerOptions?.paths ?? {};
  for (const [alias, paths] of Object.entries(aliasPaths)) {
    if (paths.includes("./*") || paths.includes("./src/*") || paths.includes("./app/*") || paths.includes("./resources/js/*")) {
      const cleanAlias = alias.replace(/\/\*$/, "") ?? null;
      return cleanAlias === "#build" ? "@" : cleanAlias;
    }
  }
  return Object.keys(aliasPaths)?.[0]?.replace(/\/\*$/, "") ?? null;
}
async function isTypeScriptProject(cwd) {
  const files = await glob("tsconfig.*", {
    cwd,
    deep: 1,
    ignore: PROJECT_SHARED_IGNORE
  });
  return files.length > 0;
}
async function getProjectConfig(cwd, defaultProjectInfo = null) {
  const [existingConfig, projectInfo] = await Promise.all([
    getConfig(cwd),
    !defaultProjectInfo ? getProjectInfo(cwd) : Promise.resolve(defaultProjectInfo)
  ]);
  if (existingConfig) {
    return existingConfig;
  }
  if (!projectInfo || !projectInfo.tailwindCssFile || projectInfo.tailwindVersion === "v3" && !projectInfo.tailwindConfigFile) {
    return null;
  }
  const config = {
    $schema: "https://shadcn-vue.com/schema.json",
    typescript: projectInfo.typescript,
    style: "new-york",
    tailwind: {
      config: projectInfo.tailwindConfigFile ?? "",
      baseColor: "zinc",
      css: projectInfo.tailwindCssFile,
      cssVariables: true,
      prefix: ""
    },
    iconLibrary: "lucide",
    aliases: {
      components: `${projectInfo.aliasPrefix}/components`,
      ui: `${projectInfo.aliasPrefix}/components/ui`,
      composables: `${projectInfo.aliasPrefix}/composables`,
      lib: `${projectInfo.aliasPrefix}/lib`,
      utils: `${projectInfo.aliasPrefix}/lib/utils`
    }
  };
  return await resolveConfigPaths(cwd, config);
}
async function getProjectTailwindVersionFromConfig(config) {
  if (!config.resolvedPaths?.cwd) {
    return "v3";
  }
  const projectInfo = await getProjectInfo(config.resolvedPaths.cwd);
  if (!projectInfo?.tailwindVersion) {
    return null;
  }
  return projectInfo.tailwindVersion;
}

// src/utils/logger.ts
import consola from "consola";
var logger = {
  error(...args) {
    consola.log(highlighter.error(args.join(" ")));
  },
  warn(...args) {
    consola.log(highlighter.warn(args.join(" ")));
  },
  info(...args) {
    consola.log(highlighter.info(args.join(" ")));
  },
  success(...args) {
    consola.log(highlighter.success(args.join(" ")));
  },
  log(...args) {
    consola.log(args.join(" "));
  },
  break() {
    consola.log("");
  }
};

// src/utils/spinner.ts
import ora from "ora";
function spinner(text, options) {
  return ora({
    text,
    isSilent: options?.silent
  });
}

// src/preflights/preflight-init.ts
import fs3 from "fs-extra";
import path4 from "pathe";
async function preFlightInit(options) {
  const errors = {};
  if (!fs3.existsSync(options.cwd) || !fs3.existsSync(path4.resolve(options.cwd, "package.json"))) {
    errors[MISSING_DIR_OR_EMPTY_PROJECT] = true;
    return {
      errors,
      projectInfo: null
    };
  }
  const projectSpinner = spinner(`Preflight checks.`, {
    silent: options.silent
  }).start();
  if (fs3.existsSync(path4.resolve(options.cwd, "components.json")) && !options.force) {
    projectSpinner?.fail();
    logger.break();
    logger.error(
      `A ${highlighter.info(
        "components.json"
      )} file already exists at ${highlighter.info(
        options.cwd
      )}.
To start over, remove the ${highlighter.info(
        "components.json"
      )} file and run ${highlighter.info("init")} again.`
    );
    logger.break();
    process.exit(1);
  }
  projectSpinner?.succeed();
  const frameworkSpinner = spinner(`Verifying framework.`, {
    silent: options.silent
  }).start();
  const projectInfo = await getProjectInfo(options.cwd);
  if (!projectInfo || projectInfo?.framework.name === "manual") {
    errors[UNSUPPORTED_FRAMEWORK] = true;
    frameworkSpinner?.fail();
    logger.break();
    if (projectInfo?.framework.links.installation) {
      logger.error(
        `We could not detect a supported framework at ${highlighter.info(
          options.cwd
        )}.
Visit ${highlighter.info(
          projectInfo?.framework.links.installation
        )} to manually configure your project.
Once configured, you can use the cli to add components.`
      );
    }
    logger.break();
    process.exit(1);
  }
  frameworkSpinner?.succeed(
    `Verifying framework. Found ${highlighter.info(
      projectInfo.framework.label
    )}.`
  );
  let tailwindSpinnerMessage = "Validating Tailwind CSS.";
  if (projectInfo.tailwindVersion === "v4") {
    tailwindSpinnerMessage = `Validating Tailwind CSS config. Found ${highlighter.info(
      "v4"
    )}.`;
  }
  const tailwindSpinner = spinner(tailwindSpinnerMessage, {
    silent: options.silent
  }).start();
  if (projectInfo.tailwindVersion === "v3" && (!projectInfo?.tailwindConfigFile || !projectInfo?.tailwindCssFile)) {
    errors[TAILWIND_NOT_CONFIGURED] = true;
    tailwindSpinner?.fail();
  } else if (projectInfo.tailwindVersion === "v4" && !projectInfo?.tailwindCssFile) {
    errors[TAILWIND_NOT_CONFIGURED] = true;
    tailwindSpinner?.fail();
  } else if (!projectInfo.tailwindVersion) {
    errors[TAILWIND_NOT_CONFIGURED] = true;
    tailwindSpinner?.fail();
  } else {
    tailwindSpinner?.succeed();
  }
  const tsConfigSpinner = spinner(`Validating import alias.`, {
    silent: options.silent
  }).start();
  if (!projectInfo?.aliasPrefix) {
    errors[IMPORT_ALIAS_MISSING] = true;
    tsConfigSpinner?.fail();
  } else {
    tsConfigSpinner?.succeed();
  }
  if (Object.keys(errors).length > 0) {
    if (errors[TAILWIND_NOT_CONFIGURED]) {
      logger.break();
      logger.error(
        `No Tailwind CSS configuration found at ${highlighter.info(
          options.cwd
        )}.`
      );
      logger.error(
        `It is likely you do not have Tailwind CSS installed or have an invalid configuration.`
      );
      logger.error(`Install Tailwind CSS then try again.`);
      if (projectInfo?.framework.links.tailwind) {
        logger.error(
          `Visit ${highlighter.info(
            projectInfo?.framework.links.tailwind
          )} to get started.`
        );
      }
    }
    if (errors[IMPORT_ALIAS_MISSING]) {
      logger.break();
      logger.error(`No import alias found in your tsconfig.json file.`);
      if (projectInfo?.framework.links.installation) {
        logger.error(
          `Visit ${highlighter.info(
            projectInfo?.framework.links.installation
          )} to learn how to set an import alias.`
        );
      }
    }
    logger.break();
    process.exit(1);
  }
  return {
    errors,
    projectInfo
  };
}

// src/registry/schema.ts
import { z as z3 } from "zod";
var registryItemTypeSchema = z3.enum([
  "registry:lib",
  "registry:block",
  "registry:component",
  "registry:ui",
  "registry:hook",
  "registry:page",
  "registry:file",
  "registry:theme",
  "registry:style",
  // Internal use only
  "registry:example",
  "registry:internal"
]);
var registryItemFileSchema = z3.discriminatedUnion("type", [
  // Target is required for registry:file and registry:page
  z3.object({
    path: z3.string(),
    content: z3.string().optional(),
    type: z3.enum(["registry:file", "registry:page"]),
    target: z3.string()
  }),
  z3.object({
    path: z3.string(),
    content: z3.string().optional(),
    type: registryItemTypeSchema.exclude(["registry:file", "registry:page"]),
    target: z3.string().optional()
  })
]);
var registryItemTailwindSchema = z3.object({
  config: z3.object({
    content: z3.array(z3.string()).optional(),
    theme: z3.record(z3.string(), z3.any()).optional(),
    plugins: z3.array(z3.string()).optional()
  }).optional()
});
var registryItemCssVarsSchema = z3.object({
  theme: z3.record(z3.string(), z3.string()).optional(),
  light: z3.record(z3.string(), z3.string()).optional(),
  dark: z3.record(z3.string(), z3.string()).optional()
});
var registryItemCssSchema = z3.record(
  z3.string(),
  z3.lazy(
    () => z3.union([
      z3.string(),
      z3.record(
        z3.string(),
        z3.union([z3.string(), z3.record(z3.string(), z3.string())])
      )
    ])
  )
);
var registryItemSchema = z3.object({
  $schema: z3.string().optional(),
  extends: z3.string().optional(),
  name: z3.string(),
  type: registryItemTypeSchema,
  title: z3.string().optional(),
  author: z3.string().min(2).optional(),
  description: z3.string().optional(),
  dependencies: z3.array(z3.string()).optional(),
  devDependencies: z3.array(z3.string()).optional(),
  registryDependencies: z3.array(z3.string()).optional(),
  files: z3.array(registryItemFileSchema).optional(),
  tailwind: registryItemTailwindSchema.optional(),
  cssVars: registryItemCssVarsSchema.optional(),
  css: registryItemCssSchema.optional(),
  meta: z3.record(z3.string(), z3.any()).optional(),
  docs: z3.string().optional(),
  categories: z3.array(z3.string()).optional()
});
var registrySchema = z3.object({
  name: z3.string(),
  homepage: z3.string(),
  items: z3.array(registryItemSchema)
});
var registryIndexSchema = z3.array(registryItemSchema);
var stylesSchema = z3.array(
  z3.object({
    name: z3.string(),
    label: z3.string()
  })
);
var iconsSchema = z3.record(
  z3.string(),
  z3.record(z3.string(), z3.string())
);
var registryBaseColorSchema = z3.object({
  inlineColors: z3.object({
    light: z3.record(z3.string(), z3.string()),
    dark: z3.record(z3.string(), z3.string())
  }),
  cssVars: registryItemCssVarsSchema,
  cssVarsV4: registryItemCssVarsSchema.optional(),
  inlineColorsTemplate: z3.string(),
  cssVarsTemplate: z3.string()
});
var registryResolvedItemsTreeSchema = registryItemSchema.pick({
  dependencies: true,
  devDependencies: true,
  files: true,
  tailwind: true,
  cssVars: true,
  css: true,
  docs: true
});

// src/utils/handle-error.ts
import { consola as consola2 } from "consola";
function handleError(error) {
  consola2.log("this is error: ", error);
  if (typeof error === "string") {
    consola2.error(error);
    process.exit(1);
  }
  if (error instanceof Error) {
    consola2.error(error.message);
    process.exit(1);
  }
  consola2.error("Something went wrong. Please try again.");
  process.exit(1);
}

// src/utils/updaters/update-tailwind-config.ts
import { promises as fs4 } from "node:fs";
import { tmpdir } from "node:os";
import deepmerge from "deepmerge";
import path5 from "pathe";
import objectToString from "stringify-object";
import {
  Project,
  QuoteKind,
  ScriptKind,
  SyntaxKind
} from "ts-morph";
async function updateTailwindConfig(tailwindConfig, config, options) {
  if (!tailwindConfig) {
    return;
  }
  options = {
    silent: false,
    tailwindVersion: "v3",
    ...options
  };
  if (options.tailwindVersion === "v4") {
    return;
  }
  const tailwindFileRelativePath = path5.relative(
    config.resolvedPaths.cwd,
    config.resolvedPaths.tailwindConfig
  );
  const tailwindSpinner = spinner(
    `Updating ${highlighter.info(tailwindFileRelativePath)}`,
    {
      silent: options.silent
    }
  ).start();
  const raw = await fs4.readFile(config.resolvedPaths.tailwindConfig, "utf8");
  const output = await transformTailwindConfig(raw, tailwindConfig, config);
  await fs4.writeFile(config.resolvedPaths.tailwindConfig, output, "utf8");
  tailwindSpinner?.succeed();
}
async function transformTailwindConfig(input, tailwindConfig, config) {
  const sourceFile = await _createSourceFile(input, config);
  const configObject = sourceFile.getDescendantsOfKind(SyntaxKind.ObjectLiteralExpression).find(
    (node) => node.getProperties().some(
      (property) => property.isKind(SyntaxKind.PropertyAssignment) && property.getName() === "content"
    )
  );
  if (!configObject) {
    return input;
  }
  const quoteChar = _getQuoteChar(configObject);
  addTailwindConfigProperty(
    configObject,
    {
      name: "darkMode",
      value: "class"
    },
    { quoteChar }
  );
  tailwindConfig.plugins?.forEach((plugin) => {
    addTailwindConfigPlugin(configObject, plugin);
  });
  if (tailwindConfig.theme) {
    await addTailwindConfigTheme(configObject, tailwindConfig.theme);
  }
  return sourceFile.getFullText();
}
function addTailwindConfigProperty(configObject, property, {
  quoteChar
}) {
  const existingProperty = configObject.getProperty("darkMode");
  if (!existingProperty) {
    const newProperty = {
      name: property.name,
      initializer: `[${quoteChar}${property.value}${quoteChar}]`
    };
    if (property.name === "darkMode") {
      configObject.insertPropertyAssignment(0, newProperty);
      return configObject;
    }
    configObject.addPropertyAssignment(newProperty);
    return configObject;
  }
  if (existingProperty.isKind(SyntaxKind.PropertyAssignment)) {
    const initializer = existingProperty.getInitializer();
    const newValue = `${quoteChar}${property.value}${quoteChar}`;
    if (initializer?.isKind(SyntaxKind.StringLiteral)) {
      const initializerText = initializer.getText();
      initializer.replaceWithText(`[${initializerText}, ${newValue}]`);
      return configObject;
    }
    if (initializer?.isKind(SyntaxKind.ArrayLiteralExpression)) {
      if (initializer.getElements().map((element) => element.getText()).includes(newValue)) {
        return configObject;
      }
      initializer.addElement(newValue);
    }
    return configObject;
  }
  return configObject;
}
async function addTailwindConfigTheme(configObject, theme) {
  if (!configObject.getProperty("theme")) {
    configObject.addPropertyAssignment({
      name: "theme",
      initializer: "{}"
    });
  }
  nestSpreadProperties(configObject);
  const themeProperty = configObject.getPropertyOrThrow("theme")?.asKindOrThrow(SyntaxKind.PropertyAssignment);
  const themeInitializer = themeProperty.getInitializer();
  if (themeInitializer?.isKind(SyntaxKind.ObjectLiteralExpression)) {
    const themeObjectString = themeInitializer.getText();
    const themeObject = await parseObjectLiteral(themeObjectString);
    const result = deepmerge(themeObject, theme, {
      arrayMerge: (dst, src) => src
    });
    const resultString = objectToString(result).replace(/'\.\.\.(.*)'/g, "...$1").replace(/'"/g, "'").replace(/"'/g, "'").replace(/'\[/g, "[").replace(/\]'/g, "]").replace(/'\\'/g, "'").replace(/\\'/g, "'").replace(/\\''/g, "'").replace(/''/g, "'");
    themeInitializer.replaceWithText(resultString);
  }
  unnestSpreadProperties(configObject);
}
function addTailwindConfigPlugin(configObject, plugin) {
  const existingPlugins = configObject.getProperty("plugins");
  if (!existingPlugins) {
    configObject.addPropertyAssignment({
      name: "plugins",
      initializer: `[${plugin}]`
    });
    return configObject;
  }
  if (existingPlugins.isKind(SyntaxKind.PropertyAssignment)) {
    const initializer = existingPlugins.getInitializer();
    if (initializer?.isKind(SyntaxKind.ArrayLiteralExpression)) {
      if (initializer.getElements().map((element) => {
        return element.getText().replace(/["']/g, "");
      }).includes(plugin.replace(/["']/g, ""))) {
        return configObject;
      }
      initializer.addElement(plugin);
    }
    return configObject;
  }
  return configObject;
}
async function _createSourceFile(input, config) {
  const dir = await fs4.mkdtemp(path5.join(tmpdir(), "shadcn-"));
  const resolvedPath = config?.resolvedPaths?.tailwindConfig || "tailwind.config.ts";
  const tempFile = path5.join(dir, `shadcn-${path5.basename(resolvedPath)}`);
  const project = new Project({
    compilerOptions: {}
  });
  const sourceFile = project.createSourceFile(tempFile, input, {
    // Note: .js and .mjs can still be valid for TS projects.
    // We can't infer TypeScript from config.tsx.
    scriptKind: path5.extname(resolvedPath) === ".ts" ? ScriptKind.TS : ScriptKind.JS
  });
  return sourceFile;
}
function _getQuoteChar(configObject) {
  return configObject.getFirstDescendantByKind(SyntaxKind.StringLiteral)?.getQuoteKind() === QuoteKind.Single ? "'" : '"';
}
function nestSpreadProperties(obj) {
  const properties = obj.getProperties();
  for (let i = 0; i < properties.length; i++) {
    const prop = properties[i];
    if (prop.isKind(SyntaxKind.SpreadAssignment)) {
      const spreadAssignment = prop.asKindOrThrow(SyntaxKind.SpreadAssignment);
      const spreadText = spreadAssignment.getExpression().getText();
      obj.insertPropertyAssignment(i, {
        // Need to escape the name with " so that deepmerge doesn't mishandle the key
        name: `"___${spreadText.replace(/^\.\.\./, "")}"`,
        initializer: `"...${spreadText.replace(/^\.\.\./, "")}"`
      });
      spreadAssignment.remove();
    } else if (prop.isKind(SyntaxKind.PropertyAssignment)) {
      const propAssignment = prop.asKindOrThrow(SyntaxKind.PropertyAssignment);
      const initializer = propAssignment.getInitializer();
      if (initializer && initializer.isKind(SyntaxKind.ObjectLiteralExpression)) {
        nestSpreadProperties(
          initializer.asKindOrThrow(SyntaxKind.ObjectLiteralExpression)
        );
      } else if (initializer && initializer.isKind(SyntaxKind.ArrayLiteralExpression)) {
        nestSpreadElements(
          initializer.asKindOrThrow(SyntaxKind.ArrayLiteralExpression)
        );
      }
    }
  }
}
function nestSpreadElements(arr) {
  const elements = arr.getElements();
  for (let j = 0; j < elements.length; j++) {
    const element = elements[j];
    if (element.isKind(SyntaxKind.ObjectLiteralExpression)) {
      nestSpreadProperties(
        element.asKindOrThrow(SyntaxKind.ObjectLiteralExpression)
      );
    } else if (element.isKind(SyntaxKind.ArrayLiteralExpression)) {
      nestSpreadElements(
        element.asKindOrThrow(SyntaxKind.ArrayLiteralExpression)
      );
    } else if (element.isKind(SyntaxKind.SpreadElement)) {
      const spreadText = element.getText();
      arr.removeElement(j);
      arr.insertElement(j, `"${spreadText}"`);
    }
  }
}
function unnestSpreadProperties(obj) {
  const properties = obj.getProperties();
  for (let i = 0; i < properties.length; i++) {
    const prop = properties[i];
    if (prop.isKind(SyntaxKind.PropertyAssignment)) {
      const propAssignment = prop;
      const initializer = propAssignment.getInitializer();
      if (initializer && initializer.isKind(SyntaxKind.StringLiteral)) {
        const value = initializer.asKindOrThrow(SyntaxKind.StringLiteral).getLiteralValue();
        if (value.startsWith("...")) {
          obj.insertSpreadAssignment(i, { expression: value.slice(3) });
          propAssignment.remove();
        }
      } else if (initializer?.isKind(SyntaxKind.ObjectLiteralExpression)) {
        unnestSpreadProperties(initializer);
      } else if (initializer && initializer.isKind(SyntaxKind.ArrayLiteralExpression)) {
        unnsetSpreadElements(
          initializer.asKindOrThrow(SyntaxKind.ArrayLiteralExpression)
        );
      }
    }
  }
}
function unnsetSpreadElements(arr) {
  const elements = arr.getElements();
  for (let j = 0; j < elements.length; j++) {
    const element = elements[j];
    if (element.isKind(SyntaxKind.ObjectLiteralExpression)) {
      unnestSpreadProperties(
        element.asKindOrThrow(SyntaxKind.ObjectLiteralExpression)
      );
    } else if (element.isKind(SyntaxKind.ArrayLiteralExpression)) {
      unnsetSpreadElements(
        element.asKindOrThrow(SyntaxKind.ArrayLiteralExpression)
      );
    } else if (element.isKind(SyntaxKind.StringLiteral)) {
      const spreadText = element.getText();
      const spreadTest = /^['"](\.\.\..*)['"]$/g;
      if (spreadTest.test(spreadText)) {
        arr.removeElement(j);
        arr.insertElement(j, spreadText.replace(spreadTest, "$1"));
      }
    }
  }
}
async function parseObjectLiteral(objectLiteralString) {
  const sourceFile = await _createSourceFile(
    `const theme = ${objectLiteralString}`,
    null
  );
  const statement = sourceFile.getStatements()[0];
  if (statement?.getKind() === SyntaxKind.VariableStatement) {
    const declaration = statement.getDeclarationList()?.getDeclarations()[0];
    const initializer = declaration.getInitializer();
    if (initializer?.isKind(SyntaxKind.ObjectLiteralExpression)) {
      return await parseObjectLiteralExpression(initializer);
    }
  }
  throw new Error("Invalid input: not an object literal");
}
function parseObjectLiteralExpression(node) {
  const result = {};
  for (const property of node.getProperties()) {
    if (property.isKind(SyntaxKind.PropertyAssignment)) {
      const name = property.getName().replace(/'/g, "");
      if (property.getInitializer()?.isKind(SyntaxKind.ObjectLiteralExpression)) {
        result[name] = parseObjectLiteralExpression(
          property.getInitializer()
        );
      } else if (property.getInitializer()?.isKind(SyntaxKind.ArrayLiteralExpression)) {
        result[name] = parseArrayLiteralExpression(
          property.getInitializer()
        );
      } else {
        result[name] = parseValue(property.getInitializer());
      }
    }
  }
  return result;
}
function parseArrayLiteralExpression(node) {
  const result = [];
  for (const element of node.getElements()) {
    if (element.isKind(SyntaxKind.ObjectLiteralExpression)) {
      result.push(
        parseObjectLiteralExpression(
          element.asKindOrThrow(SyntaxKind.ObjectLiteralExpression)
        )
      );
    } else if (element.isKind(SyntaxKind.ArrayLiteralExpression)) {
      result.push(
        parseArrayLiteralExpression(
          element.asKindOrThrow(SyntaxKind.ArrayLiteralExpression)
        )
      );
    } else {
      result.push(parseValue(element));
    }
  }
  return result;
}
function parseValue(node) {
  switch (node.getKind()) {
    case SyntaxKind.StringLiteral:
      return node.getText();
    case SyntaxKind.NumericLiteral:
      return Number(node.getText());
    case SyntaxKind.TrueKeyword:
      return true;
    case SyntaxKind.FalseKeyword:
      return false;
    case SyntaxKind.NullKeyword:
      return null;
    case SyntaxKind.ArrayLiteralExpression:
      return node.getElements().map(parseValue);
    case SyntaxKind.ObjectLiteralExpression:
      return parseObjectLiteralExpression(node);
    default:
      return node.getText();
  }
}
function buildTailwindThemeColorsFromCssVars(cssVars) {
  const result = {};
  for (const key of Object.keys(cssVars)) {
    const parts = key.split("-");
    const colorName = parts[0];
    const subType = parts.slice(1).join("-");
    if (subType === "") {
      if (typeof result[colorName] === "object") {
        result[colorName].DEFAULT = `hsl(var(--${key}))`;
      } else {
        result[colorName] = `hsl(var(--${key}))`;
      }
    } else {
      if (typeof result[colorName] !== "object") {
        result[colorName] = { DEFAULT: `hsl(var(--${colorName}))` };
      }
      result[colorName][subType] = `hsl(var(--${key}))`;
    }
  }
  for (const [colorName, value] of Object.entries(result)) {
    if (typeof value === "object" && value.DEFAULT === `hsl(var(--${colorName}))` && !(colorName in cssVars)) {
      delete value.DEFAULT;
    }
  }
  return result;
}

// src/registry/api.ts
import deepmerge2 from "deepmerge";
import { ofetch } from "ofetch";
import path6 from "pathe";
import { ProxyAgent } from "undici";
import { z as z4 } from "zod";
var REGISTRY_URL = process.env.REGISTRY_URL ?? "https://shadcn-vue.com/r";
var agent = process.env.https_proxy ? new ProxyAgent(process.env.https_proxy) : void 0;
var registryCache = /* @__PURE__ */ new Map();
async function getRegistryIndex() {
  try {
    const [result] = await fetchRegistry(["index.json"]);
    return registryIndexSchema.parse(result);
  } catch (error) {
    logger.error("\n");
    handleError(error);
  }
}
async function getRegistryStyles() {
  try {
    const [result] = await fetchRegistry(["styles/index.json"]);
    return stylesSchema.parse(result);
  } catch (error) {
    logger.error("\n");
    handleError(error);
    return [];
  }
}
async function getRegistryIcons() {
  try {
    const [result] = await fetchRegistry(["icons/index.json"]);
    return iconsSchema.parse(result);
  } catch (error) {
    handleError(error);
    return {};
  }
}
async function getRegistryItem(name, style) {
  try {
    const [result] = await fetchRegistry([
      isUrl(name) ? name : `styles/${style}/${name}.json`
    ]);
    return registryItemSchema.parse(result);
  } catch (error) {
    logger.break();
    handleError(error);
    return null;
  }
}
var BASE_COLORS = [
  {
    name: "neutral",
    label: "Neutral"
  },
  {
    name: "gray",
    label: "Gray"
  },
  {
    name: "zinc",
    label: "Zinc"
  },
  {
    name: "stone",
    label: "Stone"
  },
  {
    name: "slate",
    label: "Slate"
  }
];
async function getRegistryBaseColors() {
  return BASE_COLORS;
}
async function getRegistryBaseColor(baseColor) {
  try {
    const [result] = await fetchRegistry([`colors/${baseColor}.json`]);
    return registryBaseColorSchema.parse(result);
  } catch (error) {
    handleError(error);
  }
}
async function fetchTree(style, tree) {
  try {
    const paths = tree.map((item) => `styles/${style}/${item.name}.json`);
    const result = await fetchRegistry(paths);
    return registryIndexSchema.parse(result);
  } catch (error) {
    handleError(error);
  }
}
async function getItemTargetPath(config, item, override) {
  if (override) {
    return override;
  }
  if (item.type === "registry:ui") {
    return config.resolvedPaths.ui ?? config.resolvedPaths.components;
  }
  const [parent, type] = item.type?.split(":") ?? [];
  if (!(parent in config.resolvedPaths)) {
    return null;
  }
  return path6.join(
    config.resolvedPaths[parent],
    type
  );
}
async function fetchRegistry(paths) {
  try {
    const results = await Promise.all(
      paths.map(async (path20) => {
        const url = getRegistryUrl(path20);
        if (registryCache.has(url)) {
          return registryCache.get(url);
        }
        const response = await ofetch(url, { dispatcher: agent, parseResponse: JSON.parse }).catch((error) => {
          throw new Error(error.data);
        });
        registryCache.set(url, response);
        return response;
      })
    );
    return results;
  } catch (error) {
    logger.error("\n");
    handleError(error);
    return [];
  }
}
function getRegistryItemFileTargetPath(file, config, override) {
  if (override) {
    return override;
  }
  if (file.type === "registry:ui") {
    const folder = file.path.split("/")[1];
    return path6.join(config.resolvedPaths.ui, folder);
  }
  if (file.type === "registry:lib") {
    return config.resolvedPaths.lib;
  }
  if (file.type === "registry:block" || file.type === "registry:component") {
    return config.resolvedPaths.components;
  }
  if (file.type === "registry:hook") {
    return config.resolvedPaths.composables;
  }
  if (file.type === "registry:page") {
    return config.resolvedPaths.components;
  }
  return config.resolvedPaths.components;
}
async function registryResolveItemsTree(names, config) {
  try {
    const index = await getRegistryIndex();
    if (!index) {
      return null;
    }
    if (names.includes("index")) {
      names.unshift("index");
    }
    const registryDependencies = /* @__PURE__ */ new Set();
    for (const name of names) {
      const itemRegistryDependencies = await resolveRegistryDependencies(
        name,
        config
      );
      itemRegistryDependencies.forEach((dep) => registryDependencies.add(dep));
    }
    const uniqueRegistryDependencies = Array.from(registryDependencies);
    const result = await fetchRegistry(uniqueRegistryDependencies);
    const payload = z4.array(registryItemSchema).parse(result);
    if (!payload) {
      return null;
    }
    if (names.includes("index")) {
      if (config.tailwind.baseColor) {
        const theme = await registryGetTheme(config.tailwind.baseColor, config);
        if (theme) {
          payload.unshift(theme);
        }
      }
    }
    let tailwind = {};
    payload.forEach((item) => {
      tailwind = deepmerge2(tailwind, item.tailwind ?? {});
    });
    let cssVars = {};
    payload.forEach((item) => {
      cssVars = deepmerge2(cssVars, item.cssVars ?? {});
    });
    let docs = "";
    payload.forEach((item) => {
      if (item.docs) {
        docs += `${item.docs}
`;
      }
    });
    return registryResolvedItemsTreeSchema.parse({
      dependencies: Array.from(new Set(payload.flatMap((item) => item.dependencies ?? []))),
      devDependencies: Array.from(new Set(payload.flatMap((item) => item.devDependencies ?? []))),
      files: deepmerge2.all(payload.map((item) => item.files ?? [])),
      tailwind,
      cssVars,
      docs
    });
  } catch (error) {
    handleError(error);
    return null;
  }
}
async function resolveRegistryDependencies(url, config) {
  const visited = /* @__PURE__ */ new Set();
  const payload = [];
  const style = config.resolvedPaths?.cwd ? await getTargetStyleFromConfig(config.resolvedPaths.cwd, config.style) : config.style;
  async function resolveDependencies(itemUrl) {
    const url2 = getRegistryUrl(
      isUrl(itemUrl) ? itemUrl : `styles/${style}/${itemUrl}.json`
    );
    if (visited.has(url2)) {
      return;
    }
    visited.add(url2);
    try {
      const [result] = await fetchRegistry([url2]);
      const item = registryItemSchema.parse(result);
      payload.push(url2);
      if (item.registryDependencies) {
        for (const dependency of item.registryDependencies) {
          await resolveDependencies(dependency);
        }
      }
    } catch (error) {
      console.error(
        `Error fetching or parsing registry item at ${itemUrl}:`,
        error
      );
    }
  }
  await resolveDependencies(url);
  return Array.from(new Set(payload));
}
async function registryGetTheme(name, config) {
  const [baseColor, tailwindVersion] = await Promise.all([
    getRegistryBaseColor(name),
    getProjectTailwindVersionFromConfig(config)
  ]);
  if (!baseColor) {
    return null;
  }
  const theme = {
    name,
    type: "registry:theme",
    tailwind: {
      config: {
        theme: {
          extend: {
            borderRadius: {
              lg: "var(--radius)",
              md: "calc(var(--radius) - 2px)",
              sm: "calc(var(--radius) - 4px)"
            },
            colors: {}
          }
        }
      }
    },
    cssVars: {
      theme: {},
      light: {
        radius: "0.5rem"
      },
      dark: {}
    }
  };
  if (config.tailwind.cssVariables) {
    theme.tailwind.config.theme.extend.colors = {
      ...theme.tailwind.config.theme.extend.colors,
      ...buildTailwindThemeColorsFromCssVars(baseColor.cssVars.dark ?? {})
    };
    theme.cssVars = {
      theme: {
        ...baseColor.cssVars.theme,
        ...theme.cssVars.theme
      },
      light: {
        ...baseColor.cssVars.light,
        ...theme.cssVars.light
      },
      dark: {
        ...baseColor.cssVars.dark,
        ...theme.cssVars.dark
      }
    };
    if (tailwindVersion === "v4" && baseColor.cssVarsV4) {
      theme.cssVars = {
        theme: {
          ...baseColor.cssVarsV4.theme,
          ...theme.cssVars.theme
        },
        light: {
          ...theme.cssVars.light,
          ...baseColor.cssVarsV4.light
        },
        dark: {
          ...theme.cssVars.dark,
          ...baseColor.cssVarsV4.dark
        }
      };
    }
  }
  return theme;
}
function getRegistryUrl(path20) {
  if (isUrl(path20)) {
    const url = new URL(path20);
    if (url.pathname.match(/\/chat\/b\//) && !url.pathname.endsWith("/json")) {
      url.pathname = `${url.pathname}/json`;
    }
    return url.toString();
  }
  return `${REGISTRY_URL}/${path20}`;
}
function isUrl(path20) {
  try {
    new URL(path20);
    return true;
  } catch (error) {
    return false;
  }
}
async function resolveRegistryItems(names, config) {
  const registryDependencies = [];
  for (const name of names) {
    const itemRegistryDependencies = await resolveRegistryDependencies(
      name,
      config
    );
    registryDependencies.push(...itemRegistryDependencies);
  }
  return Array.from(new Set(registryDependencies));
}

// src/utils/updaters/update-css.ts
import { promises as fs5 } from "node:fs";
import path7 from "pathe";
import postcss from "postcss";
async function updateCss(css, config, options) {
  if (!config.resolvedPaths.tailwindCss || !css || Object.keys(css).length === 0) {
    return;
  }
  options = {
    silent: false,
    ...options
  };
  const cssFilepath = config.resolvedPaths.tailwindCss;
  const cssFilepathRelative = path7.relative(
    config.resolvedPaths.cwd,
    cssFilepath
  );
  const cssSpinner = spinner(
    `Updating ${highlighter.info(cssFilepathRelative)}`,
    {
      silent: options.silent
    }
  ).start();
  const raw = await fs5.readFile(cssFilepath, "utf8");
  const output = await transformCss(raw, css);
  await fs5.writeFile(cssFilepath, output, "utf8");
  cssSpinner.succeed();
}
async function transformCss(input, css) {
  const plugins = [updateCssPlugin(css)];
  const result = await postcss(plugins).process(input, {
    from: void 0
  });
  let output = result.css;
  output = output.replace(/\/\* ---break--- \*\//g, "");
  output = output.replace(/(\n\s*\n)+/g, "\n\n");
  output = output.trimEnd();
  return output;
}
function updateCssPlugin(css) {
  return {
    postcssPlugin: "update-css",
    Once(root) {
      for (const [selector, properties] of Object.entries(css)) {
        if (selector.startsWith("@")) {
          const atRuleMatch = selector.match(/@([a-z-]+)\s*(.*)/i);
          if (!atRuleMatch)
            continue;
          const [, name, params] = atRuleMatch;
          if (name === "keyframes") {
            let themeInline = root.nodes?.find(
              (node) => node.type === "atrule" && node.name === "theme" && node.params === "inline"
            );
            if (!themeInline) {
              themeInline = postcss.atRule({
                name: "theme",
                params: "inline",
                raws: { semicolon: true, between: " ", before: "\n" }
              });
              root.append(themeInline);
              root.insertBefore(
                themeInline,
                postcss.comment({ text: "---break---" })
              );
            }
            const keyframesRule = postcss.atRule({
              name: "keyframes",
              params,
              raws: { semicolon: true, between: " ", before: "\n  " }
            });
            themeInline.append(keyframesRule);
            if (typeof properties === "object") {
              for (const [step, stepProps] of Object.entries(properties)) {
                processRule(keyframesRule, step, stepProps);
              }
            }
          } else if (name === "utility") {
            const utilityAtRule = root.nodes?.find(
              (node) => node.type === "atrule" && node.name === name && node.params === params
            );
            if (!utilityAtRule) {
              const atRule = postcss.atRule({
                name,
                params,
                raws: { semicolon: true, between: " ", before: "\n" }
              });
              root.append(atRule);
              root.insertBefore(
                atRule,
                postcss.comment({ text: "---break---" })
              );
              if (typeof properties === "object") {
                for (const [prop, value] of Object.entries(properties)) {
                  if (typeof value === "string") {
                    const decl = postcss.decl({
                      prop,
                      value,
                      raws: { semicolon: true, before: "\n    " }
                    });
                    atRule.append(decl);
                  } else if (typeof value === "object") {
                    processRule(atRule, prop, value);
                  }
                }
              }
            } else {
              if (typeof properties === "object") {
                for (const [prop, value] of Object.entries(properties)) {
                  if (typeof value === "string") {
                    const existingDecl = utilityAtRule.nodes?.find(
                      (node) => node.type === "decl" && node.prop === prop
                    );
                    const decl = postcss.decl({
                      prop,
                      value,
                      raws: { semicolon: true, before: "\n    " }
                    });
                    existingDecl ? existingDecl.replaceWith(decl) : utilityAtRule.append(decl);
                  } else if (typeof value === "object") {
                    processRule(utilityAtRule, prop, value);
                  }
                }
              }
            }
          } else {
            processAtRule(root, name, params, properties);
          }
        } else {
          processRule(root, selector, properties);
        }
      }
    }
  };
}
function processAtRule(root, name, params, properties) {
  let atRule = root.nodes?.find(
    (node) => node.type === "atrule" && node.name === name && node.params === params
  );
  if (!atRule) {
    atRule = postcss.atRule({
      name,
      params,
      raws: { semicolon: true, between: " ", before: "\n" }
    });
    root.append(atRule);
    root.insertBefore(atRule, postcss.comment({ text: "---break---" }));
  }
  if (typeof properties === "object") {
    for (const [childSelector, childProps] of Object.entries(properties)) {
      if (childSelector.startsWith("@")) {
        const nestedMatch = childSelector.match(/@([a-z-]+)\s*(.*)/i);
        if (nestedMatch) {
          const [, nestedName, nestedParams] = nestedMatch;
          processAtRule(atRule, nestedName, nestedParams, childProps);
        }
      } else {
        processRule(atRule, childSelector, childProps);
      }
    }
  } else if (typeof properties === "string") {
    try {
      const parsed = postcss.parse(`.temp{${properties}}`);
      const tempRule = parsed.first;
      if (tempRule && tempRule.nodes) {
        const rule = postcss.rule({
          selector: "temp",
          raws: { semicolon: true, between: " ", before: "\n  " }
        });
        tempRule.nodes.forEach((node) => {
          if (node.type === "decl") {
            const clone = node.clone();
            clone.raws.before = "\n    ";
            rule.append(clone);
          }
        });
        if (rule.nodes?.length) {
          atRule.append(rule);
        }
      }
    } catch (error) {
      console.error("Error parsing at-rule content:", properties, error);
      throw error;
    }
  }
}
function processRule(parent, selector, properties) {
  let rule = parent.nodes?.find(
    (node) => node.type === "rule" && node.selector === selector
  );
  if (!rule) {
    rule = postcss.rule({
      selector,
      raws: { semicolon: true, between: " ", before: "\n  " }
    });
    parent.append(rule);
  }
  if (typeof properties === "object") {
    for (const [prop, value] of Object.entries(properties)) {
      if (typeof value === "string") {
        const decl = postcss.decl({
          prop,
          value,
          raws: { semicolon: true, before: "\n    " }
        });
        const existingDecl = rule.nodes?.find(
          (node) => node.type === "decl" && node.prop === prop
        );
        existingDecl ? existingDecl.replaceWith(decl) : rule.append(decl);
      } else if (typeof value === "object") {
        const nestedSelector = prop.startsWith("&") ? selector.replace(/^([^:]+)/, `$1${prop.substring(1)}`) : prop;
        processRule(parent, nestedSelector, value);
      }
    }
  } else if (typeof properties === "string") {
    try {
      const parsed = postcss.parse(`.temp{${properties}}`);
      const tempRule = parsed.first;
      if (tempRule && tempRule.nodes) {
        tempRule.nodes.forEach((node) => {
          if (node.type === "decl") {
            const clone = node.clone();
            clone.raws.before = "\n    ";
            rule?.append(clone);
          }
        });
      }
    } catch (error) {
      console.error("Error parsing rule content:", selector, properties, error);
      throw error;
    }
  }
}

// src/utils/updaters/update-css-vars.ts
import { promises as fs6 } from "node:fs";
import path8 from "node:path";
import postcss2 from "postcss";
import AtRule from "postcss/lib/at-rule";
import { z as z5 } from "zod";
async function updateCssVars(cssVars, config, options) {
  if (!config.resolvedPaths.tailwindCss || !Object.keys(cssVars ?? {}).length) {
    return;
  }
  options = {
    cleanupDefaultNextStyles: false,
    silent: false,
    tailwindVersion: "v3",
    overwriteCssVars: false,
    initIndex: true,
    ...options
  };
  const cssFilepath = config.resolvedPaths.tailwindCss;
  const cssFilepathRelative = path8.relative(
    config.resolvedPaths.cwd,
    cssFilepath
  );
  const cssVarsSpinner = spinner(
    `Updating CSS variables in ${highlighter.info(cssFilepathRelative)}`,
    {
      silent: options.silent
    }
  ).start();
  const raw = await fs6.readFile(cssFilepath, "utf8");
  const output = await transformCssVars(raw, cssVars ?? {}, config, {
    cleanupDefaultNextStyles: options.cleanupDefaultNextStyles,
    tailwindVersion: options.tailwindVersion,
    tailwindConfig: options.tailwindConfig,
    overwriteCssVars: options.overwriteCssVars,
    initIndex: options.initIndex
  });
  await fs6.writeFile(cssFilepath, output, "utf8");
  cssVarsSpinner.succeed();
}
async function transformCssVars(input, cssVars, config, options = {
  cleanupDefaultNextStyles: false,
  tailwindVersion: "v3",
  tailwindConfig: void 0,
  overwriteCssVars: false,
  initIndex: true
}) {
  options = {
    cleanupDefaultNextStyles: false,
    tailwindVersion: "v3",
    tailwindConfig: void 0,
    overwriteCssVars: false,
    initIndex: true,
    ...options
  };
  let plugins = [updateCssVarsPlugin(cssVars)];
  if (options.cleanupDefaultNextStyles) {
    plugins.push(cleanupDefaultNextStylesPlugin());
  }
  if (options.tailwindVersion === "v4") {
    plugins = [];
    if (config.resolvedPaths?.cwd) {
      const packageInfo = getPackageInfo(config.resolvedPaths.cwd);
      if (!packageInfo?.dependencies?.["tailwindcss-animate"] && !packageInfo?.devDependencies?.["tailwindcss-animate"] && options.initIndex) {
        plugins.push(addCustomImport({ params: "tw-animate-css" }));
      }
    }
    plugins.push(addCustomVariant({ params: "dark (&:is(.dark *))" }));
    if (options.cleanupDefaultNextStyles) {
      plugins.push(cleanupDefaultNextStylesPlugin());
    }
    plugins.push(
      updateCssVarsPluginV4(cssVars, {
        overwriteCssVars: options.overwriteCssVars
      })
    );
    plugins.push(updateThemePlugin(cssVars));
    if (options.tailwindConfig) {
      plugins.push(updateTailwindConfigPlugin(options.tailwindConfig));
      plugins.push(updateTailwindConfigAnimationPlugin(options.tailwindConfig));
      plugins.push(updateTailwindConfigKeyframesPlugin(options.tailwindConfig));
    }
  }
  if (config.tailwind.cssVariables && options.initIndex) {
    plugins.push(
      updateBaseLayerPlugin({ tailwindVersion: options.tailwindVersion })
    );
  }
  const result = await postcss2(plugins).process(input, {
    from: void 0
  });
  let output = result.css;
  output = output.replace(/\/\* ---break--- \*\//g, "");
  if (options.tailwindVersion === "v4") {
    output = output.replace(/(\n\s*\n)+/g, "\n\n");
  }
  return output;
}
function updateBaseLayerPlugin({
  tailwindVersion
}) {
  return {
    postcssPlugin: "update-base-layer",
    Once(root) {
      const requiredRules = [
        {
          selector: "*",
          apply: tailwindVersion === "v4" ? "border-border outline-ring/50" : "border-border"
        },
        { selector: "body", apply: "bg-background text-foreground" }
      ];
      let baseLayer = root.nodes.find(
        (node) => node.type === "atrule" && node.name === "layer" && node.params === "base" && requiredRules.every(
          ({ selector, apply }) => node.nodes?.some(
            (rule) => rule.type === "rule" && rule.selector === selector && rule.nodes.some(
              (applyRule) => applyRule.type === "atrule" && applyRule.name === "apply" && applyRule.params === apply
            )
          )
        )
      );
      if (!baseLayer) {
        baseLayer = postcss2.atRule({
          name: "layer",
          params: "base",
          raws: { semicolon: true, between: " ", before: "\n" }
        });
        root.append(baseLayer);
        root.insertBefore(baseLayer, postcss2.comment({ text: "---break---" }));
      }
      requiredRules.forEach(({ selector, apply }) => {
        const existingRule = baseLayer?.nodes?.find(
          (node) => node.type === "rule" && node.selector === selector
        );
        if (!existingRule) {
          baseLayer?.append(
            postcss2.rule({
              selector,
              nodes: [
                postcss2.atRule({
                  name: "apply",
                  params: apply,
                  raws: { semicolon: true, before: "\n    " }
                })
              ],
              raws: { semicolon: true, between: " ", before: "\n  " }
            })
          );
        }
      });
    }
  };
}
function updateCssVarsPlugin(cssVars) {
  return {
    postcssPlugin: "update-css-vars",
    Once(root) {
      let baseLayer = root.nodes.find(
        (node) => node.type === "atrule" && node.name === "layer" && node.params === "base"
      );
      if (!(baseLayer instanceof AtRule)) {
        baseLayer = postcss2.atRule({
          name: "layer",
          params: "base",
          nodes: [],
          raws: {
            semicolon: true,
            before: "\n",
            between: " "
          }
        });
        root.append(baseLayer);
        root.insertBefore(baseLayer, postcss2.comment({ text: "---break---" }));
      }
      if (baseLayer !== void 0) {
        Object.entries(cssVars).forEach(([key, vars]) => {
          const selector = key === "light" ? ":root" : `.${key}`;
          addOrUpdateVars(baseLayer, selector, vars);
        });
      }
    }
  };
}
function removeConflictVars(root) {
  const rootRule = root.nodes.find(
    (node) => node.type === "rule" && node.selector === ":root"
  );
  if (rootRule) {
    const propsToRemove = ["--background", "--foreground"];
    rootRule.nodes.filter(
      (node) => node.type === "decl" && propsToRemove.includes(node.prop)
    ).forEach((node) => node.remove());
    if (rootRule.nodes.length === 0) {
      rootRule.remove();
    }
  }
}
function cleanupDefaultNextStylesPlugin() {
  return {
    postcssPlugin: "cleanup-default-next-styles",
    Once(root) {
      const bodyRule = root.nodes.find(
        (node) => node.type === "rule" && node.selector === "body"
      );
      if (bodyRule) {
        bodyRule.nodes.find(
          (node) => node.type === "decl" && node.prop === "color" && ["rgb(var(--foreground-rgb))", "var(--foreground)"].includes(
            node.value
          )
        )?.remove();
        bodyRule.nodes.find((node) => {
          return node.type === "decl" && node.prop === "background" && (node.value.startsWith("linear-gradient") || node.value === "var(--background)");
        })?.remove();
        bodyRule.nodes.find(
          (node) => node.type === "decl" && node.prop === "font-family" && node.value === "Arial, Helvetica, sans-serif"
        )?.remove();
        if (bodyRule.nodes.length === 0) {
          bodyRule.remove();
        }
      }
      removeConflictVars(root);
      const darkRootRule = root.nodes.find(
        (node) => node.type === "atrule" && node.params === "(prefers-color-scheme: dark)"
      );
      if (darkRootRule) {
        removeConflictVars(darkRootRule);
        if (darkRootRule.nodes.length === 0) {
          darkRootRule.remove();
        }
      }
    }
  };
}
function addOrUpdateVars(baseLayer, selector, vars) {
  let ruleNode = baseLayer.nodes?.find(
    (node) => node.type === "rule" && node.selector === selector
  );
  if (!ruleNode) {
    if (Object.keys(vars).length > 0) {
      ruleNode = postcss2.rule({
        selector,
        raws: { between: " ", before: "\n  " }
      });
      baseLayer.append(ruleNode);
    }
  }
  Object.entries(vars).forEach(([key, value]) => {
    const prop = `--${key.replace(/^--/, "")}`;
    const newDecl = postcss2.decl({
      prop,
      value,
      raws: { semicolon: true }
    });
    const existingDecl = ruleNode?.nodes.find(
      (node) => node.type === "decl" && node.prop === prop
    );
    existingDecl ? existingDecl.replaceWith(newDecl) : ruleNode?.append(newDecl);
  });
}
function updateCssVarsPluginV4(cssVars, options) {
  return {
    postcssPlugin: "update-css-vars-v4",
    Once(root) {
      Object.entries(cssVars).forEach(([key, vars]) => {
        let selector = key === "light" ? ":root" : `.${key}`;
        if (key === "theme") {
          selector = "@theme";
          const themeNode = upsertThemeNode(root);
          Object.entries(vars).forEach(([key2, value]) => {
            const prop = `--${key2.replace(/^--/, "")}`;
            const newDecl = postcss2.decl({
              prop,
              value,
              raws: { semicolon: true }
            });
            const existingDecl = themeNode?.nodes?.find(
              (node) => node.type === "decl" && node.prop === prop
            );
            if (options.overwriteCssVars) {
              if (existingDecl) {
                existingDecl.replaceWith(newDecl);
              } else {
                themeNode?.append(newDecl);
              }
            } else {
              if (!existingDecl) {
                themeNode?.append(newDecl);
              }
            }
          });
          return;
        }
        let ruleNode = root.nodes?.find(
          (node) => node.type === "rule" && node.selector === selector
        );
        if (!ruleNode && Object.keys(vars).length > 0) {
          ruleNode = postcss2.rule({
            selector,
            nodes: [],
            raws: { semicolon: true, between: " ", before: "\n" }
          });
          root.append(ruleNode);
          root.insertBefore(ruleNode, postcss2.comment({ text: "---break---" }));
        }
        Object.entries(vars).forEach(([key2, value]) => {
          let prop = `--${key2.replace(/^--/, "")}`;
          if (prop === "--sidebar-background") {
            prop = "--sidebar";
          }
          if (isLocalHSLValue(value)) {
            value = `hsl(${value})`;
          }
          const newDecl = postcss2.decl({
            prop,
            value,
            raws: { semicolon: true }
          });
          const existingDecl = ruleNode?.nodes.find(
            (node) => node.type === "decl" && node.prop === prop
          );
          if (options.overwriteCssVars) {
            if (existingDecl) {
              existingDecl.replaceWith(newDecl);
            } else {
              ruleNode?.append(newDecl);
            }
          } else {
            if (!existingDecl) {
              ruleNode?.append(newDecl);
            }
          }
        });
      });
    }
  };
}
function updateThemePlugin(cssVars) {
  return {
    postcssPlugin: "update-theme",
    Once(root) {
      const variables = Array.from(
        new Set(
          Object.keys(cssVars).flatMap(
            (key) => Object.keys(cssVars[key] || {})
          )
        )
      );
      if (!variables.length) {
        return;
      }
      const themeNode = upsertThemeNode(root);
      const themeVarNodes = themeNode.nodes?.filter(
        (node) => node.type === "decl" && node.prop.startsWith("--")
      );
      for (const variable of variables) {
        const value = Object.values(cssVars).find((vars) => vars[variable])?.[variable];
        if (!value) {
          continue;
        }
        if (variable === "radius") {
          const radiusVariables = {
            sm: "calc(var(--radius) - 4px)",
            md: "calc(var(--radius) - 2px)",
            lg: "var(--radius)",
            xl: "calc(var(--radius) + 4px)"
          };
          for (const [key, value2] of Object.entries(radiusVariables)) {
            const cssVarNode2 = postcss2.decl({
              prop: `--radius-${key}`,
              value: value2,
              raws: { semicolon: true }
            });
            if (themeNode?.nodes?.find(
              (node) => node.type === "decl" && node.prop === cssVarNode2.prop
            )) {
              continue;
            }
            themeNode?.append(cssVarNode2);
          }
          continue;
        }
        let prop = isLocalHSLValue(value) || isColorValue(value) ? `--color-${variable.replace(/^--/, "")}` : `--${variable.replace(/^--/, "")}`;
        if (prop === "--color-sidebar-background") {
          prop = "--color-sidebar";
        }
        let propValue = `var(--${variable})`;
        if (prop === "--color-sidebar") {
          propValue = "var(--sidebar)";
        }
        const cssVarNode = postcss2.decl({
          prop,
          value: propValue,
          raws: { semicolon: true }
        });
        const existingDecl = themeNode?.nodes?.find(
          (node) => node.type === "decl" && node.prop === cssVarNode.prop
        );
        if (!existingDecl) {
          if (themeVarNodes?.length) {
            themeNode?.insertAfter(
              themeVarNodes[themeVarNodes.length - 1],
              cssVarNode
            );
          } else {
            themeNode?.append(cssVarNode);
          }
        }
      }
    }
  };
}
function upsertThemeNode(root) {
  let themeNode = root.nodes.find(
    (node) => node.type === "atrule" && node.name === "theme" && node.params === "inline"
  );
  if (!themeNode) {
    themeNode = postcss2.atRule({
      name: "theme",
      params: "inline",
      nodes: [],
      raws: { semicolon: true, between: " ", before: "\n" }
    });
    root.append(themeNode);
    root.insertBefore(themeNode, postcss2.comment({ text: "---break---" }));
  }
  return themeNode;
}
function addCustomVariant({ params }) {
  return {
    postcssPlugin: "add-custom-variant",
    Once(root) {
      const customVariant = root.nodes.find(
        (node) => node.type === "atrule" && node.name === "custom-variant"
      );
      if (!customVariant) {
        const importNodes = root.nodes.filter(
          (node) => node.type === "atrule" && node.name === "import"
        );
        const variantNode = postcss2.atRule({
          name: "custom-variant",
          params,
          raws: { semicolon: true, before: "\n" }
        });
        if (importNodes.length > 0) {
          const lastImport = importNodes[importNodes.length - 1];
          root.insertAfter(lastImport, variantNode);
        } else {
          root.insertAfter(root.nodes[0], variantNode);
        }
        root.insertBefore(variantNode, postcss2.comment({ text: "---break---" }));
      }
    }
  };
}
function addCustomImport({ params }) {
  return {
    postcssPlugin: "add-custom-import",
    Once(root) {
      const importNodes = root.nodes.filter(
        (node) => node.type === "atrule" && node.name === "import"
      );
      const customVariantNode = root.nodes.find(
        (node) => node.type === "atrule" && node.name === "custom-variant"
      );
      const hasImport = importNodes.some(
        (node) => node.params.replace(/["']/g, "") === params
      );
      if (!hasImport) {
        const importNode = postcss2.atRule({
          name: "import",
          params: `"${params}"`,
          raws: { semicolon: true, before: "\n" }
        });
        if (importNodes.length > 0) {
          const lastImport = importNodes[importNodes.length - 1];
          root.insertAfter(lastImport, importNode);
        } else if (customVariantNode) {
          root.insertBefore(customVariantNode, importNode);
          root.insertBefore(
            customVariantNode,
            postcss2.comment({ text: "---break---" })
          );
        } else {
          root.prepend(importNode);
          root.insertAfter(importNode, postcss2.comment({ text: "---break---" }));
        }
      }
    }
  };
}
function updateTailwindConfigPlugin(tailwindConfig) {
  return {
    postcssPlugin: "update-tailwind-config",
    Once(root) {
      if (!tailwindConfig?.plugins) {
        return;
      }
      const quoteType = getQuoteType(root);
      const quote = quoteType === "single" ? "'" : '"';
      const pluginNodes = root.nodes.filter(
        (node) => node.type === "atrule" && node.name === "plugin"
      );
      const lastPluginNode = pluginNodes[pluginNodes.length - 1] || root.nodes[0];
      for (const plugin of tailwindConfig.plugins) {
        const pluginName = plugin.replace(/^require\(["']|["']\)$/g, "");
        if (pluginNodes.some((node) => {
          return node.params.replace(/["']/g, "") === pluginName;
        })) {
          continue;
        }
        const pluginNode = postcss2.atRule({
          name: "plugin",
          params: `${quote}${pluginName}${quote}`,
          raws: { semicolon: true, before: "\n" }
        });
        root.insertAfter(lastPluginNode, pluginNode);
        root.insertBefore(pluginNode, postcss2.comment({ text: "---break---" }));
      }
    }
  };
}
function updateTailwindConfigKeyframesPlugin(tailwindConfig) {
  return {
    postcssPlugin: "update-tailwind-config-keyframes",
    Once(root) {
      if (!tailwindConfig?.theme?.extend?.keyframes) {
        return;
      }
      const themeNode = upsertThemeNode(root);
      const existingKeyFrameNodes = themeNode.nodes?.filter(
        (node) => node.type === "atrule" && node.name === "keyframes"
      );
      const keyframeValueSchema = z5.record(
        z5.string(),
        z5.record(z5.string(), z5.string())
      );
      for (const [keyframeName, keyframeValue] of Object.entries(
        tailwindConfig.theme.extend.keyframes
      )) {
        if (typeof keyframeName !== "string") {
          continue;
        }
        const parsedKeyframeValue = keyframeValueSchema.safeParse(keyframeValue);
        if (!parsedKeyframeValue.success) {
          continue;
        }
        if (existingKeyFrameNodes?.find(
          (node) => node.type === "atrule" && node.name === "keyframes" && node.params === keyframeName
        )) {
          continue;
        }
        const keyframeNode = postcss2.atRule({
          name: "keyframes",
          params: keyframeName,
          nodes: [],
          raws: { semicolon: true, between: " ", before: "\n  " }
        });
        for (const [key, values] of Object.entries(parsedKeyframeValue.data)) {
          const rule = postcss2.rule({
            selector: key,
            nodes: Object.entries(values).map(
              ([key2, value]) => postcss2.decl({
                prop: key2,
                value,
                raws: { semicolon: true, before: "\n      ", between: ": " }
              })
            ),
            raws: { semicolon: true, between: " ", before: "\n    " }
          });
          keyframeNode.append(rule);
        }
        themeNode.append(keyframeNode);
        themeNode.insertBefore(
          keyframeNode,
          postcss2.comment({ text: "---break---" })
        );
      }
    }
  };
}
function updateTailwindConfigAnimationPlugin(tailwindConfig) {
  return {
    postcssPlugin: "update-tailwind-config-animation",
    Once(root) {
      if (!tailwindConfig?.theme?.extend?.animation) {
        return;
      }
      const themeNode = upsertThemeNode(root);
      const existingAnimationNodes = themeNode.nodes?.filter(
        (node) => node.type === "decl" && node.prop.startsWith("--animate-")
      );
      const parsedAnimationValue = z5.record(z5.string(), z5.string()).safeParse(tailwindConfig.theme.extend.animation);
      if (!parsedAnimationValue.success) {
        return;
      }
      for (const [key, value] of Object.entries(parsedAnimationValue.data)) {
        const prop = `--animate-${key}`;
        if (existingAnimationNodes?.find(
          (node) => node.prop === prop
        )) {
          continue;
        }
        const animationNode = postcss2.decl({
          prop,
          value,
          raws: { semicolon: true, between: ": ", before: "\n  " }
        });
        themeNode.append(animationNode);
      }
    }
  };
}
function getQuoteType(root) {
  const firstNode = root.nodes[0];
  const raw = firstNode.toString();
  if (raw.includes("'")) {
    return "single";
  }
  return "double";
}
function isLocalHSLValue(value) {
  if (value.startsWith("hsl") || value.startsWith("rgb") || value.startsWith("#") || value.startsWith("oklch")) {
    return false;
  }
  const chunks = value.split(" ");
  return chunks.length === 3 && chunks.slice(1, 3).every((chunk) => chunk.includes("%"));
}
function isColorValue(value) {
  return value.startsWith("hsl") || value.startsWith("rgb") || value.startsWith("#") || value.startsWith("oklch");
}

// src/utils/updaters/update-dependencies.ts
import { addDependency } from "nypm";
async function updateDependencies(dependencies, config, options) {
  dependencies = Array.from(new Set(dependencies));
  if (!dependencies?.length) {
    return;
  }
  options = {
    silent: false,
    ...options
  };
  const dependenciesSpinner = spinner(`Installing dependencies.`, { silent: options.silent })?.start();
  dependenciesSpinner?.start();
  await addDependency(dependencies, { cwd: config.resolvedPaths.cwd });
  dependenciesSpinner?.succeed();
}

// src/utils/updaters/update-files.ts
import { existsSync, promises as fs7 } from "node:fs";
import { tmpdir as tmpdir2 } from "node:os";

// src/utils/transformers/transform-css-vars.ts
function transformCssVars2(opts) {
  return {
    type: "codemod",
    name: "add prefix to tailwind classes",
    transform({ scriptASTs, sfcAST, utils: { traverseScriptAST, traverseTemplateAST } }) {
      let transformCount = 0;
      const { baseColor, config } = opts;
      if (config.tailwind?.cssVariables || !baseColor?.inlineColors)
        return transformCount;
      for (const scriptAST of scriptASTs) {
        traverseScriptAST(scriptAST, {
          visitLiteral(path20) {
            if (path20.parent.value.type !== "ImportDeclaration" && typeof path20.node.value === "string") {
              path20.node.value = applyColorMapping(path20.node.value.replace(/"/g, ""), baseColor.inlineColors);
              transformCount++;
            }
            return this.traverse(path20);
          }
        });
      }
      if (sfcAST) {
        traverseTemplateAST(sfcAST, {
          enterNode(node) {
            if (node.type === "Literal" && typeof node.value === "string") {
              if (!["BinaryExpression", "Property"].includes(node.parent?.type ?? "")) {
                node.value = applyColorMapping(node.value.replace(/"/g, ""), baseColor.inlineColors);
                transformCount++;
              }
            } else if (node.type === "VLiteral" && typeof node.value === "string") {
              if (node.parent.key.name === "class") {
                node.value = `"${applyColorMapping(node.value.replace(/"/g, ""), baseColor.inlineColors)}"`;
                transformCount++;
              }
            }
          },
          leaveNode() {
          }
        });
      }
      return transformCount;
    }
  };
}
function splitClassName(className) {
  if (!className.includes("/") && !className.includes(":"))
    return [null, className, null];
  const parts = [];
  const [rest, alpha] = className.split("/");
  if (!rest.includes(":"))
    return [null, rest, alpha];
  const split = rest.split(":");
  const name = split.pop();
  const variant = split.join(":");
  parts.push(variant ?? null, name ?? null, alpha ?? null);
  return parts;
}
var PREFIXES = ["bg-", "text-", "border-", "ring-offset-", "ring-"];
function applyColorMapping(input, mapping) {
  if (input.includes(" border "))
    input = input.replace(" border ", " border border-border ");
  const classNames = input.split(" ");
  const lightMode = /* @__PURE__ */ new Set();
  const darkMode = /* @__PURE__ */ new Set();
  for (const className of classNames) {
    const [variant, value, modifier] = splitClassName(className);
    const prefix = PREFIXES.find((prefix2) => value?.startsWith(prefix2));
    if (!prefix) {
      if (!lightMode.has(className))
        lightMode.add(className);
      continue;
    }
    const needle = value?.replace(prefix, "");
    if (needle && needle in mapping.light) {
      lightMode.add(
        [variant, `${prefix}${mapping.light[needle]}`].filter(Boolean).join(":") + (modifier ? `/${modifier}` : "")
      );
      darkMode.add(
        ["dark", variant, `${prefix}${mapping.dark[needle]}`].filter(Boolean).join(":") + (modifier ? `/${modifier}` : "")
      );
      continue;
    }
    if (!lightMode.has(className))
      lightMode.add(className);
  }
  return [...Array.from(lightMode), ...Array.from(darkMode)].join(" ").trim();
}

// src/utils/transformers/transform-import.ts
function transformImport(opts) {
  return {
    type: "codemod",
    name: "modify import based on user config",
    transform({ scriptASTs, utils: { traverseScriptAST } }) {
      const transformCount = 0;
      const { config } = opts;
      for (const scriptAST of scriptASTs) {
        traverseScriptAST(scriptAST, {
          visitImportDeclaration(path20) {
            if (typeof path20.node.source.value === "string") {
              const sourcePath = path20.node.source.value;
              if (sourcePath.startsWith("@/registry/")) {
                if (config.aliases.ui) {
                  path20.node.source.value = sourcePath.replace(/^@\/registry\/[^/]+\/ui/, config.aliases.ui);
                } else {
                  path20.node.source.value = sourcePath.replace(/^@\/registry\/[^/]+/, config.aliases.components);
                }
              }
              if (sourcePath === "@/lib/utils") {
                const namedImports = path20.node.specifiers?.map((node) => node.local?.name ?? "") ?? [];
                const cnImport = namedImports.find((i) => i === "cn");
                if (cnImport) {
                  path20.node.source.value = sourcePath.replace(/^@\/lib\/utils/, config.aliases.utils);
                }
              }
            }
            return this.traverse(path20);
          }
        });
      }
      return transformCount;
    }
  };
}

// src/utils/transformers/transform-sfc.ts
import { transform } from "@unovue/detypes";
async function transformSFC(opts) {
  if (opts.config?.typescript)
    return opts.raw;
  return await transformByDetype(opts.raw, opts.filename).then((res) => res);
}
async function transformByDetype(content, filename) {
  return await transform(content, filename, {
    removeTsComments: true,
    prettierOptions: {
      proseWrap: "never"
    }
  });
}

// src/utils/transformers/transform-tw-prefix.ts
function transformTwPrefix(opts) {
  return {
    type: "codemod",
    name: "add prefix to tailwind classes",
    transform({ scriptASTs, sfcAST, utils: { traverseScriptAST, traverseTemplateAST, astHelpers } }) {
      let transformCount = 0;
      const { config } = opts;
      const CLASS_IDENTIFIER = ["class", "classes"];
      if (!config.tailwind?.prefix)
        return transformCount;
      for (const scriptAST of scriptASTs) {
        traverseScriptAST(scriptAST, {
          visitCallExpression(path20) {
            if (path20.node.callee.type === "Identifier" && path20.node.callee.name === "cva") {
              const nodes = path20.node.arguments;
              nodes.forEach((node) => {
                if (node.type === "Literal" && typeof node.value === "string") {
                  node.value = applyPrefix(node.value, config.tailwind.prefix);
                  transformCount++;
                } else if (node.type === "ObjectExpression") {
                  node.properties.forEach((node2) => {
                    if (node2.type === "Property" && node2.key.type === "Identifier" && node2.key.name === "variants") {
                      const nodes2 = astHelpers.findAll(node2, { type: "Literal" });
                      nodes2.forEach((node3) => {
                        if (typeof node3.value === "string") {
                          node3.value = applyPrefix(node3.value, config.tailwind.prefix);
                          transformCount++;
                        }
                      });
                    }
                  });
                }
              });
            }
            return this.traverse(path20);
          }
        });
      }
      if (sfcAST) {
        traverseTemplateAST(sfcAST, {
          enterNode(node) {
            if (node.type === "VAttribute" && node.key.type === "VDirectiveKey") {
              if (node.key.argument?.type === "VIdentifier") {
                if (CLASS_IDENTIFIER.includes(node.key.argument.name)) {
                  const nodes = astHelpers.findAll(node, { type: "Literal" });
                  nodes.forEach((node2) => {
                    if (!["BinaryExpression", "Property"].includes(node2.parent?.type ?? "") && typeof node2.value === "string") {
                      node2.value = applyPrefix(node2.value, config.tailwind.prefix);
                      transformCount++;
                    }
                  });
                }
              }
            } else if (node.type === "VLiteral" && typeof node.value === "string") {
              if (CLASS_IDENTIFIER.includes(node.parent.key.name)) {
                node.value = `"${applyPrefix(node.value.replace(/"/g, ""), config.tailwind.prefix)}"`;
                transformCount++;
              }
            }
          },
          leaveNode() {
          }
        });
      }
      return transformCount;
    }
  };
}
function applyPrefix(input, prefix = "") {
  const classNames = input.split(" ");
  const prefixed = [];
  for (const className of classNames) {
    const [variant, value, modifier] = splitClassName(className);
    if (variant) {
      modifier ? prefixed.push(`${variant}:${prefix}${value}/${modifier}`) : prefixed.push(`${variant}:${prefix}${value}`);
    } else {
      modifier ? prefixed.push(`${prefix}${value}/${modifier}`) : prefixed.push(`${prefix}${value}`);
    }
  }
  return prefixed.join(" ");
}

// src/utils/transformers/index.ts
import { transform as metaTransform } from "vue-metamorph";

// src/utils/icon-libraries.ts
var ICON_LIBRARIES = {
  lucide: {
    name: "lucide-vue-next",
    package: "lucide-vue-next",
    import: "lucide-vue-next"
  },
  radix: {
    name: "@radix-icons/vue",
    package: "@radix-icons/vue",
    import: "@radix-icons/vue"
  }
};

// src/utils/transformers/transform-icons.ts
var SOURCE_LIBRARY = "lucide";
function transformIcons(opts, registryIcons) {
  return {
    type: "codemod",
    name: "modify import of icon library on user config",
    transform({ scriptASTs, sfcAST, utils: { traverseScriptAST, traverseTemplateAST } }) {
      let transformCount = 0;
      const { config } = opts;
      if (!config.iconLibrary || !(config.iconLibrary in ICON_LIBRARIES)) {
        return transformCount;
      }
      const sourceLibrary = SOURCE_LIBRARY;
      const targetLibrary = config.iconLibrary;
      if (sourceLibrary === targetLibrary) {
        return transformCount;
      }
      const targetedIconsMap = /* @__PURE__ */ new Map();
      for (const scriptAST of scriptASTs) {
        traverseScriptAST(scriptAST, {
          visitImportDeclaration(path20) {
            if (![ICON_LIBRARIES.radix.import, ICON_LIBRARIES.lucide.import].includes(`${path20.node.source.value}`))
              return this.traverse(path20);
            for (const specifier of path20.node.specifiers ?? []) {
              if (specifier.type === "ImportSpecifier") {
                const iconName = specifier.imported.name;
                const targetedIcon = registryIcons[iconName]?.[targetLibrary];
                if (!targetedIcon || targetedIconsMap.has(targetedIcon)) {
                  continue;
                }
                targetedIconsMap.set(iconName, targetedIcon);
                specifier.imported.name = targetedIcon;
              }
            }
            if (targetedIconsMap.size > 0)
              path20.node.source.value = ICON_LIBRARIES[targetLibrary].import;
            return this.traverse(path20);
          }
        });
        if (sfcAST) {
          traverseTemplateAST(sfcAST, {
            enterNode(node) {
              if (node.type === "VElement" && targetedIconsMap.has(node.rawName)) {
                node.rawName = targetedIconsMap.get(node.rawName) ?? "";
                transformCount++;
              }
            }
          });
        }
      }
      return transformCount;
    }
  };
}

// src/utils/transformers/index.ts
async function transform2(opts) {
  const source = await transformSFC(opts);
  const registryIcons = await getRegistryIcons();
  return metaTransform(source, opts.filename, [
    transformImport(opts),
    transformCssVars2(opts),
    transformTwPrefix(opts),
    transformIcons(opts, registryIcons)
  ]).code;
}

// src/utils/updaters/update-files.ts
import path9, { basename, dirname } from "pathe";
import prompts from "prompts";
function resolveTargetDir(projectInfo, config, target) {
  if (target.startsWith("~/")) {
    return path9.join(config.resolvedPaths.cwd, target.replace("~/", ""));
  }
  return path9.join(config.resolvedPaths.cwd, target);
}
async function updateFiles(files, config, options) {
  if (!files?.length) {
    return;
  }
  options = {
    overwrite: false,
    force: false,
    silent: false,
    ...options
  };
  const filesCreatedSpinner = spinner(`Updating files.`, {
    silent: options.silent
  })?.start();
  const [projectInfo, baseColor] = await Promise.all([
    getProjectInfo(config.resolvedPaths.cwd),
    getRegistryBaseColor(config.tailwind.baseColor)
  ]);
  const filesCreated = [];
  const filesUpdated = [];
  const folderSkipped = /* @__PURE__ */ new Map();
  const filesSkipped = [];
  let tempRoot = "";
  if (!config.typescript) {
    for (const file of files) {
      if (!file.content) {
        continue;
      }
      const dirName = path9.dirname(file.path);
      tempRoot = path9.join(tmpdir2(), "shadcn-vue");
      const tempDir = path9.join(tempRoot, "registry", config.style, dirName);
      const tempPath = path9.join(tempRoot, "registry", config.style, file.path);
      await fs7.mkdir(tempDir, { recursive: true });
      await fs7.writeFile(tempPath, file.content, "utf-8");
    }
    await fs7.cp(path9.join(process.cwd(), "node_modules"), tempRoot, { recursive: true });
    await fs7.writeFile(path9.join(tempRoot, "tsconfig.json"), `{
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@/*": ["./*"]
    },
  },
  "include": ["**/*.vue", "**/*.ts"],
  "exclude": ["node_modules"]
}`, "utf8");
  }
  for (const file of files) {
    if (!file.content) {
      continue;
    }
    let targetDir = getRegistryItemFileTargetPath(file, config);
    const fileName = basename(file.path);
    let filePath = path9.join(targetDir, fileName);
    if (file.target) {
      filePath = resolveTargetDir(projectInfo, config, file.target);
      targetDir = path9.dirname(filePath);
    }
    if (!config.typescript) {
      filePath = filePath.replace(/\.ts?$/, (match) => ".js");
    }
    const existingFile = existsSync(filePath);
    if (file.type === "registry:ui") {
      const folderName = basename(dirname(filePath));
      const existingFolder = existsSync(dirname(filePath));
      if (!existingFolder) {
        folderSkipped.set(folderName, false);
      }
      if (!folderSkipped.has(folderName) && !options.overwrite) {
        filesCreatedSpinner.stop();
        const { overwrite } = await prompts({
          type: "confirm",
          name: "overwrite",
          message: `The folder ${highlighter.info(folderName)} already exists. Would you like to overwrite?`,
          initial: false
        });
        folderSkipped.set(folderName, !overwrite);
        filesCreatedSpinner?.start();
      }
      if (folderSkipped.get(folderName) === true) {
        filesSkipped.push(path9.relative(config.resolvedPaths.cwd, filePath));
        continue;
      }
    } else {
      if (existingFile && !options.overwrite) {
        filesCreatedSpinner.stop();
        const { overwrite } = await prompts({
          type: "confirm",
          name: "overwrite",
          message: `The file ${highlighter.info(
            fileName
          )} already exists. Would you like to overwrite?`,
          initial: false
        });
        if (!overwrite) {
          filesSkipped.push(path9.relative(config.resolvedPaths.cwd, filePath));
          continue;
        }
        filesCreatedSpinner?.start();
      }
    }
    if (!existsSync(targetDir)) {
      await fs7.mkdir(targetDir, { recursive: true });
    }
    const content = await transform2({
      filename: path9.join(tempRoot, "registry", config.style, file.path),
      raw: file.content,
      config,
      baseColor
    });
    await fs7.writeFile(filePath, content, "utf-8");
    existingFile ? filesUpdated.push(path9.relative(config.resolvedPaths.cwd, filePath)) : filesCreated.push(path9.relative(config.resolvedPaths.cwd, filePath));
  }
  if (tempRoot) {
    await fs7.rm(tempRoot, { recursive: true });
  }
  const hasUpdatedFiles = filesCreated.length || filesUpdated.length;
  if (!hasUpdatedFiles && !filesSkipped.length) {
    filesCreatedSpinner?.info("No files updated.");
  }
  if (filesCreated.length) {
    filesCreatedSpinner?.succeed(
      `Created ${filesCreated.length} ${filesCreated.length === 1 ? "file" : "files"}:`
    );
    if (!options.silent) {
      for (const file of filesCreated) {
        logger.log(`  - ${file}`);
      }
    }
  } else {
    filesCreatedSpinner?.stop();
  }
  if (filesUpdated.length) {
    spinner(
      `Updated ${filesUpdated.length} ${filesUpdated.length === 1 ? "file" : "files"}:`,
      {
        silent: options.silent
      }
    )?.info();
    if (!options.silent) {
      for (const file of filesUpdated) {
        logger.log(`  - ${file}`);
      }
    }
  }
  if (filesSkipped.length) {
    spinner(
      `Skipped ${filesSkipped.length} ${filesUpdated.length === 1 ? "file" : "files"}:`,
      {
        silent: options.silent
      }
    )?.info();
    if (!options.silent) {
      for (const file of filesSkipped) {
        logger.log(`  - ${file}`);
      }
    }
  }
  if (!options.silent) {
    logger.break();
  }
}

// src/utils/add-components.ts
import { z as z6 } from "zod";
async function addComponents(components, config, options) {
  options = {
    overwrite: false,
    silent: false,
    isNewProject: false,
    style: "index",
    ...options
  };
  return await addProjectComponents(components, config, options);
}
async function addProjectComponents(components, config, options) {
  const registrySpinner = spinner(`Checking registry.`, {
    silent: options.silent
  })?.start();
  const tree = await registryResolveItemsTree(components, config);
  if (!tree) {
    registrySpinner?.fail();
    return handleError(new Error("Failed to fetch components from registry."));
  }
  registrySpinner?.succeed();
  const tailwindVersion = await getProjectTailwindVersionFromConfig(config);
  await updateTailwindConfig(tree.tailwind?.config, config, {
    silent: options.silent,
    tailwindVersion
  });
  const overwriteCssVars = await shouldOverwriteCssVars(components, config);
  await updateCssVars(tree.cssVars, config, {
    cleanupDefaultNextStyles: options.isNewProject,
    silent: options.silent,
    tailwindVersion,
    tailwindConfig: tree.tailwind?.config,
    overwriteCssVars,
    initIndex: options.style ? options.style === "index" : false
  });
  await updateCss(tree.css, config, {
    silent: options.silent
  });
  await updateDependencies(tree.dependencies, config, {
    silent: options.silent
  });
  await updateFiles(tree.files, config, {
    overwrite: options.overwrite,
    silent: options.silent
  });
  if (tree.docs) {
    logger.info(tree.docs);
  }
}
async function shouldOverwriteCssVars(components, config) {
  const registryItems = await resolveRegistryItems(components, config);
  const result = await fetchRegistry(registryItems);
  const payload = z6.array(registryItemSchema).parse(result);
  return payload.some(
    (component) => component.type === "registry:theme" || component.type === "registry:style"
  );
}

// src/utils/updaters/update-tailwind-content.ts
import { promises as fs8 } from "node:fs";
import path10 from "pathe";
import { SyntaxKind as SyntaxKind2 } from "ts-morph";
async function updateTailwindContent(content, config, options) {
  if (!content) {
    return;
  }
  options = {
    silent: false,
    ...options
  };
  const tailwindFileRelativePath = path10.relative(
    config.resolvedPaths.cwd,
    config.resolvedPaths.tailwindConfig
  );
  const tailwindSpinner = spinner(
    `Updating ${highlighter.info(tailwindFileRelativePath)}`,
    {
      silent: options.silent
    }
  ).start();
  const raw = await fs8.readFile(config.resolvedPaths.tailwindConfig, "utf8");
  const output = await transformTailwindContent(raw, content, config);
  await fs8.writeFile(config.resolvedPaths.tailwindConfig, output, "utf8");
  tailwindSpinner?.succeed();
}
async function transformTailwindContent(input, content, config) {
  const sourceFile = await _createSourceFile(input, config);
  const configObject = sourceFile.getDescendantsOfKind(SyntaxKind2.ObjectLiteralExpression).find(
    (node) => node.getProperties().some(
      (property) => property.isKind(SyntaxKind2.PropertyAssignment) && property.getName() === "content"
    )
  );
  if (!configObject) {
    return input;
  }
  addTailwindConfigContent(configObject, content);
  return sourceFile.getFullText();
}
async function addTailwindConfigContent(configObject, content) {
  const quoteChar = _getQuoteChar(configObject);
  const existingProperty = configObject.getProperty("content");
  if (!existingProperty) {
    const newProperty = {
      name: "content",
      initializer: `[${quoteChar}${content.join(
        `${quoteChar}, ${quoteChar}`
      )}${quoteChar}]`
    };
    configObject.addPropertyAssignment(newProperty);
    return configObject;
  }
  if (existingProperty.isKind(SyntaxKind2.PropertyAssignment)) {
    const initializer = existingProperty.getInitializer();
    if (initializer?.isKind(SyntaxKind2.ArrayLiteralExpression)) {
      for (const contentItem of content) {
        const newValue = `${quoteChar}${contentItem}${quoteChar}`;
        if (initializer.getElements().map((element) => element.getText()).includes(newValue)) {
          continue;
        }
        initializer.addElement(newValue);
      }
    }
    return configObject;
  }
  return configObject;
}

// src/commands/init.ts
import { Command } from "commander";
import path11 from "pathe";
import prompts2 from "prompts";
import { z as z7 } from "zod";
var initOptionsSchema = z7.object({
  cwd: z7.string(),
  components: z7.array(z7.string()).optional(),
  yes: z7.boolean(),
  defaults: z7.boolean(),
  force: z7.boolean(),
  silent: z7.boolean(),
  isNewProject: z7.boolean(),
  srcDir: z7.boolean().optional(),
  cssVariables: z7.boolean(),
  baseColor: z7.string().optional().refine(
    (val) => {
      if (val) {
        return BASE_COLORS.find((color) => color.name === val);
      }
      return true;
    },
    {
      message: `Invalid base color. Please use '${BASE_COLORS.map(
        (color) => color.name
      ).join("', '")}'`
    }
  ),
  style: z7.string()
});
var init = new Command().name("init").description("initialize your project and install dependencies").argument(
  "[components...]",
  "the components to add or a url to the component."
).option("-y, --yes", "skip confirmation prompt.", true).option("-d, --defaults,", "use default configuration.", false).option("-f, --force", "force overwrite of existing configuration.", false).option(
  "-c, --cwd <cwd>",
  "the working directory. defaults to the current directory.",
  process.cwd()
).option("-s, --silent", "mute output.", false).option("--css-variables", "use css variables for theming.", true).option("--no-css-variables", "do not use css variables for theming.").action(async (components, opts) => {
  try {
    const options = initOptionsSchema.parse({
      cwd: path11.resolve(opts.cwd),
      isNewProject: false,
      components,
      style: "index",
      ...opts
    });
    if (components.length > 0 && isUrl(components[0])) {
      const item = await getRegistryItem(components[0], "");
      if (item?.type === "registry:style") {
        options.baseColor = "neutral";
        options.style = item.extends ?? "index";
      }
    }
    await runInit(options);
    logger.log(
      `${highlighter.success(
        "Success!"
      )} Project initialization completed.
You may now add components.`
    );
    logger.break();
  } catch (error) {
    logger.break();
    handleError(error);
  }
});
async function runInit(options) {
  let projectInfo;
  if (!options.skipPreflight) {
    const preflight = await preFlightInit(options);
    if (preflight.errors[MISSING_DIR_OR_EMPTY_PROJECT]) {
      process.exit(1);
    }
    projectInfo = preflight.projectInfo;
  } else {
    projectInfo = await getProjectInfo(options.cwd);
  }
  const projectConfig = await getProjectConfig(options.cwd, projectInfo);
  const config = projectConfig ? await promptForMinimalConfig(projectConfig, options) : await promptForConfig(await getConfig(options.cwd));
  if (!options.yes) {
    const { proceed } = await prompts2({
      type: "confirm",
      name: "proceed",
      message: `Write configuration to ${highlighter.info(
        "components.json"
      )}. Proceed?`,
      initial: true
    });
    if (!proceed) {
      process.exit(0);
    }
  }
  const componentSpinner = spinner(`Writing components.json.`).start();
  const targetPath = path11.resolve(options.cwd, "components.json");
  await fs9.writeFile(targetPath, JSON.stringify(config, null, 2), "utf8");
  componentSpinner.succeed();
  const fullConfig = await resolveConfigPaths(options.cwd, config);
  const components = [
    ...options.style === "none" ? [] : [options.style],
    ...options.components ?? []
  ];
  await addComponents(components, fullConfig, {
    // Init will always overwrite files.
    overwrite: true,
    silent: options.silent,
    style: options.style,
    isNewProject: options.isNewProject || projectInfo?.framework.name === "nuxt"
  });
  if (options.isNewProject && options.srcDir) {
    await updateTailwindContent(
      ["./src/**/*.{js,ts,jsx,tsx,mdx}"],
      fullConfig,
      {
        silent: options.silent
      }
    );
  }
  return fullConfig;
}
async function promptForConfig(defaultConfig = null) {
  const [styles, baseColors] = await Promise.all([
    getRegistryStyles(),
    getRegistryBaseColors()
  ]);
  logger.info("");
  const options = await prompts2([
    {
      type: "toggle",
      name: "typescript",
      message: `Would you like to use ${highlighter.info(
        "TypeScript"
      )} (recommended)?`,
      initial: defaultConfig?.typescript ?? true,
      active: "yes",
      inactive: "no"
    },
    {
      type: "select",
      name: "style",
      message: `Which ${highlighter.info("style")} would you like to use?`,
      choices: styles.map((style) => ({
        title: style.name === "new-york" ? "New York (Recommended)" : style.label,
        value: style.name
      }))
    },
    {
      type: "select",
      name: "tailwindBaseColor",
      message: `Which color would you like to use as the ${highlighter.info(
        "base color"
      )}?`,
      choices: baseColors.map((color) => ({
        title: color.label,
        value: color.name
      }))
    },
    {
      type: "text",
      name: "tailwindCss",
      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 ${highlighter.info(
        "CSS variables"
      )} for theming?`,
      initial: defaultConfig?.tailwind.cssVariables ?? true,
      active: "yes",
      inactive: "no"
    },
    {
      type: "text",
      name: "tailwindPrefix",
      message: `Are you using a custom ${highlighter.info(
        "tailwind prefix eg. tw-"
      )}? (Leave blank if not)`,
      initial: ""
    },
    {
      type: "text",
      name: "tailwindConfig",
      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 ${highlighter.info(
        "components"
      )}:`,
      initial: defaultConfig?.aliases.components ?? DEFAULT_COMPONENTS
    },
    {
      type: "text",
      name: "utils",
      message: `Configure the import alias for ${highlighter.info("utils")}:`,
      initial: defaultConfig?.aliases.utils ?? DEFAULT_UTILS
    }
  ]);
  return rawConfigSchema.parse({
    $schema: "https://shadcn-vue.com/schema.json",
    style: options.style,
    tailwind: {
      config: options.tailwindConfig,
      css: options.tailwindCss,
      baseColor: options.tailwindBaseColor,
      cssVariables: options.tailwindCssVariables,
      prefix: options.tailwindPrefix
    },
    typescript: options.typescript,
    aliases: {
      utils: options.utils,
      components: options.components,
      // TODO: fix this.
      lib: options.components.replace(/\/components$/, "/lib"),
      composables: options.components.replace(/\/components$/, "/composables")
    }
  });
}
async function promptForMinimalConfig(defaultConfig, opts) {
  let style = defaultConfig.style;
  let baseColor = defaultConfig.tailwind.baseColor;
  let cssVariables = defaultConfig.tailwind.cssVariables;
  if (!opts.defaults) {
    const [styles, baseColors, tailwindVersion] = await Promise.all([
      getRegistryStyles(),
      getRegistryBaseColors(),
      getProjectTailwindVersionFromConfig(defaultConfig)
    ]);
    const options = await prompts2([
      {
        type: tailwindVersion === "v4" ? null : "select",
        name: "style",
        message: `Which ${highlighter.info("style")} would you like to use?`,
        choices: styles.map((style2) => ({
          title: style2.name === "new-york" ? "New York (Recommended)" : style2.label,
          value: style2.name
        })),
        initial: 0
      },
      {
        type: opts.baseColor ? null : "select",
        name: "tailwindBaseColor",
        message: `Which color would you like to use as the ${highlighter.info(
          "base color"
        )}?`,
        choices: baseColors.map((color) => ({
          title: color.label,
          value: color.name
        }))
      }
    ]);
    style = options.style ?? "new-york";
    baseColor = options.tailwindBaseColor ?? baseColor;
    cssVariables = opts.cssVariables;
  }
  return rawConfigSchema.parse({
    $schema: defaultConfig?.$schema,
    style,
    tailwind: {
      ...defaultConfig?.tailwind,
      baseColor,
      cssVariables
    },
    typescript: defaultConfig.typescript,
    aliases: defaultConfig?.aliases,
    iconLibrary: defaultConfig?.iconLibrary
  });
}

// src/preflights/preflight-add.ts
import fs10 from "fs-extra";
import path12 from "pathe";
async function preFlightAdd(options) {
  const errors = {};
  if (!fs10.existsSync(options.cwd) || !fs10.existsSync(path12.resolve(options.cwd, "package.json"))) {
    errors[MISSING_DIR_OR_EMPTY_PROJECT] = true;
    return {
      errors,
      config: null
    };
  }
  if (!fs10.existsSync(path12.resolve(options.cwd, "components.json"))) {
    errors[MISSING_CONFIG] = true;
    return {
      errors,
      config: null
    };
  }
  try {
    const config = await getConfig(options.cwd);
    return {
      errors,
      config
    };
  } catch (error) {
    logger.break();
    logger.error(
      `An invalid ${highlighter.info(
        "components.json"
      )} file was found at ${highlighter.info(
        options.cwd
      )}.
Before you can add components, you must create a valid ${highlighter.info(
        "components.json"
      )} file by running the ${highlighter.info("init")} command.`
    );
    logger.error(
      `Learn more at ${highlighter.info(
        "https://shadcn-vue.com/docs/components-json"
      )}.`
    );
    logger.break();
    process.exit(1);
  }
}

// src/commands/add.ts
import { Command as Command2 } from "commander";
import path13 from "pathe";
import prompts3 from "prompts";
import { z as z8 } from "zod";
var DEPRECATED_COMPONENTS = [
  {
    name: "toast",
    deprecatedBy: "sonner",
    message: "The toast component is deprecated. Use the sonner component instead."
  },
  {
    name: "toaster",
    deprecatedBy: "sonner",
    message: "The toaster component is deprecated. Use the sonner component instead."
  }
];
var addOptionsSchema = z8.object({
  components: z8.array(z8.string()).optional(),
  yes: z8.boolean(),
  overwrite: z8.boolean(),
  cwd: z8.string(),
  all: z8.boolean(),
  path: z8.string().optional(),
  silent: z8.boolean(),
  srcDir: z8.boolean().optional(),
  cssVariables: z8.boolean()
});
var add = new Command2().name("add").description("add a component to your project").argument(
  "[components...]",
  "the components to add or a url to the component."
).option("-y, --yes", "skip confirmation prompt.", false).option("-o, --overwrite", "overwrite existing files.", false).option(
  "-c, --cwd <cwd>",
  "the working directory. defaults to the current directory.",
  process.cwd()
).option("-a, --all", "add all available components", false).option("-p, --path <path>", "the path to add the component to.").option("-s, --silent", "mute output.", false).option(
  "--src-dir",
  "use the src directory when creating a new project.",
  false
).option("--css-variables", "use css variables for theming.", true).option("--no-css-variables", "do not use css variables for theming.").action(async (components, opts) => {
  try {
    const options = addOptionsSchema.parse({
      components,
      cwd: path13.resolve(opts.cwd),
      ...opts
    });
    const isTheme = options.components?.some(
      (component) => component.includes("theme-")
    );
    if (!options.yes && isTheme) {
      logger.break();
      const { confirm } = await prompts3({
        type: "confirm",
        name: "confirm",
        message: highlighter.warn(
          "You are about to install a new theme. \nExisting CSS variables will be overwritten. Continue?"
        )
      });
      if (!confirm) {
        logger.break();
        logger.log("Theme installation cancelled.");
        logger.break();
        process.exit(1);
      }
    }
    if (!options.components?.length) {
      options.components = await promptForRegistryComponents(options);
    }
    const projectInfo = await getProjectInfo(options.cwd);
    if (projectInfo?.tailwindVersion === "v4") {
      const deprecatedComponents = DEPRECATED_COMPONENTS.filter(
        (component) => options.components?.includes(component.name)
      );
      if (deprecatedComponents?.length) {
        logger.break();
        deprecatedComponents.forEach((component) => {
          logger.warn(highlighter.warn(component.message));
        });
        logger.break();
        process.exit(1);
      }
    }
    let { errors, config } = await preFlightAdd(options);
    if (errors[MISSING_CONFIG]) {
      const { proceed } = await prompts3({
        type: "confirm",
        name: "proceed",
        message: `You need to create a ${highlighter.info(
          "components.json"
        )} file to add components. Proceed?`,
        initial: true
      });
      if (!proceed) {
        logger.break();
        process.exit(1);
      }
      config = await runInit({
        cwd: options.cwd,
        yes: true,
        force: true,
        defaults: false,
        skipPreflight: false,
        silent: true,
        isNewProject: false,
        srcDir: options.srcDir,
        cssVariables: options.cssVariables,
        style: "index"
      });
    }
    if (!config) {
      throw new Error(
        `Failed to read config at ${highlighter.info(options.cwd)}.`
      );
    }
    await addComponents(options.components, config, options);
  } catch (error) {
    logger.break();
    handleError(error);
  }
});
async function promptForRegistryComponents(options) {
  const registryIndex = await getRegistryIndex();
  if (!registryIndex) {
    logger.break();
    handleError(new Error("Failed to fetch registry index."));
    return [];
  }
  if (options.all) {
    return registryIndex.map((entry) => entry.name).filter(
      (component) => !DEPRECATED_COMPONENTS.some((c) => c.name === component)
    );
  }
  if (options.components?.length) {
    return options.components;
  }
  const { components } = await prompts3({
    type: "multiselect",
    name: "components",
    message: "Which components would you like to add?",
    hint: "Space to select. A to toggle all. Enter to submit.",
    instructions: false,
    choices: registryIndex.filter(
      (entry) => entry.type === "registry:ui" && !DEPRECATED_COMPONENTS.some(
        (component) => component.name === entry.name
      )
    ).map((entry) => ({
      title: entry.name,
      value: entry.name,
      selected: options.all ? true : options.components?.includes(entry.name)
    }))
  });
  if (!components?.length) {
    logger.warn("No components selected. Exiting.");
    logger.info("");
    process.exit(1);
  }
  const result = z8.array(z8.string()).safeParse(components);
  if (!result.success) {
    logger.error("");
    handleError(new Error("Something went wrong. Please try again."));
    return [];
  }
  return result.data;
}

// src/commands/build.ts
import * as fs12 from "node:fs/promises";

// src/preflights/preflight-build.ts
import fs11 from "fs-extra";
import path14 from "pathe";
async function preFlightBuild(options) {
  const errors = {};
  const resolvePaths = {
    cwd: options.cwd,
    registryFile: path14.resolve(options.cwd, options.registryFile),
    outputDir: path14.resolve(options.cwd, options.outputDir)
  };
  if (!fs11.existsSync(resolvePaths.registryFile)) {
    errors[BUILD_MISSING_REGISTRY_FILE] = true;
  }
  await fs11.mkdir(resolvePaths.outputDir, { recursive: true });
  if (Object.keys(errors).length > 0) {
    if (errors[BUILD_MISSING_REGISTRY_FILE]) {
      logger.break();
      logger.error(
        `The path ${highlighter.info(
          resolvePaths.registryFile
        )} does not exist.`
      );
    }
    logger.break();
    process.exit(1);
  }
  return {
    errors,
    resolvePaths
  };
}

// src/commands/build.ts
import { Command as Command3 } from "commander";
import * as path15 from "pathe";
import { z as z9 } from "zod";
var buildOptionsSchema = z9.object({
  cwd: z9.string(),
  registryFile: z9.string(),
  outputDir: z9.string()
});
var build = new Command3().name("build").description("build components for a shadcn registry").argument("[registry]", "path to registry.json file", "./registry.json").option(
  "-o, --output <path>",
  "destination directory for json files",
  "./public/r"
).option(
  "-c, --cwd <cwd>",
  "the working directory. defaults to the current directory.",
  process.cwd()
).action(async (registry, opts) => {
  try {
    const options = buildOptionsSchema.parse({
      cwd: path15.resolve(opts.cwd),
      registryFile: registry,
      outputDir: opts.output
    });
    const { resolvePaths } = await preFlightBuild(options);
    const content = await fs12.readFile(resolvePaths.registryFile, "utf-8");
    const result = registrySchema.safeParse(JSON.parse(content));
    if (!result.success) {
      logger.error(
        `Invalid registry file found at ${highlighter.info(
          resolvePaths.registryFile
        )}.`
      );
      process.exit(1);
    }
    const buildSpinner = spinner("Building registry...");
    for (const registryItem of result.data.items) {
      if (!registryItem.files) {
        continue;
      }
      buildSpinner.start(`Building ${registryItem.name}...`);
      registryItem.$schema = "https://shadcn-vue.com/schema/registry-item.json";
      for (const file of registryItem.files) {
        file.content = await fs12.readFile(
          path15.resolve(resolvePaths.cwd, file.path),
          "utf-8"
        );
      }
      const result2 = registryItemSchema.safeParse(registryItem);
      if (!result2.success) {
        logger.error(
          `Invalid registry item found for ${highlighter.info(
            registryItem.name
          )}.`
        );
        continue;
      }
      await fs12.writeFile(
        path15.resolve(resolvePaths.outputDir, `${result2.data.name}.json`),
        JSON.stringify(result2.data, null, 2)
      );
    }
    buildSpinner.succeed("Building registry.");
  } catch (error) {
    logger.break();
    handleError(error);
  }
});

// src/commands/diff.ts
import { existsSync as existsSync2, promises as fs13 } from "node:fs";
import { Command as Command4 } from "commander";
import { diffLines } from "diff";
import path16 from "pathe";
import { z as z10 } from "zod";
var updateOptionsSchema = z10.object({
  component: z10.string().optional(),
  yes: z10.boolean(),
  cwd: z10.string(),
  path: z10.string().optional()
});
var diff = new Command4().name("diff").description("check for updates against the registry").argument("[component]", "the component name").option("-y, --yes", "skip confirmation prompt.", false).option(
  "-c, --cwd <cwd>",
  "the working directory. defaults to the current directory.",
  process.cwd()
).action(async (name, opts) => {
  try {
    const options = updateOptionsSchema.parse({
      component: name,
      ...opts
    });
    const cwd = path16.resolve(options.cwd);
    if (!existsSync2(cwd)) {
      logger.error(`The path ${cwd} does not exist. Please try again.`);
      process.exit(1);
    }
    const config = await getConfig(cwd);
    if (!config) {
      logger.warn(
        `Configuration is missing. Please run ${highlighter.success(
          `init`
        )} to create a components.json file.`
      );
      process.exit(1);
    }
    const registryIndex = await getRegistryIndex();
    if (!registryIndex) {
      handleError(new Error("Failed to fetch registry index."));
      process.exit(1);
    }
    if (!options.component) {
      const targetDir = config.resolvedPaths.components;
      const projectComponents = registryIndex.filter((item) => {
        for (const file of item.files ?? []) {
          const filePath = path16.resolve(
            targetDir,
            typeof file === "string" ? file : file.path
          );
          if (existsSync2(filePath)) {
            return true;
          }
        }
        return false;
      });
      const componentsWithUpdates = [];
      for (const component2 of projectComponents) {
        const changes2 = await diffComponent(component2, config);
        if (changes2.length) {
          componentsWithUpdates.push({
            name: component2.name,
            changes: changes2
          });
        }
      }
      if (!componentsWithUpdates.length) {
        logger.info("No updates found.");
        process.exit(0);
      }
      logger.info("The following components have updates available:");
      for (const component2 of componentsWithUpdates) {
        logger.info(`- ${component2.name}`);
        for (const change of component2.changes) {
          logger.info(`  - ${change.filePath}`);
        }
      }
      logger.break();
      logger.info(
        `Run ${highlighter.success(`diff <component>`)} to see the changes.`
      );
      process.exit(0);
    }
    const component = registryIndex.find(
      (item) => item.name === options.component
    );
    if (!component) {
      logger.error(
        `The component ${highlighter.success(
          options.component
        )} does not exist.`
      );
      process.exit(1);
    }
    const changes = await diffComponent(component, config);
    if (!changes.length) {
      logger.info(`No updates found for ${options.component}.`);
      process.exit(0);
    }
    for (const change of changes) {
      logger.info(`- ${change.filePath}`);
      await printDiff(change.patch);
      logger.info("");
    }
  } catch (error) {
    handleError(error);
  }
});
async function diffComponent(component, config) {
  const payload = await fetchTree(config.style, [component]);
  const baseColor = await getRegistryBaseColor(config.tailwind.baseColor);
  if (!payload) {
    return [];
  }
  const changes = [];
  for (const item of payload) {
    const targetDir = await getItemTargetPath(config, item);
    if (!targetDir) {
      continue;
    }
    for (const file of item.files ?? []) {
      const filePath = path16.resolve(
        targetDir,
        typeof file === "string" ? file : file.path
      );
      if (!existsSync2(filePath)) {
        continue;
      }
      const fileContent = await fs13.readFile(filePath, "utf8");
      if (typeof file === "string" || !file.content) {
        continue;
      }
      const registryContent = await transform2({
        filename: file.path,
        raw: file.content,
        config,
        baseColor
      });
      const patch = diffLines(registryContent, fileContent);
      if (patch.length > 1) {
        changes.push({
          filePath,
          patch
        });
      }
    }
  }
  return changes;
}
async function printDiff(diff2) {
  diff2.forEach((part) => {
    if (part) {
      if (part.added) {
        return process.stdout.write(highlighter.success(part.value));
      }
      if (part.removed) {
        return process.stdout.write(highlighter.error(part.value));
      }
      return process.stdout.write(part.value);
    }
  });
}

// src/commands/info.ts
import { Command as Command5 } from "commander";
import consola3 from "consola";
var info = new Command5().name("info").description("get information about your project").option(
  "-c, --cwd <cwd>",
  "the working directory. defaults to the current directory.",
  process.cwd()
).action(async (opts) => {
  logger.info("> project info");
  consola3.log(await getProjectInfo(opts.cwd));
  logger.break();
  logger.info("> components.json");
  consola3.log(await getConfig(opts.cwd));
});

// src/migrations/migrate-icons.ts
import { randomBytes } from "node:crypto";
import { promises as fs14 } from "node:fs";
import { tmpdir as tmpdir3 } from "node:os";
import path17 from "pathe";
import prompts4 from "prompts";
import { glob as glob2 } from "tinyglobby";
import { Project as Project2, ScriptKind as ScriptKind2, SyntaxKind as SyntaxKind3 } from "ts-morph";
async function migrateIcons(config) {
  if (!config.resolvedPaths.ui) {
    throw new Error(
      "We could not find a valid `ui` path in your `components.json` file. Please ensure you have a valid `ui` path in your `components.json` file."
    );
  }
  const uiPath = config.resolvedPaths.ui;
  const [files, registryIcons] = await Promise.all([
    glob2("**/*.{js,ts,jsx,tsx}", {
      cwd: uiPath
    }),
    getRegistryIcons()
  ]);
  if (Object.keys(registryIcons).length === 0) {
    throw new Error("Something went wrong fetching the registry icons.");
  }
  const libraryChoices = Object.entries(ICON_LIBRARIES).map(
    ([name, iconLibrary]) => ({
      title: iconLibrary.name,
      value: name
    })
  );
  const migrateOptions = await prompts4([
    {
      type: "select",
      name: "sourceLibrary",
      message: `Which icon library would you like to ${highlighter.info(
        "migrate from"
      )}?`,
      choices: libraryChoices
    },
    {
      type: "select",
      name: "targetLibrary",
      message: `Which icon library would you like to ${highlighter.info(
        "migrate to"
      )}?`,
      choices: libraryChoices
    }
  ]);
  if (migrateOptions.sourceLibrary === migrateOptions.targetLibrary) {
    throw new Error(
      "You cannot migrate to the same icon library. Please choose a different icon library."
    );
  }
  if (!(migrateOptions.sourceLibrary in ICON_LIBRARIES && migrateOptions.targetLibrary in ICON_LIBRARIES)) {
    throw new Error("Invalid icon library. Please choose a valid icon library.");
  }
  const sourceLibrary = ICON_LIBRARIES[migrateOptions.sourceLibrary];
  const targetLibrary = ICON_LIBRARIES[migrateOptions.targetLibrary];
  const { confirm } = await prompts4({
    type: "confirm",
    name: "confirm",
    initial: true,
    message: `We will migrate ${highlighter.info(
      files.length
    )} files in ${highlighter.info(
      `./${path17.relative(config.resolvedPaths.cwd, uiPath)}`
    )} from ${highlighter.info(sourceLibrary.name)} to ${highlighter.info(
      targetLibrary.name
    )}. Continue?`
  });
  if (!confirm) {
    logger.info("Migration cancelled.");
    process.exit(0);
  }
  if (targetLibrary.package) {
    await updateDependencies([targetLibrary.package], config, {
      silent: false
    });
  }
  const migrationSpinner = spinner(`Migrating icons...`)?.start();
  await Promise.all(
    files.map(async (file) => {
      migrationSpinner.text = `Migrating ${file}...`;
      const filePath = path17.join(uiPath, file);
      const fileContent = await fs14.readFile(filePath, "utf-8");
      const content = await migrateIconsFile(
        fileContent,
        migrateOptions.sourceLibrary,
        migrateOptions.targetLibrary,
        registryIcons
      );
      await fs14.writeFile(filePath, content);
    })
  );
  migrationSpinner.succeed("Migration complete.");
}
async function migrateIconsFile(content, sourceLibrary, targetLibrary, iconsMapping) {
  const sourceLibraryImport = ICON_LIBRARIES[sourceLibrary]?.import;
  const targetLibraryImport = ICON_LIBRARIES[targetLibrary]?.import;
  const dir = await fs14.mkdtemp(path17.join(tmpdir3(), "shadcn-"));
  const project = new Project2({
    compilerOptions: {}
  });
  const tempFile = path17.join(
    dir,
    `shadcn-icons-${randomBytes(4).toString("hex")}.tsx`
  );
  const sourceFile = project.createSourceFile(tempFile, content, {
    scriptKind: ScriptKind2.TSX
  });
  const targetedIcons = [];
  for (const importDeclaration of sourceFile.getImportDeclarations() ?? []) {
    if (importDeclaration.getModuleSpecifier()?.getText() !== `"${sourceLibraryImport}"`) {
      continue;
    }
    for (const specifier of importDeclaration.getNamedImports() ?? []) {
      const iconName = specifier.getName();
      const targetedIcon = Object.values(iconsMapping).find(
        (icon) => icon[sourceLibrary] === iconName
      )?.[targetLibrary];
      if (!targetedIcon || targetedIcons.includes(targetedIcon)) {
        continue;
      }
      targetedIcons.push(targetedIcon);
      specifier.remove();
      sourceFile.getDescendantsOfKind(SyntaxKind3.JsxSelfClosingElement).filter((node) => node.getTagNameNode()?.getText() === iconName).forEach((node) => node.getTagNameNode()?.replaceWithText(targetedIcon));
    }
    if (importDeclaration.getNamedImports()?.length === 0) {
      importDeclaration.remove();
    }
  }
  if (targetedIcons.length > 0) {
    sourceFile.addImportDeclaration({
      moduleSpecifier: targetLibraryImport,
      namedImports: targetedIcons.map((icon) => ({
        name: icon
      }))
    });
  }
  return await sourceFile.getText();
}

// src/preflights/preflight-migrate.ts
import fs15 from "fs-extra";
import path18 from "pathe";
async function preFlightMigrate(options) {
  const errors = {};
  if (!fs15.existsSync(options.cwd) || !fs15.existsSync(path18.resolve(options.cwd, "package.json"))) {
    errors[MISSING_DIR_OR_EMPTY_PROJECT] = true;
    return {
      errors,
      config: null
    };
  }
  if (!fs15.existsSync(path18.resolve(options.cwd, "components.json"))) {
    errors[MISSING_CONFIG] = true;
    return {
      errors,
      config: null
    };
  }
  try {
    const config = await getConfig(options.cwd);
    return {
      errors,
      config
    };
  } catch (error) {
    logger.break();
    logger.error(
      `An invalid ${highlighter.info(
        "components.json"
      )} file was found at ${highlighter.info(
        options.cwd
      )}.
Before you can run a migration, you must create a valid ${highlighter.info(
        "components.json"
      )} file by running the ${highlighter.info("init")} command.`
    );
    logger.error(
      `Learn more at ${highlighter.info(
        "https://shadcn-vue.com/docs/components-json"
      )}.`
    );
    logger.break();
    process.exit(1);
  }
}

// src/commands/migrate.ts
import { Command as Command6 } from "commander";
import consola4 from "consola";
import path19 from "pathe";
import { z as z11 } from "zod";
var migrations = [
  {
    name: "icons",
    description: "migrate your ui components to a different icon library."
  }
];
var migrateOptionsSchema = z11.object({
  cwd: z11.string(),
  list: z11.boolean(),
  migration: z11.string().refine(
    (value) => value && migrations.some((migration) => migration.name === value),
    {
      message: "You must specify a valid migration. Run `shadcn migrate --list` to see available migrations."
    }
  ).optional()
});
var migrate = new Command6().name("migrate").description("run a migration.").argument("[migration]", "the migration to run.").option(
  "-c, --cwd <cwd>",
  "the working directory. defaults to the current directory.",
  process.cwd()
).option("-l, --list", "list all migrations.", false).action(async (migration, opts) => {
  try {
    const options = migrateOptionsSchema.parse({
      cwd: path19.resolve(opts.cwd),
      migration,
      list: opts.list
    });
    if (options.list || !options.migration) {
      consola4.info("Available migrations:");
      for (const migration2 of migrations) {
        consola4.info(`- ${migration2.name}: ${migration2.description}`);
      }
      return;
    }
    if (!options.migration) {
      throw new Error(
        "You must specify a migration. Run `shadcn migrate --list` to see available migrations."
      );
    }
    const { errors, config } = await preFlightMigrate(options);
    if (errors[MISSING_DIR_OR_EMPTY_PROJECT] || errors[MISSING_CONFIG]) {
      throw new Error(
        "No `components.json` file found. Ensure you are at the root of your project."
      );
    }
    if (!config) {
      throw new Error(
        "Something went wrong reading your `components.json` file. Please ensure you have a valid `components.json` file."
      );
    }
    if (options.migration === "icons") {
      await migrateIcons(config);
    }
  } catch (error) {
    handleError(error);
  }
});

// src/index.ts
import { Command as Command7 } from "commander";

// package.json
var package_default = {
  name: "shadcn-vue",
  type: "module",
  version: "2.0.1",
  description: "Add components to your apps.",
  publishConfig: {
    access: "public"
  },
  license: "MIT",
  repository: {
    type: "git",
    url: "https://github.com/unovue/shadcn-vue.git",
    directory: "packages/cli"
  },
  keywords: [
    "components",
    "ui",
    "vue",
    "nuxt",
    "tailwind",
    "radix-ui",
    "radix-vue",
    "reka-ui",
    "shadcn",
    "shadcn-vue"
  ],
  exports: "./dist/index.js",
  bin: "./dist/index.js",
  files: [
    "dist"
  ],
  scripts: {
    dev: "tsup --watch",
    build: "tsup",
    typecheck: "tsc --noEmit",
    clean: "node ./scripts/rimraf.js",
    lint: "eslint .",
    "lint:fix": "eslint --fix .",
    "start:dev": "REGISTRY_URL=http://localhost:5173/r node dist/index.js",
    start: "node dist/index.js",
    release: "changeset version",
    "pub:beta": "pnpm build && pnpm publish --no-git-checks --access public --tag beta",
    "pub:next": "pnpm build && pnpm publish --no-git-checks --access public --tag next",
    "pub:release": "pnpm build && pnpm publish  --no-git-checks --access public",
    test: "vitest run",
    "test:update": "vitest run -u",
    "test:ui": "vitest --ui"
  },
  peerDependencies: {
    "@vitest/ui": "*",
    vitest: "*"
  },
  dependencies: {
    "@unovue/detypes": "^0.8.5",
    "@vue/compiler-sfc": "^3.5",
    commander: "^12.1.0",
    consola: "^3.4.0",
    cosmiconfig: "^9.0.0",
    deepmerge: "^4.3.1",
    diff: "^7.0.0",
    "fs-extra": "^11.3.0",
    "get-tsconfig": "^4.10.0",
    "lodash-es": "^4.17.21",
    "magic-string": "^0.30.17",
    nypm: "^0.5.2",
    ofetch: "^1.4.1",
    ora: "^8.2.0",
    pathe: "^2.0.3",
    "pkg-types": "^1.3.1",
    postcss: "^8.5.2",
    prompts: "^2.4.2",
    "reka-ui": "catalog:",
    "stringify-object": "^5.0.0",
    tailwindcss: "^3.4.16",
    tinyexec: "^0.3.2",
    tinyglobby: "^0.2.10",
    "ts-morph": "^24.0.0",
    undici: "^7.3.0",
    "vue-metamorph": "3.2.0",
    zod: "^3.24.2"
  },
  devDependencies: {
    "@types/diff": "^7.0.1",
    "@types/fs-extra": "^11.0.4",
    "@types/lodash-es": "^4.17.12",
    "@types/node": "^22.13.4",
    "@types/prompts": "^2.4.9",
    "@types/stringify-object": "^4.0.5",
    msw: "^2.7.3",
    tsup: "^8.3.6",
    "type-fest": "^4.34.1",
    typescript: "catalog:"
  }
};

// src/index.ts
process.on("SIGINT", () => process.exit(0));
process.on("SIGTERM", () => process.exit(0));
async function main() {
  const program = new Command7().name("shadcn-vue").description("add components and dependencies to your project").version(
    package_default.version || "1.0.0",
    "-v, --version",
    "display the version number"
  );
  program.addCommand(init).addCommand(add).addCommand(diff).addCommand(migrate).addCommand(info).addCommand(build);
  program.parse();
}
main();
//# sourceMappingURL=index.js.map