digdesign 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +376 -46
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -53,6 +53,60 @@ async function writeConfig(config, cwd = process.cwd()) {
|
|
|
53
53
|
);
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
// src/lib/errors.ts
|
|
57
|
+
var DigError = class extends Error {
|
|
58
|
+
constructor(message, options) {
|
|
59
|
+
super(message, options);
|
|
60
|
+
this.name = "DigError";
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
// src/lib/prompt.ts
|
|
65
|
+
import * as readline from "readline/promises";
|
|
66
|
+
import { stdin, stdout } from "process";
|
|
67
|
+
async function askLine(question) {
|
|
68
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
69
|
+
try {
|
|
70
|
+
return await rl.question(question);
|
|
71
|
+
} catch {
|
|
72
|
+
console.log();
|
|
73
|
+
return "";
|
|
74
|
+
} finally {
|
|
75
|
+
rl.close();
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
async function confirm(question, defaultValue) {
|
|
79
|
+
const suffix = defaultValue ? "(Y/n)" : "(y/N)";
|
|
80
|
+
const raw = await askLine(`${question} ${suffix} `);
|
|
81
|
+
const answer = raw.trim().toLowerCase();
|
|
82
|
+
if (!answer) return defaultValue;
|
|
83
|
+
return answer === "y" || answer === "yes";
|
|
84
|
+
}
|
|
85
|
+
async function ask(question, defaultValue) {
|
|
86
|
+
const raw = await askLine(`${question} (${defaultValue}) `);
|
|
87
|
+
return raw.trim() || defaultValue;
|
|
88
|
+
}
|
|
89
|
+
async function multiSelect(question, options) {
|
|
90
|
+
if (options.length === 0) return [];
|
|
91
|
+
const width = String(options.length).length;
|
|
92
|
+
for (const [index, option] of options.entries()) {
|
|
93
|
+
const number = String(index + 1).padStart(width);
|
|
94
|
+
console.log(` ${number}) ${option.label}`);
|
|
95
|
+
}
|
|
96
|
+
const raw = await askLine(`${question} `);
|
|
97
|
+
return parseSelection(raw, options);
|
|
98
|
+
}
|
|
99
|
+
function parseSelection(raw, options) {
|
|
100
|
+
const picked = /* @__PURE__ */ new Set();
|
|
101
|
+
for (const token of raw.split(/[\s,،]+/).filter(Boolean)) {
|
|
102
|
+
const index = Number(token) - 1;
|
|
103
|
+
if (Number.isInteger(index) && index >= 0 && index < options.length) {
|
|
104
|
+
picked.add(options[index].value);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
return [...picked];
|
|
108
|
+
}
|
|
109
|
+
|
|
56
110
|
// src/lib/hash.ts
|
|
57
111
|
import { createHash } from "crypto";
|
|
58
112
|
function hashContent(content) {
|
|
@@ -125,31 +179,62 @@ function installArgs(pm, deps, dev) {
|
|
|
125
179
|
const devFlag = dev ? pm === "npm" ? "--save-dev" : "-D" : null;
|
|
126
180
|
return devFlag ? [verb, devFlag, ...deps] : [verb, ...deps];
|
|
127
181
|
}
|
|
182
|
+
var PEER_CONFLICT_FLAG = {
|
|
183
|
+
npm: "--legacy-peer-deps",
|
|
184
|
+
pnpm: "--strict-peer-dependencies=false"
|
|
185
|
+
};
|
|
186
|
+
function installFailure(pm, args, code, stderr) {
|
|
187
|
+
const command = `${pm} ${args.join(" ")}`;
|
|
188
|
+
const lines = [`\u0646\u0635\u0628\u0650 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627 \u0634\u06A9\u0633\u062A \u062E\u0648\u0631\u062F (${command}\u060C \u06A9\u062F ${code ?? "?"}).`];
|
|
189
|
+
if (/ERESOLVE|peer dep|ERR_PNPM_PEER_DEP_ISSUES/i.test(stderr)) {
|
|
190
|
+
const flag = PEER_CONFLICT_FLAG[pm];
|
|
191
|
+
lines.push(
|
|
192
|
+
" \u0639\u0644\u062A: \u062A\u0639\u0627\u0631\u0636\u0650 peer dependency \u062F\u0631 \u062F\u0631\u062E\u062A\u0650 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u0650 \u062E\u0648\u062F\u0650 \u067E\u0631\u0648\u0698\u0647\u060C \u0646\u0647 \u062F\u0631 \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A\u200C\u0647\u0627\u06CC \u062F\u06CC\u06AF."
|
|
193
|
+
);
|
|
194
|
+
lines.push(" \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0646\u0648\u0634\u062A\u0647 \u0634\u062F\u0646\u062F\u061B \u0641\u0642\u0637 \u0646\u0635\u0628\u0650 \u067E\u06A9\u06CC\u062C\u200C\u0647\u0627 \u0645\u0627\u0646\u062F\u0647.");
|
|
195
|
+
lines.push(
|
|
196
|
+
flag ? ` \u062F\u0633\u062A\u06CC \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F: ${command} ${flag}` : ` \u0627\u0648\u0644 \u062F\u0631\u062E\u062A\u0650 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC \u0631\u0627 \u062F\u0631\u0633\u062A \u06A9\u0646\u06CC\u062F\u060C \u0628\u0639\u062F: ${command}`
|
|
197
|
+
);
|
|
198
|
+
} else {
|
|
199
|
+
lines.push(" \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0646\u0648\u0634\u062A\u0647 \u0634\u062F\u0646\u062F\u061B \u0641\u0642\u0637 \u0646\u0635\u0628\u0650 \u067E\u06A9\u06CC\u062C\u200C\u0647\u0627 \u0645\u0627\u0646\u062F\u0647.");
|
|
200
|
+
lines.push(` \u062E\u0631\u0648\u062C\u06CC\u0650 \u06A9\u0627\u0645\u0644\u0650 ${pm} \u0628\u0627\u0644\u0627\u062A\u0631 \u0686\u0627\u067E \u0634\u062F\u0647. \u0628\u0631\u0627\u06CC \u062A\u0644\u0627\u0634 \u062F\u0648\u0628\u0627\u0631\u0647: ${command}`);
|
|
201
|
+
}
|
|
202
|
+
lines.push(" \u0628\u0631\u0627\u06CC \u0631\u062F \u06A9\u0631\u062F\u0646\u0650 \u0646\u0635\u0628\u0650 \u062E\u0648\u062F\u06A9\u0627\u0631 \u0627\u0632 \u0627\u06CC\u0646 \u0628\u0647 \u0628\u0639\u062F: dig add \u2026 --no-install");
|
|
203
|
+
return new DigError(lines.join("\n"));
|
|
204
|
+
}
|
|
128
205
|
function installDependencies(pm, deps, options = {}) {
|
|
129
206
|
if (!deps.length) return Promise.resolve();
|
|
130
207
|
const args = installArgs(pm, deps, Boolean(options.dev));
|
|
131
208
|
return new Promise((resolve, reject) => {
|
|
132
209
|
const child = spawn(pm, args, {
|
|
133
210
|
cwd: options.cwd ?? process.cwd(),
|
|
134
|
-
|
|
211
|
+
// stderr پایپ میشود تا هم مثل قبل بیکموکاست به کاربر برسد، هم بتوانیم
|
|
212
|
+
// علتِ شکست را از رویش تشخیص بدهیم. stdout همچنان inherit است چون
|
|
213
|
+
// نوارِ پیشرفتِ پکیجمنیجر باید زنده بماند.
|
|
214
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
135
215
|
shell: process.platform === "win32"
|
|
136
216
|
});
|
|
217
|
+
let stderr = "";
|
|
218
|
+
child.stderr?.on("data", (chunk) => {
|
|
219
|
+
const text = chunk.toString();
|
|
220
|
+
stderr += text;
|
|
221
|
+
process.stderr.write(text);
|
|
222
|
+
});
|
|
137
223
|
child.on("exit", (code) => {
|
|
138
224
|
if (code === 0) resolve();
|
|
139
|
-
else reject(
|
|
225
|
+
else reject(installFailure(pm, args, code, stderr));
|
|
226
|
+
});
|
|
227
|
+
child.on("error", (cause) => {
|
|
228
|
+
reject(
|
|
229
|
+
new DigError(
|
|
230
|
+
`\xAB${pm}\xBB \u0627\u062C\u0631\u0627 \u0646\u0634\u062F. \u0645\u0637\u0645\u0626\u0646 \u0634\u0648\u06CC\u062F \u0646\u0635\u0628 \u0627\u0633\u062A \u0648 \u062F\u0631 PATH \u0642\u0631\u0627\u0631 \u062F\u0627\u0631\u062F.`,
|
|
231
|
+
{ cause }
|
|
232
|
+
)
|
|
233
|
+
);
|
|
140
234
|
});
|
|
141
|
-
child.on("error", reject);
|
|
142
235
|
});
|
|
143
236
|
}
|
|
144
237
|
|
|
145
|
-
// src/lib/errors.ts
|
|
146
|
-
var DigError = class extends Error {
|
|
147
|
-
constructor(message, options) {
|
|
148
|
-
super(message, options);
|
|
149
|
-
this.name = "DigError";
|
|
150
|
-
}
|
|
151
|
-
};
|
|
152
|
-
|
|
153
238
|
// src/lib/registry.ts
|
|
154
239
|
function resolveUrl(nameOrUrl, registryUrl) {
|
|
155
240
|
if (/^https?:\/\//.test(nameOrUrl)) return nameOrUrl;
|
|
@@ -284,7 +369,10 @@ import path5 from "path";
|
|
|
284
369
|
function toPosixPath(relativePath) {
|
|
285
370
|
return relativePath.split(path5.sep).join("/");
|
|
286
371
|
}
|
|
287
|
-
function resolveTargetPath(filePath, aliases) {
|
|
372
|
+
function resolveTargetPath(filePath, aliases, options = {}) {
|
|
373
|
+
if (/(?:^|\/)app\/globals\.css$/.test(filePath)) {
|
|
374
|
+
return options.tailwindCss ?? "src/app/globals.css";
|
|
375
|
+
}
|
|
288
376
|
const match = filePath.match(/(?:^|\/)(components|lib|hooks)\/(.*)$/);
|
|
289
377
|
const cleaned = match ? `${match[1]}/${match[2]}` : filePath;
|
|
290
378
|
if (cleaned.startsWith("components/ui/")) {
|
|
@@ -311,11 +399,82 @@ async function pathExists(target) {
|
|
|
311
399
|
return false;
|
|
312
400
|
}
|
|
313
401
|
}
|
|
402
|
+
async function pickComponents(registryUrl) {
|
|
403
|
+
if (!process.stdin.isTTY) {
|
|
404
|
+
throw new DigError(
|
|
405
|
+
"\u0646\u0627\u0645 \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0631\u0627 \u0628\u062F\u0647\u06CC\u062F: dig add button\n \u0628\u0631\u0627\u06CC \u062F\u06CC\u062F\u0646\u0650 \u0641\u0647\u0631\u0633\u062A: dig list"
|
|
406
|
+
);
|
|
407
|
+
}
|
|
408
|
+
const index = await fetchRegistryIndex(registryUrl);
|
|
409
|
+
const choices = index.items.filter((item) => item.type === "registry:ui").map((item) => ({
|
|
410
|
+
value: item.name,
|
|
411
|
+
label: item.title ? `${item.name} \u2014 ${item.title}` : item.name
|
|
412
|
+
}));
|
|
413
|
+
console.log(`
|
|
414
|
+
${choices.length} \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u062F\u0631 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC:
|
|
415
|
+
`);
|
|
416
|
+
const picked = await multiSelect(
|
|
417
|
+
"\n\u0634\u0645\u0627\u0631\u0647\u200C\u0647\u0627 \u0631\u0627 \u0628\u0627 \u0641\u0627\u0635\u0644\u0647 \u0628\u062F\u0647\u06CC\u062F (\u062E\u0627\u0644\u06CC = \u0644\u063A\u0648):",
|
|
418
|
+
choices
|
|
419
|
+
);
|
|
420
|
+
if (picked.length === 0) {
|
|
421
|
+
console.log("\u0686\u06CC\u0632\u06CC \u0627\u0646\u062A\u062E\u0627\u0628 \u0646\u0634\u062F.");
|
|
422
|
+
return [];
|
|
423
|
+
}
|
|
424
|
+
return picked;
|
|
425
|
+
}
|
|
314
426
|
async function addCommand(components, options) {
|
|
315
427
|
const cwd = process.cwd();
|
|
316
428
|
const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
|
|
429
|
+
const names = components.length ? components : await pickComponents(config.registryUrl);
|
|
430
|
+
if (names.length === 0) return;
|
|
317
431
|
console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A \u0627\u0632 ${config.registryUrl} \u2026`);
|
|
318
|
-
const items = await resolveRegistryTree(
|
|
432
|
+
const items = await resolveRegistryTree(names, config.registryUrl);
|
|
433
|
+
let overwrite = Boolean(options.overwrite);
|
|
434
|
+
if (!overwrite) {
|
|
435
|
+
const existing = [];
|
|
436
|
+
for (const item of items.values()) {
|
|
437
|
+
for (const file of item.files) {
|
|
438
|
+
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases, {
|
|
439
|
+
tailwindCss: config.tailwind.css
|
|
440
|
+
}));
|
|
441
|
+
if (await pathExists(target)) existing.push(path6.relative(cwd, target));
|
|
442
|
+
}
|
|
443
|
+
}
|
|
444
|
+
if (existing.length) {
|
|
445
|
+
if (options.yes) {
|
|
446
|
+
overwrite = true;
|
|
447
|
+
} else if (process.stdin.isTTY) {
|
|
448
|
+
console.log(`
|
|
449
|
+
${existing.length} \u0641\u0627\u06CC\u0644 \u0627\u0632 \u0642\u0628\u0644 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F:`);
|
|
450
|
+
for (const file of existing.slice(0, 10)) console.log(` ${file}`);
|
|
451
|
+
if (existing.length > 10) console.log(` \u2026 \u0648 ${existing.length - 10} \u0641\u0627\u06CC\u0644 \u062F\u06CC\u06AF\u0631`);
|
|
452
|
+
overwrite = await confirm("\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0634\u0648\u0646\u062F\u061F", false);
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
if (options.dryRun) {
|
|
457
|
+
const npmDeps = /* @__PURE__ */ new Set();
|
|
458
|
+
console.log("\n\u067E\u06CC\u0634\u200C\u0646\u0645\u0627\u06CC\u0634 (\u0647\u06CC\u0686 \u0641\u0627\u06CC\u0644\u06CC \u0646\u0648\u0634\u062A\u0647 \u0646\u0645\u06CC\u200C\u0634\u0648\u062F):\n");
|
|
459
|
+
for (const item of items.values()) {
|
|
460
|
+
for (const dep of item.dependencies ?? []) npmDeps.add(dep);
|
|
461
|
+
for (const file of item.files) {
|
|
462
|
+
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases, {
|
|
463
|
+
tailwindCss: config.tailwind.css
|
|
464
|
+
}));
|
|
465
|
+
const exists = await pathExists(target);
|
|
466
|
+
const mark = exists ? overwrite ? "~" : "-" : "+";
|
|
467
|
+
const note = exists ? overwrite ? " (\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC)" : " (\u0631\u062F \u0645\u06CC\u200C\u0634\u0648\u062F\u060C \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F)" : "";
|
|
468
|
+
console.log(`${mark} ${path6.relative(cwd, target)}${note}`);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
console.log(`
|
|
472
|
+
${items.size} \u0622\u06CC\u062A\u0645 \u0627\u0632 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC.`);
|
|
473
|
+
if (npmDeps.size) {
|
|
474
|
+
console.log(`\u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627\u06CC npm: ${[...npmDeps].join(" ")}`);
|
|
475
|
+
}
|
|
476
|
+
return;
|
|
477
|
+
}
|
|
319
478
|
const dependencies = /* @__PURE__ */ new Set();
|
|
320
479
|
const devDependencies = /* @__PURE__ */ new Set();
|
|
321
480
|
let written = 0;
|
|
@@ -329,8 +488,10 @@ async function addCommand(components, options) {
|
|
|
329
488
|
const writtenFiles = {};
|
|
330
489
|
const writtenContents = {};
|
|
331
490
|
for (const file of item.files) {
|
|
332
|
-
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases
|
|
333
|
-
|
|
491
|
+
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases, {
|
|
492
|
+
tailwindCss: config.tailwind.css
|
|
493
|
+
}));
|
|
494
|
+
if (!overwrite && await pathExists(target)) {
|
|
334
495
|
console.log(`- \u0631\u062F \u0634\u062F (\u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F): ${path6.relative(cwd, target)}`);
|
|
335
496
|
skipped++;
|
|
336
497
|
continue;
|
|
@@ -384,6 +545,107 @@ ${written} \u0641\u0627\u06CC\u0644 \u0646\u0648\u0634\u062A\u0647 \u0634\u062F\
|
|
|
384
545
|
}
|
|
385
546
|
}
|
|
386
547
|
|
|
548
|
+
// src/lib/search.ts
|
|
549
|
+
var ARABIC_TO_PERSIAN = {
|
|
550
|
+
"\u064A": "\u06CC",
|
|
551
|
+
// ي → ی
|
|
552
|
+
"\u0649": "\u06CC",
|
|
553
|
+
// ى → ی
|
|
554
|
+
"\u0643": "\u06A9",
|
|
555
|
+
// ك → ک
|
|
556
|
+
"\u0629": "\u0647",
|
|
557
|
+
// ة → ه
|
|
558
|
+
"\u0623": "\u0627",
|
|
559
|
+
// أ → ا
|
|
560
|
+
"\u0625": "\u0627",
|
|
561
|
+
// إ → ا
|
|
562
|
+
"\u0622": "\u0627",
|
|
563
|
+
// آ → ا
|
|
564
|
+
"\u0624": "\u0648"
|
|
565
|
+
// ؤ → و
|
|
566
|
+
};
|
|
567
|
+
var DIACRITICS = /[ً-ْٰ]/g;
|
|
568
|
+
var INVISIBLE = /[-]/g;
|
|
569
|
+
function toSearchKey(value) {
|
|
570
|
+
return value.replace(/[يىكةأإآؤ]/g, (ch) => ARABIC_TO_PERSIAN[ch]).replace(DIACRITICS, "").replace(INVISIBLE, "").toLowerCase().replace(/[\s]+/g, "");
|
|
571
|
+
}
|
|
572
|
+
function scoreItem(item, query) {
|
|
573
|
+
const q = toSearchKey(query);
|
|
574
|
+
if (!q) return 0;
|
|
575
|
+
const name = toSearchKey(item.name);
|
|
576
|
+
const title = toSearchKey(item.title ?? "");
|
|
577
|
+
const description = toSearchKey(item.description ?? "");
|
|
578
|
+
if (name === q || title === q) return 100;
|
|
579
|
+
if (name.startsWith(q) || title.startsWith(q)) return 80;
|
|
580
|
+
if (name.includes(q) || title.includes(q)) return 60;
|
|
581
|
+
if (description.includes(q)) return 30;
|
|
582
|
+
return 0;
|
|
583
|
+
}
|
|
584
|
+
function searchItems(items, query) {
|
|
585
|
+
return items.map((item) => ({ item, score: scoreItem(item, query) })).filter((entry) => entry.score > 0).sort(
|
|
586
|
+
(a, b) => b.score - a.score || a.item.name.localeCompare(b.item.name)
|
|
587
|
+
).map((entry) => entry.item);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
// src/commands/list.ts
|
|
591
|
+
var TYPE_LABEL = {
|
|
592
|
+
"registry:ui": "\u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A",
|
|
593
|
+
"registry:lib": "\u0627\u0628\u0632\u0627\u0631",
|
|
594
|
+
"registry:theme": "\u062A\u0645"
|
|
595
|
+
};
|
|
596
|
+
async function loadItems(cwd) {
|
|
597
|
+
const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
|
|
598
|
+
const index = await fetchRegistryIndex(config.registryUrl);
|
|
599
|
+
return index.items;
|
|
600
|
+
}
|
|
601
|
+
function matchesType(item, type) {
|
|
602
|
+
if (!type) return true;
|
|
603
|
+
const wanted = type.startsWith("registry:") ? type : `registry:${type}`;
|
|
604
|
+
return item.type === wanted;
|
|
605
|
+
}
|
|
606
|
+
function printTable(items) {
|
|
607
|
+
if (items.length === 0) {
|
|
608
|
+
console.log("\u0686\u06CC\u0632\u06CC \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F.");
|
|
609
|
+
return;
|
|
610
|
+
}
|
|
611
|
+
const width = Math.max(...items.map((item) => item.name.length));
|
|
612
|
+
const labelWidth = Math.max(
|
|
613
|
+
...items.map((item) => (TYPE_LABEL[item.type] ?? item.type).length)
|
|
614
|
+
);
|
|
615
|
+
for (const item of items) {
|
|
616
|
+
const label = (TYPE_LABEL[item.type] ?? item.type).padEnd(labelWidth);
|
|
617
|
+
const title = item.title ? ` \xB7 ${item.title}` : "";
|
|
618
|
+
console.log(`${item.name.padEnd(width)} ${label}${title}`);
|
|
619
|
+
}
|
|
620
|
+
console.log(`
|
|
621
|
+
${items.length} \u0622\u06CC\u062A\u0645. \u0628\u0631\u0627\u06CC \u0646\u0635\u0628: dig add <\u0646\u0627\u0645>`);
|
|
622
|
+
}
|
|
623
|
+
async function listCommand(options) {
|
|
624
|
+
const items = (await loadItems(process.cwd())).filter(
|
|
625
|
+
(item) => matchesType(item, options.type)
|
|
626
|
+
);
|
|
627
|
+
if (options.json) {
|
|
628
|
+
console.log(JSON.stringify(items, null, 2));
|
|
629
|
+
return;
|
|
630
|
+
}
|
|
631
|
+
printTable(items);
|
|
632
|
+
}
|
|
633
|
+
async function searchCommand(query, options) {
|
|
634
|
+
const items = searchItems(await loadItems(process.cwd()), query);
|
|
635
|
+
if (options.json) {
|
|
636
|
+
console.log(JSON.stringify(items, null, 2));
|
|
637
|
+
return;
|
|
638
|
+
}
|
|
639
|
+
if (items.length === 0) {
|
|
640
|
+
console.log(
|
|
641
|
+
`\u0686\u06CC\u0632\u06CC \u0628\u0631\u0627\u06CC \xAB${query}\xBB \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F.
|
|
642
|
+
\u0641\u0647\u0631\u0633\u062A \u06A9\u0627\u0645\u0644: dig list`
|
|
643
|
+
);
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
printTable(items);
|
|
647
|
+
}
|
|
648
|
+
|
|
387
649
|
// src/lib/diff.ts
|
|
388
650
|
import { readFile as readFile4 } from "fs/promises";
|
|
389
651
|
import path7 from "path";
|
|
@@ -1686,28 +1948,77 @@ async function impactCommand(name, options) {
|
|
|
1686
1948
|
}
|
|
1687
1949
|
|
|
1688
1950
|
// src/commands/init.ts
|
|
1951
|
+
import { mkdir as mkdir4, readFile as readFile7, writeFile as writeFile5 } from "fs/promises";
|
|
1689
1952
|
import path10 from "path";
|
|
1690
|
-
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
const raw = await rl.question(`${question} ${suffix} `);
|
|
1698
|
-
rl.close();
|
|
1699
|
-
const answer = raw.trim().toLowerCase();
|
|
1700
|
-
if (!answer) return defaultValue;
|
|
1701
|
-
return answer === "y" || answer === "yes";
|
|
1953
|
+
var THEME_ITEM = "theme";
|
|
1954
|
+
async function readIfExists(target) {
|
|
1955
|
+
try {
|
|
1956
|
+
return await readFile7(target, "utf8");
|
|
1957
|
+
} catch {
|
|
1958
|
+
return null;
|
|
1959
|
+
}
|
|
1702
1960
|
}
|
|
1703
|
-
async function
|
|
1704
|
-
const
|
|
1705
|
-
const
|
|
1706
|
-
|
|
1707
|
-
|
|
1961
|
+
async function writeTheme(config, cwd, options) {
|
|
1962
|
+
const item = await fetchRegistryItem(THEME_ITEM, config.registryUrl);
|
|
1963
|
+
const file = item.files[0];
|
|
1964
|
+
if (!file) {
|
|
1965
|
+
throw new DigError("\u0622\u06CC\u062A\u0645\u0650 \xABtheme\xBB \u062F\u0631 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u0641\u0627\u06CC\u0644\u06CC \u0646\u062F\u0627\u0631\u062F.");
|
|
1966
|
+
}
|
|
1967
|
+
const target = path10.join(cwd, config.tailwind.css);
|
|
1968
|
+
const existing = await readIfExists(target);
|
|
1969
|
+
const isBoilerplate = existing === null || existing.split("\n").filter((line) => line.trim() && !line.trim().startsWith("@import")).length === 0;
|
|
1970
|
+
if (!isBoilerplate && !options.yes) {
|
|
1971
|
+
console.log(`
|
|
1972
|
+
${config.tailwind.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u062F\u0627\u0631\u062F.`);
|
|
1973
|
+
const overwrite = await confirm(
|
|
1974
|
+
"\u0628\u0627 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0634\u0648\u062F\u061F (\u0646\u0633\u062E\u0647\u0654 \u0641\u0639\u0644\u06CC \u06A9\u0646\u0627\u0631\u0634 \u0628\u0647\u200C\u0639\u0646\u0648\u0627\u0646 .backup \u0645\u06CC\u200C\u0645\u0627\u0646\u062F)",
|
|
1975
|
+
false
|
|
1976
|
+
);
|
|
1977
|
+
if (!overwrite) {
|
|
1978
|
+
console.log(
|
|
1979
|
+
`- \u062A\u0645 \u0646\u0648\u0634\u062A\u0647 \u0646\u0634\u062F. \u0628\u0631\u0627\u06CC \u0646\u0648\u0634\u062A\u0646\u0634 \u0628\u0639\u062F\u0627\u064B: dig add ${THEME_ITEM} --overwrite`
|
|
1980
|
+
);
|
|
1981
|
+
return "skipped";
|
|
1982
|
+
}
|
|
1983
|
+
}
|
|
1984
|
+
if (!isBoilerplate && existing !== null) {
|
|
1985
|
+
await writeFile5(`${target}.backup`, existing, "utf8");
|
|
1986
|
+
console.log(` \u0646\u0633\u062E\u0647\u0654 \u0642\u0628\u0644\u06CC \u062F\u0631 ${config.tailwind.css}.backup \u0646\u06AF\u0647 \u062F\u0627\u0634\u062A\u0647 \u0634\u062F.`);
|
|
1987
|
+
}
|
|
1988
|
+
await mkdir4(path10.dirname(target), { recursive: true });
|
|
1989
|
+
await writeFile5(target, file.content, "utf8");
|
|
1990
|
+
console.log(`\u2713 \u062A\u0645 \u062F\u0631 ${config.tailwind.css} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
|
|
1991
|
+
if (item.dependencies?.length) {
|
|
1992
|
+
const pm = await detectPackageManager(cwd);
|
|
1993
|
+
console.log(`
|
|
1994
|
+
\u0646\u0635\u0628 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627\u06CC \u062A\u0645 \u0628\u0627 ${pm} \u2026`);
|
|
1995
|
+
await installDependencies(pm, item.dependencies, { cwd });
|
|
1996
|
+
}
|
|
1997
|
+
return "written";
|
|
1998
|
+
}
|
|
1999
|
+
async function applyRtl(cwd) {
|
|
2000
|
+
for (const candidate of ["src/app/layout.tsx", "app/layout.tsx"]) {
|
|
2001
|
+
const target = path10.join(cwd, candidate);
|
|
2002
|
+
const source = await readIfExists(target);
|
|
2003
|
+
if (source === null) continue;
|
|
2004
|
+
if (/<html[^>]*\sdir=/.test(source)) {
|
|
2005
|
+
console.log(`- ${candidate} \u0627\u0632 \u0642\u0628\u0644 dir \u062F\u0627\u0631\u062F\u061B \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
|
|
2006
|
+
return;
|
|
2007
|
+
}
|
|
2008
|
+
const match = source.match(/<html\b([^>]*)>/);
|
|
2009
|
+
if (!match) break;
|
|
2010
|
+
const updated = source.replace(
|
|
2011
|
+
match[0],
|
|
2012
|
+
`<html${match[1]} dir="rtl">`.replace(/\s+dir="rtl">$/, ' dir="rtl">')
|
|
2013
|
+
);
|
|
2014
|
+
await writeFile5(target, updated, "utf8");
|
|
2015
|
+
console.log(`\u2713 dir="rtl" \u0628\u0647 ${candidate} \u0627\u0636\u0627\u0641\u0647 \u0634\u062F.`);
|
|
2016
|
+
return;
|
|
2017
|
+
}
|
|
2018
|
+
console.log(
|
|
2019
|
+
'- \u0686\u06CC\u062F\u0645\u0627\u0646\u0650 \u0631\u06CC\u0634\u0647 \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F. \u062E\u0648\u062F\u062A\u0627\u0646 dir="rtl" \u0631\u0627 \u0631\u0648\u06CC \u062A\u06AF <html> \u0628\u06AF\u0630\u0627\u0631\u06CC\u062F.'
|
|
2020
|
+
);
|
|
1708
2021
|
}
|
|
1709
|
-
|
|
1710
|
-
// src/commands/init.ts
|
|
1711
2022
|
async function initCommand(options) {
|
|
1712
2023
|
const cwd = process.cwd();
|
|
1713
2024
|
const base = defaultConfig();
|
|
@@ -1731,10 +2042,22 @@ async function initCommand(options) {
|
|
|
1731
2042
|
};
|
|
1732
2043
|
await writeConfig(config, cwd);
|
|
1733
2044
|
console.log(`\u2713 ${path10.join(cwd, "dig.json")} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
|
|
2045
|
+
const theme = await writeTheme(config, cwd, options);
|
|
2046
|
+
if (config.rtl) {
|
|
2047
|
+
await applyRtl(cwd);
|
|
2048
|
+
}
|
|
2049
|
+
console.log("\n\u0622\u0645\u0627\u062F\u0647 \u0627\u0633\u062A. \u0642\u062F\u0645 \u0628\u0639\u062F\u06CC:");
|
|
2050
|
+
console.log(" dig add button");
|
|
2051
|
+
if (theme === "skipped") {
|
|
2052
|
+
console.log(
|
|
2053
|
+
`
|
|
2054
|
+
\u26A0 \u0628\u062F\u0648\u0646 \u062A\u0645\u060C \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A\u200C\u0647\u0627 \u0646\u0635\u0628 \u0645\u06CC\u200C\u0634\u0648\u0646\u062F \u0648\u0644\u06CC \u0628\u06CC\u200C\u0638\u0627\u0647\u0631 \u0645\u06CC\u200C\u0645\u0627\u0646\u0646\u062F (\u0631\u0646\u06AF\u060C \u0634\u0639\u0627\u0639 \u0648 \u0633\u0627\u06CC\u0647 \u0627\u0632 \u062A\u0648\u06A9\u0646 \u0645\u06CC\u200C\u0622\u06CC\u0646\u062F).`
|
|
2055
|
+
);
|
|
2056
|
+
}
|
|
1734
2057
|
}
|
|
1735
2058
|
|
|
1736
2059
|
// src/lib/migration-apply.ts
|
|
1737
|
-
import { readFile as
|
|
2060
|
+
import { readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
|
|
1738
2061
|
import path11 from "path";
|
|
1739
2062
|
|
|
1740
2063
|
// src/lib/migration-strategy.ts
|
|
@@ -1812,7 +2135,7 @@ function looksBinary2(buffer) {
|
|
|
1812
2135
|
async function readTextFileSafely2(target) {
|
|
1813
2136
|
let buffer;
|
|
1814
2137
|
try {
|
|
1815
|
-
buffer = await
|
|
2138
|
+
buffer = await readFile8(target);
|
|
1816
2139
|
} catch (error) {
|
|
1817
2140
|
if (error.code === "ENOENT") return void 0;
|
|
1818
2141
|
throw error;
|
|
@@ -1924,12 +2247,12 @@ async function planOrApplyMigrations(params) {
|
|
|
1924
2247
|
const written = [];
|
|
1925
2248
|
try {
|
|
1926
2249
|
for (const item of pending) {
|
|
1927
|
-
await
|
|
2250
|
+
await writeFile6(item.target, item.newContent, "utf8");
|
|
1928
2251
|
written.push(item);
|
|
1929
2252
|
}
|
|
1930
2253
|
} catch (error) {
|
|
1931
2254
|
for (const item of written) {
|
|
1932
|
-
await
|
|
2255
|
+
await writeFile6(item.target, item.originalContent, "utf8");
|
|
1933
2256
|
}
|
|
1934
2257
|
return {
|
|
1935
2258
|
name,
|
|
@@ -2540,7 +2863,7 @@ ${entry.migrationHint}`);
|
|
|
2540
2863
|
}
|
|
2541
2864
|
|
|
2542
2865
|
// src/lib/update.ts
|
|
2543
|
-
import { mkdir as
|
|
2866
|
+
import { mkdir as mkdir5, readFile as readFile9, rm as rm2, writeFile as writeFile7 } from "fs/promises";
|
|
2544
2867
|
import path12 from "path";
|
|
2545
2868
|
function safeFileIndexes(drift) {
|
|
2546
2869
|
const indexes = [];
|
|
@@ -2569,14 +2892,14 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun) {
|
|
|
2569
2892
|
newContent: registryFile.content,
|
|
2570
2893
|
newHash: registryFile.hash ?? hashContent(registryFile.content),
|
|
2571
2894
|
isNewFile,
|
|
2572
|
-
originalContent: isNewFile ? void 0 : await
|
|
2895
|
+
originalContent: isNewFile ? void 0 : await readFile9(target, "utf8")
|
|
2573
2896
|
});
|
|
2574
2897
|
}
|
|
2575
2898
|
const written = [];
|
|
2576
2899
|
try {
|
|
2577
2900
|
for (const item of pending) {
|
|
2578
|
-
if (item.isNewFile) await
|
|
2579
|
-
await
|
|
2901
|
+
if (item.isNewFile) await mkdir5(path12.dirname(item.target), { recursive: true });
|
|
2902
|
+
await writeFile7(item.target, item.newContent, "utf8");
|
|
2580
2903
|
written.push(item);
|
|
2581
2904
|
}
|
|
2582
2905
|
} catch (error) {
|
|
@@ -2584,7 +2907,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun) {
|
|
|
2584
2907
|
if (item.isNewFile) {
|
|
2585
2908
|
await rm2(item.target, { force: true });
|
|
2586
2909
|
} else {
|
|
2587
|
-
await
|
|
2910
|
+
await writeFile7(item.target, item.originalContent, "utf8");
|
|
2588
2911
|
}
|
|
2589
2912
|
}
|
|
2590
2913
|
return { actions, writtenHashes: {}, rollbackError: error.message };
|
|
@@ -2872,11 +3195,18 @@ ${result.name}`);
|
|
|
2872
3195
|
}
|
|
2873
3196
|
}
|
|
2874
3197
|
|
|
3198
|
+
// src/lib/version.ts
|
|
3199
|
+
var CLI_VERSION = "0.3.0";
|
|
3200
|
+
|
|
2875
3201
|
// src/index.ts
|
|
2876
3202
|
var program = new Command();
|
|
2877
|
-
program.name("dig").description("CLI \u0631\u0633\u0645\u06CC \u062F\u06CC\u0632\u0627\u06CC\u0646 \u0633\u06CC\u0633\u062A\u0645 \u062F\u06CC\u06AF").version(
|
|
2878
|
-
program.command("init").description(
|
|
2879
|
-
|
|
3203
|
+
program.name("dig").description("CLI \u0631\u0633\u0645\u06CC \u062F\u06CC\u0632\u0627\u06CC\u0646 \u0633\u06CC\u0633\u062A\u0645 \u062F\u06CC\u06AF").version(CLI_VERSION);
|
|
3204
|
+
program.command("init").description(
|
|
3205
|
+
'\u0631\u0627\u0647\u200C\u0627\u0646\u062F\u0627\u0632\u06CC \u062F\u06CC\u06AF \u062F\u0631 \u067E\u0631\u0648\u0698\u0647: dig.json\u060C \u062A\u0645 \u0648 \u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u060C \u0648 dir="rtl"'
|
|
3206
|
+
).option("--yes", "\u067E\u0627\u0633\u062E \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0628\u0647 \u0647\u0645\u0647\u0654 \u0633\u0648\u0627\u0644\u0627\u062A", false).action(initCommand);
|
|
3207
|
+
program.command("add").description("\u0627\u0641\u0632\u0648\u062F\u0646 \u06CC\u06A9 \u06CC\u0627 \u0686\u0646\u062F \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0627\u0632 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u062F\u06CC\u06AF").argument("[components...]", "\u0646\u0627\u0645 \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A\u200C\u0647\u0627 (\u0645\u062B\u0644 button) \u06CC\u0627 \u0622\u062F\u0631\u0633 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC\u061B \u0628\u062F\u0648\u0646 \u0622\u0631\u06AF\u0648\u0645\u0627\u0646 \u0641\u0647\u0631\u0633\u062A \u0631\u0627 \u0646\u0634\u0627\u0646 \u0645\u06CC\u200C\u062F\u0647\u062F").option("--overwrite", "\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0645\u0648\u062C\u0648\u062F", false).option("-y, --yes", "\u0628\u062F\u0648\u0646 \u067E\u0631\u0633\u0634\u060C \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0645\u0648\u062C\u0648\u062F \u0631\u0627 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u06A9\u0646", false).option("--dry-run", "\u0641\u0642\u0637 \u0646\u0634\u0627\u0646 \u0628\u062F\u0647 \u0686\u0647 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC\u06CC \u0646\u0648\u0634\u062A\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F\u060C \u0686\u06CC\u0632\u06CC \u0646\u0646\u0648\u06CC\u0633", false).option("--no-install", "\u0641\u0642\u0637 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627 \u0631\u0627 \u0628\u0646\u0648\u06CC\u0633\u060C \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627 \u0631\u0627 \u0646\u0635\u0628 \u0646\u06A9\u0646").action(addCommand);
|
|
3208
|
+
program.command("list").description("\u0641\u0647\u0631\u0633\u062A \u0622\u06CC\u062A\u0645\u200C\u0647\u0627\u06CC \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u062F\u06CC\u06AF").option("--type <type>", "\u0641\u06CC\u0644\u062A\u0631 \u0646\u0648\u0639: ui\u060C lib \u06CC\u0627 theme").option("--json", "\u062E\u0631\u0648\u062C\u06CC JSON \u0628\u0631\u0627\u06CC \u0627\u0633\u06A9\u0631\u06CC\u067E\u062A/\u0627\u0628\u0632\u0627\u0631", false).action(listCommand);
|
|
3209
|
+
program.command("search").description("\u062C\u0633\u062A\u062C\u0648\u06CC \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u062F\u0631 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC\u060C \u0628\u0627 \u0646\u0627\u0645 \u0641\u0627\u0631\u0633\u06CC \u06CC\u0627 \u0627\u0646\u06AF\u0644\u06CC\u0633\u06CC").argument("<query>", "\u0639\u0628\u0627\u0631\u062A \u062C\u0633\u062A\u062C\u0648").option("--json", "\u062E\u0631\u0648\u062C\u06CC JSON \u0628\u0631\u0627\u06CC \u0627\u0633\u06A9\u0631\u06CC\u067E\u062A/\u0627\u0628\u0632\u0627\u0631", false).action(searchCommand);
|
|
2880
3210
|
program.command("diff").description(
|
|
2881
3211
|
"\u0645\u0642\u0627\u06CC\u0633\u0647\u0654 \u0641\u0642\u0637\u200C\u062E\u0648\u0627\u0646\u062F\u0646\u06CC\u0650 \u0646\u0633\u062E\u0647\u0654 \u0646\u0635\u0628\u200C\u0634\u062F\u0647 \u0628\u0627 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u0648 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0645\u062D\u0644\u06CC (\u0628\u062F\u0648\u0646 \u062A\u063A\u06CC\u06CC\u0631 \u0641\u0627\u06CC\u0644)"
|
|
2882
3212
|
).argument("<components...>", "\u0646\u0627\u0645 \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A\u200C\u0647\u0627 (\u0645\u062B\u0644 button)").option("--json", "\u062E\u0631\u0648\u062C\u06CC JSON \u0628\u0631\u0627\u06CC \u0627\u0633\u06A9\u0631\u06CC\u067E\u062A/\u0627\u0628\u0632\u0627\u0631", false).option(
|