pbjcomponents 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +1 -0
- package/dist/index.js +273 -0
- package/package.json +43 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command4 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/add.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
import chalk from "chalk";
|
|
9
|
+
import ora from "ora";
|
|
10
|
+
import prompts from "prompts";
|
|
11
|
+
import fs3 from "fs-extra";
|
|
12
|
+
import path3 from "path";
|
|
13
|
+
|
|
14
|
+
// src/utils/get-config.ts
|
|
15
|
+
import fs from "fs-extra";
|
|
16
|
+
import path from "path";
|
|
17
|
+
var DEFAULT_CONFIG = {
|
|
18
|
+
style: "default",
|
|
19
|
+
componentsDir: "components/ui",
|
|
20
|
+
registry: "https://pbjcomponents.vercel.app/registry"
|
|
21
|
+
};
|
|
22
|
+
async function getConfig(cwd) {
|
|
23
|
+
const configPath = path.join(cwd, "components.json");
|
|
24
|
+
if (!fs.existsSync(configPath)) {
|
|
25
|
+
return DEFAULT_CONFIG;
|
|
26
|
+
}
|
|
27
|
+
try {
|
|
28
|
+
const configContent = await fs.readFile(configPath, "utf-8");
|
|
29
|
+
const userConfig = JSON.parse(configContent);
|
|
30
|
+
return { ...DEFAULT_CONFIG, ...userConfig };
|
|
31
|
+
} catch {
|
|
32
|
+
return DEFAULT_CONFIG;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
// src/utils/registry.ts
|
|
37
|
+
import fs2 from "fs-extra";
|
|
38
|
+
import path2 from "path";
|
|
39
|
+
var DEFAULT_REGISTRY_URL = "https://pbjcomponents.vercel.app/registry";
|
|
40
|
+
async function getRegistryUrl(cwd) {
|
|
41
|
+
const config = await getConfig(cwd);
|
|
42
|
+
return config.registry || DEFAULT_REGISTRY_URL;
|
|
43
|
+
}
|
|
44
|
+
async function getRegistry(cwd = process.cwd()) {
|
|
45
|
+
const registryUrl = await getRegistryUrl(cwd);
|
|
46
|
+
try {
|
|
47
|
+
const response = await fetch(`${registryUrl}/index.json`);
|
|
48
|
+
if (!response.ok) {
|
|
49
|
+
throw new Error(`Failed to fetch registry: ${response.statusText}`);
|
|
50
|
+
}
|
|
51
|
+
return await response.json();
|
|
52
|
+
} catch (error) {
|
|
53
|
+
const localPath = path2.join(
|
|
54
|
+
path2.dirname(new URL(import.meta.url).pathname),
|
|
55
|
+
"../../registry/index.json"
|
|
56
|
+
);
|
|
57
|
+
if (fs2.existsSync(localPath)) {
|
|
58
|
+
const content = await fs2.readFile(localPath, "utf-8");
|
|
59
|
+
return JSON.parse(content);
|
|
60
|
+
}
|
|
61
|
+
throw error;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async function getComponentEntry(name, cwd = process.cwd()) {
|
|
65
|
+
const registryUrl = await getRegistryUrl(cwd);
|
|
66
|
+
try {
|
|
67
|
+
const response = await fetch(`${registryUrl}/${name}.json`);
|
|
68
|
+
if (!response.ok) {
|
|
69
|
+
if (response.status === 404) return null;
|
|
70
|
+
throw new Error(`Failed to fetch component: ${response.statusText}`);
|
|
71
|
+
}
|
|
72
|
+
return await response.json();
|
|
73
|
+
} catch (error) {
|
|
74
|
+
const localPath = path2.join(
|
|
75
|
+
path2.dirname(new URL(import.meta.url).pathname),
|
|
76
|
+
`../../registry/${name}.json`
|
|
77
|
+
);
|
|
78
|
+
if (fs2.existsSync(localPath)) {
|
|
79
|
+
const content = await fs2.readFile(localPath, "utf-8");
|
|
80
|
+
return JSON.parse(content);
|
|
81
|
+
}
|
|
82
|
+
return null;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
// src/commands/add.ts
|
|
87
|
+
var addCommand = new Command().name("add").description("Add a component to your project").argument("[components...]", "Components to add").option("-y, --yes", "Skip confirmation prompt", false).option("-o, --overwrite", "Overwrite existing files", false).option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (components, opts) => {
|
|
88
|
+
const cwd = path3.resolve(opts.cwd);
|
|
89
|
+
if (!fs3.existsSync(cwd)) {
|
|
90
|
+
console.error(chalk.red(`Directory ${cwd} does not exist.`));
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
const config = await getConfig(cwd);
|
|
94
|
+
if (!components || components.length === 0) {
|
|
95
|
+
const registry = await getRegistry(cwd);
|
|
96
|
+
const { selectedComponents } = await prompts({
|
|
97
|
+
type: "multiselect",
|
|
98
|
+
name: "selectedComponents",
|
|
99
|
+
message: "Which components would you like to add?",
|
|
100
|
+
choices: registry.components.map((name) => ({
|
|
101
|
+
title: name,
|
|
102
|
+
value: name
|
|
103
|
+
}))
|
|
104
|
+
});
|
|
105
|
+
if (!selectedComponents || selectedComponents.length === 0) {
|
|
106
|
+
console.log(chalk.yellow("No components selected."));
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
components = selectedComponents;
|
|
110
|
+
}
|
|
111
|
+
for (const componentName of components) {
|
|
112
|
+
const spinner = ora(`Adding ${componentName}...`).start();
|
|
113
|
+
try {
|
|
114
|
+
const entry = await getComponentEntry(componentName, cwd);
|
|
115
|
+
if (!entry) {
|
|
116
|
+
spinner.fail(`Component "${componentName}" not found in registry.`);
|
|
117
|
+
continue;
|
|
118
|
+
}
|
|
119
|
+
for (const file of entry.files) {
|
|
120
|
+
const targetPath = path3.join(cwd, file.path);
|
|
121
|
+
const targetDir = path3.dirname(targetPath);
|
|
122
|
+
if (fs3.existsSync(targetPath) && !opts.overwrite) {
|
|
123
|
+
spinner.stop();
|
|
124
|
+
if (!opts.yes) {
|
|
125
|
+
const { overwrite } = await prompts({
|
|
126
|
+
type: "confirm",
|
|
127
|
+
name: "overwrite",
|
|
128
|
+
message: `File ${file.path} already exists. Overwrite?`,
|
|
129
|
+
initial: false
|
|
130
|
+
});
|
|
131
|
+
if (!overwrite) {
|
|
132
|
+
console.log(chalk.yellow(`Skipped ${file.path}`));
|
|
133
|
+
continue;
|
|
134
|
+
}
|
|
135
|
+
} else {
|
|
136
|
+
console.log(chalk.yellow(`Skipped ${file.path} (already exists)`));
|
|
137
|
+
continue;
|
|
138
|
+
}
|
|
139
|
+
spinner.start();
|
|
140
|
+
}
|
|
141
|
+
await fs3.ensureDir(targetDir);
|
|
142
|
+
await fs3.writeFile(targetPath, file.content, "utf-8");
|
|
143
|
+
}
|
|
144
|
+
spinner.succeed(`Added ${componentName}`);
|
|
145
|
+
if (entry.dependencies && entry.dependencies.length > 0) {
|
|
146
|
+
console.log(
|
|
147
|
+
chalk.dim(` Dependencies: ${entry.dependencies.join(", ")}`)
|
|
148
|
+
);
|
|
149
|
+
}
|
|
150
|
+
} catch (error) {
|
|
151
|
+
spinner.fail(`Failed to add ${componentName}`);
|
|
152
|
+
console.error(chalk.red(error));
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
console.log("");
|
|
156
|
+
console.log(chalk.green("Done!"));
|
|
157
|
+
console.log(
|
|
158
|
+
chalk.dim("Don't forget to install the required dependencies.")
|
|
159
|
+
);
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
// src/commands/list.ts
|
|
163
|
+
import { Command as Command2 } from "commander";
|
|
164
|
+
import chalk2 from "chalk";
|
|
165
|
+
var listCommand = new Command2().name("list").description("List all available components").option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (opts) => {
|
|
166
|
+
const cwd = opts.cwd;
|
|
167
|
+
const registry = await getRegistry(cwd);
|
|
168
|
+
console.log("");
|
|
169
|
+
console.log(chalk2.bold("Available components:"));
|
|
170
|
+
console.log("");
|
|
171
|
+
for (const name of registry.components) {
|
|
172
|
+
const entry = await getComponentEntry(name, cwd);
|
|
173
|
+
if (entry) {
|
|
174
|
+
const category = entry.category ? chalk2.dim(`[${entry.category}]`) : "";
|
|
175
|
+
const description = entry.description ? chalk2.dim(` - ${entry.description}`) : "";
|
|
176
|
+
console.log(` ${chalk2.cyan(name)} ${category}${description}`);
|
|
177
|
+
} else {
|
|
178
|
+
console.log(` ${chalk2.cyan(name)}`);
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
console.log("");
|
|
182
|
+
console.log(chalk2.dim(`Total: ${registry.components.length} components`));
|
|
183
|
+
console.log("");
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
// src/commands/update.ts
|
|
187
|
+
import { Command as Command3 } from "commander";
|
|
188
|
+
import chalk3 from "chalk";
|
|
189
|
+
import ora2 from "ora";
|
|
190
|
+
import prompts2 from "prompts";
|
|
191
|
+
import fs4 from "fs-extra";
|
|
192
|
+
import path4 from "path";
|
|
193
|
+
var updateCommand = new Command3().name("update").description("Update components in your project to the latest version").argument("[components...]", "Components to update").option("-y, --yes", "Skip confirmation prompt", false).option("-c, --cwd <path>", "Working directory", process.cwd()).action(async (components, opts) => {
|
|
194
|
+
const cwd = path4.resolve(opts.cwd);
|
|
195
|
+
if (!fs4.existsSync(cwd)) {
|
|
196
|
+
console.error(chalk3.red(`Directory ${cwd} does not exist.`));
|
|
197
|
+
process.exit(1);
|
|
198
|
+
}
|
|
199
|
+
const config = await getConfig(cwd);
|
|
200
|
+
if (!components || components.length === 0) {
|
|
201
|
+
console.error(chalk3.red("Please specify at least one component to update."));
|
|
202
|
+
console.log(chalk3.dim("Usage: pbjcomponents update <component> [components...]"));
|
|
203
|
+
console.log(chalk3.dim("Example: pbjcomponents update button"));
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
if (!opts.yes) {
|
|
207
|
+
const { confirm } = await prompts2({
|
|
208
|
+
type: "confirm",
|
|
209
|
+
name: "confirm",
|
|
210
|
+
message: `Update ${components.length} component(s)? This will overwrite existing files.`,
|
|
211
|
+
initial: true
|
|
212
|
+
});
|
|
213
|
+
if (!confirm) {
|
|
214
|
+
console.log(chalk3.yellow("Update cancelled."));
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
let updatedCount = 0;
|
|
219
|
+
let skippedCount = 0;
|
|
220
|
+
for (const componentName of components) {
|
|
221
|
+
const spinner = ora2(`Updating ${componentName}...`).start();
|
|
222
|
+
try {
|
|
223
|
+
const entry = await getComponentEntry(componentName, cwd);
|
|
224
|
+
if (!entry) {
|
|
225
|
+
spinner.fail(`Component "${componentName}" not found in registry.`);
|
|
226
|
+
skippedCount++;
|
|
227
|
+
continue;
|
|
228
|
+
}
|
|
229
|
+
const componentExists = entry.files.some(
|
|
230
|
+
(file) => fs4.existsSync(path4.join(cwd, file.path))
|
|
231
|
+
);
|
|
232
|
+
if (!componentExists) {
|
|
233
|
+
spinner.warn(
|
|
234
|
+
`Component "${componentName}" not found in project. Use 'add' instead.`
|
|
235
|
+
);
|
|
236
|
+
skippedCount++;
|
|
237
|
+
continue;
|
|
238
|
+
}
|
|
239
|
+
for (const file of entry.files) {
|
|
240
|
+
const targetPath = path4.join(cwd, file.path);
|
|
241
|
+
const targetDir = path4.dirname(targetPath);
|
|
242
|
+
await fs4.ensureDir(targetDir);
|
|
243
|
+
await fs4.writeFile(targetPath, file.content, "utf-8");
|
|
244
|
+
}
|
|
245
|
+
spinner.succeed(`Updated ${componentName}`);
|
|
246
|
+
updatedCount++;
|
|
247
|
+
if (entry.dependencies && entry.dependencies.length > 0) {
|
|
248
|
+
console.log(
|
|
249
|
+
chalk3.dim(` Dependencies: ${entry.dependencies.join(", ")}`)
|
|
250
|
+
);
|
|
251
|
+
}
|
|
252
|
+
} catch (error) {
|
|
253
|
+
spinner.fail(`Failed to update ${componentName}`);
|
|
254
|
+
console.error(chalk3.red(error));
|
|
255
|
+
skippedCount++;
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
console.log("");
|
|
259
|
+
if (updatedCount > 0) {
|
|
260
|
+
console.log(chalk3.green(`Updated ${updatedCount} component(s).`));
|
|
261
|
+
}
|
|
262
|
+
if (skippedCount > 0) {
|
|
263
|
+
console.log(chalk3.yellow(`Skipped ${skippedCount} component(s).`));
|
|
264
|
+
}
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
// src/index.ts
|
|
268
|
+
var program = new Command4();
|
|
269
|
+
program.name("pbjcomponents").description("CLI for adding pbjcomponents to your project").version("0.0.1");
|
|
270
|
+
program.addCommand(addCommand);
|
|
271
|
+
program.addCommand(listCommand);
|
|
272
|
+
program.addCommand(updateCommand);
|
|
273
|
+
program.parse();
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "pbjcomponents",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "CLI for adding pbjcomponents to your project",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"pbjcomponents": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist"
|
|
11
|
+
],
|
|
12
|
+
"engines": {
|
|
13
|
+
"node": ">=20"
|
|
14
|
+
},
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"commander": "^12.0.0",
|
|
17
|
+
"chalk": "^5.3.0",
|
|
18
|
+
"ora": "^8.0.0",
|
|
19
|
+
"prompts": "^2.4.2",
|
|
20
|
+
"fs-extra": "^11.2.0"
|
|
21
|
+
},
|
|
22
|
+
"devDependencies": {
|
|
23
|
+
"@types/fs-extra": "^11.0.4",
|
|
24
|
+
"@types/node": "^20.11.0",
|
|
25
|
+
"@types/prompts": "^2.4.9",
|
|
26
|
+
"tsup": "^8.0.0",
|
|
27
|
+
"typescript": "^5.3.0"
|
|
28
|
+
},
|
|
29
|
+
"keywords": [
|
|
30
|
+
"cli",
|
|
31
|
+
"ui",
|
|
32
|
+
"components",
|
|
33
|
+
"react",
|
|
34
|
+
"tailwindcss"
|
|
35
|
+
],
|
|
36
|
+
"author": "",
|
|
37
|
+
"license": "MIT",
|
|
38
|
+
"scripts": {
|
|
39
|
+
"build": "tsup src/index.ts --format esm --dts --clean",
|
|
40
|
+
"dev": "tsup src/index.ts --format esm --watch",
|
|
41
|
+
"typecheck": "tsc --noEmit"
|
|
42
|
+
}
|
|
43
|
+
}
|