Skip to content

Commit ea14f76

Browse files
figma-botislobodiuk-figma
authored andcommitted
Code Connect v1.3.13
1 parent 131c997 commit ea14f76

44 files changed

Lines changed: 1434 additions & 108 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

CHANGELOG.md

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,30 @@
1-
# Code Connect v1.3.12
1+
# Code Connect v1.3.13 (29th January 2026)
2+
3+
## Features
4+
5+
- Add --api-url option to use a different code-connect api endpoint. This option can also be configured in figma.config.json with the `apiUrl` field
6+
- Add `language` config option to override syntax highlighting language in figma.config.json
7+
8+
### Parserless
9+
10+
- Syntax highlighting + formatting for parserless templates when publishing with a known label (e.g. React)
211

312
## Fixed
413

5-
- Fixed a problem with path alias imports incorrectly importing index files
6-
- Fixed parsing failure for Compose in Windows.
14+
- Fix crash that occurs when the provided Figma file has no components
15+
- Set version number for annotations gradle plugin
16+
- Security update: upgraded undici to fix CVE-2026-22036. Roll back and report if you encounter networking issues.
17+
- Security update: upgraded lodash to fix CVE-2025-13465.
18+
19+
# Code Connect v1.3.12 (10th December 2025)
720

821
### General
922

23+
## Fixed
24+
25+
- Fixed a problem with path alias imports incorrectly importing index files
26+
- Fixed parsing failure for Compose in Windows.
27+
1028
# Code Connect v1.3.11 (26th November 2025)
1129

1230
### Swift

cli/npm_catalog.toml

Lines changed: 50 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -100,28 +100,30 @@
100100
"@babel/types" = "7.28.5"
101101
"eslint" = "^9.36.0"
102102
"eslint-config-prettier" = "^9.1.0"
103+
"eslint-plugin-clsx" = "^0.0.12"
103104
"eslint-plugin-import" = "^2.32.0"
104105
"eslint-plugin-jest" = "^28.8.3"
105106
"eslint-plugin-react" = "^7.37.5"
106107
"eslint-plugin-react-hooks" = "^5.2.0"
107108
"eslint-plugin-simple-import-sort" = "^12.1.1"
108109
"eslint-plugin-unused-imports" = "^4.1.4"
109110
"eslint-import-resolver-typescript" = "^4.4.4"
110-
"eslint-plugin-testing-library" = "^7.12.0"
111-
"eslint-plugin-workspaces" = "^0.11.0"
111+
"eslint-plugin-testing-library" = "^7.15.4"
112+
"eslint-plugin-workspaces" = "^0.11.1"
112113
"@eslint/js" = "^9.23.0"
113114
"@eslint/config-helpers" = "^0.4.0"
114-
"@typescript-eslint/eslint-plugin" = "8.47.0"
115-
"@typescript-eslint/parser" = "8.47.0"
116-
"@typescript-eslint/project-service" = "8.47.0"
117-
"@typescript-eslint/rule-tester" = "8.47.0"
118-
"@typescript-eslint/scope-manager" = "8.47.0"
119-
"@typescript-eslint/tsconfig-utils" = "8.47.0"
120-
"@typescript-eslint/types" = "8.47.0"
121-
"@typescript-eslint/typescript-estree" = "8.47.0"
122-
"@typescript-eslint/utils" = "8.47.0"
123-
"@typescript-eslint/visitor-keys" = "8.47.0"
124-
"typescript-eslint" = "8.47.0"
115+
"@vitest/eslint-plugin" = "^1.6.6"
116+
"@typescript-eslint/eslint-plugin" = "8.52.0"
117+
"@typescript-eslint/parser" = "8.52.0"
118+
"@typescript-eslint/project-service" = "8.52.0"
119+
"@typescript-eslint/rule-tester" = "8.52.0"
120+
"@typescript-eslint/scope-manager" = "8.52.0"
121+
"@typescript-eslint/tsconfig-utils" = "8.52.0"
122+
"@typescript-eslint/types" = "8.52.0"
123+
"@typescript-eslint/typescript-estree" = "8.52.0"
124+
"@typescript-eslint/utils" = "8.52.0"
125+
"@typescript-eslint/visitor-keys" = "8.52.0"
126+
"typescript-eslint" = "8.52.0"
125127
"@jest/core" = "^29.7.0"
126128
"@jest/create-cache-key-function" = "^29.7.0"
127129
"@jest/fake-timers" = "^29.7.0"
@@ -136,8 +138,8 @@
136138
"ts-jest" = "^29.2.5"
137139
"@types/lodash" = "4.17.20"
138140
"@types/lodash-es" = "4.17.12"
139-
"lodash" = "4.17.21"
140-
"lodash-es" = "4.17.21"
141+
"lodash" = "4.17.23"
142+
"lodash-es" = "4.17.23"
141143
"@oclif/core" = "3.27.0"
142144
"@storybook/addon-actions" = "8.5.1"
143145
"@storybook/addon-a11y" = "8.5.1"
@@ -162,55 +164,62 @@
162164
"@storybook/test" = "8.5.1"
163165
"@storybook/theming" = "8.5.1"
164166
"storybook" = "8.5.1"
165-
"@stylexjs/stylex" = "0.16.2"
166-
"@stylexjs/babel-plugin" = "0.16.2"
167-
"@stylexjs/eslint-plugin" = "0.16.2"
167+
"@stylexjs/stylex" = "0.17.4"
168+
"@stylexjs/babel-plugin" = "0.17.4"
169+
"@stylexjs/eslint-plugin" = "0.17.4"
168170
"@tailwindcss/oxide" = "4.1.3"
169171
"@tailwindcss/postcss" = "4.1.3"
170172
"@tailwindcss/vite" = "4.1.3"
171173
"tailwindcss" = "4.1.3"
172174
"@vitejs/plugin-react" = "4.4.1"
173-
"@vitest/browser" = "3.2.4"
174-
"@vitest/coverage-v8" = "3.2.4"
175-
"@vitest/runner" = "3.2.4"
176-
"@vitest/ui" = "3.2.4"
177175
"vite" = "6.3.6"
178-
"vitest" = "3.2.4"
179176
"webpack" = "5.91.0"
180177
"webpack-cli" = "5.1.4"
178+
"modal" = "^0.6.0"
179+
"@axe-core/playwright" = "4.11.0"
181180
"@bazel/runfiles" = "^6.3.1"
182181
"@figma/plugin-typings" = "1.121.0"
183182
"@figma/widget-typings" = "1.12.1"
184-
"@modelcontextprotocol/sdk" = "1.18.0"
185-
"@sentry/cli" = "2.58.2"
183+
"@formatjs/icu-messageformat-parser" = "^2.11.2"
184+
"@modelcontextprotocol/ext-apps" = "0.4.0"
185+
"@modelcontextprotocol/sdk" = "1.24.0"
186+
"@opentelemetry/api" = "^1.9.0"
187+
"@sentry/cli" = "2.58.3"
188+
"@types/jsdom" = "^21.1.7"
186189
"@types/mocha" = "10.0.10"
187190
"@types/node" = "22.17.2"
188-
"@types/react" = "18.0.26"
189-
"@types/react-dom" = "18.2.15"
191+
"@types/react" = "18.3.27"
192+
"@types/react-dom" = "18.3.7"
190193
"@types/sinon" = "17.0.4"
191194
"aws-crt" = "1.21.3"
192195
"aws-sdk-client-mock" = "4.1.0"
193196
"axe-core" = "4.11.0"
194-
"@axe-core/playwright" = "4.11.0"
195197
"axios-retry" = "^4.5.0"
198+
"csstype" = "^3.2.3"
199+
"dayjs" = "^1.11.19"
196200
"esbuild" = "0.25.0"
197-
"postcss" = "8.5.2"
201+
"jotai" = "2.9.3"
202+
"intl-messageformat" = "^10.7.14"
203+
"graphql" = "16.12.0"
204+
"jsdom" = "27.4.0"
198205
"knip" = "^5.27.3"
199206
"lightningcss" = "1.29.2"
207+
"mediabunny" = "1.25.8"
200208
"mocha" = "10.8.2"
201209
"mocha-junit-reporter" = "2.2.1"
210+
"postcss" = "8.5.2"
202211
"prettier" = "3.6.2"
203-
"react" = "18.3.1"
204212
"react-dom" = "18.3.1"
205213
"react-redux" = "8.0.5"
214+
"react" = "18.3.1"
206215
"sharp" = "0.33.5"
207216
"sinon" = "^17.0.1"
208217
"ts-morph" = "^27.0.0"
209218
"ts-node" = "^10.9.2"
210219
"typescript" = "5.9.3"
211220
"yaml" = "2.8.0"
212-
"zod" = "3.25.58"
213221
"zod-to-json-schema" = "^3.23.5"
222+
"zod" = "3.25.58"
214223
"ai" = "4.1.62"
215224
"@ai-sdk/amazon-bedrock" = "2.1.4"
216225
"@ai-sdk/anthropic" = "1.2.5"
@@ -222,3 +231,13 @@
222231
"@ai-sdk/openai" = "1.2.5"
223232
"@ai-sdk/provider" = "1.1.3"
224233
"@ai-sdk/provider-utils" = "2.2.8"
234+
"@ai-sdk/amazon-bedrock-v5" = "npm:@ai-sdk/amazon-bedrock@3.0.73"
235+
"@ai-sdk/anthropic-v5" = "npm:@ai-sdk/anthropic@2.0.57"
236+
"@ai-sdk/azure-v5" = "npm:@ai-sdk/azure@2.0.91"
237+
"@ai-sdk/cerebras-v5" = "npm:@ai-sdk/cerebras@1.0.35"
238+
"@ai-sdk/fireworks-v5" = "npm:@ai-sdk/fireworks@1.0.31"
239+
"@ai-sdk/google-v5" = "npm:@ai-sdk/google@2.0.52"
240+
"@ai-sdk/google-vertex-v5" = "npm:@ai-sdk/google-vertex@3.0.72"
241+
"@ai-sdk/openai-v5" = "npm:@ai-sdk/openai@2.0.89"
242+
"@ai-sdk/provider-v5" = "npm:@ai-sdk/provider@2.0.0"
243+
"@ai-sdk/provider-utils-v5" = "npm:@ai-sdk/provider-utils@3.0.17"

cli/package.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@figma/code-connect",
3-
"version": "1.3.12",
3+
"version": "1.3.13",
44
"description": "A tool for connecting your design system components in code with your design system in Figma",
55
"keywords": [],
66
"author": "Figma",
@@ -76,7 +76,7 @@
7676
"@types/node": "22.17.2",
7777
"@types/prettier": "2.7.3",
7878
"@types/prompts": "^2.4.9",
79-
"@types/react": "18.0.26",
79+
"@types/react": "18.3.27",
8080
"cross-env": "^7.0.3",
8181
"jest": "^29.7.0",
8282
"patch-package": "^8.0.0",
@@ -101,7 +101,7 @@
101101
"find-up": "^5.0.0",
102102
"glob": "^11.0.4",
103103
"jsdom": "^24.1.1",
104-
"lodash": "4.17.21",
104+
"lodash": "4.17.23",
105105
"minimatch": "^9.0.3",
106106
"ora": "^5.4.1",
107107
"parse5": "^7.1.2",
@@ -110,7 +110,7 @@
110110
"strip-ansi": "^6.0.0",
111111
"ts-morph": "^27.0.0",
112112
"typescript": "5.9.3",
113-
"undici": "^5.29.0",
113+
"undici": "^7.19.1",
114114
"zod": "3.25.58",
115115
"zod-validation-error": "^3.2.0"
116116
}

cli/src/client/figma_client.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ export async function getComponents(fileOrNode: string) {
6464
figmaUrl: figmaUrlOfComponent(component, fileKey),
6565
componentPropertyDefinitions:
6666
component.type === 'COMPONENT_SET'
67-
? Object.keys(component.componentPropertyDefinitions).reduce((result, key) => {
67+
? Object.keys(component.componentPropertyDefinitions || {}).reduce((result, key) => {
6868
return {
6969
...result,
7070
// this removes the ID prefix from property names e.g #123:name -> name
Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
import { parseRawFile } from '../connect'
2+
import { CodeConnectConfig } from '../../connect/project'
3+
import fs from 'fs'
4+
import path from 'path'
5+
import os from 'os'
6+
7+
describe('parseRawFile', () => {
8+
let tempDir: string
9+
let tempFilePath: string
10+
11+
beforeEach(() => {
12+
// Create a temporary directory and file for testing
13+
tempDir = fs.mkdtempSync(path.join(os.tmpdir(), 'parseRawFile-test-'))
14+
tempFilePath = path.join(tempDir, 'test.figma.template.js')
15+
})
16+
17+
afterEach(() => {
18+
// Clean up temporary files
19+
if (fs.existsSync(tempFilePath)) {
20+
fs.unlinkSync(tempFilePath)
21+
}
22+
if (fs.existsSync(tempDir)) {
23+
fs.rmdirSync(tempDir)
24+
}
25+
})
26+
27+
it('parses a raw file without documentUrlSubstitutions', () => {
28+
const fileContent = `// url=https://figma.com/design/abc123?node-id=1:1
29+
const figma = require('figma')
30+
export default figma.code\`<Button />\``
31+
32+
fs.writeFileSync(tempFilePath, fileContent)
33+
34+
const result = parseRawFile(tempFilePath, undefined)
35+
36+
expect(result.figmaNode).toBe('https://figma.com/design/abc123?node-id=1:1')
37+
})
38+
39+
it('applies documentUrlSubstitutions when config is provided', () => {
40+
const fileContent = `// url=https://figma.com/design/SOURCE-FILE?node-id=1:1
41+
const figma = require('figma')
42+
export default figma.code\`<Button />\``
43+
44+
fs.writeFileSync(tempFilePath, fileContent)
45+
46+
const config: CodeConnectConfig = {
47+
parser: 'react',
48+
documentUrlSubstitutions: {
49+
'https://figma.com/design/SOURCE-FILE': 'https://figma.com/design/TARGET-FILE',
50+
},
51+
}
52+
53+
const result = parseRawFile(tempFilePath, undefined, config)
54+
55+
expect(result.figmaNode).toBe('https://figma.com/design/TARGET-FILE?node-id=1:1')
56+
})
57+
58+
it('applies multiple documentUrlSubstitutions', () => {
59+
const fileContent = `// url=https://figma.com/design/SOURCE-FILE/My-Component?node-id=1:1
60+
const figma = require('figma')
61+
export default figma.code\`<Button />\``
62+
63+
fs.writeFileSync(tempFilePath, fileContent)
64+
65+
const config: CodeConnectConfig = {
66+
parser: 'react',
67+
documentUrlSubstitutions: {
68+
'SOURCE-FILE': 'TARGET-FILE',
69+
'My-Component': 'Your-Component',
70+
},
71+
}
72+
73+
const result = parseRawFile(tempFilePath, undefined, config)
74+
75+
expect(result.figmaNode).toBe('https://figma.com/design/TARGET-FILE/Your-Component?node-id=1:1')
76+
})
77+
78+
it('does not modify URL when no matching substitutions', () => {
79+
const fileContent = `// url=https://figma.com/design/OTHER-FILE?node-id=1:1
80+
const figma = require('figma')
81+
export default figma.code\`<Button />\``
82+
83+
fs.writeFileSync(tempFilePath, fileContent)
84+
85+
const config: CodeConnectConfig = {
86+
parser: 'react',
87+
documentUrlSubstitutions: {
88+
'SOURCE-FILE': 'TARGET-FILE',
89+
},
90+
}
91+
92+
const result = parseRawFile(tempFilePath, undefined, config)
93+
94+
expect(result.figmaNode).toBe('https://figma.com/design/OTHER-FILE?node-id=1:1')
95+
})
96+
97+
it('preserves isParserless flag and other metadata', () => {
98+
const fileContent = `// url=https://figma.com/design/SOURCE-FILE?node-id=1:1
99+
const figma = require('figma')
100+
export default figma.code\`<Button />\``
101+
102+
fs.writeFileSync(tempFilePath, fileContent)
103+
104+
const config: CodeConnectConfig = {
105+
parser: 'react',
106+
documentUrlSubstitutions: {
107+
'SOURCE-FILE': 'TARGET-FILE',
108+
},
109+
}
110+
111+
const result = parseRawFile(tempFilePath, 'Python', config)
112+
113+
expect(result.figmaNode).toBe('https://figma.com/design/TARGET-FILE?node-id=1:1')
114+
expect(result.label).toBe('Python')
115+
expect(result.templateData.isParserless).toBe(true)
116+
expect(result.templateData.nestable).toBe(true)
117+
})
118+
119+
it('uses language from config when provided', () => {
120+
const fileContent = `// url=https://figma.com/design/abc123?node-id=1:1
121+
const figma = require('figma')
122+
export default figma.code\`<Button />\``
123+
124+
fs.writeFileSync(tempFilePath, fileContent)
125+
126+
const config: CodeConnectConfig = {
127+
parser: 'react',
128+
language: 'kotlin',
129+
}
130+
131+
const result = parseRawFile(tempFilePath, 'React', config)
132+
133+
expect(result.language).toBe('kotlin')
134+
expect(result.label).toBe('React')
135+
})
136+
})

0 commit comments

Comments
 (0)