digdesign 0.7.0 → 0.8.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 +300 -139
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -5,7 +5,7 @@ import { Command } from "commander";
|
|
|
5
5
|
|
|
6
6
|
// src/commands/add.ts
|
|
7
7
|
import { access as access4, mkdir as mkdir3, writeFile as writeFile5 } from "fs/promises";
|
|
8
|
-
import
|
|
8
|
+
import path8 from "path";
|
|
9
9
|
|
|
10
10
|
// src/lib/config.ts
|
|
11
11
|
import { access, readFile, writeFile } from "fs/promises";
|
|
@@ -55,6 +55,10 @@ async function writeConfig(config, cwd = process.cwd()) {
|
|
|
55
55
|
);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
+
// src/lib/framework.ts
|
|
59
|
+
import { readFile as readFile2 } from "fs/promises";
|
|
60
|
+
import path2 from "path";
|
|
61
|
+
|
|
58
62
|
// src/lib/errors.ts
|
|
59
63
|
var DigError = class extends Error {
|
|
60
64
|
constructor(message, options) {
|
|
@@ -63,6 +67,48 @@ var DigError = class extends Error {
|
|
|
63
67
|
}
|
|
64
68
|
};
|
|
65
69
|
|
|
70
|
+
// src/lib/framework.ts
|
|
71
|
+
var CLI_FRAMEWORKS = ["react", "vue"];
|
|
72
|
+
function parseFramework(value) {
|
|
73
|
+
const normalized = value.trim().toLowerCase();
|
|
74
|
+
if (CLI_FRAMEWORKS.includes(normalized)) return normalized;
|
|
75
|
+
if (normalized === "svelte" || normalized === "angular") {
|
|
76
|
+
throw new DigError(
|
|
77
|
+
`CLI \u0647\u0646\u0648\u0632 ${normalized === "svelte" ? "Svelte" : "Angular"} \u0631\u0627 \u0646\u0635\u0628 \u0646\u0645\u06CC\u200C\u06A9\u0646\u062F.
|
|
78
|
+
\u06A9\u062F \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u0631\u0627 \u0627\u0632 \u062A\u0628 \xAB\u062F\u0633\u062A\u06CC\xBB \u0635\u0641\u062D\u0647\u0654 \u0645\u0633\u062A\u0646\u062F\u0627\u062A \u0628\u06AF\u06CC\u0631\u06CC\u062F\u060C \u06CC\u0627 /r/${normalized}/<name>.json \u0631\u0627 \u062F\u0633\u062A\u06CC \u0628\u0646\u0648\u06CC\u0633\u06CC\u062F.`
|
|
79
|
+
);
|
|
80
|
+
}
|
|
81
|
+
throw new DigError(`\u0641\u0631\u06CC\u0645\u200C\u0648\u0631\u06A9 \xAB${value}\xBB \u0634\u0646\u0627\u062E\u062A\u0647 \u0646\u0634\u062F. \u06CC\u06A9\u06CC \u0627\u0632 ${CLI_FRAMEWORKS.join("\u060C ")} \u0631\u0627 \u0628\u062F\u0647\u06CC\u062F.`);
|
|
82
|
+
}
|
|
83
|
+
async function readPackageJson(cwd) {
|
|
84
|
+
try {
|
|
85
|
+
return JSON.parse(await readFile2(path2.join(cwd, "package.json"), "utf8"));
|
|
86
|
+
} catch {
|
|
87
|
+
return null;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
async function detectFramework(cwd) {
|
|
91
|
+
const pkg = await readPackageJson(cwd);
|
|
92
|
+
if (!pkg) return void 0;
|
|
93
|
+
const deps = { ...pkg.devDependencies, ...pkg.dependencies };
|
|
94
|
+
if ("react" in deps || "next" in deps) return "react";
|
|
95
|
+
if ("vue" in deps || "nuxt" in deps) return "vue";
|
|
96
|
+
return void 0;
|
|
97
|
+
}
|
|
98
|
+
async function resolveFramework(cwd, config, flag) {
|
|
99
|
+
if (flag) return parseFramework(flag);
|
|
100
|
+
if (config?.framework) return config.framework;
|
|
101
|
+
const detected = await detectFramework(cwd);
|
|
102
|
+
if (detected) return detected;
|
|
103
|
+
try {
|
|
104
|
+
const shadcn = JSON.parse(await readFile2(path2.join(cwd, "components.json"), "utf8"));
|
|
105
|
+
const hint = `${shadcn.framework ?? ""} ${shadcn.$schema ?? ""} ${shadcn.tailwind?.css ?? ""}`.toLowerCase();
|
|
106
|
+
if (/vue|nuxt/.test(hint)) return "vue";
|
|
107
|
+
} catch {
|
|
108
|
+
}
|
|
109
|
+
return "react";
|
|
110
|
+
}
|
|
111
|
+
|
|
66
112
|
// src/lib/prompt.ts
|
|
67
113
|
import * as readline from "readline/promises";
|
|
68
114
|
import { stdin, stdout } from "process";
|
|
@@ -127,19 +173,19 @@ function hashContent(content) {
|
|
|
127
173
|
}
|
|
128
174
|
|
|
129
175
|
// src/lib/lock.ts
|
|
130
|
-
import { mkdir, readFile as
|
|
131
|
-
import
|
|
176
|
+
import { mkdir, readFile as readFile3, writeFile as writeFile2 } from "fs/promises";
|
|
177
|
+
import path3 from "path";
|
|
132
178
|
var LOCK_DIR = ".dig";
|
|
133
179
|
var LOCK_FILE_NAME = "registry-lock.json";
|
|
134
180
|
function emptyLock() {
|
|
135
181
|
return { components: {} };
|
|
136
182
|
}
|
|
137
183
|
function lockFilePath(cwd) {
|
|
138
|
-
return
|
|
184
|
+
return path3.join(cwd, LOCK_DIR, LOCK_FILE_NAME);
|
|
139
185
|
}
|
|
140
186
|
async function readLock(cwd = process.cwd()) {
|
|
141
187
|
try {
|
|
142
|
-
const raw = await
|
|
188
|
+
const raw = await readFile3(lockFilePath(cwd), "utf8");
|
|
143
189
|
const parsed = JSON.parse(raw);
|
|
144
190
|
return { components: parsed?.components ?? {} };
|
|
145
191
|
} catch (error) {
|
|
@@ -148,7 +194,7 @@ async function readLock(cwd = process.cwd()) {
|
|
|
148
194
|
}
|
|
149
195
|
}
|
|
150
196
|
async function writeLock(lock, cwd = process.cwd()) {
|
|
151
|
-
await mkdir(
|
|
197
|
+
await mkdir(path3.join(cwd, LOCK_DIR), { recursive: true });
|
|
152
198
|
await writeFile2(lockFilePath(cwd), `${JSON.stringify(lock, null, 2)}
|
|
153
199
|
`, "utf8");
|
|
154
200
|
}
|
|
@@ -168,7 +214,7 @@ function mergeComponentEntry(existing, patch) {
|
|
|
168
214
|
// src/lib/package-manager.ts
|
|
169
215
|
import { access as access2 } from "fs/promises";
|
|
170
216
|
import { spawn } from "child_process";
|
|
171
|
-
import
|
|
217
|
+
import path4 from "path";
|
|
172
218
|
var LOCKFILES = [
|
|
173
219
|
["pnpm", "pnpm-lock.yaml"],
|
|
174
220
|
["yarn", "yarn.lock"],
|
|
@@ -178,7 +224,7 @@ var LOCKFILES = [
|
|
|
178
224
|
async function detectPackageManager(cwd = process.cwd()) {
|
|
179
225
|
for (const [pm, lockfile] of LOCKFILES) {
|
|
180
226
|
try {
|
|
181
|
-
await access2(
|
|
227
|
+
await access2(path4.join(cwd, lockfile));
|
|
182
228
|
return pm;
|
|
183
229
|
} catch {
|
|
184
230
|
continue;
|
|
@@ -248,9 +294,12 @@ function installDependencies(pm, deps, options = {}) {
|
|
|
248
294
|
}
|
|
249
295
|
|
|
250
296
|
// src/lib/registry.ts
|
|
251
|
-
function
|
|
297
|
+
function registryBase(registryUrl, framework) {
|
|
298
|
+
return !framework || framework === "react" ? `${registryUrl}/r` : `${registryUrl}/r/${framework}`;
|
|
299
|
+
}
|
|
300
|
+
function resolveUrl(nameOrUrl, registryUrl, framework) {
|
|
252
301
|
if (/^https?:\/\//.test(nameOrUrl)) return nameOrUrl;
|
|
253
|
-
return `${registryUrl}
|
|
302
|
+
return `${registryBase(registryUrl, framework)}/${nameOrUrl}.json`;
|
|
254
303
|
}
|
|
255
304
|
async function fetchFromRegistry(url, subject) {
|
|
256
305
|
let response;
|
|
@@ -288,28 +337,28 @@ async function fetchFromRegistry(url, subject) {
|
|
|
288
337
|
function normalizeType(type) {
|
|
289
338
|
return type.startsWith("registry:") ? `dig:${type.slice("registry:".length)}` : type;
|
|
290
339
|
}
|
|
291
|
-
async function fetchRegistryIndex(registryUrl) {
|
|
292
|
-
const url = `${registryUrl}/
|
|
340
|
+
async function fetchRegistryIndex(registryUrl, framework) {
|
|
341
|
+
const url = `${registryBase(registryUrl, framework)}/registry.json`;
|
|
293
342
|
const response = await fetchFromRegistry(url, "\u0641\u0647\u0631\u0633\u062A\u0650 \u0631\u062C\u06CC\u0633\u062A\u0631\u06CC");
|
|
294
343
|
const index = await response.json();
|
|
295
344
|
for (const item of index.items) item.type = normalizeType(item.type);
|
|
296
345
|
return index;
|
|
297
346
|
}
|
|
298
|
-
async function fetchRegistryItem(nameOrUrl, registryUrl) {
|
|
299
|
-
const url = resolveUrl(nameOrUrl, registryUrl);
|
|
347
|
+
async function fetchRegistryItem(nameOrUrl, registryUrl, framework) {
|
|
348
|
+
const url = resolveUrl(nameOrUrl, registryUrl, framework);
|
|
300
349
|
const response = await fetchFromRegistry(url, `\xAB${nameOrUrl}\xBB`);
|
|
301
350
|
const item = await response.json();
|
|
302
351
|
item.type = normalizeType(item.type);
|
|
303
352
|
for (const file of item.files ?? []) file.type = normalizeType(file.type);
|
|
304
353
|
return item;
|
|
305
354
|
}
|
|
306
|
-
async function resolveRegistryTree(names, registryUrl) {
|
|
355
|
+
async function resolveRegistryTree(names, registryUrl, framework) {
|
|
307
356
|
const resolved = /* @__PURE__ */ new Map();
|
|
308
357
|
const queued = new Set(names);
|
|
309
358
|
const queue = [...names];
|
|
310
359
|
while (queue.length) {
|
|
311
360
|
const next = queue.shift();
|
|
312
|
-
const item = await fetchRegistryItem(next, registryUrl);
|
|
361
|
+
const item = await fetchRegistryItem(next, registryUrl, framework);
|
|
313
362
|
if (resolved.has(item.name)) continue;
|
|
314
363
|
resolved.set(item.name, item);
|
|
315
364
|
for (const dep of item.registryDependencies ?? []) {
|
|
@@ -323,14 +372,14 @@ async function resolveRegistryTree(names, registryUrl) {
|
|
|
323
372
|
}
|
|
324
373
|
|
|
325
374
|
// src/lib/snapshot.ts
|
|
326
|
-
import { access as access3, mkdir as mkdir2, readFile as
|
|
327
|
-
import
|
|
328
|
-
var SNAPSHOT_ROOT =
|
|
375
|
+
import { access as access3, mkdir as mkdir2, readFile as readFile4, rm, writeFile as writeFile3 } from "fs/promises";
|
|
376
|
+
import path5 from "path";
|
|
377
|
+
var SNAPSHOT_ROOT = path5.join(".dig", "snapshots");
|
|
329
378
|
function snapshotDirFor(cwd, name, version) {
|
|
330
|
-
return
|
|
379
|
+
return path5.join(cwd, SNAPSHOT_ROOT, name, version);
|
|
331
380
|
}
|
|
332
381
|
function snapshotRelativePath(name, version) {
|
|
333
|
-
return `${SNAPSHOT_ROOT.split(
|
|
382
|
+
return `${SNAPSHOT_ROOT.split(path5.sep).join("/")}/${name}/${version}`;
|
|
334
383
|
}
|
|
335
384
|
async function fileExists(target) {
|
|
336
385
|
try {
|
|
@@ -347,19 +396,19 @@ async function writeComponentSnapshot(cwd, name, version, files) {
|
|
|
347
396
|
const dir = snapshotDirFor(cwd, name, version);
|
|
348
397
|
const pending = [];
|
|
349
398
|
for (const [relFilePath, content] of entries) {
|
|
350
|
-
const target =
|
|
399
|
+
const target = path5.join(dir, relFilePath);
|
|
351
400
|
const existedBefore = await fileExists(target);
|
|
352
401
|
pending.push({
|
|
353
402
|
target,
|
|
354
403
|
content,
|
|
355
404
|
existedBefore,
|
|
356
|
-
originalContent: existedBefore ? await
|
|
405
|
+
originalContent: existedBefore ? await readFile4(target, "utf8") : void 0
|
|
357
406
|
});
|
|
358
407
|
}
|
|
359
408
|
const written = [];
|
|
360
409
|
try {
|
|
361
410
|
for (const item of pending) {
|
|
362
|
-
await mkdir2(
|
|
411
|
+
await mkdir2(path5.dirname(item.target), { recursive: true });
|
|
363
412
|
await writeFile3(item.target, item.content, "utf8");
|
|
364
413
|
written.push(item);
|
|
365
414
|
}
|
|
@@ -377,7 +426,7 @@ async function writeComponentSnapshot(cwd, name, version, files) {
|
|
|
377
426
|
}
|
|
378
427
|
async function readSnapshotFile(cwd, name, version, relFilePath) {
|
|
379
428
|
try {
|
|
380
|
-
return await
|
|
429
|
+
return await readFile4(path5.join(snapshotDirFor(cwd, name, version), relFilePath), "utf8");
|
|
381
430
|
} catch (error) {
|
|
382
431
|
if (error.code === "ENOENT") return void 0;
|
|
383
432
|
throw error;
|
|
@@ -385,9 +434,9 @@ async function readSnapshotFile(cwd, name, version, relFilePath) {
|
|
|
385
434
|
}
|
|
386
435
|
|
|
387
436
|
// src/lib/target.ts
|
|
388
|
-
import
|
|
437
|
+
import path6 from "path";
|
|
389
438
|
function toPosixPath(relativePath) {
|
|
390
|
-
return relativePath.split(
|
|
439
|
+
return relativePath.split(path6.sep).join("/");
|
|
391
440
|
}
|
|
392
441
|
function targetPathOptions(config) {
|
|
393
442
|
return { tailwindCss: config.tailwind.css, themeCss: config.tailwind.theme };
|
|
@@ -414,8 +463,8 @@ function resolveTargetPath(filePath, aliases, options = {}) {
|
|
|
414
463
|
}
|
|
415
464
|
|
|
416
465
|
// src/commands/design-md.ts
|
|
417
|
-
import { readFile as
|
|
418
|
-
import
|
|
466
|
+
import { readFile as readFile5, writeFile as writeFile4 } from "fs/promises";
|
|
467
|
+
import path7 from "path";
|
|
419
468
|
var DESIGN_MD_FILE = "DESIGN.md";
|
|
420
469
|
var GENERATED_MARK = "Generated by Dig";
|
|
421
470
|
async function fetchDesignMd(registryUrl, options) {
|
|
@@ -438,13 +487,13 @@ async function fetchDesignMd(registryUrl, options) {
|
|
|
438
487
|
}
|
|
439
488
|
async function readIfExists(target) {
|
|
440
489
|
try {
|
|
441
|
-
return await
|
|
490
|
+
return await readFile5(target, "utf8");
|
|
442
491
|
} catch {
|
|
443
492
|
return null;
|
|
444
493
|
}
|
|
445
494
|
}
|
|
446
495
|
async function writeDesignMd(cwd, registryUrl, options) {
|
|
447
|
-
const target =
|
|
496
|
+
const target = path7.join(cwd, DESIGN_MD_FILE);
|
|
448
497
|
const existing = await readIfExists(target);
|
|
449
498
|
if (existing !== null && !options.force) {
|
|
450
499
|
const generated = existing.includes(GENERATED_MARK);
|
|
@@ -472,7 +521,7 @@ function readDesignMdSettings(text) {
|
|
|
472
521
|
}
|
|
473
522
|
}
|
|
474
523
|
async function refreshDesignMd(cwd, registryUrl, overrides = {}, log = console.log) {
|
|
475
|
-
const target =
|
|
524
|
+
const target = path7.join(cwd, DESIGN_MD_FILE);
|
|
476
525
|
const existing = await readIfExists(target);
|
|
477
526
|
if (existing === null || !existing.includes(GENERATED_MARK)) return "skipped";
|
|
478
527
|
try {
|
|
@@ -489,7 +538,7 @@ async function refreshDesignMd(cwd, registryUrl, overrides = {}, log = console.l
|
|
|
489
538
|
async function designMdCommand(options) {
|
|
490
539
|
const cwd = process.cwd();
|
|
491
540
|
const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
|
|
492
|
-
const previous = readDesignMdSettings(await readIfExists(
|
|
541
|
+
const previous = readDesignMdSettings(await readIfExists(path7.join(cwd, DESIGN_MD_FILE)) ?? "");
|
|
493
542
|
const explicit = Object.fromEntries(Object.entries(options).filter(([, value]) => value !== void 0 && value !== false));
|
|
494
543
|
options = { ...previous, ...explicit };
|
|
495
544
|
const result = await writeDesignMd(cwd, config.registryUrl, { ...options, replaceGenerated: true });
|
|
@@ -507,13 +556,13 @@ async function pathExists(target) {
|
|
|
507
556
|
return false;
|
|
508
557
|
}
|
|
509
558
|
}
|
|
510
|
-
async function pickComponents(registryUrl) {
|
|
559
|
+
async function pickComponents(registryUrl, framework) {
|
|
511
560
|
if (!process.stdin.isTTY) {
|
|
512
561
|
throw new DigError(
|
|
513
562
|
"\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"
|
|
514
563
|
);
|
|
515
564
|
}
|
|
516
|
-
const index = await fetchRegistryIndex(registryUrl);
|
|
565
|
+
const index = await fetchRegistryIndex(registryUrl, framework);
|
|
517
566
|
const choices = index.items.filter((item) => item.type === "dig:ui").map((item) => ({
|
|
518
567
|
value: item.name,
|
|
519
568
|
label: item.title ? `${item.name} \u2014 ${item.title}` : item.name
|
|
@@ -533,18 +582,25 @@ ${choices.length} \u06A9\u0627\u0645\u067E\u0648\u0646\u0646\u062A \u062F\u0631
|
|
|
533
582
|
}
|
|
534
583
|
async function addCommand(components, options) {
|
|
535
584
|
const cwd = process.cwd();
|
|
536
|
-
const
|
|
537
|
-
const
|
|
585
|
+
const hasConfig = await configExists(cwd);
|
|
586
|
+
const config = hasConfig ? await readConfig(cwd) : defaultConfig();
|
|
587
|
+
const framework = await resolveFramework(cwd, config, options.framework);
|
|
588
|
+
if (hasConfig && framework !== "react" && config.framework !== framework && !options.dryRun) {
|
|
589
|
+
config.framework = framework;
|
|
590
|
+
await writeConfig(config, cwd);
|
|
591
|
+
}
|
|
592
|
+
config.framework = framework === "react" ? config.framework : framework;
|
|
593
|
+
const names = components.length ? components : await pickComponents(config.registryUrl, framework);
|
|
538
594
|
if (names.length === 0) return;
|
|
539
|
-
console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A \u0627\u0632 ${config.registryUrl} \u2026`);
|
|
540
|
-
const items = await resolveRegistryTree(names, config.registryUrl);
|
|
595
|
+
console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A \u0627\u0632 ${config.registryUrl}${framework === "react" ? "" : ` (${framework})`} \u2026`);
|
|
596
|
+
const items = await resolveRegistryTree(names, config.registryUrl, framework);
|
|
541
597
|
let overwrite = Boolean(options.overwrite);
|
|
542
598
|
if (!overwrite && !options.skipExisting) {
|
|
543
599
|
const existing = [];
|
|
544
600
|
for (const item of items.values()) {
|
|
545
601
|
for (const file of item.files) {
|
|
546
|
-
const target =
|
|
547
|
-
if (await pathExists(target)) existing.push(
|
|
602
|
+
const target = path8.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
|
|
603
|
+
if (await pathExists(target)) existing.push(path8.relative(cwd, target));
|
|
548
604
|
}
|
|
549
605
|
}
|
|
550
606
|
if (existing.length) {
|
|
@@ -565,11 +621,11 @@ ${existing.length} \u0641\u0627\u06CC\u0644 \u0627\u0632 \u0642\u0628\u0644 \u06
|
|
|
565
621
|
for (const item of items.values()) {
|
|
566
622
|
for (const dep of item.dependencies ?? []) npmDeps.add(dep);
|
|
567
623
|
for (const file of item.files) {
|
|
568
|
-
const target =
|
|
624
|
+
const target = path8.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
|
|
569
625
|
const exists3 = await pathExists(target);
|
|
570
626
|
const mark = exists3 ? overwrite ? "~" : "-" : "+";
|
|
571
627
|
const note = exists3 ? 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)" : "";
|
|
572
|
-
console.log(`${mark} ${
|
|
628
|
+
console.log(`${mark} ${path8.relative(cwd, target)}${note}`);
|
|
573
629
|
}
|
|
574
630
|
}
|
|
575
631
|
console.log(`
|
|
@@ -592,17 +648,17 @@ ${items.size} \u0622\u06CC\u062A\u0645 \u0627\u0632 \u0631\u062C\u06CC\u0633\u06
|
|
|
592
648
|
const writtenFiles = {};
|
|
593
649
|
const writtenContents = {};
|
|
594
650
|
for (const file of item.files) {
|
|
595
|
-
const target =
|
|
651
|
+
const target = path8.join(cwd, resolveTargetPath(file.path, config.aliases, targetPathOptions(config)));
|
|
596
652
|
if (!overwrite && await pathExists(target)) {
|
|
597
|
-
if (!options.skipExisting) console.log(`- \u0631\u062F \u0634\u062F (\u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F): ${
|
|
653
|
+
if (!options.skipExisting) console.log(`- \u0631\u062F \u0634\u062F (\u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F): ${path8.relative(cwd, target)}`);
|
|
598
654
|
skipped++;
|
|
599
655
|
continue;
|
|
600
656
|
}
|
|
601
|
-
await mkdir3(
|
|
657
|
+
await mkdir3(path8.dirname(target), { recursive: true });
|
|
602
658
|
await writeFile5(target, file.content, "utf8");
|
|
603
|
-
console.log(`+ ${
|
|
659
|
+
console.log(`+ ${path8.relative(cwd, target)}`);
|
|
604
660
|
written++;
|
|
605
|
-
const relPath = toPosixPath(
|
|
661
|
+
const relPath = toPosixPath(path8.relative(cwd, target));
|
|
606
662
|
writtenFiles[relPath] = file.hash ?? hashContent(file.content);
|
|
607
663
|
writtenContents[relPath] = file.content;
|
|
608
664
|
}
|
|
@@ -625,7 +681,7 @@ ${items.size} \u0622\u06CC\u062A\u0645 \u0627\u0632 \u0631\u062C\u06CC\u0633\u06
|
|
|
625
681
|
if (lockChanged) {
|
|
626
682
|
await writeLock(lock, cwd);
|
|
627
683
|
console.log(`
|
|
628
|
-
\u062B\u0628\u062A \u0634\u062F \u062F\u0631 ${
|
|
684
|
+
\u062B\u0628\u062A \u0634\u062F \u062F\u0631 ${path8.join(".dig", "registry-lock.json")}`);
|
|
629
685
|
}
|
|
630
686
|
console.log(`
|
|
631
687
|
${written} \u0641\u0627\u06CC\u0644 \u0646\u0648\u0634\u062A\u0647 \u0634\u062F\u060C ${skipped} \u0641\u0627\u06CC\u0644 \u0631\u062F \u0634\u062F.`);
|
|
@@ -700,7 +756,7 @@ var TYPE_LABEL = {
|
|
|
700
756
|
};
|
|
701
757
|
async function loadItems(cwd) {
|
|
702
758
|
const config = await configExists(cwd) ? await readConfig(cwd) : defaultConfig();
|
|
703
|
-
const index = await fetchRegistryIndex(config.registryUrl);
|
|
759
|
+
const index = await fetchRegistryIndex(config.registryUrl, config.framework);
|
|
704
760
|
return index.items;
|
|
705
761
|
}
|
|
706
762
|
function matchesType(item, type) {
|
|
@@ -752,8 +808,8 @@ async function searchCommand(query, options) {
|
|
|
752
808
|
}
|
|
753
809
|
|
|
754
810
|
// src/lib/diff.ts
|
|
755
|
-
import { readFile as
|
|
756
|
-
import
|
|
811
|
+
import { readFile as readFile6 } from "fs/promises";
|
|
812
|
+
import path9 from "path";
|
|
757
813
|
var STATUS_PRIORITY = [
|
|
758
814
|
"conflict",
|
|
759
815
|
"untracked",
|
|
@@ -783,7 +839,7 @@ function overallStatus(files) {
|
|
|
783
839
|
}
|
|
784
840
|
async function readLocalHash(target) {
|
|
785
841
|
try {
|
|
786
|
-
const content = await
|
|
842
|
+
const content = await readFile6(target, "utf8");
|
|
787
843
|
return hashContent(content);
|
|
788
844
|
} catch (error) {
|
|
789
845
|
if (error.code === "ENOENT") return void 0;
|
|
@@ -791,8 +847,8 @@ async function readLocalHash(target) {
|
|
|
791
847
|
}
|
|
792
848
|
}
|
|
793
849
|
async function computeFileDrift(cwd, aliases, lockEntry, file, paths) {
|
|
794
|
-
const target =
|
|
795
|
-
const relPath = toPosixPath(
|
|
850
|
+
const target = path9.join(cwd, resolveTargetPath(file.path, aliases, paths));
|
|
851
|
+
const relPath = toPosixPath(path9.relative(cwd, target));
|
|
796
852
|
const registryHash = file.hash ?? hashContent(file.content);
|
|
797
853
|
const installedHash = lockEntry?.files[relPath];
|
|
798
854
|
const localHash = await readLocalHash(target);
|
|
@@ -821,8 +877,8 @@ async function computeComponentDrift(params) {
|
|
|
821
877
|
}
|
|
822
878
|
|
|
823
879
|
// src/lib/file-diff-details.ts
|
|
824
|
-
import { readFile as
|
|
825
|
-
import
|
|
880
|
+
import { readFile as readFile7 } from "fs/promises";
|
|
881
|
+
import path10 from "path";
|
|
826
882
|
|
|
827
883
|
// src/lib/text-diff.ts
|
|
828
884
|
var DEFAULT_CONTEXT = 3;
|
|
@@ -931,7 +987,7 @@ function looksBinary(buffer) {
|
|
|
931
987
|
async function readTextFileSafely(target) {
|
|
932
988
|
let buffer;
|
|
933
989
|
try {
|
|
934
|
-
buffer = await
|
|
990
|
+
buffer = await readFile7(target);
|
|
935
991
|
} catch (error) {
|
|
936
992
|
if (error.code === "ENOENT") return void 0;
|
|
937
993
|
throw error;
|
|
@@ -971,7 +1027,7 @@ async function computeFileDiffDetails(params) {
|
|
|
971
1027
|
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."
|
|
972
1028
|
};
|
|
973
1029
|
}
|
|
974
|
-
const target =
|
|
1030
|
+
const target = path10.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
|
|
975
1031
|
const localContent = await readTextFileSafely(target);
|
|
976
1032
|
if (localContent === "binary") {
|
|
977
1033
|
return {
|
|
@@ -1057,7 +1113,7 @@ async function diffCommand(components, options) {
|
|
|
1057
1113
|
for (const name of components) {
|
|
1058
1114
|
let registryItem;
|
|
1059
1115
|
try {
|
|
1060
|
-
registryItem = await fetchRegistryItem(name, config.registryUrl);
|
|
1116
|
+
registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
|
|
1061
1117
|
} catch (error) {
|
|
1062
1118
|
console.error(`\u2717 ${name}: ${error.message}`);
|
|
1063
1119
|
continue;
|
|
@@ -1528,8 +1584,8 @@ function dependencyRiskLevel(highImpactComponents) {
|
|
|
1528
1584
|
}
|
|
1529
1585
|
|
|
1530
1586
|
// src/lib/repo-scanner.ts
|
|
1531
|
-
import { readFile as
|
|
1532
|
-
import
|
|
1587
|
+
import { readFile as readFile8, readdir } from "fs/promises";
|
|
1588
|
+
import path11 from "path";
|
|
1533
1589
|
import ts2 from "typescript";
|
|
1534
1590
|
|
|
1535
1591
|
// src/lib/ast-engine.ts
|
|
@@ -1604,11 +1660,11 @@ async function collectSourceFiles(root) {
|
|
|
1604
1660
|
for (const entry of entries) {
|
|
1605
1661
|
if (entry.isDirectory()) {
|
|
1606
1662
|
if (IGNORED_DIRS.has(entry.name) || entry.name.startsWith(".")) continue;
|
|
1607
|
-
await walk(
|
|
1663
|
+
await walk(path11.join(dir, entry.name));
|
|
1608
1664
|
continue;
|
|
1609
1665
|
}
|
|
1610
|
-
if (entry.isFile() && SCAN_EXTENSIONS.has(
|
|
1611
|
-
results.push(
|
|
1666
|
+
if (entry.isFile() && SCAN_EXTENSIONS.has(path11.extname(entry.name))) {
|
|
1667
|
+
results.push(path11.join(dir, entry.name));
|
|
1612
1668
|
}
|
|
1613
1669
|
}
|
|
1614
1670
|
}
|
|
@@ -1635,7 +1691,7 @@ async function scanRepositoryForComponent(params) {
|
|
|
1635
1691
|
for (const filePath of sourceFilePaths) {
|
|
1636
1692
|
let content;
|
|
1637
1693
|
try {
|
|
1638
|
-
content = await
|
|
1694
|
+
content = await readFile8(filePath, "utf8");
|
|
1639
1695
|
} catch {
|
|
1640
1696
|
continue;
|
|
1641
1697
|
}
|
|
@@ -1649,7 +1705,7 @@ async function scanRepositoryForComponent(params) {
|
|
|
1649
1705
|
const snippets = findJsxUsagesInSource(sourceFile, tagName);
|
|
1650
1706
|
if (snippets.length === 0) continue;
|
|
1651
1707
|
files.push({
|
|
1652
|
-
path: toPosixPath(
|
|
1708
|
+
path: toPosixPath(path11.relative(projectRoot, filePath)),
|
|
1653
1709
|
usages: snippets.length,
|
|
1654
1710
|
snippets
|
|
1655
1711
|
});
|
|
@@ -2055,11 +2111,11 @@ async function impactCommand(name, options) {
|
|
|
2055
2111
|
}
|
|
2056
2112
|
|
|
2057
2113
|
// src/commands/review.ts
|
|
2058
|
-
import { readFile as
|
|
2059
|
-
import
|
|
2114
|
+
import { readFile as readFile9 } from "fs/promises";
|
|
2115
|
+
import path12 from "path";
|
|
2060
2116
|
|
|
2061
2117
|
// src/lib/version.ts
|
|
2062
|
-
var CLI_VERSION = "0.
|
|
2118
|
+
var CLI_VERSION = "0.8.0";
|
|
2063
2119
|
|
|
2064
2120
|
// src/commands/mcp.ts
|
|
2065
2121
|
import { createInterface as createInterface2 } from "readline";
|
|
@@ -2155,15 +2211,15 @@ var MAX_FILES_PER_CALL = 25;
|
|
|
2155
2211
|
async function readReviewFiles(paths, cwd) {
|
|
2156
2212
|
const files = [];
|
|
2157
2213
|
for (const input of paths) {
|
|
2158
|
-
const absolute =
|
|
2214
|
+
const absolute = path12.resolve(cwd, input);
|
|
2159
2215
|
let code;
|
|
2160
2216
|
try {
|
|
2161
|
-
code = await
|
|
2217
|
+
code = await readFile9(absolute, "utf8");
|
|
2162
2218
|
} catch {
|
|
2163
2219
|
throw new DigError(`\u0641\u0627\u06CC\u0644 \u062E\u0648\u0627\u0646\u062F\u0647 \u0646\u0634\u062F: ${input}`);
|
|
2164
2220
|
}
|
|
2165
2221
|
if (code.length > MAX_FILE_CHARS) throw new DigError(`${input} \u0628\u0632\u0631\u06AF\u200C\u062A\u0631 \u0627\u0632 ${MAX_FILE_CHARS} \u0646\u0648\u06CC\u0633\u0647 \u0627\u0633\u062A\u061B \u0628\u0647 \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u06A9\u0648\u0686\u06A9\u200C\u062A\u0631 \u0628\u0634\u06A9\u0646.`);
|
|
2166
|
-
files.push({ path:
|
|
2222
|
+
files.push({ path: path12.relative(cwd, absolute) || input, code });
|
|
2167
2223
|
}
|
|
2168
2224
|
return files;
|
|
2169
2225
|
}
|
|
@@ -2225,7 +2281,7 @@ async function reviewCommand(paths, options) {
|
|
|
2225
2281
|
|
|
2226
2282
|
// src/commands/skill.ts
|
|
2227
2283
|
import { mkdir as mkdir4, writeFile as writeFile6 } from "fs/promises";
|
|
2228
|
-
import
|
|
2284
|
+
import path13 from "path";
|
|
2229
2285
|
var SKILL_PATH = ".claude/skills/dig-design-system/SKILL.md";
|
|
2230
2286
|
async function skillCommand() {
|
|
2231
2287
|
const cwd = process.cwd();
|
|
@@ -2238,21 +2294,21 @@ async function skillCommand() {
|
|
|
2238
2294
|
throw new DigError(`\u0627\u062A\u0635\u0627\u0644 \u0628\u0647 ${url.origin} \u0628\u0631\u0627\u06CC \u06AF\u0631\u0641\u062A\u0646\u0650 Skill \u0628\u0631\u0642\u0631\u0627\u0631 \u0646\u0634\u062F.`);
|
|
2239
2295
|
}
|
|
2240
2296
|
if (!response.ok) throw new DigError(`Skill \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${response.status}`);
|
|
2241
|
-
const target =
|
|
2242
|
-
await mkdir4(
|
|
2297
|
+
const target = path13.join(cwd, SKILL_PATH);
|
|
2298
|
+
await mkdir4(path13.dirname(target), { recursive: true });
|
|
2243
2299
|
await writeFile6(target, await response.text(), "utf8");
|
|
2244
2300
|
console.log(`\u2713 ${SKILL_PATH} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC Claude Code).`);
|
|
2245
2301
|
}
|
|
2246
2302
|
|
|
2247
2303
|
// src/commands/tokens.ts
|
|
2248
|
-
import { mkdir as mkdir5, readFile as
|
|
2249
|
-
import
|
|
2304
|
+
import { mkdir as mkdir5, readFile as readFile10, writeFile as writeFile7 } from "fs/promises";
|
|
2305
|
+
import path14 from "path";
|
|
2250
2306
|
async function tokensCommand(options) {
|
|
2251
2307
|
const cwd = process.cwd();
|
|
2252
2308
|
const registryUrl = await configExists(cwd) ? (await readConfig(cwd)).registryUrl : defaultConfig().registryUrl;
|
|
2253
|
-
const designMd = await
|
|
2309
|
+
const designMd = await readFile10(path14.join(cwd, DESIGN_MD_FILE), "utf8").catch(() => "");
|
|
2254
2310
|
const brand = options.brand ?? readDesignMdSettings(designMd).brand;
|
|
2255
|
-
const outDir =
|
|
2311
|
+
const outDir = path14.join(cwd, options.out ?? "tokens");
|
|
2256
2312
|
await mkdir5(outDir, { recursive: true });
|
|
2257
2313
|
for (const mode of ["light", "dark"]) {
|
|
2258
2314
|
const url = new URL("/api/tokens", registryUrl);
|
|
@@ -2268,20 +2324,20 @@ async function tokensCommand(options) {
|
|
|
2268
2324
|
const body = await response.json().catch(() => null);
|
|
2269
2325
|
throw new DigError(`\u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u06AF\u0631\u0641\u062A\u0647 \u0646\u0634\u062F: ${body?.error ?? response.status}`);
|
|
2270
2326
|
}
|
|
2271
|
-
const file =
|
|
2327
|
+
const file = path14.join(outDir, `dig-${mode}.tokens.json`);
|
|
2272
2328
|
await writeFile7(file, await response.text(), "utf8");
|
|
2273
|
-
console.log(`\u2713 ${
|
|
2329
|
+
console.log(`\u2713 ${path14.relative(cwd, file)} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F${brand ? ` (\u0628\u0631\u0646\u062F ${brand})` : ""}.`);
|
|
2274
2330
|
}
|
|
2275
2331
|
console.log("\n\u062F\u0631 \u0641\u06CC\u06AF\u0645\u0627 \u0647\u0631 \u0641\u0627\u06CC\u0644 \u0631\u0627 \u06CC\u06A9 mode \u0627\u0632 Variables \u0648\u0627\u0631\u062F \u06A9\u0646\u06CC\u062F (\u0631\u0648\u0634\u0646 \u0648 \u062A\u06CC\u0631\u0647).");
|
|
2276
2332
|
}
|
|
2277
2333
|
|
|
2278
2334
|
// src/commands/init.ts
|
|
2279
|
-
import { readFile as
|
|
2280
|
-
import
|
|
2335
|
+
import { readFile as readFile13, writeFile as writeFile11 } from "fs/promises";
|
|
2336
|
+
import path19 from "path";
|
|
2281
2337
|
|
|
2282
2338
|
// src/lib/agent-instructions.ts
|
|
2283
|
-
import { mkdir as mkdir6, readFile as
|
|
2284
|
-
import
|
|
2339
|
+
import { mkdir as mkdir6, readFile as readFile11, writeFile as writeFile8 } from "fs/promises";
|
|
2340
|
+
import path15 from "path";
|
|
2285
2341
|
var AGENT_CLIENTS = [
|
|
2286
2342
|
{ value: "claude-code", label: "Claude Code (CLAUDE.md)" },
|
|
2287
2343
|
{ value: "codex", label: "Codex (AGENTS.md)" },
|
|
@@ -2333,25 +2389,94 @@ async function writeAgentInstructions(cwd, registryUrl, options) {
|
|
|
2333
2389
|
const files = await fetchSetupFiles(registryUrl, options);
|
|
2334
2390
|
const instructions = files.find((item) => /^[A-Z]+\.md$/.test(item.path) && item.path !== "DESIGN.md");
|
|
2335
2391
|
if (!instructions) throw new DigError("\u0641\u0627\u06CC\u0644\u0650 \u0627\u06CC\u062C\u0646\u062A \u062F\u0631 \u067E\u0627\u0633\u062E\u0650 \u0633\u0631\u0648\u0631 \u0646\u0628\u0648\u062F.");
|
|
2336
|
-
const target =
|
|
2337
|
-
const existing = await
|
|
2392
|
+
const target = path15.join(cwd, instructions.path);
|
|
2393
|
+
const existing = await readFile11(target, "utf8").catch(() => null);
|
|
2338
2394
|
await writeFile8(target, mergeInstructions(existing, instructions.content), "utf8");
|
|
2339
2395
|
console.log(
|
|
2340
2396
|
existing === null ? `\u2713 ${instructions.path} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (\u0627\u06CC\u062C\u0646\u062A \u0641\u0648\u0646\u062A \u0648 \u0631\u0646\u06AF \u0631\u0627 \u0627\u0632 \u0627\u06CC\u0646 \u0641\u0627\u06CC\u0644 \u0645\u06CC\u200C\u062E\u0648\u0627\u0646\u062F \u0648 \u062F\u0648\u0628\u0627\u0631\u0647 \u0646\u0645\u06CC\u200C\u067E\u0631\u0633\u062F).` : `\u2713 \u0628\u062E\u0634\u0650 \u062F\u06CC\u06AF \u062F\u0631 ${instructions.path} \u0628\u0647\u200C\u0631\u0648\u0632 \u0634\u062F\u061B \u0628\u0642\u06CC\u0647\u0654 \u0641\u0627\u06CC\u0644 \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`
|
|
2341
2397
|
);
|
|
2342
2398
|
const skill = files.find((item) => item.path.endsWith("/SKILL.md"));
|
|
2343
2399
|
if (skill) {
|
|
2344
|
-
const skillTarget =
|
|
2345
|
-
await mkdir6(
|
|
2400
|
+
const skillTarget = path15.join(cwd, skill.path);
|
|
2401
|
+
await mkdir6(path15.dirname(skillTarget), { recursive: true });
|
|
2346
2402
|
await writeFile8(skillTarget, skill.content, "utf8");
|
|
2347
2403
|
console.log(`\u2713 ${skill.path} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F (Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC \u0633\u0627\u062E\u062A\u0646\u0650 \u0635\u0641\u062D\u0647).`);
|
|
2348
2404
|
}
|
|
2349
2405
|
return instructions.path;
|
|
2350
2406
|
}
|
|
2351
2407
|
|
|
2352
|
-
// src/
|
|
2353
|
-
import {
|
|
2408
|
+
// src/lib/fonts.ts
|
|
2409
|
+
import { mkdir as mkdir7, writeFile as writeFile9 } from "fs/promises";
|
|
2354
2410
|
import path16 from "path";
|
|
2411
|
+
var WEIGHTS = [
|
|
2412
|
+
["Thin", 100],
|
|
2413
|
+
["UltraLight", 200],
|
|
2414
|
+
["Light", 300],
|
|
2415
|
+
["Regular", 400],
|
|
2416
|
+
["Medium", 500],
|
|
2417
|
+
["DemiBold", 600],
|
|
2418
|
+
["Bold", 700],
|
|
2419
|
+
["ExtraBold", 800],
|
|
2420
|
+
["Black", 900]
|
|
2421
|
+
];
|
|
2422
|
+
var YEKAN_WEIGHTS = [
|
|
2423
|
+
["Thin", 100],
|
|
2424
|
+
["Light", 300],
|
|
2425
|
+
["Regular", 400],
|
|
2426
|
+
["Medium", 500],
|
|
2427
|
+
["Bold", 700],
|
|
2428
|
+
["ExtraBold", 800],
|
|
2429
|
+
["Black", 900]
|
|
2430
|
+
];
|
|
2431
|
+
var VAZIR_URL = "https://cdn.jsdelivr.net/npm/@fontsource-variable/vazirmatn/files/vazirmatn-arabic-wght-normal.woff2";
|
|
2432
|
+
function fontPlan(font) {
|
|
2433
|
+
if (font === "yekan") {
|
|
2434
|
+
return { family: "IRANYekanFN", files: YEKAN_WEIGHTS.map(([n, weight]) => ({ file: `IRANYekan${n}.woff2`, weight })) };
|
|
2435
|
+
}
|
|
2436
|
+
if (font === "vazirmatn") return { family: "Vazirmatn", remote: VAZIR_URL };
|
|
2437
|
+
return { family: "IRANSansX", files: WEIGHTS.map(([n, weight]) => ({ file: `IRANSansXFaNum-${n}.woff2`, weight })) };
|
|
2438
|
+
}
|
|
2439
|
+
function fontFaceCss(font) {
|
|
2440
|
+
const plan = fontPlan(font);
|
|
2441
|
+
const header = "/* \u0641\u0648\u0646\u062A\u0650 \u0641\u0627\u0631\u0633\u06CC\u0650 \u067E\u0631\u0648\u0698\u0647\u061B \u0628\u0627 \xABdig init --font \u2026\xBB \u0633\u0627\u062E\u062A\u0647 \u0634\u062F. \u0644\u0646\u06AF\u0631 \u062F\u0631 brand.css \u06CC\u0627 dig-theme.css \u0627\u0633\u062A. */\n";
|
|
2442
|
+
if ("remote" in plan) {
|
|
2443
|
+
return `${header}@font-face {
|
|
2444
|
+
font-family: "${plan.family}";
|
|
2445
|
+
src: url("${plan.remote}") format("woff2");
|
|
2446
|
+
font-weight: 100 900;
|
|
2447
|
+
font-display: swap;
|
|
2448
|
+
}
|
|
2449
|
+
`;
|
|
2450
|
+
}
|
|
2451
|
+
return header + plan.files.map(
|
|
2452
|
+
({ file, weight }) => `@font-face {
|
|
2453
|
+
font-family: "${plan.family}";
|
|
2454
|
+
src: url("/fonts/${file}") format("woff2");
|
|
2455
|
+
font-weight: ${weight};
|
|
2456
|
+
font-display: swap;
|
|
2457
|
+
}
|
|
2458
|
+
`
|
|
2459
|
+
).join("");
|
|
2460
|
+
}
|
|
2461
|
+
async function installFonts(cwd, registryUrl, font, cssRel) {
|
|
2462
|
+
const plan = fontPlan(font);
|
|
2463
|
+
if ("files" in plan) {
|
|
2464
|
+
const dir = path16.join(cwd, "public", "fonts");
|
|
2465
|
+
await mkdir7(dir, { recursive: true });
|
|
2466
|
+
for (const { file } of plan.files) {
|
|
2467
|
+
const res = await fetch(new URL(`/fonts/${file}`, registryUrl));
|
|
2468
|
+
if (!res.ok) return false;
|
|
2469
|
+
await writeFile9(path16.join(dir, file), Buffer.from(await res.arrayBuffer()));
|
|
2470
|
+
}
|
|
2471
|
+
}
|
|
2472
|
+
const target = path16.join(cwd, cssRel);
|
|
2473
|
+
await mkdir7(path16.dirname(target), { recursive: true });
|
|
2474
|
+
await writeFile9(target, fontFaceCss(font), "utf8");
|
|
2475
|
+
return true;
|
|
2476
|
+
}
|
|
2477
|
+
|
|
2478
|
+
// src/lib/theme-files.ts
|
|
2479
|
+
import path17 from "path";
|
|
2355
2480
|
|
|
2356
2481
|
// src/lib/brand-ramp.ts
|
|
2357
2482
|
var RAMP_STEPS = [50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950];
|
|
@@ -2455,9 +2580,8 @@ function buildBrandRamp(hex) {
|
|
|
2455
2580
|
}
|
|
2456
2581
|
|
|
2457
2582
|
// src/lib/theme-files.ts
|
|
2458
|
-
import path15 from "path";
|
|
2459
2583
|
function importPath(fromFile, toFile) {
|
|
2460
|
-
const rel = toPosixPath(
|
|
2584
|
+
const rel = toPosixPath(path17.relative(path17.dirname(fromFile), toFile));
|
|
2461
2585
|
return rel.startsWith(".") ? rel : `./${rel}`;
|
|
2462
2586
|
}
|
|
2463
2587
|
function globalsCss(paths, extraStatements = []) {
|
|
@@ -2619,10 +2743,12 @@ function splitTheme(projectCss, digThemeCss) {
|
|
|
2619
2743
|
}
|
|
2620
2744
|
|
|
2621
2745
|
// src/commands/theme.ts
|
|
2746
|
+
import { access as access5, mkdir as mkdir8, readFile as readFile12, writeFile as writeFile10 } from "fs/promises";
|
|
2747
|
+
import path18 from "path";
|
|
2622
2748
|
var THEME_ITEM = "theme";
|
|
2623
2749
|
async function readIfExists2(target) {
|
|
2624
2750
|
try {
|
|
2625
|
-
return await
|
|
2751
|
+
return await readFile12(target, "utf8");
|
|
2626
2752
|
} catch {
|
|
2627
2753
|
return null;
|
|
2628
2754
|
}
|
|
@@ -2636,7 +2762,7 @@ async function exists(target) {
|
|
|
2636
2762
|
}
|
|
2637
2763
|
}
|
|
2638
2764
|
function themePaths(config) {
|
|
2639
|
-
const dir =
|
|
2765
|
+
const dir = path18.posix.dirname(toPosixPath(config.tailwind.css));
|
|
2640
2766
|
return {
|
|
2641
2767
|
css: config.tailwind.css,
|
|
2642
2768
|
theme: config.tailwind.theme ?? `${dir}/dig-theme.css`,
|
|
@@ -2670,9 +2796,9 @@ async function recordTheme(cwd, config, themeRel, item) {
|
|
|
2670
2796
|
await writeLock(lock, cwd);
|
|
2671
2797
|
}
|
|
2672
2798
|
async function writeText(cwd, rel, content) {
|
|
2673
|
-
const target =
|
|
2674
|
-
await
|
|
2675
|
-
await
|
|
2799
|
+
const target = path18.join(cwd, rel);
|
|
2800
|
+
await mkdir8(path18.dirname(target), { recursive: true });
|
|
2801
|
+
await writeFile10(target, content, "utf8");
|
|
2676
2802
|
}
|
|
2677
2803
|
async function installTheme(cwd, config, options) {
|
|
2678
2804
|
const paths = themePaths(config);
|
|
@@ -2680,7 +2806,7 @@ async function installTheme(cwd, config, options) {
|
|
|
2680
2806
|
const ramp = options.brand ? buildBrandRamp(options.brand) : void 0;
|
|
2681
2807
|
await writeText(cwd, paths.theme, item.content);
|
|
2682
2808
|
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).`);
|
|
2683
|
-
const existingBrand = await readIfExists2(
|
|
2809
|
+
const existingBrand = await readIfExists2(path18.join(cwd, paths.brand));
|
|
2684
2810
|
if (existingBrand === null) {
|
|
2685
2811
|
await writeText(cwd, paths.brand, brandCss({ ramp, hex: options.brand }));
|
|
2686
2812
|
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).`);
|
|
@@ -2691,10 +2817,10 @@ async function installTheme(cwd, config, options) {
|
|
|
2691
2817
|
console.log(`- ${paths.brand} \u0627\u0632 \u0642\u0628\u0644 \u0647\u0633\u062A\u061B \u062F\u0633\u062A \u0646\u062E\u0648\u0631\u062F.`);
|
|
2692
2818
|
}
|
|
2693
2819
|
if (ramp) reportContrast(ramp.primaryContrast);
|
|
2694
|
-
const cssTarget =
|
|
2820
|
+
const cssTarget = path18.join(cwd, paths.css);
|
|
2695
2821
|
const existingCss = await readIfExists2(cssTarget);
|
|
2696
2822
|
if (!isBoilerplateCss(existingCss) && existingCss !== null) {
|
|
2697
|
-
await
|
|
2823
|
+
await writeFile10(`${cssTarget}.backup`, existingCss, "utf8");
|
|
2698
2824
|
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.`);
|
|
2699
2825
|
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.`);
|
|
2700
2826
|
}
|
|
@@ -2727,11 +2853,11 @@ async function themeSplitCommand(options) {
|
|
|
2727
2853
|
return;
|
|
2728
2854
|
}
|
|
2729
2855
|
const paths = themePaths(config);
|
|
2730
|
-
const current = await readIfExists2(
|
|
2856
|
+
const current = await readIfExists2(path18.join(cwd, paths.css));
|
|
2731
2857
|
if (current === null || isBoilerplateCss(current)) {
|
|
2732
2858
|
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.`);
|
|
2733
2859
|
}
|
|
2734
|
-
if (await exists(
|
|
2860
|
+
if (await exists(path18.join(cwd, paths.brand))) {
|
|
2735
2861
|
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.`);
|
|
2736
2862
|
}
|
|
2737
2863
|
console.log(`\u062F\u0631\u06CC\u0627\u0641\u062A\u0650 \u062A\u0645\u0650 \u062F\u06CC\u06AF \u0627\u0632 ${config.registryUrl} \u2026`);
|
|
@@ -2750,7 +2876,7 @@ ${split.changed} \u062A\u0648\u06A9\u0646\u0650 \u0639\u0648\u0636\u200C\u0634\u
|
|
|
2750
2876
|
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)");
|
|
2751
2877
|
return;
|
|
2752
2878
|
}
|
|
2753
|
-
await
|
|
2879
|
+
await writeFile10(path18.join(cwd, `${paths.css}.backup`), current, "utf8");
|
|
2754
2880
|
await writeText(cwd, paths.theme, item.content);
|
|
2755
2881
|
await writeText(cwd, paths.brand, brandCss({ body: split.body }));
|
|
2756
2882
|
await writeText(cwd, paths.css, globalsCss(paths, split.extraStatements));
|
|
@@ -2774,7 +2900,7 @@ async function themeBrandCommand(hex) {
|
|
|
2774
2900
|
}
|
|
2775
2901
|
const paths = themePaths(config);
|
|
2776
2902
|
const ramp = buildBrandRamp(hex);
|
|
2777
|
-
const existing = await readIfExists2(
|
|
2903
|
+
const existing = await readIfExists2(path18.join(cwd, paths.brand)) ?? brandCss({});
|
|
2778
2904
|
const next = replaceBrandRamp(existing, ramp, hex);
|
|
2779
2905
|
await writeText(cwd, paths.brand, next);
|
|
2780
2906
|
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).`);
|
|
@@ -2792,14 +2918,14 @@ async function themeBrandCommand(hex) {
|
|
|
2792
2918
|
// src/commands/init.ts
|
|
2793
2919
|
async function readIfExists3(target) {
|
|
2794
2920
|
try {
|
|
2795
|
-
return await
|
|
2921
|
+
return await readFile13(target, "utf8");
|
|
2796
2922
|
} catch {
|
|
2797
2923
|
return null;
|
|
2798
2924
|
}
|
|
2799
2925
|
}
|
|
2800
2926
|
async function writeTheme(config, cwd, options) {
|
|
2801
2927
|
const paths = themePaths(config);
|
|
2802
|
-
const existing = await readIfExists3(
|
|
2928
|
+
const existing = await readIfExists3(path19.join(cwd, paths.css));
|
|
2803
2929
|
if (!isBoilerplateCss(existing) && !options.yes) {
|
|
2804
2930
|
console.log(`
|
|
2805
2931
|
${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u062F\u0627\u0631\u062F.`);
|
|
@@ -2820,11 +2946,37 @@ ${paths.css} \u0627\u0632 \u0642\u0628\u0644 \u0645\u062D\u062A\u0648\u0627 \u06
|
|
|
2820
2946
|
\u0646\u0635\u0628 \u0648\u0627\u0628\u0633\u062A\u06AF\u06CC\u200C\u0647\u0627\u06CC \u062A\u0645 \u0628\u0627 ${pm} \u2026`);
|
|
2821
2947
|
await installDependencies(pm, item.dependencies, { cwd });
|
|
2822
2948
|
}
|
|
2949
|
+
await writeFonts(cwd, config, paths, options.font);
|
|
2823
2950
|
return "written";
|
|
2824
2951
|
}
|
|
2952
|
+
async function writeFonts(cwd, config, paths, font) {
|
|
2953
|
+
const fontsCss = `${path19.posix.dirname(paths.css.split(path19.sep).join("/"))}/dig-fonts.css`;
|
|
2954
|
+
const ok = await installFonts(cwd, config.registryUrl, font, fontsCss).catch(() => false);
|
|
2955
|
+
if (!ok) {
|
|
2956
|
+
console.log("- \u0641\u0627\u06CC\u0644\u200C\u0647\u0627\u06CC \u0641\u0648\u0646\u062A \u062F\u0627\u0646\u0644\u0648\u062F \u0646\u0634\u062F\u061B \u0628\u0639\u062F\u0627\u064B \xABdig init\xBB \u0631\u0627 \u062F\u0648\u0628\u0627\u0631\u0647 \u0627\u062C\u0631\u0627 \u06A9\u0646\u06CC\u062F (\u062A\u0627 \u0622\u0646 \u0645\u0648\u0642\u0639 \u0641\u0648\u0646\u062A\u0650 \u0633\u06CC\u0633\u062A\u0645 \u0645\u06CC\u200C\u0646\u0634\u06CC\u0646\u062F).");
|
|
2957
|
+
return;
|
|
2958
|
+
}
|
|
2959
|
+
const fontStatement = `@import "${importPath(paths.css, fontsCss)}";`;
|
|
2960
|
+
await writeFile11(path19.join(cwd, paths.css), globalsCss(paths, [fontStatement]), "utf8");
|
|
2961
|
+
console.log(`\u2713 \u0641\u0648\u0646\u062A\u0650 ${fontPlan(font).family} \u062F\u0631 ${fontsCss} \u0648 public/fonts \u0646\u0635\u0628 \u0634\u062F.`);
|
|
2962
|
+
if (font && font !== "iransans") {
|
|
2963
|
+
const brandPath = path19.join(cwd, paths.brand);
|
|
2964
|
+
const brand = await readIfExists3(brandPath) ?? "";
|
|
2965
|
+
await writeFile11(
|
|
2966
|
+
brandPath,
|
|
2967
|
+
`${brand.trimEnd()}
|
|
2968
|
+
|
|
2969
|
+
:root {
|
|
2970
|
+
--font-anchor: "${fontPlan(font).family}";
|
|
2971
|
+
}
|
|
2972
|
+
`,
|
|
2973
|
+
"utf8"
|
|
2974
|
+
);
|
|
2975
|
+
}
|
|
2976
|
+
}
|
|
2825
2977
|
async function applyRtl(cwd) {
|
|
2826
2978
|
for (const candidate of ["src/app/layout.tsx", "app/layout.tsx"]) {
|
|
2827
|
-
const target =
|
|
2979
|
+
const target = path19.join(cwd, candidate);
|
|
2828
2980
|
const source = await readIfExists3(target);
|
|
2829
2981
|
if (source === null) continue;
|
|
2830
2982
|
if (/<html[^>]*\sdir=/.test(source)) {
|
|
@@ -2837,7 +2989,7 @@ async function applyRtl(cwd) {
|
|
|
2837
2989
|
match[0],
|
|
2838
2990
|
`<html${match[1]} dir="rtl">`.replace(/\s+dir="rtl">$/, ' dir="rtl">')
|
|
2839
2991
|
);
|
|
2840
|
-
await
|
|
2992
|
+
await writeFile11(target, updated, "utf8");
|
|
2841
2993
|
console.log(`\u2713 dir="rtl" \u0628\u0647 ${candidate} \u0627\u0636\u0627\u0641\u0647 \u0634\u062F.`);
|
|
2842
2994
|
return;
|
|
2843
2995
|
}
|
|
@@ -2856,7 +3008,14 @@ async function askProjectDecisions(options) {
|
|
|
2856
3008
|
}
|
|
2857
3009
|
async function initCommand(options) {
|
|
2858
3010
|
const cwd = process.cwd();
|
|
3011
|
+
const framework = await resolveFramework(cwd, void 0, options.framework);
|
|
2859
3012
|
const base = defaultConfig();
|
|
3013
|
+
if (framework === "vue") {
|
|
3014
|
+
const css = await readIfExists3(path19.join(cwd, "src/assets/main.css")) !== null ? "src/assets/main.css" : "src/style.css";
|
|
3015
|
+
const dir = path19.posix.dirname(css);
|
|
3016
|
+
base.framework = "vue";
|
|
3017
|
+
base.tailwind = { ...base.tailwind, css, theme: `${dir}/dig-theme.css`, brand: `${dir}/brand.css` };
|
|
3018
|
+
}
|
|
2860
3019
|
if (await configExists(cwd)) {
|
|
2861
3020
|
const overwrite = options.yes || await confirm("dig.json \u0627\u0632 \u0642\u0628\u0644 \u0648\u062C\u0648\u062F \u062F\u0627\u0631\u062F. \u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC \u0634\u0648\u062F\u061F", false);
|
|
2862
3021
|
if (!overwrite) {
|
|
@@ -2869,16 +3028,18 @@ async function initCommand(options) {
|
|
|
2869
3028
|
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),
|
|
2870
3029
|
tailwind: await (async () => {
|
|
2871
3030
|
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);
|
|
2872
|
-
const dir =
|
|
3031
|
+
const dir = path19.posix.dirname(css.split(path19.sep).join("/"));
|
|
2873
3032
|
return { ...base.tailwind, css, theme: `${dir}/dig-theme.css`, brand: `${dir}/brand.css` };
|
|
2874
3033
|
})()
|
|
2875
3034
|
};
|
|
2876
3035
|
const decisions = await askProjectDecisions(options);
|
|
2877
3036
|
options = { ...options, brand: decisions.brand };
|
|
2878
3037
|
await writeConfig(config, cwd);
|
|
2879
|
-
console.log(`\u2713 ${
|
|
2880
|
-
const theme2 = await writeTheme(config, cwd, options);
|
|
2881
|
-
if (config.rtl) {
|
|
3038
|
+
console.log(`\u2713 ${path19.join(cwd, "dig.json")} \u0646\u0648\u0634\u062A\u0647 \u0634\u062F.`);
|
|
3039
|
+
const theme2 = await writeTheme(config, cwd, { ...options, font: decisions.font });
|
|
3040
|
+
if (config.rtl && framework === "vue") {
|
|
3041
|
+
console.log('- dir="rtl" \u0631\u0627 \u062E\u0648\u062F\u062A\u0627\u0646 \u0631\u0648\u06CC \u062A\u06AF <html> \u062F\u0631 index.html \u0628\u06AF\u0630\u0627\u0631\u06CC\u062F (Vue \u0686\u06CC\u062F\u0645\u0627\u0646\u0650 \u0631\u06CC\u0634\u0647\u200C\u0627\u06CC \u0646\u062F\u0627\u0631\u062F \u06A9\u0647 \u062E\u0648\u062F\u06A9\u0627\u0631 \u062F\u0633\u062A \u0628\u062E\u0648\u0631\u062F).');
|
|
3042
|
+
} else if (config.rtl) {
|
|
2882
3043
|
await applyRtl(cwd);
|
|
2883
3044
|
}
|
|
2884
3045
|
await writeDesignMd(cwd, config.registryUrl, { brand: decisions.brand, font: decisions.font }).catch((error) => {
|
|
@@ -2901,8 +3062,8 @@ async function initCommand(options) {
|
|
|
2901
3062
|
}
|
|
2902
3063
|
|
|
2903
3064
|
// src/lib/migration-apply.ts
|
|
2904
|
-
import { readFile as
|
|
2905
|
-
import
|
|
3065
|
+
import { readFile as readFile14, writeFile as writeFile12 } from "fs/promises";
|
|
3066
|
+
import path20 from "path";
|
|
2906
3067
|
|
|
2907
3068
|
// src/lib/migration-strategy.ts
|
|
2908
3069
|
var TextReplaceStrategy = class {
|
|
@@ -2979,7 +3140,7 @@ function looksBinary2(buffer) {
|
|
|
2979
3140
|
async function readTextFileSafely2(target) {
|
|
2980
3141
|
let buffer;
|
|
2981
3142
|
try {
|
|
2982
|
-
buffer = await
|
|
3143
|
+
buffer = await readFile14(target);
|
|
2983
3144
|
} catch (error) {
|
|
2984
3145
|
if (error.code === "ENOENT") return void 0;
|
|
2985
3146
|
throw error;
|
|
@@ -3024,8 +3185,8 @@ async function planOrApplyMigrations(params) {
|
|
|
3024
3185
|
};
|
|
3025
3186
|
}
|
|
3026
3187
|
const fileTargets = registryItem.files.map((file) => {
|
|
3027
|
-
const target =
|
|
3028
|
-
return { relPath: toPosixPath(
|
|
3188
|
+
const target = path20.join(cwd, resolveTargetPath(file.path, aliases, paths));
|
|
3189
|
+
return { relPath: toPosixPath(path20.relative(cwd, target)), target };
|
|
3029
3190
|
});
|
|
3030
3191
|
const currentContents = /* @__PURE__ */ new Map();
|
|
3031
3192
|
for (const ft of fileTargets) {
|
|
@@ -3091,12 +3252,12 @@ async function planOrApplyMigrations(params) {
|
|
|
3091
3252
|
const written = [];
|
|
3092
3253
|
try {
|
|
3093
3254
|
for (const item of pending) {
|
|
3094
|
-
await
|
|
3255
|
+
await writeFile12(item.target, item.newContent, "utf8");
|
|
3095
3256
|
written.push(item);
|
|
3096
3257
|
}
|
|
3097
3258
|
} catch (error) {
|
|
3098
3259
|
for (const item of written) {
|
|
3099
|
-
await
|
|
3260
|
+
await writeFile12(item.target, item.originalContent, "utf8");
|
|
3100
3261
|
}
|
|
3101
3262
|
return {
|
|
3102
3263
|
name,
|
|
@@ -3154,7 +3315,7 @@ async function runPlan(components, options) {
|
|
|
3154
3315
|
continue;
|
|
3155
3316
|
}
|
|
3156
3317
|
try {
|
|
3157
|
-
const item = await fetchRegistryItem(name, config.registryUrl);
|
|
3318
|
+
const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
|
|
3158
3319
|
const toVersion = item.version ?? "0.0.0";
|
|
3159
3320
|
const migrations = getApplicableMigrations(
|
|
3160
3321
|
parseMigrations(name, item.migrations),
|
|
@@ -3225,7 +3386,7 @@ async function runApplyOrDryRun(components, options, dryRun) {
|
|
|
3225
3386
|
for (const name of components) {
|
|
3226
3387
|
let registryItem;
|
|
3227
3388
|
try {
|
|
3228
|
-
registryItem = await fetchRegistryItem(name, config.registryUrl);
|
|
3389
|
+
registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
|
|
3229
3390
|
} catch (error) {
|
|
3230
3391
|
console.error(`\u2717 ${name}: ${error.message}`);
|
|
3231
3392
|
continue;
|
|
@@ -3420,7 +3581,7 @@ ${message}`);
|
|
|
3420
3581
|
}
|
|
3421
3582
|
let item;
|
|
3422
3583
|
try {
|
|
3423
|
-
item = await fetchRegistryItem(component, config.registryUrl);
|
|
3584
|
+
item = await fetchRegistryItem(component, config.registryUrl, config.framework);
|
|
3424
3585
|
} catch (error) {
|
|
3425
3586
|
console.error(`\u2717 ${component}: ${error.message}`);
|
|
3426
3587
|
return;
|
|
@@ -3508,7 +3669,7 @@ async function releaseCommand(components, options) {
|
|
|
3508
3669
|
const entries = [];
|
|
3509
3670
|
for (const name of components) {
|
|
3510
3671
|
try {
|
|
3511
|
-
const item = await fetchRegistryItem(name, config.registryUrl);
|
|
3672
|
+
const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
|
|
3512
3673
|
const version = item.version ?? "0.0.0";
|
|
3513
3674
|
entries.push({
|
|
3514
3675
|
name,
|
|
@@ -3615,7 +3776,7 @@ async function statusCommand(components, options) {
|
|
|
3615
3776
|
const entries = [];
|
|
3616
3777
|
for (const name of components) {
|
|
3617
3778
|
try {
|
|
3618
|
-
const item = await fetchRegistryItem(name, config.registryUrl);
|
|
3779
|
+
const item = await fetchRegistryItem(name, config.registryUrl, config.framework);
|
|
3619
3780
|
const version = item.version ?? "0.0.0";
|
|
3620
3781
|
const lifecycle = parseLifecycle(name, version, item.deprecation);
|
|
3621
3782
|
const release = parseRelease(name, version, item.release);
|
|
@@ -3709,7 +3870,7 @@ ${entry.migrationHint}`);
|
|
|
3709
3870
|
|
|
3710
3871
|
// src/lib/missing-dependencies.ts
|
|
3711
3872
|
import { access as access6 } from "fs/promises";
|
|
3712
|
-
import
|
|
3873
|
+
import path21 from "path";
|
|
3713
3874
|
async function exists2(target) {
|
|
3714
3875
|
try {
|
|
3715
3876
|
await access6(target);
|
|
@@ -3725,12 +3886,12 @@ async function findMissingDependencies(params) {
|
|
|
3725
3886
|
...new Set(items.flatMap((item) => item.registryDependencies ?? []))
|
|
3726
3887
|
].filter((name) => !requested.has(name));
|
|
3727
3888
|
if (direct.length === 0) return [];
|
|
3728
|
-
const tree = await resolveRegistryTree(direct, config.registryUrl);
|
|
3889
|
+
const tree = await resolveRegistryTree(direct, config.registryUrl, config.framework);
|
|
3729
3890
|
const missing = [];
|
|
3730
3891
|
for (const item of tree.values()) {
|
|
3731
3892
|
if (requested.has(item.name) || lock.components[item.name]) continue;
|
|
3732
3893
|
for (const file of item.files) {
|
|
3733
|
-
const target =
|
|
3894
|
+
const target = path21.join(
|
|
3734
3895
|
cwd,
|
|
3735
3896
|
resolveTargetPath(file.path, config.aliases, targetPathOptions(config))
|
|
3736
3897
|
);
|
|
@@ -3744,8 +3905,8 @@ async function findMissingDependencies(params) {
|
|
|
3744
3905
|
}
|
|
3745
3906
|
|
|
3746
3907
|
// src/lib/update.ts
|
|
3747
|
-
import { mkdir as
|
|
3748
|
-
import
|
|
3908
|
+
import { mkdir as mkdir9, readFile as readFile15, rm as rm2, writeFile as writeFile13 } from "fs/promises";
|
|
3909
|
+
import path22 from "path";
|
|
3749
3910
|
function safeFileIndexes(drift) {
|
|
3750
3911
|
const indexes = [];
|
|
3751
3912
|
drift.files.forEach((file, index) => {
|
|
@@ -3765,7 +3926,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
|
|
|
3765
3926
|
for (const index of safeIndexes) {
|
|
3766
3927
|
const file = drift.files[index];
|
|
3767
3928
|
const registryFile = registryItem.files[index];
|
|
3768
|
-
const target =
|
|
3929
|
+
const target = path22.join(cwd, resolveTargetPath(registryFile.path, aliases, paths));
|
|
3769
3930
|
const isNewFile = file.status === "new_upstream";
|
|
3770
3931
|
pending.push({
|
|
3771
3932
|
index,
|
|
@@ -3773,14 +3934,14 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
|
|
|
3773
3934
|
newContent: registryFile.content,
|
|
3774
3935
|
newHash: registryFile.hash ?? hashContent(registryFile.content),
|
|
3775
3936
|
isNewFile,
|
|
3776
|
-
originalContent: isNewFile ? void 0 : await
|
|
3937
|
+
originalContent: isNewFile ? void 0 : await readFile15(target, "utf8")
|
|
3777
3938
|
});
|
|
3778
3939
|
}
|
|
3779
3940
|
const written = [];
|
|
3780
3941
|
try {
|
|
3781
3942
|
for (const item of pending) {
|
|
3782
|
-
if (item.isNewFile) await
|
|
3783
|
-
await
|
|
3943
|
+
if (item.isNewFile) await mkdir9(path22.dirname(item.target), { recursive: true });
|
|
3944
|
+
await writeFile13(item.target, item.newContent, "utf8");
|
|
3784
3945
|
written.push(item);
|
|
3785
3946
|
}
|
|
3786
3947
|
} catch (error) {
|
|
@@ -3788,7 +3949,7 @@ async function applySafeFiles(cwd, aliases, drift, registryItem, dryRun, paths)
|
|
|
3788
3949
|
if (item.isNewFile) {
|
|
3789
3950
|
await rm2(item.target, { force: true });
|
|
3790
3951
|
} else {
|
|
3791
|
-
await
|
|
3952
|
+
await writeFile13(item.target, item.originalContent, "utf8");
|
|
3792
3953
|
}
|
|
3793
3954
|
}
|
|
3794
3955
|
return { actions, writtenHashes: {}, rollbackError: error.message };
|
|
@@ -3882,7 +4043,7 @@ async function updateCommand(components, options) {
|
|
|
3882
4043
|
for (const name of components) {
|
|
3883
4044
|
let registryItem;
|
|
3884
4045
|
try {
|
|
3885
|
-
registryItem = await fetchRegistryItem(name, config.registryUrl);
|
|
4046
|
+
registryItem = await fetchRegistryItem(name, config.registryUrl, config.framework);
|
|
3886
4047
|
} catch (error) {
|
|
3887
4048
|
console.error(`\u2717 ${name}: ${error.message}`);
|
|
3888
4049
|
continue;
|
|
@@ -4116,7 +4277,7 @@ var program = new Command();
|
|
|
4116
4277
|
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);
|
|
4117
4278
|
program.command("init").description(
|
|
4118
4279
|
'\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 dir="rtl"\u060C DESIGN.md \u0648 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC\u0650 \u0627\u06CC\u062C\u0646\u062A'
|
|
4119
|
-
).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").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--agent <agent>", "\u0627\u06CC\u062C\u0646\u062A: claude-code\u060C codex\u060C cursor\u060C vscode \u06CC\u0627 gemini (\u0646\u0627\u0645\u0650 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC \u0631\u0627 \u062A\u0639\u06CC\u06CC\u0646 \u0645\u06CC\u200C\u06A9\u0646\u062F)").action(initCommand);
|
|
4280
|
+
).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").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--agent <agent>", "\u0627\u06CC\u062C\u0646\u062A: claude-code\u060C codex\u060C cursor\u060C vscode \u06CC\u0627 gemini (\u0646\u0627\u0645\u0650 \u0641\u0627\u06CC\u0644\u0650 \u062F\u0633\u062A\u0648\u0631\u0650 \u06A9\u0627\u0631\u06CC \u0631\u0627 \u062A\u0639\u06CC\u06CC\u0646 \u0645\u06CC\u200C\u06A9\u0646\u062F)").option("--framework <framework>", "react \u06CC\u0627 vue\u061B \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0627\u0632 package.json \u062D\u062F\u0633 \u0632\u062F\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F").action(initCommand);
|
|
4120
4281
|
program.command("tokens").description("\u062A\u0648\u06A9\u0646\u200C\u0647\u0627\u06CC \u062F\u06CC\u06AF \u062F\u0631 \u0642\u0627\u0644\u0628\u0650 \u0627\u0633\u062A\u0627\u0646\u062F\u0627\u0631\u062F\u0650 DTCG \u0628\u0631\u0627\u06CC \u0641\u06CC\u06AF\u0645\u0627 \u0648 \u0627\u0628\u0632\u0627\u0631\u0647\u0627\u06CC \u0637\u0631\u0627\u062D\u06CC\u060C \u06CC\u06A9 \u0641\u0627\u06CC\u0644 \u0628\u0631\u0627\u06CC \u0647\u0631 \u062D\u0627\u0644\u062A").option("--brand <hex>", "\u0631\u0646\u06AF \u0628\u0631\u0646\u062F\u061B \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0627\u0632 DESIGN.md\u0650 \u067E\u0631\u0648\u0698\u0647").option("--out <dir>", "\u067E\u0648\u0634\u0647\u0654 \u062E\u0631\u0648\u062C\u06CC (\u067E\u06CC\u0634\u200C\u0641\u0631\u0636 tokens)").action(tokensCommand);
|
|
4121
4282
|
program.command("skill").description("\u06AF\u0630\u0627\u0634\u062A\u0646 \u06CC\u0627 \u0628\u0647\u200C\u0631\u0648\u0632\u06A9\u0631\u062F\u0646\u0650 Skill\u0650 \u0631\u0633\u0645\u06CC\u0650 \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC Claude Code \u062F\u0631 .claude/skills").action(skillCommand);
|
|
4122
4283
|
program.command("design-md").description("\u0633\u0627\u062E\u062A\u0646\u0650 DESIGN.md \u062F\u0631 \u0631\u06CC\u0634\u0647\u0654 \u067E\u0631\u0648\u0698\u0647: \u062A\u0648\u06A9\u0646\u200C\u0647\u0627 \u0648 \u0642\u0627\u0639\u062F\u0647\u200C\u0647\u0627\u06CC \u062F\u06CC\u06AF \u0628\u0631\u0627\u06CC \u0627\u06CC\u062C\u0646\u062A\u200C\u0647\u0627\u06CC \u06A9\u062F\u0646\u0648\u06CC\u0633").option("--brand <hex>", "\u0631\u0646\u06AF \u0628\u0631\u0646\u062F \u062A\u0627 \u0631\u0646\u06AF\u200C\u0647\u0627\u06CC \u0648\u0627\u0642\u0639\u06CC\u0650 \u0628\u0631\u0646\u062F \u062F\u0631 \u0641\u0627\u06CC\u0644 \u0628\u06CC\u0627\u06CC\u062F\u060C \u0645\u062B\u0644 #2C4C5B").option("--secondary <hex>", "\u0631\u0646\u06AF \u062F\u0648\u0645\u0650 \u0628\u0631\u0646\u062F").option("--name <name>", "\u0646\u0627\u0645 \u0645\u062D\u0635\u0648\u0644").option("--font <font>", "\u0641\u0648\u0646\u062A: iransans\u060C yekan \u06CC\u0627 vazirmatn").option("--radius <radius>", "\u0634\u0639\u0627\u0639: none\u060C sm\u060C md\u060C lg\u060C xl \u06CC\u0627 full").option("--force", "\u0628\u0627\u0632\u0646\u0648\u06CC\u0633\u06CC\u0650 DESIGN.md\u0650 \u062F\u0633\u062A\u200C\u0646\u0648\u0634\u062A\u0647", false).action(designMdCommand);
|
|
@@ -4125,7 +4286,7 @@ var theme = program.command("theme").description("\u062A\u0645 \u0648 \u0628\u06
|
|
|
4125
4286
|
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);
|
|
4126
4287
|
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);
|
|
4127
4288
|
program.command("mcp").description("\u0633\u0631\u0648\u0631 MCP \u062F\u06CC\u06AF \u0628\u0647 \u0634\u06A9\u0644 \u0633\u0631\u0648\u0631 \u0645\u062D\u0644\u06CC stdio\u060C \u0628\u0631\u0627\u06CC \u06A9\u0644\u0627\u06CC\u0646\u062A\u200C\u0647\u0627\u06CC\u06CC \u06A9\u0647 \u0622\u062F\u0631\u0633 HTTP \u0646\u0645\u06CC\u200C\u06AF\u06CC\u0631\u0646\u062F").option("--url <url>", "\u0622\u062F\u0631\u0633 \u0633\u0631\u0648\u0631 MCP (\u067E\u06CC\u0634\u200C\u0641\u0631\u0636 https://docs.digdesign.ir/api/mcp)").action(mcpCommand);
|
|
4128
|
-
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);
|
|
4289
|
+
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").option("--framework <framework>", "react \u06CC\u0627 vue\u061B \u067E\u06CC\u0634\u200C\u0641\u0631\u0636 \u0627\u0632 dig.json \u0648 \u0628\u0639\u062F package.json (\u0648\u0627\u0628\u0633\u062A\u06AF\u06CC vue \u06CC\u0639\u0646\u06CC Vue) \u062D\u062F\u0633 \u0632\u062F\u0647 \u0645\u06CC\u200C\u0634\u0648\u062F").action(addCommand);
|
|
4129
4290
|
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);
|
|
4130
4291
|
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);
|
|
4131
4292
|
program.command("diff").description(
|