pittaya 0.0.6 → 0.0.9
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 +60 -0
- package/dist/index.js +797 -241
- package/dist/index.js.map +1 -1
- package/package.json +57 -53
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
|
}
|
|
@@ -125,14 +171,208 @@ async function checkMissingDependencies(dependencies) {
|
|
|
125
171
|
return missing;
|
|
126
172
|
}
|
|
127
173
|
|
|
174
|
+
// src/utils/component-checker.ts
|
|
175
|
+
import path4 from "path";
|
|
176
|
+
import fs4 from "fs/promises";
|
|
177
|
+
|
|
178
|
+
// src/utils/project-structure.ts
|
|
179
|
+
import fs3 from "fs/promises";
|
|
180
|
+
import path3 from "path";
|
|
181
|
+
async function hasSrcDirectory(cwd = process.cwd()) {
|
|
182
|
+
try {
|
|
183
|
+
const srcPath = path3.join(cwd, "src");
|
|
184
|
+
await fs3.access(srcPath);
|
|
185
|
+
const commonDirs = ["app", "components", "lib", "pages"];
|
|
186
|
+
for (const dir of commonDirs) {
|
|
187
|
+
try {
|
|
188
|
+
await fs3.access(path3.join(srcPath, dir));
|
|
189
|
+
return true;
|
|
190
|
+
} catch {
|
|
191
|
+
continue;
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
try {
|
|
195
|
+
const tsconfigPath = path3.join(cwd, "tsconfig.json");
|
|
196
|
+
const tsconfig = JSON.parse(await fs3.readFile(tsconfigPath, "utf-8"));
|
|
197
|
+
if (tsconfig.compilerOptions?.paths) {
|
|
198
|
+
const paths = tsconfig.compilerOptions.paths;
|
|
199
|
+
if (paths["@/*"]?.includes("./src/*")) {
|
|
200
|
+
return true;
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
} catch {
|
|
204
|
+
console.error("Bro... just in 21st century you not even have a tsconfig.json file in your project. That way you fuck me up :D");
|
|
205
|
+
}
|
|
206
|
+
return false;
|
|
207
|
+
} catch {
|
|
208
|
+
return false;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
async function resolveAliasPath(aliasPath, cwd = process.cwd()) {
|
|
212
|
+
const usesSrc = await hasSrcDirectory(cwd);
|
|
213
|
+
const baseDir = usesSrc ? "src/" : "";
|
|
214
|
+
return aliasPath.replace(/^@\//, baseDir);
|
|
215
|
+
}
|
|
216
|
+
async function getDefaultPaths(cwd = process.cwd()) {
|
|
217
|
+
const usesSrc = await hasSrcDirectory(cwd);
|
|
218
|
+
const baseDir = usesSrc ? "src/" : "";
|
|
219
|
+
return {
|
|
220
|
+
globalsCss: `${baseDir}app/globals.css`,
|
|
221
|
+
components: "@/components",
|
|
222
|
+
utils: "@/lib/utils",
|
|
223
|
+
ui: "@/components/ui",
|
|
224
|
+
lib: "@/lib",
|
|
225
|
+
hooks: "@/hooks",
|
|
226
|
+
baseDir
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
// src/utils/component-checker.ts
|
|
231
|
+
async function isComponentInstalled(name, config) {
|
|
232
|
+
try {
|
|
233
|
+
const component = await getRegistryComponent(name, config);
|
|
234
|
+
if (!component) return false;
|
|
235
|
+
for (const file of component.files) {
|
|
236
|
+
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
237
|
+
const filePath = path4.join(process.cwd(), targetPath);
|
|
238
|
+
const exists = await fs4.access(filePath).then(() => true).catch(() => false);
|
|
239
|
+
if (!exists) return false;
|
|
240
|
+
}
|
|
241
|
+
return true;
|
|
242
|
+
} catch {
|
|
243
|
+
return false;
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
async function resolveTargetPath(fileName, type, config) {
|
|
247
|
+
const normalized = fileName.replace(/\\/g, "/");
|
|
248
|
+
if (type === "registry:ui") {
|
|
249
|
+
const resolvedPath = await resolveAliasPath(config.aliases.ui);
|
|
250
|
+
const relative = normalized.replace(/^ui\//, "");
|
|
251
|
+
return path4.join(resolvedPath, relative);
|
|
252
|
+
}
|
|
253
|
+
if (type === "registry:lib") {
|
|
254
|
+
const resolvedPath = await resolveAliasPath(config.aliases.lib);
|
|
255
|
+
const relative = normalized.replace(/^lib\//, "");
|
|
256
|
+
return path4.join(resolvedPath, relative);
|
|
257
|
+
}
|
|
258
|
+
if (type === "registry:hook") {
|
|
259
|
+
const resolvedPath = await resolveAliasPath(config.aliases.hooks);
|
|
260
|
+
return path4.join(resolvedPath, fileName);
|
|
261
|
+
}
|
|
262
|
+
return fileName;
|
|
263
|
+
}
|
|
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
|
+
|
|
128
366
|
// src/commands/add.ts
|
|
129
367
|
async function add(components, options) {
|
|
130
368
|
const cwd = process.cwd();
|
|
131
|
-
const componentsJsonPath = path2.join(cwd, "components.json");
|
|
132
369
|
let config;
|
|
370
|
+
let pittayaConfig;
|
|
133
371
|
try {
|
|
134
|
-
const
|
|
135
|
-
config =
|
|
372
|
+
const loaded = await loadProjectConfig(cwd);
|
|
373
|
+
config = loaded.config;
|
|
374
|
+
pittayaConfig = loaded.pittaya;
|
|
375
|
+
applyPittayaProjectConfig(pittayaConfig);
|
|
136
376
|
} catch (error) {
|
|
137
377
|
console.log(chalk.red("\n\u274C components.json not found.\n"));
|
|
138
378
|
console.log(
|
|
@@ -141,10 +381,14 @@ async function add(components, options) {
|
|
|
141
381
|
);
|
|
142
382
|
return;
|
|
143
383
|
}
|
|
384
|
+
const resolvedOptions = {
|
|
385
|
+
...options,
|
|
386
|
+
addMissingDeps: options.addMissingDeps ?? pittayaConfig?.install?.autoInstallDeps ?? false
|
|
387
|
+
};
|
|
144
388
|
const spinner = ora("Fetching available components...").start();
|
|
145
389
|
let registry;
|
|
146
390
|
try {
|
|
147
|
-
registry = await fetchRegistry();
|
|
391
|
+
registry = await fetchRegistry(config);
|
|
148
392
|
spinner.succeed("Registry loaded!");
|
|
149
393
|
} catch (error) {
|
|
150
394
|
spinner.fail("Error loading registry");
|
|
@@ -178,25 +422,10 @@ Adding ${components.length} component(s)...
|
|
|
178
422
|
`)
|
|
179
423
|
);
|
|
180
424
|
for (const componentName of components) {
|
|
181
|
-
await addComponent(componentName, config,
|
|
425
|
+
await addComponent(componentName, config, resolvedOptions);
|
|
182
426
|
}
|
|
183
427
|
console.log(chalk.green("\n\u2705 Components added successfully!\n"));
|
|
184
428
|
}
|
|
185
|
-
async function isComponentInstalled(name, config) {
|
|
186
|
-
try {
|
|
187
|
-
const component = await getRegistryComponent(name);
|
|
188
|
-
if (!component) return false;
|
|
189
|
-
for (const file of component.files) {
|
|
190
|
-
const targetPath = resolveTargetPath(file.name, component.type, config);
|
|
191
|
-
const filePath = path2.join(process.cwd(), targetPath);
|
|
192
|
-
const exists = await fs2.access(filePath).then(() => true).catch(() => false);
|
|
193
|
-
if (!exists) return false;
|
|
194
|
-
}
|
|
195
|
-
return true;
|
|
196
|
-
} catch {
|
|
197
|
-
return false;
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
429
|
async function addComponent(name, config, options) {
|
|
201
430
|
const alreadyInstalled = await isComponentInstalled(name, config);
|
|
202
431
|
if (alreadyInstalled && !options.overwrite) {
|
|
@@ -205,7 +434,7 @@ async function addComponent(name, config, options) {
|
|
|
205
434
|
}
|
|
206
435
|
const spinner = ora(`Installing ${chalk.bold(name)}...`).start();
|
|
207
436
|
try {
|
|
208
|
-
const component = await getRegistryComponent(name);
|
|
437
|
+
const component = await getRegistryComponent(name, config);
|
|
209
438
|
if (!component) {
|
|
210
439
|
spinner.fail(`Component "${name}" not found in registry.`);
|
|
211
440
|
return;
|
|
@@ -225,12 +454,10 @@ async function addComponent(name, config, options) {
|
|
|
225
454
|
if (options.addMissingDeps) {
|
|
226
455
|
console.log(chalk.dim("Installing dependencies automatically...\n"));
|
|
227
456
|
} else {
|
|
228
|
-
const
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
initial: true
|
|
233
|
-
});
|
|
457
|
+
const install = await confirm(
|
|
458
|
+
"Do you want to install the dependencies now?",
|
|
459
|
+
true
|
|
460
|
+
);
|
|
234
461
|
if (!install) {
|
|
235
462
|
console.log(chalk.yellow("\n\u26A0\uFE0F Component not installed. Install the dependencies manually and try again.\n"));
|
|
236
463
|
return;
|
|
@@ -262,26 +489,24 @@ async function addComponent(name, config, options) {
|
|
|
262
489
|
spinner.start(`Installing ${chalk.bold(name)}...`);
|
|
263
490
|
}
|
|
264
491
|
for (const file of component.files) {
|
|
265
|
-
const targetPath = resolveTargetPath(file.name, component.type, config);
|
|
266
|
-
const filePath =
|
|
267
|
-
const exists = await
|
|
492
|
+
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
493
|
+
const filePath = path6.join(process.cwd(), targetPath);
|
|
494
|
+
const exists = await fs6.access(filePath).then(() => true).catch(() => false);
|
|
268
495
|
if (exists && !options.overwrite && !options.yes) {
|
|
269
496
|
spinner.stop();
|
|
270
|
-
const
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
initial: false
|
|
275
|
-
});
|
|
497
|
+
const overwrite = await confirm(
|
|
498
|
+
`${targetPath} already exists. Overwrite?`,
|
|
499
|
+
false
|
|
500
|
+
);
|
|
276
501
|
if (!overwrite) {
|
|
277
502
|
spinner.warn(`Skipping ${targetPath}`);
|
|
278
503
|
continue;
|
|
279
504
|
}
|
|
280
505
|
spinner.start();
|
|
281
506
|
}
|
|
282
|
-
await
|
|
507
|
+
await fs6.mkdir(path6.dirname(filePath), { recursive: true });
|
|
283
508
|
const content = transformImports(file.content, config);
|
|
284
|
-
await
|
|
509
|
+
await fs6.writeFile(filePath, content, "utf-8");
|
|
285
510
|
}
|
|
286
511
|
spinner.succeed(`${chalk.bold(name)} installed successfully!`);
|
|
287
512
|
} catch (error) {
|
|
@@ -289,86 +514,277 @@ async function addComponent(name, config, options) {
|
|
|
289
514
|
console.error(error);
|
|
290
515
|
}
|
|
291
516
|
}
|
|
292
|
-
function resolveTargetPath(fileName, type, config) {
|
|
293
|
-
if (type === "registry:ui") {
|
|
294
|
-
return path2.join(
|
|
295
|
-
config.aliases.ui.replace("@/", "src/"),
|
|
296
|
-
fileName
|
|
297
|
-
);
|
|
298
|
-
}
|
|
299
|
-
if (type === "registry:lib") {
|
|
300
|
-
return path2.join(
|
|
301
|
-
config.aliases.lib.replace("@/", "src/"),
|
|
302
|
-
fileName
|
|
303
|
-
);
|
|
304
|
-
}
|
|
305
|
-
if (type === "registry:hook") {
|
|
306
|
-
return path2.join(
|
|
307
|
-
config.aliases.hooks.replace("@/", "src/"),
|
|
308
|
-
fileName
|
|
309
|
-
);
|
|
310
|
-
}
|
|
311
|
-
return fileName;
|
|
312
|
-
}
|
|
313
517
|
|
|
314
518
|
// src/commands/init.ts
|
|
315
519
|
import chalk2 from "chalk";
|
|
316
520
|
import ora2 from "ora";
|
|
317
521
|
import prompts2 from "prompts";
|
|
318
|
-
import
|
|
319
|
-
import
|
|
522
|
+
import path8 from "path";
|
|
523
|
+
import fs8 from "fs/promises";
|
|
320
524
|
import { execa as execa2 } from "execa";
|
|
525
|
+
|
|
526
|
+
// src/utils/style-installer.ts
|
|
527
|
+
import fs7 from "fs/promises";
|
|
528
|
+
import path7 from "path";
|
|
529
|
+
import postcss from "postcss";
|
|
530
|
+
async function applyRegistryStyleToProject(styleComponent, config, options) {
|
|
531
|
+
const cssPath = config.tailwind?.css;
|
|
532
|
+
if (!cssPath) {
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
535
|
+
const absoluteCssPath = path7.resolve(process.cwd(), cssPath);
|
|
536
|
+
const raw = await fs7.readFile(absoluteCssPath, "utf-8").catch(() => "");
|
|
537
|
+
const next = await transformTailwindV4Css(raw, styleComponent.cssVars ?? {}, {
|
|
538
|
+
overwriteCssVars: options?.overwriteCssVars ?? true
|
|
539
|
+
});
|
|
540
|
+
await fs7.mkdir(path7.dirname(absoluteCssPath), { recursive: true });
|
|
541
|
+
await fs7.writeFile(absoluteCssPath, next, "utf-8");
|
|
542
|
+
}
|
|
543
|
+
async function transformTailwindV4Css(input, cssVars, options) {
|
|
544
|
+
const result = await postcss([
|
|
545
|
+
ensureImportPlugin({ importPath: "tailwindcss" }),
|
|
546
|
+
ensureImportPlugin({ importPath: "tw-animate-css" }),
|
|
547
|
+
ensureCustomVariantDarkPlugin(),
|
|
548
|
+
upsertThemeAtRulePlugin(cssVars.theme ?? {}, {
|
|
549
|
+
overwrite: options.overwriteCssVars
|
|
550
|
+
}),
|
|
551
|
+
upsertRuleVarsPlugin(":root", cssVars.light ?? {}, {
|
|
552
|
+
overwrite: options.overwriteCssVars
|
|
553
|
+
}),
|
|
554
|
+
upsertRuleVarsPlugin(".dark", cssVars.dark ?? {}, {
|
|
555
|
+
overwrite: options.overwriteCssVars
|
|
556
|
+
}),
|
|
557
|
+
ensureBaseLayerPlugin()
|
|
558
|
+
]).process(input, { from: void 0 });
|
|
559
|
+
return result.css.replace(/(\n\s*\n)+/g, "\n\n").trimStart();
|
|
560
|
+
}
|
|
561
|
+
function ensureImportPlugin({
|
|
562
|
+
importPath
|
|
563
|
+
}) {
|
|
564
|
+
return {
|
|
565
|
+
postcssPlugin: "pittaya-ensure-import",
|
|
566
|
+
Once(root) {
|
|
567
|
+
const exists = root.nodes.some(
|
|
568
|
+
(n) => n.type === "atrule" && n.name === "import" && n.params.includes(`"${importPath}"`)
|
|
569
|
+
);
|
|
570
|
+
if (exists) return;
|
|
571
|
+
const node = postcss.atRule({
|
|
572
|
+
name: "import",
|
|
573
|
+
params: `"${importPath}"`
|
|
574
|
+
});
|
|
575
|
+
root.prepend(node);
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
}
|
|
579
|
+
ensureImportPlugin.postcss = true;
|
|
580
|
+
function ensureCustomVariantDarkPlugin() {
|
|
581
|
+
return {
|
|
582
|
+
postcssPlugin: "pittaya-ensure-custom-variant-dark",
|
|
583
|
+
Once(root) {
|
|
584
|
+
const exists = root.nodes.some(
|
|
585
|
+
(n) => n.type === "atrule" && n.name === "custom-variant" && n.params.startsWith("dark ")
|
|
586
|
+
);
|
|
587
|
+
if (exists) return;
|
|
588
|
+
const node = postcss.atRule({
|
|
589
|
+
name: "custom-variant",
|
|
590
|
+
params: "dark (&:is(.dark *))"
|
|
591
|
+
});
|
|
592
|
+
root.append(node);
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
ensureCustomVariantDarkPlugin.postcss = true;
|
|
597
|
+
function upsertThemeAtRulePlugin(vars, options) {
|
|
598
|
+
return {
|
|
599
|
+
postcssPlugin: "pittaya-upsert-theme-atrule",
|
|
600
|
+
Once(root) {
|
|
601
|
+
if (Object.keys(vars).length === 0) return;
|
|
602
|
+
let themeNode = root.nodes.find(
|
|
603
|
+
(n) => n.type === "atrule" && n.name === "theme" && n.params === "inline"
|
|
604
|
+
);
|
|
605
|
+
if (!themeNode) {
|
|
606
|
+
themeNode = postcss.atRule({
|
|
607
|
+
name: "theme",
|
|
608
|
+
params: "inline"
|
|
609
|
+
});
|
|
610
|
+
root.append(themeNode);
|
|
611
|
+
}
|
|
612
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
613
|
+
const prop = `--${k.replace(/^--/, "")}`;
|
|
614
|
+
const existing = themeNode.nodes?.find(
|
|
615
|
+
(n) => n.type === "decl" && n.prop === prop
|
|
616
|
+
);
|
|
617
|
+
if (existing) {
|
|
618
|
+
if (options.overwrite) {
|
|
619
|
+
existing.value = v;
|
|
620
|
+
}
|
|
621
|
+
} else {
|
|
622
|
+
themeNode.append(
|
|
623
|
+
postcss.decl({
|
|
624
|
+
prop,
|
|
625
|
+
value: v
|
|
626
|
+
})
|
|
627
|
+
);
|
|
628
|
+
}
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
upsertThemeAtRulePlugin.postcss = true;
|
|
634
|
+
function upsertRuleVarsPlugin(selector, vars, options) {
|
|
635
|
+
return {
|
|
636
|
+
postcssPlugin: `pittaya-upsert-vars-${selector}`,
|
|
637
|
+
Once(root) {
|
|
638
|
+
if (Object.keys(vars).length === 0) return;
|
|
639
|
+
let rule = root.nodes.find(
|
|
640
|
+
(n) => n.type === "rule" && n.selector === selector
|
|
641
|
+
);
|
|
642
|
+
if (!rule) {
|
|
643
|
+
rule = postcss.rule({ selector });
|
|
644
|
+
root.append(rule);
|
|
645
|
+
}
|
|
646
|
+
for (const [k, v] of Object.entries(vars)) {
|
|
647
|
+
const prop = `--${k.replace(/^--/, "")}`;
|
|
648
|
+
const existing = rule.nodes?.find(
|
|
649
|
+
(n) => n.type === "decl" && n.prop === prop
|
|
650
|
+
);
|
|
651
|
+
if (existing) {
|
|
652
|
+
if (options.overwrite) {
|
|
653
|
+
existing.value = v;
|
|
654
|
+
}
|
|
655
|
+
} else {
|
|
656
|
+
rule.append(
|
|
657
|
+
postcss.decl({
|
|
658
|
+
prop,
|
|
659
|
+
value: v
|
|
660
|
+
})
|
|
661
|
+
);
|
|
662
|
+
}
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
};
|
|
666
|
+
}
|
|
667
|
+
upsertRuleVarsPlugin.postcss = true;
|
|
668
|
+
function ensureBaseLayerPlugin() {
|
|
669
|
+
return {
|
|
670
|
+
postcssPlugin: "pittaya-ensure-base-layer",
|
|
671
|
+
Once(root) {
|
|
672
|
+
const hasLayerBase = root.nodes.some(
|
|
673
|
+
(n) => n.type === "atrule" && n.name === "layer" && n.params === "base"
|
|
674
|
+
);
|
|
675
|
+
if (hasLayerBase) return;
|
|
676
|
+
const baseLayer = postcss.atRule({
|
|
677
|
+
name: "layer",
|
|
678
|
+
params: "base"
|
|
679
|
+
});
|
|
680
|
+
baseLayer.append(
|
|
681
|
+
postcss.rule({
|
|
682
|
+
selector: "*",
|
|
683
|
+
nodes: [
|
|
684
|
+
postcss.atRule({
|
|
685
|
+
name: "apply",
|
|
686
|
+
params: "border-border outline-ring/50"
|
|
687
|
+
})
|
|
688
|
+
]
|
|
689
|
+
})
|
|
690
|
+
);
|
|
691
|
+
baseLayer.append(
|
|
692
|
+
postcss.rule({
|
|
693
|
+
selector: "body",
|
|
694
|
+
nodes: [
|
|
695
|
+
postcss.atRule({
|
|
696
|
+
name: "apply",
|
|
697
|
+
params: "bg-background text-foreground"
|
|
698
|
+
})
|
|
699
|
+
]
|
|
700
|
+
})
|
|
701
|
+
);
|
|
702
|
+
root.append(baseLayer);
|
|
703
|
+
}
|
|
704
|
+
};
|
|
705
|
+
}
|
|
706
|
+
ensureBaseLayerPlugin.postcss = true;
|
|
707
|
+
|
|
708
|
+
// src/commands/init.ts
|
|
321
709
|
async function init(options) {
|
|
322
|
-
|
|
710
|
+
const pittayaColorHex = "#f2556d";
|
|
711
|
+
console.log(
|
|
712
|
+
chalk2.bold(
|
|
713
|
+
`
|
|
714
|
+
Welcome to ${chalk2.hex(pittayaColorHex)("Pittaya")} UI!
|
|
715
|
+
`
|
|
716
|
+
)
|
|
717
|
+
);
|
|
323
718
|
const cwd = process.cwd();
|
|
324
|
-
const componentsJsonPath =
|
|
325
|
-
const
|
|
719
|
+
const componentsJsonPath = path8.join(cwd, "components.json");
|
|
720
|
+
const pittayaJsonPath = path8.join(cwd, "pittaya.json");
|
|
721
|
+
const exists = await fs8.access(componentsJsonPath).then(() => true).catch(() => false);
|
|
722
|
+
const pittayaExists = await fs8.access(pittayaJsonPath).then(() => true).catch(() => false);
|
|
326
723
|
if (exists && !options.yes) {
|
|
327
|
-
const
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
initial: false
|
|
332
|
-
});
|
|
724
|
+
const overwrite = await confirm(
|
|
725
|
+
`${chalk2.underline("components.json")} already exists. Do you want to overwrite it?`,
|
|
726
|
+
false
|
|
727
|
+
);
|
|
333
728
|
if (!overwrite) {
|
|
334
729
|
console.log(chalk2.yellow("\n\u274C Operation cancelled.\n"));
|
|
335
730
|
return;
|
|
336
731
|
}
|
|
337
732
|
}
|
|
338
|
-
|
|
733
|
+
let shouldWritePittayaJson = true;
|
|
734
|
+
if (pittayaExists && !options.yes) {
|
|
735
|
+
const overwrite = await confirm(
|
|
736
|
+
`${chalk2.underline("pittaya.json")} already exists. Do you want to overwrite it?`,
|
|
737
|
+
false
|
|
738
|
+
);
|
|
739
|
+
if (!overwrite) {
|
|
740
|
+
shouldWritePittayaJson = false;
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
const defaultPaths = await getDefaultPaths(cwd);
|
|
744
|
+
const config = options.yes ? {
|
|
745
|
+
style: "pittaya",
|
|
746
|
+
tailwindCss: defaultPaths.globalsCss,
|
|
747
|
+
rsc: true,
|
|
748
|
+
componentsPath: defaultPaths.components,
|
|
749
|
+
utilsPath: defaultPaths.utils
|
|
750
|
+
} : await prompts2([
|
|
339
751
|
{
|
|
340
752
|
type: "select",
|
|
341
753
|
name: "style",
|
|
342
754
|
message: "Which style would you like to use?",
|
|
343
755
|
choices: [
|
|
756
|
+
{ title: "Pittaya", value: "pittaya" },
|
|
344
757
|
{ title: "New York", value: "new-york" },
|
|
345
|
-
{ title: "Default", value: "default" }
|
|
346
|
-
{ title: "Recife", value: "recife" }
|
|
758
|
+
{ title: "Default", value: "default" }
|
|
347
759
|
]
|
|
348
760
|
},
|
|
349
761
|
{
|
|
350
762
|
type: "text",
|
|
351
763
|
name: "tailwindCss",
|
|
352
764
|
message: "Where is your globals.css file?",
|
|
353
|
-
initial:
|
|
765
|
+
initial: defaultPaths.globalsCss
|
|
354
766
|
},
|
|
355
767
|
{
|
|
356
|
-
type: "
|
|
768
|
+
type: "select",
|
|
357
769
|
name: "rsc",
|
|
358
770
|
message: "Use React Server Components?",
|
|
359
|
-
|
|
771
|
+
choices: [
|
|
772
|
+
{ title: "Yes", value: true },
|
|
773
|
+
{ title: "No", value: false }
|
|
774
|
+
],
|
|
775
|
+
initial: 0
|
|
360
776
|
},
|
|
361
777
|
{
|
|
362
778
|
type: "text",
|
|
363
779
|
name: "componentsPath",
|
|
364
780
|
message: "Path for components?",
|
|
365
|
-
initial:
|
|
781
|
+
initial: defaultPaths.components
|
|
366
782
|
},
|
|
367
783
|
{
|
|
368
784
|
type: "text",
|
|
369
785
|
name: "utilsPath",
|
|
370
786
|
message: "Path for utils?",
|
|
371
|
-
initial:
|
|
787
|
+
initial: defaultPaths.utils
|
|
372
788
|
}
|
|
373
789
|
]);
|
|
374
790
|
if (!config.style && !options.yes) {
|
|
@@ -377,11 +793,11 @@ async function init(options) {
|
|
|
377
793
|
}
|
|
378
794
|
const componentsJson = {
|
|
379
795
|
$schema: "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry/schema.json",
|
|
380
|
-
style: config.style || "
|
|
796
|
+
style: config.style || "pittaya",
|
|
381
797
|
rsc: config.rsc ?? true,
|
|
382
798
|
tsx: true,
|
|
383
799
|
tailwind: {
|
|
384
|
-
config: "
|
|
800
|
+
config: "",
|
|
385
801
|
css: config.tailwindCss || "src/app/globals.css",
|
|
386
802
|
baseColor: "neutral",
|
|
387
803
|
cssVariables: true,
|
|
@@ -390,33 +806,71 @@ async function init(options) {
|
|
|
390
806
|
aliases: {
|
|
391
807
|
components: config.componentsPath || "@/components",
|
|
392
808
|
utils: config.utilsPath || "@/lib/utils",
|
|
393
|
-
ui:
|
|
809
|
+
ui: "@/components/ui",
|
|
394
810
|
lib: "@/lib",
|
|
395
811
|
hooks: "@/hooks"
|
|
396
812
|
},
|
|
397
813
|
iconLibrary: "lucide"
|
|
398
814
|
};
|
|
815
|
+
let pittayaJson = {
|
|
816
|
+
registry: {
|
|
817
|
+
url: "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry",
|
|
818
|
+
preferLocal: false
|
|
819
|
+
},
|
|
820
|
+
theme: {
|
|
821
|
+
overwriteCssVars: true
|
|
822
|
+
},
|
|
823
|
+
install: {
|
|
824
|
+
autoInstallDeps: true
|
|
825
|
+
}
|
|
826
|
+
};
|
|
827
|
+
if (!shouldWritePittayaJson) {
|
|
828
|
+
try {
|
|
829
|
+
const raw = await fs8.readFile(pittayaJsonPath, "utf-8");
|
|
830
|
+
pittayaJson = JSON.parse(raw);
|
|
831
|
+
} catch {
|
|
832
|
+
shouldWritePittayaJson = true;
|
|
833
|
+
}
|
|
834
|
+
}
|
|
399
835
|
const spinner = ora2("Creating components.json...").start();
|
|
400
|
-
await
|
|
836
|
+
await fs8.writeFile(
|
|
401
837
|
componentsJsonPath,
|
|
402
838
|
JSON.stringify(componentsJson, null, 2)
|
|
403
839
|
);
|
|
404
840
|
spinner.succeed("components.json created successfully!");
|
|
405
|
-
|
|
841
|
+
if (shouldWritePittayaJson) {
|
|
842
|
+
const pittayaSpinner = ora2("Creating pittaya.json...").start();
|
|
843
|
+
await fs8.writeFile(pittayaJsonPath, JSON.stringify(pittayaJson, null, 2));
|
|
844
|
+
pittayaSpinner.succeed("pittaya.json created successfully!");
|
|
845
|
+
}
|
|
846
|
+
applyPittayaProjectConfig(pittayaJson);
|
|
406
847
|
const depsSpinner = ora2("Installing base dependencies...").start();
|
|
407
848
|
try {
|
|
849
|
+
const packageManager = await detectPackageManager();
|
|
408
850
|
await execa2(packageManager, [
|
|
409
851
|
packageManager === "yarn" ? "add" : "install",
|
|
410
852
|
"class-variance-authority",
|
|
411
853
|
"clsx",
|
|
412
|
-
"tailwind-merge"
|
|
854
|
+
"tailwind-merge",
|
|
855
|
+
"lucide-react",
|
|
856
|
+
"tw-animate-css"
|
|
413
857
|
]);
|
|
414
858
|
depsSpinner.succeed("Dependencies installed!");
|
|
415
859
|
} catch (error) {
|
|
416
860
|
depsSpinner.fail("Error installing dependencies");
|
|
417
861
|
console.error(error);
|
|
418
862
|
}
|
|
419
|
-
|
|
863
|
+
try {
|
|
864
|
+
const styleItem = await getRegistryComponent("style", componentsJson);
|
|
865
|
+
await applyRegistryStyleToProject(styleItem, componentsJson, {
|
|
866
|
+
overwriteCssVars: pittayaJson.theme?.overwriteCssVars ?? true
|
|
867
|
+
});
|
|
868
|
+
} catch (error) {
|
|
869
|
+
console.error(error);
|
|
870
|
+
}
|
|
871
|
+
console.log(chalk2.green(`
|
|
872
|
+
\u2705 ${chalk2.hex(pittayaColorHex)("Pittaya")} UI configured successfully!
|
|
873
|
+
`));
|
|
420
874
|
console.log(chalk2.dim("Next steps:"));
|
|
421
875
|
console.log(
|
|
422
876
|
chalk2.dim(
|
|
@@ -430,28 +884,6 @@ async function init(options) {
|
|
|
430
884
|
)
|
|
431
885
|
);
|
|
432
886
|
}
|
|
433
|
-
function getDefaultConfig() {
|
|
434
|
-
return {
|
|
435
|
-
style: "new-york",
|
|
436
|
-
tailwindCss: "src/app/globals.css",
|
|
437
|
-
rsc: true,
|
|
438
|
-
componentsPath: "@/components",
|
|
439
|
-
utilsPath: "@/lib/utils"
|
|
440
|
-
};
|
|
441
|
-
}
|
|
442
|
-
async function detectPackageManager2() {
|
|
443
|
-
try {
|
|
444
|
-
await fs3.access("pnpm-lock.yaml");
|
|
445
|
-
return "pnpm";
|
|
446
|
-
} catch {
|
|
447
|
-
}
|
|
448
|
-
try {
|
|
449
|
-
await fs3.access("yarn.lock");
|
|
450
|
-
return "yarn";
|
|
451
|
-
} catch {
|
|
452
|
-
}
|
|
453
|
-
return "npm";
|
|
454
|
-
}
|
|
455
887
|
|
|
456
888
|
// src/commands/credits.ts
|
|
457
889
|
import chalk3 from "chalk";
|
|
@@ -467,15 +899,15 @@ async function credits() {
|
|
|
467
899
|
import chalk4 from "chalk";
|
|
468
900
|
import ora3 from "ora";
|
|
469
901
|
import prompts3 from "prompts";
|
|
470
|
-
import
|
|
471
|
-
import
|
|
902
|
+
import path9 from "path";
|
|
903
|
+
import fs9 from "fs/promises";
|
|
472
904
|
async function diff(components, options) {
|
|
473
905
|
const cwd = process.cwd();
|
|
474
|
-
const componentsJsonPath = path4.join(cwd, "components.json");
|
|
475
906
|
let config;
|
|
476
907
|
try {
|
|
477
|
-
const
|
|
478
|
-
config =
|
|
908
|
+
const loaded = await loadProjectConfig(cwd);
|
|
909
|
+
config = loaded.config;
|
|
910
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
479
911
|
} catch (error) {
|
|
480
912
|
console.log(chalk4.red("\n\u274C components.json not found.\n"));
|
|
481
913
|
console.log(
|
|
@@ -487,7 +919,7 @@ async function diff(components, options) {
|
|
|
487
919
|
const spinner = ora3("Fetching registry...").start();
|
|
488
920
|
let registry;
|
|
489
921
|
try {
|
|
490
|
-
registry = await fetchRegistry();
|
|
922
|
+
registry = await fetchRegistry(config);
|
|
491
923
|
spinner.succeed("Registry loaded!");
|
|
492
924
|
} catch (error) {
|
|
493
925
|
spinner.fail("Error loading registry");
|
|
@@ -498,7 +930,7 @@ async function diff(components, options) {
|
|
|
498
930
|
if (options.all) {
|
|
499
931
|
const allComponents = registry.components.filter((comp) => comp.type === "registry:ui" || comp.type === "registry:lib").map((comp) => comp.name);
|
|
500
932
|
for (const comp of allComponents) {
|
|
501
|
-
const isInstalled = await
|
|
933
|
+
const isInstalled = await isComponentInstalled(comp, config);
|
|
502
934
|
if (isInstalled) {
|
|
503
935
|
componentsToCheck.push(comp);
|
|
504
936
|
}
|
|
@@ -511,7 +943,7 @@ async function diff(components, options) {
|
|
|
511
943
|
const allComponents = registry.components.filter((comp) => comp.type === "registry:ui" || comp.type === "registry:lib").map((comp) => comp.name);
|
|
512
944
|
const installedComponents = [];
|
|
513
945
|
for (const comp of allComponents) {
|
|
514
|
-
const isInstalled = await
|
|
946
|
+
const isInstalled = await isComponentInstalled(comp, config);
|
|
515
947
|
if (isInstalled) {
|
|
516
948
|
installedComponents.push(comp);
|
|
517
949
|
}
|
|
@@ -550,29 +982,14 @@ Checking ${componentsToCheck.length} component(s)...
|
|
|
550
982
|
}
|
|
551
983
|
displayDiffResults(results);
|
|
552
984
|
}
|
|
553
|
-
async function isComponentInstalled2(name, config) {
|
|
554
|
-
try {
|
|
555
|
-
const component = await getRegistryComponent(name);
|
|
556
|
-
if (!component) return false;
|
|
557
|
-
for (const file of component.files) {
|
|
558
|
-
const targetPath = resolveTargetPath2(file.name, component.type, config);
|
|
559
|
-
const filePath = path4.join(process.cwd(), targetPath);
|
|
560
|
-
const exists = await fs4.access(filePath).then(() => true).catch(() => false);
|
|
561
|
-
if (!exists) return false;
|
|
562
|
-
}
|
|
563
|
-
return true;
|
|
564
|
-
} catch {
|
|
565
|
-
return false;
|
|
566
|
-
}
|
|
567
|
-
}
|
|
568
985
|
async function checkComponentDiff(name, config) {
|
|
569
986
|
try {
|
|
570
|
-
const component = await getRegistryComponent(name);
|
|
987
|
+
const component = await getRegistryComponent(name, config);
|
|
571
988
|
if (!component) {
|
|
572
989
|
console.log(chalk4.red(` \u274C Component "${name}" not found in registry.`));
|
|
573
990
|
return null;
|
|
574
991
|
}
|
|
575
|
-
const isInstalled = await
|
|
992
|
+
const isInstalled = await isComponentInstalled(name, config);
|
|
576
993
|
if (!isInstalled) {
|
|
577
994
|
console.log(chalk4.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
|
|
578
995
|
return null;
|
|
@@ -580,10 +997,10 @@ async function checkComponentDiff(name, config) {
|
|
|
580
997
|
const fileDiffs = [];
|
|
581
998
|
let hasChanges = false;
|
|
582
999
|
for (const file of component.files) {
|
|
583
|
-
const targetPath =
|
|
584
|
-
const filePath =
|
|
1000
|
+
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
1001
|
+
const filePath = path9.join(process.cwd(), targetPath);
|
|
585
1002
|
try {
|
|
586
|
-
const localContent = await
|
|
1003
|
+
const localContent = await fs9.readFile(filePath, "utf-8");
|
|
587
1004
|
const registryContent = transformImports(file.content, config);
|
|
588
1005
|
const contentMatches = localContent.trim() === registryContent.trim();
|
|
589
1006
|
fileDiffs.push({
|
|
@@ -649,41 +1066,20 @@ function displayDiffResults(results) {
|
|
|
649
1066
|
}
|
|
650
1067
|
console.log();
|
|
651
1068
|
}
|
|
652
|
-
function resolveTargetPath2(fileName, type, config) {
|
|
653
|
-
if (type === "registry:ui") {
|
|
654
|
-
return path4.join(
|
|
655
|
-
config.aliases.ui.replace("@/", "src/"),
|
|
656
|
-
fileName
|
|
657
|
-
);
|
|
658
|
-
}
|
|
659
|
-
if (type === "registry:lib") {
|
|
660
|
-
return path4.join(
|
|
661
|
-
config.aliases.lib.replace("@/", "src/"),
|
|
662
|
-
fileName
|
|
663
|
-
);
|
|
664
|
-
}
|
|
665
|
-
if (type === "registry:hook") {
|
|
666
|
-
return path4.join(
|
|
667
|
-
config.aliases.hooks.replace("@/", "src/"),
|
|
668
|
-
fileName
|
|
669
|
-
);
|
|
670
|
-
}
|
|
671
|
-
return fileName;
|
|
672
|
-
}
|
|
673
1069
|
|
|
674
1070
|
// src/commands/update.ts
|
|
675
1071
|
import chalk5 from "chalk";
|
|
676
1072
|
import ora4 from "ora";
|
|
677
1073
|
import prompts4 from "prompts";
|
|
678
|
-
import
|
|
679
|
-
import
|
|
1074
|
+
import path10 from "path";
|
|
1075
|
+
import fs10 from "fs/promises";
|
|
680
1076
|
async function update(components, options) {
|
|
681
1077
|
const cwd = process.cwd();
|
|
682
|
-
const componentsJsonPath = path5.join(cwd, "components.json");
|
|
683
1078
|
let config;
|
|
684
1079
|
try {
|
|
685
|
-
const
|
|
686
|
-
config =
|
|
1080
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1081
|
+
config = loaded.config;
|
|
1082
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
687
1083
|
} catch (error) {
|
|
688
1084
|
console.log(chalk5.red("\n\u274C components.json not found.\n"));
|
|
689
1085
|
console.log(
|
|
@@ -695,7 +1091,7 @@ async function update(components, options) {
|
|
|
695
1091
|
const spinner = ora4("Fetching registry...").start();
|
|
696
1092
|
let registry;
|
|
697
1093
|
try {
|
|
698
|
-
registry = await fetchRegistry();
|
|
1094
|
+
registry = await fetchRegistry(config);
|
|
699
1095
|
spinner.succeed("Registry loaded!");
|
|
700
1096
|
} catch (error) {
|
|
701
1097
|
spinner.fail("Error loading registry");
|
|
@@ -706,7 +1102,7 @@ async function update(components, options) {
|
|
|
706
1102
|
if (options.all) {
|
|
707
1103
|
const allComponents = registry.components.filter((comp) => comp.type === "registry:ui" || comp.type === "registry:lib").map((comp) => comp.name);
|
|
708
1104
|
for (const comp of allComponents) {
|
|
709
|
-
const isInstalled = await
|
|
1105
|
+
const isInstalled = await isComponentInstalled(comp, config);
|
|
710
1106
|
if (isInstalled) {
|
|
711
1107
|
componentsToUpdate.push(comp);
|
|
712
1108
|
}
|
|
@@ -716,13 +1112,11 @@ async function update(components, options) {
|
|
|
716
1112
|
return;
|
|
717
1113
|
}
|
|
718
1114
|
if (!options.yes && !options.force) {
|
|
719
|
-
const
|
|
720
|
-
|
|
721
|
-
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
});
|
|
725
|
-
if (!confirm) {
|
|
1115
|
+
const shouldUpdate = await confirm(
|
|
1116
|
+
`Update ${componentsToUpdate.length} component(s)?`,
|
|
1117
|
+
true
|
|
1118
|
+
);
|
|
1119
|
+
if (!shouldUpdate) {
|
|
726
1120
|
console.log(chalk5.yellow("\n\u274C Update cancelled.\n"));
|
|
727
1121
|
return;
|
|
728
1122
|
}
|
|
@@ -731,7 +1125,7 @@ async function update(components, options) {
|
|
|
731
1125
|
const allComponents = registry.components.filter((comp) => comp.type === "registry:ui" || comp.type === "registry:lib").map((comp) => comp.name);
|
|
732
1126
|
const installedComponents = [];
|
|
733
1127
|
for (const comp of allComponents) {
|
|
734
|
-
const isInstalled = await
|
|
1128
|
+
const isInstalled = await isComponentInstalled(comp, config);
|
|
735
1129
|
if (isInstalled) {
|
|
736
1130
|
installedComponents.push(comp);
|
|
737
1131
|
}
|
|
@@ -768,27 +1162,12 @@ Checking ${componentsToUpdate.length} component(s) for updates...
|
|
|
768
1162
|
}
|
|
769
1163
|
displayUpdateResults(results);
|
|
770
1164
|
}
|
|
771
|
-
async function isComponentInstalled3(name, config) {
|
|
772
|
-
try {
|
|
773
|
-
const component = await getRegistryComponent(name);
|
|
774
|
-
if (!component) return false;
|
|
775
|
-
for (const file of component.files) {
|
|
776
|
-
const targetPath = resolveTargetPath3(file.name, component.type, config);
|
|
777
|
-
const filePath = path5.join(process.cwd(), targetPath);
|
|
778
|
-
const exists = await fs5.access(filePath).then(() => true).catch(() => false);
|
|
779
|
-
if (!exists) return false;
|
|
780
|
-
}
|
|
781
|
-
return true;
|
|
782
|
-
} catch {
|
|
783
|
-
return false;
|
|
784
|
-
}
|
|
785
|
-
}
|
|
786
1165
|
async function hasComponentChanges(component, config) {
|
|
787
1166
|
for (const file of component.files) {
|
|
788
|
-
const targetPath =
|
|
789
|
-
const filePath =
|
|
1167
|
+
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
1168
|
+
const filePath = path10.join(process.cwd(), targetPath);
|
|
790
1169
|
try {
|
|
791
|
-
const localContent = await
|
|
1170
|
+
const localContent = await fs10.readFile(filePath, "utf-8");
|
|
792
1171
|
const registryContent = transformImports(file.content, config);
|
|
793
1172
|
if (localContent.trim() !== registryContent.trim()) {
|
|
794
1173
|
return true;
|
|
@@ -801,12 +1180,12 @@ async function hasComponentChanges(component, config) {
|
|
|
801
1180
|
}
|
|
802
1181
|
async function updateComponent(name, config, options) {
|
|
803
1182
|
try {
|
|
804
|
-
const component = await getRegistryComponent(name);
|
|
1183
|
+
const component = await getRegistryComponent(name, config);
|
|
805
1184
|
if (!component) {
|
|
806
1185
|
console.log(chalk5.red(` \u274C Component "${name}" not found in registry.`));
|
|
807
1186
|
return { name, updated: false, skipped: true, reason: "not found in registry" };
|
|
808
1187
|
}
|
|
809
|
-
const isInstalled = await
|
|
1188
|
+
const isInstalled = await isComponentInstalled(name, config);
|
|
810
1189
|
if (!isInstalled) {
|
|
811
1190
|
console.log(chalk5.dim(` \u23ED\uFE0F ${name} is not installed, skipping...`));
|
|
812
1191
|
return { name, updated: false, skipped: true, reason: "not installed" };
|
|
@@ -817,24 +1196,19 @@ async function updateComponent(name, config, options) {
|
|
|
817
1196
|
return { name, updated: false, skipped: true, reason: "already up to date" };
|
|
818
1197
|
}
|
|
819
1198
|
if (!options.yes && !options.force) {
|
|
820
|
-
const
|
|
821
|
-
|
|
822
|
-
name: "confirm",
|
|
823
|
-
message: `Update ${chalk5.bold(name)}?`,
|
|
824
|
-
initial: true
|
|
825
|
-
});
|
|
826
|
-
if (!confirm) {
|
|
1199
|
+
const shouldUpdate = await confirm(`Update ${chalk5.bold(name)}?`, true);
|
|
1200
|
+
if (!shouldUpdate) {
|
|
827
1201
|
console.log(chalk5.yellow(` \u23ED\uFE0F Skipped ${name}`));
|
|
828
1202
|
return { name, updated: false, skipped: true, reason: "user cancelled" };
|
|
829
1203
|
}
|
|
830
1204
|
}
|
|
831
1205
|
const spinner = ora4(`Updating ${chalk5.bold(name)}...`).start();
|
|
832
1206
|
for (const file of component.files) {
|
|
833
|
-
const targetPath =
|
|
834
|
-
const filePath =
|
|
835
|
-
await
|
|
1207
|
+
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
1208
|
+
const filePath = path10.join(process.cwd(), targetPath);
|
|
1209
|
+
await fs10.mkdir(path10.dirname(filePath), { recursive: true });
|
|
836
1210
|
const content = transformImports(file.content, config);
|
|
837
|
-
await
|
|
1211
|
+
await fs10.writeFile(filePath, content, "utf-8");
|
|
838
1212
|
}
|
|
839
1213
|
spinner.succeed(`${chalk5.bold(name)} updated successfully!`);
|
|
840
1214
|
return { name, updated: true, skipped: false };
|
|
@@ -866,33 +1240,213 @@ function displayUpdateResults(results) {
|
|
|
866
1240
|
}
|
|
867
1241
|
console.log();
|
|
868
1242
|
}
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
1243
|
+
|
|
1244
|
+
// src/commands/list.ts
|
|
1245
|
+
import chalk6 from "chalk";
|
|
1246
|
+
import ora5 from "ora";
|
|
1247
|
+
async function list(options) {
|
|
1248
|
+
const cwd = process.cwd();
|
|
1249
|
+
let config;
|
|
1250
|
+
try {
|
|
1251
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1252
|
+
config = loaded.config;
|
|
1253
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
1254
|
+
} catch (error) {
|
|
1255
|
+
console.log(chalk6.red("\n\u274C components.json not found.\n"));
|
|
1256
|
+
console.log(
|
|
1257
|
+
chalk6.dim(`Run ${chalk6.bold("npx pittaya init")} first.
|
|
1258
|
+
`)
|
|
874
1259
|
);
|
|
1260
|
+
return;
|
|
875
1261
|
}
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
);
|
|
1262
|
+
const spinner = ora5("Fetching components...").start();
|
|
1263
|
+
let registry;
|
|
1264
|
+
try {
|
|
1265
|
+
registry = await fetchRegistry(config);
|
|
1266
|
+
spinner.succeed("Components loaded!");
|
|
1267
|
+
} catch (error) {
|
|
1268
|
+
spinner.fail("Error loading registry");
|
|
1269
|
+
console.error(error);
|
|
1270
|
+
return;
|
|
881
1271
|
}
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
1272
|
+
const allComponents = registry.components || [];
|
|
1273
|
+
const componentsWithStatus = await Promise.all(
|
|
1274
|
+
allComponents.map(async (comp) => {
|
|
1275
|
+
const slug = comp.slug || comp.name;
|
|
1276
|
+
const installed = await isComponentInstalled(slug, config);
|
|
1277
|
+
return {
|
|
1278
|
+
...comp.slug ? comp : { ...comp, slug },
|
|
1279
|
+
installed
|
|
1280
|
+
};
|
|
1281
|
+
})
|
|
1282
|
+
);
|
|
1283
|
+
let filteredComponents = componentsWithStatus;
|
|
1284
|
+
if (options.installed) {
|
|
1285
|
+
filteredComponents = componentsWithStatus.filter((comp) => comp.installed);
|
|
1286
|
+
} else if (options.available) {
|
|
1287
|
+
filteredComponents = componentsWithStatus.filter((comp) => !comp.installed);
|
|
1288
|
+
}
|
|
1289
|
+
if (options.json) {
|
|
1290
|
+
console.log(JSON.stringify(filteredComponents, null, 2));
|
|
1291
|
+
return;
|
|
1292
|
+
}
|
|
1293
|
+
displayComponents(filteredComponents, options);
|
|
1294
|
+
}
|
|
1295
|
+
function displayComponents(components, options) {
|
|
1296
|
+
if (components.length === 0) {
|
|
1297
|
+
if (options.installed) {
|
|
1298
|
+
console.log(chalk6.yellow("\n\u{1F4E6} No components installed yet.\n"));
|
|
1299
|
+
console.log(chalk6.dim(`Run ${chalk6.bold("npx pittaya add")} to install components.
|
|
1300
|
+
`));
|
|
1301
|
+
} else if (options.available) {
|
|
1302
|
+
console.log(chalk6.yellow("\n\u2728 All components are already installed!\n"));
|
|
1303
|
+
} else {
|
|
1304
|
+
console.log(chalk6.yellow("\n\u26A0\uFE0F No components found in registry.\n"));
|
|
1305
|
+
}
|
|
1306
|
+
return;
|
|
1307
|
+
}
|
|
1308
|
+
const categorized = components.reduce((acc, comp) => {
|
|
1309
|
+
const category = comp.category || "Other";
|
|
1310
|
+
if (!acc[category]) {
|
|
1311
|
+
acc[category] = [];
|
|
1312
|
+
}
|
|
1313
|
+
acc[category].push(comp);
|
|
1314
|
+
return acc;
|
|
1315
|
+
}, {});
|
|
1316
|
+
console.log("\n");
|
|
1317
|
+
if (options.installed) {
|
|
1318
|
+
console.log(chalk6.bold.green("\u{1F4E6} Installed Components\n"));
|
|
1319
|
+
} else if (options.available) {
|
|
1320
|
+
console.log(chalk6.bold.blue("\u2728 Available Components\n"));
|
|
1321
|
+
} else {
|
|
1322
|
+
console.log(chalk6.bold("\u{1F4CB} All Components\n"));
|
|
1323
|
+
}
|
|
1324
|
+
Object.entries(categorized).sort().forEach(([category, comps]) => {
|
|
1325
|
+
console.log(chalk6.bold.cyan(`${category}:`));
|
|
1326
|
+
comps.forEach((comp) => {
|
|
1327
|
+
const status = comp.installed ? chalk6.green("\u2713") : chalk6.dim("\u25CB");
|
|
1328
|
+
const name = comp.installed ? chalk6.bold(comp.slug) : chalk6.dim(comp.slug);
|
|
1329
|
+
const description = comp.description ? chalk6.dim(` - ${comp.description}`) : "";
|
|
1330
|
+
const deps = comp.dependencies && comp.dependencies.length > 0 ? chalk6.dim.yellow(` [${comp.dependencies.length} deps]`) : "";
|
|
1331
|
+
const internalDeps = comp.internalDependencies && comp.internalDependencies.length > 0 ? chalk6.dim.blue(` [requires: ${comp.internalDependencies.join(", ")}]`) : "";
|
|
1332
|
+
console.log(` ${status} ${name}${description}${deps}${internalDeps}`);
|
|
1333
|
+
});
|
|
1334
|
+
console.log();
|
|
1335
|
+
});
|
|
1336
|
+
const installedCount = components.filter((c) => c.installed).length;
|
|
1337
|
+
const totalCount = components.length;
|
|
1338
|
+
if (!options.installed && !options.available) {
|
|
1339
|
+
console.log(chalk6.dim(`Total: ${totalCount} components (${installedCount} installed, ${totalCount - installedCount} available)
|
|
1340
|
+
`));
|
|
1341
|
+
} else {
|
|
1342
|
+
console.log(chalk6.dim(`Total: ${totalCount} components
|
|
1343
|
+
`));
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
|
|
1347
|
+
// src/commands/debug.ts
|
|
1348
|
+
import chalk7 from "chalk";
|
|
1349
|
+
import path11 from "path";
|
|
1350
|
+
import fs11 from "fs/promises";
|
|
1351
|
+
async function debug(options) {
|
|
1352
|
+
const cwd = process.cwd();
|
|
1353
|
+
console.log(chalk7.bold("\n\u{1F50D} Pittaya UI Debug Information\n"));
|
|
1354
|
+
console.log(chalk7.dim(`Working directory: ${cwd}
|
|
1355
|
+
`));
|
|
1356
|
+
let config;
|
|
1357
|
+
try {
|
|
1358
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1359
|
+
config = loaded.config;
|
|
1360
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
1361
|
+
console.log(chalk7.green("\u2705 components.json found"));
|
|
1362
|
+
console.log(chalk7.dim(` Path: ${path11.join(cwd, "components.json")}`));
|
|
1363
|
+
} catch (error) {
|
|
1364
|
+
console.log(chalk7.red("\u274C components.json not found\n"));
|
|
1365
|
+
return;
|
|
1366
|
+
}
|
|
1367
|
+
const usesSrc = await hasSrcDirectory(cwd);
|
|
1368
|
+
console.log(chalk7.green(`\u2705 Project structure: ${usesSrc ? "src/" : "root"}`));
|
|
1369
|
+
console.log(chalk7.bold("\n\u{1F4CB} Configured Aliases:"));
|
|
1370
|
+
console.log(chalk7.dim(` components: ${config.aliases.components}`));
|
|
1371
|
+
console.log(chalk7.dim(` utils: ${config.aliases.utils}`));
|
|
1372
|
+
console.log(chalk7.dim(` ui: ${config.aliases.ui}`));
|
|
1373
|
+
const resolvedUi = await resolveAliasPath(config.aliases.ui, cwd);
|
|
1374
|
+
const resolvedLib = await resolveAliasPath(config.aliases.lib || "@/lib", cwd);
|
|
1375
|
+
console.log(chalk7.bold("\n\u{1F4C2} Resolved Paths:"));
|
|
1376
|
+
console.log(chalk7.dim(` UI components: ${resolvedUi}`));
|
|
1377
|
+
console.log(chalk7.dim(` Libraries: ${resolvedLib}`));
|
|
1378
|
+
if (options.component) {
|
|
1379
|
+
console.log(chalk7.bold(`
|
|
1380
|
+
\u{1F50D} Debugging component: ${options.component}
|
|
1381
|
+
`));
|
|
1382
|
+
try {
|
|
1383
|
+
const component = await getRegistryComponent(options.component, config);
|
|
1384
|
+
if (!component) {
|
|
1385
|
+
console.log(chalk7.red(`\u274C Component not found in registry
|
|
1386
|
+
`));
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
console.log(chalk7.green(`\u2705 Component found in registry`));
|
|
1390
|
+
console.log(chalk7.dim(` Type: ${component.type}`));
|
|
1391
|
+
console.log(chalk7.dim(` Files: ${component.files.length}`));
|
|
1392
|
+
console.log(chalk7.bold("\n\u{1F4C1} Expected Files:"));
|
|
1393
|
+
for (const file of component.files) {
|
|
1394
|
+
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
1395
|
+
const fullPath = path11.join(cwd, targetPath);
|
|
1396
|
+
const exists = await fs11.access(fullPath).then(() => true).catch(() => false);
|
|
1397
|
+
const statusIcon = exists ? chalk7.green("\u2705") : chalk7.red("\u274C");
|
|
1398
|
+
const statusText = exists ? chalk7.green("EXISTS") : chalk7.red("NOT FOUND");
|
|
1399
|
+
console.log(` ${statusIcon} ${file.name}`);
|
|
1400
|
+
console.log(chalk7.dim(` Expected: ${fullPath}`));
|
|
1401
|
+
console.log(chalk7.dim(` Status: ${statusText}`));
|
|
1402
|
+
if (!exists) {
|
|
1403
|
+
const dir = path11.dirname(fullPath);
|
|
1404
|
+
try {
|
|
1405
|
+
const dirExists = await fs11.access(dir).then(() => true).catch(() => false);
|
|
1406
|
+
if (dirExists) {
|
|
1407
|
+
const filesInDir = await fs11.readdir(dir);
|
|
1408
|
+
const baseName = path11.basename(file.name, path11.extname(file.name));
|
|
1409
|
+
const similarFiles = filesInDir.filter(
|
|
1410
|
+
(f) => f.includes(baseName) || f.toLowerCase().includes(baseName.toLowerCase())
|
|
1411
|
+
);
|
|
1412
|
+
if (similarFiles.length > 0) {
|
|
1413
|
+
console.log(chalk7.yellow(` \u{1F4A1} Similar files found in directory:`));
|
|
1414
|
+
similarFiles.forEach((f) => {
|
|
1415
|
+
console.log(chalk7.dim(` - ${f}`));
|
|
1416
|
+
});
|
|
1417
|
+
}
|
|
1418
|
+
} else {
|
|
1419
|
+
console.log(chalk7.red(` \u26A0\uFE0F Directory doesn't exist: ${dir}`));
|
|
1420
|
+
}
|
|
1421
|
+
} catch (err) {
|
|
1422
|
+
}
|
|
1423
|
+
}
|
|
1424
|
+
}
|
|
1425
|
+
const isInstalled = await isComponentInstalled(options.component, config);
|
|
1426
|
+
console.log(chalk7.bold(`
|
|
1427
|
+
\u{1F4CA} Installation Status:`));
|
|
1428
|
+
if (isInstalled) {
|
|
1429
|
+
console.log(chalk7.green(` \u2705 Component is detected as INSTALLED`));
|
|
1430
|
+
} else {
|
|
1431
|
+
console.log(chalk7.red(` \u274C Component is detected as NOT INSTALLED`));
|
|
1432
|
+
console.log(chalk7.yellow(` \u{1F4A1} All files must exist for component to be considered installed`));
|
|
1433
|
+
}
|
|
1434
|
+
} catch (error) {
|
|
1435
|
+
console.log(chalk7.red(`
|
|
1436
|
+
\u274C Error debugging component:`));
|
|
1437
|
+
console.error(error);
|
|
1438
|
+
}
|
|
1439
|
+
} else {
|
|
1440
|
+
console.log(chalk7.yellow("\n\u{1F4A1} To debug a specific component, use:"));
|
|
1441
|
+
console.log(chalk7.dim(" npx pittaya debug --component <name>\n"));
|
|
887
1442
|
}
|
|
888
|
-
return fileName;
|
|
889
1443
|
}
|
|
890
1444
|
|
|
891
1445
|
// src/index.ts
|
|
892
1446
|
import { readFileSync } from "fs";
|
|
893
|
-
import { fileURLToPath } from "url";
|
|
1447
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
894
1448
|
import { dirname, join } from "path";
|
|
895
|
-
var __filename =
|
|
1449
|
+
var __filename = fileURLToPath2(import.meta.url);
|
|
896
1450
|
var __dirname = dirname(__filename);
|
|
897
1451
|
var packageJson = JSON.parse(
|
|
898
1452
|
readFileSync(join(__dirname, "../package.json"), "utf-8")
|
|
@@ -903,6 +1457,8 @@ program.command("init").description("Initialize Pittaya UI in your project").opt
|
|
|
903
1457
|
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);
|
|
904
1458
|
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);
|
|
905
1459
|
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);
|
|
1460
|
+
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);
|
|
906
1461
|
program.command("credits").description("Show Pittaya UI creators").action(credits);
|
|
1462
|
+
program.command("debug").description("Debug component installation issues").option("-c, --component <name>", "Component name to debug").action(debug);
|
|
907
1463
|
program.parse();
|
|
908
1464
|
//# sourceMappingURL=index.js.map
|