pittaya 0.0.8 → 0.1.0
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.js +798 -267
- package/dist/index.js.map +1 -1
- package/package.json +11 -1
package/dist/index.js
CHANGED
|
@@ -7,34 +7,80 @@ import { Command } from "commander";
|
|
|
7
7
|
import chalk from "chalk";
|
|
8
8
|
import ora from "ora";
|
|
9
9
|
import prompts from "prompts";
|
|
10
|
-
import
|
|
11
|
-
import
|
|
10
|
+
import path6 from "path";
|
|
11
|
+
import fs6 from "fs/promises";
|
|
12
12
|
import { execa } from "execa";
|
|
13
13
|
|
|
14
14
|
// src/utils/registry.ts
|
|
15
15
|
import fetch from "node-fetch";
|
|
16
|
-
|
|
17
|
-
|
|
16
|
+
import fs from "fs/promises";
|
|
17
|
+
import { existsSync } from "fs";
|
|
18
|
+
import path from "path";
|
|
19
|
+
import { fileURLToPath } from "url";
|
|
20
|
+
var DEFAULT_REGISTRY_BASE_URL = "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry";
|
|
21
|
+
function shouldPreferLocalRegistry() {
|
|
22
|
+
const raw = process.env.PITTAYA_REGISTRY_PREFER_LOCAL;
|
|
23
|
+
if (raw == null) return false;
|
|
24
|
+
const normalized = raw.toLowerCase();
|
|
25
|
+
return normalized === "true" || normalized === "1" || normalized === "yes";
|
|
26
|
+
}
|
|
27
|
+
function getLocalRegistryBaseUrl() {
|
|
18
28
|
try {
|
|
19
|
-
const
|
|
29
|
+
const filePath = fileURLToPath(import.meta.url);
|
|
30
|
+
const dirPath = path.dirname(filePath);
|
|
31
|
+
const candidate = path.resolve(dirPath, "../../../registry");
|
|
32
|
+
if (!existsSync(candidate)) return null;
|
|
33
|
+
if (!existsSync(path.join(candidate, "styles"))) return null;
|
|
34
|
+
return candidate;
|
|
35
|
+
} catch {
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function getRegistryBaseUrl() {
|
|
40
|
+
const localRegistry = shouldPreferLocalRegistry() ? getLocalRegistryBaseUrl() : null;
|
|
41
|
+
if (localRegistry) return localRegistry;
|
|
42
|
+
if (process.env.PITTAYA_REGISTRY_URL) {
|
|
43
|
+
return process.env.PITTAYA_REGISTRY_URL;
|
|
44
|
+
}
|
|
45
|
+
return DEFAULT_REGISTRY_BASE_URL;
|
|
46
|
+
}
|
|
47
|
+
function isHttpUrl(value) {
|
|
48
|
+
return value.startsWith("http://") || value.startsWith("https://");
|
|
49
|
+
}
|
|
50
|
+
async function readJsonFromRegistry(relativePath, config) {
|
|
51
|
+
const baseUrl = getRegistryBaseUrl();
|
|
52
|
+
if (isHttpUrl(baseUrl)) {
|
|
53
|
+
const response = await fetch(`${baseUrl}/${relativePath}`);
|
|
20
54
|
if (!response.ok) {
|
|
21
55
|
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
|
|
22
56
|
}
|
|
23
57
|
return await response.json();
|
|
58
|
+
}
|
|
59
|
+
const absolutePath = path.resolve(baseUrl, relativePath);
|
|
60
|
+
const raw = await fs.readFile(absolutePath, "utf-8");
|
|
61
|
+
return JSON.parse(raw);
|
|
62
|
+
}
|
|
63
|
+
function getStyleFromConfig(config) {
|
|
64
|
+
return config?.style || "new-york";
|
|
65
|
+
}
|
|
66
|
+
async function fetchRegistry(config) {
|
|
67
|
+
try {
|
|
68
|
+
const style = getStyleFromConfig(config);
|
|
69
|
+
const styleIndex = await readJsonFromRegistry(`styles/${style}/index.json`, config);
|
|
70
|
+
return styleIndex;
|
|
24
71
|
} catch (error) {
|
|
25
72
|
console.error("Error fetching registry:", error);
|
|
26
73
|
throw new Error("Unable to load the registry of components");
|
|
27
74
|
}
|
|
28
75
|
}
|
|
29
|
-
async function getRegistryComponent(name) {
|
|
76
|
+
async function getRegistryComponent(name, config) {
|
|
30
77
|
try {
|
|
31
|
-
const
|
|
32
|
-
|
|
78
|
+
const style = getStyleFromConfig(config);
|
|
79
|
+
const styleComponent = await readJsonFromRegistry(
|
|
80
|
+
`styles/${style}/components/${name}.json`,
|
|
81
|
+
config
|
|
33
82
|
);
|
|
34
|
-
|
|
35
|
-
throw new Error(`Component "${name}" not found in registry`);
|
|
36
|
-
}
|
|
37
|
-
return await response.json();
|
|
83
|
+
return styleComponent;
|
|
38
84
|
} catch (error) {
|
|
39
85
|
throw new Error(`Error loading component "${name}": ${error.message}`);
|
|
40
86
|
}
|
|
@@ -72,21 +118,21 @@ function escapeRegex(str) {
|
|
|
72
118
|
}
|
|
73
119
|
|
|
74
120
|
// src/utils/package-manager.ts
|
|
75
|
-
import
|
|
76
|
-
import
|
|
121
|
+
import fs2 from "fs/promises";
|
|
122
|
+
import path2 from "path";
|
|
77
123
|
async function detectPackageManager() {
|
|
78
124
|
try {
|
|
79
|
-
await
|
|
125
|
+
await fs2.access("pnpm-lock.yaml");
|
|
80
126
|
return "pnpm";
|
|
81
127
|
} catch {
|
|
82
128
|
}
|
|
83
129
|
try {
|
|
84
|
-
await
|
|
130
|
+
await fs2.access("yarn.lock");
|
|
85
131
|
return "yarn";
|
|
86
132
|
} catch {
|
|
87
133
|
}
|
|
88
134
|
try {
|
|
89
|
-
await
|
|
135
|
+
await fs2.access("bun.lockb");
|
|
90
136
|
return "bun";
|
|
91
137
|
} catch {
|
|
92
138
|
}
|
|
@@ -95,8 +141,8 @@ async function detectPackageManager() {
|
|
|
95
141
|
async function isPackageInstalled(packageName) {
|
|
96
142
|
const cwd = process.cwd();
|
|
97
143
|
try {
|
|
98
|
-
const packageJsonPath =
|
|
99
|
-
const packageJson2 = JSON.parse(await
|
|
144
|
+
const packageJsonPath = path2.join(cwd, "package.json");
|
|
145
|
+
const packageJson2 = JSON.parse(await fs2.readFile(packageJsonPath, "utf-8"));
|
|
100
146
|
const allDeps = {
|
|
101
147
|
...packageJson2.dependencies,
|
|
102
148
|
...packageJson2.devDependencies
|
|
@@ -107,8 +153,8 @@ async function isPackageInstalled(packageName) {
|
|
|
107
153
|
} catch {
|
|
108
154
|
}
|
|
109
155
|
try {
|
|
110
|
-
const packagePath =
|
|
111
|
-
await
|
|
156
|
+
const packagePath = path2.join(cwd, "node_modules", packageName);
|
|
157
|
+
await fs2.access(packagePath);
|
|
112
158
|
return true;
|
|
113
159
|
} catch {
|
|
114
160
|
}
|
|
@@ -126,28 +172,28 @@ async function checkMissingDependencies(dependencies) {
|
|
|
126
172
|
}
|
|
127
173
|
|
|
128
174
|
// src/utils/component-checker.ts
|
|
129
|
-
import
|
|
130
|
-
import
|
|
175
|
+
import path4 from "path";
|
|
176
|
+
import fs4 from "fs/promises";
|
|
131
177
|
|
|
132
178
|
// src/utils/project-structure.ts
|
|
133
|
-
import
|
|
134
|
-
import
|
|
179
|
+
import fs3 from "fs/promises";
|
|
180
|
+
import path3 from "path";
|
|
135
181
|
async function hasSrcDirectory(cwd = process.cwd()) {
|
|
136
182
|
try {
|
|
137
|
-
const srcPath =
|
|
138
|
-
await
|
|
183
|
+
const srcPath = path3.join(cwd, "src");
|
|
184
|
+
await fs3.access(srcPath);
|
|
139
185
|
const commonDirs = ["app", "components", "lib", "pages"];
|
|
140
186
|
for (const dir of commonDirs) {
|
|
141
187
|
try {
|
|
142
|
-
await
|
|
188
|
+
await fs3.access(path3.join(srcPath, dir));
|
|
143
189
|
return true;
|
|
144
190
|
} catch {
|
|
145
191
|
continue;
|
|
146
192
|
}
|
|
147
193
|
}
|
|
148
194
|
try {
|
|
149
|
-
const tsconfigPath =
|
|
150
|
-
const tsconfig = JSON.parse(await
|
|
195
|
+
const tsconfigPath = path3.join(cwd, "tsconfig.json");
|
|
196
|
+
const tsconfig = JSON.parse(await fs3.readFile(tsconfigPath, "utf-8"));
|
|
151
197
|
if (tsconfig.compilerOptions?.paths) {
|
|
152
198
|
const paths = tsconfig.compilerOptions.paths;
|
|
153
199
|
if (paths["@/*"]?.includes("./src/*")) {
|
|
@@ -184,12 +230,12 @@ async function getDefaultPaths(cwd = process.cwd()) {
|
|
|
184
230
|
// src/utils/component-checker.ts
|
|
185
231
|
async function isComponentInstalled(name, config) {
|
|
186
232
|
try {
|
|
187
|
-
const component = await getRegistryComponent(name);
|
|
233
|
+
const component = await getRegistryComponent(name, config);
|
|
188
234
|
if (!component) return false;
|
|
189
235
|
for (const file of component.files) {
|
|
190
236
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
191
|
-
const filePath =
|
|
192
|
-
const exists = await
|
|
237
|
+
const filePath = path4.join(process.cwd(), targetPath);
|
|
238
|
+
const exists = await fs4.access(filePath).then(() => true).catch(() => false);
|
|
193
239
|
if (!exists) return false;
|
|
194
240
|
}
|
|
195
241
|
return true;
|
|
@@ -198,29 +244,135 @@ async function isComponentInstalled(name, config) {
|
|
|
198
244
|
}
|
|
199
245
|
}
|
|
200
246
|
async function resolveTargetPath(fileName, type, config) {
|
|
247
|
+
const normalized = fileName.replace(/\\/g, "/");
|
|
201
248
|
if (type === "registry:ui") {
|
|
202
249
|
const resolvedPath = await resolveAliasPath(config.aliases.ui);
|
|
203
|
-
|
|
250
|
+
const relative = normalized.replace(/^ui\//, "");
|
|
251
|
+
return path4.join(resolvedPath, relative);
|
|
204
252
|
}
|
|
205
253
|
if (type === "registry:lib") {
|
|
206
254
|
const resolvedPath = await resolveAliasPath(config.aliases.lib);
|
|
207
|
-
|
|
255
|
+
const relative = normalized.replace(/^lib\//, "");
|
|
256
|
+
return path4.join(resolvedPath, relative);
|
|
208
257
|
}
|
|
209
258
|
if (type === "registry:hook") {
|
|
210
259
|
const resolvedPath = await resolveAliasPath(config.aliases.hooks);
|
|
211
|
-
return
|
|
260
|
+
return path4.join(resolvedPath, fileName);
|
|
212
261
|
}
|
|
213
262
|
return fileName;
|
|
214
263
|
}
|
|
215
264
|
|
|
265
|
+
// src/utils/project-config.ts
|
|
266
|
+
import fs5 from "fs/promises";
|
|
267
|
+
import path5 from "path";
|
|
268
|
+
function applyPittayaProjectConfig(pittaya) {
|
|
269
|
+
if (pittaya.registry?.url) {
|
|
270
|
+
process.env.PITTAYA_REGISTRY_URL = pittaya.registry.url;
|
|
271
|
+
}
|
|
272
|
+
if (typeof pittaya.registry?.preferLocal === "boolean") {
|
|
273
|
+
process.env.PITTAYA_REGISTRY_PREFER_LOCAL = String(pittaya.registry.preferLocal);
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
async function readJsonIfExists(absolutePath) {
|
|
277
|
+
try {
|
|
278
|
+
const raw = await fs5.readFile(absolutePath, "utf-8");
|
|
279
|
+
return JSON.parse(raw);
|
|
280
|
+
} catch {
|
|
281
|
+
return null;
|
|
282
|
+
}
|
|
283
|
+
}
|
|
284
|
+
async function loadProjectConfig(cwd = process.cwd()) {
|
|
285
|
+
const componentsJsonPath = path5.join(cwd, "components.json");
|
|
286
|
+
const pittayaJsonPath = path5.join(cwd, "pittaya.json");
|
|
287
|
+
const config = await readJsonIfExists(componentsJsonPath);
|
|
288
|
+
if (!config) {
|
|
289
|
+
throw new Error("components.json not found");
|
|
290
|
+
}
|
|
291
|
+
const pittaya = await readJsonIfExists(pittayaJsonPath) ?? {};
|
|
292
|
+
return { config, pittaya };
|
|
293
|
+
}
|
|
294
|
+
|
|
295
|
+
// src/utils/confirm.ts
|
|
296
|
+
import { createInterface } from "readline";
|
|
297
|
+
function resolveFromString(answer, initial) {
|
|
298
|
+
const value = (answer ?? "").trim().toLowerCase();
|
|
299
|
+
if (!value) return initial;
|
|
300
|
+
if (value === "y" || value === "yes") return true;
|
|
301
|
+
if (value === "n" || value === "no") return false;
|
|
302
|
+
return initial;
|
|
303
|
+
}
|
|
304
|
+
async function confirm(message, initial = false) {
|
|
305
|
+
const suffix = initial ? "(Y/n)" : "(y/N)";
|
|
306
|
+
const prompt = `${message} ${suffix} `;
|
|
307
|
+
if (!process.stdin.isTTY) {
|
|
308
|
+
const rl = createInterface({
|
|
309
|
+
input: process.stdin,
|
|
310
|
+
output: process.stdout
|
|
311
|
+
});
|
|
312
|
+
return await new Promise((resolve) => {
|
|
313
|
+
rl.question(prompt, (answer) => {
|
|
314
|
+
rl.close();
|
|
315
|
+
resolve(resolveFromString(answer, initial));
|
|
316
|
+
});
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return await new Promise((resolve) => {
|
|
320
|
+
const stdin = process.stdin;
|
|
321
|
+
const stdout = process.stdout;
|
|
322
|
+
const prevRawMode = stdin.isRaw;
|
|
323
|
+
if (typeof stdin.setRawMode === "function") {
|
|
324
|
+
stdin.setRawMode(true);
|
|
325
|
+
}
|
|
326
|
+
stdin.resume();
|
|
327
|
+
stdout.write(prompt);
|
|
328
|
+
const cleanup = () => {
|
|
329
|
+
stdin.off("data", onData);
|
|
330
|
+
if (typeof stdin.setRawMode === "function") {
|
|
331
|
+
stdin.setRawMode(Boolean(prevRawMode));
|
|
332
|
+
}
|
|
333
|
+
stdin.pause();
|
|
334
|
+
};
|
|
335
|
+
const finish = (result) => {
|
|
336
|
+
stdout.write(`${result ? "y" : "n"}
|
|
337
|
+
`);
|
|
338
|
+
cleanup();
|
|
339
|
+
resolve(result);
|
|
340
|
+
};
|
|
341
|
+
const onData = (chunk) => {
|
|
342
|
+
const str = chunk.toString("utf8");
|
|
343
|
+
if (str === "") {
|
|
344
|
+
cleanup();
|
|
345
|
+
process.kill(process.pid, "SIGINT");
|
|
346
|
+
return;
|
|
347
|
+
}
|
|
348
|
+
const key = str.toLowerCase();
|
|
349
|
+
if (key === "\r" || key === "\n") {
|
|
350
|
+
finish(initial);
|
|
351
|
+
return;
|
|
352
|
+
}
|
|
353
|
+
if (key === "y") {
|
|
354
|
+
finish(true);
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
if (key === "n") {
|
|
358
|
+
finish(false);
|
|
359
|
+
return;
|
|
360
|
+
}
|
|
361
|
+
};
|
|
362
|
+
stdin.on("data", onData);
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
|
|
216
366
|
// src/commands/add.ts
|
|
217
367
|
async function add(components, options) {
|
|
218
368
|
const cwd = process.cwd();
|
|
219
|
-
const componentsJsonPath = path4.join(cwd, "components.json");
|
|
220
369
|
let config;
|
|
370
|
+
let pittayaConfig;
|
|
221
371
|
try {
|
|
222
|
-
const
|
|
223
|
-
config =
|
|
372
|
+
const loaded = await loadProjectConfig(cwd);
|
|
373
|
+
config = loaded.config;
|
|
374
|
+
pittayaConfig = loaded.pittaya;
|
|
375
|
+
applyPittayaProjectConfig(pittayaConfig);
|
|
224
376
|
} catch (error) {
|
|
225
377
|
console.log(chalk.red("\n\u274C components.json not found.\n"));
|
|
226
378
|
console.log(
|
|
@@ -229,10 +381,14 @@ async function add(components, options) {
|
|
|
229
381
|
);
|
|
230
382
|
return;
|
|
231
383
|
}
|
|
384
|
+
const resolvedOptions = {
|
|
385
|
+
...options,
|
|
386
|
+
addMissingDeps: options.addMissingDeps ?? pittayaConfig?.install?.autoInstallDeps ?? false
|
|
387
|
+
};
|
|
232
388
|
const spinner = ora("Fetching available components...").start();
|
|
233
389
|
let registry;
|
|
234
390
|
try {
|
|
235
|
-
registry = await fetchRegistry();
|
|
391
|
+
registry = await fetchRegistry(config);
|
|
236
392
|
spinner.succeed("Registry loaded!");
|
|
237
393
|
} catch (error) {
|
|
238
394
|
spinner.fail("Error loading registry");
|
|
@@ -266,7 +422,7 @@ Adding ${components.length} component(s)...
|
|
|
266
422
|
`)
|
|
267
423
|
);
|
|
268
424
|
for (const componentName of components) {
|
|
269
|
-
await addComponent(componentName, config,
|
|
425
|
+
await addComponent(componentName, config, resolvedOptions);
|
|
270
426
|
}
|
|
271
427
|
console.log(chalk.green("\n\u2705 Components added successfully!\n"));
|
|
272
428
|
}
|
|
@@ -278,7 +434,7 @@ async function addComponent(name, config, options) {
|
|
|
278
434
|
}
|
|
279
435
|
const spinner = ora(`Installing ${chalk.bold(name)}...`).start();
|
|
280
436
|
try {
|
|
281
|
-
const component = await getRegistryComponent(name);
|
|
437
|
+
const component = await getRegistryComponent(name, config);
|
|
282
438
|
if (!component) {
|
|
283
439
|
spinner.fail(`Component "${name}" not found in registry.`);
|
|
284
440
|
return;
|
|
@@ -298,12 +454,10 @@ async function addComponent(name, config, options) {
|
|
|
298
454
|
if (options.addMissingDeps) {
|
|
299
455
|
console.log(chalk.dim("Installing dependencies automatically...\n"));
|
|
300
456
|
} else {
|
|
301
|
-
const
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
initial: true
|
|
306
|
-
});
|
|
457
|
+
const install = await confirm(
|
|
458
|
+
"Do you want to install the dependencies now?",
|
|
459
|
+
true
|
|
460
|
+
);
|
|
307
461
|
if (!install) {
|
|
308
462
|
console.log(chalk.yellow("\n\u26A0\uFE0F Component not installed. Install the dependencies manually and try again.\n"));
|
|
309
463
|
return;
|
|
@@ -336,25 +490,23 @@ async function addComponent(name, config, options) {
|
|
|
336
490
|
}
|
|
337
491
|
for (const file of component.files) {
|
|
338
492
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
339
|
-
const filePath =
|
|
340
|
-
const exists = await
|
|
493
|
+
const filePath = path6.join(process.cwd(), targetPath);
|
|
494
|
+
const exists = await fs6.access(filePath).then(() => true).catch(() => false);
|
|
341
495
|
if (exists && !options.overwrite && !options.yes) {
|
|
342
496
|
spinner.stop();
|
|
343
|
-
const
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
initial: false
|
|
348
|
-
});
|
|
497
|
+
const overwrite = await confirm(
|
|
498
|
+
`${targetPath} already exists. Overwrite?`,
|
|
499
|
+
false
|
|
500
|
+
);
|
|
349
501
|
if (!overwrite) {
|
|
350
502
|
spinner.warn(`Skipping ${targetPath}`);
|
|
351
503
|
continue;
|
|
352
504
|
}
|
|
353
505
|
spinner.start();
|
|
354
506
|
}
|
|
355
|
-
await
|
|
507
|
+
await fs6.mkdir(path6.dirname(filePath), { recursive: true });
|
|
356
508
|
const content = transformImports(file.content, config);
|
|
357
|
-
await
|
|
509
|
+
await fs6.writeFile(filePath, content, "utf-8");
|
|
358
510
|
}
|
|
359
511
|
spinner.succeed(`${chalk.bold(name)} installed successfully!`);
|
|
360
512
|
} catch (error) {
|
|
@@ -363,46 +515,367 @@ async function addComponent(name, config, options) {
|
|
|
363
515
|
}
|
|
364
516
|
}
|
|
365
517
|
|
|
366
|
-
// src/commands/
|
|
518
|
+
// src/commands/remove.ts
|
|
367
519
|
import chalk2 from "chalk";
|
|
368
520
|
import ora2 from "ora";
|
|
369
521
|
import prompts2 from "prompts";
|
|
370
|
-
import
|
|
371
|
-
import
|
|
522
|
+
import path7 from "path";
|
|
523
|
+
import fs7 from "fs/promises";
|
|
524
|
+
async function remove(components, options) {
|
|
525
|
+
const cwd = process.cwd();
|
|
526
|
+
let config;
|
|
527
|
+
let pittayaConfig;
|
|
528
|
+
try {
|
|
529
|
+
const loaded = await loadProjectConfig(cwd);
|
|
530
|
+
config = loaded.config;
|
|
531
|
+
pittayaConfig = loaded.pittaya;
|
|
532
|
+
applyPittayaProjectConfig(pittayaConfig);
|
|
533
|
+
} catch (error) {
|
|
534
|
+
console.log(chalk2.red("\n\u274C components.json not found.\n"));
|
|
535
|
+
console.log(
|
|
536
|
+
chalk2.dim(`Run ${chalk2.bold("npx pittaya init")} first.
|
|
537
|
+
`)
|
|
538
|
+
);
|
|
539
|
+
return;
|
|
540
|
+
}
|
|
541
|
+
const spinner = ora2("Fetching installed components...").start();
|
|
542
|
+
let registry;
|
|
543
|
+
try {
|
|
544
|
+
registry = await fetchRegistry(config);
|
|
545
|
+
spinner.succeed("Registry loaded!");
|
|
546
|
+
} catch (error) {
|
|
547
|
+
spinner.fail("Error loading registry");
|
|
548
|
+
console.error(error);
|
|
549
|
+
return;
|
|
550
|
+
}
|
|
551
|
+
if (components.length === 0) {
|
|
552
|
+
const allComponents = registry.components || [];
|
|
553
|
+
const installedComponents = [];
|
|
554
|
+
for (const comp of allComponents) {
|
|
555
|
+
const slug = comp.slug || comp.name;
|
|
556
|
+
if (await isComponentInstalled(slug, config)) {
|
|
557
|
+
installedComponents.push({
|
|
558
|
+
title: `${slug}${comp.description ? ` - ${comp.description}` : ""}`,
|
|
559
|
+
value: slug
|
|
560
|
+
});
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
if (installedComponents.length === 0) {
|
|
564
|
+
console.log(chalk2.yellow("\n\u{1F4E6} No components installed to remove.\n"));
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
const { selected } = await prompts2({
|
|
568
|
+
type: "multiselect",
|
|
569
|
+
name: "selected",
|
|
570
|
+
message: "Select components to remove:",
|
|
571
|
+
choices: installedComponents,
|
|
572
|
+
min: 1
|
|
573
|
+
});
|
|
574
|
+
if (!selected || selected.length === 0) {
|
|
575
|
+
console.log(chalk2.yellow("\n\u274C No components selected.\n"));
|
|
576
|
+
return;
|
|
577
|
+
}
|
|
578
|
+
components = selected;
|
|
579
|
+
}
|
|
580
|
+
if (!options.yes) {
|
|
581
|
+
const confirmed = await confirm(
|
|
582
|
+
`Are you sure you want to remove ${chalk2.bold(components.join(", "))}?`,
|
|
583
|
+
false
|
|
584
|
+
);
|
|
585
|
+
if (!confirmed) {
|
|
586
|
+
console.log(chalk2.yellow("\n\u274C Operation cancelled.\n"));
|
|
587
|
+
return;
|
|
588
|
+
}
|
|
589
|
+
}
|
|
590
|
+
console.log(
|
|
591
|
+
chalk2.dim(`
|
|
592
|
+
Removing ${components.length} component(s)...
|
|
593
|
+
`)
|
|
594
|
+
);
|
|
595
|
+
for (const componentName of components) {
|
|
596
|
+
await removeComponent(componentName, config);
|
|
597
|
+
}
|
|
598
|
+
console.log(chalk2.green("\n\u2705 Components removed successfully!\n"));
|
|
599
|
+
}
|
|
600
|
+
async function removeComponent(name, config) {
|
|
601
|
+
const spinner = ora2(`Removing ${chalk2.bold(name)}...`).start();
|
|
602
|
+
try {
|
|
603
|
+
const component = await getRegistryComponent(name, config);
|
|
604
|
+
if (!component) {
|
|
605
|
+
spinner.fail(`Component "${name}" not found in registry.`);
|
|
606
|
+
return;
|
|
607
|
+
}
|
|
608
|
+
const removedFiles = [];
|
|
609
|
+
for (const file of component.files) {
|
|
610
|
+
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
611
|
+
const filePath = path7.join(process.cwd(), targetPath);
|
|
612
|
+
const exists = await fs7.access(filePath).then(() => true).catch(() => false);
|
|
613
|
+
if (exists) {
|
|
614
|
+
await fs7.unlink(filePath);
|
|
615
|
+
removedFiles.push(filePath);
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
for (const filePath of removedFiles) {
|
|
619
|
+
await removeEmptyDirs(path7.dirname(filePath));
|
|
620
|
+
}
|
|
621
|
+
spinner.succeed(`${chalk2.bold(name)} removed successfully!`);
|
|
622
|
+
} catch (error) {
|
|
623
|
+
spinner.fail(`Error removing ${name}`);
|
|
624
|
+
console.error(error);
|
|
625
|
+
}
|
|
626
|
+
}
|
|
627
|
+
async function removeEmptyDirs(dirPath) {
|
|
628
|
+
try {
|
|
629
|
+
const files = await fs7.readdir(dirPath);
|
|
630
|
+
if (files.length === 0) {
|
|
631
|
+
await fs7.rmdir(dirPath);
|
|
632
|
+
await removeEmptyDirs(path7.dirname(dirPath));
|
|
633
|
+
}
|
|
634
|
+
} catch {
|
|
635
|
+
}
|
|
636
|
+
}
|
|
637
|
+
|
|
638
|
+
// src/commands/init.ts
|
|
639
|
+
import chalk3 from "chalk";
|
|
640
|
+
import ora3 from "ora";
|
|
641
|
+
import prompts3 from "prompts";
|
|
642
|
+
import path9 from "path";
|
|
643
|
+
import fs9 from "fs/promises";
|
|
372
644
|
import { execa as execa2 } from "execa";
|
|
645
|
+
|
|
646
|
+
// src/utils/style-installer.ts
|
|
647
|
+
import fs8 from "fs/promises";
|
|
648
|
+
import path8 from "path";
|
|
649
|
+
import postcss from "postcss";
|
|
650
|
+
async function applyRegistryStyleToProject(styleComponent, config, options) {
|
|
651
|
+
const cssPath = config.tailwind?.css;
|
|
652
|
+
if (!cssPath) {
|
|
653
|
+
return;
|
|
654
|
+
}
|
|
655
|
+
const absoluteCssPath = path8.resolve(process.cwd(), cssPath);
|
|
656
|
+
const raw = await fs8.readFile(absoluteCssPath, "utf-8").catch(() => "");
|
|
657
|
+
const next = await transformTailwindV4Css(raw, styleComponent.cssVars ?? {}, {
|
|
658
|
+
overwriteCssVars: options?.overwriteCssVars ?? true
|
|
659
|
+
});
|
|
660
|
+
await fs8.mkdir(path8.dirname(absoluteCssPath), { recursive: true });
|
|
661
|
+
await fs8.writeFile(absoluteCssPath, next, "utf-8");
|
|
662
|
+
}
|
|
663
|
+
async function transformTailwindV4Css(input, cssVars, options) {
|
|
664
|
+
const result = await postcss([
|
|
665
|
+
ensureImportPlugin({ importPath: "tailwindcss" }),
|
|
666
|
+
ensureImportPlugin({ importPath: "tw-animate-css" }),
|
|
667
|
+
ensureCustomVariantDarkPlugin(),
|
|
668
|
+
upsertThemeAtRulePlugin(cssVars.theme ?? {}, {
|
|
669
|
+
overwrite: options.overwriteCssVars
|
|
670
|
+
}),
|
|
671
|
+
upsertRuleVarsPlugin(":root", cssVars.light ?? {}, {
|
|
672
|
+
overwrite: options.overwriteCssVars
|
|
673
|
+
}),
|
|
674
|
+
upsertRuleVarsPlugin(".dark", cssVars.dark ?? {}, {
|
|
675
|
+
overwrite: options.overwriteCssVars
|
|
676
|
+
}),
|
|
677
|
+
ensureBaseLayerPlugin()
|
|
678
|
+
]).process(input, { from: void 0 });
|
|
679
|
+
return result.css.replace(/(\n\s*\n)+/g, "\n\n").trimStart();
|
|
680
|
+
}
|
|
681
|
+
function ensureImportPlugin({
|
|
682
|
+
importPath
|
|
683
|
+
}) {
|
|
684
|
+
return {
|
|
685
|
+
postcssPlugin: "pittaya-ensure-import",
|
|
686
|
+
Once(root) {
|
|
687
|
+
const exists = root.nodes.some(
|
|
688
|
+
(n) => n.type === "atrule" && n.name === "import" && n.params.includes(`"${importPath}"`)
|
|
689
|
+
);
|
|
690
|
+
if (exists) return;
|
|
691
|
+
const node = postcss.atRule({
|
|
692
|
+
name: "import",
|
|
693
|
+
params: `"${importPath}"`
|
|
694
|
+
});
|
|
695
|
+
root.prepend(node);
|
|
696
|
+
}
|
|
697
|
+
};
|
|
698
|
+
}
|
|
699
|
+
ensureImportPlugin.postcss = true;
|
|
700
|
+
function ensureCustomVariantDarkPlugin() {
|
|
701
|
+
return {
|
|
702
|
+
postcssPlugin: "pittaya-ensure-custom-variant-dark",
|
|
703
|
+
Once(root) {
|
|
704
|
+
const exists = root.nodes.some(
|
|
705
|
+
(n) => n.type === "atrule" && n.name === "custom-variant" && n.params.startsWith("dark ")
|
|
706
|
+
);
|
|
707
|
+
if (exists) return;
|
|
708
|
+
const node = postcss.atRule({
|
|
709
|
+
name: "custom-variant",
|
|
710
|
+
params: "dark (&:is(.dark *))"
|
|
711
|
+
});
|
|
712
|
+
root.append(node);
|
|
713
|
+
}
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
ensureCustomVariantDarkPlugin.postcss = true;
|
|
717
|
+
function upsertThemeAtRulePlugin(vars, options) {
|
|
718
|
+
return {
|
|
719
|
+
postcssPlugin: "pittaya-upsert-theme-atrule",
|
|
720
|
+
Once(root) {
|
|
721
|
+
if (Object.keys(vars).length === 0) return;
|
|
722
|
+
let themeNode = root.nodes.find(
|
|
723
|
+
(n) => n.type === "atrule" && n.name === "theme" && n.params === "inline"
|
|
724
|
+
);
|
|
725
|
+
if (!themeNode) {
|
|
726
|
+
themeNode = postcss.atRule({
|
|
727
|
+
name: "theme",
|
|
728
|
+
params: "inline"
|
|
729
|
+
});
|
|
730
|
+
root.append(themeNode);
|
|
731
|
+
}
|
|
732
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
733
|
+
const prop = `--${k.replace(/^--/, "")}`;
|
|
734
|
+
const existing = themeNode.nodes?.find(
|
|
735
|
+
(n) => n.type === "decl" && n.prop === prop
|
|
736
|
+
);
|
|
737
|
+
if (existing) {
|
|
738
|
+
if (options.overwrite) {
|
|
739
|
+
existing.value = v;
|
|
740
|
+
}
|
|
741
|
+
} else {
|
|
742
|
+
themeNode.append(
|
|
743
|
+
postcss.decl({
|
|
744
|
+
prop,
|
|
745
|
+
value: v
|
|
746
|
+
})
|
|
747
|
+
);
|
|
748
|
+
}
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
};
|
|
752
|
+
}
|
|
753
|
+
upsertThemeAtRulePlugin.postcss = true;
|
|
754
|
+
function upsertRuleVarsPlugin(selector, vars, options) {
|
|
755
|
+
return {
|
|
756
|
+
postcssPlugin: `pittaya-upsert-vars-${selector}`,
|
|
757
|
+
Once(root) {
|
|
758
|
+
if (Object.keys(vars).length === 0) return;
|
|
759
|
+
let rule = root.nodes.find(
|
|
760
|
+
(n) => n.type === "rule" && n.selector === selector
|
|
761
|
+
);
|
|
762
|
+
if (!rule) {
|
|
763
|
+
rule = postcss.rule({ selector });
|
|
764
|
+
root.append(rule);
|
|
765
|
+
}
|
|
766
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
767
|
+
const prop = `--${k.replace(/^--/, "")}`;
|
|
768
|
+
const existing = rule.nodes?.find(
|
|
769
|
+
(n) => n.type === "decl" && n.prop === prop
|
|
770
|
+
);
|
|
771
|
+
if (existing) {
|
|
772
|
+
if (options.overwrite) {
|
|
773
|
+
existing.value = v;
|
|
774
|
+
}
|
|
775
|
+
} else {
|
|
776
|
+
rule.append(
|
|
777
|
+
postcss.decl({
|
|
778
|
+
prop,
|
|
779
|
+
value: v
|
|
780
|
+
})
|
|
781
|
+
);
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
}
|
|
785
|
+
};
|
|
786
|
+
}
|
|
787
|
+
upsertRuleVarsPlugin.postcss = true;
|
|
788
|
+
function ensureBaseLayerPlugin() {
|
|
789
|
+
return {
|
|
790
|
+
postcssPlugin: "pittaya-ensure-base-layer",
|
|
791
|
+
Once(root) {
|
|
792
|
+
const hasLayerBase = root.nodes.some(
|
|
793
|
+
(n) => n.type === "atrule" && n.name === "layer" && n.params === "base"
|
|
794
|
+
);
|
|
795
|
+
if (hasLayerBase) return;
|
|
796
|
+
const baseLayer = postcss.atRule({
|
|
797
|
+
name: "layer",
|
|
798
|
+
params: "base"
|
|
799
|
+
});
|
|
800
|
+
baseLayer.append(
|
|
801
|
+
postcss.rule({
|
|
802
|
+
selector: "*",
|
|
803
|
+
nodes: [
|
|
804
|
+
postcss.atRule({
|
|
805
|
+
name: "apply",
|
|
806
|
+
params: "border-border outline-ring/50"
|
|
807
|
+
})
|
|
808
|
+
]
|
|
809
|
+
})
|
|
810
|
+
);
|
|
811
|
+
baseLayer.append(
|
|
812
|
+
postcss.rule({
|
|
813
|
+
selector: "body",
|
|
814
|
+
nodes: [
|
|
815
|
+
postcss.atRule({
|
|
816
|
+
name: "apply",
|
|
817
|
+
params: "bg-background text-foreground"
|
|
818
|
+
})
|
|
819
|
+
]
|
|
820
|
+
})
|
|
821
|
+
);
|
|
822
|
+
root.append(baseLayer);
|
|
823
|
+
}
|
|
824
|
+
};
|
|
825
|
+
}
|
|
826
|
+
ensureBaseLayerPlugin.postcss = true;
|
|
827
|
+
|
|
828
|
+
// src/commands/init.ts
|
|
373
829
|
async function init(options) {
|
|
374
|
-
|
|
830
|
+
const pittayaColorHex = "#f2556d";
|
|
831
|
+
console.log(
|
|
832
|
+
chalk3.bold(
|
|
833
|
+
`
|
|
834
|
+
Welcome to ${chalk3.hex(pittayaColorHex)("Pittaya")} UI!
|
|
835
|
+
`
|
|
836
|
+
)
|
|
837
|
+
);
|
|
375
838
|
const cwd = process.cwd();
|
|
376
|
-
const componentsJsonPath =
|
|
377
|
-
const
|
|
839
|
+
const componentsJsonPath = path9.join(cwd, "components.json");
|
|
840
|
+
const pittayaJsonPath = path9.join(cwd, "pittaya.json");
|
|
841
|
+
const exists = await fs9.access(componentsJsonPath).then(() => true).catch(() => false);
|
|
842
|
+
const pittayaExists = await fs9.access(pittayaJsonPath).then(() => true).catch(() => false);
|
|
378
843
|
if (exists && !options.yes) {
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
initial: false
|
|
384
|
-
});
|
|
844
|
+
const overwrite = await confirm(
|
|
845
|
+
`${chalk3.underline("components.json")} already exists. Do you want to overwrite it?`,
|
|
846
|
+
false
|
|
847
|
+
);
|
|
385
848
|
if (!overwrite) {
|
|
386
|
-
console.log(
|
|
849
|
+
console.log(chalk3.yellow("\n\u274C Operation cancelled.\n"));
|
|
387
850
|
return;
|
|
388
851
|
}
|
|
389
852
|
}
|
|
853
|
+
let shouldWritePittayaJson = true;
|
|
854
|
+
if (pittayaExists && !options.yes) {
|
|
855
|
+
const overwrite = await confirm(
|
|
856
|
+
`${chalk3.underline("pittaya.json")} already exists. Do you want to overwrite it?`,
|
|
857
|
+
false
|
|
858
|
+
);
|
|
859
|
+
if (!overwrite) {
|
|
860
|
+
shouldWritePittayaJson = false;
|
|
861
|
+
}
|
|
862
|
+
}
|
|
390
863
|
const defaultPaths = await getDefaultPaths(cwd);
|
|
391
864
|
const config = options.yes ? {
|
|
392
|
-
style: "
|
|
865
|
+
style: "pittaya",
|
|
393
866
|
tailwindCss: defaultPaths.globalsCss,
|
|
394
867
|
rsc: true,
|
|
395
868
|
componentsPath: defaultPaths.components,
|
|
396
869
|
utilsPath: defaultPaths.utils
|
|
397
|
-
} : await
|
|
870
|
+
} : await prompts3([
|
|
398
871
|
{
|
|
399
872
|
type: "select",
|
|
400
873
|
name: "style",
|
|
401
874
|
message: "Which style would you like to use?",
|
|
402
875
|
choices: [
|
|
876
|
+
{ title: "Pittaya", value: "pittaya" },
|
|
403
877
|
{ title: "New York", value: "new-york" },
|
|
404
|
-
{ title: "Default", value: "default" }
|
|
405
|
-
{ title: "Recife", value: "recife" }
|
|
878
|
+
{ title: "Default", value: "default" }
|
|
406
879
|
]
|
|
407
880
|
},
|
|
408
881
|
{
|
|
@@ -412,10 +885,14 @@ async function init(options) {
|
|
|
412
885
|
initial: defaultPaths.globalsCss
|
|
413
886
|
},
|
|
414
887
|
{
|
|
415
|
-
type: "
|
|
888
|
+
type: "select",
|
|
416
889
|
name: "rsc",
|
|
417
890
|
message: "Use React Server Components?",
|
|
418
|
-
|
|
891
|
+
choices: [
|
|
892
|
+
{ title: "Yes", value: true },
|
|
893
|
+
{ title: "No", value: false }
|
|
894
|
+
],
|
|
895
|
+
initial: 0
|
|
419
896
|
},
|
|
420
897
|
{
|
|
421
898
|
type: "text",
|
|
@@ -431,16 +908,16 @@ async function init(options) {
|
|
|
431
908
|
}
|
|
432
909
|
]);
|
|
433
910
|
if (!config.style && !options.yes) {
|
|
434
|
-
console.log(
|
|
911
|
+
console.log(chalk3.yellow("\n\u274C Operation cancelled.\n"));
|
|
435
912
|
return;
|
|
436
913
|
}
|
|
437
914
|
const componentsJson = {
|
|
438
915
|
$schema: "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry/schema.json",
|
|
439
|
-
style: config.style || "
|
|
916
|
+
style: config.style || "pittaya",
|
|
440
917
|
rsc: config.rsc ?? true,
|
|
441
918
|
tsx: true,
|
|
442
919
|
tailwind: {
|
|
443
|
-
config: "
|
|
920
|
+
config: "",
|
|
444
921
|
css: config.tailwindCss || "src/app/globals.css",
|
|
445
922
|
baseColor: "neutral",
|
|
446
923
|
cssVariables: true,
|
|
@@ -449,95 +926,120 @@ async function init(options) {
|
|
|
449
926
|
aliases: {
|
|
450
927
|
components: config.componentsPath || "@/components",
|
|
451
928
|
utils: config.utilsPath || "@/lib/utils",
|
|
452
|
-
ui:
|
|
929
|
+
ui: "@/components/ui",
|
|
453
930
|
lib: "@/lib",
|
|
454
931
|
hooks: "@/hooks"
|
|
455
932
|
},
|
|
456
933
|
iconLibrary: "lucide"
|
|
457
934
|
};
|
|
458
|
-
|
|
459
|
-
|
|
935
|
+
let pittayaJson = {
|
|
936
|
+
registry: {
|
|
937
|
+
url: "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry",
|
|
938
|
+
preferLocal: false
|
|
939
|
+
},
|
|
940
|
+
theme: {
|
|
941
|
+
overwriteCssVars: true
|
|
942
|
+
},
|
|
943
|
+
install: {
|
|
944
|
+
autoInstallDeps: true
|
|
945
|
+
}
|
|
946
|
+
};
|
|
947
|
+
if (!shouldWritePittayaJson) {
|
|
948
|
+
try {
|
|
949
|
+
const raw = await fs9.readFile(pittayaJsonPath, "utf-8");
|
|
950
|
+
pittayaJson = JSON.parse(raw);
|
|
951
|
+
} catch {
|
|
952
|
+
shouldWritePittayaJson = true;
|
|
953
|
+
}
|
|
954
|
+
}
|
|
955
|
+
const spinner = ora3("Creating components.json...").start();
|
|
956
|
+
await fs9.writeFile(
|
|
460
957
|
componentsJsonPath,
|
|
461
958
|
JSON.stringify(componentsJson, null, 2)
|
|
462
959
|
);
|
|
463
960
|
spinner.succeed("components.json created successfully!");
|
|
464
|
-
|
|
465
|
-
|
|
961
|
+
if (shouldWritePittayaJson) {
|
|
962
|
+
const pittayaSpinner = ora3("Creating pittaya.json...").start();
|
|
963
|
+
await fs9.writeFile(pittayaJsonPath, JSON.stringify(pittayaJson, null, 2));
|
|
964
|
+
pittayaSpinner.succeed("pittaya.json created successfully!");
|
|
965
|
+
}
|
|
966
|
+
applyPittayaProjectConfig(pittayaJson);
|
|
967
|
+
const depsSpinner = ora3("Installing base dependencies...").start();
|
|
466
968
|
try {
|
|
969
|
+
const packageManager = await detectPackageManager();
|
|
467
970
|
await execa2(packageManager, [
|
|
468
971
|
packageManager === "yarn" ? "add" : "install",
|
|
469
972
|
"class-variance-authority",
|
|
470
973
|
"clsx",
|
|
471
|
-
"tailwind-merge"
|
|
974
|
+
"tailwind-merge",
|
|
975
|
+
"lucide-react",
|
|
976
|
+
"tw-animate-css"
|
|
472
977
|
]);
|
|
473
978
|
depsSpinner.succeed("Dependencies installed!");
|
|
474
979
|
} catch (error) {
|
|
475
980
|
depsSpinner.fail("Error installing dependencies");
|
|
476
981
|
console.error(error);
|
|
477
982
|
}
|
|
478
|
-
|
|
479
|
-
|
|
983
|
+
try {
|
|
984
|
+
const styleItem = await getRegistryComponent("style", componentsJson);
|
|
985
|
+
await applyRegistryStyleToProject(styleItem, componentsJson, {
|
|
986
|
+
overwriteCssVars: pittayaJson.theme?.overwriteCssVars ?? true
|
|
987
|
+
});
|
|
988
|
+
} catch (error) {
|
|
989
|
+
console.error(error);
|
|
990
|
+
}
|
|
991
|
+
console.log(chalk3.green(`
|
|
992
|
+
\u2705 ${chalk3.hex(pittayaColorHex)("Pittaya")} UI configured successfully!
|
|
993
|
+
`));
|
|
994
|
+
console.log(chalk3.dim("Next steps:"));
|
|
480
995
|
console.log(
|
|
481
|
-
|
|
482
|
-
` ${
|
|
996
|
+
chalk3.dim(
|
|
997
|
+
` ${chalk3.bold("npx pittaya add button")} - Add a component`
|
|
483
998
|
)
|
|
484
999
|
);
|
|
485
1000
|
console.log(
|
|
486
|
-
|
|
487
|
-
` ${
|
|
1001
|
+
chalk3.dim(
|
|
1002
|
+
` ${chalk3.bold("npx pittaya add --all")} - Add all components
|
|
488
1003
|
`
|
|
489
1004
|
)
|
|
490
1005
|
);
|
|
491
1006
|
}
|
|
492
|
-
async function detectPackageManager2() {
|
|
493
|
-
try {
|
|
494
|
-
await fs5.access("pnpm-lock.yaml");
|
|
495
|
-
return "pnpm";
|
|
496
|
-
} catch {
|
|
497
|
-
}
|
|
498
|
-
try {
|
|
499
|
-
await fs5.access("yarn.lock");
|
|
500
|
-
return "yarn";
|
|
501
|
-
} catch {
|
|
502
|
-
}
|
|
503
|
-
return "npm";
|
|
504
|
-
}
|
|
505
1007
|
|
|
506
1008
|
// src/commands/credits.ts
|
|
507
|
-
import
|
|
1009
|
+
import chalk4 from "chalk";
|
|
508
1010
|
async function credits() {
|
|
509
|
-
console.log(
|
|
510
|
-
console.log(
|
|
511
|
-
console.log(
|
|
512
|
-
console.log(
|
|
513
|
-
console.log(
|
|
1011
|
+
console.log(chalk4.bold("\nPittaya UI - Creators\n"));
|
|
1012
|
+
console.log(chalk4.cyan(" \u2022 Marcos Bueno"));
|
|
1013
|
+
console.log(chalk4.cyan(" \u2022 Lucas Ribeiro"));
|
|
1014
|
+
console.log(chalk4.cyan(" \u2022 Jarbas Gouveia"));
|
|
1015
|
+
console.log(chalk4.dim("\n Thank you for using Pittaya UI! \u2764\uFE0F\n"));
|
|
514
1016
|
}
|
|
515
1017
|
|
|
516
1018
|
// src/commands/diff.ts
|
|
517
|
-
import
|
|
518
|
-
import
|
|
519
|
-
import
|
|
520
|
-
import
|
|
521
|
-
import
|
|
1019
|
+
import chalk5 from "chalk";
|
|
1020
|
+
import ora4 from "ora";
|
|
1021
|
+
import prompts4 from "prompts";
|
|
1022
|
+
import path10 from "path";
|
|
1023
|
+
import fs10 from "fs/promises";
|
|
522
1024
|
async function diff(components, options) {
|
|
523
1025
|
const cwd = process.cwd();
|
|
524
|
-
const componentsJsonPath = path6.join(cwd, "components.json");
|
|
525
1026
|
let config;
|
|
526
1027
|
try {
|
|
527
|
-
const
|
|
528
|
-
config =
|
|
1028
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1029
|
+
config = loaded.config;
|
|
1030
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
529
1031
|
} catch (error) {
|
|
530
|
-
console.log(
|
|
1032
|
+
console.log(chalk5.red("\n\u274C components.json not found.\n"));
|
|
531
1033
|
console.log(
|
|
532
|
-
|
|
1034
|
+
chalk5.dim(`Run ${chalk5.bold("npx pittaya init")} first.
|
|
533
1035
|
`)
|
|
534
1036
|
);
|
|
535
1037
|
return;
|
|
536
1038
|
}
|
|
537
|
-
const spinner =
|
|
1039
|
+
const spinner = ora4("Fetching registry...").start();
|
|
538
1040
|
let registry;
|
|
539
1041
|
try {
|
|
540
|
-
registry = await fetchRegistry();
|
|
1042
|
+
registry = await fetchRegistry(config);
|
|
541
1043
|
spinner.succeed("Registry loaded!");
|
|
542
1044
|
} catch (error) {
|
|
543
1045
|
spinner.fail("Error loading registry");
|
|
@@ -554,7 +1056,7 @@ async function diff(components, options) {
|
|
|
554
1056
|
}
|
|
555
1057
|
}
|
|
556
1058
|
if (componentsToCheck.length === 0) {
|
|
557
|
-
console.log(
|
|
1059
|
+
console.log(chalk5.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
|
|
558
1060
|
return;
|
|
559
1061
|
}
|
|
560
1062
|
} else if (components.length === 0) {
|
|
@@ -567,10 +1069,10 @@ async function diff(components, options) {
|
|
|
567
1069
|
}
|
|
568
1070
|
}
|
|
569
1071
|
if (installedComponents.length === 0) {
|
|
570
|
-
console.log(
|
|
1072
|
+
console.log(chalk5.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
|
|
571
1073
|
return;
|
|
572
1074
|
}
|
|
573
|
-
const { selected } = await
|
|
1075
|
+
const { selected } = await prompts4({
|
|
574
1076
|
type: "multiselect",
|
|
575
1077
|
name: "selected",
|
|
576
1078
|
message: "Select components to check for updates:",
|
|
@@ -581,14 +1083,14 @@ async function diff(components, options) {
|
|
|
581
1083
|
min: 1
|
|
582
1084
|
});
|
|
583
1085
|
if (!selected || selected.length === 0) {
|
|
584
|
-
console.log(
|
|
1086
|
+
console.log(chalk5.yellow("\n\u274C No components selected.\n"));
|
|
585
1087
|
return;
|
|
586
1088
|
}
|
|
587
1089
|
componentsToCheck = selected;
|
|
588
1090
|
} else {
|
|
589
1091
|
componentsToCheck = components;
|
|
590
1092
|
}
|
|
591
|
-
console.log(
|
|
1093
|
+
console.log(chalk5.dim(`
|
|
592
1094
|
Checking ${componentsToCheck.length} component(s)...
|
|
593
1095
|
`));
|
|
594
1096
|
const results = [];
|
|
@@ -602,23 +1104,23 @@ Checking ${componentsToCheck.length} component(s)...
|
|
|
602
1104
|
}
|
|
603
1105
|
async function checkComponentDiff(name, config) {
|
|
604
1106
|
try {
|
|
605
|
-
const component = await getRegistryComponent(name);
|
|
1107
|
+
const component = await getRegistryComponent(name, config);
|
|
606
1108
|
if (!component) {
|
|
607
|
-
console.log(
|
|
1109
|
+
console.log(chalk5.red(` \u274C Component "${name}" not found in registry.`));
|
|
608
1110
|
return null;
|
|
609
1111
|
}
|
|
610
1112
|
const isInstalled = await isComponentInstalled(name, config);
|
|
611
1113
|
if (!isInstalled) {
|
|
612
|
-
console.log(
|
|
1114
|
+
console.log(chalk5.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
|
|
613
1115
|
return null;
|
|
614
1116
|
}
|
|
615
1117
|
const fileDiffs = [];
|
|
616
1118
|
let hasChanges = false;
|
|
617
1119
|
for (const file of component.files) {
|
|
618
1120
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
619
|
-
const filePath =
|
|
1121
|
+
const filePath = path10.join(process.cwd(), targetPath);
|
|
620
1122
|
try {
|
|
621
|
-
const localContent = await
|
|
1123
|
+
const localContent = await fs10.readFile(filePath, "utf-8");
|
|
622
1124
|
const registryContent = transformImports(file.content, config);
|
|
623
1125
|
const contentMatches = localContent.trim() === registryContent.trim();
|
|
624
1126
|
fileDiffs.push({
|
|
@@ -647,7 +1149,7 @@ async function checkComponentDiff(name, config) {
|
|
|
647
1149
|
isInstalled: true
|
|
648
1150
|
};
|
|
649
1151
|
} catch (error) {
|
|
650
|
-
console.log(
|
|
1152
|
+
console.log(chalk5.red(` \u274C Error checking ${name}`));
|
|
651
1153
|
console.error(error);
|
|
652
1154
|
return null;
|
|
653
1155
|
}
|
|
@@ -657,59 +1159,59 @@ function displayDiffResults(results) {
|
|
|
657
1159
|
const componentsUpToDate = results.filter((r) => !r.hasChanges);
|
|
658
1160
|
console.log();
|
|
659
1161
|
if (componentsWithChanges.length > 0) {
|
|
660
|
-
console.log(
|
|
1162
|
+
console.log(chalk5.yellow(`\u{1F4DD} Components with updates available (${componentsWithChanges.length}):
|
|
661
1163
|
`));
|
|
662
1164
|
for (const result of componentsWithChanges) {
|
|
663
|
-
console.log(
|
|
1165
|
+
console.log(chalk5.yellow(` \u2022 ${chalk5.bold(result.name)}`));
|
|
664
1166
|
for (const file of result.files) {
|
|
665
1167
|
if (file.hasChanges) {
|
|
666
1168
|
if (file.isMissing) {
|
|
667
|
-
console.log(
|
|
1169
|
+
console.log(chalk5.red(` \u2514\u2500 ${file.name} (missing locally)`));
|
|
668
1170
|
} else {
|
|
669
|
-
console.log(
|
|
1171
|
+
console.log(chalk5.dim(` \u2514\u2500 ${file.name} (modified)`));
|
|
670
1172
|
}
|
|
671
1173
|
}
|
|
672
1174
|
}
|
|
673
1175
|
}
|
|
674
1176
|
console.log();
|
|
675
|
-
console.log(
|
|
1177
|
+
console.log(chalk5.dim(`Run ${chalk5.bold("npx pittaya update <component>")} to update.`));
|
|
676
1178
|
}
|
|
677
1179
|
if (componentsUpToDate.length > 0) {
|
|
678
|
-
console.log(
|
|
1180
|
+
console.log(chalk5.green(`
|
|
679
1181
|
\u2705 Components up to date (${componentsUpToDate.length}):
|
|
680
1182
|
`));
|
|
681
1183
|
for (const result of componentsUpToDate) {
|
|
682
|
-
console.log(
|
|
1184
|
+
console.log(chalk5.dim(` \u2022 ${result.name}`));
|
|
683
1185
|
}
|
|
684
1186
|
}
|
|
685
1187
|
console.log();
|
|
686
1188
|
}
|
|
687
1189
|
|
|
688
1190
|
// src/commands/update.ts
|
|
689
|
-
import
|
|
690
|
-
import
|
|
691
|
-
import
|
|
692
|
-
import
|
|
693
|
-
import
|
|
1191
|
+
import chalk6 from "chalk";
|
|
1192
|
+
import ora5 from "ora";
|
|
1193
|
+
import prompts5 from "prompts";
|
|
1194
|
+
import path11 from "path";
|
|
1195
|
+
import fs11 from "fs/promises";
|
|
694
1196
|
async function update(components, options) {
|
|
695
1197
|
const cwd = process.cwd();
|
|
696
|
-
const componentsJsonPath = path7.join(cwd, "components.json");
|
|
697
1198
|
let config;
|
|
698
1199
|
try {
|
|
699
|
-
const
|
|
700
|
-
config =
|
|
1200
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1201
|
+
config = loaded.config;
|
|
1202
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
701
1203
|
} catch (error) {
|
|
702
|
-
console.log(
|
|
1204
|
+
console.log(chalk6.red("\n\u274C components.json not found.\n"));
|
|
703
1205
|
console.log(
|
|
704
|
-
|
|
1206
|
+
chalk6.dim(`Run ${chalk6.bold("npx pittaya init")} first.
|
|
705
1207
|
`)
|
|
706
1208
|
);
|
|
707
1209
|
return;
|
|
708
1210
|
}
|
|
709
|
-
const spinner =
|
|
1211
|
+
const spinner = ora5("Fetching registry...").start();
|
|
710
1212
|
let registry;
|
|
711
1213
|
try {
|
|
712
|
-
registry = await fetchRegistry();
|
|
1214
|
+
registry = await fetchRegistry(config);
|
|
713
1215
|
spinner.succeed("Registry loaded!");
|
|
714
1216
|
} catch (error) {
|
|
715
1217
|
spinner.fail("Error loading registry");
|
|
@@ -726,18 +1228,16 @@ async function update(components, options) {
|
|
|
726
1228
|
}
|
|
727
1229
|
}
|
|
728
1230
|
if (componentsToUpdate.length === 0) {
|
|
729
|
-
console.log(
|
|
1231
|
+
console.log(chalk6.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
|
|
730
1232
|
return;
|
|
731
1233
|
}
|
|
732
1234
|
if (!options.yes && !options.force) {
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
if (!confirm) {
|
|
740
|
-
console.log(chalk5.yellow("\n\u274C Update cancelled.\n"));
|
|
1235
|
+
const shouldUpdate = await confirm(
|
|
1236
|
+
`Update ${componentsToUpdate.length} component(s)?`,
|
|
1237
|
+
true
|
|
1238
|
+
);
|
|
1239
|
+
if (!shouldUpdate) {
|
|
1240
|
+
console.log(chalk6.yellow("\n\u274C Update cancelled.\n"));
|
|
741
1241
|
return;
|
|
742
1242
|
}
|
|
743
1243
|
}
|
|
@@ -751,10 +1251,10 @@ async function update(components, options) {
|
|
|
751
1251
|
}
|
|
752
1252
|
}
|
|
753
1253
|
if (installedComponents.length === 0) {
|
|
754
|
-
console.log(
|
|
1254
|
+
console.log(chalk6.yellow("\n\u26A0\uFE0F No components installed yet.\n"));
|
|
755
1255
|
return;
|
|
756
1256
|
}
|
|
757
|
-
const { selected } = await
|
|
1257
|
+
const { selected } = await prompts5({
|
|
758
1258
|
type: "multiselect",
|
|
759
1259
|
name: "selected",
|
|
760
1260
|
message: "Select components to update:",
|
|
@@ -765,14 +1265,14 @@ async function update(components, options) {
|
|
|
765
1265
|
min: 1
|
|
766
1266
|
});
|
|
767
1267
|
if (!selected || selected.length === 0) {
|
|
768
|
-
console.log(
|
|
1268
|
+
console.log(chalk6.yellow("\n\u274C No components selected.\n"));
|
|
769
1269
|
return;
|
|
770
1270
|
}
|
|
771
1271
|
componentsToUpdate = selected;
|
|
772
1272
|
} else {
|
|
773
1273
|
componentsToUpdate = components;
|
|
774
1274
|
}
|
|
775
|
-
console.log(
|
|
1275
|
+
console.log(chalk6.dim(`
|
|
776
1276
|
Checking ${componentsToUpdate.length} component(s) for updates...
|
|
777
1277
|
`));
|
|
778
1278
|
const results = [];
|
|
@@ -785,9 +1285,9 @@ Checking ${componentsToUpdate.length} component(s) for updates...
|
|
|
785
1285
|
async function hasComponentChanges(component, config) {
|
|
786
1286
|
for (const file of component.files) {
|
|
787
1287
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
788
|
-
const filePath =
|
|
1288
|
+
const filePath = path11.join(process.cwd(), targetPath);
|
|
789
1289
|
try {
|
|
790
|
-
const localContent = await
|
|
1290
|
+
const localContent = await fs11.readFile(filePath, "utf-8");
|
|
791
1291
|
const registryContent = transformImports(file.content, config);
|
|
792
1292
|
if (localContent.trim() !== registryContent.trim()) {
|
|
793
1293
|
return true;
|
|
@@ -800,45 +1300,40 @@ async function hasComponentChanges(component, config) {
|
|
|
800
1300
|
}
|
|
801
1301
|
async function updateComponent(name, config, options) {
|
|
802
1302
|
try {
|
|
803
|
-
const component = await getRegistryComponent(name);
|
|
1303
|
+
const component = await getRegistryComponent(name, config);
|
|
804
1304
|
if (!component) {
|
|
805
|
-
console.log(
|
|
1305
|
+
console.log(chalk6.red(` \u274C Component "${name}" not found in registry.`));
|
|
806
1306
|
return { name, updated: false, skipped: true, reason: "not found in registry" };
|
|
807
1307
|
}
|
|
808
1308
|
const isInstalled = await isComponentInstalled(name, config);
|
|
809
1309
|
if (!isInstalled) {
|
|
810
|
-
console.log(
|
|
1310
|
+
console.log(chalk6.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
|
|
811
1311
|
return { name, updated: false, skipped: true, reason: "not installed" };
|
|
812
1312
|
}
|
|
813
1313
|
const hasChanges = await hasComponentChanges(component, config);
|
|
814
1314
|
if (!hasChanges && !options.force) {
|
|
815
|
-
console.log(
|
|
1315
|
+
console.log(chalk6.dim(` \u2713 ${name} is already up to date`));
|
|
816
1316
|
return { name, updated: false, skipped: true, reason: "already up to date" };
|
|
817
1317
|
}
|
|
818
1318
|
if (!options.yes && !options.force) {
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
name
|
|
822
|
-
message: `Update ${chalk5.bold(name)}?`,
|
|
823
|
-
initial: true
|
|
824
|
-
});
|
|
825
|
-
if (!confirm) {
|
|
826
|
-
console.log(chalk5.yellow(` \u23ED\uFE0F Skipped ${name}`));
|
|
1319
|
+
const shouldUpdate = await confirm(`Update ${chalk6.bold(name)}?`, true);
|
|
1320
|
+
if (!shouldUpdate) {
|
|
1321
|
+
console.log(chalk6.yellow(` \u23ED\uFE0F Skipped ${name}`));
|
|
827
1322
|
return { name, updated: false, skipped: true, reason: "user cancelled" };
|
|
828
1323
|
}
|
|
829
1324
|
}
|
|
830
|
-
const spinner =
|
|
1325
|
+
const spinner = ora5(`Updating ${chalk6.bold(name)}...`).start();
|
|
831
1326
|
for (const file of component.files) {
|
|
832
1327
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
833
|
-
const filePath =
|
|
834
|
-
await
|
|
1328
|
+
const filePath = path11.join(process.cwd(), targetPath);
|
|
1329
|
+
await fs11.mkdir(path11.dirname(filePath), { recursive: true });
|
|
835
1330
|
const content = transformImports(file.content, config);
|
|
836
|
-
await
|
|
1331
|
+
await fs11.writeFile(filePath, content, "utf-8");
|
|
837
1332
|
}
|
|
838
|
-
spinner.succeed(`${
|
|
1333
|
+
spinner.succeed(`${chalk6.bold(name)} updated successfully!`);
|
|
839
1334
|
return { name, updated: true, skipped: false };
|
|
840
1335
|
} catch (error) {
|
|
841
|
-
console.log(
|
|
1336
|
+
console.log(chalk6.red(` \u274C Error updating ${name}`));
|
|
842
1337
|
console.error(error);
|
|
843
1338
|
return { name, updated: false, skipped: true, reason: "error" };
|
|
844
1339
|
}
|
|
@@ -848,48 +1343,46 @@ function displayUpdateResults(results) {
|
|
|
848
1343
|
const skipped = results.filter((r) => r.skipped);
|
|
849
1344
|
console.log();
|
|
850
1345
|
if (updated.length > 0) {
|
|
851
|
-
console.log(
|
|
1346
|
+
console.log(chalk6.green(`\u2705 Updated ${updated.length} component(s):
|
|
852
1347
|
`));
|
|
853
1348
|
for (const result of updated) {
|
|
854
|
-
console.log(
|
|
1349
|
+
console.log(chalk6.dim(` \u2022 ${result.name}`));
|
|
855
1350
|
}
|
|
856
1351
|
}
|
|
857
1352
|
if (skipped.length > 0) {
|
|
858
|
-
console.log(
|
|
1353
|
+
console.log(chalk6.yellow(`
|
|
859
1354
|
\u23ED\uFE0F Skipped ${skipped.length} component(s):
|
|
860
1355
|
`));
|
|
861
1356
|
for (const result of skipped) {
|
|
862
1357
|
const reason = result.reason ? ` (${result.reason})` : "";
|
|
863
|
-
console.log(
|
|
1358
|
+
console.log(chalk6.dim(` \u2022 ${result.name}${reason}`));
|
|
864
1359
|
}
|
|
865
1360
|
}
|
|
866
1361
|
console.log();
|
|
867
1362
|
}
|
|
868
1363
|
|
|
869
1364
|
// src/commands/list.ts
|
|
870
|
-
import
|
|
871
|
-
import
|
|
872
|
-
import path8 from "path";
|
|
873
|
-
import fs8 from "fs/promises";
|
|
1365
|
+
import chalk7 from "chalk";
|
|
1366
|
+
import ora6 from "ora";
|
|
874
1367
|
async function list(options) {
|
|
875
1368
|
const cwd = process.cwd();
|
|
876
|
-
const componentsJsonPath = path8.join(cwd, "components.json");
|
|
877
1369
|
let config;
|
|
878
1370
|
try {
|
|
879
|
-
const
|
|
880
|
-
config =
|
|
1371
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1372
|
+
config = loaded.config;
|
|
1373
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
881
1374
|
} catch (error) {
|
|
882
|
-
console.log(
|
|
1375
|
+
console.log(chalk7.red("\n\u274C components.json not found.\n"));
|
|
883
1376
|
console.log(
|
|
884
|
-
|
|
1377
|
+
chalk7.dim(`Run ${chalk7.bold("npx pittaya init")} first.
|
|
885
1378
|
`)
|
|
886
1379
|
);
|
|
887
1380
|
return;
|
|
888
1381
|
}
|
|
889
|
-
const spinner =
|
|
1382
|
+
const spinner = ora6("Fetching components...").start();
|
|
890
1383
|
let registry;
|
|
891
1384
|
try {
|
|
892
|
-
registry = await fetchRegistry();
|
|
1385
|
+
registry = await fetchRegistry(config);
|
|
893
1386
|
spinner.succeed("Components loaded!");
|
|
894
1387
|
} catch (error) {
|
|
895
1388
|
spinner.fail("Error loading registry");
|
|
@@ -899,9 +1392,10 @@ async function list(options) {
|
|
|
899
1392
|
const allComponents = registry.components || [];
|
|
900
1393
|
const componentsWithStatus = await Promise.all(
|
|
901
1394
|
allComponents.map(async (comp) => {
|
|
902
|
-
const
|
|
1395
|
+
const slug = comp.slug || comp.name;
|
|
1396
|
+
const installed = await isComponentInstalled(slug, config);
|
|
903
1397
|
return {
|
|
904
|
-
...comp,
|
|
1398
|
+
...comp.slug ? comp : { ...comp, slug },
|
|
905
1399
|
installed
|
|
906
1400
|
};
|
|
907
1401
|
})
|
|
@@ -921,13 +1415,13 @@ async function list(options) {
|
|
|
921
1415
|
function displayComponents(components, options) {
|
|
922
1416
|
if (components.length === 0) {
|
|
923
1417
|
if (options.installed) {
|
|
924
|
-
console.log(
|
|
925
|
-
console.log(
|
|
1418
|
+
console.log(chalk7.yellow("\n\u{1F4E6} No components installed yet.\n"));
|
|
1419
|
+
console.log(chalk7.dim(`Run ${chalk7.bold("npx pittaya add")} to install components.
|
|
926
1420
|
`));
|
|
927
1421
|
} else if (options.available) {
|
|
928
|
-
console.log(
|
|
1422
|
+
console.log(chalk7.yellow("\n\u2728 All components are already installed!\n"));
|
|
929
1423
|
} else {
|
|
930
|
-
console.log(
|
|
1424
|
+
console.log(chalk7.yellow("\n\u26A0\uFE0F No components found in registry.\n"));
|
|
931
1425
|
}
|
|
932
1426
|
return;
|
|
933
1427
|
}
|
|
@@ -941,20 +1435,20 @@ function displayComponents(components, options) {
|
|
|
941
1435
|
}, {});
|
|
942
1436
|
console.log("\n");
|
|
943
1437
|
if (options.installed) {
|
|
944
|
-
console.log(
|
|
1438
|
+
console.log(chalk7.bold.green("\u{1F4E6} Installed Components\n"));
|
|
945
1439
|
} else if (options.available) {
|
|
946
|
-
console.log(
|
|
1440
|
+
console.log(chalk7.bold.blue("\u2728 Available Components\n"));
|
|
947
1441
|
} else {
|
|
948
|
-
console.log(
|
|
1442
|
+
console.log(chalk7.bold("\u{1F4CB} All Components\n"));
|
|
949
1443
|
}
|
|
950
1444
|
Object.entries(categorized).sort().forEach(([category, comps]) => {
|
|
951
|
-
console.log(
|
|
1445
|
+
console.log(chalk7.bold.cyan(`${category}:`));
|
|
952
1446
|
comps.forEach((comp) => {
|
|
953
|
-
const status = comp.installed ?
|
|
954
|
-
const name = comp.installed ?
|
|
955
|
-
const description = comp.description ?
|
|
956
|
-
const deps = comp.dependencies && comp.dependencies.length > 0 ?
|
|
957
|
-
const internalDeps = comp.internalDependencies && comp.internalDependencies.length > 0 ?
|
|
1447
|
+
const status = comp.installed ? chalk7.green("\u2713") : chalk7.dim("\u25CB");
|
|
1448
|
+
const name = comp.installed ? chalk7.bold(comp.slug) : chalk7.dim(comp.slug);
|
|
1449
|
+
const description = comp.description ? chalk7.dim(` - ${comp.description}`) : "";
|
|
1450
|
+
const deps = comp.dependencies && comp.dependencies.length > 0 ? chalk7.dim.yellow(` [${comp.dependencies.length} deps]`) : "";
|
|
1451
|
+
const internalDeps = comp.internalDependencies && comp.internalDependencies.length > 0 ? chalk7.dim.blue(` [requires: ${comp.internalDependencies.join(", ")}]`) : "";
|
|
958
1452
|
console.log(` ${status} ${name}${description}${deps}${internalDeps}`);
|
|
959
1453
|
});
|
|
960
1454
|
console.log();
|
|
@@ -962,117 +1456,142 @@ function displayComponents(components, options) {
|
|
|
962
1456
|
const installedCount = components.filter((c) => c.installed).length;
|
|
963
1457
|
const totalCount = components.length;
|
|
964
1458
|
if (!options.installed && !options.available) {
|
|
965
|
-
console.log(
|
|
1459
|
+
console.log(chalk7.dim(`Total: ${totalCount} components (${installedCount} installed, ${totalCount - installedCount} available)
|
|
966
1460
|
`));
|
|
967
1461
|
} else {
|
|
968
|
-
console.log(
|
|
1462
|
+
console.log(chalk7.dim(`Total: ${totalCount} components
|
|
969
1463
|
`));
|
|
970
1464
|
}
|
|
971
1465
|
}
|
|
972
1466
|
|
|
973
1467
|
// src/commands/debug.ts
|
|
974
|
-
import
|
|
975
|
-
import
|
|
976
|
-
import
|
|
1468
|
+
import chalk8 from "chalk";
|
|
1469
|
+
import path12 from "path";
|
|
1470
|
+
import fs12 from "fs/promises";
|
|
977
1471
|
async function debug(options) {
|
|
978
1472
|
const cwd = process.cwd();
|
|
979
|
-
|
|
980
|
-
console.log(
|
|
981
|
-
console.log(chalk7.dim(`Working directory: ${cwd}
|
|
1473
|
+
console.log(chalk8.bold("\n\u{1F50D} Pittaya UI Debug Information\n"));
|
|
1474
|
+
console.log(chalk8.dim(`Working directory: ${cwd}
|
|
982
1475
|
`));
|
|
983
1476
|
let config;
|
|
984
1477
|
try {
|
|
985
|
-
const
|
|
986
|
-
config =
|
|
987
|
-
|
|
988
|
-
console.log(
|
|
1478
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1479
|
+
config = loaded.config;
|
|
1480
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
1481
|
+
console.log(chalk8.green("\u2705 components.json found"));
|
|
1482
|
+
console.log(chalk8.dim(` Path: ${path12.join(cwd, "components.json")}`));
|
|
989
1483
|
} catch (error) {
|
|
990
|
-
console.log(
|
|
1484
|
+
console.log(chalk8.red("\u274C components.json not found\n"));
|
|
991
1485
|
return;
|
|
992
1486
|
}
|
|
993
1487
|
const usesSrc = await hasSrcDirectory(cwd);
|
|
994
|
-
console.log(
|
|
995
|
-
console.log(
|
|
996
|
-
console.log(
|
|
997
|
-
console.log(
|
|
998
|
-
console.log(
|
|
1488
|
+
console.log(chalk8.green(`\u2705 Project structure: ${usesSrc ? "src/" : "root"}`));
|
|
1489
|
+
console.log(chalk8.bold("\n\u{1F4CB} Configured Aliases:"));
|
|
1490
|
+
console.log(chalk8.dim(` components: ${config.aliases.components}`));
|
|
1491
|
+
console.log(chalk8.dim(` utils: ${config.aliases.utils}`));
|
|
1492
|
+
console.log(chalk8.dim(` ui: ${config.aliases.ui}`));
|
|
999
1493
|
const resolvedUi = await resolveAliasPath(config.aliases.ui, cwd);
|
|
1000
1494
|
const resolvedLib = await resolveAliasPath(config.aliases.lib || "@/lib", cwd);
|
|
1001
|
-
console.log(
|
|
1002
|
-
console.log(
|
|
1003
|
-
console.log(
|
|
1495
|
+
console.log(chalk8.bold("\n\u{1F4C2} Resolved Paths:"));
|
|
1496
|
+
console.log(chalk8.dim(` UI components: ${resolvedUi}`));
|
|
1497
|
+
console.log(chalk8.dim(` Libraries: ${resolvedLib}`));
|
|
1004
1498
|
if (options.component) {
|
|
1005
|
-
console.log(
|
|
1499
|
+
console.log(chalk8.bold(`
|
|
1006
1500
|
\u{1F50D} Debugging component: ${options.component}
|
|
1007
1501
|
`));
|
|
1008
1502
|
try {
|
|
1009
|
-
const component = await getRegistryComponent(options.component);
|
|
1503
|
+
const component = await getRegistryComponent(options.component, config);
|
|
1010
1504
|
if (!component) {
|
|
1011
|
-
console.log(
|
|
1505
|
+
console.log(chalk8.red(`\u274C Component not found in registry
|
|
1012
1506
|
`));
|
|
1013
1507
|
return;
|
|
1014
1508
|
}
|
|
1015
|
-
console.log(
|
|
1016
|
-
console.log(
|
|
1017
|
-
console.log(
|
|
1018
|
-
console.log(
|
|
1509
|
+
console.log(chalk8.green(`\u2705 Component found in registry`));
|
|
1510
|
+
console.log(chalk8.dim(` Type: ${component.type}`));
|
|
1511
|
+
console.log(chalk8.dim(` Files: ${component.files.length}`));
|
|
1512
|
+
console.log(chalk8.bold("\n\u{1F4C1} Expected Files:"));
|
|
1019
1513
|
for (const file of component.files) {
|
|
1020
1514
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
1021
|
-
const fullPath =
|
|
1022
|
-
const exists = await
|
|
1023
|
-
const statusIcon = exists ?
|
|
1024
|
-
const statusText = exists ?
|
|
1515
|
+
const fullPath = path12.join(cwd, targetPath);
|
|
1516
|
+
const exists = await fs12.access(fullPath).then(() => true).catch(() => false);
|
|
1517
|
+
const statusIcon = exists ? chalk8.green("\u2705") : chalk8.red("\u274C");
|
|
1518
|
+
const statusText = exists ? chalk8.green("EXISTS") : chalk8.red("NOT FOUND");
|
|
1025
1519
|
console.log(` ${statusIcon} ${file.name}`);
|
|
1026
|
-
console.log(
|
|
1027
|
-
console.log(
|
|
1520
|
+
console.log(chalk8.dim(` Expected: ${fullPath}`));
|
|
1521
|
+
console.log(chalk8.dim(` Status: ${statusText}`));
|
|
1028
1522
|
if (!exists) {
|
|
1029
|
-
const dir =
|
|
1523
|
+
const dir = path12.dirname(fullPath);
|
|
1030
1524
|
try {
|
|
1031
|
-
const dirExists = await
|
|
1525
|
+
const dirExists = await fs12.access(dir).then(() => true).catch(() => false);
|
|
1032
1526
|
if (dirExists) {
|
|
1033
|
-
const filesInDir = await
|
|
1034
|
-
const baseName =
|
|
1527
|
+
const filesInDir = await fs12.readdir(dir);
|
|
1528
|
+
const baseName = path12.basename(file.name, path12.extname(file.name));
|
|
1035
1529
|
const similarFiles = filesInDir.filter(
|
|
1036
1530
|
(f) => f.includes(baseName) || f.toLowerCase().includes(baseName.toLowerCase())
|
|
1037
1531
|
);
|
|
1038
1532
|
if (similarFiles.length > 0) {
|
|
1039
|
-
console.log(
|
|
1533
|
+
console.log(chalk8.yellow(` \u{1F4A1} Similar files found in directory:`));
|
|
1040
1534
|
similarFiles.forEach((f) => {
|
|
1041
|
-
console.log(
|
|
1535
|
+
console.log(chalk8.dim(` - ${f}`));
|
|
1042
1536
|
});
|
|
1043
1537
|
}
|
|
1044
1538
|
} else {
|
|
1045
|
-
console.log(
|
|
1539
|
+
console.log(chalk8.red(` \u26A0\uFE0F Directory doesn't exist: ${dir}`));
|
|
1046
1540
|
}
|
|
1047
1541
|
} catch (err) {
|
|
1048
1542
|
}
|
|
1049
1543
|
}
|
|
1050
1544
|
}
|
|
1051
1545
|
const isInstalled = await isComponentInstalled(options.component, config);
|
|
1052
|
-
console.log(
|
|
1546
|
+
console.log(chalk8.bold(`
|
|
1053
1547
|
\u{1F4CA} Installation Status:`));
|
|
1054
1548
|
if (isInstalled) {
|
|
1055
|
-
console.log(
|
|
1549
|
+
console.log(chalk8.green(` \u2705 Component is detected as INSTALLED`));
|
|
1056
1550
|
} else {
|
|
1057
|
-
console.log(
|
|
1058
|
-
console.log(
|
|
1551
|
+
console.log(chalk8.red(` \u274C Component is detected as NOT INSTALLED`));
|
|
1552
|
+
console.log(chalk8.yellow(` \u{1F4A1} All files must exist for component to be considered installed`));
|
|
1059
1553
|
}
|
|
1060
1554
|
} catch (error) {
|
|
1061
|
-
console.log(
|
|
1555
|
+
console.log(chalk8.red(`
|
|
1062
1556
|
\u274C Error debugging component:`));
|
|
1063
1557
|
console.error(error);
|
|
1064
1558
|
}
|
|
1065
1559
|
} else {
|
|
1066
|
-
console.log(
|
|
1067
|
-
console.log(
|
|
1560
|
+
console.log(chalk8.yellow("\n\u{1F4A1} To debug a specific component, use:"));
|
|
1561
|
+
console.log(chalk8.dim(" npx pittaya debug --component <name>\n"));
|
|
1562
|
+
}
|
|
1563
|
+
}
|
|
1564
|
+
|
|
1565
|
+
// src/utils/banner.ts
|
|
1566
|
+
import chalk9 from "chalk";
|
|
1567
|
+
import CFonts from "cfonts";
|
|
1568
|
+
import gradient from "gradient-string";
|
|
1569
|
+
async function showBanner() {
|
|
1570
|
+
try {
|
|
1571
|
+
const textOutput = CFonts.render("Pittaya UI", {
|
|
1572
|
+
font: "block",
|
|
1573
|
+
align: "left",
|
|
1574
|
+
colors: ["system"],
|
|
1575
|
+
background: "transparent",
|
|
1576
|
+
letterSpacing: 1,
|
|
1577
|
+
lineHeight: 1,
|
|
1578
|
+
space: false
|
|
1579
|
+
});
|
|
1580
|
+
const pittayaGradient = gradient(["#fda4af", "#fb7185", "#9f1239"]);
|
|
1581
|
+
process.stdout.write("\n" + pittayaGradient.multiline(textOutput?.string || "Pittaya UI"));
|
|
1582
|
+
console.log(chalk9.gray(`
|
|
1583
|
+
${"\u2500".repeat(20)} Pittaya UI - Components that scale with your ideas ${"\u2500".repeat(20)}
|
|
1584
|
+
`));
|
|
1585
|
+
} catch (error) {
|
|
1586
|
+
CFonts.say("Pittaya UI", { font: "block", colors: ["#fb7185"] });
|
|
1068
1587
|
}
|
|
1069
1588
|
}
|
|
1070
1589
|
|
|
1071
1590
|
// src/index.ts
|
|
1072
1591
|
import { readFileSync } from "fs";
|
|
1073
|
-
import { fileURLToPath } from "url";
|
|
1592
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1074
1593
|
import { dirname, join } from "path";
|
|
1075
|
-
var __filename =
|
|
1594
|
+
var __filename = fileURLToPath2(import.meta.url);
|
|
1076
1595
|
var __dirname = dirname(__filename);
|
|
1077
1596
|
var packageJson = JSON.parse(
|
|
1078
1597
|
readFileSync(join(__dirname, "../package.json"), "utf-8")
|
|
@@ -1081,10 +1600,22 @@ var program = new Command();
|
|
|
1081
1600
|
program.name("pittaya").description("Add Pittaya UI components to your project").version(packageJson.version);
|
|
1082
1601
|
program.command("init").description("Initialize Pittaya UI in your project").option("-y, --yes", "Skip confirmations and use default values").action(init);
|
|
1083
1602
|
program.command("add").description("Add a component to your project").argument("[components...]", "Component names to add").option("-y, --yes", "Skip confirmations and overwrite existing files").option("-o, --overwrite", "Overwrite existing files").option("-a, --all", "Add all available components").option("--add-missing-deps", "Automatically install missing dependencies").action(add);
|
|
1603
|
+
program.command("remove").description("Remove a component from your project").argument("[components...]", "Component names to remove").option("-y, --yes", "Skip confirmation prompts").action(remove);
|
|
1084
1604
|
program.command("diff").description("Check for component updates").argument("[components...]", "Component names to check (leave empty for interactive mode)").option("-a, --all", "Check all installed components").action(diff);
|
|
1085
1605
|
program.command("update").description("Update components to latest version").argument("[components...]", "Component names to update (leave empty for interactive mode)").option("-a, --all", "Update all installed components").option("-y, --yes", "Skip confirmation prompts").option("-f, --force", "Force update even if no changes detected").action(update);
|
|
1086
1606
|
program.command("list").description("List available and installed components").option("--installed", "Show only installed components").option("--available", "Show only available components").option("--json", "Output in JSON format").action(list);
|
|
1087
1607
|
program.command("credits").description("Show Pittaya UI creators").action(credits);
|
|
1608
|
+
program.command("banner").description("Show the amazing Pittaya banner").action(showBanner);
|
|
1088
1609
|
program.command("debug").description("Debug component installation issues").option("-c, --component <name>", "Component name to debug").action(debug);
|
|
1089
|
-
|
|
1610
|
+
async function run() {
|
|
1611
|
+
const args = process.argv.slice(2);
|
|
1612
|
+
const isHelpOrVersion = args.some((arg) => ["--help", "-h", "--version", "-v"].includes(arg));
|
|
1613
|
+
const isInitCommand = args.length > 0 && args[0] === "init";
|
|
1614
|
+
const isCreditsCommand = args.length > 0 && args[0] === "credits";
|
|
1615
|
+
if (isInitCommand || isCreditsCommand) {
|
|
1616
|
+
await showBanner();
|
|
1617
|
+
}
|
|
1618
|
+
program.parse();
|
|
1619
|
+
}
|
|
1620
|
+
run();
|
|
1090
1621
|
//# sourceMappingURL=index.js.map
|