pittaya 0.0.8 → 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/dist/index.js +526 -152
- package/dist/index.js.map +1 -1
- package/package.json +6 -2
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) {
|
|
@@ -367,29 +519,230 @@ async function addComponent(name, config, options) {
|
|
|
367
519
|
import chalk2 from "chalk";
|
|
368
520
|
import ora2 from "ora";
|
|
369
521
|
import prompts2 from "prompts";
|
|
370
|
-
import
|
|
371
|
-
import
|
|
522
|
+
import path8 from "path";
|
|
523
|
+
import fs8 from "fs/promises";
|
|
372
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
|
|
373
709
|
async function init(options) {
|
|
374
|
-
|
|
710
|
+
const pittayaColorHex = "#f2556d";
|
|
711
|
+
console.log(
|
|
712
|
+
chalk2.bold(
|
|
713
|
+
`
|
|
714
|
+
Welcome to ${chalk2.hex(pittayaColorHex)("Pittaya")} UI!
|
|
715
|
+
`
|
|
716
|
+
)
|
|
717
|
+
);
|
|
375
718
|
const cwd = process.cwd();
|
|
376
|
-
const componentsJsonPath =
|
|
377
|
-
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);
|
|
378
723
|
if (exists && !options.yes) {
|
|
379
|
-
const
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
initial: false
|
|
384
|
-
});
|
|
724
|
+
const overwrite = await confirm(
|
|
725
|
+
`${chalk2.underline("components.json")} already exists. Do you want to overwrite it?`,
|
|
726
|
+
false
|
|
727
|
+
);
|
|
385
728
|
if (!overwrite) {
|
|
386
729
|
console.log(chalk2.yellow("\n\u274C Operation cancelled.\n"));
|
|
387
730
|
return;
|
|
388
731
|
}
|
|
389
732
|
}
|
|
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
|
+
}
|
|
390
743
|
const defaultPaths = await getDefaultPaths(cwd);
|
|
391
744
|
const config = options.yes ? {
|
|
392
|
-
style: "
|
|
745
|
+
style: "pittaya",
|
|
393
746
|
tailwindCss: defaultPaths.globalsCss,
|
|
394
747
|
rsc: true,
|
|
395
748
|
componentsPath: defaultPaths.components,
|
|
@@ -400,9 +753,9 @@ async function init(options) {
|
|
|
400
753
|
name: "style",
|
|
401
754
|
message: "Which style would you like to use?",
|
|
402
755
|
choices: [
|
|
756
|
+
{ title: "Pittaya", value: "pittaya" },
|
|
403
757
|
{ title: "New York", value: "new-york" },
|
|
404
|
-
{ title: "Default", value: "default" }
|
|
405
|
-
{ title: "Recife", value: "recife" }
|
|
758
|
+
{ title: "Default", value: "default" }
|
|
406
759
|
]
|
|
407
760
|
},
|
|
408
761
|
{
|
|
@@ -412,10 +765,14 @@ async function init(options) {
|
|
|
412
765
|
initial: defaultPaths.globalsCss
|
|
413
766
|
},
|
|
414
767
|
{
|
|
415
|
-
type: "
|
|
768
|
+
type: "select",
|
|
416
769
|
name: "rsc",
|
|
417
770
|
message: "Use React Server Components?",
|
|
418
|
-
|
|
771
|
+
choices: [
|
|
772
|
+
{ title: "Yes", value: true },
|
|
773
|
+
{ title: "No", value: false }
|
|
774
|
+
],
|
|
775
|
+
initial: 0
|
|
419
776
|
},
|
|
420
777
|
{
|
|
421
778
|
type: "text",
|
|
@@ -436,11 +793,11 @@ async function init(options) {
|
|
|
436
793
|
}
|
|
437
794
|
const componentsJson = {
|
|
438
795
|
$schema: "https://raw.githubusercontent.com/pittaya-ui/cli/main/registry/schema.json",
|
|
439
|
-
style: config.style || "
|
|
796
|
+
style: config.style || "pittaya",
|
|
440
797
|
rsc: config.rsc ?? true,
|
|
441
798
|
tsx: true,
|
|
442
799
|
tailwind: {
|
|
443
|
-
config: "
|
|
800
|
+
config: "",
|
|
444
801
|
css: config.tailwindCss || "src/app/globals.css",
|
|
445
802
|
baseColor: "neutral",
|
|
446
803
|
cssVariables: true,
|
|
@@ -449,33 +806,71 @@ async function init(options) {
|
|
|
449
806
|
aliases: {
|
|
450
807
|
components: config.componentsPath || "@/components",
|
|
451
808
|
utils: config.utilsPath || "@/lib/utils",
|
|
452
|
-
ui:
|
|
809
|
+
ui: "@/components/ui",
|
|
453
810
|
lib: "@/lib",
|
|
454
811
|
hooks: "@/hooks"
|
|
455
812
|
},
|
|
456
813
|
iconLibrary: "lucide"
|
|
457
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
|
+
}
|
|
458
835
|
const spinner = ora2("Creating components.json...").start();
|
|
459
|
-
await
|
|
836
|
+
await fs8.writeFile(
|
|
460
837
|
componentsJsonPath,
|
|
461
838
|
JSON.stringify(componentsJson, null, 2)
|
|
462
839
|
);
|
|
463
840
|
spinner.succeed("components.json created successfully!");
|
|
464
|
-
|
|
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);
|
|
465
847
|
const depsSpinner = ora2("Installing base dependencies...").start();
|
|
466
848
|
try {
|
|
849
|
+
const packageManager = await detectPackageManager();
|
|
467
850
|
await execa2(packageManager, [
|
|
468
851
|
packageManager === "yarn" ? "add" : "install",
|
|
469
852
|
"class-variance-authority",
|
|
470
853
|
"clsx",
|
|
471
|
-
"tailwind-merge"
|
|
854
|
+
"tailwind-merge",
|
|
855
|
+
"lucide-react",
|
|
856
|
+
"tw-animate-css"
|
|
472
857
|
]);
|
|
473
858
|
depsSpinner.succeed("Dependencies installed!");
|
|
474
859
|
} catch (error) {
|
|
475
860
|
depsSpinner.fail("Error installing dependencies");
|
|
476
861
|
console.error(error);
|
|
477
862
|
}
|
|
478
|
-
|
|
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
|
+
`));
|
|
479
874
|
console.log(chalk2.dim("Next steps:"));
|
|
480
875
|
console.log(
|
|
481
876
|
chalk2.dim(
|
|
@@ -489,19 +884,6 @@ async function init(options) {
|
|
|
489
884
|
)
|
|
490
885
|
);
|
|
491
886
|
}
|
|
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
887
|
|
|
506
888
|
// src/commands/credits.ts
|
|
507
889
|
import chalk3 from "chalk";
|
|
@@ -517,15 +899,15 @@ async function credits() {
|
|
|
517
899
|
import chalk4 from "chalk";
|
|
518
900
|
import ora3 from "ora";
|
|
519
901
|
import prompts3 from "prompts";
|
|
520
|
-
import
|
|
521
|
-
import
|
|
902
|
+
import path9 from "path";
|
|
903
|
+
import fs9 from "fs/promises";
|
|
522
904
|
async function diff(components, options) {
|
|
523
905
|
const cwd = process.cwd();
|
|
524
|
-
const componentsJsonPath = path6.join(cwd, "components.json");
|
|
525
906
|
let config;
|
|
526
907
|
try {
|
|
527
|
-
const
|
|
528
|
-
config =
|
|
908
|
+
const loaded = await loadProjectConfig(cwd);
|
|
909
|
+
config = loaded.config;
|
|
910
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
529
911
|
} catch (error) {
|
|
530
912
|
console.log(chalk4.red("\n\u274C components.json not found.\n"));
|
|
531
913
|
console.log(
|
|
@@ -537,7 +919,7 @@ async function diff(components, options) {
|
|
|
537
919
|
const spinner = ora3("Fetching registry...").start();
|
|
538
920
|
let registry;
|
|
539
921
|
try {
|
|
540
|
-
registry = await fetchRegistry();
|
|
922
|
+
registry = await fetchRegistry(config);
|
|
541
923
|
spinner.succeed("Registry loaded!");
|
|
542
924
|
} catch (error) {
|
|
543
925
|
spinner.fail("Error loading registry");
|
|
@@ -602,7 +984,7 @@ Checking ${componentsToCheck.length} component(s)...
|
|
|
602
984
|
}
|
|
603
985
|
async function checkComponentDiff(name, config) {
|
|
604
986
|
try {
|
|
605
|
-
const component = await getRegistryComponent(name);
|
|
987
|
+
const component = await getRegistryComponent(name, config);
|
|
606
988
|
if (!component) {
|
|
607
989
|
console.log(chalk4.red(` \u274C Component "${name}" not found in registry.`));
|
|
608
990
|
return null;
|
|
@@ -616,9 +998,9 @@ async function checkComponentDiff(name, config) {
|
|
|
616
998
|
let hasChanges = false;
|
|
617
999
|
for (const file of component.files) {
|
|
618
1000
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
619
|
-
const filePath =
|
|
1001
|
+
const filePath = path9.join(process.cwd(), targetPath);
|
|
620
1002
|
try {
|
|
621
|
-
const localContent = await
|
|
1003
|
+
const localContent = await fs9.readFile(filePath, "utf-8");
|
|
622
1004
|
const registryContent = transformImports(file.content, config);
|
|
623
1005
|
const contentMatches = localContent.trim() === registryContent.trim();
|
|
624
1006
|
fileDiffs.push({
|
|
@@ -689,15 +1071,15 @@ function displayDiffResults(results) {
|
|
|
689
1071
|
import chalk5 from "chalk";
|
|
690
1072
|
import ora4 from "ora";
|
|
691
1073
|
import prompts4 from "prompts";
|
|
692
|
-
import
|
|
693
|
-
import
|
|
1074
|
+
import path10 from "path";
|
|
1075
|
+
import fs10 from "fs/promises";
|
|
694
1076
|
async function update(components, options) {
|
|
695
1077
|
const cwd = process.cwd();
|
|
696
|
-
const componentsJsonPath = path7.join(cwd, "components.json");
|
|
697
1078
|
let config;
|
|
698
1079
|
try {
|
|
699
|
-
const
|
|
700
|
-
config =
|
|
1080
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1081
|
+
config = loaded.config;
|
|
1082
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
701
1083
|
} catch (error) {
|
|
702
1084
|
console.log(chalk5.red("\n\u274C components.json not found.\n"));
|
|
703
1085
|
console.log(
|
|
@@ -709,7 +1091,7 @@ async function update(components, options) {
|
|
|
709
1091
|
const spinner = ora4("Fetching registry...").start();
|
|
710
1092
|
let registry;
|
|
711
1093
|
try {
|
|
712
|
-
registry = await fetchRegistry();
|
|
1094
|
+
registry = await fetchRegistry(config);
|
|
713
1095
|
spinner.succeed("Registry loaded!");
|
|
714
1096
|
} catch (error) {
|
|
715
1097
|
spinner.fail("Error loading registry");
|
|
@@ -730,13 +1112,11 @@ async function update(components, options) {
|
|
|
730
1112
|
return;
|
|
731
1113
|
}
|
|
732
1114
|
if (!options.yes && !options.force) {
|
|
733
|
-
const
|
|
734
|
-
|
|
735
|
-
|
|
736
|
-
|
|
737
|
-
|
|
738
|
-
});
|
|
739
|
-
if (!confirm) {
|
|
1115
|
+
const shouldUpdate = await confirm(
|
|
1116
|
+
`Update ${componentsToUpdate.length} component(s)?`,
|
|
1117
|
+
true
|
|
1118
|
+
);
|
|
1119
|
+
if (!shouldUpdate) {
|
|
740
1120
|
console.log(chalk5.yellow("\n\u274C Update cancelled.\n"));
|
|
741
1121
|
return;
|
|
742
1122
|
}
|
|
@@ -785,9 +1165,9 @@ Checking ${componentsToUpdate.length} component(s) for updates...
|
|
|
785
1165
|
async function hasComponentChanges(component, config) {
|
|
786
1166
|
for (const file of component.files) {
|
|
787
1167
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
788
|
-
const filePath =
|
|
1168
|
+
const filePath = path10.join(process.cwd(), targetPath);
|
|
789
1169
|
try {
|
|
790
|
-
const localContent = await
|
|
1170
|
+
const localContent = await fs10.readFile(filePath, "utf-8");
|
|
791
1171
|
const registryContent = transformImports(file.content, config);
|
|
792
1172
|
if (localContent.trim() !== registryContent.trim()) {
|
|
793
1173
|
return true;
|
|
@@ -800,7 +1180,7 @@ async function hasComponentChanges(component, config) {
|
|
|
800
1180
|
}
|
|
801
1181
|
async function updateComponent(name, config, options) {
|
|
802
1182
|
try {
|
|
803
|
-
const component = await getRegistryComponent(name);
|
|
1183
|
+
const component = await getRegistryComponent(name, config);
|
|
804
1184
|
if (!component) {
|
|
805
1185
|
console.log(chalk5.red(` \u274C Component "${name}" not found in registry.`));
|
|
806
1186
|
return { name, updated: false, skipped: true, reason: "not found in registry" };
|
|
@@ -816,13 +1196,8 @@ async function updateComponent(name, config, options) {
|
|
|
816
1196
|
return { name, updated: false, skipped: true, reason: "already up to date" };
|
|
817
1197
|
}
|
|
818
1198
|
if (!options.yes && !options.force) {
|
|
819
|
-
const
|
|
820
|
-
|
|
821
|
-
name: "confirm",
|
|
822
|
-
message: `Update ${chalk5.bold(name)}?`,
|
|
823
|
-
initial: true
|
|
824
|
-
});
|
|
825
|
-
if (!confirm) {
|
|
1199
|
+
const shouldUpdate = await confirm(`Update ${chalk5.bold(name)}?`, true);
|
|
1200
|
+
if (!shouldUpdate) {
|
|
826
1201
|
console.log(chalk5.yellow(` \u23ED\uFE0F Skipped ${name}`));
|
|
827
1202
|
return { name, updated: false, skipped: true, reason: "user cancelled" };
|
|
828
1203
|
}
|
|
@@ -830,10 +1205,10 @@ async function updateComponent(name, config, options) {
|
|
|
830
1205
|
const spinner = ora4(`Updating ${chalk5.bold(name)}...`).start();
|
|
831
1206
|
for (const file of component.files) {
|
|
832
1207
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
833
|
-
const filePath =
|
|
834
|
-
await
|
|
1208
|
+
const filePath = path10.join(process.cwd(), targetPath);
|
|
1209
|
+
await fs10.mkdir(path10.dirname(filePath), { recursive: true });
|
|
835
1210
|
const content = transformImports(file.content, config);
|
|
836
|
-
await
|
|
1211
|
+
await fs10.writeFile(filePath, content, "utf-8");
|
|
837
1212
|
}
|
|
838
1213
|
spinner.succeed(`${chalk5.bold(name)} updated successfully!`);
|
|
839
1214
|
return { name, updated: true, skipped: false };
|
|
@@ -869,15 +1244,13 @@ function displayUpdateResults(results) {
|
|
|
869
1244
|
// src/commands/list.ts
|
|
870
1245
|
import chalk6 from "chalk";
|
|
871
1246
|
import ora5 from "ora";
|
|
872
|
-
import path8 from "path";
|
|
873
|
-
import fs8 from "fs/promises";
|
|
874
1247
|
async function list(options) {
|
|
875
1248
|
const cwd = process.cwd();
|
|
876
|
-
const componentsJsonPath = path8.join(cwd, "components.json");
|
|
877
1249
|
let config;
|
|
878
1250
|
try {
|
|
879
|
-
const
|
|
880
|
-
config =
|
|
1251
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1252
|
+
config = loaded.config;
|
|
1253
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
881
1254
|
} catch (error) {
|
|
882
1255
|
console.log(chalk6.red("\n\u274C components.json not found.\n"));
|
|
883
1256
|
console.log(
|
|
@@ -889,7 +1262,7 @@ async function list(options) {
|
|
|
889
1262
|
const spinner = ora5("Fetching components...").start();
|
|
890
1263
|
let registry;
|
|
891
1264
|
try {
|
|
892
|
-
registry = await fetchRegistry();
|
|
1265
|
+
registry = await fetchRegistry(config);
|
|
893
1266
|
spinner.succeed("Components loaded!");
|
|
894
1267
|
} catch (error) {
|
|
895
1268
|
spinner.fail("Error loading registry");
|
|
@@ -899,9 +1272,10 @@ async function list(options) {
|
|
|
899
1272
|
const allComponents = registry.components || [];
|
|
900
1273
|
const componentsWithStatus = await Promise.all(
|
|
901
1274
|
allComponents.map(async (comp) => {
|
|
902
|
-
const
|
|
1275
|
+
const slug = comp.slug || comp.name;
|
|
1276
|
+
const installed = await isComponentInstalled(slug, config);
|
|
903
1277
|
return {
|
|
904
|
-
...comp,
|
|
1278
|
+
...comp.slug ? comp : { ...comp, slug },
|
|
905
1279
|
installed
|
|
906
1280
|
};
|
|
907
1281
|
})
|
|
@@ -972,20 +1346,20 @@ function displayComponents(components, options) {
|
|
|
972
1346
|
|
|
973
1347
|
// src/commands/debug.ts
|
|
974
1348
|
import chalk7 from "chalk";
|
|
975
|
-
import
|
|
976
|
-
import
|
|
1349
|
+
import path11 from "path";
|
|
1350
|
+
import fs11 from "fs/promises";
|
|
977
1351
|
async function debug(options) {
|
|
978
1352
|
const cwd = process.cwd();
|
|
979
|
-
const componentsJsonPath = path9.join(cwd, "components.json");
|
|
980
1353
|
console.log(chalk7.bold("\n\u{1F50D} Pittaya UI Debug Information\n"));
|
|
981
1354
|
console.log(chalk7.dim(`Working directory: ${cwd}
|
|
982
1355
|
`));
|
|
983
1356
|
let config;
|
|
984
1357
|
try {
|
|
985
|
-
const
|
|
986
|
-
config =
|
|
1358
|
+
const loaded = await loadProjectConfig(cwd);
|
|
1359
|
+
config = loaded.config;
|
|
1360
|
+
applyPittayaProjectConfig(loaded.pittaya);
|
|
987
1361
|
console.log(chalk7.green("\u2705 components.json found"));
|
|
988
|
-
console.log(chalk7.dim(` Path: ${
|
|
1362
|
+
console.log(chalk7.dim(` Path: ${path11.join(cwd, "components.json")}`));
|
|
989
1363
|
} catch (error) {
|
|
990
1364
|
console.log(chalk7.red("\u274C components.json not found\n"));
|
|
991
1365
|
return;
|
|
@@ -1006,7 +1380,7 @@ async function debug(options) {
|
|
|
1006
1380
|
\u{1F50D} Debugging component: ${options.component}
|
|
1007
1381
|
`));
|
|
1008
1382
|
try {
|
|
1009
|
-
const component = await getRegistryComponent(options.component);
|
|
1383
|
+
const component = await getRegistryComponent(options.component, config);
|
|
1010
1384
|
if (!component) {
|
|
1011
1385
|
console.log(chalk7.red(`\u274C Component not found in registry
|
|
1012
1386
|
`));
|
|
@@ -1018,20 +1392,20 @@ async function debug(options) {
|
|
|
1018
1392
|
console.log(chalk7.bold("\n\u{1F4C1} Expected Files:"));
|
|
1019
1393
|
for (const file of component.files) {
|
|
1020
1394
|
const targetPath = await resolveTargetPath(file.name, component.type, config);
|
|
1021
|
-
const fullPath =
|
|
1022
|
-
const exists = await
|
|
1395
|
+
const fullPath = path11.join(cwd, targetPath);
|
|
1396
|
+
const exists = await fs11.access(fullPath).then(() => true).catch(() => false);
|
|
1023
1397
|
const statusIcon = exists ? chalk7.green("\u2705") : chalk7.red("\u274C");
|
|
1024
1398
|
const statusText = exists ? chalk7.green("EXISTS") : chalk7.red("NOT FOUND");
|
|
1025
1399
|
console.log(` ${statusIcon} ${file.name}`);
|
|
1026
1400
|
console.log(chalk7.dim(` Expected: ${fullPath}`));
|
|
1027
1401
|
console.log(chalk7.dim(` Status: ${statusText}`));
|
|
1028
1402
|
if (!exists) {
|
|
1029
|
-
const dir =
|
|
1403
|
+
const dir = path11.dirname(fullPath);
|
|
1030
1404
|
try {
|
|
1031
|
-
const dirExists = await
|
|
1405
|
+
const dirExists = await fs11.access(dir).then(() => true).catch(() => false);
|
|
1032
1406
|
if (dirExists) {
|
|
1033
|
-
const filesInDir = await
|
|
1034
|
-
const baseName =
|
|
1407
|
+
const filesInDir = await fs11.readdir(dir);
|
|
1408
|
+
const baseName = path11.basename(file.name, path11.extname(file.name));
|
|
1035
1409
|
const similarFiles = filesInDir.filter(
|
|
1036
1410
|
(f) => f.includes(baseName) || f.toLowerCase().includes(baseName.toLowerCase())
|
|
1037
1411
|
);
|
|
@@ -1070,9 +1444,9 @@ async function debug(options) {
|
|
|
1070
1444
|
|
|
1071
1445
|
// src/index.ts
|
|
1072
1446
|
import { readFileSync } from "fs";
|
|
1073
|
-
import { fileURLToPath } from "url";
|
|
1447
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
1074
1448
|
import { dirname, join } from "path";
|
|
1075
|
-
var __filename =
|
|
1449
|
+
var __filename = fileURLToPath2(import.meta.url);
|
|
1076
1450
|
var __dirname = dirname(__filename);
|
|
1077
1451
|
var packageJson = JSON.parse(
|
|
1078
1452
|
readFileSync(join(__dirname, "../package.json"), "utf-8")
|