@promptui-lib/cli 0.1.16 → 0.1.18

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/README.md CHANGED
@@ -180,6 +180,37 @@ export FIGMA_FILE_ID=ABC123xyz
180
180
  **File ID:**
181
181
  Da URL do Figma: `https://www.figma.com/file/ABC123xyz/MeuProjeto` → `ABC123xyz`
182
182
 
183
+ ### Entendendo o fileId vs node-id
184
+
185
+ > ⚠️ **Importante**: O `fileId` é do **arquivo Figma inteiro**, não de uma tela específica!
186
+
187
+ Na URL do Figma:
188
+ ```
189
+ https://www.figma.com/design/5gCjy5F30XJySmOPpgDKLM/Tela-de-Login?node-id=13-2&m=dev
190
+ └──────────────────────┘ └──────┘
191
+ fileId node-id (NÃO usar)
192
+ ```
193
+
194
+ | Conceito | O que é | Precisa na config? |
195
+ |----------|---------|-------------------|
196
+ | `fileId` | Identifica o **arquivo Figma inteiro** | ✅ Sim |
197
+ | `node-id` | Identifica um frame específico | ❌ Não |
198
+
199
+ **Regra:**
200
+ - **Mesmo arquivo Figma, telas diferentes** → Use o **mesmo fileId**
201
+ - **Arquivo Figma diferente** → Precisa de um **novo fileId**
202
+
203
+ **Exemplo:**
204
+ ```
205
+ 📁 Meu Projeto (fileId: ABC123xyz)
206
+ ├── #LoginScreen ← mesmo fileId
207
+ ├── #HomeScreen ← mesmo fileId
208
+ ├── #ProfileScreen ← mesmo fileId
209
+ └── #SettingsScreen ← mesmo fileId
210
+ ```
211
+
212
+ O CLI busca automaticamente **todos os frames** que começam com `#` dentro do arquivo.
213
+
183
214
  ---
184
215
 
185
216
  ## Guia para Designers
@@ -2,7 +2,7 @@
2
2
  * Generate Command
3
3
  * Gera componente a partir de um node do Figma ou arquivo JSON local
4
4
  */
5
- import type { ComponentLayer, FrameworkType } from '@promptui-lib/core';
5
+ import type { ComponentLayer, FrameworkType } from "@promptui-lib/core";
6
6
  export interface IGenerateOptions {
7
7
  force?: boolean;
8
8
  output?: string;
@@ -1 +1 @@
1
- {"version":3,"file":"generate.cmd.d.ts","sourceRoot":"","sources":["../../src/commands/generate.cmd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAc,aAAa,EAAE,MAAM,oBAAoB,CAAC;AAapF,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AA0ED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CAqJf;AAyBD;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CAAC,OAAO,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC,CA6HjF"}
1
+ {"version":3,"file":"generate.cmd.d.ts","sourceRoot":"","sources":["../../src/commands/generate.cmd.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAIH,OAAO,KAAK,EACV,cAAc,EAEd,aAAa,EACd,MAAM,oBAAoB,CAAC;AAiB5B,MAAM,WAAW,gBAAgB;IAC/B,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,KAAK,CAAC,EAAE,cAAc,CAAC;IACvB,SAAS,CAAC,EAAE,aAAa,CAAC;IAC1B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,OAAO,CAAC;CACf;AA4ED,wBAAsB,eAAe,CACnC,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CA2Jf;AAyBD;;;;;;;;;GASG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,IAAI,CAAC,CA0If"}
@@ -2,26 +2,26 @@
2
2
  * Generate Command
3
3
  * Gera componente a partir de um node do Figma ou arquivo JSON local
4
4
  */
5
- import { readFile } from 'node:fs/promises';
6
- import { createHash } from 'node:crypto';
7
- import { createFigmaClient } from '@promptui-lib/figma-parser';
8
- import { parseNode } from '@promptui-lib/figma-parser';
9
- import { writeComponent, generateCode, generateMuiComponent, generateTailwindComponent, generateBootstrapComponent, FRAMEWORKS, } from '@promptui-lib/codegen';
10
- import { loadConfig, resolveConfig, validateConfig } from '@promptui-lib/mcp-agent';
5
+ import { readFile } from "node:fs/promises";
6
+ import { createHash } from "node:crypto";
7
+ import { createFigmaClient } from "@promptui-lib/figma-parser";
8
+ import { parseNode } from "@promptui-lib/figma-parser";
9
+ import { writeComponent, generateCode, generateMuiComponent, generateTailwindComponent, generateBootstrapComponent, FRAMEWORKS, } from "@promptui-lib/codegen";
10
+ import { loadConfig, resolveConfig, validateConfig, } from "@promptui-lib/mcp-agent";
11
11
  /**
12
12
  * Detecta se o input é um arquivo JSON local ou nodeId do Figma
13
13
  */
14
14
  function isLocalFile(input) {
15
- return input.endsWith('.json') || input.startsWith('./') || input.startsWith('/');
15
+ return (input.endsWith(".json") || input.startsWith("./") || input.startsWith("/"));
16
16
  }
17
17
  /**
18
18
  * Carrega node de arquivo JSON local
19
19
  */
20
20
  async function loadNodeFromFile(filePath) {
21
- const content = await readFile(filePath, 'utf-8');
21
+ const content = await readFile(filePath, "utf-8");
22
22
  const node = JSON.parse(content);
23
23
  if (!node.id || !node.name || !node.type) {
24
- throw new Error('Invalid Figma node JSON: missing id, name or type');
24
+ throw new Error("Invalid Figma node JSON: missing id, name or type");
25
25
  }
26
26
  return node;
27
27
  }
@@ -30,10 +30,10 @@ async function loadNodeFromFile(filePath) {
30
30
  */
31
31
  function generateMeta(node, ast, source, files) {
32
32
  const content = JSON.stringify({ node, ast, source, files });
33
- const checksum = createHash('sha256').update(content).digest('hex');
33
+ const checksum = createHash("sha256").update(content).digest("hex");
34
34
  return {
35
- generator: 'promptui-figma-codegen',
36
- version: '1.0.0',
35
+ generator: "promptui-figma-codegen",
36
+ version: "1.0.0",
37
37
  generatedAt: new Date().toISOString(),
38
38
  source: {
39
39
  nodeId: node.id,
@@ -52,7 +52,7 @@ function generateMeta(node, ast, source, files) {
52
52
  }
53
53
  export async function generateCommand(input, options) {
54
54
  const isFile = isLocalFile(input);
55
- console.log(`[PromptUI] Generating component from ${isFile ? 'file' : 'Figma node'}: ${input}`);
55
+ console.log(`[PromptUI] Generating component from ${isFile ? "file" : "Figma node"}: ${input}`);
56
56
  // Carrega config
57
57
  const config = await loadConfig();
58
58
  const resolved = resolveConfig(config);
@@ -69,7 +69,7 @@ export async function generateCommand(input, options) {
69
69
  // Valida config para API
70
70
  const errors = validateConfig(resolved);
71
71
  if (errors.length > 0) {
72
- console.error('[PromptUI] Configuration errors:');
72
+ console.error("[PromptUI] Configuration errors:");
73
73
  for (const error of errors) {
74
74
  console.error(` - ${error}`);
75
75
  }
@@ -88,32 +88,32 @@ export async function generateCommand(input, options) {
88
88
  }
89
89
  // Parseia
90
90
  const ast = parseNode(node, { forceLayer: options.layer });
91
- const framework = options.framework ?? 'react';
91
+ const framework = options.framework ?? "react";
92
92
  const frameworkInfo = FRAMEWORKS[framework];
93
93
  console.log(`[PromptUI] Parsed: ${ast.name} (${ast.layer})`);
94
94
  console.log(`[PromptUI] Framework: ${frameworkInfo?.displayName ?? framework}`);
95
95
  // Gera código baseado no framework
96
96
  const generateForFramework = () => {
97
97
  switch (framework) {
98
- case 'mui':
98
+ case "mui":
99
99
  return {
100
100
  tsx: generateMuiComponent(ast),
101
- scss: '', // MUI usa sx props inline
101
+ scss: "", // MUI usa sx props inline
102
102
  index: `export { ${ast.name} } from './${ast.fileName}';\nexport type { I${ast.name}Props } from './${ast.fileName}';\n`,
103
103
  };
104
- case 'tailwind':
104
+ case "tailwind":
105
105
  return {
106
106
  tsx: generateTailwindComponent(ast),
107
- scss: '', // Tailwind usa classes inline
107
+ scss: "", // Tailwind usa classes inline
108
108
  index: `export { ${ast.name} } from './${ast.fileName}';\nexport type { I${ast.name}Props } from './${ast.fileName}';\n`,
109
109
  };
110
- case 'bootstrap':
110
+ case "bootstrap":
111
111
  return {
112
112
  tsx: generateBootstrapComponent(ast),
113
- scss: '', // Bootstrap usa classes inline
113
+ scss: "", // Bootstrap usa classes inline
114
114
  index: `export { ${ast.name} } from './${ast.fileName}';\nexport type { I${ast.name}Props } from './${ast.fileName}';\n`,
115
115
  };
116
- case 'react':
116
+ case "react":
117
117
  default:
118
118
  return generateCode(ast);
119
119
  }
@@ -121,22 +121,22 @@ export async function generateCommand(input, options) {
121
121
  // Preview mode
122
122
  if (options.preview) {
123
123
  const code = generateForFramework();
124
- console.log('\n--- TSX ---');
124
+ console.log("\n--- TSX ---");
125
125
  console.log(code.tsx);
126
126
  if (code.scss) {
127
- console.log('\n--- SCSS ---');
127
+ console.log("\n--- SCSS ---");
128
128
  console.log(code.scss);
129
129
  }
130
- console.log('\n--- index.ts ---');
130
+ console.log("\n--- index.ts ---");
131
131
  console.log(code.index);
132
132
  if (!options.noMeta) {
133
133
  const meta = generateMeta(node, ast, sourceInfo, [
134
134
  `${ast.fileName}.tsx`,
135
135
  `${ast.fileName}.scss`,
136
- 'index.ts',
137
- 'meta.json',
136
+ "index.ts",
137
+ "meta.json",
138
138
  ]);
139
- console.log('\n--- meta.json ---');
139
+ console.log("\n--- meta.json ---");
140
140
  console.log(JSON.stringify(meta, null, 2));
141
141
  }
142
142
  return;
@@ -148,7 +148,7 @@ export async function generateCommand(input, options) {
148
148
  forceOverwrite: options.force,
149
149
  });
150
150
  if (!result.success) {
151
- console.error('[PromptUI] Failed to write files:');
151
+ console.error("[PromptUI] Failed to write files:");
152
152
  for (const error of result.errors ?? []) {
153
153
  console.error(` - ${error}`);
154
154
  }
@@ -156,31 +156,31 @@ export async function generateCommand(input, options) {
156
156
  }
157
157
  // Gera meta.json
158
158
  if (!options.noMeta) {
159
- const { writeFile } = await import('node:fs/promises');
160
- const { join, dirname } = await import('node:path');
161
- const metaPath = join(dirname(result.files.tsx), 'meta.json');
159
+ const { writeFile } = await import("node:fs/promises");
160
+ const { join, dirname } = await import("node:path");
161
+ const metaPath = join(dirname(result.files.tsx), "meta.json");
162
162
  const meta = generateMeta(node, ast, sourceInfo, [
163
163
  `${ast.fileName}.tsx`,
164
164
  `${ast.fileName}.scss`,
165
- 'index.ts',
166
- 'meta.json',
165
+ "index.ts",
166
+ "meta.json",
167
167
  ]);
168
- await writeFile(metaPath, JSON.stringify(meta, null, 2), 'utf-8');
169
- console.log('[PromptUI] Generated files:');
168
+ await writeFile(metaPath, JSON.stringify(meta, null, 2), "utf-8");
169
+ console.log("[PromptUI] Generated files:");
170
170
  console.log(` - ${result.files.tsx}`);
171
171
  console.log(` - ${result.files.scss}`);
172
172
  console.log(` - ${result.files.index}`);
173
173
  console.log(` - ${metaPath}`);
174
174
  }
175
175
  else {
176
- console.log('[PromptUI] Generated files:');
176
+ console.log("[PromptUI] Generated files:");
177
177
  console.log(` - ${result.files.tsx}`);
178
178
  console.log(` - ${result.files.scss}`);
179
179
  console.log(` - ${result.files.index}`);
180
180
  }
181
181
  }
182
182
  catch (error) {
183
- const message = error instanceof Error ? error.message : 'Unknown error';
183
+ const message = error instanceof Error ? error.message : "Unknown error";
184
184
  console.error(`[PromptUI] Error: ${message}`);
185
185
  process.exit(1);
186
186
  }
@@ -192,7 +192,7 @@ function hasExportableChildren(node) {
192
192
  if (!node.children)
193
193
  return false;
194
194
  for (const child of node.children) {
195
- if (child.name.startsWith('#'))
195
+ if (child.name.startsWith("#"))
196
196
  return true;
197
197
  if (hasExportableChildren(child))
198
198
  return true;
@@ -212,10 +212,10 @@ function hasExportableChildren(node) {
212
212
  export async function generateAllCommand(options) {
213
213
  const exportAll = options.all;
214
214
  if (exportAll) {
215
- console.log('[PromptUI] Generating ALL top-level frames (--all mode)...');
215
+ console.log("[PromptUI] Generating ALL top-level frames (--all mode)...");
216
216
  }
217
217
  else {
218
- console.log('[PromptUI] Generating all exportable components...');
218
+ console.log("[PromptUI] Generating all exportable components...");
219
219
  }
220
220
  // Carrega config
221
221
  const config = await loadConfig();
@@ -223,7 +223,7 @@ export async function generateAllCommand(options) {
223
223
  // Valida
224
224
  const errors = validateConfig(resolved);
225
225
  if (errors.length > 0) {
226
- console.error('[PromptUI] Configuration errors:');
226
+ console.error("[PromptUI] Configuration errors:");
227
227
  for (const error of errors) {
228
228
  console.error(` - ${error}`);
229
229
  }
@@ -238,12 +238,8 @@ export async function generateAllCommand(options) {
238
238
  function findExportable(node, depth = 0, parentId) {
239
239
  // Se --all, exporta frames de nível superior (depth <= 2 = document > page > frame)
240
240
  // Se não, apenas os que começam com #
241
- const isTopLevelFrame = depth === 2 && (node.type === 'FRAME' || node.type === 'COMPONENT');
242
- const isMarkedForExport = node.name.startsWith('#');
243
- // Debug: mostra frames de nível superior
244
- if (depth === 2) {
245
- console.log(` [DEBUG] Top-level frame: "${node.name}" (type: ${node.type}, starts with #: ${isMarkedForExport})`);
246
- }
241
+ const isTopLevelFrame = depth === 2 && (node.type === "FRAME" || node.type === "COMPONENT");
242
+ const isMarkedForExport = node.name.startsWith("#");
247
243
  if (exportAll ? isTopLevelFrame : isMarkedForExport) {
248
244
  // Só adiciona se ainda não existe (evita duplicatas)
249
245
  if (!exportableMap.has(node.id)) {
@@ -265,23 +261,23 @@ export async function generateAllCommand(options) {
265
261
  console.log(`[PromptUI] Found ${exportableNodes.length} exportable components`);
266
262
  if (exportableNodes.length === 0) {
267
263
  if (exportAll) {
268
- console.log('[PromptUI] No top-level frames found in the file.');
264
+ console.log("[PromptUI] No top-level frames found in the file.");
269
265
  }
270
266
  else {
271
- console.log('[PromptUI] No components found. Mark frames with # prefix to export.');
272
- console.log('[PromptUI] Or use --all flag to export all top-level frames.');
267
+ console.log("[PromptUI] No components found. Mark frames with # prefix to export.");
268
+ console.log("[PromptUI] Or use --all flag to export all top-level frames.");
273
269
  }
274
270
  return;
275
271
  }
276
272
  // Ordena por profundidade decrescente (folhas primeiro, pais depois)
277
273
  // Isso garante que componentes filhos sejam gerados antes dos pais
278
274
  exportableNodes.sort((a, b) => b.depth - a.depth);
279
- console.log('[PromptUI] Generation order (leaves first):');
275
+ console.log("[PromptUI] Generation order (leaves first):");
280
276
  for (const { node, depth } of exportableNodes) {
281
277
  const hasChildren = hasExportableChildren(node);
282
- console.log(` ${hasChildren ? '📦' : '🍃'} ${node.name} (depth: ${depth}, id: ${node.id.slice(0, 8)}...)`);
278
+ console.log(` ${hasChildren ? "📦" : "🍃"} ${node.name} (depth: ${depth}, id: ${node.id.slice(0, 8)}...)`);
283
279
  }
284
- console.log('');
280
+ console.log("");
285
281
  let successCount = 0;
286
282
  let errorCount = 0;
287
283
  for (const { node } of exportableNodes) {
@@ -297,21 +293,21 @@ export async function generateAllCommand(options) {
297
293
  successCount++;
298
294
  }
299
295
  else {
300
- console.log(` ❌ ${node.name}: ${result.errors?.join(', ')}`);
296
+ console.log(` ❌ ${node.name}: ${result.errors?.join(", ")}`);
301
297
  errorCount++;
302
298
  }
303
299
  }
304
300
  catch (error) {
305
- const message = error instanceof Error ? error.message : 'Unknown error';
301
+ const message = error instanceof Error ? error.message : "Unknown error";
306
302
  console.log(` ❌ ${node.name}: ${message}`);
307
303
  errorCount++;
308
304
  }
309
305
  }
310
- console.log('');
306
+ console.log("");
311
307
  console.log(`[PromptUI] Done: ${successCount} success, ${errorCount} errors`);
312
308
  }
313
309
  catch (error) {
314
- const message = error instanceof Error ? error.message : 'Unknown error';
310
+ const message = error instanceof Error ? error.message : "Unknown error";
315
311
  console.error(`[PromptUI] Error: ${message}`);
316
312
  process.exit(1);
317
313
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@promptui-lib/cli",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "private": false,
5
5
  "description": "CLI for PromptUI - Figma to React code generator",
6
6
  "license": "UNLICENSED",
@@ -45,10 +45,10 @@
45
45
  "bin"
46
46
  ],
47
47
  "dependencies": {
48
- "@promptui-lib/core": "0.1.16",
49
- "@promptui-lib/figma-parser": "0.1.16",
50
- "@promptui-lib/codegen": "0.1.16",
51
- "@promptui-lib/mcp-agent": "0.1.16"
48
+ "@promptui-lib/core": "0.1.18",
49
+ "@promptui-lib/figma-parser": "0.1.18",
50
+ "@promptui-lib/codegen": "0.1.18",
51
+ "@promptui-lib/mcp-agent": "0.1.18"
52
52
  },
53
53
  "devDependencies": {
54
54
  "@types/node": "^20.0.0",