Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,11 @@
"execa": "^7.2.0",
"is-unicode-supported": "^2.0.0",
"node-fetch-native": "^1.6.4",
"semver": "^7.7.1"
"prettier": "^3.5.3",
"prettier-plugin-svelte": "^3.3.3",
"semver": "^7.7.1",
"sv-strip": "^0.0.7",
"ts-blank-space": "^0.6.1"
},
"devDependencies": {
"@types/node": "^18.19.22",
Expand Down
13 changes: 9 additions & 4 deletions packages/cli/src/commands/add.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { getEnvProxy, getEnvRegistry } from "../utils/get-env-proxy.js";
import { cancel, intro, prettifyList } from "../utils/prompt-helpers.js";
import * as p from "../utils/prompts.js";
import * as registry from "../utils/registry/index.js";
import { transformImports } from "../utils/transformers.js";
import { transformContent } from "../utils/transformers.js";
import { resolveCommand } from "package-manager-detector/commands";
import { checkPreconditions } from "../utils/preconditions.js";

Expand Down Expand Up @@ -162,7 +162,7 @@ async function runAdd(cwd: string, config: cliConfig.Config, options: AddOptions
config,
});

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

if (payload.length === 0) cancel("Selected components not found.");
Expand Down Expand Up @@ -265,16 +265,21 @@ async function runAdd(cwd: string, config: cliConfig.Config, options: AddOptions
let pageName: string | undefined;
for (const file of item.files) {
const targetDir = registry.getRegistryItemTargetPath(config, file.type);
const filePath = path.resolve(targetDir, file.target);
let filePath = path.resolve(targetDir, file.target);

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

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

if (!config.typescript && filePath.endsWith(".ts")) {
filePath = filePath.replace(".ts", ".js");
file.target = file.target.replace(".ts", ".js");
}

await fs.writeFile(filePath, content);
if (file.type === "registry:page") {
pageName = file.target;
Expand Down
22 changes: 15 additions & 7 deletions packages/cli/src/commands/update.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { cancel, intro, prettifyList } from "../utils/prompt-helpers.js";
import * as p from "../utils/prompts.js";
import * as registry from "../utils/registry/index.js";
import { UTILS, UTILS_JS } from "../utils/templates.js";
import { transformImports } from "../utils/transformers.js";
import { transformContent } from "../utils/transformers.js";
import { resolveCommand } from "package-manager-detector/commands";
import { checkPreconditions } from "../utils/preconditions.js";

Expand Down Expand Up @@ -183,9 +183,7 @@ async function runUpdate(cwd: string, config: cliConfig.Config, options: UpdateO
names: selectedComponents.map((com) => com.name),
config,
});
const payload = (await registry.fetchTree(config, tree)).sort((a, b) =>
a.name.localeCompare(b.name)
);
const payload = (await registry.fetchTree(tree)).sort((a, b) => a.name.localeCompare(b.name));

const componentsToRemove: Record<string, string[]> = {};
const dependencies = new Set<string>();
Expand All @@ -212,16 +210,26 @@ async function runUpdate(cwd: string, config: cliConfig.Config, options: UpdateO
}

for (const file of item.files) {
const filePath = path.resolve(targetDir, item.name, file.name);
let filePath = path.resolve(targetDir, item.name, file.name);

if (!config.typescript && filePath.endsWith(".ts")) {
filePath = filePath.replace(".ts", ".js");
}

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

await fs.writeFile(filePath, content);
}

const installedFiles = await fs.readdir(componentDir);
const remoteFiles = item.files.map((file) => file.name);
const remoteFiles = item.files.map((file) => {
if (!config.typescript && file.name.endsWith(".ts")) {
return file.name.replace(".ts", ".js");
}

return file.name;
});
const filesToDelete = installedFiles
.filter((file) => !remoteFiles.includes(file))
.map((file) => path.resolve(targetDir, item.name, file));
Expand Down
13 changes: 3 additions & 10 deletions packages/cli/src/utils/registry/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,8 +83,7 @@ export async function resolveTree({
let entry = index.find((entry) => entry.name === name);

if (!entry) {
const itemPath = getRegistryItemPath(name, config);
const [item] = await fetchRegistry([itemPath]);
const [item] = await fetchRegistry([`${name}.json`]);
if (item) entry = item;
if (!entry) continue;
}
Expand All @@ -106,9 +105,9 @@ export async function resolveTree({
);
}

export async function fetchTree(config: Config, tree: RegistryIndex) {
export async function fetchTree(tree: RegistryIndex) {
try {
const paths = tree.map((item) => getRegistryItemPath(item.name, config));
const paths = tree.map((item) => `${item.name}.json`);
const result = await fetchRegistry(paths);

return v.parse(schemas.registryWithContentSchema, result);
Expand All @@ -118,12 +117,6 @@ export async function fetchTree(config: Config, tree: RegistryIndex) {
}
}

export function getRegistryItemPath(name: string, config: Config) {
const lang = config.typescript ? "ts" : "js";

return `${lang}/${name}.json`;
}

export function getItemTargetPath(
config: Config,
item: v.InferOutput<typeof schemas.registryItemWithContentSchema>,
Expand Down
36 changes: 36 additions & 0 deletions packages/cli/src/utils/transformers.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,25 @@
import type { Config } from "./get-config.js";
import * as prettier from "prettier";
import tsBlankSpace from "ts-blank-space";
import prettierPluginSvelte from "prettier-plugin-svelte";
import { strip } from "sv-strip";

const prettierConfig: prettier.Config = {
useTabs: true,
singleQuote: false,
trailingComma: "es5",
printWidth: 100,
};

export async function transformContent(content: string, filename: string, config: Config) {
content = transformImports(content, config);

if (!config.typescript) {
content = await stripTypes(content, filename);
}

return content;
}

export function transformImports(content: string, config: Config) {
let str = content.replace(/\$lib\/registry\/.*\/components/g, config.aliases.components);
Expand All @@ -7,3 +28,18 @@ export function transformImports(content: string, config: Config) {
str = str.replace(/\$lib\/utils/g, config.aliases.utils);
return str;
}

export async function stripTypes(content: string, filename: string) {
if (filename.endsWith(".svelte")) {
content = strip(content, { filename });
} else {
content = tsBlankSpace(content);
}

return await prettier.format(content, {
...prettierConfig,
filepath: filename,
plugins: [prettierPluginSvelte],
overrides: [{ files: "*.svelte", options: { parser: "svelte" } }],
});
}
14 changes: 1 addition & 13 deletions packages/cli/test/utils/registry/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import path from "node:path";
import { describe, expect, it } from "vitest";
import { getItemTargetPath, getRegistryItemPath } from "../../../src/utils/registry/index";
import { getItemTargetPath } from "../../../src/utils/registry/index";
import { SITE_BASE_URL } from "../../../src/constants";

const config = {
Expand Down Expand Up @@ -92,15 +92,3 @@ describe("getItemTargetPath", () => {
).toEqual(path.join("src", "lib", "components", "ui"));
});
});

describe("getRegistryItemPath", () => {
it("Resolves path to ts when typescript", async () => {
expect(getRegistryItemPath("alert", config)).toBe("ts/alert.json");
});

it("Resolves path to js when javascript", () => {
expect(getRegistryItemPath("alert", { ...config, typescript: false })).toBe(
"js/alert.json"
);
});
});
Loading