@figma/code-connect 1.3.12 → 1.4.0

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 (128) hide show
  1. package/dist/cli.js.map +1 -1
  2. package/dist/client/external.js.map +1 -1
  3. package/dist/client/figma_client.js +1 -1
  4. package/dist/client/figma_client.js.map +1 -1
  5. package/dist/commands/connect.d.ts +5 -4
  6. package/dist/commands/connect.d.ts.map +1 -1
  7. package/dist/commands/connect.js +242 -24
  8. package/dist/commands/connect.js.map +1 -1
  9. package/dist/common/error_formatting.d.ts +34 -0
  10. package/dist/common/error_formatting.d.ts.map +1 -0
  11. package/dist/common/error_formatting.js +115 -0
  12. package/dist/common/error_formatting.js.map +1 -0
  13. package/dist/common/fetch.js.map +1 -1
  14. package/dist/common/logging.js.map +1 -1
  15. package/dist/common/tsconfig.js.map +1 -1
  16. package/dist/common/updates.js.map +1 -1
  17. package/dist/connect/api.d.ts +13 -0
  18. package/dist/connect/api.d.ts.map +1 -1
  19. package/dist/connect/api.js.map +1 -1
  20. package/dist/connect/create.d.ts.map +1 -1
  21. package/dist/connect/create.js +2 -1
  22. package/dist/connect/create.js.map +1 -1
  23. package/dist/connect/create_common.js.map +1 -1
  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/external_types.d.ts +1 -0
  29. package/dist/connect/external_types.d.ts.map +1 -1
  30. package/dist/connect/external_types.js +4 -0
  31. package/dist/connect/external_types.js.map +1 -1
  32. package/dist/connect/figma_connect.d.ts +4 -1
  33. package/dist/connect/figma_connect.d.ts.map +1 -1
  34. package/dist/connect/figma_connect.js.map +1 -1
  35. package/dist/connect/figma_rest_api.d.ts +1 -1
  36. package/dist/connect/figma_rest_api.d.ts.map +1 -1
  37. package/dist/connect/figma_rest_api.js +5 -1
  38. package/dist/connect/figma_rest_api.js.map +1 -1
  39. package/dist/connect/helpers.js.map +1 -1
  40. package/dist/connect/index_common.js.map +1 -1
  41. package/dist/connect/intrinsics.d.ts +9 -2
  42. package/dist/connect/intrinsics.d.ts.map +1 -1
  43. package/dist/connect/intrinsics.js +19 -0
  44. package/dist/connect/intrinsics.js.map +1 -1
  45. package/dist/connect/label_language_mapping.d.ts +48 -0
  46. package/dist/connect/label_language_mapping.d.ts.map +1 -0
  47. package/dist/connect/label_language_mapping.js +76 -0
  48. package/dist/connect/label_language_mapping.js.map +1 -0
  49. package/dist/connect/migration_helpers.d.ts +41 -0
  50. package/dist/connect/migration_helpers.d.ts.map +1 -0
  51. package/dist/connect/migration_helpers.js +339 -0
  52. package/dist/connect/migration_helpers.js.map +1 -0
  53. package/dist/connect/modifiers.js.map +1 -1
  54. package/dist/connect/parser_common.d.ts +1 -0
  55. package/dist/connect/parser_common.d.ts.map +1 -1
  56. package/dist/connect/parser_common.js +1 -0
  57. package/dist/connect/parser_common.js.map +1 -1
  58. package/dist/connect/parser_executable_types.d.ts +11 -5
  59. package/dist/connect/parser_executable_types.d.ts.map +1 -1
  60. package/dist/connect/parser_executable_types.js +5 -1
  61. package/dist/connect/parser_executable_types.js.map +1 -1
  62. package/dist/connect/parser_executables.js.map +1 -1
  63. package/dist/connect/project.d.ts +11 -0
  64. package/dist/connect/project.d.ts.map +1 -1
  65. package/dist/connect/project.js +22 -4
  66. package/dist/connect/project.js.map +1 -1
  67. package/dist/connect/upload.d.ts +2 -1
  68. package/dist/connect/upload.d.ts.map +1 -1
  69. package/dist/connect/upload.js +12 -6
  70. package/dist/connect/upload.js.map +1 -1
  71. package/dist/connect/validation.d.ts +1 -1
  72. package/dist/connect/validation.d.ts.map +1 -1
  73. package/dist/connect/validation.js +2 -2
  74. package/dist/connect/validation.js.map +1 -1
  75. package/dist/connect/wizard/autolinking.js.map +1 -1
  76. package/dist/connect/wizard/embeddings.d.ts +2 -1
  77. package/dist/connect/wizard/embeddings.d.ts.map +1 -1
  78. package/dist/connect/wizard/embeddings.js +2 -2
  79. package/dist/connect/wizard/embeddings.js.map +1 -1
  80. package/dist/connect/wizard/helpers.js.map +1 -1
  81. package/dist/connect/wizard/prop_mapping.js.map +1 -1
  82. package/dist/connect/wizard/prop_mapping_helpers.d.ts +2 -1
  83. package/dist/connect/wizard/prop_mapping_helpers.d.ts.map +1 -1
  84. package/dist/connect/wizard/prop_mapping_helpers.js +5 -3
  85. package/dist/connect/wizard/prop_mapping_helpers.js.map +1 -1
  86. package/dist/connect/wizard/run_wizard.d.ts.map +1 -1
  87. package/dist/connect/wizard/run_wizard.js +6 -3
  88. package/dist/connect/wizard/run_wizard.js.map +1 -1
  89. package/dist/connect/wizard/signature_extraction.js.map +1 -1
  90. package/dist/html/create.js.map +1 -1
  91. package/dist/html/external.d.ts +1 -1
  92. package/dist/html/external.d.ts.map +1 -1
  93. package/dist/html/external.js +1 -0
  94. package/dist/html/external.js.map +1 -1
  95. package/dist/html/index_html.js.map +1 -1
  96. package/dist/html/parser.d.ts +2 -2
  97. package/dist/html/parser.d.ts.map +1 -1
  98. package/dist/html/parser.js +15 -6
  99. package/dist/html/parser.js.map +1 -1
  100. package/dist/html/parser_template_helpers.js.map +1 -1
  101. package/dist/html/template_literal.js.map +1 -1
  102. package/dist/html/types.js.map +1 -1
  103. package/dist/parser_scripts/compose_errors.js.map +1 -1
  104. package/dist/parser_scripts/get_file_if_exists.js.map +1 -1
  105. package/dist/parser_scripts/get_gradlew_path.js.map +1 -1
  106. package/dist/parser_scripts/get_swift_parser_dir.js.map +1 -1
  107. package/dist/react/create.d.ts.map +1 -1
  108. package/dist/react/create.js +3 -0
  109. package/dist/react/create.js.map +1 -1
  110. package/dist/react/external.d.ts +2 -2
  111. package/dist/react/external.d.ts.map +1 -1
  112. package/dist/react/external.js +2 -1
  113. package/dist/react/external.js.map +1 -1
  114. package/dist/react/index_react.js.map +1 -1
  115. package/dist/react/parser.d.ts +3 -3
  116. package/dist/react/parser.d.ts.map +1 -1
  117. package/dist/react/parser.js +13 -8
  118. package/dist/react/parser.js.map +1 -1
  119. package/dist/react/parser_template_helpers.d.ts.map +1 -1
  120. package/dist/react/parser_template_helpers.js +4 -1
  121. package/dist/react/parser_template_helpers.js.map +1 -1
  122. package/dist/react/types.js.map +1 -1
  123. package/dist/storybook/convert.d.ts.map +1 -1
  124. package/dist/storybook/convert.js +3 -2
  125. package/dist/storybook/convert.js.map +1 -1
  126. package/dist/storybook/external.js.map +1 -1
  127. package/dist/typescript/compiler.js.map +1 -1
  128. package/package.json +7 -5
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,qDAAsC;AACtC,gDAA+D;AAC/D,sDAAgF;AAEhF,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAA;AAE1B,KAAK,UAAU,GAAG;IAChB,IAAA,+CAAqC,GAAE,CAAA;IAEvC,MAAM,OAAO,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAA;IACrF,OAAO,CAAC,uBAAuB,EAAE,CAAA;IAEjC,IAAA,oCAA0B,EAAC,OAAO,CAAC,CAAA;IAEnC,8EAA8E;IAC9E,sCAAsC;IACtC;;;;;;;MAOE;IAEF,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,UAAU,EAAE,CAAA;QACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,GAAG,EAAE,CAAA"}
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAEA,qDAAsC;AACtC,gDAA+D;AAC/D,sDAAgF;AAEhF,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAA;AAE1B,KAAK,UAAU,GAAG;IAChB,IAAA,+CAAqC,GAAE,CAAA;IAEvC,MAAM,OAAO,GAAG,IAAI,SAAS,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAC,OAAO,CAAC,CAAA;IACrF,OAAO,CAAC,uBAAuB,EAAE,CAAA;IAEjC,IAAA,oCAA0B,EAAC,OAAO,CAAC,CAAA;IAEnC,8EAA8E;IAC9E,sCAAsC;IACtC;;;;;;;MAOE;IAEF,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;IAC3B,IAAI,OAAO,CAAC,IAAI,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,OAAO,CAAC,UAAU,EAAE,CAAA;QACpB,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC;AAED,GAAG,EAAE,CAAA","sourcesContent":["#!/usr/bin/env node\n\nimport * as commander from 'commander'\nimport { addConnectCommandToProgram } from './commands/connect'\nimport { maybePrefillWizardQuestionsForTesting } from './connect/wizard/helpers'\n\nrequire('dotenv').config()\n\nasync function run() {\n maybePrefillWizardQuestionsForTesting()\n\n const program = new commander.Command().version(require('./../package.json').version)\n program.enablePositionalOptions()\n\n addConnectCommandToProgram(program)\n\n // Update command is temporarily disabled until we can show the correct update\n // command to React vs non-React users\n /*\n program\n .command('update')\n .description('Updates to the latest version of the Figma CLI')\n .action(() => {\n updateCli()\n })\n */\n\n program.parse(process.argv)\n if (program.args.length < 1) {\n program.outputHelp()\n process.exit(1)\n }\n}\n\nrun()\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/client/external.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAArC,6GAAA,aAAa,OAAA"}
1
+ {"version":3,"file":"external.js","sourceRoot":"","sources":["../../src/client/external.ts"],"names":[],"mappings":";;;AAAA,+CAA8C;AAArC,6GAAA,aAAa,OAAA","sourcesContent":["export { getComponents } from './figma_client'\n"]}
@@ -34,7 +34,7 @@ async function getComponents(fileOrNode) {
34
34
  fileKey,
35
35
  figmaUrl: (0, helpers_1.figmaUrlOfComponent)(component, fileKey),
36
36
  componentPropertyDefinitions: component.type === 'COMPONENT_SET'
37
- ? Object.keys(component.componentPropertyDefinitions).reduce((result, key) => {
37
+ ? Object.keys(component.componentPropertyDefinitions || {}).reduce((result, key) => {
38
38
  return {
39
39
  ...result,
40
40
  // this removes the ID prefix from property names e.g #123:name -> name
@@ -1 +1 @@
1
- {"version":3,"file":"figma_client.js","sourceRoot":"","sources":["../../src/client/figma_client.ts"],"names":[],"mappings":";;AAwCA,sCAmCC;AA3ED,8DAAgF;AAChF,gDAM2B;AAsB3B,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAA;AAE1B;;;;;;;;GAQG;AACI,KAAK,UAAU,aAAa,CAAC,UAAkB;IACpD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IAClD,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,UAAU,CAAC,CAAA;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,oBAAoB,CAAC,CAAA;IAC5E,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,CAAC,UAAU,CAAC,CAAC,CAAA;IAC1C,IAAI,MAAM,GAAG,IAAA,0BAAS,EAAC,UAAU,IAAI,EAAE,CAAC,GAAG,UAAU,OAAO,EAAE,CAAA;IAC9D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;IACvC,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,IAAA,4BAAW,EAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;IAErE,sFAAsF;IACtF,gFAAgF;IAChF,OAAO,IAAA,kCAAwB,EAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACvD,GAAG,SAAS;QACZ,OAAO;QACP,QAAQ,EAAE,IAAA,6BAAmB,EAAC,SAAS,EAAE,OAAO,CAAC;QACjD,4BAA4B,EAC1B,SAAS,CAAC,IAAI,KAAK,eAAe;YAChC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,4BAA4B,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;gBACzE,OAAO;oBACL,GAAG,MAAM;oBACT,uEAAuE;oBACvE,CAAC,IAAA,2BAAiB,EAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,4BAA4B,CAAC,GAAG,CAAC;iBACtE,CAAA;YACH,CAAC,EAAE,EAAE,CAAC;YACR,CAAC,CAAC,SAAS;KAChB,CAAC,CAAC,CAAA;AACL,CAAC"}
1
+ {"version":3,"file":"figma_client.js","sourceRoot":"","sources":["../../src/client/figma_client.ts"],"names":[],"mappings":";;AAwCA,sCAmCC;AA3ED,8DAAgF;AAChF,gDAM2B;AAsB3B,OAAO,CAAC,QAAQ,CAAC,CAAC,MAAM,EAAE,CAAA;AAE1B;;;;;;;;GAQG;AACI,KAAK,UAAU,aAAa,CAAC,UAAkB;IACpD,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,CAAC;QACpC,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAA;IAClD,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,UAAU,CAAC,CAAA;IACxC,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CAAC,2BAA2B,UAAU,oBAAoB,CAAC,CAAA;IAC5E,CAAC;IAED,MAAM,OAAO,GAAG,IAAA,sBAAY,EAAC,CAAC,UAAU,CAAC,CAAC,CAAA;IAC1C,IAAI,MAAM,GAAG,IAAA,0BAAS,EAAC,UAAU,IAAI,EAAE,CAAC,GAAG,UAAU,OAAO,EAAE,CAAA;IAC9D,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,QAAQ,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAA;IACvC,CAAC;IAED,MAAM,GAAG,GAAG,MAAM,IAAA,4BAAW,EAAC,MAAM,EAAE,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,CAAA;IAErE,sFAAsF;IACtF,gFAAgF;IAChF,OAAO,IAAA,kCAAwB,EAAC,GAAG,CAAC,CAAC,GAAG,CAAC,CAAC,SAAS,EAAE,EAAE,CAAC,CAAC;QACvD,GAAG,SAAS;QACZ,OAAO;QACP,QAAQ,EAAE,IAAA,6BAAmB,EAAC,SAAS,EAAE,OAAO,CAAC;QACjD,4BAA4B,EAC1B,SAAS,CAAC,IAAI,KAAK,eAAe;YAChC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,4BAA4B,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,GAAG,EAAE,EAAE;gBAC/E,OAAO;oBACL,GAAG,MAAM;oBACT,uEAAuE;oBACvE,CAAC,IAAA,2BAAiB,EAAC,GAAG,CAAC,CAAC,EAAE,SAAS,CAAC,4BAA4B,CAAC,GAAG,CAAC;iBACtE,CAAA;YACH,CAAC,EAAE,EAAE,CAAC;YACR,CAAC,CAAC,SAAS;KAChB,CAAC,CAAC,CAAA;AACL,CAAC","sourcesContent":["import { FigmaRestApi, getApiUrl, getDocument } from '../connect/figma_rest_api'\nimport {\n figmaUrlOfComponent,\n findComponentsInDocument,\n normalizePropName,\n parseFileKey,\n parseNodeIds,\n} from '../connect/helpers'\n\nexport interface ComponentInfo {\n id: string\n name: string\n fileKey: string\n figmaUrl: string\n}\n\nexport interface FigmaConnectClient {\n /**\n * Fetches components from a figma file, filtering out components that don't\n * match the provided function.\n *\n * @param fileOrNode figma URL\n * @param match a function that returns true if the component should be\n * included\n * @returns a list of components\n */\n getComponents: (fileOrNode: string) => Promise<(FigmaRestApi.Component & ComponentInfo)[]>\n}\n\nrequire('dotenv').config()\n\n/**\n * Fetch components from a figma file. If the `node-id` query parameter is used,\n * only components within those frames will be included. This is useful if your\n * file is very large, as this will speed up the query.\n *\n * @param fileOrNode a figma file URL\n * @param match a function that returns true if the component should be included\n * @returns\n */\nexport async function getComponents(fileOrNode: string) {\n if (!process.env.FIGMA_ACCESS_TOKEN) {\n throw new Error('FIGMA_ACCESS_TOKEN is not set')\n }\n\n const fileKey = parseFileKey(fileOrNode)\n if (!fileKey) {\n throw new Error(`Invalid Figma file URL: ${fileOrNode}, file key missing`)\n }\n\n const nodeIds = parseNodeIds([fileOrNode])\n let apiUrl = getApiUrl(fileOrNode ?? '') + `/files/${fileKey}`\n if (nodeIds.length > 0) {\n apiUrl += `?ids=${nodeIds.join(',')}`\n }\n\n const doc = await getDocument(apiUrl, process.env.FIGMA_ACCESS_TOKEN)\n\n // `doc` in this case will only include the top frame(s) passed via `ids`. We omit the\n // nodeIds arg here because we want to return all components within the frame(s)\n return findComponentsInDocument(doc).map((component) => ({\n ...component,\n fileKey,\n figmaUrl: figmaUrlOfComponent(component, fileKey),\n componentPropertyDefinitions:\n component.type === 'COMPONENT_SET'\n ? Object.keys(component.componentPropertyDefinitions || {}).reduce((result, key) => {\n return {\n ...result,\n // this removes the ID prefix from property names e.g #123:name -> name\n [normalizePropName(key)]: component.componentPropertyDefinitions[key],\n }\n }, {})\n : undefined,\n }))\n}\n"]}
@@ -1,5 +1,5 @@
1
1
  import * as commander from 'commander';
2
- import { ProjectInfo } from '../connect/project';
2
+ import { CodeConnectConfig, ProjectInfo } from '../connect/project';
3
3
  import { CodeConnectJSON } from '../connect/figma_connect';
4
4
  export type BaseCommand = commander.Command & {
5
5
  token: string;
@@ -12,13 +12,14 @@ export type BaseCommand = commander.Command & {
12
12
  jsonFile: string;
13
13
  skipUpdateCheck: boolean;
14
14
  exitOnUnreadableFiles: boolean;
15
+ apiUrl?: string;
16
+ removeProps?: boolean;
15
17
  };
16
18
  export declare function addConnectCommandToProgram(program: commander.Command): void;
17
19
  export declare function getAccessToken(cmd: BaseCommand): string;
18
20
  export declare function getDir(cmd: BaseCommand): string;
19
- export declare function parseRawFile(filePath: string, label: string | undefined): CodeConnectJSON;
21
+ export declare function parseRawFile(filePath: string, label: string | undefined, config?: CodeConnectConfig, dir?: string): CodeConnectJSON;
20
22
  export declare function getCodeConnectObjects(cmd: BaseCommand & {
21
23
  label?: string;
22
- includeTemplateFiles?: boolean;
23
- }, projectInfo: ProjectInfo, silent?: boolean): Promise<CodeConnectJSON[]>;
24
+ }, projectInfo: ProjectInfo, silent?: boolean, skipTemplateHelpers?: boolean): Promise<CodeConnectJSON[]>;
24
25
  //# sourceMappingURL=connect.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,WAAW,CAAA;AAKtC,OAAO,EAIL,WAAW,EAKZ,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AAqB1D,MAAM,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,GAAG;IAC5C,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,OAAO,CAAA;IACxB,qBAAqB,EAAE,OAAO,CAAA;CAC/B,CAAA;AAyBD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,QAsDpE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,UAE9C;AAcD,wBAAgB,MAAM,CAAC,GAAG,EAAE,WAAW,UAEtC;AA0CD,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,SAAS,GAAG,eAAe,CAmBzF;AAED,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,oBAAoB,CAAC,EAAE,OAAO,CAAA;CAAE,EACrE,WAAW,EAAE,WAAW,EACxB,MAAM,UAAQ,GACb,OAAO,CAAC,eAAe,EAAE,CAAC,CAwF5B"}
1
+ {"version":3,"file":"connect.d.ts","sourceRoot":"","sources":["../../src/commands/connect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,WAAW,CAAA;AAKtC,OAAO,EACL,iBAAiB,EAIjB,WAAW,EAKZ,MAAM,oBAAoB,CAAA;AAE3B,OAAO,EAAE,eAAe,EAAE,MAAM,0BAA0B,CAAA;AA0B1D,MAAM,MAAM,WAAW,GAAG,SAAS,CAAC,OAAO,GAAG;IAC5C,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,OAAO,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,MAAM,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;IACf,GAAG,EAAE,MAAM,CAAA;IACX,QAAQ,EAAE,MAAM,CAAA;IAChB,eAAe,EAAE,OAAO,CAAA;IACxB,qBAAqB,EAAE,OAAO,CAAA;IAC9B,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,WAAW,CAAC,EAAE,OAAO,CAAA;CACtB,CAAA;AA0BD,wBAAgB,0BAA0B,CAAC,OAAO,EAAE,SAAS,CAAC,OAAO,QAiEpE;AAED,wBAAgB,cAAc,CAAC,GAAG,EAAE,WAAW,UAE9C;AAcD,wBAAgB,MAAM,CAAC,GAAG,EAAE,WAAW,UAEtC;AA0CD,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,KAAK,EAAE,MAAM,GAAG,SAAS,EACzB,MAAM,CAAC,EAAE,iBAAiB,EAC1B,GAAG,CAAC,EAAE,MAAM,GACX,eAAe,CAoEjB;AAED,wBAAsB,qBAAqB,CACzC,GAAG,EAAE,WAAW,GAAG;IAAE,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,EACrC,WAAW,EAAE,WAAW,EACxB,MAAM,UAAQ,EACd,mBAAmB,UAAQ,GAC1B,OAAO,CAAC,eAAe,EAAE,CAAC,CAkH5B"}
@@ -20,11 +20,16 @@ const run_wizard_1 = require("../connect/wizard/run_wizard");
20
20
  const parser_executables_1 = require("../connect/parser_executables");
21
21
  const zod_validation_error_1 = require("zod-validation-error");
22
22
  const parser_executable_types_1 = require("../connect/parser_executable_types");
23
+ const path_1 = __importDefault(require("path"));
23
24
  const updates_1 = require("../common/updates");
24
25
  const helpers_1 = require("../connect/helpers");
25
26
  const parser_1 = require("../html/parser");
26
27
  const parser_common_1 = require("../connect/parser_common");
27
28
  const parser_2 = require("../react/parser");
29
+ const label_language_mapping_1 = require("../connect/label_language_mapping");
30
+ const migration_helpers_1 = require("../connect/migration_helpers");
31
+ const run_wizard_2 = require("../connect/wizard/run_wizard");
32
+ const project_2 = require("../connect/project");
28
33
  function addBaseCommand(command, name, description) {
29
34
  return command
30
35
  .command(name)
@@ -36,6 +41,7 @@ function addBaseCommand(command, name, description) {
36
41
  .option('-o --outFile <file>', 'specify a file to output generated Code Connect')
37
42
  .option('-o --outDir <dir>', 'specify a directory to output generated Code Connect')
38
43
  .option('-c --config <path>', 'path to a figma config file')
44
+ .option('-a --api-url <url>', 'custom Figma API URL to use instead of https://api.figma.com/v1')
39
45
  .option('--skip-update-check', 'skips checking for an updated version of the Figma CLI')
40
46
  .option('--exit-on-unreadable-files', 'exit if any Code Connect files cannot be parsed. We recommend using this option for CI/CD.')
41
47
  .option('--dry-run', 'tests publishing without actually publishing')
@@ -50,7 +56,6 @@ function addConnectCommandToProgram(program) {
50
56
  'If no config file is found, this parses the current directory. An optional `--dir` flag can be used to specify a directory to parse.')
51
57
  .option('--skip-validation', 'skip validation of Code Connect docs')
52
58
  .option('-l --label <label>', 'label to apply to the published files')
53
- .option('--include-template-files', 'flag to include any figma.template.js files')
54
59
  .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.')
55
60
  .action((0, updates_1.withUpdateCheck)(handlePublish));
56
61
  addBaseCommand(connectCommand, 'unpublish', 'Run to find any files that have figma connections and unpublish them from Figma. ' +
@@ -58,15 +63,19 @@ function addConnectCommandToProgram(program) {
58
63
  'If no config file is found, this parses the current directory. An optional `--dir` flag can be used to specify a directory to parse.')
59
64
  .option('--node <link_to_node>', 'specify the node to unpublish. This will unpublish for the specified label.')
60
65
  .option('-l --label <label>', 'label to unpublish for')
61
- .option('--include-template-files', 'flag to include any figma.template.js files')
62
66
  .action((0, updates_1.withUpdateCheck)(handleUnpublish));
63
67
  addBaseCommand(connectCommand, 'parse', 'Run Code Connect locally to find any files that have figma connections, then converts them to JSON and outputs to stdout.')
64
68
  .option('-l --label <label>', 'label to apply to the parsed files')
65
- .option('--include-template-files', 'flag to include any figma.template.js files')
66
69
  .action((0, updates_1.withUpdateCheck)(handleParse));
67
70
  addBaseCommand(connectCommand, 'create', 'Generate a Code Connect file with boilerplate in the current directory for a Figma node URL')
68
71
  .argument('<figma-node-url>', 'Figma node URL to create the Code Connect file from')
69
72
  .action((0, updates_1.withUpdateCheck)(handleCreate));
73
+ addBaseCommand(connectCommand, 'migrate', 'Parse Code Connect files and migrate their templates into .figma.js files that can be published directly without parsing.')
74
+ .argument('[pattern]', 'glob pattern to match files (optional, uses config if not provided)')
75
+ .option('-l --label <label>', 'label to apply to the migrated templates')
76
+ .option('--output-dir <dir>', 'directory to write template files (default: same directory as source file)')
77
+ .option('--remove-props', 'remove __props metadata blocks from migrated templates')
78
+ .action((0, updates_1.withUpdateCheck)(handleMigrate));
70
79
  }
71
80
  function getAccessToken(cmd) {
72
81
  return cmd.token ?? process.env.FIGMA_ACCESS_TOKEN;
@@ -112,29 +121,75 @@ function transformDocFromParser(doc, remoteUrl, config) {
112
121
  figmaNode,
113
122
  };
114
123
  }
115
- function parseRawFile(filePath, label) {
124
+ function parseRawFile(filePath, label, config, dir) {
116
125
  const fileContent = fs_1.default.readFileSync(filePath, 'utf-8');
117
- const [firstLine, ...templateLines] = fileContent.split('\n');
118
- const figmaNodeUrl = firstLine.replace(/\/\/\s*url=/, '').trim();
119
- const template = templateLines.join('\n');
126
+ const lines = fileContent.split('\n');
127
+ const fields = {};
128
+ let templateStartIndex = 0;
129
+ // Parse consecutive comment lines at the start of the file
130
+ for (let i = 0; i < lines.length; i++) {
131
+ const line = lines[i].trim();
132
+ // Match pattern: // fieldName=value
133
+ const match = line.match(/^\/\/\s*(\w+)=(.+)$/);
134
+ if (match) {
135
+ const [, fieldName, fieldValue] = match;
136
+ const normalizedFieldName = fieldName.toLowerCase();
137
+ if (normalizedFieldName === 'url' ||
138
+ normalizedFieldName === 'component' ||
139
+ normalizedFieldName === 'source') {
140
+ fields[normalizedFieldName] = fieldValue.trim();
141
+ }
142
+ templateStartIndex = i + 1;
143
+ }
144
+ else if (line === '' || line.startsWith('//')) {
145
+ // Allow blank lines or other comments, but don't increment template start
146
+ continue;
147
+ }
148
+ else {
149
+ // First non-comment line found
150
+ break;
151
+ }
152
+ }
153
+ if (!fields.url) {
154
+ throw new Error(`Missing required url field in ${filePath}. Please add a // url=... comment to the top of the file.`);
155
+ }
156
+ let figmaNodeUrl = fields.url;
157
+ const template = lines.slice(templateStartIndex).join('\n');
158
+ // Apply documentUrlSubstitutions if provided
159
+ if (config?.documentUrlSubstitutions) {
160
+ Object.entries(config.documentUrlSubstitutions).forEach(([from, to]) => {
161
+ figmaNodeUrl = figmaNodeUrl.replace(from, to);
162
+ });
163
+ }
164
+ // Determine effective label from parameter, config, or default
165
+ const effectiveLabel = label || config?.label || label_language_mapping_1.CodeConnectLabel.Code;
166
+ const language = config?.language || (0, label_language_mapping_1.getInferredLanguageForRaw)(effectiveLabel);
120
167
  return {
121
168
  figmaNode: figmaNodeUrl,
169
+ component: fields.component,
122
170
  template,
123
- // nestable by default unless user specifies otherwise
124
- templateData: { nestable: true },
125
- language: 'raw',
126
- label: label || 'Code',
127
- source: '',
171
+ // nestable by default unless user specifies in template
172
+ // (templateData.nestable AND template.metadata.nestable need to
173
+ // be true for instance to be nested)
174
+ templateData: { nestable: true, isParserless: true },
175
+ language,
176
+ label: effectiveLabel,
177
+ source: fields.source,
128
178
  sourceLocation: { line: -1 },
129
179
  metadata: {
130
180
  cliVersion: require('../../package.json').version,
131
181
  },
132
182
  };
133
183
  }
134
- async function getCodeConnectObjects(cmd, projectInfo, silent = false) {
184
+ async function getCodeConnectObjects(cmd, projectInfo, silent = false, skipTemplateHelpers = false) {
135
185
  if (cmd.jsonFile) {
136
186
  try {
137
- return JSON.parse(fs_1.default.readFileSync(cmd.jsonFile, 'utf8'));
187
+ const docsFromJson = JSON.parse(fs_1.default.readFileSync(cmd.jsonFile, 'utf8'));
188
+ // Strip internal fields from JSON input
189
+ return docsFromJson.map((doc) => {
190
+ const { _codeConnectFilePath, ...cleanDoc } = doc;
191
+ return cleanDoc;
192
+ });
138
193
  }
139
194
  catch (e) {
140
195
  logging_1.logger.error('Failed to parse JSON file:', e);
@@ -142,7 +197,7 @@ async function getCodeConnectObjects(cmd, projectInfo, silent = false) {
142
197
  }
143
198
  let codeConnectObjects = [];
144
199
  if (projectInfo.config.parser === 'react') {
145
- codeConnectObjects = await getReactCodeConnectObjects(projectInfo, cmd, silent);
200
+ codeConnectObjects = await getReactCodeConnectObjects(projectInfo, cmd, silent, skipTemplateHelpers);
146
201
  }
147
202
  else if (projectInfo.config.parser === 'html') {
148
203
  codeConnectObjects = await getCodeConnectObjectsFromParseFn({
@@ -151,13 +206,14 @@ async function getCodeConnectObjects(cmd, projectInfo, silent = false) {
151
206
  projectInfo,
152
207
  cmd,
153
208
  silent,
209
+ skipTemplateHelpers,
154
210
  });
155
211
  }
156
212
  else {
157
213
  const payload = {
158
214
  mode: 'PARSE',
159
215
  paths: projectInfo.files,
160
- config: projectInfo.config,
216
+ config: { ...projectInfo.config, skipTemplateHelpers },
161
217
  verbose: cmd.verbose,
162
218
  };
163
219
  try {
@@ -188,9 +244,19 @@ async function getCodeConnectObjects(cmd, projectInfo, silent = false) {
188
244
  }
189
245
  }
190
246
  }
191
- if (cmd.includeTemplateFiles) {
192
- const rawTemplateFiles = projectInfo.files.filter((f) => f.endsWith('.figma.template.js'));
193
- const rawTemplateDocs = rawTemplateFiles.map((file) => parseRawFile(file, cmd.label));
247
+ const rawTemplateFiles = projectInfo.files.filter((f) => f.endsWith('.figma.js') || f.endsWith('.figma.template.js'));
248
+ if (rawTemplateFiles.length > 0) {
249
+ // Resolve the label before parsing so language inference works correctly
250
+ const resolvedLabel = cmd.label || projectInfo.config.label;
251
+ const rawTemplateDocs = rawTemplateFiles.map((file) => {
252
+ const doc = parseRawFile(file, resolvedLabel, projectInfo.config, projectInfo.absPath);
253
+ // Store the Code Connect file path for migration purposes
254
+ doc._codeConnectFilePath = file;
255
+ if (!silent || cmd.verbose) {
256
+ logging_1.logger.info((0, logging_1.success)(file));
257
+ }
258
+ return doc;
259
+ });
194
260
  codeConnectObjects = codeConnectObjects.concat(rawTemplateDocs);
195
261
  }
196
262
  if (cmd.label || projectInfo.config.label) {
@@ -199,6 +265,12 @@ async function getCodeConnectObjects(cmd, projectInfo, silent = false) {
199
265
  doc.label = cmd.label || projectInfo.config.label || doc.label;
200
266
  });
201
267
  }
268
+ if (projectInfo.config.language) {
269
+ logging_1.logger.info(`Using language "${projectInfo.config.language}"`);
270
+ codeConnectObjects.forEach((doc) => {
271
+ doc.language = projectInfo.config.language || doc.language;
272
+ });
273
+ }
202
274
  return codeConnectObjects;
203
275
  }
204
276
  // React/Storybook and HTML parsers are handled as special cases for now, they
@@ -216,7 +288,9 @@ projectInfo,
216
288
  /** The commander command object */
217
289
  cmd,
218
290
  /** Silences console output */
219
- silent = false, }) {
291
+ silent = false,
292
+ /** Skip template helpers (used for extract command) */
293
+ skipTemplateHelpers = false, }) {
220
294
  const codeConnectObjects = [];
221
295
  const tsProgram = (0, project_1.getTsProgram)(projectInfo);
222
296
  const { files, remoteUrl, config, absPath } = projectInfo;
@@ -233,6 +307,7 @@ silent = false, }) {
233
307
  repoUrl: remoteUrl,
234
308
  debug: cmd.verbose,
235
309
  silent,
310
+ skipTemplateHelpers,
236
311
  },
237
312
  });
238
313
  codeConnectObjects.push(...docs);
@@ -268,7 +343,7 @@ silent = false, }) {
268
343
  }
269
344
  return codeConnectObjects;
270
345
  }
271
- async function getReactCodeConnectObjects(projectInfo, cmd, silent = false) {
346
+ async function getReactCodeConnectObjects(projectInfo, cmd, silent = false, skipTemplateHelpers = false) {
272
347
  const codeConnectObjects = await getCodeConnectObjectsFromParseFn({
273
348
  parseFn: parser_2.parseReactDoc,
274
349
  resolveImportsFn: parser_2.findAndResolveImports,
@@ -276,6 +351,7 @@ async function getReactCodeConnectObjects(projectInfo, cmd, silent = false) {
276
351
  projectInfo,
277
352
  cmd,
278
353
  silent,
354
+ skipTemplateHelpers,
279
355
  });
280
356
  const storybookCodeConnectObjects = await (0, convert_1.convertStorybookFiles)({
281
357
  projectInfo: (0, project_1.getReactProjectInfo)(projectInfo),
@@ -303,7 +379,7 @@ async function handlePublish(cmd) {
303
379
  else {
304
380
  logging_1.logger.info('Validating Code Connect files...');
305
381
  var start = new Date().getTime();
306
- const valid = await (0, validation_1.validateDocs)(cmd, accessToken, codeConnectObjects);
382
+ const valid = await (0, validation_1.validateDocs)(cmd, accessToken, codeConnectObjects, cmd.apiUrl || projectInfo.config.apiUrl);
307
383
  if (!valid) {
308
384
  (0, helpers_1.exitWithFeedbackMessage)(1);
309
385
  }
@@ -325,7 +401,13 @@ async function handlePublish(cmd) {
325
401
  (0, helpers_1.exitWithFeedbackMessage)(1);
326
402
  }
327
403
  }
328
- (0, upload_1.upload)({ accessToken, docs: codeConnectObjects, batchSize: batchSize, verbose: cmd.verbose });
404
+ (0, upload_1.upload)({
405
+ accessToken,
406
+ docs: codeConnectObjects,
407
+ batchSize: batchSize,
408
+ verbose: cmd.verbose,
409
+ apiUrl: cmd.apiUrl || projectInfo.config.apiUrl,
410
+ });
329
411
  }
330
412
  async function handleUnpublish(cmd) {
331
413
  setupHandler(cmd);
@@ -334,6 +416,7 @@ async function handleUnpublish(cmd) {
334
416
  logging_1.logger.info(`Files that would be unpublished:`);
335
417
  }
336
418
  let nodesToDeleteRelevantInfo;
419
+ const projectInfo = await (0, project_1.getProjectInfo)(dir, cmd.config);
337
420
  if (cmd.node) {
338
421
  if (!cmd.label) {
339
422
  (0, logging_1.exitWithError)('Label is required when specifying a node');
@@ -341,7 +424,6 @@ async function handleUnpublish(cmd) {
341
424
  nodesToDeleteRelevantInfo = [{ figmaNode: cmd.node, label: cmd.label }];
342
425
  }
343
426
  else {
344
- const projectInfo = await (0, project_1.getProjectInfo)(dir, cmd.config);
345
427
  const codeConnectObjects = await getCodeConnectObjects(cmd, projectInfo);
346
428
  nodesToDeleteRelevantInfo = codeConnectObjects.map((doc) => ({
347
429
  figmaNode: doc.figmaNode,
@@ -359,6 +441,7 @@ async function handleUnpublish(cmd) {
359
441
  (0, delete_docs_1.delete_docs)({
360
442
  accessToken,
361
443
  docs: nodesToDeleteRelevantInfo,
444
+ apiUrl: cmd.apiUrl || projectInfo.config.apiUrl,
362
445
  });
363
446
  }
364
447
  async function handleParse(cmd) {
@@ -399,4 +482,139 @@ async function handleCreate(nodeUrl, cmd) {
399
482
  cmd,
400
483
  });
401
484
  }
485
+ /**
486
+ * Migrate native parser Code Connect files to parserless. For each found doc:
487
+ * - Replace helpers with figma.* versions
488
+ * - Migrate v1 syntax to v2 (equivalent but more readable)
489
+ * - Format as valid parserless file w/ url="" comment
490
+ * - Name collisions are skipped, unless file is from migration (in which case add "_1")
491
+ */
492
+ async function handleMigrate(pattern, cmd) {
493
+ setupHandler(cmd);
494
+ const dir = cmd.dir ?? process.cwd();
495
+ let projectInfo = await (0, project_1.getProjectInfo)(dir, cmd.config);
496
+ const documentUrlSubstitutions = projectInfo.config.documentUrlSubstitutions;
497
+ // Clear documentUrlSubstitutions so we preserve original URLs in migrated templates
498
+ projectInfo = {
499
+ ...projectInfo,
500
+ config: {
501
+ ...projectInfo.config,
502
+ documentUrlSubstitutions: {},
503
+ },
504
+ };
505
+ // If a glob pattern is provided, override the project files
506
+ if (pattern) {
507
+ const { globSync } = require('glob');
508
+ const files = globSync(pattern, {
509
+ cwd: dir,
510
+ absolute: true,
511
+ nodir: true,
512
+ });
513
+ if (files.length === 0) {
514
+ (0, logging_1.exitWithError)(`No files found matching pattern: ${pattern}`);
515
+ }
516
+ logging_1.logger.info(`Found ${files.length} file(s) matching pattern: ${pattern}`);
517
+ projectInfo = {
518
+ ...projectInfo,
519
+ files,
520
+ };
521
+ }
522
+ // Parse the files to get Code Connect objects
523
+ const allCodeConnectObjects = await getCodeConnectObjects(cmd, projectInfo, false, true);
524
+ const codeConnectObjectsByFigmaUrl = (0, migration_helpers_1.groupCodeConnectObjectsByFigmaUrl)(allCodeConnectObjects);
525
+ const totalVariants = Object.values(codeConnectObjectsByFigmaUrl).reduce((acc, obj) => acc + obj.variants.length, 0);
526
+ // TODO support variants (for now filtering on non-variants)
527
+ const codeConnectObjects = Object.values(codeConnectObjectsByFigmaUrl).flatMap((obj) => obj.main ? [obj.main] : []);
528
+ if (codeConnectObjects.length === 0) {
529
+ (0, logging_1.exitWithError)('No Code Connect objects found to migrate');
530
+ }
531
+ logging_1.logger.info(`Found ${codeConnectObjects.length} Code Connect object(s) to migrate`);
532
+ let migratedCount = 0;
533
+ let skippedCount = 0;
534
+ const errors = [];
535
+ // Track file paths created during this migration run
536
+ const filePathsCreated = new Set();
537
+ // Get git root path for converting remote URLs to local paths
538
+ const gitRootPath = (0, project_2.getGitRepoAbsolutePath)(dir);
539
+ // Migrate each Code Connect object to a template file
540
+ for (const doc of codeConnectObjects) {
541
+ try {
542
+ // Skip if no template (shouldn't happen, but be safe)
543
+ if (!doc.template) {
544
+ logging_1.logger.warn(`Skipping ${doc.figmaNode}: no template found`);
545
+ skippedCount++;
546
+ continue;
547
+ }
548
+ // Determine local source path for output location
549
+ let localSourcePath;
550
+ if (doc._codeConnectFilePath) {
551
+ // Use the Code Connect file path directly (preferred)
552
+ localSourcePath = doc._codeConnectFilePath;
553
+ }
554
+ else if (doc.source && gitRootPath) {
555
+ // Fallback: Convert remote file URL to local path
556
+ const relativePath = (0, run_wizard_2.convertRemoteFileUrlToRelativePath)({
557
+ remoteFileUrl: doc.source,
558
+ gitRootPath,
559
+ dir,
560
+ });
561
+ if (relativePath) {
562
+ // Convert relative path to absolute path for writeTemplateFile
563
+ localSourcePath = path_1.default.resolve(dir, relativePath);
564
+ }
565
+ }
566
+ const { outputPath, skipped } = (0, migration_helpers_1.writeTemplateFile)(doc, cmd.outDir, dir, localSourcePath, filePathsCreated, cmd.removeProps);
567
+ if (skipped) {
568
+ logging_1.logger.warn(`Skipping ${outputPath}: file already exists`);
569
+ skippedCount++;
570
+ }
571
+ else {
572
+ logging_1.logger.info(`${(0, logging_1.success)('✓')} Migrated to ${(0, logging_1.highlight)(outputPath)}`);
573
+ migratedCount++;
574
+ }
575
+ }
576
+ catch (error) {
577
+ const errorMsg = `Failed to migrate ${doc.figmaNode}: ${error}`;
578
+ logging_1.logger.error(errorMsg);
579
+ errors.push(errorMsg);
580
+ }
581
+ }
582
+ if (migratedCount > 0) {
583
+ if (cmd.outDir) {
584
+ const configFilePath = path_1.default.join(cmd.outDir, 'figma.config.json');
585
+ if (fs_1.default.existsSync(configFilePath)) {
586
+ logging_1.logger.warn(`Config file already exists at ${(0, logging_1.highlight)(configFilePath)}`);
587
+ }
588
+ else {
589
+ const { language: docLanguage, label } = codeConnectObjects[0];
590
+ const language = (0, label_language_mapping_1.getInferredLanguageForRaw)(label, docLanguage);
591
+ const config = {
592
+ include: ['**/*.figma.js'],
593
+ language,
594
+ label,
595
+ ...(documentUrlSubstitutions && Object.keys(documentUrlSubstitutions).length > 0
596
+ ? { documentUrlSubstitutions }
597
+ : {}),
598
+ };
599
+ fs_1.default.writeFileSync(configFilePath, JSON.stringify({ codeConnect: config }, null, 2));
600
+ logging_1.logger.info(`${(0, logging_1.success)('✓')} Wrote Figma config to ${(0, logging_1.highlight)(configFilePath)}`);
601
+ }
602
+ }
603
+ }
604
+ // Summary
605
+ console.log('');
606
+ logging_1.logger.info(`Migration complete: ${(0, logging_1.success)(`${migratedCount} migrated`)}, ${skippedCount} skipped`);
607
+ if (totalVariants > 0) {
608
+ logging_1.logger.error(`${(0, logging_1.error)(`${totalVariants} variant restriction(s)`)} found, but not supported by the migration script yet`);
609
+ }
610
+ if (errors.length > 0) {
611
+ console.log('');
612
+ logging_1.logger.error(`Encountered ${errors.length} error(s):`);
613
+ errors.forEach((err) => logging_1.logger.error(` ${err}`));
614
+ process.exit(1);
615
+ }
616
+ if (migratedCount === 0) {
617
+ (0, logging_1.exitWithError)('No files were migrated');
618
+ }
619
+ }
402
620
  //# sourceMappingURL=connect.js.map