@figma/code-connect 1.4.3 → 1.4.4

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.
Files changed (53) hide show
  1. package/README.md +2 -22
  2. package/dist/commands/connect.d.ts.map +1 -1
  3. package/dist/commands/connect.js +61 -10
  4. package/dist/commands/connect.js.map +1 -1
  5. package/dist/commands/connect_template.d.ts +36 -0
  6. package/dist/commands/connect_template.d.ts.map +1 -0
  7. package/dist/commands/connect_template.js +324 -0
  8. package/dist/commands/connect_template.js.map +1 -0
  9. package/dist/commands/preview_utils.d.ts +49 -0
  10. package/dist/commands/preview_utils.d.ts.map +1 -0
  11. package/dist/commands/preview_utils.js +390 -0
  12. package/dist/commands/preview_utils.js.map +1 -0
  13. package/dist/connect/batch_templates.d.ts +11 -0
  14. package/dist/connect/batch_templates.d.ts.map +1 -0
  15. package/dist/connect/batch_templates.js +70 -0
  16. package/dist/connect/batch_templates.js.map +1 -0
  17. package/dist/connect/create.d.ts.map +1 -1
  18. package/dist/connect/create.js +13 -0
  19. package/dist/connect/create.js.map +1 -1
  20. package/dist/connect/create_template.d.ts +22 -0
  21. package/dist/connect/create_template.d.ts.map +1 -0
  22. package/dist/connect/create_template.js +195 -0
  23. package/dist/connect/create_template.js.map +1 -0
  24. package/dist/connect/delete_docs.d.ts +2 -1
  25. package/dist/connect/delete_docs.d.ts.map +1 -1
  26. package/dist/connect/delete_docs.js +2 -2
  27. package/dist/connect/delete_docs.js.map +1 -1
  28. package/dist/connect/figma_rest_api.d.ts +1 -5
  29. package/dist/connect/figma_rest_api.d.ts.map +1 -1
  30. package/dist/connect/figma_rest_api.js +9 -3
  31. package/dist/connect/figma_rest_api.js.map +1 -1
  32. package/dist/connect/project.d.ts +9 -7
  33. package/dist/connect/project.d.ts.map +1 -1
  34. package/dist/connect/project.js +39 -25
  35. package/dist/connect/project.js.map +1 -1
  36. package/dist/connect/raw_templates.d.ts +8 -1
  37. package/dist/connect/raw_templates.d.ts.map +1 -1
  38. package/dist/connect/raw_templates.js +20 -7
  39. package/dist/connect/raw_templates.js.map +1 -1
  40. package/dist/connect/upload.d.ts +3 -1
  41. package/dist/connect/upload.d.ts.map +1 -1
  42. package/dist/connect/upload.js +23 -8
  43. package/dist/connect/upload.js.map +1 -1
  44. package/dist/connect/validation.d.ts +2 -2
  45. package/dist/connect/validation.d.ts.map +1 -1
  46. package/dist/connect/validation.js +4 -4
  47. package/dist/connect/validation.js.map +1 -1
  48. package/dist/connect/wizard/helpers.js.map +1 -1
  49. package/dist/storybook/convert.d.ts.map +1 -1
  50. package/dist/storybook/convert.js +1 -1
  51. package/dist/storybook/convert.js.map +1 -1
  52. package/figma-types.d.ts +3 -0
  53. package/package.json +6 -2
@@ -0,0 +1,324 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.addCodeConnectCommandsToProgram = addCodeConnectCommandsToProgram;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const upload_1 = require("../connect/upload");
9
+ const validation_1 = require("../connect/validation");
10
+ const project_1 = require("../connect/project");
11
+ const logging_1 = require("../common/logging");
12
+ const delete_docs_1 = require("../connect/delete_docs");
13
+ const helpers_1 = require("../connect/helpers");
14
+ const raw_templates_1 = require("../connect/raw_templates");
15
+ const batch_templates_1 = require("../connect/batch_templates");
16
+ const filter_project_info_1 = require("./filter_project_info");
17
+ const create_template_1 = require("../connect/create_template");
18
+ function getAccessTokenOrExit(cmd) {
19
+ const token = cmd.token;
20
+ if (!token) {
21
+ (0, logging_1.exitWithError)(cmd.useOAuth
22
+ ? `Couldn't find a Figma OAuth token. Please re-authenticate.`
23
+ : `Couldn't find a Figma access token. Please set the FIGMA_ACCESS_TOKEN environment variable`);
24
+ }
25
+ return token;
26
+ }
27
+ function setupHandler(cmd) {
28
+ if (cmd.verbose) {
29
+ logging_1.logger.setLogLevel(logging_1.LogLevel.Debug);
30
+ }
31
+ }
32
+ function getDir(cmd) {
33
+ return cmd.dir ?? process.cwd();
34
+ }
35
+ /**
36
+ * Returns Code Connect objects from template files (.figma.ts / .figma.js)
37
+ * only. Native parser paths (react, html, executable) are intentionally
38
+ * omitted — this entry point is for parserless/template-file workflows.
39
+ */
40
+ async function getCodeConnectObjects(cmd, projectInfo, silent = false) {
41
+ const rawTemplateFiles = projectInfo.files.filter((f) => {
42
+ const isPotentialRawTemplate = f.endsWith('.figma.js') ||
43
+ f.endsWith('.figma.template.js') ||
44
+ f.endsWith('.figma.ts') ||
45
+ f.endsWith('.figma.template.ts');
46
+ if (!isPotentialRawTemplate)
47
+ return false;
48
+ try {
49
+ return (0, raw_templates_1.isRawTemplate)(fs_1.default.readFileSync(f, 'utf-8'));
50
+ }
51
+ catch {
52
+ return false;
53
+ }
54
+ });
55
+ let codeConnectObjects = [];
56
+ if (rawTemplateFiles.length > 0) {
57
+ const resolvedLabel = cmd.label || projectInfo.config.label;
58
+ const rawTemplateDocs = [];
59
+ for (const file of rawTemplateFiles) {
60
+ try {
61
+ const doc = (0, raw_templates_1.parseRawFile)(file, resolvedLabel, projectInfo.config, projectInfo.absPath);
62
+ doc._codeConnectFilePath = file;
63
+ if (!silent || cmd.verbose) {
64
+ logging_1.logger.info((0, logging_1.success)(file));
65
+ }
66
+ rawTemplateDocs.push(doc);
67
+ }
68
+ catch (e) {
69
+ if (!silent || cmd.verbose) {
70
+ logging_1.logger.error(`❌ ${file}`);
71
+ if (cmd.verbose) {
72
+ console.trace(e);
73
+ }
74
+ else {
75
+ logging_1.logger.error(e instanceof Error ? e.message : String(e));
76
+ }
77
+ }
78
+ if (cmd.exitOnUnreadableFiles) {
79
+ logging_1.logger.info('Exiting due to unreadable files');
80
+ process.exit(1);
81
+ }
82
+ }
83
+ }
84
+ codeConnectObjects = codeConnectObjects.concat(rawTemplateDocs);
85
+ }
86
+ // Process batch files (.figma.batch.json)
87
+ const batchFiles = projectInfo.files.filter((f) => f.endsWith('.figma.batch.json'));
88
+ if (batchFiles.length > 0) {
89
+ const resolvedLabel = cmd.label || projectInfo.config.label;
90
+ for (const file of batchFiles) {
91
+ try {
92
+ const docs = (0, batch_templates_1.parseBatchFile)(file, resolvedLabel, projectInfo.config, projectInfo.absPath);
93
+ docs.forEach((doc) => {
94
+ doc._codeConnectFilePath = file;
95
+ });
96
+ codeConnectObjects = codeConnectObjects.concat(docs);
97
+ if (!silent || cmd.verbose) {
98
+ logging_1.logger.info((0, logging_1.success)(`${file} (${docs.length} components)`));
99
+ }
100
+ }
101
+ catch (e) {
102
+ logging_1.logger.error(`${file}: ${e}`);
103
+ if (cmd.exitOnUnreadableFiles) {
104
+ process.exit(1);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ if (cmd.label || projectInfo.config.label) {
110
+ logging_1.logger.info(`Using label "${cmd.label || projectInfo.config.label}"`);
111
+ codeConnectObjects.forEach((doc) => {
112
+ doc.label = cmd.label || projectInfo.config.label || doc.label;
113
+ });
114
+ }
115
+ if (projectInfo.config.language) {
116
+ logging_1.logger.info(`Using language "${projectInfo.config.language}"`);
117
+ codeConnectObjects.forEach((doc) => {
118
+ doc.language = projectInfo.config.language || doc.language;
119
+ });
120
+ }
121
+ return codeConnectObjects;
122
+ }
123
+ async function handlePublish(cmd) {
124
+ setupHandler(cmd);
125
+ let dir = getDir(cmd);
126
+ const projectInfo = (0, filter_project_info_1.filterProjectInfoByFile)(await (0, project_1.getProjectInfo)(dir, cmd.config, true), cmd.file);
127
+ const codeConnectObjects = await getCodeConnectObjects(cmd, projectInfo);
128
+ if (codeConnectObjects.length === 0) {
129
+ logging_1.logger.warn(`No Code Connect files found in ${dir} - Make sure you have configured \`include\` and \`exclude\` in your figma.config.json file correctly, or that you are running in a directory that contains Code Connect files.`);
130
+ process.exit(0);
131
+ }
132
+ if (cmd.dryRun) {
133
+ logging_1.logger.info(`Files that would be published:`);
134
+ logging_1.logger.info(codeConnectObjects.map((o) => `- ${o.component} (${o.figmaNode})`).join('\n'));
135
+ }
136
+ const accessToken = getAccessTokenOrExit(cmd);
137
+ if (cmd.skipValidation) {
138
+ logging_1.logger.info('Validation skipped');
139
+ }
140
+ else {
141
+ logging_1.logger.info('Validating Code Connect files...');
142
+ const start = new Date().getTime();
143
+ const valid = await (0, validation_1.validateDocs)(cmd, accessToken, codeConnectObjects, cmd.apiUrl || projectInfo.config.apiUrl, cmd.useOAuth);
144
+ if (!valid) {
145
+ (0, helpers_1.exitWithFeedbackMessage)(1);
146
+ }
147
+ else {
148
+ const end = new Date().getTime();
149
+ const time = end - start;
150
+ logging_1.logger.info(`All Code Connect files are valid (${time}ms)`);
151
+ }
152
+ }
153
+ if (cmd.dryRun) {
154
+ logging_1.logger.info(`Dry run complete`);
155
+ process.exit(0);
156
+ }
157
+ let batchSize;
158
+ if (cmd.batchSize) {
159
+ batchSize = parseInt(cmd.batchSize, 10);
160
+ if (isNaN(batchSize)) {
161
+ logging_1.logger.error('Error: failed to parse batch-size. batch-size passed must be a number');
162
+ (0, helpers_1.exitWithFeedbackMessage)(1);
163
+ }
164
+ }
165
+ (0, upload_1.upload)({
166
+ accessToken,
167
+ useOAuth: cmd.useOAuth,
168
+ docs: codeConnectObjects,
169
+ batchSize,
170
+ verbose: cmd.verbose,
171
+ apiUrl: cmd.apiUrl || projectInfo.config.apiUrl,
172
+ force: cmd.force,
173
+ });
174
+ }
175
+ async function handleUnpublish(cmd) {
176
+ setupHandler(cmd);
177
+ let dir = getDir(cmd);
178
+ if (cmd.dryRun) {
179
+ logging_1.logger.info(`Files that would be unpublished:`);
180
+ }
181
+ let nodesToDeleteRelevantInfo;
182
+ const projectInfo = (0, filter_project_info_1.filterProjectInfoByFile)(await (0, project_1.getProjectInfo)(dir, cmd.config, true), cmd.file);
183
+ if (cmd.node) {
184
+ if (!cmd.label) {
185
+ (0, logging_1.exitWithError)('Label is required when specifying a node');
186
+ }
187
+ nodesToDeleteRelevantInfo = [{ figmaNode: cmd.node, label: cmd.label }];
188
+ }
189
+ else {
190
+ const codeConnectObjects = await getCodeConnectObjects(cmd, projectInfo);
191
+ nodesToDeleteRelevantInfo = codeConnectObjects.map((doc) => ({
192
+ figmaNode: doc.figmaNode,
193
+ label: cmd.label || projectInfo.config.label || doc.label,
194
+ }));
195
+ if (cmd.label || projectInfo.config.label) {
196
+ logging_1.logger.info(`Using label ${cmd.label || projectInfo.config.label}`);
197
+ }
198
+ if (cmd.dryRun) {
199
+ logging_1.logger.info(`Dry run complete`);
200
+ process.exit(0);
201
+ }
202
+ }
203
+ const accessToken = getAccessTokenOrExit(cmd);
204
+ (0, delete_docs_1.delete_docs)({
205
+ accessToken,
206
+ useOAuth: cmd.useOAuth,
207
+ docs: nodesToDeleteRelevantInfo,
208
+ apiUrl: cmd.apiUrl || projectInfo.config.apiUrl,
209
+ });
210
+ }
211
+ async function handleParse(cmd) {
212
+ setupHandler(cmd);
213
+ const dir = cmd.dir ?? process.cwd();
214
+ const projectInfo = (0, filter_project_info_1.filterProjectInfoByFile)(await (0, project_1.getProjectInfo)(dir, cmd.config, true), cmd.file);
215
+ const codeConnectObjects = await getCodeConnectObjects(cmd, projectInfo);
216
+ if (cmd.dryRun) {
217
+ logging_1.logger.info(`Dry run complete`);
218
+ process.exit(0);
219
+ }
220
+ if (cmd.outFile) {
221
+ fs_1.default.writeFileSync(cmd.outFile, JSON.stringify(codeConnectObjects, null, 2));
222
+ logging_1.logger.info(`Wrote Code Connect JSON to ${(0, logging_1.highlight)(cmd.outFile)}`);
223
+ }
224
+ else {
225
+ console.log(JSON.stringify(codeConnectObjects, undefined, 2));
226
+ }
227
+ }
228
+ async function handleCreate(nodeUrl, cmd) {
229
+ setupHandler(cmd);
230
+ const dir = getDir(cmd);
231
+ const projectInfo = await (0, project_1.getProjectInfo)(dir, cmd.config, true);
232
+ const accessToken = getAccessTokenOrExit(cmd);
233
+ return (0, create_template_1.createCodeConnectFromUrl)({
234
+ accessToken,
235
+ figmaNodeUrl: nodeUrl.replace(/\\/g, ''),
236
+ outFile: cmd.outFile,
237
+ outDir: cmd.outDir,
238
+ projectInfo,
239
+ cmd,
240
+ });
241
+ }
242
+ /**
243
+ * Registers Code Connect commands on a commander program, restricted to
244
+ * template-file workflows only. Intended for use by CLIs that support
245
+ * Code Connect during a migration period but do not need native parsers.
246
+ *
247
+ * Note: does NOT use addBaseCommand internally because that function registers
248
+ * both `-o --outFile` and `-o --outDir` with the same `-o` short flag.
249
+ * commander@12+ (used by litmus-cli) throws a conflict error on duplicate flags.
250
+ */
251
+ function addCodeConnectCommandsToProgram(program, programOptions = {}) {
252
+ function addBase(parent, name, description) {
253
+ return parent
254
+ .command(name)
255
+ .description(description)
256
+ .usage('[options]')
257
+ .option('-r --dir <dir>', 'directory to parse')
258
+ .option('-f --file <file>', 'path to a single Code Connect file to process')
259
+ .option('--outFile <file>', 'specify a file to output generated Code Connect')
260
+ .option('--outDir <dir>', 'specify a directory to output generated Code Connect')
261
+ .option('-c --config <path>', 'path to a figma config file')
262
+ .option('--exit-on-unreadable-files', 'exit if any Code Connect files cannot be parsed. We recommend using this option for CI/CD.')
263
+ .option('--dry-run', 'tests publishing without actually publishing')
264
+ .addHelpText('before', 'For feedback or bugs, please raise an issue: https://github.com/figma/code-connect/issues');
265
+ }
266
+ function wrapHandler(handler) {
267
+ return (options, cmd) => {
268
+ const globalOpts = cmd.optsWithGlobals();
269
+ // Attempt to get a token from the provided getter (e.g. OAuth store).
270
+ // If it returns undefined or throws (e.g. no OAuth token stored in CI),
271
+ // fall back to FIGMA_ACCESS_TOKEN and use PAT headers.
272
+ let oauthToken;
273
+ try {
274
+ oauthToken = programOptions.getToken?.();
275
+ }
276
+ catch {
277
+ // getToken threw (e.g. no OAuth token stored); fall back to PAT below
278
+ }
279
+ const token = oauthToken ?? process.env.FIGMA_ACCESS_TOKEN;
280
+ const useOAuth = oauthToken !== undefined;
281
+ return handler({
282
+ ...options,
283
+ token,
284
+ useOAuth,
285
+ verbose: globalOpts.logLevel === 'debug',
286
+ apiUrl: globalOpts.apiBaseUrl,
287
+ }).catch((err) => {
288
+ // Commander v12 catches rejected action promises internally and exits 0.
289
+ // Commander v11 left them as unhandled rejections, and Node.js 15+ would
290
+ // exit 1 for those — so exit code 1 on handler errors was previously
291
+ // accidental. This catch makes it explicit and version-independent.
292
+ logging_1.logger.error(err.message);
293
+ process.exitCode = 1;
294
+ });
295
+ };
296
+ }
297
+ const connectCommand = program
298
+ .command('connect')
299
+ .description('Code Connect commands')
300
+ .addHelpText('before', 'For feedback or bugs, please raise an issue: https://github.com/figma/code-connect/issues');
301
+ connectCommand.action(() => connectCommand.help());
302
+ addBase(connectCommand, 'publish', 'Run Code Connect locally to find any files that have figma connections and publish them to Figma. ' +
303
+ 'By default this looks for a config file named "figma.config.json", and uses the `include` and `exclude` fields to determine which files to parse. ' +
304
+ 'If no config file is found, this parses the current directory. An optional `--dir` flag can be used to specify a directory to parse.')
305
+ .option('--skip-validation', 'skip validation of Code Connect docs')
306
+ .option('-l --label <label>', 'label to apply to the published files')
307
+ .option('-b --batch-size <batch_size>', 'optional batch size (in number of documents) to use when uploading. Use this if you hit "request too large" errors. See README for more information.')
308
+ .option('--force', 'overwrite existing UI-created Code Connect mappings if they conflict with the files being published')
309
+ .action(wrapHandler(handlePublish));
310
+ addBase(connectCommand, 'unpublish', 'Run to find any files that have figma connections and unpublish them from Figma. ' +
311
+ 'By default this looks for a config file named "figma.config.json", and uses the `include` and `exclude` fields to determine which files to parse. ' +
312
+ 'If no config file is found, this parses the current directory. An optional `--dir` flag can be used to specify a directory to parse. ' +
313
+ 'Alternatively, use `--node` and `--label` to unpublish a specific component.')
314
+ .option('--node <link_to_node>', 'specify the node to unpublish. This will unpublish for the specified label.')
315
+ .option('-l --label <label>', 'label to unpublish for')
316
+ .action(wrapHandler(handleUnpublish));
317
+ addBase(connectCommand, 'parse', 'Run Code Connect locally to find any files that have figma connections, then converts them to JSON and outputs to stdout.')
318
+ .option('-l --label <label>', 'label to apply to the parsed files')
319
+ .action(wrapHandler(handleParse));
320
+ addBase(connectCommand, 'create', 'Generate a Code Connect file with boilerplate in the current directory for a Figma node URL')
321
+ .argument('<figma-node-url>', 'Figma node URL to create the Code Connect file from')
322
+ .action((nodeUrl, options, cmd) => wrapHandler((mergedCmd) => handleCreate(nodeUrl, mergedCmd))(options, cmd));
323
+ }
324
+ //# sourceMappingURL=connect_template.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"connect_template.js","sourceRoot":"","sources":["../../src/commands/connect_template.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Slim Code Connect entry point template-files-only support.\n */\nimport * as commander from 'commander'\nimport fs from 'fs'\nimport { upload } from '../connect/upload'\nimport { validateDocs } from '../connect/validation'\nimport { ProjectInfo, getProjectInfo } from '../connect/project'\nimport { LogLevel, exitWithError, highlight, logger, success } from '../common/logging'\nimport { CodeConnectJSON } from '../connect/figma_connect'\nimport { delete_docs } from '../connect/delete_docs'\nimport { exitWithFeedbackMessage } from '../connect/helpers'\nimport { isRawTemplate, parseRawFile } from '../connect/raw_templates'\nimport { parseBatchFile } from '../connect/batch_templates'\nimport { filterProjectInfoByFile } from './filter_project_info'\nimport { createCodeConnectFromUrl } from '../connect/create_template'\n\nexport type BaseCommand = commander.Command & {\n token: string\n useOAuth: boolean\n verbose: boolean\n outFile: string\n outDir: string\n config: string\n dryRun: boolean\n dir: string\n file: string\n jsonFile: string\n skipUpdateCheck: boolean\n exitOnUnreadableFiles: boolean\n apiUrl?: string\n includeProps?: boolean\n}\n\nfunction getAccessTokenOrExit(cmd: BaseCommand): string {\n const token = cmd.token\n if (!token) {\n exitWithError(\n cmd.useOAuth\n ? `Couldn't find a Figma OAuth token. Please re-authenticate.`\n : `Couldn't find a Figma access token. Please set the FIGMA_ACCESS_TOKEN environment variable`,\n )\n }\n return token\n}\n\nfunction setupHandler(cmd: BaseCommand) {\n if (cmd.verbose) {\n logger.setLogLevel(LogLevel.Debug)\n }\n}\n\nfunction getDir(cmd: BaseCommand) {\n return cmd.dir ?? process.cwd()\n}\n\n/**\n * Returns Code Connect objects from template files (.figma.ts / .figma.js)\n * only. Native parser paths (react, html, executable) are intentionally\n * omitted — this entry point is for parserless/template-file workflows.\n */\nasync function getCodeConnectObjects(\n cmd: BaseCommand & { label?: string },\n projectInfo: ProjectInfo,\n silent = false,\n): Promise<CodeConnectJSON[]> {\n const rawTemplateFiles = projectInfo.files.filter((f: string) => {\n const isPotentialRawTemplate =\n f.endsWith('.figma.js') ||\n f.endsWith('.figma.template.js') ||\n f.endsWith('.figma.ts') ||\n f.endsWith('.figma.template.ts')\n if (!isPotentialRawTemplate) return false\n try {\n return isRawTemplate(fs.readFileSync(f, 'utf-8'))\n } catch {\n return false\n }\n })\n\n let codeConnectObjects: CodeConnectJSON[] = []\n\n if (rawTemplateFiles.length > 0) {\n const resolvedLabel = cmd.label || projectInfo.config.label\n const rawTemplateDocs: CodeConnectJSON[] = []\n for (const file of rawTemplateFiles) {\n try {\n const doc = parseRawFile(file, resolvedLabel, projectInfo.config, projectInfo.absPath)\n doc._codeConnectFilePath = file\n if (!silent || cmd.verbose) {\n logger.info(success(file))\n }\n rawTemplateDocs.push(doc)\n } catch (e) {\n if (!silent || cmd.verbose) {\n logger.error(`❌ ${file}`)\n if (cmd.verbose) {\n console.trace(e)\n } else {\n logger.error(e instanceof Error ? e.message : String(e))\n }\n }\n if (cmd.exitOnUnreadableFiles) {\n logger.info('Exiting due to unreadable files')\n process.exit(1)\n }\n }\n }\n codeConnectObjects = codeConnectObjects.concat(rawTemplateDocs)\n }\n\n // Process batch files (.figma.batch.json)\n const batchFiles = projectInfo.files.filter((f: string) => f.endsWith('.figma.batch.json'))\n\n if (batchFiles.length > 0) {\n const resolvedLabel = cmd.label || projectInfo.config.label\n\n for (const file of batchFiles) {\n try {\n const docs = parseBatchFile(file, resolvedLabel, projectInfo.config, projectInfo.absPath)\n docs.forEach((doc) => {\n doc._codeConnectFilePath = file\n })\n codeConnectObjects = codeConnectObjects.concat(docs)\n if (!silent || cmd.verbose) {\n logger.info(success(`${file} (${docs.length} components)`))\n }\n } catch (e) {\n logger.error(`${file}: ${e}`)\n if (cmd.exitOnUnreadableFiles) {\n process.exit(1)\n }\n }\n }\n }\n\n if (cmd.label || projectInfo.config.label) {\n logger.info(`Using label \"${cmd.label || projectInfo.config.label}\"`)\n codeConnectObjects.forEach((doc) => {\n doc.label = cmd.label || projectInfo.config.label || doc.label\n })\n }\n\n if (projectInfo.config.language) {\n logger.info(`Using language \"${projectInfo.config.language}\"`)\n codeConnectObjects.forEach((doc) => {\n doc.language = projectInfo.config.language || doc.language\n })\n }\n\n return codeConnectObjects\n}\n\nasync function handlePublish(\n cmd: BaseCommand & {\n skipValidation: boolean\n label: string\n batchSize: string\n force?: boolean\n },\n) {\n setupHandler(cmd)\n\n let dir = getDir(cmd)\n const projectInfo = filterProjectInfoByFile(await getProjectInfo(dir, cmd.config, true), cmd.file)\n const codeConnectObjects = await getCodeConnectObjects(cmd, projectInfo)\n\n if (codeConnectObjects.length === 0) {\n logger.warn(\n `No Code Connect files found in ${dir} - Make sure you have configured \\`include\\` and \\`exclude\\` in your figma.config.json file correctly, or that you are running in a directory that contains Code Connect files.`,\n )\n process.exit(0)\n }\n\n if (cmd.dryRun) {\n logger.info(`Files that would be published:`)\n logger.info(codeConnectObjects.map((o) => `- ${o.component} (${o.figmaNode})`).join('\\n'))\n }\n\n const accessToken = getAccessTokenOrExit(cmd)\n\n if (cmd.skipValidation) {\n logger.info('Validation skipped')\n } else {\n logger.info('Validating Code Connect files...')\n const start = new Date().getTime()\n const valid = await validateDocs(\n cmd,\n accessToken,\n codeConnectObjects,\n cmd.apiUrl || projectInfo.config.apiUrl,\n cmd.useOAuth,\n )\n if (!valid) {\n exitWithFeedbackMessage(1)\n } else {\n const end = new Date().getTime()\n const time = end - start\n logger.info(`All Code Connect files are valid (${time}ms)`)\n }\n }\n\n if (cmd.dryRun) {\n logger.info(`Dry run complete`)\n process.exit(0)\n }\n\n let batchSize\n if (cmd.batchSize) {\n batchSize = parseInt(cmd.batchSize, 10)\n if (isNaN(batchSize)) {\n logger.error('Error: failed to parse batch-size. batch-size passed must be a number')\n exitWithFeedbackMessage(1)\n }\n }\n\n upload({\n accessToken,\n useOAuth: cmd.useOAuth,\n docs: codeConnectObjects,\n batchSize,\n verbose: cmd.verbose,\n apiUrl: cmd.apiUrl || projectInfo.config.apiUrl,\n force: cmd.force,\n })\n}\n\nasync function handleUnpublish(cmd: BaseCommand & { node: string; label: string }) {\n setupHandler(cmd)\n\n let dir = getDir(cmd)\n\n if (cmd.dryRun) {\n logger.info(`Files that would be unpublished:`)\n }\n\n let nodesToDeleteRelevantInfo\n\n const projectInfo = filterProjectInfoByFile(await getProjectInfo(dir, cmd.config, true), cmd.file)\n\n if (cmd.node) {\n if (!cmd.label) {\n exitWithError('Label is required when specifying a node')\n }\n nodesToDeleteRelevantInfo = [{ figmaNode: cmd.node, label: cmd.label }]\n } else {\n const codeConnectObjects = await getCodeConnectObjects(cmd, projectInfo)\n\n nodesToDeleteRelevantInfo = codeConnectObjects.map((doc) => ({\n figmaNode: doc.figmaNode,\n label: cmd.label || projectInfo.config.label || doc.label,\n }))\n\n if (cmd.label || projectInfo.config.label) {\n logger.info(`Using label ${cmd.label || projectInfo.config.label}`)\n }\n\n if (cmd.dryRun) {\n logger.info(`Dry run complete`)\n process.exit(0)\n }\n }\n\n const accessToken = getAccessTokenOrExit(cmd)\n\n delete_docs({\n accessToken,\n useOAuth: cmd.useOAuth,\n docs: nodesToDeleteRelevantInfo,\n apiUrl: cmd.apiUrl || projectInfo.config.apiUrl,\n })\n}\n\nasync function handleParse(cmd: BaseCommand & { label: string }) {\n setupHandler(cmd)\n\n const dir = cmd.dir ?? process.cwd()\n const projectInfo = filterProjectInfoByFile(await getProjectInfo(dir, cmd.config, true), cmd.file)\n const codeConnectObjects = await getCodeConnectObjects(cmd, projectInfo)\n\n if (cmd.dryRun) {\n logger.info(`Dry run complete`)\n process.exit(0)\n }\n\n if (cmd.outFile) {\n fs.writeFileSync(cmd.outFile, JSON.stringify(codeConnectObjects, null, 2))\n logger.info(`Wrote Code Connect JSON to ${highlight(cmd.outFile)}`)\n } else {\n console.log(JSON.stringify(codeConnectObjects, undefined, 2))\n }\n}\n\nasync function handleCreate(nodeUrl: string, cmd: BaseCommand) {\n setupHandler(cmd)\n\n const dir = getDir(cmd)\n const projectInfo = await getProjectInfo(dir, cmd.config, true)\n\n const accessToken = getAccessTokenOrExit(cmd)\n\n return createCodeConnectFromUrl({\n accessToken,\n figmaNodeUrl: nodeUrl.replace(/\\\\/g, ''),\n outFile: cmd.outFile,\n outDir: cmd.outDir,\n projectInfo,\n cmd,\n })\n}\n\ninterface ProgramOptions {\n /** Override how the auth token is retrieved. Return undefined to fall back to FIGMA_ACCESS_TOKEN. */\n getToken?: () => string | undefined\n}\n\n/**\n * Registers Code Connect commands on a commander program, restricted to\n * template-file workflows only. Intended for use by CLIs that support\n * Code Connect during a migration period but do not need native parsers.\n *\n * Note: does NOT use addBaseCommand internally because that function registers\n * both `-o --outFile` and `-o --outDir` with the same `-o` short flag.\n * commander@12+ (used by litmus-cli) throws a conflict error on duplicate flags.\n */\nexport function addCodeConnectCommandsToProgram(\n program: commander.Command,\n programOptions: ProgramOptions = {},\n) {\n function addBase(parent: commander.Command, name: string, description: string) {\n return parent\n .command(name)\n .description(description)\n .usage('[options]')\n .option('-r --dir <dir>', 'directory to parse')\n .option('-f --file <file>', 'path to a single Code Connect file to process')\n .option('--outFile <file>', 'specify a file to output generated Code Connect')\n .option('--outDir <dir>', 'specify a directory to output generated Code Connect')\n .option('-c --config <path>', 'path to a figma config file')\n .option(\n '--exit-on-unreadable-files',\n 'exit if any Code Connect files cannot be parsed. We recommend using this option for CI/CD.',\n )\n .option('--dry-run', 'tests publishing without actually publishing')\n .addHelpText(\n 'before',\n 'For feedback or bugs, please raise an issue: https://github.com/figma/code-connect/issues',\n )\n }\n\n function wrapHandler<T extends BaseCommand>(handler: (cmd: T) => Promise<void>) {\n return (options: unknown, cmd: commander.Command) => {\n const globalOpts = cmd.optsWithGlobals<{ logLevel?: string; apiBaseUrl?: string }>()\n\n // Attempt to get a token from the provided getter (e.g. OAuth store).\n // If it returns undefined or throws (e.g. no OAuth token stored in CI),\n // fall back to FIGMA_ACCESS_TOKEN and use PAT headers.\n let oauthToken: string | undefined\n try {\n oauthToken = programOptions.getToken?.()\n } catch {\n // getToken threw (e.g. no OAuth token stored); fall back to PAT below\n }\n const token = oauthToken ?? process.env.FIGMA_ACCESS_TOKEN\n const useOAuth = oauthToken !== undefined\n\n return handler({\n ...(options as object),\n token,\n useOAuth,\n verbose: globalOpts.logLevel === 'debug',\n apiUrl: globalOpts.apiBaseUrl,\n } as unknown as T).catch((err: Error) => {\n // Commander v12 catches rejected action promises internally and exits 0.\n // Commander v11 left them as unhandled rejections, and Node.js 15+ would\n // exit 1 for those — so exit code 1 on handler errors was previously\n // accidental. This catch makes it explicit and version-independent.\n logger.error(err.message)\n process.exitCode = 1\n })\n }\n }\n\n const connectCommand = program\n .command('connect')\n .description('Code Connect commands')\n .addHelpText(\n 'before',\n 'For feedback or bugs, please raise an issue: https://github.com/figma/code-connect/issues',\n )\n connectCommand.action(() => connectCommand.help())\n\n addBase(\n connectCommand,\n 'publish',\n 'Run Code Connect locally to find any files that have figma connections and publish them to Figma. ' +\n 'By default this looks for a config file named \"figma.config.json\", and uses the `include` and `exclude` fields to determine which files to parse. ' +\n 'If no config file is found, this parses the current directory. An optional `--dir` flag can be used to specify a directory to parse.',\n )\n .option('--skip-validation', 'skip validation of Code Connect docs')\n .option('-l --label <label>', 'label to apply to the published files')\n .option(\n '-b --batch-size <batch_size>',\n 'optional batch size (in number of documents) to use when uploading. Use this if you hit \"request too large\" errors. See README for more information.',\n )\n .option(\n '--force',\n 'overwrite existing UI-created Code Connect mappings if they conflict with the files being published',\n )\n .action(wrapHandler(handlePublish))\n\n addBase(\n connectCommand,\n 'unpublish',\n 'Run to find any files that have figma connections and unpublish them from Figma. ' +\n 'By default this looks for a config file named \"figma.config.json\", and uses the `include` and `exclude` fields to determine which files to parse. ' +\n 'If no config file is found, this parses the current directory. An optional `--dir` flag can be used to specify a directory to parse. ' +\n 'Alternatively, use `--node` and `--label` to unpublish a specific component.',\n )\n .option(\n '--node <link_to_node>',\n 'specify the node to unpublish. This will unpublish for the specified label.',\n )\n .option('-l --label <label>', 'label to unpublish for')\n .action(wrapHandler(handleUnpublish))\n\n addBase(\n connectCommand,\n 'parse',\n 'Run Code Connect locally to find any files that have figma connections, then converts them to JSON and outputs to stdout.',\n )\n .option('-l --label <label>', 'label to apply to the parsed files')\n .action(wrapHandler(handleParse))\n\n addBase(\n connectCommand,\n 'create',\n 'Generate a Code Connect file with boilerplate in the current directory for a Figma node URL',\n )\n .argument('<figma-node-url>', 'Figma node URL to create the Code Connect file from')\n .action((nodeUrl: string, options: unknown, cmd: commander.Command) =>\n wrapHandler<BaseCommand>((mergedCmd) => handleCreate(nodeUrl, mergedCmd))(options, cmd),\n )\n}\n"]}
@@ -0,0 +1,49 @@
1
+ import { BaseCommand } from './connect';
2
+ import { CodeConnectJSON } from '../connect/figma_connect';
3
+ export interface NodeToPreview {
4
+ fileKey: string;
5
+ nodeId: string;
6
+ url: string;
7
+ filePath: string;
8
+ }
9
+ export interface PreviewResult {
10
+ url: string;
11
+ nodeId: string;
12
+ filePath: string;
13
+ success: boolean;
14
+ snippet?: string;
15
+ language?: string;
16
+ component?: string;
17
+ error?: string;
18
+ }
19
+ /**
20
+ * Collect nodes to preview from file arguments.
21
+ * Matches by exact path first, then by basename.
22
+ */
23
+ export declare function collectNodesToPreview(files: string[], allCodeConnectObjects: CodeConnectJSON[], dir: string, cmd: BaseCommand): Promise<NodeToPreview[]>;
24
+ /**
25
+ * Filter templates to only those matching the requested node IDs.
26
+ */
27
+ export declare function filterTemplatesForNodes(nodeIds: string[], allTemplates: CodeConnectJSON[]): CodeConnectJSON[];
28
+ export declare function getPrettierParserMap(): Record<string, string>;
29
+ /**
30
+ * Check if a snippet can be parsed by Prettier.
31
+ * Returns true for languages without a Prettier parser (nothing to validate).
32
+ */
33
+ export declare function isPrettierParseable(snippet: string, language?: string): Promise<boolean>;
34
+ /**
35
+ * Format snippet with Prettier.
36
+ * Returns the snippet unmodified for languages Prettier doesn't support.
37
+ */
38
+ export declare function formatSnippet(snippet: string, language?: string): Promise<string>;
39
+ /**
40
+ * Display results with terminal colors
41
+ */
42
+ export declare function displayResults(results: PreviewResult[]): void;
43
+ /**
44
+ * Handle the preview command
45
+ */
46
+ export declare function handlePreview(files: string[], cmd: BaseCommand & {
47
+ output?: string;
48
+ }): Promise<void>;
49
+ //# sourceMappingURL=preview_utils.d.ts.map
@@ -0,0 +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;AAED;;GAEG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,GAAG,EAAE,WAAW,GAAG;IAAE,MAAM,CAAC,EAAE,MAAM,CAAA;CAAE,iBAkK1F"}