desen-cli 1.0.0-draft.5 ā 1.0.0-draft.7
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/.turbo/turbo-build.log +1 -1
- package/dist/index.js +81 -5
- package/package.json +2 -2
- package/src/index.ts +84 -5
package/.turbo/turbo-build.log
CHANGED
package/dist/index.js
CHANGED
|
@@ -172,8 +172,9 @@ program
|
|
|
172
172
|
<div class="card">
|
|
173
173
|
<h1>š DESEN Daemon Active</h1>
|
|
174
174
|
<p>The Synchronization (Sync) server is waiting for incoming <strong>UI AST</strong> data from Figma. It can safely continue running in the background.</p>
|
|
175
|
-
<p>
|
|
176
|
-
<div class="code">
|
|
175
|
+
<p>When you press <strong>Sync to Localhost</strong> in Figma, the daemon will <strong>automatically</strong>:</p>
|
|
176
|
+
<div class="code">1. Validate & save JSON files<br/>2. Install dependencies (if needed)<br/>3. Start dev server on port 3001<br/>4. Open your browser āØ</div>
|
|
177
|
+
<p style="margin-top:16px;color:#888;">Zero-touch. Just press Sync and watch the magic.</p>
|
|
177
178
|
</div>
|
|
178
179
|
</body>
|
|
179
180
|
</html>
|
|
@@ -248,8 +249,8 @@ program
|
|
|
248
249
|
"start": "next start"
|
|
249
250
|
},
|
|
250
251
|
dependencies: {
|
|
251
|
-
"desen-core": "1.0.0-draft.
|
|
252
|
-
"desen": "1.0.0-draft.
|
|
252
|
+
"desen-core": "1.0.0-draft.7",
|
|
253
|
+
"desen": "1.0.0-draft.7",
|
|
253
254
|
"next": "14.2.3",
|
|
254
255
|
"react": "18.3.1",
|
|
255
256
|
"react-dom": "18.3.1"
|
|
@@ -429,7 +430,7 @@ function buildCssFromNode(layout: any, style: any, opts?: { isText?: boolean; is
|
|
|
429
430
|
|
|
430
431
|
if (layout) {
|
|
431
432
|
css.display = 'flex';
|
|
432
|
-
css.flexDirection = layout.direction === 'row' ? 'row' : 'column';
|
|
433
|
+
css.flexDirection = (layout.direction === 'row' || layout.direction === 'horizontal') ? 'row' : 'column';
|
|
433
434
|
if (layout.gap !== undefined && layout.gap !== 0) css.gap = layout.gap;
|
|
434
435
|
|
|
435
436
|
const am: Record<string, string> = { start:'flex-start', end:'flex-end', center:'center', 'space-between':'space-between', 'space-around':'space-around', 'space-evenly':'space-evenly' };
|
|
@@ -532,11 +533,18 @@ export const registry: Record<string, React.FC<any>> = {
|
|
|
532
533
|
element: GenericContainer,
|
|
533
534
|
group: GenericContainer,
|
|
534
535
|
stack: GenericContainer,
|
|
536
|
+
Stack: GenericContainer,
|
|
537
|
+
Card: GenericContainer,
|
|
538
|
+
Grid: GenericContainer,
|
|
539
|
+
Header: GenericContainer,
|
|
540
|
+
Footer: GenericContainer,
|
|
535
541
|
text: TextComponent,
|
|
536
542
|
Text: TextComponent,
|
|
537
543
|
button: ButtonComponent,
|
|
544
|
+
Button: ButtonComponent,
|
|
538
545
|
input: (props: any) => <input style={buildCssFromNode(props.layout, props.style)} placeholder={props.content || props.name} />,
|
|
539
546
|
icon: (props: any) => <div style={{ ...buildCssFromNode(props.layout, props.style), display:'inline-flex', alignItems:'center', justifyContent:'center' }}>āļø</div>,
|
|
547
|
+
Icon: (props: any) => <div style={{ ...buildCssFromNode(props.layout, props.style), display:'inline-flex', alignItems:'center', justifyContent:'center' }}>āļø</div>,
|
|
540
548
|
};
|
|
541
549
|
`.trim());
|
|
542
550
|
console.log(chalk_1.default.green(`ā
Done! Standalone App Scaffolded.`));
|
|
@@ -551,6 +559,74 @@ export const registry: Record<string, React.FC<any>> = {
|
|
|
551
559
|
}
|
|
552
560
|
}
|
|
553
561
|
} // End if(!package.json)
|
|
562
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
563
|
+
// AUTO-PILOT: npm install + npm run dev + browser open
|
|
564
|
+
// Zero-touch DX ā developer never leaves Figma
|
|
565
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
566
|
+
const nodeModulesPath = path_1.default.join(workspaceDir, "node_modules");
|
|
567
|
+
const devServerPort = 3001;
|
|
568
|
+
const isPortInUse = (port) => {
|
|
569
|
+
return new Promise((resolve) => {
|
|
570
|
+
const net = require("net");
|
|
571
|
+
const tester = net.createServer()
|
|
572
|
+
.once("error", (err) => {
|
|
573
|
+
if (err.code === "EADDRINUSE")
|
|
574
|
+
resolve(true);
|
|
575
|
+
else
|
|
576
|
+
resolve(false);
|
|
577
|
+
})
|
|
578
|
+
.once("listening", () => {
|
|
579
|
+
tester.close(() => resolve(false));
|
|
580
|
+
})
|
|
581
|
+
.listen(port);
|
|
582
|
+
});
|
|
583
|
+
};
|
|
584
|
+
const runNpmInstallIfNeeded = async () => {
|
|
585
|
+
if (fs_1.default.existsSync(nodeModulesPath))
|
|
586
|
+
return;
|
|
587
|
+
console.log(chalk_1.default.blue(`\nš¦ Installing dependencies...`));
|
|
588
|
+
const { execSync } = require("child_process");
|
|
589
|
+
try {
|
|
590
|
+
execSync("npm install", { cwd: workspaceDir, stdio: "inherit" });
|
|
591
|
+
console.log(chalk_1.default.green(`ā
Dependencies installed.`));
|
|
592
|
+
}
|
|
593
|
+
catch (e) {
|
|
594
|
+
console.error(chalk_1.default.red(`ā npm install failed: ${e.message}`));
|
|
595
|
+
}
|
|
596
|
+
};
|
|
597
|
+
const startDevServerIfNeeded = async () => {
|
|
598
|
+
const portBusy = await isPortInUse(devServerPort);
|
|
599
|
+
if (portBusy) {
|
|
600
|
+
console.log(chalk_1.default.gray(` Dev server already running on port ${devServerPort}.`));
|
|
601
|
+
return;
|
|
602
|
+
}
|
|
603
|
+
console.log(chalk_1.default.blue(`\nš Starting dev server on port ${devServerPort}...`));
|
|
604
|
+
const { spawn } = require("child_process");
|
|
605
|
+
const child = spawn("npm", ["run", "dev"], {
|
|
606
|
+
cwd: workspaceDir,
|
|
607
|
+
detached: true,
|
|
608
|
+
stdio: "ignore"
|
|
609
|
+
});
|
|
610
|
+
child.unref();
|
|
611
|
+
console.log(chalk_1.default.green(`ā
Dev server launched (PID: ${child.pid}).`));
|
|
612
|
+
// Wait a bit then open browser
|
|
613
|
+
setTimeout(() => {
|
|
614
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
615
|
+
const { exec } = require("child_process");
|
|
616
|
+
exec(`${openCmd} http://localhost:${devServerPort}`);
|
|
617
|
+
console.log(chalk_1.default.cyan(`š Browser opened: http://localhost:${devServerPort}`));
|
|
618
|
+
}, 3000);
|
|
619
|
+
};
|
|
620
|
+
// Fire and forget ā don't block the HTTP response
|
|
621
|
+
(async () => {
|
|
622
|
+
try {
|
|
623
|
+
await runNpmInstallIfNeeded();
|
|
624
|
+
await startDevServerIfNeeded();
|
|
625
|
+
}
|
|
626
|
+
catch (e) {
|
|
627
|
+
console.error(chalk_1.default.yellow(`ā ļø Auto-pilot warning: ${e.message}`));
|
|
628
|
+
}
|
|
629
|
+
})();
|
|
554
630
|
res.status(200).json({ success: true, message: `Successfully saved ${savedCount} files.` });
|
|
555
631
|
}
|
|
556
632
|
catch (error) {
|
package/package.json
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "desen-cli",
|
|
3
|
-
"version": "1.0.0-draft.
|
|
3
|
+
"version": "1.0.0-draft.7",
|
|
4
4
|
"main": "dist/index.js",
|
|
5
5
|
"dependencies": {
|
|
6
6
|
"chalk": "^5.6.2",
|
|
7
7
|
"commander": "^14.0.3",
|
|
8
8
|
"express": "^4.19.2",
|
|
9
9
|
"cors": "^2.8.5",
|
|
10
|
-
"desen-core": "1.0.0-draft.
|
|
10
|
+
"desen-core": "1.0.0-draft.7"
|
|
11
11
|
},
|
|
12
12
|
"devDependencies": {
|
|
13
13
|
"@types/cors": "^2.8.19",
|
package/src/index.ts
CHANGED
|
@@ -190,8 +190,9 @@ program
|
|
|
190
190
|
<div class="card">
|
|
191
191
|
<h1>š DESEN Daemon Active</h1>
|
|
192
192
|
<p>The Synchronization (Sync) server is waiting for incoming <strong>UI AST</strong> data from Figma. It can safely continue running in the background.</p>
|
|
193
|
-
<p>
|
|
194
|
-
<div class="code">
|
|
193
|
+
<p>When you press <strong>Sync to Localhost</strong> in Figma, the daemon will <strong>automatically</strong>:</p>
|
|
194
|
+
<div class="code">1. Validate & save JSON files<br/>2. Install dependencies (if needed)<br/>3. Start dev server on port 3001<br/>4. Open your browser āØ</div>
|
|
195
|
+
<p style="margin-top:16px;color:#888;">Zero-touch. Just press Sync and watch the magic.</p>
|
|
195
196
|
</div>
|
|
196
197
|
</body>
|
|
197
198
|
</html>
|
|
@@ -274,8 +275,8 @@ program
|
|
|
274
275
|
"start": "next start"
|
|
275
276
|
},
|
|
276
277
|
dependencies: {
|
|
277
|
-
"desen-core": "1.0.0-draft.
|
|
278
|
-
"desen": "1.0.0-draft.
|
|
278
|
+
"desen-core": "1.0.0-draft.7",
|
|
279
|
+
"desen": "1.0.0-draft.7",
|
|
279
280
|
"next": "14.2.3",
|
|
280
281
|
"react": "18.3.1",
|
|
281
282
|
"react-dom": "18.3.1"
|
|
@@ -464,7 +465,7 @@ function buildCssFromNode(layout: any, style: any, opts?: { isText?: boolean; is
|
|
|
464
465
|
|
|
465
466
|
if (layout) {
|
|
466
467
|
css.display = 'flex';
|
|
467
|
-
css.flexDirection = layout.direction === 'row' ? 'row' : 'column';
|
|
468
|
+
css.flexDirection = (layout.direction === 'row' || layout.direction === 'horizontal') ? 'row' : 'column';
|
|
468
469
|
if (layout.gap !== undefined && layout.gap !== 0) css.gap = layout.gap;
|
|
469
470
|
|
|
470
471
|
const am: Record<string, string> = { start:'flex-start', end:'flex-end', center:'center', 'space-between':'space-between', 'space-around':'space-around', 'space-evenly':'space-evenly' };
|
|
@@ -567,11 +568,18 @@ export const registry: Record<string, React.FC<any>> = {
|
|
|
567
568
|
element: GenericContainer,
|
|
568
569
|
group: GenericContainer,
|
|
569
570
|
stack: GenericContainer,
|
|
571
|
+
Stack: GenericContainer,
|
|
572
|
+
Card: GenericContainer,
|
|
573
|
+
Grid: GenericContainer,
|
|
574
|
+
Header: GenericContainer,
|
|
575
|
+
Footer: GenericContainer,
|
|
570
576
|
text: TextComponent,
|
|
571
577
|
Text: TextComponent,
|
|
572
578
|
button: ButtonComponent,
|
|
579
|
+
Button: ButtonComponent,
|
|
573
580
|
input: (props: any) => <input style={buildCssFromNode(props.layout, props.style)} placeholder={props.content || props.name} />,
|
|
574
581
|
icon: (props: any) => <div style={{ ...buildCssFromNode(props.layout, props.style), display:'inline-flex', alignItems:'center', justifyContent:'center' }}>āļø</div>,
|
|
582
|
+
Icon: (props: any) => <div style={{ ...buildCssFromNode(props.layout, props.style), display:'inline-flex', alignItems:'center', justifyContent:'center' }}>āļø</div>,
|
|
575
583
|
};
|
|
576
584
|
`.trim());
|
|
577
585
|
|
|
@@ -589,6 +597,77 @@ export const registry: Record<string, React.FC<any>> = {
|
|
|
589
597
|
}
|
|
590
598
|
} // End if(!package.json)
|
|
591
599
|
|
|
600
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
601
|
+
// AUTO-PILOT: npm install + npm run dev + browser open
|
|
602
|
+
// Zero-touch DX ā developer never leaves Figma
|
|
603
|
+
// āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
|
|
604
|
+
const nodeModulesPath = path.join(workspaceDir, "node_modules");
|
|
605
|
+
const devServerPort = 3001;
|
|
606
|
+
|
|
607
|
+
const isPortInUse = (port: number): Promise<boolean> => {
|
|
608
|
+
return new Promise((resolve) => {
|
|
609
|
+
const net = require("net");
|
|
610
|
+
const tester = net.createServer()
|
|
611
|
+
.once("error", (err: any) => {
|
|
612
|
+
if (err.code === "EADDRINUSE") resolve(true);
|
|
613
|
+
else resolve(false);
|
|
614
|
+
})
|
|
615
|
+
.once("listening", () => {
|
|
616
|
+
tester.close(() => resolve(false));
|
|
617
|
+
})
|
|
618
|
+
.listen(port);
|
|
619
|
+
});
|
|
620
|
+
};
|
|
621
|
+
|
|
622
|
+
const runNpmInstallIfNeeded = async () => {
|
|
623
|
+
if (fs.existsSync(nodeModulesPath)) return;
|
|
624
|
+
|
|
625
|
+
console.log(chalk.blue(`\nš¦ Installing dependencies...`));
|
|
626
|
+
const { execSync } = require("child_process");
|
|
627
|
+
try {
|
|
628
|
+
execSync("npm install", { cwd: workspaceDir, stdio: "inherit" });
|
|
629
|
+
console.log(chalk.green(`ā
Dependencies installed.`));
|
|
630
|
+
} catch (e: any) {
|
|
631
|
+
console.error(chalk.red(`ā npm install failed: ${e.message}`));
|
|
632
|
+
}
|
|
633
|
+
};
|
|
634
|
+
|
|
635
|
+
const startDevServerIfNeeded = async () => {
|
|
636
|
+
const portBusy = await isPortInUse(devServerPort);
|
|
637
|
+
if (portBusy) {
|
|
638
|
+
console.log(chalk.gray(` Dev server already running on port ${devServerPort}.`));
|
|
639
|
+
return;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
console.log(chalk.blue(`\nš Starting dev server on port ${devServerPort}...`));
|
|
643
|
+
const { spawn } = require("child_process");
|
|
644
|
+
const child = spawn("npm", ["run", "dev"], {
|
|
645
|
+
cwd: workspaceDir,
|
|
646
|
+
detached: true,
|
|
647
|
+
stdio: "ignore"
|
|
648
|
+
});
|
|
649
|
+
child.unref();
|
|
650
|
+
console.log(chalk.green(`ā
Dev server launched (PID: ${child.pid}).`));
|
|
651
|
+
|
|
652
|
+
// Wait a bit then open browser
|
|
653
|
+
setTimeout(() => {
|
|
654
|
+
const openCmd = process.platform === "darwin" ? "open" : process.platform === "win32" ? "start" : "xdg-open";
|
|
655
|
+
const { exec } = require("child_process");
|
|
656
|
+
exec(`${openCmd} http://localhost:${devServerPort}`);
|
|
657
|
+
console.log(chalk.cyan(`š Browser opened: http://localhost:${devServerPort}`));
|
|
658
|
+
}, 3000);
|
|
659
|
+
};
|
|
660
|
+
|
|
661
|
+
// Fire and forget ā don't block the HTTP response
|
|
662
|
+
(async () => {
|
|
663
|
+
try {
|
|
664
|
+
await runNpmInstallIfNeeded();
|
|
665
|
+
await startDevServerIfNeeded();
|
|
666
|
+
} catch (e: any) {
|
|
667
|
+
console.error(chalk.yellow(`ā ļø Auto-pilot warning: ${e.message}`));
|
|
668
|
+
}
|
|
669
|
+
})();
|
|
670
|
+
|
|
592
671
|
res.status(200).json({ success: true, message: `Successfully saved ${savedCount} files.` });
|
|
593
672
|
} catch (error: any) {
|
|
594
673
|
console.error(chalk.red("ā Sync Error:"), error);
|