Skip to content

Commit

Permalink
next: update registry to support pages/hooks/components (#1340)
Browse files Browse the repository at this point in the history
Co-authored-by: AdrianGonz97 <31664583+AdrianGonz97@users.noreply.github.com>
  • Loading branch information
huntabyte and AdrianGonz97 authored Oct 23, 2024
1 parent d6a5ac0 commit 90d9b6d
Show file tree
Hide file tree
Showing 334 changed files with 10,579 additions and 4,211 deletions.
2 changes: 1 addition & 1 deletion .vscode/settings.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// Auto fix
"editor.codeActionsOnSave": {
"source.fixAll.eslint": "explicit",
"source.organizeImports": "explicit",
"source.organizeImports": "never",
"source.removeUnusedImports": "never",
"source.removeUnused.ts": "never"
},
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@
"eslint-config-prettier": "^9.1.0",
"eslint-plugin-svelte": "^2.44.1",
"globals": "^15.11.0",
"prettier": "^3.2.5",
"prettier": "^3.3.3",
"prettier-plugin-svelte": "^3.2.7",
"prettier-plugin-tailwindcss": "^0.6.8",
"pretty-quick": "^4.0.0",
Expand Down
87 changes: 59 additions & 28 deletions packages/cli/src/commands/add.ts
Original file line number Diff line number Diff line change
@@ -1,24 +1,18 @@
import { existsSync, promises as fs } from "node:fs";
import path from "node:path";
import process from "node:process";
import color from "chalk";
import { Command } from "commander";
import { execa } from "execa";
import { existsSync, promises as fs } from "node:fs";
import path from "node:path";
import process from "node:process";
import * as v from "valibot";
import { type Config, getConfig } from "../utils/get-config.js";
import { getEnvProxy } from "../utils/get-env-proxy.js";
import { detectPM } from "../utils/auto-detect.js";
import { ConfigError, error, handleError } from "../utils/errors.js";
import {
fetchTree,
getItemTargetPath,
// getRegistryBaseColor,
getRegistryIndex,
resolveTree,
} from "../utils/registry/index.js";
import { transformImports } from "../utils/transformers.js";
import * as p from "../utils/prompts.js";
import * as cliConfig from "../utils/get-config.js";
import { getEnvProxy } from "../utils/get-env-proxy.js";
import { intro, prettifyList } from "../utils/prompt-helpers.js";
import { detectPM } from "../utils/auto-detect.js";
import * as p from "../utils/prompts.js";
import * as registry from "../utils/registry/index.js";
import { transformImports } from "../utils/transformers.js";

const highlight = (...args: unknown[]) => color.bold.cyan(...args);

Expand Down Expand Up @@ -60,13 +54,15 @@ export const add = new Command()
throw error(`The path ${color.cyan(cwd)} does not exist. Please try again.`);
}

const config = await getConfig(cwd);
const config = await cliConfig.getConfig(cwd);
if (!config) {
throw new ConfigError(
`Configuration file is missing. Please run ${color.green("init")} to create a ${highlight("components.json")} file.`
);
}

registry.setRegistry(config.registry);

await runAdd(cwd, config, options);

p.outro(`${color.green("Success!")} Component installation completed.`);
Expand All @@ -75,13 +71,13 @@ export const add = new Command()
}
});

async function runAdd(cwd: string, config: Config, options: AddOptions) {
async function runAdd(cwd: string, config: cliConfig.Config, options: AddOptions) {
if (options.proxy !== undefined) {
process.env.HTTP_PROXY = options.proxy;
p.log.info(`You are using the provided proxy: ${color.green(options.proxy)}`);
}

const registryIndex = await getRegistryIndex();
const registryIndex = await registry.getRegistryIndex();

let selectedComponents = new Set(
options.all ? registryIndex.map(({ name }) => name) : options.components
Expand Down Expand Up @@ -118,12 +114,34 @@ async function runAdd(cwd: string, config: Config, options: AddOptions) {

// adds `registryDependency` to `selectedComponents` so that they can be individually overwritten
for (const name of selectedComponents) {
const regDeps = registryDepMap.get(name);
regDeps?.forEach((dep) => selectedComponents.add(dep));
if (registryDepMap.has(name)) {
const regDeps = registryDepMap.get(name);
regDeps?.forEach((dep) => selectedComponents.add(dep));
} else {
const tree = await registry.resolveTree({
index: registryIndex,
names: [name],
includeRegDeps: true,
config,
});
for (const item of tree) {
for (const regDep of item.registryDependencies) {
selectedComponents.add(regDep);
const regDeps = registryDepMap.get(regDep);
regDeps?.forEach((dep) => selectedComponents.add(dep));
}
}
}
}

const tree = await resolveTree(registryIndex, Array.from(selectedComponents), false);
const payload = await fetchTree(config, tree);
const tree = await registry.resolveTree({
index: registryIndex,
names: Array.from(selectedComponents),
includeRegDeps: false,
config,
});

const payload = await registry.fetchTree(config, tree);
// const baseColor = await getRegistryBaseColor(config.tailwind.baseColor);

if (payload.length === 0) {
Expand All @@ -136,8 +154,11 @@ async function runAdd(cwd: string, config: Config, options: AddOptions) {
const targetPath = options.path ? path.resolve(cwd, options.path) : undefined;
for (const item of payload) {
if (selectedComponents.has(item.name) === false) continue;
for (const regDep of item.registryDependencies) {
selectedComponents.add(regDep);
}

const targetDir = getItemTargetPath(config, item, targetPath);
const targetDir = registry.getRegistryItemTargetPath(config, item.type, targetPath);
if (targetDir === null) continue;

const componentExists = item.files.some((file) => {
Expand Down Expand Up @@ -187,7 +208,7 @@ async function runAdd(cwd: string, config: Config, options: AddOptions) {
const dependencies = new Set<string>();
const tasks: p.Task[] = [];
for (const item of payload) {
const targetDir = getItemTargetPath(config, item, targetPath);
const targetDir = registry.getRegistryItemTargetPath(config, item.type, targetPath);
if (targetDir === null) continue;

if (!existsSync(targetDir)) {
Expand Down Expand Up @@ -225,14 +246,15 @@ async function runAdd(cwd: string, config: Config, options: AddOptions) {
title: `Installing ${highlight(item.name)}`,
async task() {
for (const file of item.files) {
const componentDir = path.resolve(targetDir, item.name);
const filePath = path.resolve(targetDir, item.name, file.name);
const targetDir = registry.getRegistryItemTargetPath(config, file.type);
const filePath = path.resolve(targetDir, file.target);

// Run transformers.
const content = transformImports(file.content, config);

if (!existsSync(componentDir)) {
await fs.mkdir(componentDir, { recursive: true });
const dir = path.parse(filePath).dir;
if (!existsSync(dir)) {
await fs.mkdir(dir, { recursive: true });
}

await fs.writeFile(filePath, content);
Expand All @@ -259,6 +281,15 @@ async function runAdd(cwd: string, config: Config, options: AddOptions) {
});
}

// Update the config
tasks.push({
title: "Updating config file",
async task() {
cliConfig.writeConfig(cwd, config);
return `Config file ${highlight("components.json")} updated`;
},
});

await p.tasks(tasks);

if (!options.deps) {
Expand Down
89 changes: 65 additions & 24 deletions packages/cli/src/commands/init.ts
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
import color from "chalk";
import { Command, Option } from "commander";
import { execa } from "execa";
import { existsSync, promises as fs } from "node:fs";
import path from "node:path";
import process from "node:process";
import color from "chalk";
import * as v from "valibot";
import { Command, Option } from "commander";
import { execa } from "execa";
import * as cliConfig from "../utils/get-config.js";
import type { Config } from "../utils/get-config.js";
import { error, handleError } from "../utils/errors.js";
import { getBaseColors, getRegistryBaseColor, getStyles } from "../utils/registry/index.js";
import * as templates from "../utils/templates.js";
import * as p from "../utils/prompts.js";
import { intro, prettifyList } from "../utils/prompt-helpers.js";
import { resolveImport } from "../utils/resolve-imports.js";
import { syncSvelteKit } from "../utils/sveltekit.js";
import {
type DetectLanguageResult,
detectConfigs,
detectLanguage,
detectPM,
} from "../utils/auto-detect.js";
import { error, handleError } from "../utils/errors.js";
import type { Config } from "../utils/get-config.js";
import * as cliConfig from "../utils/get-config.js";
import { intro, prettifyList } from "../utils/prompt-helpers.js";
import * as p from "../utils/prompts.js";
import * as registry from "../utils/registry/index.js";
import { resolveImport } from "../utils/resolve-imports.js";
import { syncSvelteKit } from "../utils/sveltekit.js";
import * as templates from "../utils/templates.js";

const PROJECT_DEPENDENCIES = ["tailwind-variants", "clsx", "tailwind-merge"] as const;
const highlight = (...args: unknown[]) => color.bold.cyan(...args);

const baseColors = getBaseColors();
const styles = getStyles();
const baseColors = registry.getBaseColors();
const styles = registry.getStyles();

const initOptionsSchema = v.object({
cwd: v.string(),
Expand All @@ -35,6 +35,8 @@ const initOptionsSchema = v.object({
tailwindConfig: v.optional(v.string()),
componentsAlias: v.optional(v.string()),
utilsAlias: v.optional(v.string()),
hooksAlias: v.optional(v.string()),
uiAlias: v.optional(v.string()),
deps: v.boolean(),
});

Expand All @@ -59,6 +61,7 @@ export const init = new Command()
.option("--tailwind-config <path>", "path to the tailwind config file")
.option("--components-alias <path>", "import alias for components")
.option("--utils-alias <path>", "import alias for utils")
.option("--hooks-alias <path>", "import alias for hooks")
.action(async (opts) => {
intro();
const options = v.parse(initOptionsSchema, opts);
Expand All @@ -74,6 +77,8 @@ export const init = new Command()
const existingConfig = await cliConfig.getConfig(cwd);
const config = await promptForConfig(cwd, existingConfig, options);

registry.setRegistry(config.registry);

await runInit(cwd, config, options);

p.outro(`${color.green("Success!")} Project initialization completed.`);
Expand Down Expand Up @@ -241,17 +246,16 @@ async function promptForConfig(cwd: string, defaultConfig: Config | null, option
componentAlias = promptResult;
}

// infers the alias from `components`. if `components = $lib/components` then suggest `alias = $lib/alias`
const inferAlias = (alias: string) =>
`${componentAlias.split("/").slice(0, -1).join("/")}/${alias}`;

// Utils Alias
let utilsAlias = options.utilsAlias;
if (utilsAlias === undefined) {
const input = await p.text({
message: `Configure the import alias for ${highlight("utils")}:`,
initialValue:
// eslint-disable-next-line no-constant-binary-expression
defaultConfig?.aliases.utils ??
// infers the alias from `components`. if `components = @/comps` then suggest `utils = @/utils`
`${componentAlias?.split("/").slice(0, -1).join("/")}/utils` ??
cliConfig.DEFAULT_UTILS,
initialValue: defaultConfig?.aliases.utils ?? inferAlias("utils"),
placeholder: cliConfig.DEFAULT_UTILS,
validate: (value) => validateImportAlias(value, langConfig),
});
Expand All @@ -264,10 +268,47 @@ async function promptForConfig(cwd: string, defaultConfig: Config | null, option
utilsAlias = input;
}

// Hooks Alias
let hooksAlias = options.hooksAlias;
if (hooksAlias === undefined) {
const input = await p.text({
message: `Configure the import alias for ${highlight("hooks")}:`,
initialValue: defaultConfig?.aliases.hooks ?? inferAlias("hooks"),
placeholder: cliConfig.DEFAULT_HOOKS,
validate: (value) => validateImportAlias(value, langConfig),
});

if (p.isCancel(input)) {
p.cancel("Operation cancelled.");
process.exit(0);
}

hooksAlias = input;
}

// UI Alias
let uiAlias = options.uiAlias;
if (uiAlias === undefined) {
const input = await p.text({
message: `Configure the import alias for ${highlight("ui")}:`,
initialValue: defaultConfig?.aliases.ui ?? `${componentAlias}/ui`,
placeholder: cliConfig.DEFAULT_UI,
validate: (value) => validateImportAlias(value, langConfig),
});

if (p.isCancel(input)) {
p.cancel("Operation cancelled.");
process.exit(0);
}

uiAlias = input;
}

const config = v.parse(cliConfig.rawConfigSchema, {
$schema: "https://shadcn-svelte.com/schema.json",
style,
typescript: langConfig.type === "tsconfig.json",
registry: defaultConfig?.registry,
tailwind: {
config: tailwindConfig,
css: globalCss,
Expand All @@ -276,6 +317,8 @@ async function promptForConfig(cwd: string, defaultConfig: Config | null, option
aliases: {
utils: utilsAlias,
components: componentAlias,
hooks: hooksAlias,
ui: uiAlias,
},
});

Expand Down Expand Up @@ -306,9 +349,7 @@ export async function runInit(cwd: string, config: Config, options: InitOptions)
tasks.push({
title: "Creating config file",
async task() {
const targetPath = path.resolve(cwd, "components.json");
const conf = v.parse(cliConfig.rawConfigSchema, config); // inefficient, but it'll do
await fs.writeFile(targetPath, JSON.stringify(conf, null, "\t"), "utf8");
cliConfig.writeConfig(cwd, config);
return `Config file ${highlight("components.json")} created`;
},
});
Expand Down Expand Up @@ -345,7 +386,7 @@ export async function runInit(cwd: string, config: Config, options: InitOptions)
await fs.writeFile(config.resolvedPaths.tailwindConfig, tailwindConfigContent, "utf8");

// Write css file.
const baseColor = await getRegistryBaseColor(config.tailwind.baseColor);
const baseColor = await registry.getRegistryBaseColor(config.tailwind.baseColor);
if (baseColor) {
await fs.writeFile(
config.resolvedPaths.tailwindCss,
Expand Down
Loading

0 comments on commit 90d9b6d

Please sign in to comment.