@figma/code-connect 1.4.4 → 1.4.5
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
|
@@ -1,3 +1,23 @@
|
|
|
1
|
-
|
|
1
|
+
# Code Connect
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Code Connect is a tool for connecting your design system components in code with your design system in Figma. When using Code Connect, Figma's Dev Mode will display true-to-production code snippets from your design system instead of autogenerated code examples. In addition to connecting component definitions, Code Connect also supports mapping properties from code to Figma enabling dynamic and correct examples. This can be useful for when you have an existing design system and are looking to drive consistent and correct adoption of that design system across design and engineering.
|
|
4
|
+
|
|
5
|
+
Code Connect is easy to set up, easy to maintain, type-safe, and extensible. The easiest way to get started is using **template files** — a framework-agnostic way to represent any code snippet, giving you full control over how components appear in Dev Mode. Code Connect also includes framework-specific integrations for React (and React Native), Storybook, HTML (e.g. Web Components, Angular and Vue), SwiftUI and Jetpack Compose.
|
|
6
|
+
|
|
7
|
+

|
|
8
|
+
|
|
9
|
+
> [!NOTE]
|
|
10
|
+
> Code Connect is available on Organization and Enterprise plans and requires a full Design or Dev Mode seat to use.
|
|
11
|
+
|
|
12
|
+
## Documentation
|
|
13
|
+
|
|
14
|
+
Use Figma’s Code Connect to make your design system easily accessible to your developers and create a shared source of truth for both the design and code elements.
|
|
15
|
+
|
|
16
|
+
Our Getting Started guide will walk you through setting up Code Connect and publishing your first components using template files. **[Code Connect Documentation →](https://developers.figma.com/docs/code-connect/)**
|
|
17
|
+
|
|
18
|
+
For framework-specific prop mapping and variant support, see the integration guides for:
|
|
19
|
+
|
|
20
|
+
- **[React (and React Native) →](https://www.figma.com/code-connect-docs/react)**
|
|
21
|
+
- **[HTML (e.g. Web Components, Angular and Vue) →](https://www.figma.com/code-connect-docs/html)**
|
|
22
|
+
- **[SwiftUI →](https://www.figma.com/code-connect-docs/swiftui)**
|
|
23
|
+
- **[Jetpack Compose →](https://www.figma.com/code-connect-docs/compose)**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview_utils.d.ts","sourceRoot":"","sources":["../../src/commands/preview_utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA6D,MAAM,WAAW,CAAA;AAElG,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAM1D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EAAE,EACf,qBAAqB,EAAE,eAAe,EAAE,EACxC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,aAAa,EAAE,CAAC,CAqF1B;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EAAE,EACjB,YAAY,EAAE,eAAe,EAAE,GAC9B,eAAe,EAAE,CAQnB;AAiBD,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB7D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAc9F;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBvF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAqC7D;
|
|
1
|
+
{"version":3,"file":"preview_utils.d.ts","sourceRoot":"","sources":["../../src/commands/preview_utils.ts"],"names":[],"mappings":"AAGA,OAAO,EAAE,WAAW,EAA6D,MAAM,WAAW,CAAA;AAElG,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAM1D,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,WAAW,aAAa;IAC5B,GAAG,EAAE,MAAM,CAAA;IACX,MAAM,EAAE,MAAM,CAAA;IACd,QAAQ,EAAE,MAAM,CAAA;IAChB,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED;;;GAGG;AACH,wBAAsB,qBAAqB,CACzC,KAAK,EAAE,MAAM,EAAE,EACf,qBAAqB,EAAE,eAAe,EAAE,EACxC,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,aAAa,EAAE,CAAC,CAqF1B;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,OAAO,EAAE,MAAM,EAAE,EACjB,YAAY,EAAE,eAAe,EAAE,GAC9B,eAAe,EAAE,CAQnB;AAiBD,wBAAgB,oBAAoB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAqB7D;AAED;;;GAGG;AACH,wBAAsB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAc9F;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsBvF;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE,aAAa,EAAE,GAAG,IAAI,CAqC7D;AA8LD;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,iBA0F1F"}
|
|
@@ -255,6 +255,117 @@ function displayResults(results) {
|
|
|
255
255
|
}
|
|
256
256
|
console.log(`${bold}Summary:${reset} ${purple}${successCount} succeeded${reset}, ${errorCount > 0 ? `${red}${errorCount} failed${reset}` : `${gray}${errorCount} failed${reset}`}`);
|
|
257
257
|
}
|
|
258
|
+
// The server caps inbound request bodies at 5MB. The figmaDocs payload
|
|
259
|
+
// (one Code Connect template per requested component) dominates the body size,
|
|
260
|
+
// so for projects with many components we split into smaller chunks and send
|
|
261
|
+
// them in parallel rather than risking a 413.
|
|
262
|
+
const PREVIEW_CHUNK_SIZE = 50;
|
|
263
|
+
// Bound the number of chunks in flight at once. Without this cap, large
|
|
264
|
+
// libraries (~1k+ components) trigger N parallel preview requests, which
|
|
265
|
+
// overwhelms upstream token validation and causes spurious 403 "Invalid
|
|
266
|
+
// token" responses for the chunks that queue up too long.
|
|
267
|
+
const PREVIEW_MAX_CONCURRENCY = 5;
|
|
268
|
+
function chunkArray(arr, size) {
|
|
269
|
+
const chunks = [];
|
|
270
|
+
for (let i = 0; i < arr.length; i += size) {
|
|
271
|
+
chunks.push(arr.slice(i, i + size));
|
|
272
|
+
}
|
|
273
|
+
return chunks;
|
|
274
|
+
}
|
|
275
|
+
async function runInWaves(items, fn, maxConcurrency) {
|
|
276
|
+
const out = [];
|
|
277
|
+
for (let i = 0; i < items.length; i += maxConcurrency) {
|
|
278
|
+
const wave = items.slice(i, i + maxConcurrency);
|
|
279
|
+
const settled = await Promise.all(wave.map(fn));
|
|
280
|
+
out.push(...settled);
|
|
281
|
+
}
|
|
282
|
+
return out;
|
|
283
|
+
}
|
|
284
|
+
function sendPreviewChunk({ chunkNodeIds, requiredTemplates, baseApiUrl, fileKey, accessToken, }) {
|
|
285
|
+
const chunkTemplates = filterTemplatesForNodes(chunkNodeIds, requiredTemplates);
|
|
286
|
+
return fetch_1.request
|
|
287
|
+
.post(`${baseApiUrl}/code_connect/preview_snippets?file_key=${fileKey}`, { nodeIds: chunkNodeIds, figmaDocs: { all: chunkTemplates } }, { headers: (0, figma_rest_api_1.getHeaders)(accessToken) })
|
|
288
|
+
.then((response) => ({ chunkNodeIds, response, error: null }))
|
|
289
|
+
.catch((err) => ({ chunkNodeIds, response: null, error: err }));
|
|
290
|
+
}
|
|
291
|
+
function chunkOutcomeToResults(outcome, nodes, fileKey) {
|
|
292
|
+
const { chunkNodeIds, response, error } = outcome;
|
|
293
|
+
const results = [];
|
|
294
|
+
if (error) {
|
|
295
|
+
const errorMsg = (0, fetch_1.isFetchError)(error)
|
|
296
|
+
? error.data?.message || error.response.statusText
|
|
297
|
+
: String(error);
|
|
298
|
+
// 503 means the server-side killswitch is on — surface the server's
|
|
299
|
+
// message directly without the per-file/per-node noise so the user
|
|
300
|
+
// sees a single clear line during an incident.
|
|
301
|
+
if ((0, fetch_1.isFetchError)(error) && error.response.status === 503) {
|
|
302
|
+
(0, logging_1.exitWithError)(errorMsg);
|
|
303
|
+
}
|
|
304
|
+
else {
|
|
305
|
+
logging_1.logger.error(`Failed to preview components in file ${fileKey}: ${errorMsg}`);
|
|
306
|
+
for (const nodeId of chunkNodeIds) {
|
|
307
|
+
for (const node of nodes.filter((n) => n.nodeId === nodeId)) {
|
|
308
|
+
results.push({
|
|
309
|
+
url: node.url,
|
|
310
|
+
nodeId: node.nodeId,
|
|
311
|
+
filePath: node.filePath,
|
|
312
|
+
success: false,
|
|
313
|
+
error: errorMsg,
|
|
314
|
+
});
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
return results;
|
|
319
|
+
}
|
|
320
|
+
if (response.response.status === 200 && response.data.meta?.results) {
|
|
321
|
+
// Track match index per nodeId so duplicate node IDs get the correct file attribution.
|
|
322
|
+
// The server returns results in the same order as the templates we sent. Each chunk's
|
|
323
|
+
// nodeIds are disjoint (we dedupe before chunking), so per-chunk indexing is correct.
|
|
324
|
+
const nodeMatchIndex = {};
|
|
325
|
+
for (const result of response.data.meta.results) {
|
|
326
|
+
const idx = nodeMatchIndex[result.nodeId] ?? 0;
|
|
327
|
+
const matchingNodes = nodes.filter((n) => n.nodeId === result.nodeId);
|
|
328
|
+
const node = matchingNodes[idx] || matchingNodes[0];
|
|
329
|
+
nodeMatchIndex[result.nodeId] = idx + 1;
|
|
330
|
+
results.push({
|
|
331
|
+
url: node?.url || result.nodeUrl,
|
|
332
|
+
nodeId: result.nodeId,
|
|
333
|
+
filePath: node?.filePath || '',
|
|
334
|
+
success: !result.error && !!result.snippet,
|
|
335
|
+
snippet: result.snippet,
|
|
336
|
+
language: result.language,
|
|
337
|
+
component: result.component,
|
|
338
|
+
error: result.error || (!result.snippet ? 'No snippet returned by server' : undefined),
|
|
339
|
+
});
|
|
340
|
+
}
|
|
341
|
+
return results;
|
|
342
|
+
}
|
|
343
|
+
for (const nodeId of chunkNodeIds) {
|
|
344
|
+
for (const node of nodes.filter((n) => n.nodeId === nodeId)) {
|
|
345
|
+
results.push({
|
|
346
|
+
url: node.url,
|
|
347
|
+
nodeId: node.nodeId,
|
|
348
|
+
filePath: node.filePath,
|
|
349
|
+
success: false,
|
|
350
|
+
error: `API request failed with status ${response.response.status}`,
|
|
351
|
+
});
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
return results;
|
|
355
|
+
}
|
|
356
|
+
async function previewFile({ fileKey, nodes, baseApiUrl, accessToken, dir, allCodeConnectObjects, }) {
|
|
357
|
+
const allNodeIds = nodes.map((n) => n.nodeId);
|
|
358
|
+
// Deduplicate — multiple figma.connect() calls may share the same nodeId;
|
|
359
|
+
// the individual templates are sent in figmaDocs and the server iterates per-template.
|
|
360
|
+
const nodeIds = [...new Set(allNodeIds)];
|
|
361
|
+
// Only send templates from the requested files — other files' templates
|
|
362
|
+
// for the same nodeId exist on the server and shouldn't be rendered individually.
|
|
363
|
+
const requestedFilePaths = new Set(nodes.map((n) => path_1.default.resolve(dir, n.filePath)));
|
|
364
|
+
const requiredTemplates = filterTemplatesForNodes(allNodeIds, allCodeConnectObjects).filter((t) => requestedFilePaths.has(path_1.default.resolve(t._codeConnectFilePath || '')));
|
|
365
|
+
const chunks = chunkArray(nodeIds, PREVIEW_CHUNK_SIZE);
|
|
366
|
+
const outcomes = await runInWaves(chunks, (chunkNodeIds) => sendPreviewChunk({ chunkNodeIds, requiredTemplates, baseApiUrl, fileKey, accessToken }), PREVIEW_MAX_CONCURRENCY);
|
|
367
|
+
return outcomes.flatMap((outcome) => chunkOutcomeToResults(outcome, nodes, fileKey));
|
|
368
|
+
}
|
|
258
369
|
/**
|
|
259
370
|
* Handle the preview command
|
|
260
371
|
*/
|
|
@@ -299,65 +410,15 @@ async function handlePreview(files, cmd) {
|
|
|
299
410
|
const results = [];
|
|
300
411
|
for (const [fileKey, nodes] of Object.entries(nodesByFileKey)) {
|
|
301
412
|
const baseApiUrl = (0, figma_rest_api_1.getApiUrl)(nodes[0].url, cmd.apiUrl || projectInfo.config.apiUrl);
|
|
302
|
-
const
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
try {
|
|
312
|
-
const response = await fetch_1.request.post(`${baseApiUrl}/code_connect/preview_snippets?file_key=${fileKey}`, { nodeIds, figmaDocs }, { headers: (0, figma_rest_api_1.getHeaders)(accessToken) });
|
|
313
|
-
if (response.response.status === 200 && response.data.meta?.results) {
|
|
314
|
-
// Track match index per nodeId so duplicate node IDs get the correct file attribution.
|
|
315
|
-
// The server returns results in the same order as the templates we sent.
|
|
316
|
-
const nodeMatchIndex = {};
|
|
317
|
-
for (const result of response.data.meta.results) {
|
|
318
|
-
const idx = nodeMatchIndex[result.nodeId] ?? 0;
|
|
319
|
-
const matchingNodes = nodes.filter((n) => n.nodeId === result.nodeId);
|
|
320
|
-
const node = matchingNodes[idx] || matchingNodes[0];
|
|
321
|
-
nodeMatchIndex[result.nodeId] = idx + 1;
|
|
322
|
-
results.push({
|
|
323
|
-
url: node?.url || result.nodeUrl,
|
|
324
|
-
nodeId: result.nodeId,
|
|
325
|
-
filePath: node?.filePath || '',
|
|
326
|
-
success: !result.error && !!result.snippet,
|
|
327
|
-
snippet: result.snippet,
|
|
328
|
-
language: result.language,
|
|
329
|
-
component: result.component,
|
|
330
|
-
error: result.error || (!result.snippet ? 'No snippet returned by server' : undefined),
|
|
331
|
-
});
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
else {
|
|
335
|
-
for (const node of nodes) {
|
|
336
|
-
results.push({
|
|
337
|
-
url: node.url,
|
|
338
|
-
nodeId: node.nodeId,
|
|
339
|
-
filePath: node.filePath,
|
|
340
|
-
success: false,
|
|
341
|
-
error: `API request failed with status ${response.response.status}`,
|
|
342
|
-
});
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
}
|
|
346
|
-
catch (err) {
|
|
347
|
-
const errorMsg = (0, fetch_1.isFetchError)(err)
|
|
348
|
-
? err.data?.message || err.response.statusText
|
|
349
|
-
: String(err);
|
|
350
|
-
logging_1.logger.error(`Failed to preview components in file ${fileKey}: ${errorMsg}`);
|
|
351
|
-
for (const node of nodes) {
|
|
352
|
-
results.push({
|
|
353
|
-
url: node.url,
|
|
354
|
-
nodeId: node.nodeId,
|
|
355
|
-
filePath: node.filePath,
|
|
356
|
-
success: false,
|
|
357
|
-
error: errorMsg,
|
|
358
|
-
});
|
|
359
|
-
}
|
|
360
|
-
}
|
|
413
|
+
const fileResults = await previewFile({
|
|
414
|
+
fileKey,
|
|
415
|
+
nodes,
|
|
416
|
+
baseApiUrl,
|
|
417
|
+
accessToken,
|
|
418
|
+
dir,
|
|
419
|
+
allCodeConnectObjects,
|
|
420
|
+
});
|
|
421
|
+
results.push(...fileResults);
|
|
361
422
|
}
|
|
362
423
|
// Validate snippet syntax
|
|
363
424
|
for (const result of results) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"preview_utils.js","sourceRoot":"","sources":["../../src/commands/preview_utils.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport * as prettier from 'prettier'\nimport { BaseCommand, getCodeConnectObjects, getAccessTokenOrExit, setupHandler } from './connect'\nimport { exitWithError, logger } from '../common/logging'\nimport { CodeConnectJSON } from '../connect/figma_connect'\nimport { parseFigmaNode } from '../connect/validation'\nimport { getProjectInfo } from '../connect/project'\nimport { getApiUrl, getHeaders } from '../connect/figma_rest_api'\nimport { request, isFetchError } from '../common/fetch'\n\nexport interface NodeToPreview {\n fileKey: string\n nodeId: string\n url: string\n filePath: string\n}\n\nexport interface PreviewResult {\n url: string\n nodeId: string\n filePath: string\n success: boolean\n snippet?: string\n language?: string\n component?: string\n error?: string\n}\n\n/**\n * Collect nodes to preview from file arguments.\n * Matches by exact path first, then by basename.\n */\nexport async function collectNodesToPreview(\n files: string[],\n allCodeConnectObjects: CodeConnectJSON[],\n dir: string,\n cmd: BaseCommand,\n): Promise<NodeToPreview[]> {\n const nodesToPreview: NodeToPreview[] = []\n\n for (const filePath of files) {\n const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(dir, filePath)\n\n // Try exact path first\n if (fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isFile()) {\n const docs = allCodeConnectObjects.filter(\n (d) => path.resolve(d._codeConnectFilePath || '') === resolvedPath,\n )\n if (docs.length > 0) {\n if (docs.length === 1) {\n logger.info(`Found: ${filePath}`)\n } else {\n logger.info(`Found ${docs.length} component definition(s) in ${filePath}`)\n }\n for (const doc of docs) {\n const parsed = parseFigmaNode(cmd.verbose, doc, true)\n if (parsed) {\n nodesToPreview.push({\n fileKey: parsed.fileKey,\n nodeId: parsed.nodeId,\n url: doc.figmaNode,\n filePath: path.relative(dir, doc._codeConnectFilePath || ''),\n })\n } else {\n logger.error(`Failed to parse figmaNode from file: ${filePath}`)\n }\n }\n } else {\n logger.error(`Not a valid Code Connect file: ${filePath}`)\n }\n continue\n }\n\n // Fall back to basename matching\n const fileName = path.basename(filePath)\n if (cmd.verbose) {\n logger.debug(`Searching for files matching: ${fileName}`)\n logger.debug(`Total Code Connect objects: ${allCodeConnectObjects.length}`)\n }\n\n const matches = allCodeConnectObjects.filter(\n (d) => path.basename(d._codeConnectFilePath || '') === fileName,\n )\n\n if (matches.length === 0) {\n logger.error(`No files found matching: ${filePath}`)\n continue\n }\n\n if (matches.length === 1) {\n logger.info(`Found: ${matches[0]._codeConnectFilePath}`)\n } else {\n const uniqueFiles = new Set(matches.map((d) => d._codeConnectFilePath))\n if (uniqueFiles.size === 1) {\n logger.info(\n `Found ${matches.length} component definition(s) in ${path.relative(dir, Array.from(uniqueFiles)[0] || '')}`,\n )\n } else {\n logger.info(`Found ${matches.length} component definition(s) in ${uniqueFiles.size} files:`)\n for (const fp of uniqueFiles) {\n const count = matches.filter((d) => d._codeConnectFilePath === fp).length\n logger.info(\n ` - ${path.relative(dir, fp || '')} (${count} definition${count > 1 ? 's' : ''})`,\n )\n }\n }\n }\n\n for (const doc of matches) {\n const parsed = parseFigmaNode(cmd.verbose, doc, true)\n if (parsed) {\n nodesToPreview.push({\n fileKey: parsed.fileKey,\n nodeId: parsed.nodeId,\n url: doc.figmaNode,\n filePath: path.relative(dir, doc._codeConnectFilePath || ''),\n })\n }\n }\n }\n\n return nodesToPreview\n}\n\n/**\n * Filter templates to only those matching the requested node IDs.\n */\nexport function filterTemplatesForNodes(\n nodeIds: string[],\n allTemplates: CodeConnectJSON[],\n): CodeConnectJSON[] {\n return allTemplates.filter((template) => {\n if (!template.figmaNode) return false\n const nodeIdMatch = template.figmaNode.match(/node-id=([^&\\s]+)/)\n if (!nodeIdMatch?.[1]) return false\n const templateNodeId = nodeIdMatch[1].replace(/-/g, ':')\n return nodeIds.includes(templateNodeId)\n })\n}\n\n/**\n * Aliases for Code Connect labels that don't directly match a Prettier language name.\n */\nconst CC_LABEL_ALIASES: Record<string, string> = {\n react: 'typescript',\n code: 'typescript',\n}\n\n/**\n * Map from Code Connect language labels to Prettier parser names,\n * built lazily from Prettier's getSupportInfo() on first access.\n * Lazy to avoid triggering plugin loading at module import time.\n */\nlet _prettierParserMap: Record<string, string> | null = null\n\nexport function getPrettierParserMap(): Record<string, string> {\n if (_prettierParserMap) return _prettierParserMap\n\n const info = prettier.getSupportInfo() as {\n languages: Array<{ name: string; parsers?: string[] }>\n }\n _prettierParserMap = {}\n\n for (const lang of info.languages) {\n if (lang.parsers?.[0]) {\n _prettierParserMap[lang.name.toLowerCase()] = lang.parsers[0]\n }\n }\n\n for (const [alias, target] of Object.entries(CC_LABEL_ALIASES)) {\n if (_prettierParserMap[target]) {\n _prettierParserMap[alias] = _prettierParserMap[target]\n }\n }\n\n return _prettierParserMap\n}\n\n/**\n * Check if a snippet can be parsed by Prettier.\n * Returns true for languages without a Prettier parser (nothing to validate).\n */\nexport async function isPrettierParseable(snippet: string, language?: string): Promise<boolean> {\n const lang = language?.toLowerCase()\n const parser = lang ? getPrettierParserMap()[lang] : 'typescript'\n\n if (!parser) {\n return true\n }\n\n try {\n await prettier.format(snippet, { parser })\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Format snippet with Prettier.\n * Returns the snippet unmodified for languages Prettier doesn't support.\n */\nexport async function formatSnippet(snippet: string, language?: string): Promise<string> {\n const lang = language?.toLowerCase()\n const parser = lang ? getPrettierParserMap()[lang] : 'typescript'\n\n if (!parser) {\n return snippet\n }\n\n try {\n let formatted = await prettier.format(snippet, {\n parser,\n semi: false,\n singleQuote: true,\n printWidth: 80,\n tabWidth: 2,\n })\n formatted = formatted.replace(/^;\\s*/, '')\n return formatted\n } catch {\n logger.info(`Autoformatting couldn't be applied: language not supported or code is malformed`)\n return snippet\n }\n}\n\n/**\n * Display results with terminal colors\n */\nexport function displayResults(results: PreviewResult[]): void {\n console.log('')\n const successCount = results.filter((r) => r.success).length\n const errorCount = results.filter((r) => !r.success).length\n\n const purple = '\\x1b[38;5;93m'\n const red = '\\x1b[38;5;196m'\n const gray = '\\x1b[38;5;243m'\n const reset = '\\x1b[0m'\n const bold = '\\x1b[1m'\n\n for (const result of results) {\n if (result.success && result.snippet) {\n const componentInfo = result.component ? ` ${gray}→ ${result.component}${reset}` : ''\n console.log(`${purple}●${reset} ${bold}${result.filePath}${reset}${componentInfo}`)\n console.log(` ${gray}${result.url}${reset}`)\n console.log('')\n\n const indentedSnippet = result.snippet\n .trim()\n .split('\\n')\n .map((line) => ' ' + line)\n .join('\\n')\n console.log(indentedSnippet)\n console.log('')\n } else {\n const componentInfo = result.component ? ` ${gray}(${result.component})${reset}` : ''\n console.log(`${red}✕${reset} ${bold}${result.filePath}${reset}${componentInfo}`)\n console.log(` ${gray}${result.url}${reset}`)\n console.log(` ${red}Error:${reset} ${result.error}`)\n console.log('')\n }\n }\n\n console.log(\n `${bold}Summary:${reset} ${purple}${successCount} succeeded${reset}, ${errorCount > 0 ? `${red}${errorCount} failed${reset}` : `${gray}${errorCount} failed${reset}`}`,\n )\n}\n\n/**\n * Handle the preview command\n */\nexport async function handlePreview(files: string[], cmd: BaseCommand & { output?: string }) {\n setupHandler(cmd)\n\n const dir = cmd.dir ?? process.cwd()\n const projectInfo = await getProjectInfo(dir, cmd.config)\n const accessToken = getAccessTokenOrExit(cmd)\n const outputFormat = cmd.output || 'table'\n\n const allCodeConnectObjects = await getCodeConnectObjects(cmd, projectInfo, true)\n\n let nodesToCheck: NodeToPreview[]\n\n if (files && files.length > 0) {\n nodesToCheck = await collectNodesToPreview(files, allCodeConnectObjects, dir, cmd)\n } else {\n logger.info('Previewing all local Code Connect files...')\n nodesToCheck = []\n for (const doc of allCodeConnectObjects) {\n const parsed = parseFigmaNode(cmd.verbose, doc, true)\n if (parsed) {\n nodesToCheck.push({\n fileKey: parsed.fileKey,\n nodeId: parsed.nodeId,\n url: doc.figmaNode,\n filePath: path.relative(dir, doc._codeConnectFilePath || ''),\n })\n }\n }\n }\n\n if (nodesToCheck.length === 0) {\n exitWithError('No valid Code Connect files found to preview')\n }\n\n logger.info(`Previewing ${nodesToCheck.length} component(s)...`)\n\n // Group nodes by fileKey for batching\n const nodesByFileKey: Record<string, NodeToPreview[]> = {}\n for (const node of nodesToCheck) {\n if (!nodesByFileKey[node.fileKey]) {\n nodesByFileKey[node.fileKey] = []\n }\n nodesByFileKey[node.fileKey].push(node)\n }\n\n const results: PreviewResult[] = []\n\n for (const [fileKey, nodes] of Object.entries(nodesByFileKey)) {\n const baseApiUrl = getApiUrl(nodes[0].url, cmd.apiUrl || projectInfo.config.apiUrl)\n const allNodeIds = nodes.map((n) => n.nodeId)\n // Deduplicate — multiple figma.connect() calls may share the same nodeId;\n // the individual templates are sent in figmaDocs and the server iterates per-template.\n const nodeIds = [...new Set(allNodeIds)]\n\n // Only send templates from the requested files — other files' templates\n // for the same nodeId exist on the server and shouldn't be rendered individually.\n const requestedFilePaths = new Set(nodes.map((n) => path.resolve(dir, n.filePath)))\n const requiredTemplates = filterTemplatesForNodes(allNodeIds, allCodeConnectObjects).filter(\n (t) => requestedFilePaths.has(path.resolve(t._codeConnectFilePath || '')),\n )\n const figmaDocs: Record<string, any[]> = { all: requiredTemplates }\n\n try {\n const response = await request.post<{\n status: number\n error: boolean\n meta: {\n results: Array<{\n nodeId: string\n nodeUrl: string\n snippet?: string\n language?: string\n component?: string\n error?: string\n }>\n }\n }>(\n `${baseApiUrl}/code_connect/preview_snippets?file_key=${fileKey}`,\n { nodeIds, figmaDocs },\n { headers: getHeaders(accessToken) },\n )\n\n if (response.response.status === 200 && response.data.meta?.results) {\n // Track match index per nodeId so duplicate node IDs get the correct file attribution.\n // The server returns results in the same order as the templates we sent.\n const nodeMatchIndex: Record<string, number> = {}\n\n for (const result of response.data.meta.results) {\n const idx = nodeMatchIndex[result.nodeId] ?? 0\n const matchingNodes = nodes.filter((n) => n.nodeId === result.nodeId)\n const node = matchingNodes[idx] || matchingNodes[0]\n nodeMatchIndex[result.nodeId] = idx + 1\n\n results.push({\n url: node?.url || result.nodeUrl,\n nodeId: result.nodeId,\n filePath: node?.filePath || '',\n success: !result.error && !!result.snippet,\n snippet: result.snippet,\n language: result.language,\n component: result.component,\n error: result.error || (!result.snippet ? 'No snippet returned by server' : undefined),\n })\n }\n } else {\n for (const node of nodes) {\n results.push({\n url: node.url,\n nodeId: node.nodeId,\n filePath: node.filePath,\n success: false,\n error: `API request failed with status ${response.response.status}`,\n })\n }\n }\n } catch (err) {\n const errorMsg = isFetchError(err)\n ? err.data?.message || err.response.statusText\n : String(err)\n logger.error(`Failed to preview components in file ${fileKey}: ${errorMsg}`)\n for (const node of nodes) {\n results.push({\n url: node.url,\n nodeId: node.nodeId,\n filePath: node.filePath,\n success: false,\n error: errorMsg,\n })\n }\n }\n }\n\n // Validate snippet syntax\n for (const result of results) {\n if (result.success && result.snippet) {\n const prettierValid = await isPrettierParseable(result.snippet, result.language)\n if (!prettierValid) {\n // Prettier can parse this language but failed — mark as error\n result.success = false\n result.error = 'Snippet has syntax errors and may not be valid code'\n }\n }\n }\n\n if (outputFormat === 'json') {\n console.log(JSON.stringify(results, null, 2))\n } else {\n const formattedResults: PreviewResult[] = await Promise.all(\n results.map(async (result) => {\n if (result.success && result.snippet) {\n const formattedSnippet = await formatSnippet(result.snippet, result.language)\n return { ...result, snippet: formattedSnippet }\n }\n return result\n }),\n )\n displayResults(formattedResults)\n }\n\n if (results.every((r) => !r.success)) {\n process.exit(1)\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"preview_utils.js","sourceRoot":"","sources":["../../src/commands/preview_utils.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs'\nimport path from 'path'\nimport * as prettier from 'prettier'\nimport { BaseCommand, getCodeConnectObjects, getAccessTokenOrExit, setupHandler } from './connect'\nimport { exitWithError, logger } from '../common/logging'\nimport { CodeConnectJSON } from '../connect/figma_connect'\nimport { parseFigmaNode } from '../connect/validation'\nimport { getProjectInfo } from '../connect/project'\nimport { getApiUrl, getHeaders } from '../connect/figma_rest_api'\nimport { request, isFetchError } from '../common/fetch'\n\nexport interface NodeToPreview {\n fileKey: string\n nodeId: string\n url: string\n filePath: string\n}\n\nexport interface PreviewResult {\n url: string\n nodeId: string\n filePath: string\n success: boolean\n snippet?: string\n language?: string\n component?: string\n error?: string\n}\n\n/**\n * Collect nodes to preview from file arguments.\n * Matches by exact path first, then by basename.\n */\nexport async function collectNodesToPreview(\n files: string[],\n allCodeConnectObjects: CodeConnectJSON[],\n dir: string,\n cmd: BaseCommand,\n): Promise<NodeToPreview[]> {\n const nodesToPreview: NodeToPreview[] = []\n\n for (const filePath of files) {\n const resolvedPath = path.isAbsolute(filePath) ? filePath : path.resolve(dir, filePath)\n\n // Try exact path first\n if (fs.existsSync(resolvedPath) && fs.statSync(resolvedPath).isFile()) {\n const docs = allCodeConnectObjects.filter(\n (d) => path.resolve(d._codeConnectFilePath || '') === resolvedPath,\n )\n if (docs.length > 0) {\n if (docs.length === 1) {\n logger.info(`Found: ${filePath}`)\n } else {\n logger.info(`Found ${docs.length} component definition(s) in ${filePath}`)\n }\n for (const doc of docs) {\n const parsed = parseFigmaNode(cmd.verbose, doc, true)\n if (parsed) {\n nodesToPreview.push({\n fileKey: parsed.fileKey,\n nodeId: parsed.nodeId,\n url: doc.figmaNode,\n filePath: path.relative(dir, doc._codeConnectFilePath || ''),\n })\n } else {\n logger.error(`Failed to parse figmaNode from file: ${filePath}`)\n }\n }\n } else {\n logger.error(`Not a valid Code Connect file: ${filePath}`)\n }\n continue\n }\n\n // Fall back to basename matching\n const fileName = path.basename(filePath)\n if (cmd.verbose) {\n logger.debug(`Searching for files matching: ${fileName}`)\n logger.debug(`Total Code Connect objects: ${allCodeConnectObjects.length}`)\n }\n\n const matches = allCodeConnectObjects.filter(\n (d) => path.basename(d._codeConnectFilePath || '') === fileName,\n )\n\n if (matches.length === 0) {\n logger.error(`No files found matching: ${filePath}`)\n continue\n }\n\n if (matches.length === 1) {\n logger.info(`Found: ${matches[0]._codeConnectFilePath}`)\n } else {\n const uniqueFiles = new Set(matches.map((d) => d._codeConnectFilePath))\n if (uniqueFiles.size === 1) {\n logger.info(\n `Found ${matches.length} component definition(s) in ${path.relative(dir, Array.from(uniqueFiles)[0] || '')}`,\n )\n } else {\n logger.info(`Found ${matches.length} component definition(s) in ${uniqueFiles.size} files:`)\n for (const fp of uniqueFiles) {\n const count = matches.filter((d) => d._codeConnectFilePath === fp).length\n logger.info(\n ` - ${path.relative(dir, fp || '')} (${count} definition${count > 1 ? 's' : ''})`,\n )\n }\n }\n }\n\n for (const doc of matches) {\n const parsed = parseFigmaNode(cmd.verbose, doc, true)\n if (parsed) {\n nodesToPreview.push({\n fileKey: parsed.fileKey,\n nodeId: parsed.nodeId,\n url: doc.figmaNode,\n filePath: path.relative(dir, doc._codeConnectFilePath || ''),\n })\n }\n }\n }\n\n return nodesToPreview\n}\n\n/**\n * Filter templates to only those matching the requested node IDs.\n */\nexport function filterTemplatesForNodes(\n nodeIds: string[],\n allTemplates: CodeConnectJSON[],\n): CodeConnectJSON[] {\n return allTemplates.filter((template) => {\n if (!template.figmaNode) return false\n const nodeIdMatch = template.figmaNode.match(/node-id=([^&\\s]+)/)\n if (!nodeIdMatch?.[1]) return false\n const templateNodeId = nodeIdMatch[1].replace(/-/g, ':')\n return nodeIds.includes(templateNodeId)\n })\n}\n\n/**\n * Aliases for Code Connect labels that don't directly match a Prettier language name.\n */\nconst CC_LABEL_ALIASES: Record<string, string> = {\n react: 'typescript',\n code: 'typescript',\n}\n\n/**\n * Map from Code Connect language labels to Prettier parser names,\n * built lazily from Prettier's getSupportInfo() on first access.\n * Lazy to avoid triggering plugin loading at module import time.\n */\nlet _prettierParserMap: Record<string, string> | null = null\n\nexport function getPrettierParserMap(): Record<string, string> {\n if (_prettierParserMap) return _prettierParserMap\n\n const info = prettier.getSupportInfo() as {\n languages: Array<{ name: string; parsers?: string[] }>\n }\n _prettierParserMap = {}\n\n for (const lang of info.languages) {\n if (lang.parsers?.[0]) {\n _prettierParserMap[lang.name.toLowerCase()] = lang.parsers[0]\n }\n }\n\n for (const [alias, target] of Object.entries(CC_LABEL_ALIASES)) {\n if (_prettierParserMap[target]) {\n _prettierParserMap[alias] = _prettierParserMap[target]\n }\n }\n\n return _prettierParserMap\n}\n\n/**\n * Check if a snippet can be parsed by Prettier.\n * Returns true for languages without a Prettier parser (nothing to validate).\n */\nexport async function isPrettierParseable(snippet: string, language?: string): Promise<boolean> {\n const lang = language?.toLowerCase()\n const parser = lang ? getPrettierParserMap()[lang] : 'typescript'\n\n if (!parser) {\n return true\n }\n\n try {\n await prettier.format(snippet, { parser })\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Format snippet with Prettier.\n * Returns the snippet unmodified for languages Prettier doesn't support.\n */\nexport async function formatSnippet(snippet: string, language?: string): Promise<string> {\n const lang = language?.toLowerCase()\n const parser = lang ? getPrettierParserMap()[lang] : 'typescript'\n\n if (!parser) {\n return snippet\n }\n\n try {\n let formatted = await prettier.format(snippet, {\n parser,\n semi: false,\n singleQuote: true,\n printWidth: 80,\n tabWidth: 2,\n })\n formatted = formatted.replace(/^;\\s*/, '')\n return formatted\n } catch {\n logger.info(`Autoformatting couldn't be applied: language not supported or code is malformed`)\n return snippet\n }\n}\n\n/**\n * Display results with terminal colors\n */\nexport function displayResults(results: PreviewResult[]): void {\n console.log('')\n const successCount = results.filter((r) => r.success).length\n const errorCount = results.filter((r) => !r.success).length\n\n const purple = '\\x1b[38;5;93m'\n const red = '\\x1b[38;5;196m'\n const gray = '\\x1b[38;5;243m'\n const reset = '\\x1b[0m'\n const bold = '\\x1b[1m'\n\n for (const result of results) {\n if (result.success && result.snippet) {\n const componentInfo = result.component ? ` ${gray}→ ${result.component}${reset}` : ''\n console.log(`${purple}●${reset} ${bold}${result.filePath}${reset}${componentInfo}`)\n console.log(` ${gray}${result.url}${reset}`)\n console.log('')\n\n const indentedSnippet = result.snippet\n .trim()\n .split('\\n')\n .map((line) => ' ' + line)\n .join('\\n')\n console.log(indentedSnippet)\n console.log('')\n } else {\n const componentInfo = result.component ? ` ${gray}(${result.component})${reset}` : ''\n console.log(`${red}✕${reset} ${bold}${result.filePath}${reset}${componentInfo}`)\n console.log(` ${gray}${result.url}${reset}`)\n console.log(` ${red}Error:${reset} ${result.error}`)\n console.log('')\n }\n }\n\n console.log(\n `${bold}Summary:${reset} ${purple}${successCount} succeeded${reset}, ${errorCount > 0 ? `${red}${errorCount} failed${reset}` : `${gray}${errorCount} failed${reset}`}`,\n )\n}\n\n// The server caps inbound request bodies at 5MB. The figmaDocs payload\n// (one Code Connect template per requested component) dominates the body size,\n// so for projects with many components we split into smaller chunks and send\n// them in parallel rather than risking a 413.\nconst PREVIEW_CHUNK_SIZE = 50\n// Bound the number of chunks in flight at once. Without this cap, large\n// libraries (~1k+ components) trigger N parallel preview requests, which\n// overwhelms upstream token validation and causes spurious 403 \"Invalid\n// token\" responses for the chunks that queue up too long.\nconst PREVIEW_MAX_CONCURRENCY = 5\n\ntype PreviewResponseData = {\n status: number\n error: boolean\n meta: {\n results: Array<{\n nodeId: string\n nodeUrl: string\n snippet?: string\n language?: string\n component?: string\n error?: string\n }>\n }\n}\n\ntype ChunkOutcome = {\n chunkNodeIds: string[]\n response: Awaited<ReturnType<typeof request.post<PreviewResponseData>>> | null\n error: unknown\n}\n\nfunction chunkArray<T>(arr: T[], size: number): T[][] {\n const chunks: T[][] = []\n for (let i = 0; i < arr.length; i += size) {\n chunks.push(arr.slice(i, i + size))\n }\n return chunks\n}\n\nasync function runInWaves<T, R>(\n items: T[],\n fn: (item: T) => Promise<R>,\n maxConcurrency: number,\n): Promise<R[]> {\n const out: R[] = []\n for (let i = 0; i < items.length; i += maxConcurrency) {\n const wave = items.slice(i, i + maxConcurrency)\n const settled = await Promise.all(wave.map(fn))\n out.push(...settled)\n }\n return out\n}\n\nfunction sendPreviewChunk({\n chunkNodeIds,\n requiredTemplates,\n baseApiUrl,\n fileKey,\n accessToken,\n}: {\n chunkNodeIds: string[]\n requiredTemplates: CodeConnectJSON[]\n baseApiUrl: string\n fileKey: string\n accessToken: string\n}): Promise<ChunkOutcome> {\n const chunkTemplates = filterTemplatesForNodes(chunkNodeIds, requiredTemplates)\n return request\n .post<PreviewResponseData>(\n `${baseApiUrl}/code_connect/preview_snippets?file_key=${fileKey}`,\n { nodeIds: chunkNodeIds, figmaDocs: { all: chunkTemplates } },\n { headers: getHeaders(accessToken) },\n )\n .then((response) => ({ chunkNodeIds, response, error: null as unknown }))\n .catch((err: unknown) => ({ chunkNodeIds, response: null, error: err }))\n}\n\nfunction chunkOutcomeToResults(\n outcome: ChunkOutcome,\n nodes: NodeToPreview[],\n fileKey: string,\n): PreviewResult[] {\n const { chunkNodeIds, response, error } = outcome\n const results: PreviewResult[] = []\n\n if (error) {\n const errorMsg = isFetchError(error)\n ? error.data?.message || error.response.statusText\n : String(error)\n // 503 means the server-side killswitch is on — surface the server's\n // message directly without the per-file/per-node noise so the user\n // sees a single clear line during an incident.\n if (isFetchError(error) && error.response.status === 503) {\n exitWithError(errorMsg)\n } else {\n logger.error(`Failed to preview components in file ${fileKey}: ${errorMsg}`)\n for (const nodeId of chunkNodeIds) {\n for (const node of nodes.filter((n) => n.nodeId === nodeId)) {\n results.push({\n url: node.url,\n nodeId: node.nodeId,\n filePath: node.filePath,\n success: false,\n error: errorMsg,\n })\n }\n }\n }\n return results\n }\n\n if (response!.response.status === 200 && response!.data.meta?.results) {\n // Track match index per nodeId so duplicate node IDs get the correct file attribution.\n // The server returns results in the same order as the templates we sent. Each chunk's\n // nodeIds are disjoint (we dedupe before chunking), so per-chunk indexing is correct.\n const nodeMatchIndex: Record<string, number> = {}\n for (const result of response!.data.meta.results) {\n const idx = nodeMatchIndex[result.nodeId] ?? 0\n const matchingNodes = nodes.filter((n) => n.nodeId === result.nodeId)\n const node = matchingNodes[idx] || matchingNodes[0]\n nodeMatchIndex[result.nodeId] = idx + 1\n results.push({\n url: node?.url || result.nodeUrl,\n nodeId: result.nodeId,\n filePath: node?.filePath || '',\n success: !result.error && !!result.snippet,\n snippet: result.snippet,\n language: result.language,\n component: result.component,\n error: result.error || (!result.snippet ? 'No snippet returned by server' : undefined),\n })\n }\n return results\n }\n\n for (const nodeId of chunkNodeIds) {\n for (const node of nodes.filter((n) => n.nodeId === nodeId)) {\n results.push({\n url: node.url,\n nodeId: node.nodeId,\n filePath: node.filePath,\n success: false,\n error: `API request failed with status ${response!.response.status}`,\n })\n }\n }\n return results\n}\n\nasync function previewFile({\n fileKey,\n nodes,\n baseApiUrl,\n accessToken,\n dir,\n allCodeConnectObjects,\n}: {\n fileKey: string\n nodes: NodeToPreview[]\n baseApiUrl: string\n accessToken: string\n dir: string\n allCodeConnectObjects: CodeConnectJSON[]\n}): Promise<PreviewResult[]> {\n const allNodeIds = nodes.map((n) => n.nodeId)\n // Deduplicate — multiple figma.connect() calls may share the same nodeId;\n // the individual templates are sent in figmaDocs and the server iterates per-template.\n const nodeIds = [...new Set(allNodeIds)]\n\n // Only send templates from the requested files — other files' templates\n // for the same nodeId exist on the server and shouldn't be rendered individually.\n const requestedFilePaths = new Set(nodes.map((n) => path.resolve(dir, n.filePath)))\n const requiredTemplates = filterTemplatesForNodes(allNodeIds, allCodeConnectObjects).filter((t) =>\n requestedFilePaths.has(path.resolve(t._codeConnectFilePath || '')),\n )\n\n const chunks = chunkArray(nodeIds, PREVIEW_CHUNK_SIZE)\n const outcomes = await runInWaves(\n chunks,\n (chunkNodeIds) =>\n sendPreviewChunk({ chunkNodeIds, requiredTemplates, baseApiUrl, fileKey, accessToken }),\n PREVIEW_MAX_CONCURRENCY,\n )\n\n return outcomes.flatMap((outcome) => chunkOutcomeToResults(outcome, nodes, fileKey))\n}\n\n/**\n * Handle the preview command\n */\nexport async function handlePreview(files: string[], cmd: BaseCommand & { output?: string }) {\n setupHandler(cmd)\n\n const dir = cmd.dir ?? process.cwd()\n const projectInfo = await getProjectInfo(dir, cmd.config)\n const accessToken = getAccessTokenOrExit(cmd)\n const outputFormat = cmd.output || 'table'\n\n const allCodeConnectObjects = await getCodeConnectObjects(cmd, projectInfo, true)\n\n let nodesToCheck: NodeToPreview[]\n\n if (files && files.length > 0) {\n nodesToCheck = await collectNodesToPreview(files, allCodeConnectObjects, dir, cmd)\n } else {\n logger.info('Previewing all local Code Connect files...')\n nodesToCheck = []\n for (const doc of allCodeConnectObjects) {\n const parsed = parseFigmaNode(cmd.verbose, doc, true)\n if (parsed) {\n nodesToCheck.push({\n fileKey: parsed.fileKey,\n nodeId: parsed.nodeId,\n url: doc.figmaNode,\n filePath: path.relative(dir, doc._codeConnectFilePath || ''),\n })\n }\n }\n }\n\n if (nodesToCheck.length === 0) {\n exitWithError('No valid Code Connect files found to preview')\n }\n\n logger.info(`Previewing ${nodesToCheck.length} component(s)...`)\n\n // Group nodes by fileKey for batching\n const nodesByFileKey: Record<string, NodeToPreview[]> = {}\n for (const node of nodesToCheck) {\n if (!nodesByFileKey[node.fileKey]) {\n nodesByFileKey[node.fileKey] = []\n }\n nodesByFileKey[node.fileKey].push(node)\n }\n\n const results: PreviewResult[] = []\n\n for (const [fileKey, nodes] of Object.entries(nodesByFileKey)) {\n const baseApiUrl = getApiUrl(nodes[0].url, cmd.apiUrl || projectInfo.config.apiUrl)\n const fileResults = await previewFile({\n fileKey,\n nodes,\n baseApiUrl,\n accessToken,\n dir,\n allCodeConnectObjects,\n })\n results.push(...fileResults)\n }\n\n // Validate snippet syntax\n for (const result of results) {\n if (result.success && result.snippet) {\n const prettierValid = await isPrettierParseable(result.snippet, result.language)\n if (!prettierValid) {\n // Prettier can parse this language but failed — mark as error\n result.success = false\n result.error = 'Snippet has syntax errors and may not be valid code'\n }\n }\n }\n\n if (outputFormat === 'json') {\n console.log(JSON.stringify(results, null, 2))\n } else {\n const formattedResults: PreviewResult[] = await Promise.all(\n results.map(async (result) => {\n if (result.success && result.snippet) {\n const formattedSnippet = await formatSnippet(result.snippet, result.language)\n return { ...result, snippet: formattedSnippet }\n }\n return result\n }),\n )\n displayResults(formattedResults)\n }\n\n if (results.every((r) => !r.success)) {\n process.exit(1)\n }\n}\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@figma/code-connect",
|
|
3
|
-
"version": "1.4.
|
|
3
|
+
"version": "1.4.5",
|
|
4
4
|
"description": "A tool for connecting your design system components in code with your design system in Figma",
|
|
5
5
|
"keywords": [],
|
|
6
6
|
"author": "Figma",
|
|
@@ -89,7 +89,7 @@
|
|
|
89
89
|
"jest": "^29.7.0",
|
|
90
90
|
"patch-package": "^8.0.0",
|
|
91
91
|
"pkg": "^5.8.1",
|
|
92
|
-
"ts-jest": "^29.
|
|
92
|
+
"ts-jest": "^29.4.9",
|
|
93
93
|
"ts-loader": "^9.5.1",
|
|
94
94
|
"tsx": "4.21.0",
|
|
95
95
|
"webpack": "5.91.0",
|
|
@@ -118,7 +118,7 @@
|
|
|
118
118
|
"prompts": "^2.4.2",
|
|
119
119
|
"strip-ansi": "^6.0.0",
|
|
120
120
|
"ts-morph": "^27.0.0",
|
|
121
|
-
"typescript": "
|
|
121
|
+
"typescript": "6.0.3",
|
|
122
122
|
|
|
123
123
|
"undici": "^7.19.1",
|
|
124
124
|
"zod": "3.25.58",
|