pjdev2d-cli 1.0.0 → 1.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/README.md ADDED
@@ -0,0 +1,5 @@
1
+ # To add components
2
+
3
+ ```bash
4
+ npx pjdev2d-cli add <name>
5
+ ```
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { Command } from "commander";
4
+ import fs from "fs-extra";
5
+ import path from "path";
6
+ import { fileURLToPath } from "url";
7
+ import registry from "../registry.json" assert { type: "json" };
8
+
9
+ const __filename = fileURLToPath(import.meta.url);
10
+ const __dirname = path.dirname(__filename);
11
+
12
+ const program = new Command();
13
+
14
+ program
15
+ .command("add <name>")
16
+ .description("Add a template")
17
+ .action(async (name) => {
18
+ try {
19
+ const cwd = process.cwd();
20
+
21
+ const item = registry[name];
22
+
23
+ if (!item) {
24
+ console.log(`❌ "${name}" not found in registry`);
25
+ return;
26
+ }
27
+
28
+ const sourcePath = path.join(__dirname, "..", item.path);
29
+
30
+ if (!fs.existsSync(sourcePath)) {
31
+ console.log(`❌ Missing template: ${item.path}`);
32
+ return;
33
+ }
34
+
35
+ const outputDir = path.join(cwd, "src/pjdev2d-cli");
36
+ await fs.ensureDir(outputDir);
37
+
38
+ const stats = await fs.stat(sourcePath);
39
+
40
+ if (stats.isDirectory()) {
41
+ const outputPath = path.join(outputDir, path.basename(sourcePath));
42
+
43
+ await fs.copy(sourcePath, outputPath);
44
+
45
+ console.log(`✅ Added folder ${path.basename(sourcePath)}`);
46
+ } else {
47
+ const outputPath = path.join(outputDir, path.basename(sourcePath));
48
+
49
+ await fs.copy(sourcePath, outputPath);
50
+
51
+ console.log(`✅ Added file ${path.basename(sourcePath)}`);
52
+ }
53
+ } catch (error) {
54
+ console.error("❌ Failed");
55
+ console.error(error);
56
+ }
57
+ });
58
+
59
+ program.parse();
package/package.json CHANGED
@@ -1,10 +1,11 @@
1
1
  {
2
2
  "name": "pjdev2d-cli",
3
- "version": "1.0.0",
3
+ "version": "1.0.1",
4
+ "type": "module",
4
5
  "description": "CLI to install reusable React components like shadcn/ui",
5
- "main": "bin/index.js",
6
+ "main": "bin/cli.js",
6
7
  "bin": {
7
- "pjdev2d-cli": "./bin/index.js"
8
+ "pjdev2d-cli": "./bin/pjdev2d-cli.js"
8
9
  },
9
10
  "files": [
10
11
  "bin",
@@ -21,7 +22,7 @@
21
22
  "dependencies": {
22
23
  "@babel/core": "^7.29.0",
23
24
  "@babel/preset-react": "^7.28.5",
24
- "@babel/preset-typescript": "^7.28.5",
25
+ "@babel/preset-typescript": "^7.29.7",
25
26
  "@types/react": "^19.2.14",
26
27
  "clsx": "^2.1.1",
27
28
  "commander": "^14.0.3",
@@ -30,4 +31,4 @@
30
31
  "react": "^19.2.6",
31
32
  "tailwind-merge": "^3.6.0"
32
33
  }
33
- }
34
+ }
package/registry.json CHANGED
@@ -5,3 +5,4 @@
5
5
  "files": ["templates/tasks/README.md"]
6
6
  }
7
7
  }
8
+
package/bin/index.js DELETED
@@ -1,291 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- const { Command } = require("commander");
4
- const fs = require("fs-extra");
5
- const path = require("path");
6
- const babel = require("@babel/core");
7
- const presetTypescript = require("@babel/preset-typescript");
8
- const { execSync } = require("child_process");
9
- const registry = require("../registry.json");
10
-
11
- const program = new Command();
12
-
13
- /* -----------------------------
14
- INQUIRER (FIXED SAFE WRAPPER)
15
- ------------------------------*/
16
- const prompt = async (questions) => {
17
- const inquirer = await import("inquirer");
18
- return inquirer.default.prompt(questions);
19
- };
20
-
21
- /* =============================
22
- ADD COMMAND
23
- ============================= */
24
- program
25
- .command("add <name>")
26
- .description("Add components or utilities")
27
- .action(async (name) => {
28
- try {
29
- const cwd = process.cwd();
30
- console.log("\n🚀 Starting installation...\n");
31
-
32
- const isTsProject = fs.existsSync(path.join(cwd, "tsconfig.json"));
33
-
34
- let templatePath = "";
35
- let outputDir = "";
36
- let extension = "tsx";
37
-
38
- /* ---------------- COMPONENTS ---------------- */
39
- if (!name.startsWith("utils/")) {
40
- templatePath = path.join(__dirname, `../templates/${name}.tsx`);
41
- outputDir = path.join(cwd, "src/components/pejay-ui");
42
- extension = "tsx";
43
- } else {
44
-
45
- /* ---------------- UTILITIES ---------------- */
46
- const utilName = name.split("/")[1];
47
- templatePath = path.join(__dirname, `../utils/${utilName}.ts`);
48
- outputDir = path.join(cwd, "src/utils/pejay-ui");
49
- extension = "ts";
50
- }
51
-
52
- if (!fs.existsSync(templatePath)) {
53
- console.log(`❌ "${name}" not found`);
54
- return;
55
- }
56
-
57
- const code = await fs.readFile(templatePath, "utf8");
58
-
59
- let finalCode = code;
60
- let outputExt = extension;
61
-
62
- /* ---------------- TRANSFORM ---------------- */
63
- if (!isTsProject) {
64
- const transformed = babel.transformSync(code, {
65
- presets: [presetTypescript],
66
- filename: `file.${extension}`,
67
- });
68
-
69
- if (!transformed?.code) {
70
- throw new Error("Babel transform failed");
71
- }
72
-
73
- finalCode = transformed.code;
74
- outputExt = extension === "tsx" ? "jsx" : "js";
75
- }
76
-
77
- await fs.ensureDir(outputDir);
78
-
79
- const itemName = name.includes("/") ? name.split("/")[1] : name;
80
- const outputPath = path.join(outputDir, `${itemName}.${outputExt}`);
81
-
82
- await fs.writeFile(outputPath, finalCode);
83
- console.log(`✅ Created ${itemName}.${outputExt}`);
84
-
85
- /* ---------------- DEPENDENCIES ---------------- */
86
- const itemRegistry = registry[name];
87
-
88
- if (itemRegistry?.dependencies?.length) {
89
- for (const dependency of itemRegistry.dependencies) {
90
- const depName = dependency.includes("/")
91
- ? dependency.split("/")[1]
92
- : dependency;
93
-
94
- const depPath = path.join(__dirname, `../utils/${depName}.ts`);
95
-
96
- if (!fs.existsSync(depPath)) continue;
97
-
98
- let depCode = await fs.readFile(depPath, "utf8");
99
-
100
- if (!isTsProject) {
101
- const transformed = babel.transformSync(depCode, {
102
- presets: [presetTypescript],
103
- filename: `${depName}.ts`,
104
- });
105
-
106
- depCode = transformed.code;
107
- }
108
-
109
- const utilDir = path.join(cwd, "src/utils/pejay-ui");
110
- await fs.ensureDir(utilDir);
111
-
112
- const ext = isTsProject ? "ts" : "js";
113
- const outPath = path.join(utilDir, `${depName}.${ext}`);
114
-
115
- if (!fs.existsSync(outPath)) {
116
- await fs.writeFile(outPath, depCode);
117
- console.log(`📦 Added dependency ${depName}`);
118
- }
119
- }
120
- }
121
-
122
- /* ---------------- STATE SAVE ---------------- */
123
- const statePath = path.join(cwd, ".pejay-ui.json");
124
-
125
- let state = {};
126
- if (fs.existsSync(statePath)) {
127
- state = JSON.parse(await fs.readFile(statePath, "utf8"));
128
- }
129
-
130
- state.installed = state.installed || {};
131
-
132
- state.installed[name] = {
133
- files: [`src/components/pejay-ui/${itemName}.${outputExt}`],
134
- uses:
135
- itemRegistry?.dependencies?.map((d) =>
136
- d.includes("/") ? d.split("/")[1] : d,
137
- ) || [],
138
- };
139
-
140
- await fs.writeFile(statePath, JSON.stringify(state, null, 2));
141
-
142
- console.log(`\n🎉 ${name} installed successfully\n`);
143
- } catch (err) {
144
- console.error("\n❌ Add failed\n", err);
145
- }
146
- });
147
-
148
- /* =============================
149
- REMOVE COMMAND (SAFE VERSION)
150
- ============================= */
151
- program
152
- .command("remove <name>")
153
- .description("Remove components or utilities safely")
154
- .action(async (name) => {
155
- try {
156
- const cwd = process.cwd();
157
- console.log("\n🧹 Starting removal...\n");
158
-
159
- const itemRegistry = registry[name];
160
-
161
- if (!itemRegistry) {
162
- console.log(`❌ "${name}" not found in registry`);
163
- return;
164
- }
165
-
166
- const isTsProject = fs.existsSync(path.join(cwd, "tsconfig.json"));
167
- const itemName = name.includes("/") ? name.split("/")[1] : name;
168
-
169
- const componentDir = path.join(cwd, "src/components/pejay-ui");
170
- const utilsDir = path.join(cwd, "src/utils/pejay-ui");
171
-
172
- let removedAny = false;
173
-
174
- /* ---------------- REMOVE COMPONENT ---------------- */
175
- const exts = isTsProject ? ["tsx", "ts"] : ["jsx", "js"];
176
-
177
- for (const ext of exts) {
178
- const file = path.join(componentDir, `${itemName}.${ext}`);
179
-
180
- if (fs.existsSync(file)) {
181
- await fs.remove(file);
182
- console.log(`🗑️ Removed ${file}`);
183
- removedAny = true;
184
- }
185
- }
186
-
187
- /* ---------------- LOAD STATE ---------------- */
188
- const statePath = path.join(cwd, ".pejay-ui.json");
189
-
190
- let state = {};
191
- if (fs.existsSync(statePath)) {
192
- state = JSON.parse(await fs.readFile(statePath, "utf8"));
193
- }
194
-
195
- state.installed = state.installed || {};
196
-
197
- /* ---------------- BUILD USAGE MAP ---------------- */
198
- const usageMap = new Map();
199
-
200
- for (const comp of Object.values(state.installed)) {
201
- for (const u of comp.uses || []) {
202
- usageMap.set(u, (usageMap.get(u) || 0) + 1);
203
- }
204
- }
205
-
206
- /* ---------------- SAFE UTILITY REMOVE ---------------- */
207
- if (itemRegistry.dependencies?.length) {
208
- for (const dep of itemRegistry.dependencies) {
209
- const utilName = dep.includes("/") ? dep.split("/")[1] : dep;
210
-
211
- const usage = usageMap.get(utilName) || 0;
212
-
213
- if (usage > 1) {
214
- console.log(`⛔ Skipping ${utilName} (used by other components)`);
215
- continue;
216
- }
217
-
218
- const { confirm } = await prompt([
219
- {
220
- type: "confirm",
221
- name: "confirm",
222
- message: `Remove utility "${utilName}"?`,
223
- default: false,
224
- },
225
- ]);
226
-
227
- if (!confirm) continue;
228
-
229
- for (const ext of exts) {
230
- const file = path.join(utilsDir, `${utilName}.${ext}`);
231
-
232
- if (fs.existsSync(file)) {
233
- await fs.remove(file);
234
- console.log(`🗑️ Removed ${file}`);
235
- removedAny = true;
236
- }
237
- }
238
- }
239
- }
240
-
241
- /* ---------------- REMOVE PACKAGES ---------------- */
242
- // Only collect packages from deps that NO other component still uses
243
- const pkgs = [];
244
-
245
- for (const dep of itemRegistry.dependencies || []) {
246
- const utilName = dep.includes("/") ? dep.split("/")[1] : dep;
247
- const usage = usageMap.get(utilName) || 0;
248
-
249
- // usage > 1 means another component still needs this dep → skip its packages
250
- if (usage > 1) {
251
- console.log(`⛔ Keeping packages for ${utilName} (used by other components)`);
252
- continue;
253
- }
254
-
255
- const reg = registry[dep];
256
- if (reg?.packages) pkgs.push(...reg.packages);
257
- }
258
-
259
- if (pkgs.length) {
260
- const unique = [...new Set(pkgs)];
261
-
262
- const { ok } = await prompt([
263
- {
264
- type: "confirm",
265
- name: "ok",
266
- message: `Uninstall packages: ${unique.join(", ")}?`,
267
- default: false,
268
- },
269
- ]);
270
-
271
- if (ok) {
272
- execSync(`npm uninstall ${unique.join(" ")}`, {
273
- cwd,
274
- stdio: "inherit",
275
- });
276
- }
277
- }
278
-
279
- /* ---------------- CLEAN STATE ---------------- */
280
- if (state.installed[name]) {
281
- delete state.installed[name];
282
- await fs.writeFile(statePath, JSON.stringify(state, null, 2));
283
- }
284
-
285
- console.log(`\n🎉 ${name} removed successfully\n`);
286
- } catch (err) {
287
- console.error("\n❌ Remove failed\n", err);
288
- }
289
- });
290
-
291
- program.parse();