digdesign 0.2.0 → 0.4.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 +839 -72
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -20,6 +20,8 @@ function defaultConfig() {
|
|
|
20
20
|
tsx: true,
|
|
21
21
|
tailwind: {
|
|
22
22
|
css: "src/app/globals.css",
|
|
23
|
+
theme: "src/app/dig-theme.css",
|
|
24
|
+
brand: "src/app/brand.css",
|
|
23
25
|
baseColor: "neutral",
|
|
24
26
|
cssVariables: true
|
|
25
27
|
},
|
|
@@ -53,6 +55,60 @@ async function writeConfig(config, cwd = process.cwd()) {
|
|
|
53
55
|
);
|
|
54
56
|
}
|
|
55
57
|
|
|
58
|
+
// src/lib/errors.ts
|
|
59
|
+
var DigError = class extends Error {
|
|
60
|
+
constructor(message, options) {
|
|
61
|
+
super(message, options);
|
|
62
|
+
this.name = "DigError";
|
|
63
|
+
}
|
|
64
|
+
};
|
|
65
|
+
|
|
66
|
+
// src/lib/prompt.ts
|
|
67
|
+
import * as readline from "readline/promises";
|
|
68
|
+
import { stdin, stdout } from "process";
|
|
69
|
+
async function askLine(question) {
|
|
70
|
+
const rl = readline.createInterface({ input: stdin, output: stdout });
|
|
71
|
+
try {
|
|
72
|
+
return await rl.question(question);
|
|
73
|
+
} catch {
|
|
74
|
+
console.log();
|
|
75
|
+
return "";
|
|
76
|
+
} finally {
|
|
77
|
+
rl.close();
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
async function confirm(question, defaultValue) {
|
|
81
|
+
const suffix = defaultValue ? "(Y/n)" : "(y/N)";
|
|
82
|
+
const raw = await askLine(`${question} ${suffix} `);
|
|
83
|
+
const answer = raw.trim().toLowerCase();
|
|
84
|
+
if (!answer) return defaultValue;
|
|
85
|
+
return answer === "y" || answer === "yes";
|
|
86
|
+
}
|
|
87
|
+
async function ask(question, defaultValue) {
|
|
88
|
+
const raw = await askLine(`${question} (${defaultValue}) `);
|
|
89
|
+
return raw.trim() || defaultValue;
|
|
90
|
+
}
|
|
91
|
+
async function multiSelect(question, options) {
|
|
92
|
+
if (options.length === 0) return [];
|
|
93
|
+
const width = String(options.length).length;
|
|
94
|
+
for (const [index, option] of options.entries()) {
|
|
95
|
+
const number = String(index + 1).padStart(width);
|
|
96
|
+
console.log(` ${number}) ${option.label}`);
|
|
97
|
+
}
|
|
98
|
+
const raw = await askLine(`${question} `);
|
|
99
|
+
return parseSelection(raw, options);
|
|
100
|
+
}
|
|
101
|
+
function parseSelection(raw, options) {
|
|
102
|
+
const picked = /* @__PURE__ */ new Set();
|
|
103
|
+
for (const token of raw.split(/[\s,،]+/).filter(Boolean)) {
|
|
104
|
+
const index = Number(token) - 1;
|
|
105
|
+
if (Number.isInteger(index) && index >= 0 && index < options.length) {
|
|
106
|
+
picked.add(options[index].value);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return [...picked];
|
|
110
|
+
}
|
|
111
|
+
|
|
56
112
|
// src/lib/hash.ts
|
|
57
113
|
import { createHash } from "crypto";
|
|
58
114
|
function hashContent(content) {
|
|
@@ -125,31 +181,62 @@ function installArgs(pm, deps, dev) {
|
|
|
125
181
|
const devFlag = dev ? pm === "npm" ? "--save-dev" : "-D" : null;
|
|
126
182
|
return devFlag ? [verb, devFlag, ...deps] : [verb, ...deps];
|
|
127
183
|
}
|
|
184
|
+
var PEER_CONFLICT_FLAG = {
|
|
185
|
+
npm: "--legacy-peer-deps",
|
|
186
|
+
pnpm: "--strict-peer-dependencies=false"
|
|
187
|
+
};
|
|
188
|
+
function installFailure(pm, args, code, stderr) {
|
|
189
|
+
const command = `${pm} ${args.join(" ")}`;
|
|
190
|
+
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 ?? "?"}).`];
|
|
191
|
+
if (/ERESOLVE|peer dep|ERR_PNPM_PEER_DEP_ISSUES/i.test(stderr)) {
|
|
192
|
+
const flag = PEER_CONFLICT_FLAG[pm];
|
|
193
|
+
lines.push(
|
|
194
|
+
" \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."
|
|
195
|
+
);
|
|
196
|
+
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.");
|
|
197
|
+
lines.push(
|
|
198
|
+
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}`
|
|
199
|
+
);
|
|
200
|
+
} else {
|
|
201
|
+
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.");
|
|
202
|
+
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}`);
|
|
203
|
+
}
|
|
204
|
+
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");
|
|
205
|
+
return new DigError(lines.join("\n"));
|
|
206
|
+
}
|
|
128
207
|
function installDependencies(pm, deps, options = {}) {
|
|
129
208
|
if (!deps.length) return Promise.resolve();
|
|
130
209
|
const args = installArgs(pm, deps, Boolean(options.dev));
|
|
131
210
|
return new Promise((resolve, reject) => {
|
|
132
211
|
const child = spawn(pm, args, {
|
|
133
212
|
cwd: options.cwd ?? process.cwd(),
|
|
134
|
-
|
|
213
|
+
// stderr پایپ میشود تا هم مثل قبل بیکموکاست به کاربر برسد، هم بتوانیم
|
|
214
|
+
// علتِ شکست را از رویش تشخیص بدهیم. stdout همچنان inherit است چون
|
|
215
|
+
// نوارِ پیشرفتِ پکیجمنیجر باید زنده بماند.
|
|
216
|
+
stdio: ["inherit", "inherit", "pipe"],
|
|
135
217
|
shell: process.platform === "win32"
|
|
136
218
|
});
|
|
219
|
+
let stderr = "";
|
|
220
|
+
child.stderr?.on("data", (chunk) => {
|
|
221
|
+
const text = chunk.toString();
|
|
222
|
+
stderr += text;
|
|
223
|
+
process.stderr.write(text);
|
|
224
|
+
});
|
|
137
225
|
child.on("exit", (code) => {
|
|
138
226
|
if (code === 0) resolve();
|
|
139
|
-
else reject(
|
|
227
|
+
else reject(installFailure(pm, args, code, stderr));
|
|
228
|
+
});
|
|
229
|
+
child.on("error", (cause) => {
|
|
230
|
+
reject(
|
|
231
|
+
new DigError(
|
|
232
|
+
`\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.`,
|
|
233
|
+
{ cause }
|
|
234
|
+
)
|
|
235
|
+
);
|
|
140
236
|
});
|
|
141
|
-
child.on("error", reject);
|
|
142
237
|
});
|
|
143
238
|
}
|
|
144
239
|
|
|
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
240
|
// src/lib/registry.ts
|
|
154
241
|
function resolveUrl(nameOrUrl, registryUrl) {
|
|
155
242
|
if (/^https?:\/\//.test(nameOrUrl)) return nameOrUrl;
|
|
@@ -188,15 +275,23 @@ async function fetchFromRegistry(url, subject) {
|
|
|
188
275
|
}
|
|
189
276
|
throw new DigError(`\u062F\u0631\u06CC\u0627\u0641\u062A ${subject} \u0646\u0627\u0645\u0648\u0641\u0642 \u0628\u0648\u062F (${response.status}): ${url}`);
|
|
190
277
|
}
|
|
278
|
+
function normalizeType(type) {
|
|
279
|
+
return type.startsWith("registry:") ? `dig:${type.slice("registry:".length)}` : type;
|
|
280
|
+
}
|
|
191
281
|
async function fetchRegistryIndex(registryUrl) {
|
|
192
282
|
const url = `${registryUrl}/r/registry.json`;
|
|
193
283
|
const response = await fetchFromRegistry(url, "\u0641\u0647\u0631\u0633\u062A\u0650 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC");
|
|
194
|
-
|
|
284
|
+
const index = await response.json();
|
|
285
|
+
for (const item of index.items) item.type = normalizeType(item.type);
|
|
286
|
+
return index;
|
|
195
287
|
}
|
|
196
288
|
async function fetchRegistryItem(nameOrUrl, registryUrl) {
|
|
197
289
|
const url = resolveUrl(nameOrUrl, registryUrl);
|
|
198
290
|
const response = await fetchFromRegistry(url, `\xAB${nameOrUrl}\xBB`);
|
|
199
|
-
|
|
291
|
+
const item = await response.json();
|
|
292
|
+
item.type = normalizeType(item.type);
|
|
293
|
+
for (const file of item.files ?? []) file.type = normalizeType(file.type);
|
|
294
|
+
return item;
|
|
200
295
|
}
|
|
201
296
|
async function resolveRegistryTree(names, registryUrl) {
|
|
202
297
|
const resolved = /* @__PURE__ */ new Map();
|
|
@@ -284,7 +379,13 @@ import path5 from "path";
|
|
|
284
379
|
function toPosixPath(relativePath) {
|
|
285
380
|
return relativePath.split(path5.sep).join("/");
|
|
286
381
|
}
|
|
287
|
-
function
|
|
382
|
+
function targetPathOptions(config) {
|
|
383
|
+
return { tailwindCss: config.tailwind.css, themeCss: config.tailwind.theme };
|
|
384
|
+
}
|
|
385
|
+
function resolveTargetPath(filePath, aliases, options = {}) {
|
|
386
|
+
if (/(?:^|\/)app\/globals\.css$/.test(filePath)) {
|
|
387
|
+
return options.themeCss ?? options.tailwindCss ?? "src/app/globals.css";
|
|
388
|
+
}
|
|
288
389
|
const match = filePath.match(/(?:^|\/)(components|lib|hooks)\/(.*)$/);
|
|
289
390
|
const cleaned = match ? `${match[1]}/${match[2]}` : filePath;
|
|
290
391
|
if (cleaned.startsWith("components/ui/")) {
|
|
@@ -311,11 +412,78 @@ async function pathExists(target) {
|
|
|
311
412
|
return false;
|
|
312
413
|
}
|
|
313
414
|
}
|
|
415
|
+
async function pickComponents(registryUrl) {
|
|
416
|
+
if (!process.stdin.isTTY) {
|
|
417
|
+
throw new DigError(
|
|
418
|
+
"\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"
|
|
419
|
+
);
|
|
420
|
+
}
|
|
421
|
+
const index = await fetchRegistryIndex(registryUrl);
|
|
422
|
+
const choices = index.items.filter((item) => item.type === "dig:ui").map((item) => ({
|
|
423
|
+
value: item.name,
|
|
424
|
+
label: item.title ? `${item.name} \u2014 ${item.title}` : item.name
|
|
425
|
+
}));
|
|
426
|
+
console.log(`
|
|
427
|
+
${choices.length} \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u062F\u0631 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC:
|
|
428
|
+
`);
|
|
429
|
+
const picked = await multiSelect(
|
|
430
|
+
"\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):",
|
|
431
|
+
choices
|
|
432
|
+
);
|
|
433
|
+
if (picked.length === 0) {
|
|
434
|
+
console.log("\u0686\u06CC\u0632\u06CC \u0627\u0646\u062A\u062E\u0627\u0628 \u0646\u0634\u062F.");
|
|
435
|
+
return [];
|
|
436
|
+
}
|
|
437
|
+
return picked;
|
|
438
|
+
}
|
|
314
439
|
async function addCommand(components, options) {
|
|
315
440
|
const cwd = process.cwd();
|
|
316
441
|
const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
|
|
442
|
+
const names = components.length ? components : await pickComponents(config.registryUrl);
|
|
443
|
+
if (names.length === 0) return;
|
|
317
444
|
console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A \u0627\u0632 ${config.registryUrl} \u2026`);
|
|
318
|
-
const items = await resolveRegistryTree(
|
|
445
|
+
const items = await resolveRegistryTree(names, config.registryUrl);
|
|
446
|
+
let overwrite = Boolean(options.overwrite);
|
|
447
|
+
if (!overwrite) {
|
|
448
|
+
const existing = [];
|
|
449
|
+
for (const item of items.values()) {
|
|
450
|
+
for (const file of item.files) {
|
|
451
|
+
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
|
|
452
|
+
if (await pathExists(target)) existing.push(path6.relative(cwd, target));
|
|
453
|
+
}
|
|
454
|
+
}
|
|
455
|
+
if (existing.length) {
|
|
456
|
+
if (options.yes) {
|
|
457
|
+
overwrite = true;
|
|
458
|
+
} else if (process.stdin.isTTY) {
|
|
459
|
+
console.log(`
|
|
460
|
+
${existing.length} \u0641\u0627\u06CC\u0644 \u0627\u0632 \u0642\u0628\u0644 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F:`);
|
|
461
|
+
for (const file of existing.slice(0, 10)) console.log(` ${file}`);
|
|
462
|
+
if (existing.length > 10) console.log(` \u2026 \u0648 ${existing.length - 10} \u0641\u0627\u06CC\u0644 \u062F\u06CC\u06AF\u0631`);
|
|
463
|
+
overwrite = await confirm("\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0634\u0648\u0646\u062F\u061F", false);
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
if (options.dryRun) {
|
|
468
|
+
const npmDeps = /* @__PURE__ */ new Set();
|
|
469
|
+
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");
|
|
470
|
+
for (const item of items.values()) {
|
|
471
|
+
for (const dep of item.dependencies ?? []) npmDeps.add(dep);
|
|
472
|
+
for (const file of item.files) {
|
|
473
|
+
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
|
|
474
|
+
const exists2 = await pathExists(target);
|
|
475
|
+
const mark = exists2 ? overwrite ? "~" : "-" : "+";
|
|
476
|
+
const note = exists2 ? 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)" : "";
|
|
477
|
+
console.log(`${mark} ${path6.relative(cwd, target)}${note}`);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
console.log(`
|
|
481
|
+
${items.size} \u0622\u06CC\u062A\u0645 \u0627\u0632 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC.`);
|
|
482
|
+
if (npmDeps.size) {
|
|
483
|
+
console.log(`\u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627\u06CC npm: ${[...npmDeps].join(" ")}`);
|
|
484
|
+
}
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
319
487
|
const dependencies = /* @__PURE__ */ new Set();
|
|
320
488
|
const devDependencies = /* @__PURE__ */ new Set();
|
|
321
489
|
let written = 0;
|
|
@@ -329,8 +497,8 @@ async function addCommand(components, options) {
|
|
|
329
497
|
const writtenFiles = {};
|
|
330
498
|
const writtenContents = {};
|
|
331
499
|
for (const file of item.files) {
|
|
332
|
-
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases));
|
|
333
|
-
if (!
|
|
500
|
+
const target = path6.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
|
|
501
|
+
if (!overwrite && await pathExists(target)) {
|
|
334
502
|
console.log(`- \u0631\u062F \u0634\u062F (\u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F): ${path6.relative(cwd, target)}`);
|
|
335
503
|
skipped++;
|
|
336
504
|
continue;
|
|
@@ -384,6 +552,107 @@ ${written} \u0641\u0627\u06CC\u0644 \u0646\u0648\u0634\u062A\u0647 \u0634\u062F\
|
|
|
384
552
|
}
|
|
385
553
|
}
|
|
386
554
|
|
|
555
|
+
// src/lib/search.ts
|
|
556
|
+
var ARABIC_TO_PERSIAN = {
|
|
557
|
+
"\u064A": "\u06CC",
|
|
558
|
+
// ي → ی
|
|
559
|
+
"\u0649": "\u06CC",
|
|
560
|
+
// ى → ی
|
|
561
|
+
"\u0643": "\u06A9",
|
|
562
|
+
// ك → ک
|
|
563
|
+
"\u0629": "\u0647",
|
|
564
|
+
// ة → ه
|
|
565
|
+
"\u0623": "\u0627",
|
|
566
|
+
// أ → ا
|
|
567
|
+
"\u0625": "\u0627",
|
|
568
|
+
// إ → ا
|
|
569
|
+
"\u0622": "\u0627",
|
|
570
|
+
// آ → ا
|
|
571
|
+
"\u0624": "\u0648"
|
|
572
|
+
// ؤ → و
|
|
573
|
+
};
|
|
574
|
+
var DIACRITICS = /[ً-ْٰ]/g;
|
|
575
|
+
var INVISIBLE = /[-]/g;
|
|
576
|
+
function toSearchKey(value) {
|
|
577
|
+
return value.replace(/[يىكةأإآؤ]/g, (ch) => ARABIC_TO_PERSIAN[ch]).replace(DIACRITICS, "").replace(INVISIBLE, "").toLowerCase().replace(/[\s]+/g, "");
|
|
578
|
+
}
|
|
579
|
+
function scoreItem(item, query) {
|
|
580
|
+
const q = toSearchKey(query);
|
|
581
|
+
if (!q) return 0;
|
|
582
|
+
const name = toSearchKey(item.name);
|
|
583
|
+
const title = toSearchKey(item.title ?? "");
|
|
584
|
+
const description = toSearchKey(item.description ?? "");
|
|
585
|
+
if (name === q || title === q) return 100;
|
|
586
|
+
if (name.startsWith(q) || title.startsWith(q)) return 80;
|
|
587
|
+
if (name.includes(q) || title.includes(q)) return 60;
|
|
588
|
+
if (description.includes(q)) return 30;
|
|
589
|
+
return 0;
|
|
590
|
+
}
|
|
591
|
+
function searchItems(items, query) {
|
|
592
|
+
return items.map((item) => ({ item, score: scoreItem(item, query) })).filter((entry) => entry.score > 0).sort(
|
|
593
|
+
(a, b) => b.score - a.score || a.item.name.localeCompare(b.item.name)
|
|
594
|
+
).map((entry) => entry.item);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
// src/commands/list.ts
|
|
598
|
+
var TYPE_LABEL = {
|
|
599
|
+
"dig:ui": "\u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A",
|
|
600
|
+
"dig:lib": "\u0627\u0628\u0632\u0627\u0631",
|
|
601
|
+
"dig:theme": "\u062A\u0645"
|
|
602
|
+
};
|
|
603
|
+
async function loadItems(cwd) {
|
|
604
|
+
const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
|
|
605
|
+
const index = await fetchRegistryIndex(config.registryUrl);
|
|
606
|
+
return index.items;
|
|
607
|
+
}
|
|
608
|
+
function matchesType(item, type) {
|
|
609
|
+
if (!type) return true;
|
|
610
|
+
const wanted = type.startsWith("dig:") ? type : `dig:${type}`;
|
|
611
|
+
return item.type === wanted;
|
|
612
|
+
}
|
|
613
|
+
function printTable(items) {
|
|
614
|
+
if (items.length === 0) {
|
|
615
|
+
console.log("\u0686\u06CC\u0632\u06CC \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F.");
|
|
616
|
+
return;
|
|
617
|
+
}
|
|
618
|
+
const width = Math.max(...items.map((item) => item.name.length));
|
|
619
|
+
const labelWidth = Math.max(
|
|
620
|
+
...items.map((item) => (TYPE_LABEL[item.type] ?? item.type).length)
|
|
621
|
+
);
|
|
622
|
+
for (const item of items) {
|
|
623
|
+
const label = (TYPE_LABEL[item.type] ?? item.type).padEnd(labelWidth);
|
|
624
|
+
const title = item.title ? ` \xB7 ${item.title}` : "";
|
|
625
|
+
console.log(`${item.name.padEnd(width)} ${label}${title}`);
|
|
626
|
+
}
|
|
627
|
+
console.log(`
|
|
628
|
+
${items.length} \u0622\u06CC\u062A\u0645. \u0628\u0631\u0627\u06CC \u0646\u0635\u0628: dig add <\u0646\u0627\u0645>`);
|
|
629
|
+
}
|
|
630
|
+
async function listCommand(options) {
|
|
631
|
+
const items = (await loadItems(process.cwd())).filter(
|
|
632
|
+
(item) => matchesType(item, options.type)
|
|
633
|
+
);
|
|
634
|
+
if (options.json) {
|
|
635
|
+
console.log(JSON.stringify(items, null, 2));
|
|
636
|
+
return;
|
|
637
|
+
}
|
|
638
|
+
printTable(items);
|
|
639
|
+
}
|
|
640
|
+
async function searchCommand(query, options) {
|
|
641
|
+
const items = searchItems(await loadItems(process.cwd()), query);
|
|
642
|
+
if (options.json) {
|
|
643
|
+
console.log(JSON.stringify(items, null, 2));
|
|
644
|
+
return;
|
|
645
|
+
}
|
|
646
|
+
if (items.length === 0) {
|
|
647
|
+
console.log(
|
|
648
|
+
`\u0686\u06CC\u0632\u06CC \u0628\u0631\u0627\u06CC \xAB${query}\xBB \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F.
|
|
649
|
+
\u0641\u0647\u0631\u0633\u062A \u06A9\u0627\u0645\u0644: dig list`
|
|
650
|
+
);
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
printTable(items);
|
|
654
|
+
}
|
|
655
|
+
|
|
387
656
|
// src/lib/diff.ts
|
|
388
657
|
import { readFile as readFile4 } from "fs/promises";
|
|
389
658
|
import path7 from "path";
|
|
@@ -423,8 +692,8 @@ async function readLocalHash(target) {
|
|
|
423
692
|
throw error;
|
|
424
693
|
}
|
|
425
694
|
}
|
|
426
|
-
async function computeFileDrift(cwd, aliases, lockEntry, file) {
|
|
427
|
-
const target = path7.join(cwd, resolveTargetPath(file.path, aliases));
|
|
695
|
+
async function computeFileDrift(cwd, aliases, lockEntry, file, paths) {
|
|
696
|
+
const target = path7.join(cwd, resolveTargetPath(file.path, aliases, paths));
|
|
428
697
|
const relPath = toPosixPath(path7.relative(cwd, target));
|
|
429
698
|
const registryHash = file.hash ?? hashContent(file.content);
|
|
430
699
|
const installedHash = lockEntry?.files[relPath];
|
|
@@ -438,9 +707,9 @@ async function computeFileDrift(cwd, aliases, lockEntry, file) {
|
|
|
438
707
|
};
|
|
439
708
|
}
|
|
440
709
|
async function computeComponentDrift(params) {
|
|
441
|
-
const { cwd, aliases, registryUrl, lockEntry, registryItem } = params;
|
|
710
|
+
const { cwd, aliases, registryUrl, lockEntry, registryItem, paths } = params;
|
|
442
711
|
const files = await Promise.all(
|
|
443
|
-
registryItem.files.map((file) => computeFileDrift(cwd, aliases, lockEntry, file))
|
|
712
|
+
registryItem.files.map((file) => computeFileDrift(cwd, aliases, lockEntry, file, paths))
|
|
444
713
|
);
|
|
445
714
|
return {
|
|
446
715
|
name: registryItem.name,
|
|
@@ -588,7 +857,7 @@ function describeThreeWayConflict(baseContent, localContent, registryContent) {
|
|
|
588
857
|
return `\u0646\u0633\u0628\u062A \u0628\u0647 \u0646\u0633\u062E\u0647\u0654 \u0646\u0635\u0628\u200C\u0634\u062F\u0647 (\u067E\u0627\u06CC\u0647): \u0634\u0645\u0627 ${local.added + local.removed} \u062E\u0637 \u062A\u063A\u06CC\u06CC\u0631 \u062F\u0627\u062F\u0647\u200C\u0627\u06CC\u062F (+${local.added}/-${local.removed})\u060C \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC ${registry.added + registry.removed} \u062E\u0637 \u062A\u063A\u06CC\u06CC\u0631 \u062F\u0627\u062F\u0647 (+${registry.added}/-${registry.removed}). \u062F\u06CC\u06AF \u062E\u0648\u062F\u06A9\u0627\u0631 \u0627\u062F\u063A\u0627\u0645 \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F \u2014 \u062F\u0648 \u062F\u06CC\u0641\u0650 \u0628\u0627\u0644\u0627 \u0631\u0627 \u062F\u0633\u062A\u06CC \u0628\u0631\u0631\u0633\u06CC \u06A9\u0646\u06CC\u062F.`;
|
|
589
858
|
}
|
|
590
859
|
async function computeFileDiffDetails(params) {
|
|
591
|
-
const { cwd, aliases, name, snapshotVersion, file, registryFile } = params;
|
|
860
|
+
const { cwd, aliases, name, snapshotVersion, file, registryFile, paths } = params;
|
|
592
861
|
if (file.status === "up_to_date") return void 0;
|
|
593
862
|
if (file.status === "new_upstream") {
|
|
594
863
|
return {
|
|
@@ -604,7 +873,7 @@ async function computeFileDiffDetails(params) {
|
|
|
604
873
|
note: file.registryHash === file.installedHash ? "\u0641\u0627\u06CC\u0644 \u0628\u0647\u200C\u0635\u0648\u0631\u062A \u0645\u062D\u0644\u06CC \u062D\u0630\u0641 \u0634\u062F\u0647\u061B \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u0627\u0632 \u0632\u0645\u0627\u0646 \u0646\u0635\u0628 \u062A\u063A\u06CC\u06CC\u0631\u06CC \u0646\u06A9\u0631\u062F\u0647." : "\u0641\u0627\u06CC\u0644 \u0628\u0647\u200C\u0635\u0648\u0631\u062A \u0645\u062D\u0644\u06CC \u062D\u0630\u0641 \u0634\u062F\u0647 \u0648 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC \u0647\u0645 \u062A\u063A\u06CC\u06CC\u0631 \u06A9\u0631\u062F\u0647 \u2014 \u0645\u0642\u0627\u06CC\u0633\u0647\u200C\u0627\u06CC \u0628\u0627 \u0641\u0627\u06CC\u0644 \u062D\u0630\u0641\u200C\u0634\u062F\u0647 \u0645\u0645\u06A9\u0646 \u0646\u06CC\u0633\u062A."
|
|
605
874
|
};
|
|
606
875
|
}
|
|
607
|
-
const target = path8.join(cwd, resolveTargetPath(registryFile.path, aliases));
|
|
876
|
+
const target = path8.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
|
|
608
877
|
const localContent = await readTextFileSafely(target);
|
|
609
878
|
if (localContent === "binary") {
|
|
610
879
|
return {
|
|
@@ -699,6 +968,7 @@ async function diffCommand(components, options) {
|
|
|
699
968
|
const drift = await computeComponentDrift({
|
|
700
969
|
cwd,
|
|
701
970
|
aliases: config.aliases,
|
|
971
|
+
paths: targetPathOptions(config),
|
|
702
972
|
registryUrl: config.registryUrl,
|
|
703
973
|
lockEntry,
|
|
704
974
|
registryItem
|
|
@@ -710,6 +980,7 @@ async function diffCommand(components, options) {
|
|
|
710
980
|
(file, index) => file.status === "up_to_date" ? Promise.resolve(void 0) : computeFileDiffDetails({
|
|
711
981
|
cwd,
|
|
712
982
|
aliases: config.aliases,
|
|
983
|
+
paths: targetPathOptions(config),
|
|
713
984
|
name,
|
|
714
985
|
snapshotVersion: lockEntry?.snapshot?.version,
|
|
715
986
|
file,
|
|
@@ -1393,7 +1664,7 @@ async function generateIntelligenceExport(params) {
|
|
|
1393
1664
|
} catch {
|
|
1394
1665
|
continue;
|
|
1395
1666
|
}
|
|
1396
|
-
if (item.type !== "
|
|
1667
|
+
if (item.type !== "dig:ui") continue;
|
|
1397
1668
|
const scan = await scanRepositoryForComponent({ projectRoot: cwd, component: name });
|
|
1398
1669
|
installedComponents.push({
|
|
1399
1670
|
name,
|
|
@@ -1612,7 +1883,7 @@ async function healthCommand(options) {
|
|
|
1612
1883
|
} catch {
|
|
1613
1884
|
continue;
|
|
1614
1885
|
}
|
|
1615
|
-
if (item.type !== "
|
|
1886
|
+
if (item.type !== "dig:ui") continue;
|
|
1616
1887
|
const scan = await scanRepositoryForComponent({ projectRoot: cwd, component: name });
|
|
1617
1888
|
installedComponents.push({
|
|
1618
1889
|
name,
|
|
@@ -1686,28 +1957,497 @@ async function impactCommand(name, options) {
|
|
|
1686
1957
|
}
|
|
1687
1958
|
|
|
1688
1959
|
// src/commands/init.ts
|
|
1960
|
+
import { readFile as readFile8, writeFile as writeFile6 } from "fs/promises";
|
|
1961
|
+
import path12 from "path";
|
|
1962
|
+
|
|
1963
|
+
// src/commands/theme.ts
|
|
1964
|
+
import { access as access5, mkdir as mkdir4, readFile as readFile7, writeFile as writeFile5 } from "fs/promises";
|
|
1965
|
+
import path11 from "path";
|
|
1966
|
+
|
|
1967
|
+
// src/lib/brand-ramp.ts
|
|
1968
|
+
var RAMP_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
|
1969
|
+
var REFERENCE_L = {
|
|
1970
|
+
50: 96.6,
|
|
1971
|
+
100: 93.1,
|
|
1972
|
+
200: 87.6,
|
|
1973
|
+
300: 79.7,
|
|
1974
|
+
400: 69,
|
|
1975
|
+
500: 60.4,
|
|
1976
|
+
600: 52.9,
|
|
1977
|
+
700: 47.3,
|
|
1978
|
+
800: 41.1,
|
|
1979
|
+
900: 36.9,
|
|
1980
|
+
950: 26.9
|
|
1981
|
+
};
|
|
1982
|
+
var CHROMA_SHAPE = {
|
|
1983
|
+
50: 0.07,
|
|
1984
|
+
100: 0.13,
|
|
1985
|
+
200: 0.25,
|
|
1986
|
+
300: 0.44,
|
|
1987
|
+
400: 0.69,
|
|
1988
|
+
500: 0.89,
|
|
1989
|
+
600: 1,
|
|
1990
|
+
700: 0.92,
|
|
1991
|
+
800: 0.74,
|
|
1992
|
+
900: 0.55,
|
|
1993
|
+
950: 0.34
|
|
1994
|
+
};
|
|
1995
|
+
function parseHex(hex) {
|
|
1996
|
+
const clean = hex.trim().replace(/^#/, "");
|
|
1997
|
+
const full = clean.length === 3 ? [...clean].map((ch) => ch + ch).join("") : clean;
|
|
1998
|
+
if (!/^[0-9a-fA-F]{6}$/.test(full)) {
|
|
1999
|
+
throw new DigError(`\xAB${hex}\xBB \u0631\u0646\u06AF\u0650 \u0647\u06AF\u0632\u0650 \u0645\u0639\u062A\u0628\u0631 \u0646\u06CC\u0633\u062A\u061B \u0645\u062B\u0644\u0627\u064B #2C4C5B \u0628\u062F\u0647\u06CC\u062F.`);
|
|
2000
|
+
}
|
|
2001
|
+
return [0, 2, 4].map((i) => parseInt(full.slice(i, i + 2), 16) / 255);
|
|
2002
|
+
}
|
|
2003
|
+
var toLinear = (v) => v <= 0.04045 ? v / 12.92 : ((v + 0.055) / 1.055) ** 2.4;
|
|
2004
|
+
var fromLinear = (v) => v <= 31308e-7 ? 12.92 * v : 1.055 * v ** (1 / 2.4) - 0.055;
|
|
2005
|
+
function hexToOklch(hex) {
|
|
2006
|
+
const [r, g, b] = parseHex(hex).map(toLinear);
|
|
2007
|
+
const l = Math.cbrt(0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b);
|
|
2008
|
+
const m = Math.cbrt(0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b);
|
|
2009
|
+
const s = Math.cbrt(0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b);
|
|
2010
|
+
const L = 0.2104542553 * l + 0.793617785 * m - 0.0040720468 * s;
|
|
2011
|
+
const A = 1.9779984951 * l - 2.428592205 * m + 0.4505937099 * s;
|
|
2012
|
+
const B = 0.0259040371 * l + 0.7827717662 * m - 0.808675766 * s;
|
|
2013
|
+
const c = Math.sqrt(A * A + B * B);
|
|
2014
|
+
const h = (Math.atan2(B, A) * 180 / Math.PI + 360) % 360;
|
|
2015
|
+
return { l: L * 100, c, h };
|
|
2016
|
+
}
|
|
2017
|
+
function oklchToSrgb({ l, c, h }) {
|
|
2018
|
+
const L = l / 100;
|
|
2019
|
+
const rad = h * Math.PI / 180;
|
|
2020
|
+
const A = c * Math.cos(rad);
|
|
2021
|
+
const B = c * Math.sin(rad);
|
|
2022
|
+
const l_ = (L + 0.3963377774 * A + 0.2158037573 * B) ** 3;
|
|
2023
|
+
const m_ = (L - 0.1055613458 * A - 0.0638541728 * B) ** 3;
|
|
2024
|
+
const s_ = (L - 0.0894841775 * A - 1.291485548 * B) ** 3;
|
|
2025
|
+
return [
|
|
2026
|
+
fromLinear(4.0767416621 * l_ - 3.3077115913 * m_ + 0.2309699292 * s_),
|
|
2027
|
+
fromLinear(-1.2684380046 * l_ + 2.6097574011 * m_ - 0.3413193965 * s_),
|
|
2028
|
+
fromLinear(-0.0041960863 * l_ - 0.7034186147 * m_ + 1.707614701 * s_)
|
|
2029
|
+
];
|
|
2030
|
+
}
|
|
2031
|
+
var inGamut = (rgb) => rgb.every((v) => v >= -5e-4 && v <= 1.0005);
|
|
2032
|
+
function fitGamut(color) {
|
|
2033
|
+
let { c } = color;
|
|
2034
|
+
while (c > 0 && !inGamut(oklchToSrgb({ ...color, c }))) c -= 2e-3;
|
|
2035
|
+
return { ...color, c: Math.max(0, c) };
|
|
2036
|
+
}
|
|
2037
|
+
function relativeLuminance(rgb) {
|
|
2038
|
+
const [r, g, b] = rgb.map((v) => toLinear(Math.min(1, Math.max(0, v))));
|
|
2039
|
+
return 0.2126 * r + 0.7152 * g + 0.0722 * b;
|
|
2040
|
+
}
|
|
2041
|
+
function contrastWithWhite(color) {
|
|
2042
|
+
return 1.05 / (relativeLuminance(oklchToSrgb(color)) + 0.05);
|
|
2043
|
+
}
|
|
2044
|
+
function formatOklch({ l, c, h }) {
|
|
2045
|
+
return `oklch(${l.toFixed(1)}% ${c.toFixed(3)} ${h.toFixed(1)})`;
|
|
2046
|
+
}
|
|
2047
|
+
function buildBrandRamp(hex) {
|
|
2048
|
+
const base = hexToOklch(hex);
|
|
2049
|
+
const top = 97.5;
|
|
2050
|
+
const bottom = Math.min(26, Math.max(8, base.l * 0.55));
|
|
2051
|
+
const ref600 = REFERENCE_L[600];
|
|
2052
|
+
const steps = {};
|
|
2053
|
+
for (const step of RAMP_STEPS) {
|
|
2054
|
+
if (step === 600) {
|
|
2055
|
+
steps[step] = base;
|
|
2056
|
+
continue;
|
|
2057
|
+
}
|
|
2058
|
+
const ref = REFERENCE_L[step];
|
|
2059
|
+
const l = ref > ref600 ? base.l + (ref - ref600) / (REFERENCE_L[50] - ref600) * (top - base.l) : base.l - (ref600 - ref) / (ref600 - REFERENCE_L[950]) * (base.l - bottom);
|
|
2060
|
+
steps[step] = fitGamut({ l, c: base.c * CHROMA_SHAPE[step], h: base.h });
|
|
2061
|
+
}
|
|
2062
|
+
return { steps, primaryContrast: contrastWithWhite(base) };
|
|
2063
|
+
}
|
|
2064
|
+
|
|
2065
|
+
// src/lib/theme-files.ts
|
|
1689
2066
|
import path10 from "path";
|
|
2067
|
+
function importPath(fromFile, toFile) {
|
|
2068
|
+
const rel = toPosixPath(path10.relative(path10.dirname(fromFile), toFile));
|
|
2069
|
+
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
2070
|
+
}
|
|
2071
|
+
function globalsCss(paths, extraStatements = []) {
|
|
2072
|
+
const lines = [
|
|
2073
|
+
"/* \u0641\u0642\u0637 import. \u062A\u0645 \u062F\u0631 dig-theme.css (\u0645\u0627\u0644\u0650 \u062F\u06CC\u06AF) \u0648 \u0628\u0631\u0646\u062F \u062F\u0631 brand.css (\u0645\u0627\u0644\u0650",
|
|
2074
|
+
" \u067E\u0631\u0648\u0698\u0647) \u0627\u0633\u062A\u061B \u062A\u0631\u062A\u06CC\u0628 \u0645\u0647\u0645 \u0627\u0633\u062A: \u0628\u0631\u0646\u062F \u0628\u0639\u062F \u0627\u0632 \u062A\u0645 \u0645\u06CC\u200C\u0622\u06CC\u062F \u062A\u0627 \u0628\u0631\u0646\u062F\u0647 \u0628\u0627\u0634\u062F. */",
|
|
2075
|
+
`@import "${importPath(paths.css, paths.theme)}";`,
|
|
2076
|
+
...extraStatements,
|
|
2077
|
+
`@import "${importPath(paths.css, paths.brand)}";`,
|
|
2078
|
+
""
|
|
2079
|
+
];
|
|
2080
|
+
return lines.join("\n");
|
|
2081
|
+
}
|
|
2082
|
+
var BRAND_HEADER = `/* ==================================================================== *
|
|
2083
|
+
* \u0628\u0631\u0646\u062F\u0650 \u067E\u0631\u0648\u0698\u0647
|
|
2084
|
+
*
|
|
2085
|
+
* \u0627\u06CC\u0646 \u0641\u0627\u06CC\u0644 \u0645\u0627\u0644\u0650 \u067E\u0631\u0648\u0698\u0647 \u0627\u0633\u062A \u0648 \u062F\u06CC\u06AF \u0647\u06CC\u0686\u200C\u0648\u0642\u062A \u0622\u0646 \u0631\u0627 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F\u061B \u062A\u0645\u0650 \u062F\u06CC\u06AF \u062F\u0631
|
|
2086
|
+
* dig-theme.css \u0627\u0633\u062A \u0648 \u0628\u0627 \xABdig update theme\xBB \u0628\u0647\u200C\u0631\u0648\u0632 \u0645\u06CC\u200C\u0634\u0648\u062F.
|
|
2087
|
+
*
|
|
2088
|
+
* \u0686\u0647 \u0686\u06CC\u0632\u06CC \u0627\u06CC\u0646\u062C\u0627 \u0645\u06CC\u200C\u0622\u06CC\u062F:
|
|
2089
|
+
* \u06F1) \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F (--brand-*\u060C \u0644\u0627\u06CC\u0647\u0654 \u06F2)\u061B Shade \u06F6\u06F0\u06F0 \u0647\u0645\u0627\u0646 --primary \u0627\u0633\u062A.
|
|
2090
|
+
* \u06F2) \u0644\u0627\u06CC\u0647\u0654 \u0645\u062D\u0635\u0648\u0644: \u0641\u0642\u0637 \u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u06CC \u0645\u0639\u0646\u0627\u06CC\u06CC\u200C\u0627\u06CC \u06A9\u0647 \u0628\u0627 \u067E\u06CC\u0634\u200C\u0641\u0631\u0636\u0650 \u062F\u06CC\u06AF \u0641\u0631\u0642 \u062F\u0627\u0631\u0646\u062F
|
|
2091
|
+
* (--background\u060C --foreground\u060C --radius\u060C --font-anchor\u060C \u0633\u0627\u06CC\u0647\u200C\u0647\u0627\u060C ...).
|
|
2092
|
+
* \u06F3) \u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u06CC \u062A\u0627\u0632\u0647\u0654 \u062E\u0648\u062F\u0650 \u0645\u062D\u0635\u0648\u0644 \u062F\u0627\u062E\u0644 @theme inline.
|
|
2093
|
+
*
|
|
2094
|
+
* \u0631\u0645\u067E \u0631\u0627 \u0645\u06CC\u200C\u0634\u0648\u062F \u062F\u0648\u0628\u0627\u0631\u0647 \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF \u0633\u0627\u062E\u062A: npx digdesign theme brand "#2C4C5B"
|
|
2095
|
+
* ==================================================================== */
|
|
2096
|
+
`;
|
|
2097
|
+
function brandRampBlock(ramp, hex) {
|
|
2098
|
+
const lines = RAMP_STEPS.map((step) => ` --brand-${step}: ${formatOklch(ramp.steps[step])};`);
|
|
2099
|
+
return `/* dig:brand-ramp-start \u2014 \u0633\u0627\u062E\u062A\u0647\u200C\u0634\u062F\u0647 \u0627\u0632 ${hex.toUpperCase()}\u061B \xABdig theme brand\xBB \u0647\u0645\u06CC\u0646 \u0628\u0644\u0648\u06A9 \u0631\u0627 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0645\u06CC\u200C\u06A9\u0646\u062F */
|
|
2100
|
+
:root {
|
|
2101
|
+
${lines.join("\n")}
|
|
2102
|
+
}
|
|
2103
|
+
/* dig:brand-ramp-end */`;
|
|
2104
|
+
}
|
|
2105
|
+
function brandCss(options) {
|
|
2106
|
+
const parts = [BRAND_HEADER];
|
|
2107
|
+
if (options.ramp && options.hex) parts.push(brandRampBlock(options.ramp, options.hex));
|
|
2108
|
+
if (options.body?.trim()) parts.push(options.body.trim());
|
|
2109
|
+
if (!options.ramp && !options.body?.trim()) {
|
|
2110
|
+
parts.push(`/* \u0646\u0645\u0648\u0646\u0647:
|
|
2111
|
+
:root {
|
|
2112
|
+
--brand-600: #2c4c5b;
|
|
2113
|
+
--radius: 0.75rem;
|
|
2114
|
+
}
|
|
2115
|
+
*/`);
|
|
2116
|
+
}
|
|
2117
|
+
return `${parts.join("\n\n")}
|
|
2118
|
+
`;
|
|
2119
|
+
}
|
|
2120
|
+
function replaceBrandRamp(existing, ramp, hex) {
|
|
2121
|
+
const block = brandRampBlock(ramp, hex);
|
|
2122
|
+
const pattern = /\/\* dig:brand-ramp-start[\s\S]*?\/\* dig:brand-ramp-end \*\//;
|
|
2123
|
+
if (pattern.test(existing)) return existing.replace(pattern, block);
|
|
2124
|
+
const headerEnd = existing.indexOf("* ==================================================================== */");
|
|
2125
|
+
if (existing.startsWith("/* ====") && headerEnd !== -1) {
|
|
2126
|
+
const cut = existing.indexOf("\n", headerEnd) + 1;
|
|
2127
|
+
return `${existing.slice(0, cut)}
|
|
2128
|
+
${block}
|
|
2129
|
+
${existing.slice(cut)}`;
|
|
2130
|
+
}
|
|
2131
|
+
return `${block}
|
|
1690
2132
|
|
|
1691
|
-
|
|
1692
|
-
|
|
1693
|
-
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
const
|
|
1698
|
-
|
|
1699
|
-
const
|
|
1700
|
-
|
|
1701
|
-
|
|
2133
|
+
${existing}`;
|
|
2134
|
+
}
|
|
2135
|
+
function stripComments(css) {
|
|
2136
|
+
return css.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2137
|
+
}
|
|
2138
|
+
function parseCss(css) {
|
|
2139
|
+
const source = stripComments(css);
|
|
2140
|
+
const declarations = [];
|
|
2141
|
+
const statements = [];
|
|
2142
|
+
const stack = [];
|
|
2143
|
+
let buffer = "";
|
|
2144
|
+
let depthParen = 0;
|
|
2145
|
+
const flush = (terminator) => {
|
|
2146
|
+
const text = buffer.trim();
|
|
2147
|
+
buffer = "";
|
|
2148
|
+
if (!text) return;
|
|
2149
|
+
if (text.startsWith("@")) {
|
|
2150
|
+
statements.push({ context: [...stack], text: `${text};` });
|
|
2151
|
+
return;
|
|
2152
|
+
}
|
|
2153
|
+
const colon = text.indexOf(":");
|
|
2154
|
+
if (colon === -1) return;
|
|
2155
|
+
declarations.push({
|
|
2156
|
+
context: [...stack],
|
|
2157
|
+
property: text.slice(0, colon).trim(),
|
|
2158
|
+
value: text.slice(colon + 1).trim().replace(/\s+/g, " ")
|
|
2159
|
+
});
|
|
2160
|
+
void terminator;
|
|
2161
|
+
};
|
|
2162
|
+
for (const ch of source) {
|
|
2163
|
+
if (ch === "(") depthParen++;
|
|
2164
|
+
if (ch === ")") depthParen--;
|
|
2165
|
+
if (depthParen > 0) {
|
|
2166
|
+
buffer += ch;
|
|
2167
|
+
continue;
|
|
2168
|
+
}
|
|
2169
|
+
if (ch === "{") {
|
|
2170
|
+
stack.push(buffer.trim().replace(/\s+/g, " "));
|
|
2171
|
+
buffer = "";
|
|
2172
|
+
} else if (ch === ";") {
|
|
2173
|
+
flush(";");
|
|
2174
|
+
} else if (ch === "}") {
|
|
2175
|
+
flush("}");
|
|
2176
|
+
stack.pop();
|
|
2177
|
+
} else {
|
|
2178
|
+
buffer += ch;
|
|
2179
|
+
}
|
|
2180
|
+
}
|
|
2181
|
+
return { declarations, statements };
|
|
1702
2182
|
}
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
const
|
|
1706
|
-
|
|
1707
|
-
|
|
2183
|
+
var key = (context, name) => `${context.join(" > ")}|${name}`;
|
|
2184
|
+
function splitTheme(projectCss, digThemeCss) {
|
|
2185
|
+
const project = parseCss(projectCss);
|
|
2186
|
+
const dig = parseCss(digThemeCss);
|
|
2187
|
+
const digValues = new Map(dig.declarations.map((d) => [key(d.context, d.property), d.value]));
|
|
2188
|
+
const digStatements = new Set(dig.statements.map((s) => key(s.context, s.text)));
|
|
2189
|
+
const overrides = /* @__PURE__ */ new Map();
|
|
2190
|
+
let changed = 0;
|
|
2191
|
+
let added = 0;
|
|
2192
|
+
for (const decl of project.declarations) {
|
|
2193
|
+
const k = key(decl.context, decl.property);
|
|
2194
|
+
const digValue = digValues.get(k);
|
|
2195
|
+
if (digValue === decl.value) {
|
|
2196
|
+
overrides.delete(k);
|
|
2197
|
+
continue;
|
|
2198
|
+
}
|
|
2199
|
+
overrides.set(k, decl);
|
|
2200
|
+
}
|
|
2201
|
+
for (const [k] of overrides) {
|
|
2202
|
+
if (digValues.has(k)) changed++;
|
|
2203
|
+
else added++;
|
|
2204
|
+
}
|
|
2205
|
+
const groups = /* @__PURE__ */ new Map();
|
|
2206
|
+
for (const decl of overrides.values()) {
|
|
2207
|
+
const ctx = decl.context.join(" > ");
|
|
2208
|
+
if (!groups.has(ctx)) groups.set(ctx, []);
|
|
2209
|
+
groups.get(ctx).push(decl);
|
|
2210
|
+
}
|
|
2211
|
+
const blocks = [];
|
|
2212
|
+
for (const [, decls] of groups) {
|
|
2213
|
+
const context = decls[0].context;
|
|
2214
|
+
const indent = (level) => " ".repeat(level);
|
|
2215
|
+
const lines = [];
|
|
2216
|
+
context.forEach((selector, level) => lines.push(`${indent(level)}${selector} {`));
|
|
2217
|
+
for (const d of decls) lines.push(`${indent(context.length)}${d.property}: ${d.value};`);
|
|
2218
|
+
for (let level = context.length - 1; level >= 0; level--) lines.push(`${indent(level)}}`);
|
|
2219
|
+
blocks.push(lines.join("\n"));
|
|
2220
|
+
}
|
|
2221
|
+
const extraStatements = project.statements.filter((s) => s.context.length === 0 && !digStatements.has(key(s.context, s.text))).map((s) => s.text);
|
|
2222
|
+
return { body: blocks.join("\n\n"), extraStatements, changed, added };
|
|
2223
|
+
}
|
|
2224
|
+
|
|
2225
|
+
// src/commands/theme.ts
|
|
2226
|
+
var THEME_ITEM = "theme";
|
|
2227
|
+
async function readIfExists(target) {
|
|
2228
|
+
try {
|
|
2229
|
+
return await readFile7(target, "utf8");
|
|
2230
|
+
} catch {
|
|
2231
|
+
return null;
|
|
2232
|
+
}
|
|
2233
|
+
}
|
|
2234
|
+
async function exists(target) {
|
|
2235
|
+
try {
|
|
2236
|
+
await access5(target);
|
|
2237
|
+
return true;
|
|
2238
|
+
} catch {
|
|
2239
|
+
return false;
|
|
2240
|
+
}
|
|
2241
|
+
}
|
|
2242
|
+
function themePaths(config) {
|
|
2243
|
+
const dir = path11.posix.dirname(toPosixPath(config.tailwind.css));
|
|
2244
|
+
return {
|
|
2245
|
+
css: config.tailwind.css,
|
|
2246
|
+
theme: config.tailwind.theme ?? `${dir}/dig-theme.css`,
|
|
2247
|
+
brand: config.tailwind.brand ?? `${dir}/brand.css`
|
|
2248
|
+
};
|
|
2249
|
+
}
|
|
2250
|
+
function isBoilerplateCss(content) {
|
|
2251
|
+
if (content === null) return true;
|
|
2252
|
+
const withoutComments = content.replace(/\/\*[\s\S]*?\*\//g, "");
|
|
2253
|
+
return withoutComments.split("\n").filter((line) => line.trim() && !line.trim().startsWith("@import")).length === 0;
|
|
2254
|
+
}
|
|
2255
|
+
async function fetchTheme(config) {
|
|
2256
|
+
const item = await fetchRegistryItem(THEME_ITEM, config.registryUrl);
|
|
2257
|
+
const file = item.files[0];
|
|
2258
|
+
if (!file) 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.");
|
|
2259
|
+
return { ...item, content: file.content };
|
|
2260
|
+
}
|
|
2261
|
+
async function recordTheme(cwd, config, themeRel, item) {
|
|
2262
|
+
const lock = await readLock(cwd);
|
|
2263
|
+
const version = item.version ?? "0.0.0";
|
|
2264
|
+
const installedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
2265
|
+
const relPath = toPosixPath(themeRel);
|
|
2266
|
+
const snapshot = await writeComponentSnapshot(cwd, THEME_ITEM, version, { [relPath]: item.content });
|
|
2267
|
+
lock.components[THEME_ITEM] = mergeComponentEntry(lock.components[THEME_ITEM], {
|
|
2268
|
+
version: item.version,
|
|
2269
|
+
registryUrl: config.registryUrl,
|
|
2270
|
+
installedAt,
|
|
2271
|
+
writtenFiles: { [relPath]: item.files[0].hash ?? hashContent(item.content) },
|
|
2272
|
+
snapshot: "path" in snapshot ? { version, path: snapshot.path, installedAt } : void 0
|
|
2273
|
+
});
|
|
2274
|
+
await writeLock(lock, cwd);
|
|
2275
|
+
}
|
|
2276
|
+
async function writeText(cwd, rel, content) {
|
|
2277
|
+
const target = path11.join(cwd, rel);
|
|
2278
|
+
await mkdir4(path11.dirname(target), { recursive: true });
|
|
2279
|
+
await writeFile5(target, content, "utf8");
|
|
2280
|
+
}
|
|
2281
|
+
async function installTheme(cwd, config, options) {
|
|
2282
|
+
const paths = themePaths(config);
|
|
2283
|
+
const item = await fetchTheme(config);
|
|
2284
|
+
const ramp = options.brand ? buildBrandRamp(options.brand) : void 0;
|
|
2285
|
+
await writeText(cwd, paths.theme, item.content);
|
|
2286
|
+
console.log(`\u2713 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u062F\u0631 ${paths.theme} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (\u0645\u0627\u0644\u0650 \u062F\u06CC\u06AF\u061B \u0628\u0627 \xABdig update theme\xBB \u0628\u0647\u200C\u0631\u0648\u0632 \u0645\u06CC\u200C\u0634\u0648\u062F).`);
|
|
2287
|
+
const existingBrand = await readIfExists(path11.join(cwd, paths.brand));
|
|
2288
|
+
if (existingBrand === null) {
|
|
2289
|
+
await writeText(cwd, paths.brand, brandCss({ ramp, hex: options.brand }));
|
|
2290
|
+
console.log(`\u2713 ${paths.brand} \u0633\u0627\u062E\u062A\u0647 \u0634\u062F (\u0645\u0627\u0644\u0650 \u067E\u0631\u0648\u0698\u0647\u061B \u062F\u06CC\u06AF \u0647\u0631\u06AF\u0632 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u200C\u0627\u0634 \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F).`);
|
|
2291
|
+
} else if (ramp && options.brand) {
|
|
2292
|
+
await writeText(cwd, paths.brand, replaceBrandRamp(existingBrand, ramp, options.brand));
|
|
2293
|
+
console.log(`\u2713 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u062F\u0631 ${paths.brand} \u0627\u0632 ${options.brand} \u0628\u0627\u0632\u0633\u0627\u0632\u06CC \u0634\u062F\u061B \u0628\u0642\u06CC\u0647\u0654 \u0641\u0627\u06CC\u0644 \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
|
|
2294
|
+
} else {
|
|
2295
|
+
console.log(`- ${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0647\u0633\u062A\u061B \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
|
|
2296
|
+
}
|
|
2297
|
+
if (ramp) reportContrast(ramp.primaryContrast);
|
|
2298
|
+
const cssTarget = path11.join(cwd, paths.css);
|
|
2299
|
+
const existingCss = await readIfExists(cssTarget);
|
|
2300
|
+
if (!isBoilerplateCss(existingCss) && existingCss !== null) {
|
|
2301
|
+
await writeFile5(`${cssTarget}.backup`, existingCss, "utf8");
|
|
2302
|
+
console.log(` \u0646\u0633\u062E\u0647\u0654 \u0642\u0628\u0644\u06CC\u0650 ${paths.css} \u062F\u0631 ${paths.css}.backup \u0646\u06AF\u0647 \u062F\u0627\u0634\u062A\u0647 \u0634\u062F.`);
|
|
2303
|
+
console.log(` \u0627\u06AF\u0631 \u0622\u0646 \u0641\u0627\u06CC\u0644 \u062A\u0645\u0650 \u0642\u062F\u06CC\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0648\u062F\u060C \u0628\u0647\u200C\u062C\u0627\u06CC init \u0627\u0632 \xABdig theme split\xBB \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u06A9\u0646\u06CC\u062F.`);
|
|
2304
|
+
}
|
|
2305
|
+
await writeText(cwd, paths.css, globalsCss(paths));
|
|
2306
|
+
console.log(`\u2713 ${paths.css} \u0641\u0642\u0637 import \u0634\u062F: \u062A\u0645\u060C \u0633\u067E\u0633 \u0628\u0631\u0646\u062F.`);
|
|
2307
|
+
await recordTheme(cwd, config, paths.theme, item);
|
|
2308
|
+
return item;
|
|
2309
|
+
}
|
|
2310
|
+
function reportContrast(contrast) {
|
|
2311
|
+
const ratio = contrast.toFixed(2);
|
|
2312
|
+
if (contrast >= 4.5) {
|
|
2313
|
+
console.log(` \u06A9\u0646\u062A\u0631\u0627\u0633\u062A\u0650 \u0645\u062A\u0646\u0650 \u0633\u0641\u06CC\u062F \u0631\u0648\u06CC \u0631\u0646\u06AF\u0650 \u0627\u0635\u0644\u06CC: ${ratio} (AA \u0631\u0627 \u0631\u062F \u0645\u06CC\u200C\u06A9\u0646\u062F).`);
|
|
2314
|
+
} else {
|
|
2315
|
+
console.log(
|
|
2316
|
+
` \u26A0 \u06A9\u0646\u062A\u0631\u0627\u0633\u062A\u0650 \u0645\u062A\u0646\u0650 \u0633\u0641\u06CC\u062F \u0631\u0648\u06CC \u0631\u0646\u06AF\u0650 \u0627\u0635\u0644\u06CC ${ratio} \u0627\u0633\u062A\u060C \u06A9\u0645\u062A\u0631 \u0627\u0632 \u06F4.\u06F5 (AA). \u0645\u062A\u0646\u0650 \u062F\u06A9\u0645\u0647\u200C\u0647\u0627\u06CC \u0627\u0635\u0644\u06CC \u062E\u0648\u0627\u0646\u0627 \u0646\u06CC\u0633\u062A\u061B \u0631\u0646\u06AF\u06CC \u062A\u06CC\u0631\u0647\u200C\u062A\u0631 \u0628\u062F\u0647\u06CC\u062F \u06CC\u0627 --primary-foreground \u0631\u0627 \u062F\u0631 brand.css \u062A\u06CC\u0631\u0647 \u06A9\u0646\u06CC\u062F.`
|
|
2317
|
+
);
|
|
2318
|
+
}
|
|
2319
|
+
}
|
|
2320
|
+
async function requireConfig(cwd) {
|
|
2321
|
+
if (!await configExists(cwd)) {
|
|
2322
|
+
throw new DigError("dig.json \u067E\u06CC\u062F\u0627 \u0646\u0634\u062F\u061B \u0627\u0648\u0644 \xABnpx digdesign init\xBB \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F.");
|
|
2323
|
+
}
|
|
2324
|
+
return readConfig(cwd);
|
|
2325
|
+
}
|
|
2326
|
+
async function themeSplitCommand(options) {
|
|
2327
|
+
const cwd = process.cwd();
|
|
2328
|
+
const config = await requireConfig(cwd);
|
|
2329
|
+
if (config.tailwind.theme) {
|
|
2330
|
+
console.log(`\u067E\u0631\u0648\u0698\u0647 \u0627\u0632 \u0642\u0628\u0644 \u0633\u0627\u062E\u062A\u0627\u0631\u0650 \u062F\u0648\u0641\u0627\u06CC\u0644\u06CC \u062F\u0627\u0631\u062F (${config.tailwind.theme})\u061B \u06A9\u0627\u0631\u06CC \u0644\u0627\u0632\u0645 \u0646\u06CC\u0633\u062A.`);
|
|
2331
|
+
return;
|
|
2332
|
+
}
|
|
2333
|
+
const paths = themePaths(config);
|
|
2334
|
+
const current = await readIfExists(path11.join(cwd, paths.css));
|
|
2335
|
+
if (current === null || isBoilerplateCss(current)) {
|
|
2336
|
+
throw new DigError(`${paths.css} \u062A\u0645\u06CC \u0646\u062F\u0627\u0631\u062F\u061B \u0628\u0631\u0627\u06CC \u0646\u0635\u0628\u0650 \u062A\u0627\u0632\u0647 \xABdig init\xBB \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F.`);
|
|
2337
|
+
}
|
|
2338
|
+
if (await exists(path11.join(cwd, paths.brand))) {
|
|
2339
|
+
throw new DigError(`${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F\u061B \u0628\u0631\u0627\u06CC \u062C\u0644\u0648\u06AF\u06CC\u0631\u06CC \u0627\u0632 \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u060C \u0627\u0648\u0644 \u062C\u0627\u0628\u0647\u200C\u062C\u0627\u06CC\u0634 \u06A9\u0646\u06CC\u062F.`);
|
|
2340
|
+
}
|
|
2341
|
+
console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 ${config.registryUrl} \u2026`);
|
|
2342
|
+
const item = await fetchTheme(config);
|
|
2343
|
+
const split = splitTheme(current, item.content);
|
|
2344
|
+
console.log(`
|
|
2345
|
+
${split.changed} \u062A\u0648\u06A9\u0646\u0650 \u0639\u0648\u0636\u200C\u0634\u062F\u0647 \u0648 ${split.added} \u062A\u0648\u06A9\u0646\u0650 \u062A\u0627\u0632\u0647 \u067E\u06CC\u062F\u0627 \u0634\u062F \u2192 ${paths.brand}`);
|
|
2346
|
+
if (split.extraStatements.length) {
|
|
2347
|
+
console.log(`${split.extraStatements.length} \u062F\u0633\u062A\u0648\u0631\u0650 \u0633\u0637\u062D\u0650 \u0628\u0627\u0644\u0627 \u062F\u0631 ${paths.css} \u0645\u06CC\u200C\u0645\u0627\u0646\u062F:`);
|
|
2348
|
+
for (const statement of split.extraStatements) console.log(` ${statement}`);
|
|
2349
|
+
}
|
|
2350
|
+
if (options.dryRun) {
|
|
2351
|
+
console.log(`
|
|
2352
|
+
\u067E\u06CC\u0634\u200C\u0646\u0645\u0627\u06CC\u0634\u0650 ${paths.brand} (\u0686\u06CC\u0632\u06CC \u0646\u0648\u0634\u062A\u0647 \u0646\u0634\u062F):
|
|
2353
|
+
`);
|
|
2354
|
+
console.log(split.body || "(\u062E\u0627\u0644\u06CC: \u067E\u0631\u0648\u0698\u0647 \u0686\u06CC\u0632\u06CC \u062F\u0631 \u062A\u0645 \u0639\u0648\u0636 \u0646\u06A9\u0631\u062F\u0647)");
|
|
2355
|
+
return;
|
|
2356
|
+
}
|
|
2357
|
+
await writeFile5(path11.join(cwd, `${paths.css}.backup`), current, "utf8");
|
|
2358
|
+
await writeText(cwd, paths.theme, item.content);
|
|
2359
|
+
await writeText(cwd, paths.brand, brandCss({ body: split.body }));
|
|
2360
|
+
await writeText(cwd, paths.css, globalsCss(paths, split.extraStatements));
|
|
2361
|
+
await writeConfig(
|
|
2362
|
+
{ ...config, tailwind: { ...config.tailwind, theme: paths.theme, brand: paths.brand } },
|
|
2363
|
+
cwd
|
|
2364
|
+
);
|
|
2365
|
+
await recordTheme(cwd, config, paths.theme, item);
|
|
2366
|
+
console.log(`
|
|
2367
|
+
\u2713 ${paths.theme} (\u062A\u0645\u0650 \u062F\u06CC\u06AF)\u060C ${paths.brand} (\u0628\u0631\u0646\u062F) \u0648 ${paths.css} (\u0641\u0642\u0637 import) \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
|
|
2368
|
+
console.log(` \u0646\u0633\u062E\u0647\u0654 \u0642\u0628\u0644\u06CC: ${paths.css}.backup`);
|
|
2369
|
+
console.log(
|
|
2370
|
+
` \u062A\u0641\u0627\u0648\u062A\u200C\u0647\u0627 \u0628\u0627 \u0622\u062E\u0631\u06CC\u0646 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0645\u0642\u0627\u06CC\u0633\u0647 \u0634\u062F\u0646\u062F\u061B \u0627\u06AF\u0631 \u067E\u0631\u0648\u0698\u0647 \u0646\u0633\u062E\u0647\u0654 \u0642\u062F\u06CC\u0645\u06CC\u200C\u062A\u0631\u06CC \u0627\u0632 \u062A\u0645 \u062F\u0627\u0634\u062A\u060C \u0645\u0645\u06A9\u0646 \u0627\u0633\u062A \u0686\u0646\u062F \u0645\u0642\u062F\u0627\u0631\u0650 \u0642\u062F\u06CC\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0647\u0645 \u0628\u0647 ${paths.brand} \u0631\u0641\u062A\u0647 \u0628\u0627\u0634\u062F. \u06CC\u06A9 \u0646\u06AF\u0627\u0647 \u0628\u0647 \u0622\u0646 \u0628\u06CC\u0646\u062F\u0627\u0632\u06CC\u062F.`
|
|
2371
|
+
);
|
|
2372
|
+
}
|
|
2373
|
+
async function themeBrandCommand(hex) {
|
|
2374
|
+
const cwd = process.cwd();
|
|
2375
|
+
const config = await requireConfig(cwd);
|
|
2376
|
+
if (!config.tailwind.theme) {
|
|
2377
|
+
throw new DigError("\u0627\u06CC\u0646 \u067E\u0631\u0648\u0698\u0647 \u0647\u0646\u0648\u0632 brand.css \u0646\u062F\u0627\u0631\u062F\u061B \u0627\u0648\u0644 \xABdig theme split\xBB \u0631\u0627 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F.");
|
|
2378
|
+
}
|
|
2379
|
+
const paths = themePaths(config);
|
|
2380
|
+
const ramp = buildBrandRamp(hex);
|
|
2381
|
+
const existing = await readIfExists(path11.join(cwd, paths.brand)) ?? brandCss({});
|
|
2382
|
+
const next = replaceBrandRamp(existing, ramp, hex);
|
|
2383
|
+
await writeText(cwd, paths.brand, next);
|
|
2384
|
+
console.log(`\u2713 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u062F\u0631 ${paths.brand} \u0627\u0632 ${hex} \u0633\u0627\u062E\u062A\u0647 \u0634\u062F (Shade \u06F6\u06F0\u06F0 = \u0631\u0646\u06AF\u0650 \u062F\u0627\u062F\u0647\u200C\u0634\u062F\u0647).`);
|
|
2385
|
+
reportContrast(ramp.primaryContrast);
|
|
2386
|
+
const outside = next.replace(/\/\* dig:brand-ramp-start[\s\S]*?\/\* dig:brand-ramp-end \*\//, "");
|
|
2387
|
+
const shadowing = outside.match(/--brand-\d+\s*:/g);
|
|
2388
|
+
if (shadowing) {
|
|
2389
|
+
console.log(
|
|
2390
|
+
` \u26A0 ${shadowing.length} \u0627\u0639\u0644\u0627\u0646\u0650 --brand-* \u0628\u06CC\u0631\u0648\u0646 \u0627\u0632 \u0628\u0644\u0648\u06A9\u0650 \u0631\u0645\u067E \u062F\u0631 ${paths.brand} \u0647\u0633\u062A \u0648 \u0628\u0631 \u0622\u0646 \u0628\u0631\u0646\u062F\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F\u061B \u0627\u06AF\u0631 \u0631\u0645\u067E\u0650 \u062A\u0627\u0632\u0647 \u0631\u0627 \u0645\u06CC\u200C\u062E\u0648\u0627\u0647\u06CC\u062F\u060C \u0622\u0646\u200C\u0647\u0627 \u0631\u0627 \u067E\u0627\u06A9 \u06A9\u0646\u06CC\u062F.`
|
|
2391
|
+
);
|
|
2392
|
+
}
|
|
1708
2393
|
}
|
|
1709
2394
|
|
|
1710
2395
|
// src/commands/init.ts
|
|
2396
|
+
async function readIfExists2(target) {
|
|
2397
|
+
try {
|
|
2398
|
+
return await readFile8(target, "utf8");
|
|
2399
|
+
} catch {
|
|
2400
|
+
return null;
|
|
2401
|
+
}
|
|
2402
|
+
}
|
|
2403
|
+
async function writeTheme(config, cwd, options) {
|
|
2404
|
+
const paths = themePaths(config);
|
|
2405
|
+
const existing = await readIfExists2(path12.join(cwd, paths.css));
|
|
2406
|
+
if (!isBoilerplateCss(existing) && !options.yes) {
|
|
2407
|
+
console.log(`
|
|
2408
|
+
${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u062F\u0627\u0631\u062F.`);
|
|
2409
|
+
console.log(` \u0627\u06AF\u0631 \u062A\u0645\u0650 \u0642\u062F\u06CC\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0627\u0633\u062A\u060C \u0628\u0647\u200C\u062C\u0627\u06CC \u0627\u06CC\u0646 \u0627\u0632 \xABdig theme split\xBB \u0627\u0633\u062A\u0641\u0627\u062F\u0647 \u06A9\u0646\u06CC\u062F \u062A\u0627 \u0628\u0631\u0646\u062F\u062A\u0627\u0646 \u062D\u0641\u0638 \u0634\u0648\u062F.`);
|
|
2410
|
+
const overwrite = await confirm(
|
|
2411
|
+
"\u0628\u0627 \u0633\u0627\u062E\u062A\u0627\u0631\u0650 \u062A\u0627\u0632\u0647 (\u0641\u0642\u0637 import) \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)",
|
|
2412
|
+
false
|
|
2413
|
+
);
|
|
2414
|
+
if (!overwrite) {
|
|
2415
|
+
console.log(`- \u062A\u0645 \u0646\u0648\u0634\u062A\u0647 \u0646\u0634\u062F. \u0628\u0639\u062F\u0627\u064B: dig init \u06CC\u0627 dig theme split`);
|
|
2416
|
+
return "skipped";
|
|
2417
|
+
}
|
|
2418
|
+
}
|
|
2419
|
+
const item = await installTheme(cwd, config, { brand: options.brand });
|
|
2420
|
+
if (item.dependencies?.length) {
|
|
2421
|
+
const pm = await detectPackageManager(cwd);
|
|
2422
|
+
console.log(`
|
|
2423
|
+
\u0646\u0635\u0628 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627\u06CC \u062A\u0645 \u0628\u0627 ${pm} \u2026`);
|
|
2424
|
+
await installDependencies(pm, item.dependencies, { cwd });
|
|
2425
|
+
}
|
|
2426
|
+
return "written";
|
|
2427
|
+
}
|
|
2428
|
+
async function applyRtl(cwd) {
|
|
2429
|
+
for (const candidate of ["src/app/layout.tsx", "app/layout.tsx"]) {
|
|
2430
|
+
const target = path12.join(cwd, candidate);
|
|
2431
|
+
const source = await readIfExists2(target);
|
|
2432
|
+
if (source === null) continue;
|
|
2433
|
+
if (/<html[^>]*\sdir=/.test(source)) {
|
|
2434
|
+
console.log(`- ${candidate} \u0627\u0632 \u0642\u0628\u0644 dir \u062F\u0627\u0631\u062F\u061B \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
|
|
2435
|
+
return;
|
|
2436
|
+
}
|
|
2437
|
+
const match = source.match(/<html\b([^>]*)>/);
|
|
2438
|
+
if (!match) break;
|
|
2439
|
+
const updated = source.replace(
|
|
2440
|
+
match[0],
|
|
2441
|
+
`<html${match[1]} dir="rtl">`.replace(/\s+dir="rtl">$/, ' dir="rtl">')
|
|
2442
|
+
);
|
|
2443
|
+
await writeFile6(target, updated, "utf8");
|
|
2444
|
+
console.log(`\u2713 dir="rtl" \u0628\u0647 ${candidate} \u0627\u0636\u0627\u0641\u0647 \u0634\u062F.`);
|
|
2445
|
+
return;
|
|
2446
|
+
}
|
|
2447
|
+
console.log(
|
|
2448
|
+
'- \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.'
|
|
2449
|
+
);
|
|
2450
|
+
}
|
|
1711
2451
|
async function initCommand(options) {
|
|
1712
2452
|
const cwd = process.cwd();
|
|
1713
2453
|
const base = defaultConfig();
|
|
@@ -1721,21 +2461,34 @@ async function initCommand(options) {
|
|
|
1721
2461
|
const config = options.yes ? base : {
|
|
1722
2462
|
...base,
|
|
1723
2463
|
rtl: await confirm("\u067E\u0631\u0648\u0698\u0647 \u0631\u0627\u0633\u062A\u200C\u0628\u0647\u200C\u0686\u067E (RTL) \u0627\u0633\u062A\u061F", base.rtl),
|
|
1724
|
-
tailwind: {
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
)
|
|
1730
|
-
}
|
|
2464
|
+
tailwind: await (async () => {
|
|
2465
|
+
const css = await ask("\u0645\u0633\u06CC\u0631 \u0641\u0627\u06CC\u0644 CSS \u0627\u0635\u0644\u06CC \u062A\u06CC\u0644\u0648\u06CC\u0646\u062F\u061F", base.tailwind.css);
|
|
2466
|
+
const dir = path12.posix.dirname(css.split(path12.sep).join("/"));
|
|
2467
|
+
return { ...base.tailwind, css, theme: `${dir}/dig-theme.css`, brand: `${dir}/brand.css` };
|
|
2468
|
+
})()
|
|
1731
2469
|
};
|
|
1732
2470
|
await writeConfig(config, cwd);
|
|
1733
|
-
console.log(`\u2713 ${
|
|
2471
|
+
console.log(`\u2713 ${path12.join(cwd, "dig.json")} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
|
|
2472
|
+
const theme2 = await writeTheme(config, cwd, options);
|
|
2473
|
+
if (config.rtl) {
|
|
2474
|
+
await applyRtl(cwd);
|
|
2475
|
+
}
|
|
2476
|
+
console.log("\n\u0622\u0645\u0627\u062F\u0647 \u0627\u0633\u062A. \u0642\u062F\u0645 \u0628\u0639\u062F\u06CC:");
|
|
2477
|
+
console.log(" dig add button");
|
|
2478
|
+
if (theme2 === "written") {
|
|
2479
|
+
console.log("\n\u0628\u0631\u0646\u062F \u0648 \u0634\u062E\u0635\u06CC\u200C\u0633\u0627\u0632\u06CC \u0641\u0642\u0637 \u062F\u0631 brand.css\u061B \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0628\u0627 \xABdig update theme\xBB \u0628\u0647\u200C\u0631\u0648\u0632 \u0645\u06CC\u200C\u0634\u0648\u062F.");
|
|
2480
|
+
}
|
|
2481
|
+
if (theme2 === "skipped") {
|
|
2482
|
+
console.log(
|
|
2483
|
+
`
|
|
2484
|
+
\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).`
|
|
2485
|
+
);
|
|
2486
|
+
}
|
|
1734
2487
|
}
|
|
1735
2488
|
|
|
1736
2489
|
// src/lib/migration-apply.ts
|
|
1737
|
-
import { readFile as
|
|
1738
|
-
import
|
|
2490
|
+
import { readFile as readFile9, writeFile as writeFile7 } from "fs/promises";
|
|
2491
|
+
import path13 from "path";
|
|
1739
2492
|
|
|
1740
2493
|
// src/lib/migration-strategy.ts
|
|
1741
2494
|
var TextReplaceStrategy = class {
|
|
@@ -1812,7 +2565,7 @@ function looksBinary2(buffer) {
|
|
|
1812
2565
|
async function readTextFileSafely2(target) {
|
|
1813
2566
|
let buffer;
|
|
1814
2567
|
try {
|
|
1815
|
-
buffer = await
|
|
2568
|
+
buffer = await readFile9(target);
|
|
1816
2569
|
} catch (error) {
|
|
1817
2570
|
if (error.code === "ENOENT") return void 0;
|
|
1818
2571
|
throw error;
|
|
@@ -1834,7 +2587,7 @@ function summarizeMigration(migration) {
|
|
|
1834
2587
|
return void 0;
|
|
1835
2588
|
}
|
|
1836
2589
|
async function planOrApplyMigrations(params) {
|
|
1837
|
-
const { cwd, aliases, registryUrl, lock, registryItem, dryRun } = params;
|
|
2590
|
+
const { cwd, aliases, registryUrl, lock, registryItem, dryRun, paths } = params;
|
|
1838
2591
|
const name = registryItem.name;
|
|
1839
2592
|
const lockEntry = lock.components[name];
|
|
1840
2593
|
if (!lockEntry) {
|
|
@@ -1857,8 +2610,8 @@ async function planOrApplyMigrations(params) {
|
|
|
1857
2610
|
};
|
|
1858
2611
|
}
|
|
1859
2612
|
const fileTargets = registryItem.files.map((file) => {
|
|
1860
|
-
const target =
|
|
1861
|
-
return { relPath: toPosixPath(
|
|
2613
|
+
const target = path13.join(cwd, resolveTargetPath(file.path, aliases, paths));
|
|
2614
|
+
return { relPath: toPosixPath(path13.relative(cwd, target)), target };
|
|
1862
2615
|
});
|
|
1863
2616
|
const currentContents = /* @__PURE__ */ new Map();
|
|
1864
2617
|
for (const ft of fileTargets) {
|
|
@@ -1924,12 +2677,12 @@ async function planOrApplyMigrations(params) {
|
|
|
1924
2677
|
const written = [];
|
|
1925
2678
|
try {
|
|
1926
2679
|
for (const item of pending) {
|
|
1927
|
-
await
|
|
2680
|
+
await writeFile7(item.target, item.newContent, "utf8");
|
|
1928
2681
|
written.push(item);
|
|
1929
2682
|
}
|
|
1930
2683
|
} catch (error) {
|
|
1931
2684
|
for (const item of written) {
|
|
1932
|
-
await
|
|
2685
|
+
await writeFile7(item.target, item.originalContent, "utf8");
|
|
1933
2686
|
}
|
|
1934
2687
|
return {
|
|
1935
2688
|
name,
|
|
@@ -2066,6 +2819,7 @@ async function runApplyOrDryRun(components, options, dryRun) {
|
|
|
2066
2819
|
const result = await planOrApplyMigrations({
|
|
2067
2820
|
cwd,
|
|
2068
2821
|
aliases: config.aliases,
|
|
2822
|
+
paths: targetPathOptions(config),
|
|
2069
2823
|
registryUrl: config.registryUrl,
|
|
2070
2824
|
lock,
|
|
2071
2825
|
registryItem,
|
|
@@ -2223,7 +2977,7 @@ ${message}`);
|
|
|
2223
2977
|
}
|
|
2224
2978
|
const summary = intelligence.components.find((c) => c.name === component);
|
|
2225
2979
|
if (!summary) {
|
|
2226
|
-
const message = `\xAB${component}\xBB \u062F\u0631 \u062F\u0627\u062F\u0647\u0654 \u0647\u0648\u0634\u0645\u0646\u062F\u06CC\u0650 \u0641\u0639\u0644\u06CC \u0646\u06CC\u0633\u062A (\u0634\u0627\u06CC\u062F \u0627\u0632 \u0646\u0648\u0639\u0650
|
|
2980
|
+
const message = `\xAB${component}\xBB \u062F\u0631 \u062F\u0627\u062F\u0647\u0654 \u0647\u0648\u0634\u0645\u0646\u062F\u06CC\u0650 \u0641\u0639\u0644\u06CC \u0646\u06CC\u0633\u062A (\u0634\u0627\u06CC\u062F \u0627\u0632 \u0646\u0648\u0639\u0650 dig:lib \u0628\u0627\u0634\u062F\u060C \u0646\u0647 UI).`;
|
|
2227
2981
|
if (options.json) {
|
|
2228
2982
|
console.log(JSON.stringify({ component, status: "no-data", message }, null, 2));
|
|
2229
2983
|
} else {
|
|
@@ -2540,8 +3294,8 @@ ${entry.migrationHint}`);
|
|
|
2540
3294
|
}
|
|
2541
3295
|
|
|
2542
3296
|
// src/lib/update.ts
|
|
2543
|
-
import { mkdir as
|
|
2544
|
-
import
|
|
3297
|
+
import { mkdir as mkdir5, readFile as readFile10, rm as rm2, writeFile as writeFile8 } from "fs/promises";
|
|
3298
|
+
import path14 from "path";
|
|
2545
3299
|
function safeFileIndexes(drift) {
|
|
2546
3300
|
const indexes = [];
|
|
2547
3301
|
drift.files.forEach((file, index) => {
|
|
@@ -2550,7 +3304,7 @@ function safeFileIndexes(drift) {
|
|
|
2550
3304
|
});
|
|
2551
3305
|
return indexes;
|
|
2552
3306
|
}
|
|
2553
|
-
async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun) {
|
|
3307
|
+
async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths) {
|
|
2554
3308
|
const actions = new Array(drift.files.length).fill("skipped");
|
|
2555
3309
|
const safeIndexes = safeFileIndexes(drift);
|
|
2556
3310
|
if (dryRun) {
|
|
@@ -2561,7 +3315,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun) {
|
|
|
2561
3315
|
for (const index of safeIndexes) {
|
|
2562
3316
|
const file = drift.files[index];
|
|
2563
3317
|
const registryFile = registryItem.files[index];
|
|
2564
|
-
const target =
|
|
3318
|
+
const target = path14.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
|
|
2565
3319
|
const isNewFile = file.status === "new_upstream";
|
|
2566
3320
|
pending.push({
|
|
2567
3321
|
index,
|
|
@@ -2569,14 +3323,14 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun) {
|
|
|
2569
3323
|
newContent: registryFile.content,
|
|
2570
3324
|
newHash: registryFile.hash ?? hashContent(registryFile.content),
|
|
2571
3325
|
isNewFile,
|
|
2572
|
-
originalContent: isNewFile ? void 0 : await
|
|
3326
|
+
originalContent: isNewFile ? void 0 : await readFile10(target, "utf8")
|
|
2573
3327
|
});
|
|
2574
3328
|
}
|
|
2575
3329
|
const written = [];
|
|
2576
3330
|
try {
|
|
2577
3331
|
for (const item of pending) {
|
|
2578
|
-
if (item.isNewFile) await
|
|
2579
|
-
await
|
|
3332
|
+
if (item.isNewFile) await mkdir5(path14.dirname(item.target), { recursive: true });
|
|
3333
|
+
await writeFile8(item.target, item.newContent, "utf8");
|
|
2580
3334
|
written.push(item);
|
|
2581
3335
|
}
|
|
2582
3336
|
} catch (error) {
|
|
@@ -2584,7 +3338,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun) {
|
|
|
2584
3338
|
if (item.isNewFile) {
|
|
2585
3339
|
await rm2(item.target, { force: true });
|
|
2586
3340
|
} else {
|
|
2587
|
-
await
|
|
3341
|
+
await writeFile8(item.target, item.originalContent, "utf8");
|
|
2588
3342
|
}
|
|
2589
3343
|
}
|
|
2590
3344
|
return { actions, writtenHashes: {}, rollbackError: error.message };
|
|
@@ -2609,7 +3363,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun) {
|
|
|
2609
3363
|
return { actions, writtenHashes, snapshotPath: snapshotResult.path };
|
|
2610
3364
|
}
|
|
2611
3365
|
async function updateComponent(params) {
|
|
2612
|
-
const { cwd, aliases, registryUrl, lock, registryItem, dryRun = false } = params;
|
|
3366
|
+
const { cwd, aliases, registryUrl, lock, registryItem, dryRun = false, paths } = params;
|
|
2613
3367
|
const name = registryItem.name;
|
|
2614
3368
|
const lockEntry = lock.components[name];
|
|
2615
3369
|
if (!lockEntry) {
|
|
@@ -2620,9 +3374,10 @@ async function updateComponent(params) {
|
|
|
2620
3374
|
aliases,
|
|
2621
3375
|
registryUrl,
|
|
2622
3376
|
lockEntry,
|
|
2623
|
-
registryItem
|
|
3377
|
+
registryItem,
|
|
3378
|
+
paths
|
|
2624
3379
|
});
|
|
2625
|
-
const { actions, writtenHashes, rollbackError, snapshotPath, snapshotError } = await applySafeFiles(cwd, aliases, drift, registryItem, dryRun);
|
|
3380
|
+
const { actions, writtenHashes, rollbackError, snapshotPath, snapshotError } = await applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths);
|
|
2626
3381
|
if (rollbackError) {
|
|
2627
3382
|
return {
|
|
2628
3383
|
name,
|
|
@@ -2686,6 +3441,7 @@ async function updateCommand(components, options) {
|
|
|
2686
3441
|
const result = await updateComponent({
|
|
2687
3442
|
cwd,
|
|
2688
3443
|
aliases: config.aliases,
|
|
3444
|
+
paths: targetPathOptions(config),
|
|
2689
3445
|
registryUrl: config.registryUrl,
|
|
2690
3446
|
lock,
|
|
2691
3447
|
registryItem,
|
|
@@ -2817,6 +3573,7 @@ ${result.name}`);
|
|
|
2817
3573
|
const details = await computeFileDiffDetails({
|
|
2818
3574
|
cwd,
|
|
2819
3575
|
aliases: config.aliases,
|
|
3576
|
+
paths: targetPathOptions(config),
|
|
2820
3577
|
name: result.name,
|
|
2821
3578
|
snapshotVersion,
|
|
2822
3579
|
file,
|
|
@@ -2872,11 +3629,21 @@ ${result.name}`);
|
|
|
2872
3629
|
}
|
|
2873
3630
|
}
|
|
2874
3631
|
|
|
3632
|
+
// src/lib/version.ts
|
|
3633
|
+
var CLI_VERSION = "0.4.0";
|
|
3634
|
+
|
|
2875
3635
|
// src/index.ts
|
|
2876
3636
|
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
|
-
|
|
3637
|
+
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);
|
|
3638
|
+
program.command("init").description(
|
|
3639
|
+
'\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"'
|
|
3640
|
+
).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).option("--brand <hex>", "\u0633\u0627\u062E\u062A\u0646\u0650 \u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF (\u0631\u0648\u06CC Shade \u06F6\u06F0\u06F0 \u0645\u06CC\u200C\u0646\u0634\u06CC\u0646\u062F)\u060C \u0645\u062B\u0644 #2C4C5B").action(initCommand);
|
|
3641
|
+
var theme = program.command("theme").description("\u062A\u0645 \u0648 \u0628\u0631\u0646\u062F: \u062C\u062F\u0627 \u06A9\u0631\u062F\u0646\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 \u0628\u0631\u0646\u062F\u0650 \u067E\u0631\u0648\u0698\u0647");
|
|
3642
|
+
theme.command("split").description("\u067E\u0631\u0648\u0698\u0647\u0654 \u0642\u062F\u06CC\u0645\u06CC \u0631\u0627 \u0628\u0647 \u0633\u0627\u062E\u062A\u0627\u0631\u0650 \u062F\u0648\u0641\u0627\u06CC\u0644\u06CC \u0645\u06CC\u200C\u0628\u0631\u062F (dig-theme.css \u0645\u0627\u0644\u0650 \u062F\u06CC\u06AF\u060C brand.css \u0645\u0627\u0644\u0650 \u067E\u0631\u0648\u0698\u0647)").option("--dry-run", "\u0641\u0642\u0637 \u0646\u0634\u0627\u0646 \u0628\u062F\u0647 \u0686\u0647 \u0686\u06CC\u0632\u06CC \u0628\u0647 brand.css \u0645\u06CC\u200C\u0631\u0648\u062F\u060C \u0686\u06CC\u0632\u06CC \u0646\u0646\u0648\u06CC\u0633", false).action(themeSplitCommand);
|
|
3643
|
+
theme.command("brand").description("\u0631\u0645\u067E\u0650 \u0628\u0631\u0646\u062F \u0631\u0627 \u062F\u0631 brand.css \u0627\u0632 \u06CC\u06A9 \u0631\u0646\u06AF \u0645\u06CC\u200C\u0633\u0627\u0632\u062F\u061B \u0628\u0642\u06CC\u0647\u0654 \u0641\u0627\u06CC\u0644 \u062F\u0633\u062A \u0646\u0645\u06CC\u200C\u062E\u0648\u0631\u062F").argument("<hex>", "\u0631\u0646\u06AF\u0650 \u0627\u0635\u0644\u06CC\u0650 \u0628\u0631\u0646\u062F\u060C \u0645\u062B\u0644 #2C4C5B").action(themeBrandCommand);
|
|
3644
|
+
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);
|
|
3645
|
+
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);
|
|
3646
|
+
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
3647
|
program.command("diff").description(
|
|
2881
3648
|
"\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
3649
|
).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(
|