From e7f8a0f323f9fcb6e5dc1fdec7c0ad2546ff510a Mon Sep 17 00:00:00 2001 From: figma-bot Date: Tue, 10 Sep 2024 11:22:39 +0000 Subject: [PATCH 1/9] Code Connect v1.1.0 --- .gitignore | 1 + CHANGELOG.md | 28 +- Package.resolved | 4 +- Package.swift | 2 +- README.md | 16 +- cli/README.md | 597 +---------------- cli/jest.config.js | 3 + cli/package.json | 34 +- cli/scripts/README.md | 1 + cli/src/__test__/e2e_connect_command.test.ts | 190 ------ .../e2e_connect_command_swift.test.ts | 170 ----- cli/src/__test__/utils.ts | 2 - cli/src/client/figma_client.ts | 20 +- cli/src/commands/connect.ts | 190 ++++-- cli/src/common/README.md | 1 + cli/src/common/__test__/project.test.ts | 17 - .../connect/__test__/determine_parser.test.ts | 64 +- .../angular/components/.gitkeep} | 0 .../determine_parser/angular/package.json | 15 + .../html/components/.gitkeep} | 0 .../determine_parser/html/package.json | 13 + .../determine_parser/vue/components/.gitkeep} | 0 .../determine_parser/vue/package.json | 15 + .../__test__/e2e}/e2e_create_command.test.ts | 10 +- .../dummy_api_response.json | 0 .../invalid_parser/figma.config.json | 0 .../react/expected_component | 2 +- .../e2e_create_command/react}/package.json | 0 .../unit_test_parser/figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../unit_test_parser_error/figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../__test__/e2e}/e2e_legacy_config.test.ts | 171 ++--- .../dummy_api_response_for_wizard.json | 0 .../e2e/e2e_parse_command/html/package.json | 13 + .../html/test-component.figma.ts | 5 + .../html_angular/package.json | 15 + .../html_angular/test-component.figma.ts | 5 + .../e2e_parse_command/html_vue/package.json | 15 + .../html_vue/test-component.figma.ts | 5 + .../invalid_parser/figma.config.json | 0 .../legacy_both_config/figma.config.json | 0 .../legacy_react_config/figma.config.json | 0 .../legacy_react_config}/package.json | 0 .../figma.config.json | 0 .../legacy_react_minimal_config}/package.json | 0 .../legacy_swift_config/Test.xcodeproj | 0 .../legacy_swift_config/figma.config.json | 0 .../ReactApiComponent.figmadoc.tsx | 0 .../react_storybook/ReactApiComponent.tsx | 0 .../StorybookComponent.stories.tsx | 0 .../react_storybook/StorybookComponent.tsx | 0 .../react_storybook}/package.json | 0 .../react_storybook/tsconfig.json | 0 .../react_wizard/components/NoExports.tsx | 0 .../react_wizard/components/PrimaryButton.tsx | 0 .../react_wizard}/package.json | 0 .../react_wizard/tsconfig.json | 0 .../swift_package/Package.resolved | 6 +- .../swift_package/Package.swift | 2 +- .../CodeConnectE2ETest/Toggle+Figma.swift | 0 .../swift_parser.xcodeproj/project.pbxproj | 2 +- .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/swiftpm/Package.resolved | 4 +- .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../swift_parser/ContentView.swift | 0 .../Preview Assets.xcassets/Contents.json | 0 .../swift_parser/Toggle+Figma.swift | 0 .../swift_parser/swift_parser.entitlements | 0 .../swift_parser/swift_parserApp.swift | 0 .../swift_wizard.xcodeproj/project.pbxproj | 2 +- .../contents.xcworkspacedata | 0 .../xcshareddata/IDEWorkspaceChecks.plist | 0 .../xcshareddata/swiftpm/Package.resolved | 4 +- .../xcschemes/xcschememanagement.plist | 0 .../AccentColor.colorset/Contents.json | 0 .../AppIcon.appiconset/Contents.json | 0 .../Assets.xcassets/Contents.json | 0 .../swift_wizard/ContentView.swift | 0 .../Preview Assets.xcassets/Contents.json | 0 .../swift_wizard/PrimaryButton.swift | 0 .../swift_wizard/Toggle+Figma.swift | 0 .../swift_wizard/swift_parser.entitlements | 0 .../swift_wizard/swift_parserApp.swift | 0 .../unit_test_parser/Excluded.test | 0 .../unit_test_parser/OtherFile.test | 0 .../unit_test_parser/Test.test | 0 .../unit_test_parser/figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../unit_test_parser_error/Test.test | 0 .../unit_test_parser_error/figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../Test.test | 0 .../figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../unit_test_parser_warning/Excluded.test | 0 .../unit_test_parser_warning/OtherFile.test | 0 .../unit_test_parser_warning/Test.test | 0 .../figma.config.json | 0 .../parser/unit_test_parser.js | 0 .../e2e/e2e_parse_command_html.test.ts | 101 +++ ...e_parse_command_parser_executables.test.ts | 114 ++++ .../e2e/e2e_parse_command_react.test.ts | 70 ++ .../e2e/e2e_parse_command_swift.test.ts | 89 +++ .../e2e_parse_command_swift_xcodeproj.test.ts | 86 +++ .../__test__/e2e}/e2e_wizard_react.test.ts | 4 +- .../__test__/e2e}/e2e_wizard_swift.test.ts | 4 +- .../__test__/e2e}/test_wizard_e2e.ts | 8 +- cli/src/connect/__test__/project.test.ts | 32 +- .../__test__/template_rendering_utils.ts | 248 +++++++ cli/src/{common => connect}/api.ts | 111 +--- cli/src/connect/create.ts | 3 + cli/src/connect/create_common.ts | 25 + cli/src/connect/delete_docs.ts | 2 +- cli/src/connect/external_types.ts | 35 + cli/src/{common => connect}/figma_connect.ts | 0 cli/src/connect/figma_rest_api.ts | 4 + cli/src/connect/index_common.ts | 21 + cli/src/{common => connect}/intrinsics.ts | 92 ++- cli/src/connect/parser_common.ts | 452 +++++++++++++ cli/src/connect/parser_executable_types.ts | 30 +- cli/src/connect/parser_executables.ts | 2 +- cli/src/connect/project.ts | 129 +++- cli/src/connect/upload.ts | 2 +- cli/src/connect/validation.ts | 2 +- .../__test__/autolinking/autolinking.test.ts | 145 ----- .../wizard/__test__/autolinking/types.ts | 12 - .../connect/wizard/__test__/helpers.test.ts | 14 +- .../wizard/__test__/prop_mapping/basic.ts | 44 ++ .../prop_mapping/prop_mapping.test.ts | 170 ++--- .../prop_mapping/signature_extraction.test.ts | 99 +++ .../tsProgram/react/Components.tsx | 12 +- .../tsProgram/react/Components2.tsx | 9 + .../wizard/__test__/prop_mapping/types.ts | 16 + .../tsProgram/react/figma.config.json | 6 + .../react/non_supported_filetype.css | 5 + .../tsProgram/react/plain_js_file.jsx | 5 + cli/src/connect/wizard/helpers.ts | 31 +- cli/src/connect/wizard/prop_mapping.ts | 244 ++++--- cli/src/connect/wizard/run_wizard.ts | 17 +- .../connect/wizard/signature_extraction.ts | 59 ++ cli/src/html/README.md | 3 + .../parser/examples/NoConfigObject.figma.ts | 4 + .../parser/examples/NoExample.figma.ts | 4 + ...gularFunctionExampleWithExtraCode.figma.ts | 8 + .../examples/WrongSignatureJsx.figma.tsx | 10 + .../examples/WrongSignatureNoHtmlTag.figma.ts | 10 + cli/src/html/__test__/parser/parser.test.ts | 68 ++ cli/src/html/create.ts | 62 ++ cli/src/html/external.ts | 39 ++ cli/src/html/index_html.ts | 97 +++ cli/src/html/parser.ts | 586 +++++++++++++++++ cli/src/html/parser_template_helpers.ts | 63 ++ cli/src/html/template_literal.ts | 10 + cli/src/index.ts | 34 - .../parser_scripts/get_swift_parser_dir.ts | 57 +- cli/src/react/README.md | 3 + .../__test__/ButtonArrowFunction.figma.tsx | 2 +- .../react/__test__/ImportsCasings.figma.tsx | 12 + .../components/test-component-kebab.tsx | 3 + .../components/test_component_underscore.tsx | 3 + cli/src/react/__test__/create.test.ts | 216 +++++- cli/src/react/__test__/parser.test.ts | 73 ++- cli/src/react/create.ts | 216 ++++-- cli/src/{common => react}/external.ts | 51 +- cli/src/react/index_react.ts | 118 ++++ cli/src/react/parser.ts | 559 +++++----------- cli/src/react/parser_template_helpers.ts | 96 +-- cli/src/storybook/convert.ts | 12 +- cli/src/storybook/external.ts | 2 +- cli/src/typescript/compiler.ts | 21 +- compose/README.md | 264 +------- compose/plugin/gradle.properties | 2 +- ...nnectTemplate.kt => CodeConnectCreator.kt} | 2 +- .../code/connect/FigmaCodeConnectPlugin.kt | 2 +- docs/README.md | 7 + docs/compose.md | 265 ++++++++ docs/html.md | 541 +++++++++++++++ docs/react.md | 615 ++++++++++++++++++ docs/swiftui.md | 354 ++++++++++ react/README.md | 2 +- scripts/make_readme_links_absolute.ts | 21 + swiftui/README.md | 349 +--------- 190 files changed, 6067 insertions(+), 2997 deletions(-) delete mode 100644 cli/src/__test__/e2e_connect_command.test.ts delete mode 100644 cli/src/__test__/e2e_connect_command_swift.test.ts create mode 100644 cli/src/common/README.md delete mode 100644 cli/src/common/__test__/project.test.ts rename cli/src/{__test__/e2e_connect_command/legacy_swift_config/Test.xcodeproj => connect/__test__/determine_parser/angular/components/.gitkeep} (100%) create mode 100644 cli/src/connect/__test__/determine_parser/angular/package.json rename cli/src/{__test__/e2e_connect_command/unit_test_parser/Excluded.test => connect/__test__/determine_parser/html/components/.gitkeep} (100%) create mode 100644 cli/src/connect/__test__/determine_parser/html/package.json rename cli/src/{__test__/e2e_connect_command/unit_test_parser_warning/Excluded.test => connect/__test__/determine_parser/vue/components/.gitkeep} (100%) create mode 100644 cli/src/connect/__test__/determine_parser/vue/package.json rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command.test.ts (94%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command/dummy_api_response.json (100%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command/invalid_parser/figma.config.json (100%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command/react/expected_component (91%) rename cli/src/{__test__/e2e_connect_command/legacy_react_config => connect/__test__/e2e/e2e_create_command/react}/package.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_create_command}/unit_test_parser/figma.config.json (100%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command/unit_test_parser/parser/unit_test_parser.js (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_create_command}/unit_test_parser_error/figma.config.json (100%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command/unit_test_parser_error/parser/unit_test_parser.js (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_create_command}/unit_test_parser_invalid_response/figma.config.json (100%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command/unit_test_parser_invalid_response/parser/unit_test_parser.js (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_create_command}/unit_test_parser_warning/figma.config.json (100%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_create_command/unit_test_parser_warning/parser/unit_test_parser.js (100%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_legacy_config.test.ts (65%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/dummy_api_response_for_wizard.json (100%) create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/html/package.json create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/html/test-component.figma.ts create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/html_angular/package.json create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/html_angular/test-component.figma.ts create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/html_vue/package.json create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/html_vue/test-component.figma.ts rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/invalid_parser/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/legacy_both_config/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/legacy_react_config/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command/legacy_react_minimal_config => connect/__test__/e2e/e2e_parse_command/legacy_react_config}/package.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/legacy_react_minimal_config/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command/react_storybook => connect/__test__/e2e/e2e_parse_command/legacy_react_minimal_config}/package.json (100%) create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/legacy_swift_config/Test.xcodeproj rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/legacy_swift_config/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_storybook/ReactApiComponent.figmadoc.tsx (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_storybook/ReactApiComponent.tsx (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_storybook/StorybookComponent.stories.tsx (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_storybook/StorybookComponent.tsx (100%) rename cli/src/{__test__/e2e_connect_command/react_wizard => connect/__test__/e2e/e2e_parse_command/react_storybook}/package.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_storybook/tsconfig.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_wizard/components/NoExports.tsx (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_wizard/components/PrimaryButton.tsx (100%) rename cli/src/{__test__/e2e_create_command/react => connect/__test__/e2e/e2e_parse_command/react_wizard}/package.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/react_wizard/tsconfig.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_package/Package.resolved (79%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_package/Package.swift (92%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_package/Sources/CodeConnectE2ETest/Toggle+Figma.swift (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser.xcodeproj/project.pbxproj (99%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename cli/src/{__test__/e2e_connect_command/swift_wizard/swift_wizard.xcodeproj => connect/__test__/e2e/e2e_parse_command/swift_parser/swift_parser.xcodeproj}/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (86%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/Assets.xcassets/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/ContentView.swift (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/Preview Content/Preview Assets.xcassets/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/Toggle+Figma.swift (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/swift_parser.entitlements (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_parser/swift_parser/swift_parserApp.swift (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard.xcodeproj/project.pbxproj (99%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard.xcodeproj/project.xcworkspace/contents.xcworkspacedata (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist (100%) rename cli/src/{__test__/e2e_connect_command/swift_parser/swift_parser.xcodeproj => connect/__test__/e2e/e2e_parse_command/swift_wizard/swift_wizard.xcodeproj}/project.xcworkspace/xcshareddata/swiftpm/Package.resolved (86%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard.xcodeproj/xcuserdata/slees.xcuserdatad/xcschemes/xcschememanagement.plist (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/Assets.xcassets/AccentColor.colorset/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/Assets.xcassets/AppIcon.appiconset/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/Assets.xcassets/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/ContentView.swift (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/Preview Content/Preview Assets.xcassets/Contents.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/PrimaryButton.swift (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/Toggle+Figma.swift (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/swift_parser.entitlements (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/swift_wizard/swift_wizard/swift_parserApp.swift (100%) create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/unit_test_parser/Excluded.test rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser/OtherFile.test (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser/Test.test (100%) rename cli/src/{__test__/e2e_create_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser/parser/unit_test_parser.js (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_error/Test.test (100%) rename cli/src/{__test__/e2e_create_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_error/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_error/parser/unit_test_parser.js (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_invalid_response/Test.test (100%) rename cli/src/{__test__/e2e_create_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_invalid_response/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_invalid_response/parser/unit_test_parser.js (100%) create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command/unit_test_parser_warning/Excluded.test rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_warning/OtherFile.test (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_warning/Test.test (100%) rename cli/src/{__test__/e2e_create_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_warning/figma.config.json (100%) rename cli/src/{__test__/e2e_connect_command => connect/__test__/e2e/e2e_parse_command}/unit_test_parser_warning/parser/unit_test_parser.js (100%) create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command_html.test.ts create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command_parser_executables.test.ts create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command_react.test.ts create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command_swift.test.ts create mode 100644 cli/src/connect/__test__/e2e/e2e_parse_command_swift_xcodeproj.test.ts rename cli/src/{__test__ => connect/__test__/e2e}/e2e_wizard_react.test.ts (65%) rename cli/src/{__test__ => connect/__test__/e2e}/e2e_wizard_swift.test.ts (75%) rename cli/src/{__test__ => connect/__test__/e2e}/test_wizard_e2e.ts (92%) create mode 100644 cli/src/connect/__test__/template_rendering_utils.ts rename cli/src/{common => connect}/api.ts (50%) create mode 100644 cli/src/connect/create_common.ts create mode 100644 cli/src/connect/external_types.ts rename cli/src/{common => connect}/figma_connect.ts (100%) create mode 100644 cli/src/connect/index_common.ts rename cli/src/{common => connect}/intrinsics.ts (82%) create mode 100644 cli/src/connect/parser_common.ts delete mode 100644 cli/src/connect/wizard/__test__/autolinking/autolinking.test.ts delete mode 100644 cli/src/connect/wizard/__test__/autolinking/types.ts create mode 100644 cli/src/connect/wizard/__test__/prop_mapping/basic.ts create mode 100644 cli/src/connect/wizard/__test__/prop_mapping/signature_extraction.test.ts create mode 100644 cli/src/connect/wizard/__test__/prop_mapping/tsProgram/react/Components2.tsx create mode 100644 cli/src/connect/wizard/__test__/prop_mapping/types.ts create mode 100644 cli/src/connect/wizard/__test__/tsProgram/react/figma.config.json create mode 100644 cli/src/connect/wizard/__test__/tsProgram/react/non_supported_filetype.css create mode 100644 cli/src/connect/wizard/__test__/tsProgram/react/plain_js_file.jsx create mode 100644 cli/src/connect/wizard/signature_extraction.ts create mode 100644 cli/src/html/README.md create mode 100644 cli/src/html/__test__/parser/examples/NoConfigObject.figma.ts create mode 100644 cli/src/html/__test__/parser/examples/NoExample.figma.ts create mode 100644 cli/src/html/__test__/parser/examples/RegularFunctionExampleWithExtraCode.figma.ts create mode 100644 cli/src/html/__test__/parser/examples/WrongSignatureJsx.figma.tsx create mode 100644 cli/src/html/__test__/parser/examples/WrongSignatureNoHtmlTag.figma.ts create mode 100644 cli/src/html/__test__/parser/parser.test.ts create mode 100644 cli/src/html/create.ts create mode 100644 cli/src/html/external.ts create mode 100644 cli/src/html/index_html.ts create mode 100644 cli/src/html/parser.ts create mode 100644 cli/src/html/parser_template_helpers.ts create mode 100644 cli/src/html/template_literal.ts delete mode 100644 cli/src/index.ts create mode 100644 cli/src/react/README.md create mode 100644 cli/src/react/__test__/ImportsCasings.figma.tsx create mode 100644 cli/src/react/__test__/components/test-component-kebab.tsx create mode 100644 cli/src/react/__test__/components/test_component_underscore.tsx rename cli/src/{common => react}/external.ts (51%) create mode 100644 cli/src/react/index_react.ts rename compose/plugin/src/main/kotlin/com/figma/code/connect/{CodeConnectTemplate.kt => CodeConnectCreator.kt} (99%) create mode 100644 docs/README.md create mode 100644 docs/compose.md create mode 100644 docs/html.md create mode 100644 docs/react.md create mode 100644 docs/swiftui.md create mode 100644 scripts/make_readme_links_absolute.ts diff --git a/.gitignore b/.gitignore index de6569f..f74dec7 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,4 @@ bundle/ .swiftpm/ bundle-cli webpack-dist +bundle-npm diff --git a/CHANGELOG.md b/CHANGELOG.md index c225c67..7006f0a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,30 @@ +# Code Connect v1.1.0 (10th September 2024) + +## Features + +### HTML +- Added support for documenting HTML-based frameworks (including Web Components, Angular and Vue), using the new `html` parser. See the [documentation](docs/html.md) for more information. + + HTML support for Code Connect is in preview, and the API is liable to change during this period. Please let us know your feedback via [GitHub Issues](https://github.com/figma/code-connect/issues/new/choose). + +### SwiftUI +- Added a `swiftPackagePath` configuration option to specify a custom path to a `Package.swift` file to run Code Connect from. + +### React +- Code Connect files created in the CLI assistant will now start including some auto-generated prop mappings between Figma properties and linked code props. This is an early feature and support for different prop types is limited. + +### General + +- Restructured the Code Connect documentation. All documentation can now be found in the [docs](docs) directory. + +## Fixed + +### React +- `figma.nestedProps` can now be used in conjunction with `figma.boolean` for conditionally hidden nested instances (fixes https://github.com/figma/code-connect/issues/118, https://github.com/figma/code-connect/issues/89) +- Fixed an issue where backticks could not be used in the example code (fixes https://github.com/figma/code-connect/issues/139) +- Fixed an issue with wildcard paths in import mappings +- Fixed an error when trying to use the icon script with component sets + # Code Connect v1.0.6 (21st August 2024) ## Fixed @@ -7,7 +34,6 @@ ## Features - ### React - figma.enum now supports floating point numbers diff --git a/Package.resolved b/Package.resolved index 47b3c84..00ea305 100644 --- a/Package.resolved +++ b/Package.resolved @@ -14,8 +14,8 @@ "kind" : "remoteSourceControl", "location" : "https://github.com/apple/swift-syntax", "state" : { - "revision" : "64889f0c732f210a935a0ad7cda38f77f876262d", - "version" : "509.1.1" + "revision" : "2bc86522d115234d1f588efe2bcb4ce4be8f8b82", + "version" : "510.0.3" } }, { diff --git a/Package.swift b/Package.swift index 6d2317e..9920646 100644 --- a/Package.swift +++ b/Package.swift @@ -15,7 +15,7 @@ let package = Package( .executable(name: "figma-swift", targets: ["CodeConnectCLI"]) ], dependencies: [ - .package(url: "https://github.com/apple/swift-syntax", from: "509.1.1"), + .package(url: "https://github.com/apple/swift-syntax", "510.0.3"..."600.0.0-prerelease-2024-08-14"), .package(url: "https://github.com/apple/swift-argument-parser", from: "1.0.0"), .package(url: "https://github.com/nicklockwood/SwiftFormat", from: "0.49.0"), ], diff --git a/README.md b/README.md index a890573..344730a 100644 --- a/README.md +++ b/README.md @@ -2,7 +2,7 @@ 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. -Code Connect is easy to set up, easy to maintain, type-safe, and extensible. Out of the box Code Connect comes with support for React (and React Native), Storybook, SwiftUI and Jetpack Compose. +Code Connect is easy to set up, easy to maintain, type-safe, and extensible. Out of the box Code Connect comes with support for React (and React Native), Storybook, HTML (e.g. Web Components, Angular and Vue), SwiftUI and Jetpack Compose. ![image](https://static.figma.com/uploads/d98e747613e01685d6a0f9dd3e2dcd022ff289c0.png) @@ -25,9 +25,10 @@ We hope to provide a way to install Code Connect without requiring Node.js soon. To learn how to implement Code Connect for your platform, please navigate to the platform-specific API usage and documentation. -- [React (or React Native)](cli/README.md) -- [SwiftUI](swiftui/README.md) -- [Jetpack Compose](compose/README.md) +- [React (or React Native)](docs/react.md) +- [HTML (Web Components, Angular, Vue, etc.)](docs/html.md) +- [SwiftUI](docs/swiftui.md) +- [Jetpack Compose](docs/compose.md) ## General configuration @@ -53,10 +54,11 @@ Every platform supports some common configuration options, in addition to any pl Code Connect will attempt to determine your project type by looking the first ancestor of the working directory which matches one of the following: - If a `package.json` containing `react` is found, your project is detected as React +- If a `package.json` is found not containing `react`, your project is detected as HTML - If a file matching `Package.swift` or `*.xcodeproj` is found, your project is detected as Swift - If a file matching `build.gradle.kts` is found, your project is detected as Jetpack Compose -In case this does not correctly work for your project, you can override the project type by using the `parser` configuration key. Valid values are `react`, `swift` and `compose`. +In case this does not correctly work for your project, you can override the project type by using the `parser` configuration key. Valid values are `react`, `html`, `swift` and `compose`. ```jsonp { @@ -66,6 +68,10 @@ In case this does not correctly work for your project, you can override the proj } ``` +### `label` + +`label` allows you to specify the label used in Figma for your Code Connect docs. This defaults to the type of your project (e.g. `React`). You can override this to show a different name in the UI, which can be useful for e.g. showing different versions of the code. + ### `documentUrlSubstitutions` `documentUrlSubstitutions` allows you to specify a set of substitutions which will be run on the `figmaNode` URLs when parsing or publishing documents. diff --git a/cli/README.md b/cli/README.md index ee4d962..7626aa6 100644 --- a/cli/README.md +++ b/cli/README.md @@ -1,596 +1,3 @@ -# Code Connect (React) +See the [main README](../README.md) for Code Connect documentation. -For more information about Code Connect as well as guides for other platforms and frameworks, please [go here](../README.md). - -This documentation will help you connect your React (or React Native) components with Figma components using Code Connect. We'll cover basic setup to display your first connected code snippet, followed by making snippets dynamic by using property mappings. Code Connect for React works as both a standalone implementation and as an integration with existing Storybook files to enable easily maintaining both systems in parallel. - -## Installation - -Code Connect is used through a command line interface (CLI). The CLI comes bundled with the `@figma/code-connect` package, which you'll need to install through `npm`. This package also includes helper functions and types associated with Code Connect. - -```sh -npm install @figma/code-connect -``` - -## Basic setup - -To connect your first component go to Dev Mode in Figma and right-click on the component you want to connect, then choose `Copy link to selection` from the menu. Make sure you are copying the link to a main component and not an instance of the component. The main component will typically be located in a centralized design system library file. Using this link, run `figma connect create` from inside your React project. Note that depending on what terminal software you're using, you might need to wrap the URL in quotes. - -```sh -npx figma connect create "https://..." --token -``` - -This will create a Code Connect file with some basic scaffolding for the component you want to connect. By default this file will be called `.figma.tsx` based on the name of the component in Figma. However, you may rename this file as you see fit. The scaffolding that is generated is based on the interface of the component in Figma. Depending on how closely this matches your code component you'll need to make some edits to this file before you publish it. - -Some CLI commands, like `create`, require a valid [authentication token](https://help.figma.com/hc/en-us/articles/8085703771159-Manage-personal-access-tokens) with write permission for the Code Connect scope as well as the read permission for the File content scope. You can either pass this via the `--token` flag, or set the `FIGMA_ACCESS_TOKEN` environment variable. The Figma CLI reads this from a `.env` file in the same folder, if it exists. - -To keep things simple, we're going to start by replacing the contents of the generated file with the most basic Code Connect configuration possible to make sure everything is set up and working as expected. Replace the contents of the file with the following, replacing the `Button` reference with a reference to whatever component you are trying to connect. The object called by `figma.connect` is your Code Connect doc. - -```tsx -import figma from '@figma/code-connect' -import { Button } from 'src/components' - -figma.connect(Button, 'https://...', { - example: () => { - return - ) - }, -}) -``` - -And this is how we would achieve the same thing using the Storybook integration. Notice how this works well with existing `args` configuration you may already be using in Storybook. - -```tsx -import figma from "@figma/code-connect" - -export default { - component: Button, - parameters: { - design: { - type: 'figma', - url: 'https://...', - examples: [ButtonExample], - props: { - label: figma.string('Text Content'), - disabled: figma.boolean('Disabled'), - type: figma.enum('Type', { - Primary: ButtonType.Primary, - Secondary: ButtonType.Secondary - }, - }, - }, - argTypes: { - label: { control: 'string' }, - disabled: { control: 'boolean' }, - type: { - control: { - type: 'select', - options: [ButtonType.Primary, ButtonType.Secondary] - } - } - }, - args: { - label: 'Hello world', - disabled: false, - type: ButtonType.Primary - } - } -} - -export function ButtonExample({ label, disabled, type }) { - return -} -``` - -The `figma` import contains helpers for mapping all sorts of properties from design to code. They work for simple mappings where only the naming differs between Figma and code, as well as more complex mappings where the type differs. See the below reference for all the helpers that exist and the ways you can use them to connect Figma and code components using Code Connect. - -### figma.connect - -`figma.connect()` has two signatures for connecting components. - -``` -// connect a component in code to a Figma component -figma.connect(Button, "https://...") - -// connect a Figma component to e.g a native element -figma.connect("https://...") -``` - -The second option is useful if you want to just render a HTML tag instead of a React component. The first argument is used to determine where your component lives in code, in order to generate an import statement for the component. This isn't needed if you just want to render e.g a `button` tag. - -``` -figma.connect("https://...", { - example: () => -}) -``` - -### Strings - -Strings are the simplest value to map from Figma to code. Simply call `figma.string` with the Figma prop name you want to reference as a parameter. This is useful for things like button labels, header titles, tooltips, etc. - -```tsx -figma.string('Title') -``` - -### Booleans - -Booleans work similar to strings. However Code Connect also provides helpers for mapping booleans in Figma to more complex types in code. For example you may want to map a Figma boolean to the existence of a specific sublayer in code. In addition to mapping boolean props, `figma.boolean` can be used to map boolean Variants in Figma. A boolean Variant is a Variant with only two options that are either "Yes"/"No", "True"/"False" or "On"/Off". For `figma.boolean` these values are normalized to `true` and `false`. - -```tsx -// simple mapping of boolean from figma to code -figma.boolean('Has Icon') - -// map a boolean value to one of two options of any type -figma.boolean('Has Icon', { - true: , - false: , -}) -``` - -In some cases, you only want to render a certain prop if it matches some value in Figma. You can do this either by passing a partial mapping object, or setting the value to `undefined`. - -```tsx -// Don't render the prop if 'Has label' in figma is `false` -figma.boolean('Has label', { - true: figma.string('Label'), - false: undefined, -}) -``` - -### Enums - -Variants (or enums) in Figma are commonly used to control the look and feel of components that require more complex options than a simple boolean toggle. Variant properties are always strings in Figma but they can be mapped to any type in code. The first parameter is the name of the Variant in Figma, and the second parameter is a value mapping. The _keys_ in this object should match the different options of that Variant in Figma, and the _value_ is whatever you want to output instead. - -```tsx -// maps the 'Options' variant in Figma to enum values in code -figma.enum('Options', { - 'Option 1': Option.first, - 'Option 2': Option.second, -}) - -// maps the 'Options' variant in Figma to sub-component values in code -figma.enum('Options', { - 'Option 1': , - 'Option 2': , -}) - -// result is true for disabled variants otherwise undefined -figma.enum('Variant', { Disabled: true }) - -// enums mappings can be used to show a component based on a Figma variant -figma.connect(Modal, 'https://...', { - props: { - cancelButton: figma.enum('Type', { - Cancellable: , - }), - // ... - }, - example: ({ cancelButton }) => { - return ( - - Title - Some content - {cancelButton} - - ) - }, -}) -``` - -Mapping objects for `figma.enum` as well as `figma.boolean` allows nested references, which is useful if you want to conditionally render a nested instance for example. (see the next section for how to use `figma.instance`) - -```tsx -// maps the 'Options' variant in Figma to enum values in code -figma.enum('Type', { - WithIcon: figma.instance('Icon'), - WithoutIcon: undefined, -}) -``` - -Note that in contrast to `figma.boolean`, values are _not_ normalized for `figma.enum`. You always need to pass the exact literal values to the mapping object. - -```tsx -// These two are equivalent for a variant with the options "Yes" and "No" -disabled: figma.enum("Boolean Variant", { - Yes: // ... - No: // ... -}) -disabled: figma.boolean("Boolean Variant", { - true: // ... - false: // ... -}) -``` - -### Instances - -Instances is a Figma term for nested component references. For example, in the case of a `Button` containing an `Icon` as a nested component, we would call the `Icon` an instance. In Figma instances can be properties, (that is, inputs to the component), just like we have render props in code. Similarly to how we can map booleans, enums, and strings from Figma to code, we can also map these to instance props. - -To ensure instance properties are as useful as possible with Code Connect, it is advised that you also provide Code Connect for the common components which you would expect to be used as values to this property. Dev Mode will automatically hydrate the referenced component's connected code snippet example and how changes it in Dev Mode for instance props. - -```tsx -// maps an instance-swap property from Figma -figma.instance('PropName') -``` - -The return value of `figma.instance` is a JSX component and can be used in your example like a typical JSX component prop would be in your codebase. - -```tsx -figma.connect(Button, 'https://...', { - props: { - icon: figma.instance('Icon'), - }, - example: ({ icon }) => { - return - }, -}) -``` - -You should then have a separate `figma.connect` call that connects the Icon component with the nested Figma component. Make sure to connect the backing component of that instance, not the instance itself. - -```tsx -figma.connect(Icon32Add, 'https://...') -``` - -### Instance children - -It's common for components in Figma to have child instances that aren't bound to an instance-swap prop. Similarly to `figma.instance`, we can render the code snippets for these nested instances with `figma.children`. This helper takes the _name of the instance layer within the parent component_ as its parameter, rather than a Figma prop name. - -To illustrate this, consider the layer hierarchy in a component vs an instance of that component: - -Button (Component) -Icon (Instance) -- "Icon" is the original name of the layer, this is what you should pass to `figma.children()` - -Button (Instance) -RenamedIcon (Instance) -- here the instance layer was renamed, which won't break the mapping since we're not using this name - -Note that the nested instance also must be connected separately. - -> Layer names may differ between variants in a component set. To ensure the component (Button) can render a nested instance (Icon) for any of those variants, you must either use the wildcard option `figma.children("*")` or ensure that the layer name representing the instance (Icon) is the same across all variants of your component set (Button). - -```tsx -// map one child instance with the layer name "Tab" -figma.children('Tab') - -// map multiple child instances by their layer names to a single prop -figma.children(['Tab 1', 'Tab 2']) -``` - -### Wildcard match - -`figma.children()` can be used with a single wildcard '\*' character, to partially match names or to render any nested child. Wildcards cannot be used with the array argument. Matches are case sensitive. - -```tsx -// map any (all) child instances -figma.children('*') - -// map any child instances that starts with "Icon" -figma.children('Icon*') -``` - -### Nested properties - -In cases where you don't want to connect a child component, but instead map its properties on the parent level, you can use `figma.nestedProps()` to achieve this. This helper takes the name of the layer as it's first parameter, and a mapping object as the second parameter. These props can then be referenced in the example function. `nestedProps` will always select a **single** instance, and cannot be used to map multiple children. - -```tsx -// map the properties of a nested instance named "Button Shape" -figma.connect(Button, "https://...", { - props: { - buttonShape: figma.nestedProps('Button Shape', { - size: figma.enum({ ... }), - }) - }, - example: ({ buttonShape }) => -} -``` - -### className - -For mapping figma properties to a className string, you can use the `figma.className` helper. It takes an array of strings and returns the concatenated string. Any other helper that returns a string (or undefined) can be used in conjunction with this. Undefined values or empty strings will be filtered out from the result - -```tsx -figma.connect("https://...", { - props: { - className: figma.className([ - 'btn-base', - figma.enum("Size", { Large: 'btn-large' }), - figma.boolean("Disabled", { true: 'btn-disabled', false: '' }), - ]) - }, - example: ({ className }) =>