forked from figma/code-connect
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
figma-bot
committed
Sep 30, 2024
1 parent
a7fab93
commit 233ec33
Showing
28 changed files
with
854 additions
and
175 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,24 @@ | ||
# Code Connect v1.1.4 (26th September 2024) | ||
|
||
## Fixed | ||
|
||
### React | ||
- Fixed a Prettier bug with the interactive setup | ||
- Removed empty enum mappings from generated Code Connect in interactive setup | ||
- Fixed an issue with props not rendering correctly in the Figma UI if used in the body of a component (e.g. as a hook argument). Any Code Connect with this issue will need republishing to be fixed. (fixes https://github.com/figma/code-connect/issues/167) | ||
- Support mapping from an enum value to a boolean prop in CLI Assistant | ||
|
||
## Features | ||
|
||
### Compose | ||
- The dependencies required to author Code Connect files now live in a separate module from the plugin and are hosted on Maven Central. Refer to the [documentation](docs/compose.md) for updated instructions on adding Code Connect to your project. | ||
|
||
### SwiftUI | ||
- Updated the swift-syntax dependency to include 600.0.0 (Swift 6) | ||
|
||
# Code Connect v1.1.3 (11th September 2024) | ||
|
||
## Fixed | ||
## Fixed | ||
|
||
### HTML | ||
- Fixed an issue where `imports` was incorrectly not included in the TypeScript interface | ||
|
@@ -9,18 +27,23 @@ | |
### React | ||
- Fixed an issue where `imports` was incorrectly not included in the TypeScript interface (fixes https://github.com/figma/code-connect/issues/159) | ||
|
||
## Features | ||
|
||
### React | ||
- Code Connect files created in the CLI assistant will now start try to use auto-generated prop mappings in the component props. This is an early feature and support for different types is limited. | ||
|
||
# Code Connect v1.1.2 (10th September 2024) | ||
|
||
## Fixed | ||
## Fixed | ||
|
||
### React | ||
### React | ||
- Fixed an issue with `client` export used by the icon script (fixes https://github.com/figma/code-connect/issues/156) | ||
|
||
# Code Connect v1.1.1 (10th September 2024) | ||
|
||
## Fixed | ||
|
||
### General | ||
### General | ||
- Fixed an issue where the `@figma/[email protected]` npm package had an incorrect README | ||
|
||
# Code Connect v1.1.0 (10th September 2024) | ||
|
@@ -205,10 +228,10 @@ | |
|
||
### React | ||
|
||
- Added support for [nested properties](cli/README.md#nested-properties), using `figma.nestedProps` | ||
- Added support for [concatenating strings for CSS class names](cli/README.md#classname), using `figma.className` | ||
- Added support for [text content from layers](cli/README.md#text-content), using `figma.textContent` | ||
- Added support for [wildcards](cli/README.md#wildcard-match) with `figma.children` | ||
- Added support for [nested properties](docs/react.md#nested-properties), using `figma.nestedProps` | ||
- Added support for [concatenating strings for CSS class names](docs/react.md#classname), using `figma.className` | ||
- Added support for [text content from layers](docs/react.md#text-content), using `figma.textContent` | ||
- Added support for [wildcards](docs/react.md#wildcard-match) with `figma.children` | ||
|
||
### SwiftUI | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
cli/src/connect/__test__/e2e/e2e_parse_command/dummy_api_response_for_wizard.json
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
221 changes: 221 additions & 0 deletions
221
cli/src/connect/wizard/__test__/prop_mapping/benchmarking_helpers.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,221 @@ | ||
import fs from 'fs' | ||
import path from 'path' | ||
import basic from './basic' | ||
import { generatePropMapping } from '../../prop_mapping' | ||
import { Intrinsic } from '../../../intrinsics' | ||
import chalk from 'chalk' | ||
|
||
const PROP_MAPPING_TEST_SUITES = [ | ||
basic, | ||
] | ||
|
||
// Order important - worst to best | ||
enum PropResultType { | ||
FalsePositive, | ||
Miss, | ||
PartiallyCorrect, | ||
Correct, | ||
} | ||
|
||
type ComponentResult = { | ||
componentName: string | ||
results: PropResultType[] | ||
} | ||
|
||
type ResultTotals = { | ||
totalMappings: number | ||
correct: number | ||
partiallyCorrect: number | ||
falsePositives: number | ||
} | ||
|
||
export type BenchmarkingSuiteResult = { | ||
name: string | ||
results: ComponentResult[] | ||
} | ||
|
||
function areIntrinsicsEqual(a: Intrinsic, b: Intrinsic) { | ||
function replacer(key: string, value: boolean | string | string[] | Record<string, any>) { | ||
// TODO is order of children([]) significant? | ||
if (Array.isArray(value)) { | ||
return value.sort() | ||
} | ||
if (value && typeof value === 'object') { | ||
return Object.keys(value) | ||
.sort() | ||
.reduce( | ||
(acc, key) => { | ||
acc[key] = value[key] | ||
return acc | ||
}, | ||
{} as Record<string, any>, | ||
) | ||
} | ||
return value | ||
} | ||
|
||
return JSON.stringify(a, replacer) === JSON.stringify(b, replacer) | ||
} | ||
|
||
function isASubsetOf(a: any, b: any): boolean { | ||
if (a === undefined) { | ||
return true | ||
} | ||
// TODO is order of children([]) significant? | ||
if (Array.isArray(a) && Array.isArray(b)) { | ||
return a.every((value) => b.includes(value)) | ||
} | ||
if (a && typeof a === 'object' && b && typeof b === 'object') { | ||
return Object.keys(a).every((subKey) => isASubsetOf(a[subKey], b[subKey])) | ||
} | ||
return a === b | ||
} | ||
|
||
function getPropMappingBenchmarkingResults( | ||
printDiffSinceLastRun = false, | ||
prevResults?: BenchmarkingSuiteResult[], | ||
) { | ||
/** | ||
* For each suite of components, get the total number of props that have a mapping | ||
* in the test data, as well as the count of mappings we've correctly generated. | ||
* We then divide correct / total to get the overall success rate | ||
*/ | ||
return PROP_MAPPING_TEST_SUITES.map(({ testCases, name }) => { | ||
return testCases.reduce( | ||
(suiteResults, testCase, caseIndex) => { | ||
const componentResults: PropResultType[] = [] | ||
const actualResult = generatePropMapping({ | ||
componentPropertyDefinitions: testCase.componentPropertyDefinitions, | ||
signature: testCase.signature, | ||
}) | ||
|
||
// iterate expected individual prop mappings for current component | ||
Object.keys(testCase.perfectResult).forEach((prop, propIndex) => { | ||
let propResult = PropResultType.Miss | ||
if (prop in actualResult) { | ||
if (areIntrinsicsEqual(actualResult[prop], testCase.perfectResult[prop])) { | ||
propResult = PropResultType.Correct | ||
} else if (isASubsetOf(actualResult[prop], testCase.perfectResult[prop])) { | ||
// TODO would be good if this also reflected | ||
propResult = PropResultType.PartiallyCorrect | ||
} else { | ||
propResult = PropResultType.FalsePositive | ||
} | ||
} | ||
if (printDiffSinceLastRun && prevResults) { | ||
const prevPropResult = prevResults.find( | ||
(prevSuite) => prevSuite.name === suiteResults.name, | ||
)?.results[caseIndex]?.results[propIndex] | ||
if (propResult !== prevPropResult) { | ||
const text = | ||
`Prop mapping result changed: ${PropResultType[prevPropResult!]} -> ${PropResultType[propResult]}` + | ||
` (${suiteResults.name} - ${testCase.exportName} - ${prop})` + | ||
(prop in actualResult | ||
? `\nResult: ${JSON.stringify(actualResult[prop], null, 2)}` | ||
: '') | ||
if (propResult > prevPropResult!) { | ||
console.log(chalk.green(text)) | ||
} else { | ||
console.log(chalk.red(text)) | ||
} | ||
} | ||
} | ||
componentResults.push(propResult) | ||
}) | ||
|
||
suiteResults.results.push({ | ||
componentName: testCase.exportName, | ||
results: componentResults, | ||
}) | ||
|
||
return suiteResults | ||
}, | ||
{ | ||
name, | ||
results: [], | ||
} as BenchmarkingSuiteResult, | ||
) | ||
}) | ||
} | ||
|
||
export function runPropMappingBenchmarking() { | ||
const prevResults = JSON.parse( | ||
fs.readFileSync(path.join(__dirname, 'prop_mapping_benchmarking_snapshot.json'), 'utf8'), | ||
) as BenchmarkingSuiteResult[] | ||
|
||
const results = getPropMappingBenchmarkingResults(true, prevResults) | ||
|
||
const hasChanged = JSON.stringify(results) !== JSON.stringify(prevResults) | ||
|
||
return { results, prevResults, hasChanged } | ||
} | ||
|
||
function getSuiteTotals(suiteResult: BenchmarkingSuiteResult) { | ||
const propResults = suiteResult.results.flatMap((r) => r.results) | ||
return propResults.reduce( | ||
(acc, propResult) => { | ||
if (propResult === PropResultType.Correct) { | ||
acc.correct++ | ||
} else if (propResult === PropResultType.PartiallyCorrect) { | ||
acc.partiallyCorrect++ | ||
} else if (propResult === PropResultType.FalsePositive) { | ||
acc.falsePositives++ | ||
} | ||
acc.totalMappings++ | ||
return acc | ||
}, | ||
{ | ||
totalMappings: 0, | ||
correct: 0, | ||
partiallyCorrect: 0, | ||
falsePositives: 0, | ||
} as ResultTotals, | ||
) | ||
} | ||
|
||
export function prettyPrintBenchmarkingResults( | ||
suiteResultsWithoutTotal: BenchmarkingSuiteResult[], | ||
prevSuiteResultsWithoutTotal: BenchmarkingSuiteResult[], | ||
) { | ||
const prettyResults: Record<string, Record<string, string | number>> = {} | ||
|
||
const addTotals = (allResults: BenchmarkingSuiteResult[]) => [ | ||
...allResults, | ||
{ | ||
name: 'TOTAL', | ||
results: allResults.flatMap((r) => r.results), | ||
}, | ||
] | ||
|
||
const suiteResults = addTotals(suiteResultsWithoutTotal) | ||
const prevSuiteResults = addTotals(prevSuiteResultsWithoutTotal) | ||
|
||
suiteResults.forEach((suiteResult, index) => { | ||
const prevTotals = getSuiteTotals(prevSuiteResults[index]) | ||
const currenttotals = getSuiteTotals(suiteResult) | ||
|
||
const printDiff = (print: (totals: ResultTotals) => string | number) => { | ||
const prev = print(prevTotals) | ||
const current = print(currenttotals) | ||
return current === prev ? current : `${prev} -> ${current}` | ||
} | ||
|
||
prettyResults[suiteResult.name] = { | ||
'Total Mappings': printDiff((totals) => totals.totalMappings), | ||
Correct: printDiff( | ||
(totals) => | ||
`${totals.correct} (${((totals.correct / totals.totalMappings) * 100).toFixed(1)}%)`, | ||
), | ||
'Partially correct': printDiff( | ||
(totals) => | ||
`${totals.partiallyCorrect} (${((totals.partiallyCorrect / totals.totalMappings) * 100).toFixed(1)}%)`, | ||
), | ||
'False positives': printDiff( | ||
(totals) => | ||
`${totals.falsePositives} (${((totals.falsePositives / totals.totalMappings) * 100).toFixed(1)}%)`, | ||
), | ||
} | ||
}) | ||
|
||
console.table(prettyResults) | ||
} |
Oops, something went wrong.