@designtools/codesurface 0.1.9 → 0.1.10
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/cli.js +320 -25
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -41,8 +41,25 @@ async function detectFramework(projectRoot) {
|
|
|
41
41
|
componentDirCandidates = ["components/ui", "src/components/ui"];
|
|
42
42
|
}
|
|
43
43
|
const appResult = await findDir(projectRoot, appDirCandidates);
|
|
44
|
-
|
|
45
|
-
|
|
44
|
+
let componentResult = await findDir(projectRoot, componentDirCandidates);
|
|
45
|
+
let componentFileCount = componentResult.exists ? await countComponentFiles(projectRoot, componentResult.dir) : 0;
|
|
46
|
+
let fallbackComponentDirs = [];
|
|
47
|
+
if (!componentResult.exists) {
|
|
48
|
+
fallbackComponentDirs = await scanForComponentDirs(projectRoot);
|
|
49
|
+
if (fallbackComponentDirs.length > 0) {
|
|
50
|
+
const best = fallbackComponentDirs[0];
|
|
51
|
+
componentResult = { dir: best.dir, exists: true };
|
|
52
|
+
componentFileCount = best.fileCount;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
let cssFiles = await findCssFiles(projectRoot);
|
|
56
|
+
let fallbackCssFiles = [];
|
|
57
|
+
if (cssFiles.length === 0) {
|
|
58
|
+
fallbackCssFiles = await scanForCssFiles(projectRoot);
|
|
59
|
+
if (fallbackCssFiles.length > 0) {
|
|
60
|
+
cssFiles = fallbackCssFiles;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
46
63
|
return {
|
|
47
64
|
name,
|
|
48
65
|
appDir: appResult.dir,
|
|
@@ -50,7 +67,9 @@ async function detectFramework(projectRoot) {
|
|
|
50
67
|
componentDir: componentResult.dir,
|
|
51
68
|
componentDirExists: componentResult.exists,
|
|
52
69
|
componentFileCount,
|
|
53
|
-
cssFiles
|
|
70
|
+
cssFiles,
|
|
71
|
+
fallbackComponentDirs,
|
|
72
|
+
fallbackCssFiles
|
|
54
73
|
};
|
|
55
74
|
}
|
|
56
75
|
async function findDir(root, candidates) {
|
|
@@ -64,11 +83,11 @@ async function findDir(root, candidates) {
|
|
|
64
83
|
}
|
|
65
84
|
return { dir: candidates[0], exists: false };
|
|
66
85
|
}
|
|
67
|
-
async function
|
|
86
|
+
async function countComponentFiles(root, dir) {
|
|
68
87
|
const full = path.join(root, dir);
|
|
69
88
|
try {
|
|
70
89
|
const entries = await fs.readdir(full);
|
|
71
|
-
return entries.filter((e) => e.endsWith(
|
|
90
|
+
return entries.filter((e) => e.endsWith(".tsx") || e.endsWith(".jsx")).length;
|
|
72
91
|
} catch {
|
|
73
92
|
return 0;
|
|
74
93
|
}
|
|
@@ -93,6 +112,98 @@ async function findCssFiles(projectRoot) {
|
|
|
93
112
|
}
|
|
94
113
|
return found;
|
|
95
114
|
}
|
|
115
|
+
var COMPONENT_SCAN_DIRS = [
|
|
116
|
+
"components",
|
|
117
|
+
"src/components",
|
|
118
|
+
"lib",
|
|
119
|
+
"src/lib",
|
|
120
|
+
"ui",
|
|
121
|
+
"src/ui"
|
|
122
|
+
];
|
|
123
|
+
async function scanForComponentDirs(projectRoot) {
|
|
124
|
+
const results = [];
|
|
125
|
+
for (const parentDir of COMPONENT_SCAN_DIRS) {
|
|
126
|
+
const fullParent = path.join(projectRoot, parentDir);
|
|
127
|
+
let stat;
|
|
128
|
+
try {
|
|
129
|
+
stat = await fs.stat(fullParent);
|
|
130
|
+
} catch {
|
|
131
|
+
continue;
|
|
132
|
+
}
|
|
133
|
+
if (!stat.isDirectory()) continue;
|
|
134
|
+
const hits = await countDataSlotFiles(fullParent);
|
|
135
|
+
if (hits > 0) {
|
|
136
|
+
results.push({ dir: parentDir, fileCount: hits });
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
const entries = await fs.readdir(fullParent, { withFileTypes: true });
|
|
140
|
+
for (const entry of entries) {
|
|
141
|
+
if (!entry.isDirectory()) continue;
|
|
142
|
+
const subDir = path.join(parentDir, entry.name);
|
|
143
|
+
const subHits = await countDataSlotFiles(path.join(projectRoot, subDir));
|
|
144
|
+
if (subHits > 0) {
|
|
145
|
+
results.push({ dir: subDir, fileCount: subHits });
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
} catch {
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
results.sort((a, b3) => b3.fileCount - a.fileCount);
|
|
152
|
+
return results;
|
|
153
|
+
}
|
|
154
|
+
async function countDataSlotFiles(dirPath) {
|
|
155
|
+
let count = 0;
|
|
156
|
+
try {
|
|
157
|
+
const files = await fs.readdir(dirPath);
|
|
158
|
+
for (const file of files) {
|
|
159
|
+
if (!file.endsWith(".tsx") && !file.endsWith(".jsx")) continue;
|
|
160
|
+
try {
|
|
161
|
+
const content = await fs.readFile(path.join(dirPath, file), "utf-8");
|
|
162
|
+
if (content.includes("data-slot")) {
|
|
163
|
+
count++;
|
|
164
|
+
}
|
|
165
|
+
} catch {
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
} catch {
|
|
169
|
+
}
|
|
170
|
+
return count;
|
|
171
|
+
}
|
|
172
|
+
var CSS_SCAN_DIRS = [
|
|
173
|
+
"app",
|
|
174
|
+
"src/app",
|
|
175
|
+
"src",
|
|
176
|
+
"styles",
|
|
177
|
+
"assets",
|
|
178
|
+
"theme",
|
|
179
|
+
"css"
|
|
180
|
+
];
|
|
181
|
+
var CSS_CUSTOM_PROPERTY_RE = /--[\w-]+\s*:/;
|
|
182
|
+
async function scanForCssFiles(projectRoot) {
|
|
183
|
+
const found = [];
|
|
184
|
+
for (const dir of CSS_SCAN_DIRS) {
|
|
185
|
+
const fullDir = path.join(projectRoot, dir);
|
|
186
|
+
let entries;
|
|
187
|
+
try {
|
|
188
|
+
entries = await fs.readdir(fullDir);
|
|
189
|
+
} catch {
|
|
190
|
+
continue;
|
|
191
|
+
}
|
|
192
|
+
for (const file of entries) {
|
|
193
|
+
if (!file.endsWith(".css")) continue;
|
|
194
|
+
const relPath = path.join(dir, file);
|
|
195
|
+
if (found.includes(relPath)) continue;
|
|
196
|
+
try {
|
|
197
|
+
const content = await fs.readFile(path.join(projectRoot, relPath), "utf-8");
|
|
198
|
+
if (CSS_CUSTOM_PROPERTY_RE.test(content)) {
|
|
199
|
+
found.push(relPath);
|
|
200
|
+
}
|
|
201
|
+
} catch {
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return found;
|
|
206
|
+
}
|
|
96
207
|
|
|
97
208
|
// src/server/lib/detect-styling.ts
|
|
98
209
|
import fs2 from "fs/promises";
|
|
@@ -1337,18 +1448,20 @@ import fs5 from "fs/promises";
|
|
|
1337
1448
|
import path5 from "path";
|
|
1338
1449
|
import recast2 from "recast";
|
|
1339
1450
|
import { namedTypes as n3 } from "ast-types";
|
|
1340
|
-
async function scanComponents(projectRoot) {
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1451
|
+
async function scanComponents(projectRoot, overrideDir) {
|
|
1452
|
+
let componentDir = overrideDir || "";
|
|
1453
|
+
if (!componentDir) {
|
|
1454
|
+
const componentDirs = [
|
|
1455
|
+
"components/ui",
|
|
1456
|
+
"src/components/ui"
|
|
1457
|
+
];
|
|
1458
|
+
for (const dir of componentDirs) {
|
|
1459
|
+
try {
|
|
1460
|
+
await fs5.access(path5.join(projectRoot, dir));
|
|
1461
|
+
componentDir = dir;
|
|
1462
|
+
break;
|
|
1463
|
+
} catch {
|
|
1464
|
+
}
|
|
1352
1465
|
}
|
|
1353
1466
|
}
|
|
1354
1467
|
if (!componentDir) {
|
|
@@ -1356,7 +1469,7 @@ async function scanComponents(projectRoot) {
|
|
|
1356
1469
|
}
|
|
1357
1470
|
const fullDir = path5.join(projectRoot, componentDir);
|
|
1358
1471
|
const files = await fs5.readdir(fullDir);
|
|
1359
|
-
const tsxFiles = files.filter((f) => f.endsWith(".tsx"));
|
|
1472
|
+
const tsxFiles = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx"));
|
|
1360
1473
|
const parser = await getParser();
|
|
1361
1474
|
const components = [];
|
|
1362
1475
|
for (const file of tsxFiles) {
|
|
@@ -2535,12 +2648,15 @@ function isFromComponentDir(importPath, componentDir, _parentDir, leafDir) {
|
|
|
2535
2648
|
|
|
2536
2649
|
// src/server/lib/scanner.ts
|
|
2537
2650
|
var cachedScan = null;
|
|
2651
|
+
var predetectedFramework;
|
|
2652
|
+
var predetectedStyling;
|
|
2538
2653
|
async function runScan(projectRoot) {
|
|
2539
|
-
const framework = await detectFramework(projectRoot);
|
|
2540
|
-
const styling = await detectStylingSystem(projectRoot, framework);
|
|
2654
|
+
const framework = predetectedFramework || await detectFramework(projectRoot);
|
|
2655
|
+
const styling = predetectedStyling || await detectStylingSystem(projectRoot, framework);
|
|
2656
|
+
const componentDir = framework.componentDirExists ? framework.componentDir : void 0;
|
|
2541
2657
|
const [tokens, components, shadows, borders, gradients, spacing, usages] = await Promise.all([
|
|
2542
2658
|
scanTokens(projectRoot, framework),
|
|
2543
|
-
scanComponents(projectRoot),
|
|
2659
|
+
scanComponents(projectRoot, componentDir),
|
|
2544
2660
|
scanShadows(projectRoot, framework, styling),
|
|
2545
2661
|
scanBorders(projectRoot, framework, styling),
|
|
2546
2662
|
scanGradients(projectRoot, framework, styling),
|
|
@@ -2585,7 +2701,9 @@ async function rescanGradients(projectRoot) {
|
|
|
2585
2701
|
patchCachedScan("gradients", gradients);
|
|
2586
2702
|
return gradients;
|
|
2587
2703
|
}
|
|
2588
|
-
function createScanRouter(projectRoot) {
|
|
2704
|
+
function createScanRouter(projectRoot, framework, styling) {
|
|
2705
|
+
predetectedFramework = framework;
|
|
2706
|
+
predetectedStyling = styling;
|
|
2589
2707
|
const router = Router2();
|
|
2590
2708
|
runScan(projectRoot).then(() => {
|
|
2591
2709
|
console.log(" Project scanned successfully");
|
|
@@ -3383,7 +3501,7 @@ async function createServer(config) {
|
|
|
3383
3501
|
};
|
|
3384
3502
|
tryOpen();
|
|
3385
3503
|
});
|
|
3386
|
-
app.use("/scan", createScanRouter(config.projectRoot));
|
|
3504
|
+
app.use("/scan", createScanRouter(config.projectRoot, config.framework, config.styling));
|
|
3387
3505
|
const __dirname = path16.dirname(fileURLToPath(import.meta.url));
|
|
3388
3506
|
const clientDistPath = path16.join(__dirname, "client");
|
|
3389
3507
|
const isDev = !fs18.existsSync(path16.join(clientDistPath, "index.html"));
|
|
@@ -3468,10 +3586,150 @@ async function promptPort(message, options) {
|
|
|
3468
3586
|
});
|
|
3469
3587
|
});
|
|
3470
3588
|
}
|
|
3589
|
+
async function promptComponentDir(framework, projectRoot) {
|
|
3590
|
+
const candidates = framework.fallbackComponentDirs.length > 0 ? framework.fallbackComponentDirs : await findDirsWithComponentFiles(projectRoot);
|
|
3591
|
+
if (candidates.length === 0) {
|
|
3592
|
+
return { dir: framework.componentDir, exists: false, fileCount: 0 };
|
|
3593
|
+
}
|
|
3594
|
+
const rl = readline.createInterface({ input: process2.stdin, output: process2.stdout });
|
|
3595
|
+
console.log("");
|
|
3596
|
+
console.log(` ${yellow("?")} Where are your UI components?`);
|
|
3597
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
3598
|
+
const c = candidates[i];
|
|
3599
|
+
console.log(` ${cyan(String(i + 1))}. ${c.dir}/ ${dim(`(${c.fileCount} files)`)}`);
|
|
3600
|
+
}
|
|
3601
|
+
const enterIdx = candidates.length + 1;
|
|
3602
|
+
const skipIdx = candidates.length + 2;
|
|
3603
|
+
console.log(` ${cyan(String(enterIdx))}. Enter a path`);
|
|
3604
|
+
console.log(` ${cyan(String(skipIdx))}. Skip \u2014 continue without component editing`);
|
|
3605
|
+
console.log("");
|
|
3606
|
+
return new Promise((resolve) => {
|
|
3607
|
+
rl.question(` ${dim("Choice [1]:")} `, (answer) => {
|
|
3608
|
+
rl.close();
|
|
3609
|
+
const trimmed = answer.trim();
|
|
3610
|
+
if (!trimmed || trimmed === "1") {
|
|
3611
|
+
const best = candidates[0];
|
|
3612
|
+
resolve({ dir: best.dir, exists: true, fileCount: best.fileCount });
|
|
3613
|
+
return;
|
|
3614
|
+
}
|
|
3615
|
+
const idx = parseInt(trimmed, 10);
|
|
3616
|
+
if (idx >= 1 && idx <= candidates.length) {
|
|
3617
|
+
const picked = candidates[idx - 1];
|
|
3618
|
+
resolve({ dir: picked.dir, exists: true, fileCount: picked.fileCount });
|
|
3619
|
+
return;
|
|
3620
|
+
}
|
|
3621
|
+
if (idx === enterIdx) {
|
|
3622
|
+
const rl2 = readline.createInterface({ input: process2.stdin, output: process2.stdout });
|
|
3623
|
+
rl2.question(` ${dim("Path:")} `, (pathAnswer) => {
|
|
3624
|
+
rl2.close();
|
|
3625
|
+
const customDir = pathAnswer.trim();
|
|
3626
|
+
if (customDir && fs19.existsSync(path17.join(projectRoot, customDir))) {
|
|
3627
|
+
resolve({ dir: customDir, exists: true, fileCount: 0 });
|
|
3628
|
+
} else {
|
|
3629
|
+
resolve({ dir: customDir || framework.componentDir, exists: false, fileCount: 0 });
|
|
3630
|
+
}
|
|
3631
|
+
});
|
|
3632
|
+
return;
|
|
3633
|
+
}
|
|
3634
|
+
resolve({ dir: framework.componentDir, exists: false, fileCount: 0 });
|
|
3635
|
+
});
|
|
3636
|
+
});
|
|
3637
|
+
}
|
|
3638
|
+
async function promptCssFile(framework, projectRoot) {
|
|
3639
|
+
const candidates = framework.fallbackCssFiles;
|
|
3640
|
+
if (candidates.length === 0) {
|
|
3641
|
+
return [];
|
|
3642
|
+
}
|
|
3643
|
+
const rl = readline.createInterface({ input: process2.stdin, output: process2.stdout });
|
|
3644
|
+
console.log("");
|
|
3645
|
+
console.log(` ${yellow("?")} Which CSS file has your design tokens / custom properties?`);
|
|
3646
|
+
for (let i = 0; i < candidates.length; i++) {
|
|
3647
|
+
console.log(` ${cyan(String(i + 1))}. ${candidates[i]}`);
|
|
3648
|
+
}
|
|
3649
|
+
const enterIdx = candidates.length + 1;
|
|
3650
|
+
const skipIdx = candidates.length + 2;
|
|
3651
|
+
console.log(` ${cyan(String(enterIdx))}. Enter a path`);
|
|
3652
|
+
console.log(` ${cyan(String(skipIdx))}. Skip \u2014 continue without token editing`);
|
|
3653
|
+
console.log("");
|
|
3654
|
+
return new Promise((resolve) => {
|
|
3655
|
+
rl.question(` ${dim("Choice [1]:")} `, (answer) => {
|
|
3656
|
+
rl.close();
|
|
3657
|
+
const trimmed = answer.trim();
|
|
3658
|
+
if (!trimmed || trimmed === "1") {
|
|
3659
|
+
resolve([candidates[0]]);
|
|
3660
|
+
return;
|
|
3661
|
+
}
|
|
3662
|
+
const idx = parseInt(trimmed, 10);
|
|
3663
|
+
if (idx >= 1 && idx <= candidates.length) {
|
|
3664
|
+
resolve([candidates[idx - 1]]);
|
|
3665
|
+
return;
|
|
3666
|
+
}
|
|
3667
|
+
if (idx === enterIdx) {
|
|
3668
|
+
const rl2 = readline.createInterface({ input: process2.stdin, output: process2.stdout });
|
|
3669
|
+
rl2.question(` ${dim("Path:")} `, (pathAnswer) => {
|
|
3670
|
+
rl2.close();
|
|
3671
|
+
const customPath = pathAnswer.trim();
|
|
3672
|
+
if (customPath && fs19.existsSync(path17.join(projectRoot, customPath))) {
|
|
3673
|
+
resolve([customPath]);
|
|
3674
|
+
} else {
|
|
3675
|
+
resolve([]);
|
|
3676
|
+
}
|
|
3677
|
+
});
|
|
3678
|
+
return;
|
|
3679
|
+
}
|
|
3680
|
+
resolve([]);
|
|
3681
|
+
});
|
|
3682
|
+
});
|
|
3683
|
+
}
|
|
3684
|
+
async function findDirsWithComponentFiles(projectRoot) {
|
|
3685
|
+
const scanDirs = [
|
|
3686
|
+
"components",
|
|
3687
|
+
"src/components",
|
|
3688
|
+
"lib",
|
|
3689
|
+
"src/lib",
|
|
3690
|
+
"ui",
|
|
3691
|
+
"src/ui"
|
|
3692
|
+
];
|
|
3693
|
+
const results = [];
|
|
3694
|
+
for (const dir of scanDirs) {
|
|
3695
|
+
const fullDir = path17.join(projectRoot, dir);
|
|
3696
|
+
try {
|
|
3697
|
+
const stat = fs19.statSync(fullDir);
|
|
3698
|
+
if (!stat.isDirectory()) continue;
|
|
3699
|
+
} catch {
|
|
3700
|
+
continue;
|
|
3701
|
+
}
|
|
3702
|
+
try {
|
|
3703
|
+
const files = fs19.readdirSync(fullDir);
|
|
3704
|
+
const count = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
|
|
3705
|
+
if (count > 0) {
|
|
3706
|
+
results.push({ dir, fileCount: count });
|
|
3707
|
+
}
|
|
3708
|
+
for (const file of files) {
|
|
3709
|
+
const subPath = path17.join(fullDir, file);
|
|
3710
|
+
try {
|
|
3711
|
+
if (!fs19.statSync(subPath).isDirectory()) continue;
|
|
3712
|
+
} catch {
|
|
3713
|
+
continue;
|
|
3714
|
+
}
|
|
3715
|
+
const subFiles = fs19.readdirSync(subPath);
|
|
3716
|
+
const subCount = subFiles.filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
|
|
3717
|
+
if (subCount > 0) {
|
|
3718
|
+
results.push({ dir: `${dir}/${file}`, fileCount: subCount });
|
|
3719
|
+
}
|
|
3720
|
+
}
|
|
3721
|
+
} catch {
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
results.sort((a, b3) => b3.fileCount - a.fileCount);
|
|
3725
|
+
return results;
|
|
3726
|
+
}
|
|
3471
3727
|
async function main() {
|
|
3472
3728
|
const args = process2.argv.slice(2);
|
|
3473
3729
|
let targetPort = 3e3;
|
|
3474
3730
|
let toolPort = 4400;
|
|
3731
|
+
let componentsOverride;
|
|
3732
|
+
let cssOverride;
|
|
3475
3733
|
for (let i = 0; i < args.length; i++) {
|
|
3476
3734
|
if (args[i] === "--port" && args[i + 1]) {
|
|
3477
3735
|
targetPort = parseInt(args[i + 1], 10);
|
|
@@ -3481,6 +3739,14 @@ async function main() {
|
|
|
3481
3739
|
toolPort = parseInt(args[i + 1], 10);
|
|
3482
3740
|
i++;
|
|
3483
3741
|
}
|
|
3742
|
+
if (args[i] === "--components" && args[i + 1]) {
|
|
3743
|
+
componentsOverride = args[i + 1];
|
|
3744
|
+
i++;
|
|
3745
|
+
}
|
|
3746
|
+
if (args[i] === "--css" && args[i + 1]) {
|
|
3747
|
+
cssOverride = args[i + 1];
|
|
3748
|
+
i++;
|
|
3749
|
+
}
|
|
3484
3750
|
}
|
|
3485
3751
|
const projectRoot = process2.cwd();
|
|
3486
3752
|
console.log("");
|
|
@@ -3496,6 +3762,17 @@ async function main() {
|
|
|
3496
3762
|
process2.exit(1);
|
|
3497
3763
|
}
|
|
3498
3764
|
const framework = await detectFramework(projectRoot);
|
|
3765
|
+
if (componentsOverride) {
|
|
3766
|
+
framework.componentDir = componentsOverride;
|
|
3767
|
+
framework.componentDirExists = fs19.existsSync(path17.join(projectRoot, componentsOverride));
|
|
3768
|
+
if (framework.componentDirExists) {
|
|
3769
|
+
const files = fs19.readdirSync(path17.join(projectRoot, componentsOverride));
|
|
3770
|
+
framework.componentFileCount = files.filter((f) => f.endsWith(".tsx") || f.endsWith(".jsx")).length;
|
|
3771
|
+
}
|
|
3772
|
+
}
|
|
3773
|
+
if (cssOverride) {
|
|
3774
|
+
framework.cssFiles = fs19.existsSync(path17.join(projectRoot, cssOverride)) ? [cssOverride] : [];
|
|
3775
|
+
}
|
|
3499
3776
|
const frameworkLabel = framework.name === "nextjs" ? "Next.js" : framework.name === "remix" ? "Remix" : framework.name === "vite" ? "Vite" : "Unknown";
|
|
3500
3777
|
console.log(` ${green("\u2713")} Framework ${frameworkLabel}`);
|
|
3501
3778
|
if (framework.appDirExists) {
|
|
@@ -3508,12 +3785,28 @@ async function main() {
|
|
|
3508
3785
|
` ${green("\u2713")} Components ${framework.componentDir}/ ${dim(`(${framework.componentFileCount} files)`)}`
|
|
3509
3786
|
);
|
|
3510
3787
|
} else {
|
|
3511
|
-
console.log(` ${yellow("\u26A0")} Components ${dim("not found
|
|
3788
|
+
console.log(` ${yellow("\u26A0")} Components ${dim("not found")}`);
|
|
3789
|
+
if (!componentsOverride && process2.stdin.isTTY) {
|
|
3790
|
+
const result = await promptComponentDir(framework, projectRoot);
|
|
3791
|
+
if (result.exists) {
|
|
3792
|
+
framework.componentDir = result.dir;
|
|
3793
|
+
framework.componentDirExists = true;
|
|
3794
|
+
framework.componentFileCount = result.fileCount;
|
|
3795
|
+
console.log(` ${green("\u2713")} Components ${framework.componentDir}/ ${dim(`(${framework.componentFileCount} files)`)}`);
|
|
3796
|
+
}
|
|
3797
|
+
}
|
|
3512
3798
|
}
|
|
3513
3799
|
if (framework.cssFiles.length > 0) {
|
|
3514
3800
|
console.log(` ${green("\u2713")} CSS files ${framework.cssFiles[0]}`);
|
|
3515
3801
|
} else {
|
|
3516
3802
|
console.log(` ${yellow("\u26A0")} CSS files ${dim("no CSS files found")}`);
|
|
3803
|
+
if (!cssOverride && process2.stdin.isTTY) {
|
|
3804
|
+
const result = await promptCssFile(framework, projectRoot);
|
|
3805
|
+
if (result.length > 0) {
|
|
3806
|
+
framework.cssFiles = result;
|
|
3807
|
+
console.log(` ${green("\u2713")} CSS files ${framework.cssFiles[0]}`);
|
|
3808
|
+
}
|
|
3809
|
+
}
|
|
3517
3810
|
}
|
|
3518
3811
|
const styling = await detectStylingSystem(projectRoot, framework);
|
|
3519
3812
|
const stylingLabels = {
|
|
@@ -3584,7 +3877,9 @@ async function main() {
|
|
|
3584
3877
|
targetPort,
|
|
3585
3878
|
toolPort,
|
|
3586
3879
|
projectRoot,
|
|
3587
|
-
stylingType: styling.type
|
|
3880
|
+
stylingType: styling.type,
|
|
3881
|
+
framework,
|
|
3882
|
+
styling
|
|
3588
3883
|
});
|
|
3589
3884
|
const httpServer = await new Promise((resolve, reject) => {
|
|
3590
3885
|
let attempts = 0;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@designtools/codesurface",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.10",
|
|
4
4
|
"description": "Visual editing CLI — hybrid architecture with selection overlays in the target app and editor UI served separately",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "CC-BY-NC-4.0",
|